Reputation: 881
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
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
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