I am working on an OSX app that does some pixel-level image manipulation. I am using the following code to access the pixel color components (RGBA) as regular bytes cast as uint8 pointers.
NSImage *image = self.iv.image;
NSRect imageRect = NSMakeRect(0, 0, image.size.width, image.size.height);
CGImageRef cgImage = [image CGImageForProposedRect:&imageRect context:NULL hints:nil];
NSData *data = (NSData *)CFBridgingRelease(CGDataProviderCopyData(CGImageGetDataProvider(cgImage)));
uint8 *pixels = (uint8 *)[data bytes];
At this point I apply some byte level changes in:
for (int i = 0; i < [data length]; i += 4) { ... }
Changing this region of memory does not appear to have any effect on the original CGImageRef
(which is at the time displayed in an NSImageView
). I must do the following to see the image update accordingly:
CGImageRef newImageRef = CGImageCreate (width,
height,
bitsPerComponent,
bitsPerPixel,
bytesPerRow,
colorspace,
bitmapInfo,
provider,
NULL,
false,
kCGRenderingIntentDefault);
NSSize size = NSMakeSize(CGImageGetWidth(newImageRef),
CGImageGetHeight(newImageRef));
NSImage * newIm = [[NSImage alloc] initWithCGImage:newImageRef size:size];
self.iv.image = newIm;
In other words, the bytes I get back to modify are just a copy of the original bytes, presumably as a result of CGDataProviderCopyData(CGImageGetDataProvider(cgImage)
.
My question is as follows. Is there is a way to access the underlying bytes of the CGImageRef directly such that when I modify them the image is updated on screen as I manipulate them?
No. CGImage
s are immutable. You can't change them once they are created.
In your code, the call to [data bytes]
gives a pointer to const
void
. You have cast away the const
which gets it to compile without warnings, but that's a violation of the design contract. Writing to the buffer backing the data provider is not legal and not guaranteed to work, even if you create a new CGImage
from it.
I will also point out that the format of the data in the buffer may be quite different from what you were expecting. There's no good reason to expect the data to be 32 bits per pixel, RGBA vs. BGRA vs. ARGB vs. …, or anything.
I strong recommend that you read the sections about the various image objects in the 10.6 AppKit release notes. Scroll down to "NSImage, CGImage, and CoreGraphics impedance matching" and read through all of the following image-related sections until you hit "NSComboBox". The section "NSBitmapImageRep: CoreGraphics impedance matching and performance notes" is one of the more important for your purposes.
Beyond what that says, you could just maintain a pixel buffer that you allocated yourself in whatever format you prefer. Then, when you want a CGImage
of that, create it from the buffer, draw with it, and discard it. Any pixel manipulations would be done on that buffer.