Ninjas are deadly. Chipmunk Ninjas are just weird.
About this blog
Marc Travels
Marc on Twitter
JustLooking on Twitter

Marc Wandschneider is a professional software developer with well over fifteen years of industry experience (yes, he really is that old). He travels the globe working on interesting projects and gives talks at conferences and trade shows whenever possible.

My Publications:

My book, "Core Web Application Programming with PHP and MySQL" is now available everywhere, including

My "PHP and MySQL LiveLessons" DVD Series has just been published by Prentice-Hall, and can be purchased on Amazon, through Informit, or Safari

Sep 20, 2006 | 19:56:12
Rotating an NSImage object in Cocoa
By marcwan

I recently started working on an image viewing program for Mac OS X using Cocoa, and one of the features I decided to add was the ability to rotate images in 90° increments. I did some searching on the internet, and found a few things:

Neither of the first two was exactly what I wanted—the first didn’t quite work, while the second was too complicated and, in order to support arbitrary rotation, created an NSImage object that was way too large.

So, after reading the Apple Cocoa Drawing Guide on Using Transforms, I came up with the following code to rotate an NSImage object 90°. Please note that this function ONLY supports a clockwise or counterclockwise 90° rotation. It also returns an object that must be released by the callER. I’m not 100% sure if this is standard Objective-C/Cocoa methodology, as I’m still a bit new to all this stuff.

But, without any further ado, here is the rotation function:

- (NSImage *)rotateIndividualImage: (NSImage *)image clockwise: (BOOL)clockwise
    NSImage *existingImage = image;
    NSSize existingSize;

     * Get the size of the original image in its raw bitmap format.
     * The bestRepresentationForDevice: nil tells the NSImage to just
     * give us the raw image instead of it's wacky DPI-translated version.
    existingSize.width = [[existingImage bestRepresentationForDevice: nil] pixelsWide];
    existingSize.height = [[existingImage bestRepresentationForDevice: nil] pixelsHigh];

    NSSize newSize = NSMakeSize(existingSize.height, existingSize.width);
    NSImage *rotatedImage = [[NSImage alloc] initWithSize:newSize];

    [rotatedImage lockFocus];

     * Apply the following transformations:
     * - bring the rotation point to the centre of the image instead of
     *   the default lower, left corner (0,0).
     * - rotate it by 90 degrees, either clock or counter clockwise.
     * - re-translate the rotated image back down to the lower left corner
     *   so that it appears in the right place.
    NSAffineTransform *rotateTF = [NSAffineTransform transform];
    NSPoint centerPoint = NSMakePoint(newSize.width / 2, newSize.height / 2);

    [rotateTF translateXBy: centerPoint.x yBy: centerPoint.y];
    [rotateTF rotateByDegrees: (clockwise) ? - 90 : 90];
    [rotateTF translateXBy: -centerPoint.y yBy: -centerPoint.x];
    [rotateTF concat];

     * We have to get the image representation to do its drawing directly,
     * because otherwise the stupid NSImage DPI thingie bites us in the butt
     * again.
    NSRect r1 = NSMakeRect(0, 0, newSize.height, newSize.width);
    [[existingImage bestRepresentationForDevice: nil] drawInRect: r1];

    [rotatedImage unlockFocus];

    return rotatedImage;

The function works great and correctly rotates the incoming NSImage 90 degrees. However, People working with JPEGs should probably not save these data to disk in place of existing images, as the function works on the decompressed bits and resaving them can lose more image data. To truly solve this problem, you should use a “Lossless JPEG Image Rotation” algorithm.

Add a Comment





Copyright © 2005-2008 Marc Wandschneider All Rights Reserved.