Convert image to Blob - image

I want to upload image data to a php script on the server. I have a URL for an image source (PNG, the image might be located on a different server). I load this into a Javascript image, draw this into a canvas and use the canvas.toBlob() method (or a polyfill as it is not mainly supported yet) to generate a blob holding the image data. This works fine, but I recognized that the resulting blob size is much bigger than the original image data.
In contrast if I use a HTML File input and let the user select an image on the client the resulting blob has equal size to the original image. Can I get image data from a canvas that is equal to the original image size?
I guess the reason is that I loose the PNG (or any image compression) when using the canvas.toBlob() polyfill:
value: function (callback, type, quality) {
var binStr = atob(this.toDataURL(type, quality).split(',')[1]),
len = binStr.length,
arr = new Uint8Array(len);
for (var i=0; i<len; i++ ) {
arr[i] = binStr.charCodeAt(i);
}
callback(new Blob([arr], {type: type || 'image/png'}));
}
I am confused by so many conversion steps via image, canvas, blob - so maybe there is an alternative to get the image data from a given URL and finally append it to FormData to send it to the server?

The method toDataURL when using the png format only uses a limited set of the possible formats available for PNG files. It is the 8bit per channel RGBA (32 bits) compressed format. There are no options to use any of the other formats available so you are forced to include redundant data when you save as a PNG. PNG also has a 24bit and 8 bit format. PNG also has several compression options available though I am unsure which is used but each browser.
In most cases it is best to send the original image. If you need to modify the image and do not use the alpha channel (no transparency) but still want the quality to be high send it as a jpeg with quality set to 1 (max).
You may also consider the use of a custom encoder for PNG that gives you access to more of the PNG encoding options, or even try one of the many other formats available, or make up your own format, though you will be hard pushed to improve on jpeg and webp.
You could also consider compressing the data on the server when you store it, even jpeg and webp have a little room for more compression. For transport you should not worry as most data these days is compressed as it leaves the page and most definitely compressed by the time it leaves the clients ISP

Related

How can I use low-level functions (not imread) to read a grayscale image?

I'm trying to use low-level functions (fopen and fread) to read a grayscale image of type uint16 in TIFF format as follows:
fid = fopen(filepath,'r');
img = fread(fid,[ncolms, nrows], 'uint16=>uint16')';
The obtained image matrix is different from that obtained by simply using imread:
img = imread(filepath);
The resulting images are shown below (the left is by fread and the right is by imread):
In addition to the obvious intensity difference, one may also note that fread image has some artifacts in the top edge of image. I think this must be due to their different mechanisms of reading images.
I want to know how to use such low-level functions as fopen and fread to read images (grayscale, not binary), equivalently to using imread, if they can.
Those "artifacts" you're seeing are likely the header and tag data stored in the file before the image data. I would suggest taking a look at this TIFF File Format Summary. It will tell you exactly how to read all this extra information, if you really want to do it yourself. Note that some of this extra tag information (i.e. ImageHeight, ImageWidth, BitsPerSample, SamplesPerPixel, etc.) will be useful in determining exactly how to read the image data correctly, and thus match the image you get from the imread function.

EXIF and thumbnails

I'm working on a photo viewer. In this context, I wrote a small class to be able to read and use some EXIF data, as e.g. image orientation. This class works well for reading.
However, I would add a new option to rotate photos. I want to rotate and write the photo data itself, not just rewrite the orientation tag. I already wrote the code to rotate and save the primary JPEG image, and it works well. But I also need to rotate the thumbnail contained in the EXIF data, if any, to keep the image coherent. For this reason I need to write in the EXIF data, to replace the existing thumbnail.
But this raises some questions, that I've some trouble answering, namely:
Can the EXIF data contains more than 1 thumbnail, and if yes, what is the maximum thumbnail count that an image can contain?
What are the supported formats for thumbnails? (I found JPEG and TIFF, are there other?)
Is there any guarantee in the EXIF standards that the thumbnails are always written in the late EXIF data, just before the primary image?
If not, then each tags containing an offset that points to a location beyond the thumbnail to replace should be updated. So, is there a standard way to iterate through all tags and sub-directories, to recognize which EXIF tags contain offsets, and to update them if needed? Or the only way is to read a maximum of tags and rewrite only that are known?
Or is there a way to guarantee that the size of the newly rotated thumbnail will be smaller or equal to previous thumbnail size to replace with?
Regards
Here are some answers for your questions:
1) The EXIF data is laid out like a TIFF file with 2 pages. The first page is the camera information and the second page is the thumbnail. If you add more pages (with thumbnails), 99.99% of the applications probably won't notice since you'll be doing it differently than the "standard" way. As far as "maximum count", you have 64k of data that can be stored in any JFIF tag. You can put what you want in that 64k.
2) There is only 1 supported EXIF thumbnail format: TIFF. Inside the TIFF there can be compressed (JPEG) or uncompressed data. Again, you're welcome to stick LZW-compressed data in there, but most apps probably won't be prepared to display it properly.
3) The JFIF container format allows for tags with metadata to appear before the main image. The APPx tags contain metadata that can follow the standard or not. You're welcome to stick multiple EXIF APP1 tags into your files, but again, most apps won't be able to properly handle that situation. So the simple answer is that the EXIF data (including thumbnail) must come before the main image and if you put more than 1 thumbnail it will most likely be ignored.
4) If you are modifying a JFIF (including the metadata), you must rewrite the metadata. It's actually quite simple because each tag is independent and has a simple length value instead of relative offsets.
5) You can do anything you want with the size/orientation of your thumbnail as long as you make the EXIF APP1 tag data total size fit within 64k.
Here's what you need to do...
1) Read the source image (and thumbnail if present).
2) Prepare your rotated image (and thumbnail).
3) Write the new metadata with the new thumbnail image.
4) Write the new main image.
If you want to preserve the original metadata along with your new thumbnail, it's pretty easy. Just read the original tags and hold on to them, then write them in the new image. Each JFIF tag is just a 2 byte identifier (FFxx) followed by a 2 byte length and then the data. They can be packed in almost any order and there's no hard limit on how many total tags can appear before the main image.

Loading PNG images but using them as COMPRESSED_RGBA_S3TC_DXT5_EXT in WebGL?

I'm trying to load images in WebGL, and then uploading them to the GPU. I'd like to use a compressed texture format, even though the original images are uncompressed/lossless.
To upload, this is what I'm doing:
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureSource);
In the above code, textureSource is a loaded (say, "texture.png").
It all works well, but I'd like to load WEBGL_compressed_texture_s3tc formats (COMPRESSED_RGB_S3TC_DXT1_EXT) to store the image in a compressed fashion.
I make sure that the extension is available and enabled...
var ext = gl.getExtension("WEBGL_compressed_texture_s3tc");
var fmt = ext.COMPRESSED_RGBA_S3TC_DXT5_EXT;
console.log(fmt); // 33779
But then I can't use it as a format. Using texImage2D() doesn't work:
gl.texImage2D(gl.TEXTURE_2D, 0, fmt, fmt, gl.UNSIGNED_BYTE, textureSource);
// WebGL: INVALID_ENUM: texImage2D: invalid texture format
// [.WebGLRenderingContext]RENDER WARNING: texture bound to texture unit 0 is not renderable. It maybe non-power-of-2 and have incompatible texture filtering or is not 'texture complete'
The expected method is compressedTexImage2D(), but that's not very helpful either:
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, fmt, 256, 256, 0, texture.source);
// Uncaught TypeError: Failed to execute 'compressedTexImage2D' on 'WebGLRenderingContext': parameter 7 is not of type 'ArrayBufferView'.
This is obviously because compressedTexImage2D() expects an Uint8Array with the actual DDS/DXT data, not a JavaScript image like what I'm passing.
The obvious solution is to uploading files in their native DDS format - files that have been compressed somewhere else. But that's what I'm trying to avoid: in my current workflow, it'd make sense to have the image in their original format rather than pre-compress them (or having duplicates).
My question then is as such: can I still use the original PNG images, loading them, and having them upload to the GPU on their compressed format? In other words, can I compress textures to their DXT1/5 formats on the fly?
I'm a little bit constrained by video memory in what I'm doing, so any saving would be great. I managed to minimize the space used by the textures by using UNSIGNED_SHORT_4_4_4_4 and the other data types, which is a good start, but I'd like to try using the native compression too.
I haven't found much documentation on the topic, nor found relevant code on other popular libraries (Three.js, Pixi, etc), which leads me to believe that my request is super stupid, but I'd like to understand why. This page hints at licensing issues, which might be why WebGL doesn't feature a way to properly compress the file, nor allow for browser support of image objects.
can I still use the original PNG images, loading them, and having them upload to the GPU on their compressed format? In other words, can I compress textures to their DXT1/5 formats on the fly?
As far as I am informed: NO.
I only work on desktop and embedded GL, but even there is no chance to compress textures on the fly without dedicated code or a library.
(And, well, those DXT formats are not very good, either, if your textures are too detailed or have lots of different colors within small buckets. Most likely you're better off just using smaller textures, as the DXT1 compresses to 1/8th and DXT5 to 1/4 of the original size (which is like halving the resolution of the texture).)
Theoretically I think you could compress the PNGs to DXT with Javascript. I guess that'd be just mad though :)
Better encode beforehand with native code. An option for supporting PNG content is to have an asset proxy for doing the conversions on the fly on server side (our partner company that hosts http://www.meshmoon.com/ does exactly that).

Can CGPDFDataFormatJPEG2000 be used for something other than a JPEG2000 image?

Using the Quartz 2D PDF routines, can the CGPDFDataFormat format of a CGPDFStreamRef PDF stream be equal to CGPDFDataFormatJPEG2000 in any case other than for an XObject image with a filter of /JPXDecode?
In other words, is the CGPDFDataFormatJPEG2000 format ever used for anything other than JPEG2000 image streams? The reasonable answer would be no, but there can always be a difference between common usage and what's theoretically possible.
JPXDecode filter expects a JPEG2000 image file to be stored in the image XObject, not just compressed raw data. I can say 100% it is always used for image XObjects. But theoretically nothing stops you to wrap your raw content stream data as a JPEG2000 image and then use the JPXDecode filter with a regular content stream. It is just not practical.

Can jpg images support animation?

jpeg image
How is the above jpg image animated? As far as I know jpg format does not support animation.
No, the JPEG file format has no inherent support for animation.
The image you linked is actually an animated GIF disguised with a jpg file extension. (The browser apparently ignores even the MIME type and looks at the file header bytes in such cases.)
If you view the image in firefox, you can right-click on it and select properties:
You'll see Type: GIF image (animated, 54 frames)
Thus, it is a gif-image that has been renamed to .jpg.
For completeness, I'd like to point our that there's Motion-JPEG - sort of a jpg animation.
MJPEGs, usually produced by webcams, are a stream of JPEG files concatenated together, one after another, sometimes delimited by a HTTP header, and served by webcam-webservers with a MIME-Type of multipart/x-mixed-replace;boundary=, where boundary= defines the delimiter.
A search for animated JPEG related projects on github results in two findings:
In case people care about the size of an animated GIF, they strip it into separate JPG frames and tell the browser to exchange these frames in-place via some JavaScript code. For example. (Pawel's answer)
Then there's actually a proposed Animated JPEG standard, which stems from MJPEG and declares framerate and so forth in each JPG frame. Not probable to arrive in browsers anytime soon.
And lastly, I've seen image-hosters to replace large animated GIFs with a mp4 version of the GIF for presentation, plus some Javascript to serve the actual GIF for downloads/non-supported browsers.
And no, JPEG itself, via JFIF, does not offer a facility to animate a JPG file in itself, just as Noldorin already noted in the chosen answer. :shrug:
It is a GIF image... the extension has been changed by hand. Browser engine is smart enough to determine image format regardless of file extension.
var c = 1;
/* Preloading images */
var image1 = new Image();
image1.src = "a1.jpg";
var image2 = new Image();
image2.src = "a2.jpg";
var image3 = new Image();
image3.src = "a3.jpg";
var image4 = new Image();
image4.src = "a4.jpg";
var image5 = new Image();
image5.src = "a5.jpg";
function disp_img(w)
{
if (c == 6)
{
c = 1;
}
var img_src = "a" + c + ".jpg";
document.ani.src = img_src;
c++;
}
t = setInterval("disp_img(c)", 1000);
No JPEG doesn't support animation. Saving a GIF file with .jpeg extension doesn't male it a JPEG file. It's still a GIF file. Because OS Image viewer doesn't look into file extension it rather looks into the content.
If you open that file as binary (in a text editor) you will see the first line contains
GIF89ad�d�˜|� Which is the magic number for GIF.
Yes,
you can make animation using single jpeg. Google "jpeg css sprites". Of course this will not be native animation support by jpeg format.
A bit of a necro-post but since this question popped first when I tried to get info about pixel motion jpeg, here's some additional info.
Since Pixel2, Google created motion jpeg, which is an ordinary jpeg at the end of which there's an mp4 video.
More on this here:
https://android.jlelse.eu/working-with-motion-photos-da0aa49b50c
JPG does not animate. You either saw a series of JPG images rendered with javascript or you saw a GIF file named as a JPG. A web server and browser might still recognize the correct GIF filetype, even if the wrong extension has been added to the filename.
If you open the image file and if it is a sort of GIF format by using a hex editor, you see the following 4 bytes designating that image type is of GIF.

Resources