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;
}
}
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;
}
}
Share
edited Dec 23, 2016 at 8:23
Jelle
asked Dec 22, 2016 at 16:36
JelleJelle
8082 gold badges15 silver badges36 bronze badges
3
- can you show a more plete code sample? – Joel Harkes Commented Dec 22, 2016 at 16:40
- Another note: people can disable/circumvent JavaScript and still upload anything, you should check serverside too. – Joel Harkes Commented Dec 22, 2016 at 16:43
- I added the extra code, and yes you're right i still need the serverside check, but its less important to me. – Jelle Commented Dec 22, 2016 at 17:27
2 Answers
Reset to default 15you 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/wikipedia/mons/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/wikipedia/mons/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./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>
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./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./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();
}