1

I need to rotate an image by 90 degrees i.e, swap the width and height (flip the image). This needs to be done before I feed the image to the encoder for creating a video out of it. I use the following code (Reference: How do I export UIImage array as a movie?)

- (CVPixelBufferRef) newPixelBufferFromCGImage: (CGImageRef) image
{
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
        [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
        [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
        nil];
    CVPixelBufferRef pxbuffer = NULL;
    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, CGImageGetWidth(image),
        CGImageGetHeight(image), kCVPixelFormatType_32ARGB, (CFDictionaryRef) options, 
        &pxbuffer);
    NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);

    CVPixelBufferLockBaseAddress(pxbuffer, 0);
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
    NSParameterAssert(pxdata != NULL);

    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pxdata, CGImageGetWidth(image),
        CGImageGetHeight(image), 8, 4*CGImageGetWidth(image), rgbColorSpace, 
        kCGImageAlphaNoneSkipFirst);
    NSParameterAssert(context);
    CGContextConcatCTM(context, CGAffineTransformMakeRotation(1.571)); // ROTATION
    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), 
        CGImageGetHeight(image)), image);
    CGColorSpaceRelease(rgbColorSpace);
    CGContextRelease(context);

    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);

    return pxbuffer;
}

However, the rotation by 90 degrees doesn't work (indicated by a comment). Can you please identify the problem ?

Community
  • 1
  • 1
Hrishikesh_Pardeshi
  • 995
  • 4
  • 19
  • 45

1 Answers1

4

The transform you're applying IS rotating the context, the problem is that the origin is on the corner rather than the center of the context. By rotating the image 90 degrees you completely move it to negative bounds and hence don't see anything. Assuming that in your code frameSize is the size of the rotated image (with the inverted width/height), you need to move this origin to the center and apply the rotation there. Try:

CGContextTranslateCTM(context, frameSize.width / 2, frameSize.height / 2);
CGContextRotateCTM(context, M_PI_2);
CGContextTranslateCTM(context, -frameSize.height / 2, -frameSize.width / 2);
CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);


- (CVPixelBufferRef) newPixelBufferFromCGImage: (CGImageRef) image
{
    CGSize frameSize = CGSizeMake(CGImageGetHeight(image), CGImageGetWidth(image));
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
        [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
        [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
        nil];
    CVPixelBufferRef pxbuffer = NULL;
    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, frameSize.width,
        frameSize.height, kCVPixelFormatType_32ARGB, (CFDictionaryRef) options, 
        &pxbuffer);
    NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);

    CVPixelBufferLockBaseAddress(pxbuffer, 0);
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
    NSParameterAssert(pxdata != NULL);

    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pxdata, frameSize.width,
        frameSize.height, 8, 4 * frameSize.width, rgbColorSpace, 
        kCGImageAlphaNoneSkipFirst);
    NSParameterAssert(context);
    CGContextTranslateCTM(context, frameSize.width / 2, frameSize.height / 2);
    CGContextRotateCTM(context, M_PI_2);
    CGContextTranslateCTM(context, -frameSize.height / 2, -frameSize.width / 2);
    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);

    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), 
        CGImageGetHeight(image)), image);
    CGColorSpaceRelease(rgbColorSpace);
    CGContextRelease(context);

    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);

    return pxbuffer;
}
Fernando Mazzon
  • 3,562
  • 1
  • 19
  • 21
  • Thanks for the reply. I understand what you say, but the method still doesn't work. Also, frameSize would be the image size itself. Sorry for the confusion, I have updated in the code posted. – Hrishikesh_Pardeshi Jan 03 '13 at 04:13
  • 1
    This is the code I use: CGContextTranslateCTM(context, CGImageGetHeight(image)/2, CGImageGetWidth(image)/2); CGContextRotateCTM(context, M_PI_2); CGContextTranslateCTM(context, -CGImageGetWidth(image)/2, -CGImageGetHeight(image)/2); The image rotates but is cut out half on rotation. – Hrishikesh_Pardeshi Jan 03 '13 at 04:44
  • Added the full code. Check it out. You must have mixed up the size when creating the context. – Fernando Mazzon Jan 03 '13 at 13:51
  • Thanks. It does work. You were correct, I was messing up the size. But, it takes a lot of time for the rotation. – Hrishikesh_Pardeshi Jan 04 '13 at 04:17