get image size (kb) with javascript with out loading it - javascript

Is there any way to get image size (kb) before loading it in browser by java script ?
for example there is an image in this address : "mysite.com/content/sample.jpg"
now how can we understand how much is the size (kb) of this image?

You can get it like below
window.onload = function() {
var image = new Image();
image.onload = function() {
var info = "Image Info:<br>Width: "+this.width+", Height: "+this.height;
document.getElementById("imageInfo").innerHTML = info;
}
image.src = 'http://upload.wikimedia.org/wikipedia/commons/1/16/HDRI_Sample_Scene_Balls_%28JPEG-HDR%29.jpg';
}
Here is the sample - http://plnkr.co/edit/X1cqZYv93FzK4zC5kRE7?p=preview

If it's only ever a jpeg, you can just load the first chunk of the file which contains the EXIF metadata. That metadata contains width and height most of the time, although you can't be 100% certain that it's there or that it's correct. But it's probably your best bet. There are a couple of nice EXIF libraries in Javascript, and I've used this one: https://github.com/bwindels/exif-parser
It still requires you to make an HTTP request for it though, so if that's what you're worried about, there's no way to avoid it.

Related

Why does canvas.toDataURL() not produce the same base64 as in Ruby for an image?

I'm trying to produce the same base64 data for an image file in both JavaScript and in Ruby. Unfortunately both are outputting two very different values.
In Ruby I do this:
Base64.encode64(File.binread('test.png'));
And then in JavaScript:
var image = new Image();
image.src = 'http://localhost:8000/test.png';
$(image).load(function() {
var canvas, context, base64ImageData;
canvas = document.createElement('canvas');
context = canvas.getContext('2d');
canvas.width = this.width;
canvas.height = this.height;
context.drawImage(this, 0, 0);
imageData = canvas.toDataURL('image/png').replace(/data:image\/[a-z]+;base64,/, '');
console.log(imageData);
});
Any idea why these outputs are different?
When you load the image in Ruby the binary file without any modifications will be encoded directly to base-64.
When you load an image in the browser it will apply some processing to the image before you will be able to use it with canvas:
ICC profile will be applied (if the image file contains that)
Gamma correction (where supported)
By the time you draw the image to canvas, the bitmap values has already been changed and won't necessarily be identical to the bitmap that was encoded before loading it as image (if you have an alpha channel in the file this may affect the color values when drawn to canvas - canvas is a little peculiar at this..).
As the color values are changed the resulting string from canvas will naturally also be different, before you even get to the stage of re-encoding the bitmap (as PNG is loss-less the encoding/compressing should be fairly identical, but factors may exist depending on the browser implementation that will influence that as well. to test, save out a black unprocessed canvas as PNG and compare with a similar image from your application - all values should be 0 incl. alpha and at the same size of course).
The only way to avoid this is to deal with the binary data directly. This is of course a bit overkill (in general at least) and a relative slow process in a browser.
A possible solution that works in some cases, is to remove any ICC profile from the image file. To save an image from Photoshop without ICC choose "Save for web.." in the file menu.
The browser is re-encoding the image as you save the canvas.
It does not generate an identical encoding to the file you rendered.
So I actually ended up solving this...
Fortunately I am using imgcache.js to cache images in the local filesystem using the FileSystem API. My solution is to use this API (and imgcache.js makes it easy) to get the base64 data from the actual cached copy of the file. The code looks like this:
var imageUrl = 'http://localhost:8000/test.png';
ImgCache.init(function() {
ImgCache.cacheFile(imageUrl, function() {
ImgCache.getCachedFile(imageUrl, function(url, fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
console.log($.md5(this.result.replace(/data:image\/[a-z]+;base64,/, '')));
};
reader.readAsDataURL(file);
});
});
});
});
Also, and very importantly, I had to remove line breaks from the base64 in Ruby:
Base64.encode64(File.binread('test.png')).gsub("\n", '');

canvas.toDataURL("image/png") - how does it work and how to optimize it

I wanted to know if there was anyone out there that knows how
canvas.toDataURL("image/png");
works? I want to understand better because at times it seems to really slow my computer down.
Is there a way to optimize the base64 image before during or after to get better performance ?
function base64(url) {
var dataURL;
var img = new Image(),
canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d"),
src = url;
img.crossOrigin = "Anonymous";
img.onload = function () {
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL('image/png');
preload(dataURL);
canvas = null;
};
img.src = url;
}
Basically this is my function but I wanted to see if there was a way to make this process perform better or if there was an alternative to canvas.toDataURL('image/png');
thanks
toDataURL() does the following when called (synchronously):
Creates a file header based on the file type requested or supported (defaults to PNG)
Compresses the bitmap data based on file format
Encodes the resulting binary file to Base-64 string
Prepends the data-uri header and returns the result
When setting a data-uri as source (asynchronously):
String is verified
Base-64 part is separated and decoded to binary format
Binary file verified then parsed and uncompressed
Resulting bitmap set to Image element and proper callbacks invoked
These are time-consuming steps and as they are internal we cannot tap into them for any reason. As they are pretty optimized as they are given the context they work in there is little we can do to optimize them.
You can experiment with different compression schemes by using JPEG versus PNG. They are using very different compression techniques and depending on the image size and content one can be better than the other in various situations.
My 2 cents..
The high performance alternative is canvas.toBlob. It is extremely fast, asynchronous, and produces a blob which can also be swapped to disk, and is subjectly speaking simply far more useful.
Unfortunately it is implemented in Firefox, but not in chrome.
Having carefully bench-marked this, there is no way around because canvas.toDataURL itself is the bottleneck by orders of magnitude.

Bad image rotation

I have an issue with JavaScript when rendering an image before upload in a correct rotation. It seems that when you render the image witch have the correct rotation only on exif data the browser doesn't use it.
Users see a different rotation between what they have on their system on when image is displayed on the website by JavaScript.
The code is very basic:
Do you know a simple way to correct this rotation bug ?
LbEmeraude.handleImage = function (f) {
if (f.type.match('image.*')) {
var reader = new FileReader();
reader.onload = (function (file) {
return function (e) {
var image = {};
image.dataAsUrl = e.target.result;
LbEmeraude.renderImage(image);
};
})(f);
var image = reader.readAsDataURL(f);
}
}
LbEmeraude.renderImage = function (image) {
var eImage = LbEmeraude.createImgElement(image.dataAsUrl);
$('someElement').append(eImage);
};
LbEmeraude.createImgElement = function (src) {
var image = document.createElement("img");
image.src = src;
return image;
}
Thank for your attention.
What you are asking for is nothing new... check this out: https://bugzilla.mozilla.org/show_bug.cgi?id=298619
That sucker was opened in 2005 and has not been resolved yet. This article is old but really robust: http://www.daveperrett.com/articles/2012/07/28/exif-orientation-handling-is-a-ghetto/
But the key part in there is kinda far down where he notes that the browser does not usually apply exif rotation when in the context of an html img tag, but may honor it when opening the image in its own tab.
So right now no browser will do it by default, the web apps that seem to do it are mostly getting that value on the server and serving down different assets.
But it looks like there is hope if you want to hack it in: Accessing JPEG EXIF rotation data in JavaScript on the client side

JavaScript image loading in percents

Is there any way to show "percentage-load-bar" while loading an image in js?
In other words I want to use this:
var img = new Image();
img.onload = function() {
document.querySelector('#percents').innerHTML = 'all done';
};
img.onreadystatechange = function(e) {
document.querySelector('#percents').innerHTML = e.percentsLoaded;
};
img.src = 'http://example.com/image.png';
Javascript has no intermediate events for loading resources. You can however show a loading bar if you are loading more than one image but I'm guessing that's not the case.
If you do really want this I think the only solution is to use Flash, which can do a number of fancy things but .. well .. it's Flash :/
Look at some of the big album-image hosting sites and see if they have a solution.

Getting size of javascript preloaded image

I'm trying to preload a number of images generated on the server to a small website. The preloading is done using setWindowTimeout and uses an Image object, sets the onload callback and then applies the new request uri.
For some requests, the server may have to signal that the image is 'unchanged' and I'm doing it by sending done a small 1x1 pixel gif (seems like I need to send an actual image, returning empty content will cause the Image object to not fire onload). In my onload handler I would like to determine the size of the fetched image and then determine if I should update the visual image with the given image.
Below is a snippet of my current solution (the output is a div to help debug):
refresh: function() {
var newSrc = '/screenshot.ashx?tick=' + new Date().getTime();
var imgObj = new Image();
var self = this;
// this is called when load is done
imgObj.onload = function() {
//if (imgObj.complete)
// return;
if (imgObj.width > 1 && imgObj.height > 1) {
output.innerHTML += '<br/>Updating image:' + newSrc;
img.src = newSrc; //fiddler shows no reload here, read from cache
}
else {
output.innerHTML += '<br/>Empty image:' + newSrc;
}
self.setupNewRefresh();
};
output.innerHTML += '<br/>Loading image:' + newSrc;
imgObj.src = newSrc;
},
I seem to have two problems:
a) the imgObj.complete is false when the function is first called but it is only called once (hence my commenting it out) and
b) I can't seem to rely on the width or height property of the image when loaded. From my tests of fetch the 1x1 pixel, it sometimes reads out 50 which seems to be default when creating a new Image() and it sometimes reads out the correct size of 1.
My ultimate goal is to have a small chunk of javascript logic that queries the server for a new image periodically, does nothing if nothing new has happened (1 pixel image) or loads the new image. I might be going about it the wrong way here or have overlooked important properties or calls, so I'm happy to receive feedbacks.
EDIT: upon suggestion from mplungjan, I preloaded into a hidden div instead, which helped me with problem b). Still no solution to problem a) though; reports complete = false once and is not called again
I'll go ahead and answer my own question.
Preloading the image into a hidden element in the DOM instead of a code-level element was the trick for actually getting correct sizes (thanks mplungjan). The a) issue, namely the complete event, remains unsolved.
As a side note I ended up using the XMLHttpRequest instead as it allowed by to look at the size of the payload returned.

Categories

Resources