Reputation: 65530
Sorry if this has already been answered, but I can't find it if so.
I want to find the height and width of an image file in Javascript. I don't actually need to show the image in the page, just the height and width.
At the moment I've got the following code, but it's returning height and width 0 (in Mozilla 5).
var img = new Image();
img.src = "./filename.jpg";
var imgHeight = img.height;
var imgWidth = img.width;
alert("image height = " + imgHeight + ", image width = " + imgWidth);
The file definitely exists, it's in the same directory as the HTML, and it doesn't have height and width 0 :)
What am I doing wrong?
Upvotes: 22
Views: 38366
Reputation: 472
This solution get the image width/height without loading the image at all.
The trick here, is only load the first 1k of the image, where the metadata is placed, and then parse this info. This code only works for .jpg images. Need some adaptation for work with another formats.
function jpg1k(url) {
// indexOf for multi-pattern
function indexOfMulti(arr, pattern) {
var found,
_index = arr.indexOf(pattern[0]);
while (_index > -1) {
found = true;
var _idx = _index;
for (var patt of pattern) {
if (arr.indexOf(patt, _idx) !== _idx) {
found = false;
break;
}
_idx++;
}
if (found) {
return _index;
}
_index = arr.indexOf(pattern[0], _index + 1);
}
return -1;
}
const SOF_B = [ 0xFF, 0xC0 ], // Start Of Frame (Baseline),
SOF_P = [ 0xFF, 0xC2 ]; // Start Of Frame (Progressive)
return new Promise(function(res, rej) {
var xhr = new XMLHttpRequest;
xhr.onreadystatechange = function () {
if (xhr.readyState != 4) {
return;
}
const JPG = new Uint8Array(xhr.response);
const IDX_SOF_B = indexOfMulti(JPG, SOF_B);
if (IDX_SOF_B > -1) {
var h = JPG.slice(IDX_SOF_B + 5, IDX_SOF_B + 7),
w = JPG.slice(IDX_SOF_B + 7, IDX_SOF_B + 9);
h = parseInt(h[0].toString(2) + h[1].toString(2).padStart(8, '0'), 2);
w = parseInt(w[0].toString(2) + w[1].toString(2).padStart(8, '0'), 2);
return res({ w: w, h: h });
}
const IDX_SOF_P = indexOfMulti(JPG, SOF_P);
if (IDX_SOF_P > -1) {
var h = JPG.slice(IDX_SOF_P + 5, IDX_SOF_P + 7),
w = JPG.slice(IDX_SOF_P + 7, IDX_SOF_P + 9);
h = parseInt(h[0].toString(2) + h[1].toString(2).padStart(8, '0'), 2);
w = parseInt(w[0].toString(2) + w[1].toString(2).padStart(8, '0'), 2);
return res({ w: w, h: h });
}
return rej({ w: -1, h: -1 });
};
xhr.open('GET', url, true);
xhr.responseType = "arraybuffer";
xhr.setRequestHeader('Range', 'bytes=0-1024');
xhr.send(null);
});
}
jpg1k('path_to_your_image.jpg')
.then(console.log);
For PNG, we need adapt the code to PNG struct, but we only need the first 24 bytes to determine the width/height, so we dont need to request 1k like jpg.
function png24b(url) {
return new Promise(function(res, rej) {
var xhr = new XMLHttpRequest;
xhr.onreadystatechange = function () {
if (xhr.readyState != 4) {
return;
}
const PNG = new Uint8Array(xhr.response),
decoder = new TextDecoder();
// PNG.slice(0, 8) === [ _ P N G CR LF _ _ ]
// PNG.slice(8, 16) === [ CHUNKLENGTH CHUNKFORMAT ]
// IHDR must be the first CHUNKFORMAT:
// PNG.slice(16, 24) === [ WIDTH------ HEIGHT----- ]
if ( decoder.decode(PNG.slice(1, 4)) === 'PNG' ) {
const view = new DataView(xhr.response);
return res({ w: view.getUint32(16), h: view.getUint32(20) });
}
return rej({ w: -1, h: -1 });
};
xhr.open('GET', url, true);
xhr.responseType = "arraybuffer";
xhr.setRequestHeader('Range', 'bytes=0-24');
xhr.send(null);
});
}
png24b('path_to_your_image.png')
.then(console.log);
Upvotes: 2
Reputation: 32085
The following code will get you the width/height without waiting for the image to load completely, making it significantly faster than the other solutions here.
For testing change abc123
in image source to any random string to prevent caching.
There is a JSFiddle Demo as well.
<div id="info"></div>
<img id="image" src="https://upload.wikimedia.org/wikipedia/commons/d/da/Island_Archway,_Great_Ocean_Rd,_Victoria,_Australia_-_Nov_08.jpg?abc123">
<script>
getImageSize($('#image'), function(width, height) {
$('#info').text(width + ',' + height);
});
function getImageSize(img, callback) {
var $img = $(img);
var wait = setInterval(function() {
var w = $img[0].naturalWidth,
h = $img[0].naturalHeight;
if (w && h) {
clearInterval(wait);
callback.apply(this, [w, h]);
}
}, 30);
}
</script>
Upvotes: 11
Reputation: 2978
If you check this link here is a method to get all the image dimensions in a directory with PHP which checks it without having to load it to the page. This might help you. You can pass it to your js with a
var dimensions = <?php echo json_encode($imageDimensions)?>
PHP Get dimensions of images in dir
I think this is a better approach if you really don't want to load the images
Upvotes: 0
Reputation: 5857
The height and width properties of an image element (like the offsetHeight and offsetWidth properties of any element),
return 0 instead of the actual values until it has been added to some document (and if its style.display attribute is not set to "none").
A common way to work around this is displaying the image outside the visible area of your page; your users will not see it, and its height and width properties will return the actual values instead of 0.
Then you should remove the image from the document.
var img = new Image();
img.src = "./filename.jpg";
img.style.position = "absolute";
img.style.left = -9999; // Image width must not exceed 9999 pixels
img.style.visibility = "hidden"; // Maybe you can remove this
document.body.appendChild(img);
var imgHeight = img.height;
var imgWidth = img.width;
alert("image height = " + imgHeight + ", image width = " + imgWidth);
document.body.removeChild(img); // Removes the image from the DOM (This does not destroy the image element)
Upvotes: 5
Reputation: 37494
If the image is not loaded, it won't have its' height and width set. You have to wait until the image is fully loaded, then inspect its' size. Maybe something along these lines:
function getWidthAndHeight() {
alert("'" + this.name + "' is " + this.width + " by " + this.height + " pixels in size.");
return true;
}
function loadFailure() {
alert("'" + this.name + "' failed to load.");
return true;
}
var myImage = new Image();
myImage.name = "image.jpg";
myImage.onload = getWidthAndHeight;
myImage.onerror = loadFailure;
myImage.src = "image.jpg";
Upvotes: 24