How do I use imagemagick to convert HEIC to JPG and preserve quality? - command-line

I'd like to batch convert .heic images (e.g. iPhone photograph) to .jpg files with imagemagick, with the goal of retaining as much of the quality from the original image as possible. To be clear, the resulting output size is not a concern.
I've been using
magick input.heic -quality 100% output.jpg
Is it possible to do better?

No, its not possible to do better per ImageMagick's website:
Set the quality to 100 to produce lossless HEIC images. Requires the libheif delegate library.
I interpret lossless as NOTHING is lost from original picture. However since you ARE converting to another file type maybe its possible you lose something, are you seeing any artifacts/issues?

Related

Does an image loses quality when it is converted from jpg to png?

We all know that converting from jpg to jpg makes an image lose quality, and that the same doesn't happen when it's png to png, but what about jpg to png ?
In my mind it makes sense that it doesn't, but still I'm not sure.
I think that good answer to this question probably would be an article in which there would be a good explanation of why it happens or not. Do you now of any ? I couldn't find such article.
It doesn't, but it's complicated.
Reading of JPEG is not a precisely defined process. Different JPEG decoders are allowed to produce slightly different results from the same file.
Converting JPEG to PNG makes pixels forever represent the particular method that was used to decode the JPEG, even if it wasn't the best one. If you use a "bad" JPEG decoder for the conversion you lose ability to use a "better" JPEG decoder later.
The differences are:
Chroma upsampling. JPEG may store chroma (~color) at lower resolution than luma (~brightness) of the image. The spec doesn't say how the chroma channel should be resized, so some decoders use blocky nearest-neighbor scaling, some use bilinear scaling, some do even weirder things.
Numeric precision. JPEG requires calculations to be done to convert image from DCT and YCbCr representation to RGB. This can be done quickly and cheaply using integer math and 8-bit color, or a tiny bit better using floating-point math and higher-depth color.
Color profiles and CMYK. Conversion may change color space (in case of CMYK it has to convert to RGB), which is easy to get wrong.
There are other reasons to avoid the conversion:
The file will almost certainly become much larger. JPEG compression artifacts are the worst case for PNG.
The file will lose metadata (like camera info, GPS). While in theory PNG could carry the same metadata, in practice converters rarely preserve it.
And a case for conversion: jpeg2png project, which doesn't merely convert the file, but also uses quite advanced post-processing to smooth out JPEG compression distortions. In that case you might salvage a low-quality blocky JPEG and get a smoother image instead.
The process you describe is:
JPEG Stream => JPEG DECODER => BITMAP
=> PNG ENCODER => PNG Stream
There is no change in step #2. Step #1 might have rounding errors inherent in JPEG.

Why does PNGing an image from a JPG make it 10x bigger?

I have an image captured via webcam of my cat (the subject might not be important). I've aquired it as a 31 kB JPG file. When I open it with an image editor, then save it (without alteration) as a PNG (max. compression) it stores as a 297 kB file.
Why is the PNG file 10x larger than the original JPG. As I understand it, opening a JPG is lossless, and saving a PNG is lossless. So, where does all the extra data come from? If the image comes entirely out of the small file, why does it then re-save to 10x the size on disc?
Please read this carefully. I'm not asking why the two formats produce different file sizes from an original image. I'm asking why opening an existing JPG then saving that exact same image as PNG is 10x bigger. I don't think that this is a duplicate question as far as I can ascertain.
Some tests I've done:-
I've looked at both JPG and PNG and they look identical.
I've zipped both files and got cat.jpg.zip as 31 kB, and cat.png.zip as 296 kB. I take this to mean that both files are fully compressed with virtually no latent redundancy.
I've tried this via the BMP format as well; cat.jpg (31 kB) -> cat.bmp (922 kB) -> cat.bmp.zip (404 kB).
Any ideas regarding the mysterious extra data..?
JPEG inherently produces better compression than PNG. However, JPEG trades off fidelity to the original image for better compression. PNG reproduces the original exactly.
If you go from JPEG to PNG, you are not going to see a changes.
If you go from PNG to JPEG, it is likely you ill see a lot of change.
JPEG uses a series of compression techniques. One of them, the DCT, transforms the image. This creates a subtle waviness in color. For example, if you start with a solid red block that is all one color, JPEG produces a lot of slight color variations.
PNG compression relies on finding repeated pixel patterns in scan lines. The subtle color variations introduced by JPEG can make PNG compression less effective.
The extra data you refer to is simply the difference in how the two format represent the same image.
If I take a JPEG image from a camera and convert to PNG, the result is usually about 10 times larger.
For a PNG Graphic image going to JPEG, I normally get files about 1/3 smaller.
JPG uses lossy compression, while PNG uses loseless compression. When you convert JPG to PNG, what actually happens is uncompressing from JPG and saving the results in PNG.
The "extra data" is actually due to different algorithms used.
As for why zipped files also have different size, that's because PNG has to save all pixels(including those JPG has lossy compressed) loselessy.

Set quality for PNG images in MATLAB

I have a matlab code and it generates a .png image of 1024*768 resolution. The images are about 450KB in size and I need to know how to optimise and compress these images using matlab.
Can't I play with the quality as in JPEG ?
I read the imwrite manual and don`t seem to find a good way to do this.
Is there any way to achieve it in matlab ?
By design PNG files are lossless - there is no 'quality' to be adjusted (it's probably why a mod changed your question title).
You can reduce the number of colors in the image (the color depth) which will in turn reduce filesize (PNG-8 instead of PNG-24, for example), but the whole point of PNG is it produces lossless images, so there is simple no quality value a la JPEG.
Taken from the manual :
A parameter of input in case it is JPEG:
'Quality' - A number between 0 and 100; higher numbers mean higher quality (less image degradation due to compression), but the resulting file size is larger.
imwrite(x,'c:\1.jpg','Quality',10)
edit: Sorry, I answered this one while the title was JPEG and not PNG.
PNG doesn't support any quality settings - it is a lossless format. The compression it applies is generally as good as possible.

Transparency with JPEGs

JPEGs are smaller in size than PNGs. So, I thought that if I can make a specific region in a JPEG-file transparent, with some code, maybe I can save some bytes.
So does anyone know how to achieve this with for example PHP or JavaScript?
No. You can't do this. JPGs do not support alpha channels and have no capacity to designate certain colors as transparent either (GIF-style).
There's several issues with this, all of them have to do with that JPEG is a lossy compression format. The JPEG format is optimized for natural images and sharp edges will get blurred. If you intend that a specific pixel should have the value #d67fff there's no guarantee that after color conversion, FDCT, quantization, IDCT and color conversion, the pixel still will have that value. There's also a strong possibility that that pixel value will occur in areas that you don't want.
No. JPEG does not support transparency and is not likely to do so any time
soon. http://www.faqs.org/faqs/jpeg-faq/part1/section-12.html
You cannot do that, the client renders the image and doesn't know that you want it to treat that color as transparent (plus various compression methods on jpeg wouldn't work well with transparencies anyway).
I believe you can go with an 8-bit custom-pallet png, should save you a lot of space. Otherwise 24-bit PNG is your only high color option.
You can convert your image to SVG containing a color information as JPEG and an alpha channel as grayscale mask. Here is a tool I wrote to do it https://github.com/igrmk/transpeg

Setting DPI for PNG files

I have a bunch of diagrams created using a Java diagramming tool that I wrote - they are mostly black and white diagrams, with the blocks in aqua, and occasional other colours. They are currently being saved as JPG files, and I want to insert them into a book that I am preparing for Print On Demand.
The book is an OpenOffice ODT file, which will later be converted to a PDF.
Currently I use JPG files, but the print facility they use requires 300 DPI, so I modified my diagramming tool to set the xDensity and yDensity to 300, and resUnits to 1, using getAsTree(), and then expand the diagram by a factor of 3 (300/96). IMO the result looks pretty good!
Unfortunately, someone on another forum pointed out that line diagrams are "fuzzed" on JPG files, so suggested that I change over to PNG, or possibly BMP files, both of which ODT files allow to be inserted.
My problem is that BMPs don't seem to have a DPI, and PNGMetadata doesn't seem to support getAsTree(). Can someone point me in the right direction? Thanks.
I don't understand the getAsTree() part, but answering the question that appears in the title, setting dpi for PNG files, you could use the imagemagick convert tool:
convert -density 300 -units pixelsperinch infile.jpg outfile.png
PNG, BMP and dozens of other image formats don't compress your diagrams - compression is probably what your commentor was getting at. JPEGs are great for photos but suck at diagrams.
You might want to look into SVG and other vector formats. Or if your environment allows, exporting 0% compression JPEGs and converting them into another format for lossless reproduction at 300DPI.
Hope that helps!
I decided not to try to do this programmatically. Instead I create the original diagram in PNG, then convert to 300 DPI using Irfanview. Irfanview's batch capability lets me convert to 300 DPI, scale up to compensate, and set to grey scale, all in one operation - and on multiple files at a time. This seems to be the best solution - but thanks to everyone anyway!