5

I've been trying a ton of different options and tricks for getting a UIImage to build properly from a CIImage. But, every time I create the CIImage its colors seem to be inverted.

The most recent code I have is:

NSURL *url = [[NSBundle mainBundle] URLForResource:@"C4Sky" withExtension:@"png"];
CIImage *c = [CIImage imageWithContentsOfURL:url];
UIImage *i = [UIImage imageWithCIImage:c];
UIImageView *uiiv = [[UIImageView alloc] initWithImage:i];
[self.canvas addSubview:uiiv];

Which produces the following image:

The inverted color image.

However, building an image like this:

UIImage *i = [UIImage imageNamed:@"C4Sky"];
UIImageView *uiiv = [[UIImageView alloc] initWithImage:i];
[self.canvas addSubview:uiiv];

... produces the following image:

enter image description here

I've tried a lot of different ways of constructing the CIImage.

Is this happening because the pixel format in iOS for a CIImage is ARGB? (It seems this is the only format possible on iOS6 right now)

If so, how can I swap pixel formats get this CIImage to look normal?



I've created a project repo on git showing all the major different ways I've tried (not including variations of each). There are 6 methods, the first 5 failing:

https://github.com/C4Code/CIImageTest

The last method works, but it's really dirty:

-(void)test6 {
    UIImage *img = [UIImage imageNamed:@"C4Sky"];

    CGContextRef    bitmapContext = NULL;
    void *          bitmapData;
    int             bitmapByteCount;
    int             bitmapBytesPerRow;
    CGSize          size = img.size;
    bitmapBytesPerRow   = (size.width * 4);
    bitmapByteCount     = (bitmapBytesPerRow * size.height);
    bitmapData = malloc( bitmapByteCount );
    bitmapContext = CGBitmapContextCreate(bitmapData, size.width, size.height,8,bitmapBytesPerRow,
                                          CGColorSpaceCreateDeviceRGB(),kCGImageAlphaPremultipliedFirst);
    CGContextDrawImage(bitmapContext, (CGRect){CGPointZero,size}, img.CGImage);
    CGImageRef imgRef = CGBitmapContextCreateImage(bitmapContext);

    CIImage *cii = [CIImage imageWithCGImage:imgRef];
    UIImage *finalImage = [UIImage imageWithCIImage:cii];

    UIImageView *uiiv = [[UIImageView alloc] initWithImage:finalImage];
    [self.canvas addSubview:uiiv];
    //works but it's dirrrrrrrty
}

I am drawing from a UIImage into my own graphics context, and because this works it has me believe that there might be a bug with CIImage's native implementation. That is, creating a CIImage from a UIImage doesn't work... Again, the only thing I can think of is that the CIImage is in ARGB space, and the UIImage isn't... But, I don't know how to get around this?

Is this a bug?

Community
  • 1
  • 1
C4 - Travis
  • 4,502
  • 4
  • 31
  • 56

3 Answers3

6

A few additional variants to try:

//Grab the CIImage directly from the UIImage
UIImage *img = [UIImage imageNamed:@"C4Sky.png"];
CIImage *c = img.CIImage;
UIImage *i = [UIImage imageWithCIImage:c];
UIImageView *uiiv = [[UIImageView alloc] initWithImage:i];
[self.canvas addSubview:uiiv];

Or

//Maybe you need to set your own color space?
UIImage *img = [UIImage imageNamed:@"C4Sky.png"];
CIImage *c = [CIImage imageWithCGImage:img.CGImage options:@{kCIImageColorSpace: kCGColorSpaceModelRGB}];
UIImage *i = [UIImage imageWithCIImage:c];
UIImageView *uiiv = [[UIImageView alloc] initWithImage:i];
[self.canvas addSubview:uiiv];

-jt

jimt
  • 1,980
  • 2
  • 21
  • 28
2

This bit me before too. I convert UIImages from CIImages with something like this:

- (UIImage *)newUIImageFromCIImage:(CIImage *)image
{
    CGImageRef newImageRef = [[CIContext contextWithOptions:nil] createCGImage:image fromRect:[image extent]]; // you can cache CIContext as it's a little slow to create
    UIImage *newImage = [[UIImage alloc] initWithCGImage:newImageRef];
    CGImageRelease(newImageRef);

    return newImage;
}

Some discussions here.

Community
  • 1
  • 1
John Estropia
  • 17,460
  • 4
  • 46
  • 50
1

have a look at this tutorial. YOu have to apply filters before it looks alright. Hope this helps!

rachel :)

e.g. (just in case link breaks)

CIImage *beginImage = [CIImage imageWithContentsOfURL:fileNameAndPath];

CIContext *context = [CIContext contextWithOptions:nil];

CIFilter *filter = [CIFilter filterWithName:@"CISepiaTone"
                          keysAndValues: kCIInputImageKey, beginImage,
                @"inputIntensity", @0.8, nil];
CIImage *outputImage = [filter outputImage];


CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]];


UIImage *newImage = [UIImage imageWithCGImage:cgimg]; 
self.imageView.image = newImage;


CGImageRelease(cgimg);
Rachel Gallen
  • 27,943
  • 21
  • 72
  • 81
  • Hey rachel, thanks for the link, but this code still produces the same error only with a sepia tone to it. – C4 - Travis Jan 31 '13 at 08:02
  • Yes, had a look at the link, but there doesn't seem to be a filter which will fix this issue, if you know which one that would be great. I think it could be a bug with UIImage's constructors, img.CGImage should produce a Core Graphics representation of the exact same image... not one that looks like the topmost image. – C4 - Travis Jan 31 '13 at 08:26
  • look at this link it's better http://stackoverflow.com/questions/8425647/how-to-convert-uiimage-to-ciimage-and-vise-verse you might be doing overkill – Rachel Gallen Jan 31 '13 at 08:29
  • this is a list of filters https://developer.apple.com/library/mac/#documentation/graphicsimaging/reference/CoreImageFilterReference/Reference/reference.html – Rachel Gallen Jan 31 '13 at 08:33