Compress UIImage by reducing bits per pixel in Swift [duplicate] - swift

This question already has an answer here:
Convert an image to a 16bit color image
(1 answer)
Closed 4 years ago.
I'm trying to obtain a PNG image with a resolution 512px x 512px smaller than 100 kB.
At the moment the files are around 350 kB. I'm trying to reduce the file size and a way I was thinking is to reduce the Color-depth.
This is the information of the PNG images:
bits per component -> 8
bits per pixel -> 32
I wrote some code to create the CGContext with a different bits per Pixel, but I don't think that's the write way.
I don't want to use the UIImage.jpegData(compressionQuality: CGFloat) since I need to maintain the alpha channel.
I already found some code in Objective-C but that didn't help. I'm looking for a solution in Swift

You would need to decimate the original image somehow, e.g. zeroing some number of the least significant bits or reducing the resolution. However that completely defeats the purpose of using PNG in the first place, which is intended for lossless image compression.
If you want lossy image compression, where decimation followed by PNG is one approach, then you should instead use JPEG, which makes much more efficient use of the bits to reproduce a psycho-visually highly similar image. More efficient than anything you or I might come up with as a lossy pre-processing step to PNG.

Related

How to shrink or manage an image's size in bytes

Python 3.6.6, Pillow 5.2.0
The Google Vision API has a size limit of 10485760 bytes.
When I'm working with a PIL Image, and save it to Bytes, it is hard to predict what the size will be. Sometimes when I try to resize it to have smaller height and width, the image size as bytes gets bigger.
I've tried experimenting with modes and formats, to understand their impact on size, but I'm not having much luck getting consistent results.
So I start out with a rawImage that is Bytes obtained from some user uploading an image (meaning I don't know much about what I'm working with yet).
rawImageSize = sys.getsizeof(rawImage)
if rawImageSize >= 10485760:
imageToShrink = Image.open(io.BytesIO(rawImage))
## do something to the image here to shrink it
# ... mystery code ...
## ideally, the minimum amount of shrinkage necessary to get it under 10485760
rawBuffer = io.BytesIO()
# possibly convert to RGB first
shrunkImage.save(rawBuffer, format='JPEG') # PNG files end up bigger after this resizing (!?)
rawImage = rawBuffer.getvalue()
print(sys.getsizeof(rawImage))
To shrink it I've tried getting a shrink ratio and then simply resizing it:
shrinkRatio = 10485760.0 / float(rawImageSize)
imageWidth, imageHeight = pilImage.size
shrunkImage = imageToShrink.resize((int(imageWidth * shrinkRatio),
int(imageHeight * shrinkRatio)), Image.LANCZOS)
Of course I could use a sufficiently small and somewhat arbitrary thumbnail size instead. I've thought about iterating thumbnail sizes until a combination takes me below the maximum bytes size threshold. I'm guessing the bytes size varies based on the color depth and mode and (?) I got from the end user that uploaded the original image. And that brings me to my questions:
Can I predict the size in bytes a PIL Image will be before I convert it for consumption by Google Vision? What is the best way to manage that size in bytes before I convert it?
First all, you probably don't need to maximize to the 10M limit posed by Google Vision API. In most case, a much smaller file will be just fine, and faster.
In addition to that, you may want to keep in mind that the aspect ratio might lead to different result. See this, https://www.mlreader.com/prepare-image-for-google-vision-api

Why smaller PNG image takes up more space than the original after getting resized by GraphicsMagic

The original PNG image is 800x1200 and takes up about 34K. After the images is resized by GraphicsMagick to 320x480 size, the resulting images takes up approximately 37K. (For comparison, if the image is resized with Paint on Windows 7 then the resulting image is 40K.) What gives? The whole point of resizing an image was to save space. How should GraphicsMagick be used to shrink the image size?
PNG is a lossless format and compresses the image data by first performing a step called prediction and then applying the same algorithm used in zlib. The prediction step is a crucial one in order to effectively compress the file, and it is based on the values of earlier neighbors pixels.
So, suppose you have a large PNG in black & white (by that I really mean only black and white, some people confuse that by grayscale sometimes). Also suppose it is not a tiny checkerboard pattern. In many regions of this image, you will have a relatively large white region, and then a relatively large black region, and so on. When the predictor is inside one of these large regions, it has no trouble to correctly predict that the current pixel intensity is exactly equal to the last one. This makes it easier to better compress the data describing your image.
Now, let us downscale this black & white image using some resampling filter different than nearest neighbor (let's say Lanczos). This has a great chance to turn your black & white image into a grayscale one, which has a much greater intensity range. This potentially makes the job of the predictor much harder, and thus the final file size might be larger.
For instance here is a black & white 256x256 PNG image which takes 5440 bytes, a resizing of it (using 3-lobed Lanczos) to 120x120 which now takes 7658 bytes, and another resizing (using nearest neighbor) to 120x120 which occupies 2467 bytes.
PNG is a compressed format. Sometimes trying to compress a maximally compressed item actually results in a larger item. So if the 800x1200 is resized to a smaller size, but the result retains everything that was in the original, because the original is already as minimal as possible, you could see this happen. To demonstrate this, try using 7zip to compress some data with ultra compression. Then try compressing the compressed file. Often the second compressed file will be larger than the first.

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.

How does one embed a file inside of an image? iOS iPhone

There is an app on the app store called active photo (http://itunes.apple.com/us/app/active-photo/id366798464?mt=8) that allows you to embed a hidden image or .exe file inside of an image. I would like to know how to do this regrading adding images to images, kinda like sub images in the original image.
I've been looking into metadata but no tag seems to be big enough to hold an NSData representation of the second picture.
How would one go about adding any type of file to an image, either through embedding or metadata, that would allow the image to be sent though email and or text message and still retain the data?
Thank you.
This is known as steganography.
I would imagine the simplest way of hiding a file inside a JPEG image is just to alter its pixel data in such a way that the compression doesn't damage it but is subtle enough that an interceptor can't detect the hidden data.
I don't think it is possible with JPEG because it's a lossy compression so you would end up corrupting the embedded file. But PNG uses a compression method similar to Deflate, which is loseless.
I have started writing a program like this. The idea was to hide bytes of data by splitting them into the least significant bits of pixels' color channels. Let me do some examples.
An RGB-8 image represents a pixel with 3 bytes, one for red, one for green and one for blue. I store 3 bits into red channel, two into green (human eye is more sensitive to green color) and 3 into blue. So I embed one byte per pixel. Similarly with RGBA-8 image I do 2-2-2-2. This of course involves some bitwise operations.
Things become more interesting with RGB(A)-16 images, where there are two bytes per channel. I use the entire least significant byte of every channel with minimal distortion (worst case 255 / 65535 = ~3.9%) and store up to 3 or 4 bytes of data per pixel. Not bad!!
Moreover there are no complex bitwise operations in this case, a single assignement does the job.
There are lot of improvement to it. I thought to ask the user a password, hash it and seed a secure pseudo random number generator, then no longer move pixel by pixel but instead asking the generator for a new random index.
The drawback of this solution is that the more data has already been embedded, the slower it becomes, because the generator will give more and more occupied indices. But it is much more secure in this way. To make it even more safer I thought to introduce noise data in the untouched pixels, in order to hide the positions of the true data.
As you can see you can do a lot with PNG images! If you are interested I can give the code I wrote so far.

Best practice for PNG optimization?

I 'd like to prepare my PNGs for the best optimization, so I can get the best image quality (lossless if possible) and the smallest size.
From what I understand, I should use: PNG, 72 dpi, RGB, but what else?
Here is what we find in the iPhone HIG:
Note:*The standard bit depth for icons and images is 24 bits (8 bits each for red, green, and blue), plus an 8-bit alpha channel. The PNG format is recommended, because it preserves color depth and supports an embedded alpha channel.
I guess this mean we should save the image as PNG 24 and create them in 8 bits mode? But I also read about 32 bits for best quality ?
The interlacing scheme (witch add to the file size) allows for the PNGs to display faster. Does this applies to the iPhone?
Thanks.
I suggest using ImageAlpha (lossy) on as many images as you can, because it greatly reduces their size.
Optimize all images with ImageOptim — it will remove all invisible junk and re-compress the data.
Disable Xcode conversion, because it undoes other optimisations and can make images much slower to load.
24 bit is red, green and blue with 8 bits each. 32 bits is RGB plus an 8-bit alpha channel. So if you need (semi-)transparent images, you should go for 32bit PNG, otherwise 24bit.
You don't have to compress/crush the PNGs yourself, Xcode's build steps will automatically use pngcrush and re-order the color channels for the iPhone's BGR memory alignment.
For my background app I am using JPEG (Export for web in photoshop) with quality 70.
Last day I heard about pngcrunch, tried it but file size is the same...
http://pmt.sourceforge.net/pngcrush/
Take a look at this previous post :
Understanding 24 bit PNG generated with Photoshop