7

I am trying to build a image capture for my iOS app, but I keep getting color distortion on my CGImage result. Here is the camera preview, right colors.

enter image description here

Cola is red, all is well.

When I run my snapshot code, I get this :

enter image description here

Cola is blue... where did this come from?

I tried messing with some of the parameters, but only end up getting no image at all. Here is my snapshot code :

int bitsPerComponent = 8;
    int bitsPerPixel = 32;
    int bytesPerRow = [cameraVideo bufRowBytes];
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, [cameraVideo bufDataPtr], [cameraVideo bufWidth]*[cameraVideo bufHeight]*4, NULL);

    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGImageAlphaNoneSkipLast;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentPerceptual;

    CGImageRef imageRef = CGImageCreate( [cameraVideo bufWidth], [cameraVideo bufHeight], bitsPerComponent, bitsPerPixel,
                                        bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);

    CGColorSpaceRelease(colorSpaceRef);

I am at my wits end, so if anyone can see what I am doing wrong, please let me know.

FIXED

Here is the final code:

if (cameraVideo.ARPixelFormat == kCVPixelFormatType_32ARGB) {
    bitmapInfo = kCGBitmapByteOrder32Big | kCGImageAlphaNoneSkipFirst;
} else {
    bitmapInfo = kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst;
}
Nils Munch
  • 8,805
  • 11
  • 51
  • 103

1 Answers1

12

It looks like your R (red) and B (blue) channels are swapped. The camera is filling the buffer in BGR order, but you're telling the CGImage that the data is in RGB order. I believe you control this using one of the kCGBitmapByteOrder... constants in your CGBitmapInfo. Try setting bitmapInfo like this:

CGBitmapInfo bitmapInfo = kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big;

If that doesn't work, try the other kCGBitmapByteOrder... constants (kCGBitmapByteOrder32Little, kCGBitmapByteOrder16Big, kCGBitmapByteOrder16Little).

EDIT

Apple's SquareCam sample project has a file named SquareCam/SqareCamViewController.m (yes, “Square” is misspelled in the filename). It contains this code:

    sourcePixelFormat = CVPixelBufferGetPixelFormatType( pixelBuffer );
    if ( kCVPixelFormatType_32ARGB == sourcePixelFormat )
        bitmapInfo = kCGBitmapByteOrder32Big | kCGImageAlphaNoneSkipFirst;
    else if ( kCVPixelFormatType_32BGRA == sourcePixelFormat )
        bitmapInfo = kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst;
    else
        return -95014; // only uncompressed pixel formats

You might want to do the same thing.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • +1. Good problem diagnosis! Hopefully, this will fix the OP's question tidily. :) – MrGomez Apr 02 '12 at 23:23
  • Rob, are there any other techniques for figuring out the byte order of `CGImage` besides looking at bitmap and alpha info? I'm getting [wrong endianness](http://stackoverflow.com/questions/39320474/getting-pixel-format-from-cgimage) when working with loaded png / jpeg via `NSImage` and stuck on figuring out what's happening. – Ian Bytchek Sep 04 '16 at 20:09