Search code examples
objective-ccore-graphicsgraphicsmagick

How to convert from CGImageRef to GraphicsMagick Blob type?


I have a fairly standard RGBA image as a CGImageRef.

I'm looking to convert this into a GraphicsMagick Blob (http://www.graphicsmagick.org/Magick++/Image.html#blobs)

What's the best way to go about transposing it?

I have this but it produces only a plain black image if I specify PNG8 in the pathString or it crashes:

- (void)saveImage:(CGImageRef)image path:(NSString *)pathString
{
    CGDataProviderRef dataProvider = CGImageGetDataProvider(image);
    NSData *data = CFBridgingRelease(CGDataProviderCopyData(dataProvider));
    const void *bytes = [data bytes];

    size_t width = CGImageGetWidth(image);
    size_t height = CGImageGetHeight(image);
    size_t length = CGImageGetBytesPerRow(image) * height;

    NSString *sizeString = [NSString stringWithFormat:@"%ldx%ld", width, height];

    Image pngImage;
    Blob blob(bytes, length);

    pngImage.read(blob);
    pngImage.size([sizeString UTF8String]);
    pngImage.magick("RGBA");
    pngImage.write([pathString UTF8String]);
}

Solution

  • Needed to get the image in the right RGBA format first. The original CGImageRef had a huge number of bytes per row. Creating a context with only 4 bytes per pixel did the trick.

    // Calculate the image width, height and bytes per row
    size_t width = CGImageGetWidth(image);
    size_t height = CGImageGetHeight(image);
    size_t bytesPerRow = 4 * width;
    size_t length = bytesPerRow * height;
    
    // Set the frame
    CGRect frame = CGRectMake(0, 0, width, height);
    
    // Create context
    CGContextRef context = CGBitmapContextCreate(NULL,
                                                 width,
                                                 height,
                                                 CGImageGetBitsPerComponent(image),
                                                 bytesPerRow,
                                                 CGImageGetColorSpace(image),
                                                 kCGImageAlphaPremultipliedLast);
    
    if (!context) {
        return;
    }
    
    // Draw the image inside the context
    CGContextSetBlendMode(context, kCGBlendModeCopy);
    CGContextDrawImage(context, frame, image);
    
    // Get the bitmap data from the context
    void *bytes = CGBitmapContextGetData(context);