⬆️ ⬇️

Use jpeg with transparency

Of course, the JPEG format does not support transparency, but the very idea of ​​using JPEG instead of PNG for transparent textures has stirred minds for quite some time. Comrade PaulZi recently suggested using the HTML format for SVG, which stores the image itself and the mask. Jim Studt suggests using EXIF ​​fields in JPEG and storing masks there, and displaying them on a web page using Canvas.

Both methods are relatively difficult to use, and are designed for the web, so I stopped at the simplest option: store a separate lossy JPEG for RGB and a lossless mask in PNG, and combine them at the stage of getting a UIImage in the program. I just want to say that I am writing on MonoTouch, because the code I quote in C #, although in ObjC this is done in almost the same way, taking into account the syntax.





Channel separation



I use the ImageMagik console utilities for sharing.

This command separates the alpha channel:

convert file.png -channel Alpha -separate file.mask.png



The following command creates a jpeg file, discarding transparency data. Characteristically, some other utilities (including Photoshop) add a kind of single-color substrate to the PNG file when converting a PNG file and only then save it in RGB, which gives a beautiful but incorrect picture with pre-multiplied alpha.

convert file.png -quality 90 -alpha off file.jpg



The quality of the received file is regulated by the quality 90 parameter. 90% of the quality for JPEG is more than Apple sets for screenshots of programs and movies. I think everyone will be able to adjust this value to their taste.



Optimization



The mask is obtained as an 8-bit Grayscale PNG without transparency. Such a format is perfectly compressed via optipng or through the website www.tinypng.org .

With jpeg the situation is more interesting. It would be possible to confine myself to the task of quality, but recently I came across a wonderful jpegrescan utility from Loren Merritt, one of the ffmpeg developers and the x264 encoder ( there are suspicions about him that he is a representative of the alien mind or the cybernetic brain ).

The utility uses an unusual approach: selects different coefficients for Progressive compression and selects the most optimal. Winning is obtained from 5 to 15% with identical picture quality. The utility has no own page, only a topic with the discussion and the perl-code itself: pastebin.com/f78dbc4bc

')

In order not to enter commands manually every time, I wrote a simple bash script:

 #!/bin/bash basefile=${1##*/} maskfile="${basefile%.*}.mask.png" jpegfile="${basefile%.*}.jpg" convert $1 -channel Alpha -separate $maskfile convert $1 -quality 90 -alpha off $jpegfile optipng $maskfile jpegrescan $jpegfile $jpegfile 




Here is the result of the script:



In my case, from a 1.8MB file, I got two files for 380Kb and 35Kb.



Gluing



Self-gluing is done very simply - two images are loaded into a UIImage, then a CGImage is created based on them with the WithMask method (in ObjC, this is a CGImageRef and initWithMask, respectively), and then it turns into a new UIImage.

  UIImage result; using(UIImage uiimage = UIImage.FromFile(file)) using(UIImage mask = UIImage.FromFile(maskFile)) { CGImage image = uiimage.CGImage; image = image.WithMask(mask.CGImage); result = UIImage.FromImage(image, uiimage.CurrentScale, uiimage.Orientation); } 




In a real project, I made it a bit more complicated and check for the presence of the * .mask.png file, and if it is missing, I return the usual UIImage.FromFile ().



Profit







Visually, the game has not changed. The delay in loading and gluing the textures to the eye is not noticeable, so I did not measure it. The project itself has decreased by 6 (!!) megabytes, both in .ipa form, and in iTunes and on the device.







Screen from the game in PNG. No artifacts or compression / transparency issues are visible.

A little confused double the number of pictures in the project folder, but it can be survived. Minimal code changes. For interface graphics, this method is not ideal because of the need to manually assign a UIImage, rather than load it from the NIB / XIB, but it’s quite suitable for your own controls or textures. Even if JPEG is saved with 100% quality, the size of the received files may be smaller than the original PNG without any loss of quality.



PS ImageMagick and optipng are put from ports (MacPorts / Fink / Brew) and are called as. The jpegrescan script swings with pastebin and uses the jpeg port

Source: https://habr.com/ru/post/152225/



All Articles