我正在使用以下代码根据滑块值为uiimage设置模糊效果。条子值范围从0,5,10,15,20。这种逻辑在模拟器中运行良好,但它在设备中崩溃。请告诉我这个逻辑中有什么错误,或者是否还有比这更好的逻辑。
我是这个目标的新手 - c。请帮我解决这个问题。
这是崩溃日志
Program received signal: “EXC_BAD_ACCESS”.
(gdb) bt
#0 0x320d27c4 in CGSConvertABGR8888toRGBA8888 ()
#1 0x31fdb184 in argb32_image ()
#2 0x3126fb60 in ripl_Mark ()
#3 0x31272dd0 in ripl_BltImage ()
#4 0x312649c0 in RIPLayerBltImage ()
#5 0x3126954c in ripc_RenderImage ()
#6 0x3126be34 in ripc_DrawImage ()
#7 0x31fd5054 in CGContextDelegateDrawImage ()
#8 0x31fd4e78 in CGContextDrawImage ()
#9 0x31c8af38 in CA::Render::create_image_by_rendering ()
#10 0x31c8460c in CA::Render::create_image_from_image_data ()
#11 0x31c84498 in CA::Render::create_image ()
#12 0x31c84154 in CA::Render::copy_image ()
#13 0x31c8407c in CA::Render::prepare_image ()
#14 0x31c7e9a0 in CALayerPrepareCommit_ ()
#15 0x31c7e9d8 in CALayerPrepareCommit_ ()
#16 0x31c7e9d8 in CALayerPrepareCommit_ ()
#17 0x31c7e9d8 in CALayerPrepareCommit_ ()
#18 0x31c7e9d8 in CALayerPrepareCommit_ ()
#19 0x31c7e9d8 in CALayerPrepareCommit_ ()
#20 0x31c7e9d8 in CALayerPrepareCommit_ ()
#21 0x31c7e86c in CALayerPrepareCommit ()
#22 0x31c7bbd0 in CA::Context::commit_transaction ()
#23 0x31c7b7e0 in CA::Transaction::commit ()
#24 0x31c839e0 in CA::Transaction::observer_callback ()
#25 0x3223524a in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ ()
#26 0x32236da4 in __CFRunLoopDoObservers ()
#27 0x322382fc in __CFRunLoopRun ()
#28 0x321df0c2 in CFRunLoopRunSpecific ()
#29 0x321defd0 in CFRunLoopRunInMode ()
#30 0x3390ff90 in GSEventRunModal ()
#31 0x34b0ab48 in -[UIApplication _run] ()
#32 0x34b08fc0 in UIApplicationMain ()
#33 0x00002db2 in main (argc=1, argv=0x2ffff570) at /Users/Desktop/SampleProject/Shared/main.m:14
这是调用方法:
tempImgView.image = [self blurredCopyUsingGuassFactor:value andPixelRadius:value];
CGContextRef CreateARGBBitmapContext (CGImageRef inImage)
{
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
void * bitmapData;
int bitmapByteCount;
int bitmapBytesPerRow;
size_t pixelsWide = CGImageGetWidth(inImage);
size_t pixelsHigh = CGImageGetHeight(inImage);
bitmapBytesPerRow = (pixelsWide * 4);
bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);
colorSpace = CGColorSpaceCreateDeviceRGB();
if (colorSpace == NULL)
return NULL;
bitmapData = malloc( bitmapByteCount );
if (bitmapData == NULL)
CGColorSpaceRelease( colorSpace );
context = CGBitmapContextCreate (bitmapData,
pixelsWide,
pixelsHigh,
8,
bitmapBytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedFirst);
if (context == NULL)
free (bitmapData);
CGColorSpaceRelease( colorSpace );
return context;
}
CGImageRef CreateCGImageByBlurringImage(CGImageRef inImage, NSUInteger pixelRadius, NSUInteger gaussFactor)
{
unsigned char *srcData, *destData, *finalData;
CGContextRef context = CreateARGBBitmapContext(inImage);
if (context == NULL)
return NULL;
size_t width = CGBitmapContextGetWidth(context);
size_t height = CGBitmapContextGetHeight(context);
size_t bpr = CGBitmapContextGetBytesPerRow(context);
size_t bpp = (CGBitmapContextGetBitsPerPixel(context) / 8);
CGRect rect = {{0,0},{width,height}};
CGContextDrawImage(context, rect, inImage);
// Now we can get a pointer to the image data associated with the bitmap
// context.
srcData = (unsigned char *)CGBitmapContextGetData (context);
if (srcData != NULL)
{
size_t dataSize = bpr * height;
finalData = malloc(dataSize);
destData = malloc(dataSize);
memcpy(finalData, srcData, dataSize);
memcpy(destData, srcData, dataSize);
int sums[gaussFactor];
int i, x, y, k;
int gauss_sum=0;
int radius = pixelRadius * 2 + 1;
int *gauss_fact = malloc(radius * sizeof(int));
for (i = 0; i < pixelRadius; i++)
{
gauss_fact[i] = 1 + (gaussFactor*i);
gauss_fact[radius - (i + 1)] = 1 + (gaussFactor * i);
gauss_sum += (gauss_fact[i] + gauss_fact[radius - (i + 1)]);
}
gauss_fact[(radius - 1)/2] = 1 + (gaussFactor*pixelRadius);
gauss_sum += gauss_fact[(radius-1)/2];
unsigned char *p1, *p2, *p3;
for ( y = 0; y < height; y++ )
{
for ( x = 0; x < width; x++ )
{
p1 = srcData + bpp * (y * width + x);
p2 = destData + bpp * (y * width + x);
for (i=0; i < gaussFactor; i++)
sums[i] = 0;
for(k=0;k<radius;k++)
{
if ((y-((radius-1)>>1)+k) < height)
p1 = srcData + bpp * ( (y-((radius-1)>>1)+k) * width + x);
else
p1 = srcData + bpp * (y * width + x);
for (i = 0; i < bpp; i++)
sums[i] += p1[i]*gauss_fact[k];
}
for (i=0; i < bpp; i++)
p2[i] = sums[i]/gauss_sum;
}
}
for ( y = 0; y < height; y++ )
{
for ( x = 0; x < width; x++ )
{
p2 = destData + bpp * (y * width + x);
p3 = finalData + bpp * (y * width + x);
for (i=0; i < gaussFactor; i++)
sums[i] = 0;
for(k=0;k<radius;k++)
{
if ((x -((radius-1)>>1)+k) < width)
p1 = srcData + bpp * ( y * width + (x -((radius-1)>>1)+k));
else
p1 = srcData + bpp * (y * width + x);
for (i = 0; i < bpp; i++)
sums[i] += p2[i]*gauss_fact[k];
}
for (i=0; i < bpp; i++)
{
p3[i] = sums[i]/gauss_sum;
}
}
}
}
size_t bitmapByteCount = bpr * height;
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, destData, bitmapByteCount, NULL);
CGImageRef cgImage = CGImageCreate(width, height, CGBitmapContextGetBitsPerComponent(context),
CGBitmapContextGetBitsPerPixel(context), CGBitmapContextGetBytesPerRow(context), CGBitmapContextGetColorSpace(context), CGBitmapContextGetBitmapInfo(context),
dataProvider, NULL, true, kCGRenderingIntentDefault);
CGDataProviderRelease(dataProvider);
CGContextRelease(context);
if (destData)
free(destData);
if (finalData)
free(finalData);
return cgImage;
}
- (UIImage *)blurredCopyUsingGuassFactor:(int)gaussFactor andPixelRadius:(int)pixelRadius
{
CGImageRef retCGImage = CreateCGImageByBlurringImage(refImage.CGImage, pixelRadius, gaussFactor);
UIImage *retUIImage = [UIImage imageWithCGImage:retCGImage];
CGImageRelease(retCGImage);
return retUIImage;
}
答案 0 :(得分:3)
我认为使用像opencv这样的东西可以更快地实现你的目标。
这是使用opencv创建高斯模糊的概念验证:
- (UIImage *)gaussianBlurWithUIImage:(UIImage *)anImage {
// Create an IplImage from UIImage
IplImage *img_color = [self CreateIplImageFromUIImage:anImage];
//obtain a 4channel RGB reference from the above
IplImage *img = cvCreateImage(cvGetSize(img_color), IPL_DEPTH_8U, 4);
//release the source. we don't care any more about it
cvReleaseImage(&img_color);
//make the Blur
cvSmooth(img, img, CV_GAUSSIAN, 7, 7, 0, 0);
//return the resulting image
UIImage *retUIImage = [self UIImageFromIplImage:img];
//release any allocated memory
cvReleaseImage(&img);
return retUIImage;
}
答案 1 :(得分:1)
几乎肯定你正在访问释放的内存。我假设使用tempImgView.image
选项@property
为retain
。如果没有,您需要保留blurredCopyUsingGuassFactor
的结果。
最简单的检查方法是运行构建和分析,并查看与调用retain几次相关的问题。
如果没有显示任何内容,请尝试打开僵尸
http://loufranco.com/blog/files/debugging-memory-iphone.html
这使得对象不能解除分配,但是如果在对它们调用dealloc之后向它们发送消息,则写入控制台。不幸的是,这对你对malloc和free的记忆没有帮助。
要确保的最后一件事是你不要通过超出malloced数据的界限来破坏堆。检查的一种方法是使用Enable Guard Malloc,然后按照检测堆腐败下的说明进行操作:
最后,仅仅因为它在模拟器中没有崩溃并不意味着bug也不存在 - 它只是没有取消引用恰好指向未映射内存的坏指针。检测内存问题无法保证 - 你可能有内存错误但仍然无法获得EXC_BAD_ACCESS - 这并不意味着错误不存在。
答案 2 :(得分:0)
我找到了一个中间解决方案。问题是destData正在被释放。我不太了解Cocoa如何在引擎盖下工作以进一步诊断它。它接近底部:
CGDataProviderRelease(dataProvider);
CGContextRelease(context);
if (destData)
free(destData); // this line breaks things
if (finalData)
free(finalData);
我怀疑cgImage是以某种方式懒散加载的?我不知道。如果你没有释放destData,一切正常。当然,除了你现在正在泄露记忆。
答案 3 :(得分:0)
如果您引用了代码的原始来源,那会更容易 - 这是(c)Jeff LaMarche
正如您将从讨论主题中看到的那样,答案是正确使用dataprovider回调,它会在正确的时间释放内存。