Check image transparency

2020-05-26 10:17发布

I have a website where people can upload an PNG image and save it. But before they can save it, i need a check if the image contains transparency. Is there an way to check (i prefer JavaScript) if an image is not 24 bits?

<img id="imageId" src=#" onload="checkRestriction(this,'1')" alt=""/>

var isPng24Bit = false;

function checkRestriction(image, id) {
    if(image.colorDepth != 24) {
      PNGis24Bit = false;
    } else {
      PNGis24Bit = true; 
    }
}

2条回答
等我变得足够好
2楼-- · 2020-05-26 10:45

you can use this canvas technique for this purpose and customize this code as your demand
Make sure you resize your canvas to the same size as the image or else some pixels will be transparent where the image doesn't cover the canvas.

c.width=element.width;
c.height=element.height;

Example code and Demo:

var canvas1=document.getElementById("canvas1");
var ctx1=canvas1.getContext("2d");
var canvas2=document.getElementById("canvas2");
var ctx2=canvas2.getContext("2d");

$p1=$('#results1');
$p2=$('#results2');

var img1=new Image();
img1.crossOrigin='anonymous'
img1.onload=start1;
img1.src="https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png";
function start1(){

  canvas1.width=img1.width;
  canvas1.height=img1.height;

  ctx1.drawImage(img1,0,0);

  var imgData=ctx1.getImageData(0,0,canvas1.width,canvas1.height);
  var data=imgData.data;
  var found1='Left canvas does not have transparency';
  for(var i=0;i<data.length;i+=4){
    if(data[i+3]<255){found1='Left canvas does have transparency'; 
        break;
        }
  }

  $p1.text(found1);

}


var img2=new Image();
img2.crossOrigin='anonymous'
img2.onload=start2;
img2.src="https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png";
function start2(){

  canvas2.width=img2.width;
  canvas2.height=img2.height;

  ctx2.drawImage(img2,0,0);

  var imgData=ctx2.getImageData(0,0,canvas2.width,canvas2.height);
  var data=imgData.data;
  var found2='Right canvas does not have transparency';
  for(var i=0;i<data.length;i+=4){
    if(data[i+3]<255){found2='Right canvas does have transparency'; 
                      break;
                     }
  }

  $p2.text(found2);

}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<p id=results1>Results:</p>
<p id=results2>Results:</p>
<canvas id="canvas1" width=300 height=300></canvas>
<canvas id="canvas2" width=300 height=300></canvas>

查看更多
够拽才男人
3楼-- · 2020-05-26 10:45

I post this as an alternative approach to check via the PNG file's header directly. This saves memory and doesn't have to iterate through pixels, and the same good performance will be the same regardless of image size.

You can do this by loading the file via HTTPRequest or FileReader as ArrayBuffer, then simply check the file header structure using a DataView.

A PNG file always starts with the IHDR chunk so we only need to check if it's actually a PNG file and then assume the offset for the information telling the depth and type.

The depth field can be of value 1, 2, 4, 8 and 16 (1, 2, 4 being indexed, 8 = 24-bit or 8-bits per channel etc.).

The type field can be 0 (grayscale), 2 (true-color or RGB), 3 (indexed), 4 (grayscale + alpha) and 6 (RGB + alpha).

For details on the PNG file format and the IHDR header, see this link.

loadXHR("//i.imgur.com/zpWwpEM.png", function(result) {
  console.log(result); // result.buffer = original arraybuffer
});

function check(buffer, callback) {
  var view = new DataView(buffer);
  
  // is a PNG?
  if (view.getUint32(0) === 0x89504E47 && view.getUint32(4) === 0x0D0A1A0A) {
    // We know format field exists in the IHDR chunk. The chunk exists at 
    // offset 8 +8 bytes (size, name) +8 (depth) & +9 (type)
    var depth = view.getUint8(8 + 8 + 8);
    var type  = view.getUint8(8 + 8 + 9);
    
    callback({
      depth: depth,
      type: ["G", "", "RGB", "Indexed", "GA", "", "RGBA"][type],
      buffer: view.buffer,
      hasAlpha: type === 4 || type === 6  // grayscale + alpha or RGB + alpha
    })
  }
}

function loadXHR(url, callback) {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", url, true);
  xhr.responseType = "arraybuffer";
  xhr.onload = function() {
    if (xhr.status === 200) check(xhr.response, callback);
    else consle.log("Loading error: " + xhr.statusText);
  };
  xhr.send();
}

Same example but inserting image that is being checked into DOM:

loadXHR("//i.imgur.com/zpWwpEM.png", function(result) {
  console.log(result); // result.buffer = original arraybuffer
  
  var img = new Image();
  img.onload = function() {URL.revokeObjectURL(this.src)};
  img.src = URL.createObjectURL(new Blob([result.buffer]));
  document.body.appendChild(img);
});

function check(buffer, callback) {
  var view = new DataView(buffer);
  
  // is a PNG?
  if (view.getUint32(0) === 0x89504E47 && view.getUint32(4) === 0x0D0A1A0A) {
    // We know format field exists in the IHDR chunk. The chunk exists at 
    // offset 8 +8 bytes (size, name) +8 (depth) & +9 (type)
    var depth = view.getUint8(8 + 8 + 8);
    var type  = view.getUint8(8 + 8 + 9);
    
    callback({
      depth: depth,
      type: ["G", "", "RGB", "Indexed", "GA", "", "RGBA"][type],
      buffer: view.buffer,
      hasAlpha: type === 4 || type === 6  // grayscale + alpha or RGB + alpha
    })
  }
}

function loadXHR(url, callback) {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", url, true);
  xhr.responseType = "arraybuffer";
  xhr.onload = function() {
    if (xhr.status === 200) check(xhr.response, callback);
    else consle.log("Loading error: " + xhr.statusText);
  };
  xhr.send();
}

查看更多
登录 后发表回答