iPhone/iPad 上的 CGBitmapContextCreate

发布于 2024-08-28 11:07:52 字数 1067 浏览 9 评论 0原文

我有一个方法需要逐像素解析一堆大型 PNG 图像(每个 PNG 为 600x600 像素)。它似乎在模拟器上工作得很好,但在设备(iPad)上,我在某些内部内存复制功能中得到了 EXC_BAD_ACCESS 。看起来尺寸是罪魁祸首,因为如果我在较小的图像上尝试,一切似乎都有效。这是下面方法中与内存相关的内容。

+ (CGRect) getAlphaBoundsForUImage: (UIImage*) image 
{    
    CGImageRef imageRef = [image CGImage];

NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

unsigned char *rawData = malloc(height * width * 4);
memset(rawData,0,height * width * 4);

NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

CGColorSpaceRelease(colorSpace);

CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);

/* non-memory related stuff */

free(rawData);

当我在一堆图像上运行这个程序时,它运行了 12 次然后就崩溃了,而在模拟器上它运行没有问题。你们有什么想法吗?

I have a method that needs to parse through a bunch of large PNG images pixel by pixel (the PNGs are 600x600 pixels each). It seems to work great on the Simulator, but on the device (iPad), i get an EXC_BAD_ACCESS in some internal memory copying function. It seems the size is the culprit because if I try it on smaller images, everything seems to work. Here's the memory related meat of method below.

+ (CGRect) getAlphaBoundsForUImage: (UIImage*) image 
{    
    CGImageRef imageRef = [image CGImage];

NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

unsigned char *rawData = malloc(height * width * 4);
memset(rawData,0,height * width * 4);

NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

CGColorSpaceRelease(colorSpace);

CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);

/* non-memory related stuff */

free(rawData);

When I run this on a bunch of images, it runs 12 times and then craps out, while on the simulator it runs no problem. Do you guys have any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

五里雾 2024-09-04 11:07:52

运行 12 次然后崩溃听起来像是内存不足的问题。 CGContext 可能在内部创建一些大型自动释放结构。由于您是在循环中执行此操作,因此它们不会被释放,因此您会耗尽内存并死亡。

我不确定 Core Foundation 如何处理临时对象。我不认为 CF 对象具有相当于自动释放的功能,并且 Core Graphics 上下文几乎肯定是在处理 CF 对象而不是 NSObject。

为了减少代码中的内存流失,我建议在开始处理之前重构它以创建一个离屏 CGContext 一次,并重复使用它来处理每个图像。完成后释放它。在任何情况下,这都会更快(因为您不会在每次循环时分配巨大的数据结构。)

我敢打赌这将消除您的崩溃问题,而且我敢打赌它也会使您的代码更快。与其他操作相比,内存分配非常慢,并且您需要使用一些相当大的数据结构来处理 600x600 像素 RGBA 图像。

Running 12 times and then crashing sounds like a running out of memory problem. It might be that internally the CGContext is creating some large autoreleased structures. Since you're doing this in a loop, they are not getting freed, so you run out of memory and die.

I'm not sure how Core Foundation deals with temporary objects though. I don't think CF objects have the equivalent of autorelease, and a Core Graphics context is almost certainly dealing with CF objects rather than NSObjects.

To reduce the memory churn in your code, I would suggest refactoring it to create an offscreen CGContext once before you start processing, and use it repeatedly to process each image. Then release it when you are done. That is going to be faster in any case (since you aren't allocating huge data structures on each pass through the loop.)

I'll wager that will eliminate your crash problem, and I bet it also makes your code much, much faster. Memory allocation is very slow compared to other operations, and you're slinging around some pretty big data structures to handle 600x600 pixel RGBA images.

把时间冻结 2024-09-04 11:07:52

转到产品 ->编辑方案->启用僵尸对象。在启用僵尸对象之前打勾。现在构建并运行它。它可以为您提供 EXC_BAD_ACCES 错误的更好、更中肯的描述。

Goto Product -> Edit Schemes -> Enable Zombie objects. Put a tick mark before Enable Zombie objects. Now build and run it. It can give you better and to the point description for EXC_BAD_ACCES error.

桃扇骨 2024-09-04 11:07:52

我在 iPad(当然是 iPhoneOS 3.2)上使用 CGImageCreate() 时遇到了类似的崩溃。看到你的困难给了我一个暗示。我通过将 bytesPerRow 对齐到下一个最大的 2 次幂来解决这个问题。

size_t bytesPerRowPower2 = (size_t) round( pow( 2.0, trunc( log((double) bytesPerRow) / log(2.0) ) + 1.0 ) ) ;

如果提供 2 行对齐功能也能解决您的问题,请告诉我们。您需要分配 *rawData 调整后的大小并将 bytesPerRowPower2 传递给 CGBitmapContextCreate() ...高度似乎不需要对齐。

I was getting a similar crash on my iPad (iPhoneOS 3.2 of course) using CGImageCreate(). Seeing your difficulty gave me a hint. I solved the problem by aligning my bytesPerRow to the next largest power of 2.

size_t bytesPerRowPower2 = (size_t) round( pow( 2.0, trunc( log((double) bytesPerRow) / log(2.0) ) + 1.0 ) );

Let us know if providing power of 2 row alignment also solves your problem. You would need to allocate *rawData with the adjusted size and pass bytesPerRowPower2 to CGBitmapContextCreate()... The height does not seem to need alignment.

娇妻 2024-09-04 11:07:52

也许 CGImageGetBytesPerRow (两个的幂听起来有点过分)。

Perhaps CGImageGetBytesPerRow (power of two sounds excessive).

筑梦 2024-09-04 11:07:52

当我以编程方式创建图像时,我在直接定义行大小的应用程序中使用了两个对齐行大小的幂。但我也建议 toastie 在尝试我的建议之前尝试 CGImageGetBytesPerRow。

I used a power of two aligned row size in an app that was defining the row size directly, as I was creating images programmatically. But I would also recommend toastie to try CGImageGetBytesPerRow before trying my suggestion as well.

一江春梦 2024-09-04 11:07:52

在设备上运行应用程序时尝试运行仪器分配,这可能是与内存相关的问题。如果您处于循环中,请在该循环内创建一个自动释放池。

Try to Run instruments allocation while you are running the application on device, it cold be' a memory related issue. If you are in a loop, create inside that loop an auto release pool.

假扮的天使 2024-09-04 11:07:52

也许替换

CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);

CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGColorSpaceRelease(colorSpace);

,因为可能仍然需要某种颜色空间参考?只是随机猜测...
甚至可能把它放在上下文的发布后面?

// cleanup
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);

Maybe replace

CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);

with

CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGColorSpaceRelease(colorSpace);

as the color space ref might still be needed somehow? Just a random guess...
And maybe even put it behind the release of the context?

// cleanup
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
甜点 2024-09-04 11:07:52

我通过制作一个正方形上下文(宽度=高度)解决了这个问题。我有一个 512x256 纹理,每次我将数据发送到 OpenGL 时它都会崩溃。现在我分配了 512x512 缓冲区,但仍然渲染 512x256。希望这有帮助。

I solved the problem by making a square context (width=height). I was having a 512x256 texture and it crashing every time I sent the data to OpenGL. Now I allocate a 512x512 buffer BUT STILL render 512x256. Hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文