3ef9g
3ef9g

Reputation: 881

How to create a CGImageSourceRef from image raw data?

How to create a CGImageSourceRef from raw data? I have one file that consists only of the pixel information of an image. I know the resolution and the depth and so on (e.g. 640x860, RGB, 8bit, orientation = 1, DPI = 300). These informations aren't stored inside the file. As I already wrote, this file just stores the raw pixel information.

Now I tried the following:

NSString *path = @"/Users/.../Desktop/image";
NSData *data = [NSData dataWithContentsOfFile: path];
CFDataRef cfdata = CFDataCreate(NULL, [data bytes], [data length]);
CFDictionaryRef options;
CGImageSourceRef imageSource = CGImageSourceCreateWithData(cfdata, nil);

The image is not created correctly, because of the undefined image dimensions. I have no idea how to define the image informations (resolution and so on) for this CFImageSourceRef. Think I have to initialize the CFDictionaryRef options and deliver it to

CGImageSourceRef imageSource = CGImageSourceCreateWithData(cfdata, options);

How can I create a CFDictionaryRef that it is usable for the method CGImageSourceCreateWithData?

Upvotes: 3

Views: 5863

Answers (2)

Ken Thomases
Ken Thomases

Reputation: 90521

You don't want to use a CGImageSource. That's not suitable for raw pixel data. It's for standard image file formats (PNG, GIF, JPEG, etc.). You should create the CGImage directly using CGImageCreate():

NSString *path = @"/Users/.../Desktop/image";
NSData *data = [NSData dataWithContentsOfFile: path];
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
CGImageRef image = CGImageCreate(640, // width
                                 860, // height
                                 8, // bitsPerComponent
                                 32, // bitsPerPixel
                                 4 * 640, // bytesPerRow
                                 colorspace,
                                 kCGImageAlphaNoneSkipFirst, // bitmapInfo
                                 provider,
                                 NULL, // decode
                                 true, // shouldInterpolate
                                 kCGRenderingIntentDefault // intent
                                 );
CGColorSpaceRelease(colorspace);
CGDataProviderRelease(provider);

Some of the above (bitsPerComponent, bitsPerPixel, bytesPerRow, bitmapInfo) are guesses based on your brief description of your pixel data. If they are not correct for your data, adjust them.

You could create the data provider directly from the file using CGDataProviderCreateWithURL() or CGDataProviderCreateWithFilename(), but I decided to illustrate the more general means of creating it with raw data that could come from anywhere.

Upvotes: 2

Josip B.
Josip B.

Reputation: 2464

I'm not sure if this code can help you but in this way I create images downloaded from networking. Originally I found this code in one of AFNetworking classes.

- (UIImage *)imageFromResponse:(NSHTTPURLResponse *)response data:(NSData *)data scale:(CGFloat)scale {

    if (!data || [data length] == 0) {
        return nil;
    }

    CGImageRef imageRef = NULL;
    CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);

    if ([response.MIMEType isEqualToString:@"image/png"]) {
        imageRef = CGImageCreateWithPNGDataProvider(dataProvider,  NULL, true, kCGRenderingIntentDefault);
    } else if ([response.MIMEType isEqualToString:@"image/jpeg"]) {
        imageRef = CGImageCreateWithJPEGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault);

        // CGImageCreateWithJPEGDataProvider does not properly handle CMKY, so if so, fall back to AFImageWithDataAtScale
        if (imageRef) {
            CGColorSpaceRef imageColorSpace = CGImageGetColorSpace(imageRef);
            CGColorSpaceModel imageColorSpaceModel = CGColorSpaceGetModel(imageColorSpace);
            if (imageColorSpaceModel == kCGColorSpaceModelCMYK) {
                CGImageRelease(imageRef);
                imageRef = NULL;
            }
        }
    }

    CGDataProviderRelease(dataProvider);

    UIImage *anImage = [[UIImage alloc] initWithData:data];
    UIImage *image = [[UIImage alloc] initWithCGImage:[anImage CGImage] scale:scale orientation:anImage.imageOrientation];

    if (!imageRef) {
        if (image.images || !image) {
            return image;
        }

        imageRef = CGImageCreateCopy([image CGImage]);
        if (!imageRef) {
            return nil;
        }
    }

    size_t width = CGImageGetWidth(imageRef);
    size_t height = CGImageGetHeight(imageRef);
    size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef);

    if (width * height > 1024 * 1024 || bitsPerComponent > 8) {
        CGImageRelease(imageRef);

        return image;
    }

    size_t bytesPerRow = 0; // CGImageGetBytesPerRow() calculates incorrectly in iOS 5.0, so defer to CGBitmapContextCreate
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace);
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);

    if (colorSpaceModel == kCGColorSpaceModelRGB) {
        uint32_t alpha = (bitmapInfo & kCGBitmapAlphaInfoMask);
        if (alpha == kCGImageAlphaNone) {
            bitmapInfo &= ~kCGBitmapAlphaInfoMask;
            bitmapInfo |= kCGImageAlphaNoneSkipFirst;
        } else if (!(alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast)) {
            bitmapInfo &= ~kCGBitmapAlphaInfoMask;
            bitmapInfo |= kCGImageAlphaPremultipliedFirst;
        }
    }

    CGContextRef context = CGBitmapContextCreate(NULL, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo);

    CGColorSpaceRelease(colorSpace);

    if (!context) {
        CGImageRelease(imageRef);
        return image;
    }

    CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), imageRef);
    CGImageRef inflatedImageRef = CGBitmapContextCreateImage(context);

    CGContextRelease(context);

    UIImage *inflatedImage = [[UIImage alloc] initWithCGImage:inflatedImageRef scale:scale orientation:image.imageOrientation];

    CGImageRelease(inflatedImageRef);
    CGImageRelease(imageRef);

    return inflatedImage;
}

Upvotes: 0

Related Questions