Dan Wood: The Eponymous Weblog (Archives)

Dan Wood Dan Wood is co-owner of Karelia Software, creating programs for the Macintosh computer. He is the father of two kids, lives in the Bay Area of California USA, and prefers bicycles to cars. This site is his older weblog, which mostly covers geeky topics like Macs and Mac Programming. Go visit the current blog here.

Useful Tidbits and Egotistical Musings from Dan Wood

Categories: Business · Mac OS X · Cocoa Programming · General · All Categories

Sun, 04 Feb 2007

Preserve Metadata when resizing JPEG images

One thing that Sandvox does is to make resized copies of image files. There are often a lot of useful metadata in a JPEG file, so I decided that it would be a good idea to preserve these as much as possible if scaling down a JPEG file to another size. Many but not all of these are supported by NSImage, so it's not hard to extract from the original image and put in the other.

To do this, you just need to extract the metadata from the source and apply to the new image. You can get the NSImageEXIFData and NSImageColorSyncProfileData and apply to the new image.

Here's a category method on NSImage that will do the trick. You pass in the original bitmap that the scaled image (self) will use for its source metadata.

- (NSData *)JPEGRepresentationWithQuality:(float)aQuality
    originalBitmap:(NSBitmapImageRep *)parentImage;
{
    NSMutableDictionary *props;
    if (nil != parentImage)
    {
        NSSet *propsToExtract = [NSSet setWithObjects: NSImageEXIFData,
            NSImageColorSyncProfileData, nil];
        props = [parentImage dictionaryOfPropertiesWithSetOfKeys:
                    propsToExtract];
        
        // Fix up dictionary to take out ISOSpeedRatings since that
        // doesn't appear to be settable
        NSDictionary *exifDict = [props objectForKey:NSImageEXIFData];
        if (nil != exifDict)
        {
            NSMutableDictionary *dict
              = [NSMutableDictionary dictionaryWithDictionary:exifDict];
            [dict removeObjectForKey:@"ISOSpeedRatings"];
            [props setObject:dict forKey:NSImageEXIFData];
        }
    }
    else
    {
        props = [NSMutableDictionary dictionary];
    }
    // Now set our desired compression property, and make the image NOT
    // progressive for the benefit of the flash-based viewers who care
    // about that kind of thing
    [props setObject:[NSNumber numberWithFloat:aQuality] 
        forKey:NSImageCompressionFactor];
    [props setObject:[NSNumber numberWithBool:NO]
        forKey:NSImageProgressive];
    
    NSData *result = [[self bitmap]	// method to get images's bitmap
        representationUsingType:NSJPEGFileType
                     properties:props];
    
    return result;
}

PNG files have a bit of metadata too; this technique could also apply for PNG to PNG conversion as well.