Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPEG Compression Quality using CGImage

I’m using the CGImage APIs (CGImageDestination, CGBitmapContext,, CGImage etc.) on Mac OS X as well as iOS to compress images to JPEG. Using the kCGImageDestinationLossyCompressionQuality property you can control the compression quality: 0.0 being maximum compression and 1.0 being maximum quality (lossless if possible according to Apple).

I’ve found that there’s a huge jump in both disk size & image quality when you go from 0.99 to 1.0. For example, I’ve got a 2048x1368 image that compresses to 430 KB when the quality is set to 0.99 but balloons to 2.3 MB when the quality is set to 1.0. There’s a big jump in visual quality as well and the 0.99 setting isn’t acceptable for this particular image. Trying to set the quality to anything between 0.99 to 1.0 doesn’t work as the size remains at 430 KB up until 0.995 where it jumps up to 2.3 MB. Also, there really isn’t much difference between qualities of 0.90 to 0.99 which ranges in file size from ~353 KB to 430 KB, but not much improvement in visual quality.

Does anyone know if there’s any way to increase the JPEG quality? I really need something better than what 0.99 is giving me but less than what 1.0 provides. Maybe there’s some other API I could use?

I may try using libjpeg directly but I hope it doesn’t come to that.

Update

After some investigation it turns out that for all kCGImageDestinationLossyCompressionQuality settings up to 1.0 Apple uses 4:2:0 chroma subsampling (or chroma decimation). This means that for the YCrCb image they only sample one chroma pixel (CrCb) for every 4 luminance (Y) pixels. In other words they’re only using 1/4 of the chroma data from the original image. For a quality of 1.0 Apple uses 4:4:4 chroma subsampling, which is no chroma subsampling or one chroma pixel for every luminance pixel. This is why the file size explodes as the image contains 4x the color data vs. qualities <= 0.99.

So, does anyone know if there’s a way to turn off chroma subsampling using CGImage (or any other API) for qualities less than 1.0?

like image 774
Cutterpillow Avatar asked Jan 10 '14 05:01

Cutterpillow


2 Answers

Final Update

After extensive research and following the suggestions in the comments above it appears that there is no way to disable chroma subsampling/decimation with any of Apple’s built-in APIs short of setting kCGImageDestinationLossyCompressionQuality to 1.0 which results in very large images.

If you need to be able to control chroma subsampling/decimation yourself when saving to JPEG then you’ll need to use a 3rd party library such as libjpeg.

like image 169
Cutterpillow Avatar answered Oct 18 '22 22:10

Cutterpillow


Maybe there’s some other API I could use?

WebP is a new image format from Google that gives you better compression than jpg and png, both lossless and lossy. There is a project on github that is pretty easy to use: https://github.com/seanooi/iOS-WebP

You just add a category and the WebP framework to your project to use it.

//Converting To WebP
// quality value is [0, 100]
NSData *webpData = [UIImage imageToWebP:[UIImage imageNamed:@"image.jpg"] quality:75];

//Converting From WebP
UIImage *webPImage = [UIImage imageFromWebP:@"/path/to/file"];

//Setting image transparency
//alpha value is [0, 1]
UIImage *transparencyImage = [[UIImage imageNamed:image.jpg] imageByApplyingAlpha:0.5];

The alpha isn't working right, but since you are using jpg, I'm assuming you don't need it.

like image 23
Bryan Cimo Avatar answered Oct 18 '22 20:10

Bryan Cimo