访问CGImageRef底层字节并修改?

时间:2016-06-29 14:41:46

标签: macos image-processing core-graphics cgimage

我正在开发一个OSX应用程序,它可以进行一些像素级图像处理。我使用以下代码访问像素颜色组件(RGBA)作为uint8指针的常规字节。

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];

此时我在:

中应用了一些字节级别的更改
 for (int i = 0; i < [data length]; i += 4) { ... }

更改此内存区域似乎对原始CGImageRef(在NSImageView中显示的时间)没有任何影响。我必须执行以下操作以相应地查看图像更新:

 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;

换句话说,我返回修改的字节只是原始字节的副本,可能是CGDataProviderCopyData(CGImageGetDataProvider(cgImage)的结果。

我的问题如下。有没有办法直接访问CGImageRef的底层字节,这样当我修改它们时,我在操作它们时会在屏幕上更新图像?

1 个答案:

答案 0 :(得分:3)

没有。 CGImage是不可变的。创建后,您无法更改它们。

在您的代码中,对[data bytes]的调用会指向const void。你抛弃了const,它会在没有警告的情况下编译它,但这违反了设计合同。写入支持数据提供者的缓冲区是不合法的,并且不保证可以正常工作,即使您从中创建了新的CGImage

我还要指出缓冲区中数据的格式可能与您的预期完全不同。没有理由期望数据是每像素32位,RGBA与BGRA对抗ARGB与...,或任何其他。

我强烈建议您阅读10.6 AppKit release notes中有关各种图像对象的部分。向下滚动到&#34; NSImage,CGImage和CoreGraphics阻抗匹配&#34;并阅读以下所有与图像相关的部分,直到您点击&#34; NSComboBox&#34;。部分&#34; NSBitmapImageRep:CoreGraphics阻抗匹配和性能说明&#34;对你来说是最重要的一个。

除此之外,您可以维护一个像素缓冲区,您可以按照自己喜欢的格式自行分配。然后,当你想要CGImage时,从缓冲区创建它,用它绘制,然后丢弃它。任何像素操作都将在该缓冲区上完成。