7

In iOS to save an UIImage as JPEG, I use UIImageJPEGRepresentation, however it doesn't take options other than compression ratio. I wish to save the UIImage into progressive JPEG format, is there a easy way to do so?

Looks like in OS X there is an NSImageProgressive option to save NSImage to progressive format.

Mike Abdullah
  • 14,933
  • 2
  • 50
  • 75
Robert Mao
  • 1,911
  • 22
  • 24

2 Answers2

9

I think you can do it using the ImageIO framework, like this:

#import <UIKit/UIKit.h>
#import <ImageIO/ImageIO.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import "AppDelegate.h"

int main(int argc, char *argv[])
{
    @autoreleasepool {
        UIImage *sourceImage = [UIImage imageNamed:@"test.jpg"];

        CFURLRef url = CFURLCreateWithString(NULL, CFSTR("file:///tmp/progressive.jpg"), NULL);
        CGImageDestinationRef destination = CGImageDestinationCreateWithURL(url, kUTTypeJPEG, 1, NULL);
        CFRelease(url);

        NSDictionary *jfifProperties = [NSDictionary dictionaryWithObjectsAndKeys:
            (__bridge id)kCFBooleanTrue, kCGImagePropertyJFIFIsProgressive,
            nil];

        NSDictionary *properties = [NSDictionary dictionaryWithObjectsAndKeys:
            [NSNumber numberWithFloat:.6], kCGImageDestinationLossyCompressionQuality,
            jfifProperties, kCGImagePropertyJFIFDictionary,
            nil];

        CGImageDestinationAddImage(destination, sourceImage.CGImage, (__bridge CFDictionaryRef)properties);
        CGImageDestinationFinalize(destination);
        CFRelease(destination);

        return 0;
    }
}

Preview.app says the output file is progressive, and ImageMagick's identify command says it has “Interlace: JPEG”.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
0

This code does work on the device - the key is to specify all the density values (note its using new literal syntax):

- (UIImage *)imager
{
    UIImage *object = [UIImage imageNamed:@"Untitled.jpg"];
    NSString *str = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"Tester.jpg"];
    NSURL *url = [[NSURL alloc] initFileURLWithPath:str];

    CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)url, kUTTypeJPEG, 1, NULL);

    NSDictionary *jfifProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                    @72, kCGImagePropertyJFIFXDensity,
                                    @72, kCGImagePropertyJFIFYDensity,
                                    @1, kCGImagePropertyJFIFDensityUnit,
                                    nil];

    NSDictionary *properties = [NSDictionary dictionaryWithObjectsAndKeys:
                                [NSNumber numberWithFloat:.5f], kCGImageDestinationLossyCompressionQuality,
                                jfifProperties, kCGImagePropertyJFIFDictionary,
                                nil];

    CGImageDestinationAddImage(destination, ((UIImage*)object).CGImage, (__bridge CFDictionaryRef)properties);
    CGImageDestinationFinalize(destination);
    CFRelease(destination);

    return [UIImage imageWithContentsOfFile:str];
}
David H
  • 40,852
  • 12
  • 92
  • 138
  • 1
    Shouldn't `(__bridge id)kCFBooleanTrue, kCGImagePropertyJFIFIsProgressive` be a part of the `jfifProperties`? I had to add that to actually get it to save as a progressive image. – qix Aug 30 '13 at 19:54
  • @Linus, when I answered this question either I missed this, or there was no such property. Evidently this answer has been of no use to anyone certainly not the original poster, so I would view what is here with suspicion (even though of course I'm pretty sure its correct or I would not have posted it :-)) – David H Aug 30 '13 at 22:56