Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrong rotation when loading image using CGImageSourceRef

I load images in a C++ library using the code below. When loading some images the rotation of the image is wrong. It seems to affect JPEGs that come from the iPhone camera. How do I fix this?

Presumably there is a flag somewhere that gets set for JPEGs captured by the camera. I'm not sure how to access it when loading the images in this way.

CGImageSourceRef source = CGImageSourceCreateWithURL(url, NULL);
CFRelease(url);

if(source==NULL)
    return IM_ErrFileError;

CGImageRef image = CGImageSourceCreateImageAtIndex(source, 0, NULL);
CFRelease(source);

if(image==NULL)
    return IM_ErrFileError;

int w = (int)CGImageGetWidth(image);
int h = (int)CGImageGetHeight(image);

im::Err err = img.Create(im::IntSize(w, h), bands, sizeof(uint8_t), imgtype);
if(IM_FAILED(err))
{
    CGImageRelease(image);
    return err;
}

img.Clear();

CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(colorspacename);
if(colorSpace==NULL)
{
    CGImageRelease(image);
    return IM_ErrAlloc;
}

// Create RGBA context
CGContextRef context = CGBitmapContextCreate(img.BytePtr(), w, h, 8, img.StrideBytes(), colorSpace, alphainfo);

if(context==NULL)
{
    CGColorSpaceRelease(colorSpace);
    CGImageRelease(image);
    return IM_ErrAlloc;
}

CGColorSpaceRelease(colorSpace);

CGRect rect;

rect.origin.x = 0;
rect.origin.y = 0;
rect.size.width = w;
rect.size.height = h;

CGContextDrawImage(context, rect, image);

CGContextRelease(context);
CGImageRelease(image);

Based on the answer, here is how I modified my code. First get the orientation:

int orientation = 1;

CFDictionaryRef dict = CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);
if(dict)
{
    CFNumberRef imageOrientation;

    if(CFDictionaryGetValueIfPresent(dict, kCGImagePropertyOrientation, (const void **)&imageOrientation))
    {
        if(imageOrientation)
            CFNumberGetValue(imageOrientation, kCFNumberIntType, &orientation);
    }

    CFRelease(dict);
}

Ensure that the sizes are correct:

int width = (int)CGImageGetWidth(image);
int height = (int)CGImageGetHeight(image);

int canvasw, canvash;

if(orientation<=4)
{
    canvasw = width;
    canvash = height;
}
else
{
    canvasw = height;
    canvash = width;
}

Use the canvas size to create the bitmap context image. Compensate for the orientation when rendering:

switch(orientation)
{
    case 2:
        // 2 = 0th row is at the top, and 0th column is on the right - Flip Horizontal
        CGContextConcatCTM(context, CGAffineTransformMake(-1.0, 0.0, 0.0, 1.0, width, 0.0));
        break;

    case 3:
        // 3 = 0th row is at the bottom, and 0th column is on the right - Rotate 180 degrees
        CGContextConcatCTM(context, CGAffineTransformMake(-1.0, 0.0, 0.0, -1.0, width, height));
        break;

    case 4:
        // 4 = 0th row is at the bottom, and 0th column is on the left - Flip Vertical
        CGContextConcatCTM(context, CGAffineTransformMake(1.0, 0.0, 0, -1.0, 0.0, height));
        break;

    case 5:
        // 5 = 0th row is on the left, and 0th column is the top - Rotate -90 degrees and Flip Vertical
        CGContextConcatCTM(context, CGAffineTransformMake(0.0, -1.0, -1.0, 0.0, height, width));
        break;

    case 6:
        // 6 = 0th row is on the right, and 0th column is the top - Rotate 90 degrees
        CGContextConcatCTM(context, CGAffineTransformMake(0.0, -1.0, 1.0, 0.0, 0.0, width));
        break;

    case 7:
        // 7 = 0th row is on the right, and 0th column is the bottom - Rotate 90 degrees and Flip Vertical
        CGContextConcatCTM(context, CGAffineTransformMake(0.0, 1.0, 1.0, 0.0, 0.0, 0.0));
        break;

    case 8:
        // 8 = 0th row is on the left, and 0th column is the bottom - Rotate -90 degrees
        CGContextConcatCTM(context, CGAffineTransformMake(0.0, 1.0, -1.0, 0.0, height, 0.0));
        break;

    default:
        break;
}
like image 590
Robotbugs Avatar asked Oct 01 '22 07:10

Robotbugs


1 Answers

I haven't actually tried this with iPhone images, but I suggest using CGImageSourceCopyPropertiesAtIndex to get kCGImagePropertyOrientation. Once you know the proper orientation, you can apply some transformation when you draw it.

like image 159
JWWalker Avatar answered Oct 04 '22 07:10

JWWalker