views:

450

answers:

2

Loading a CGImage or NSImage from a file using a standard image format (jpeg, gif, png et.) is all very simple.

However, I now need to create a CGImage from an array in bytes in memory generated using libfreetype. Its really easy to create OpenGL textures from an array of formatted bytes, and I can see how to create a CGBitmapContext to write to. But I can't seem to find an easy way to create a CGImage from a raw pixel array.

+2  A: 

You can create a CGDataProvider, and let CG request the necessary data from your provider, instead of writing to an image buffer.

Here's a very simple example that generates a black CGImage of size 64x64.

CGDataProviderSequentialCallbacks callbacks;
callbacks.getBytes = getBytes;

CGDataProviderRef provider = CGDataProviderCreateSequential(NULL, &callbacks);
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGImageRef img = CGImageCreate(64,                         // width
                               64,                         // height
                               8,                          // bitsPerComponent
                               24,                         // bitsPerPixel
                               64*3,                       // bytesPerRow
                               space,                      // colorspace
                               kCGBitmapByteOrderDefault,  // bitmapInfo
                               provider,                   // CGDataProvider
                               NULL,                       // decode array
                               NO,                         // shouldInterpolate
                               kCGRenderingIntentDefault); // intent

CGColorSpaceRelease(space);
CGDataProviderRelease(provider);

// use the created CGImage

CGImageRelease(img);

and getBytes is defined like this:

size_t getBytes(void *info, void *buffer, size_t count) {
    memset(buffer, 0x00, count);
    return count;
}

of course, you will want to implement the other callbacks (skipForward, rewind, releaseInfo), and use a proper structure or object for info.

For more information, check out the CGImage and CGDataProvider references.

Can Berk Güder
ha. the correct function was right under my nose. It looks quite simple to wrap my data in a CFData object, and then CGDataProviderCreateWithCFData.
Chris Becke
A: 

Using CFData can make the above code simpler. Here is the code.

// raw pixel data memory of 64 * 64 pixel size

UInt8 pixelData[64 * 64 * 3];

// fill the raw pixel buffer with arbitrary gray color for test

for(size_t ui = 0; ui < 64 * 64 * 3; ui++) pixelData[ui] = 210;

CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();

CFDataRef rgbData = CFDataCreate(NULL, pixelData, 64 * 64 * 3);

CGDataProviderRef provider = CGDataProviderCreateWithCFData(rgbData);

CGImageRef rgbImageRef = CGImageCreate(64, 64, 8, 24, 64 * 3, colorspace, kCGBitmapByteOrderDefault, provider, NULL, true, kCGRenderingIntentDefault);

CFRelease(rgbData);

CGDataProviderRelease(provider);

CGColorSpaceRelease(colorspace);

// use the created CGImage

CGImageRelease(rgbImageRef);

chansuk park
The thing with the core foundation APIs - CFData etc. is that they look like they are designed to carry around ref counted instances of immutable data. But in practice they do seem to create new allocations and memcpy a lot.
Chris Becke