开发者

Applying blur effect for UIImage in iPhone

开发者 https://www.devze.com 2023-01-13 21:39 出处:网络
I\'m using this following code to set blur effect for an uiimage basing on slider value. sliver value ranges from 0,5,10,15,20. THis logic is working fine in simulator but it is crashing in device. Pl

I'm using this following code to set blur effect for an uiimage basing on slider value. sliver value ranges from 0,5,10,15,20. THis logic is working fine in simulator but it is crashing in device. Please tell me anyone whats wrong in this logic, or is there any other logic better than this.

I'm new to this objective-c. Please help me in solving this issue.

Thanks in advance.........

This is the crash log

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

This is the calling method:

 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开发者_StackOverflow社区 (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;

}


I think that your goal can be achieved more quickly, using something like opencv.

Here is a proof-of-concept to create a Gaussian blur using 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;
}


Almost definitely you are accessing freed memory. I assume that tempImgView.image is an @property using the retain option. If not, you need to retain the result of blurredCopyUsingGuassFactor.

The easiest way to check is to run a Build and Analyze and look at issues related to calling retain too few times.

If that doesn't show anything, try to turn on zombies

http://loufranco.com/blog/files/debugging-memory-iphone.html

This makes object not deallocate, but write to the console if messages are sent to them after dealloc has been called on them. Unfortunately, this won't help with memory you malloc and free.

The last thing to make sure of is that you don't corrupt the heap by going out of bounds on your malloced data. One way to check is to use Enable Guard Malloc and then follow directions under Detecting Heap Corruption here:

http://developer.apple.com/iphone/library/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html

Finally, just because it doesn't crash in the Simulator doesn't mean that the bug isn't there too -- it's just not dereferencing a bad pointer that happens to be pointing to unmapped memory. Detecting the memory problems is not guaranteed -- you could have memory bugs and still not get EXC_BAD_ACCESS -- that doesn't mean the bug isn't there.


I found an intermediate solution. The problem is that destData is being freed. I don't know enough about how Cocoa works under the hood to diagnose it further. It's near the bottom:

CGDataProviderRelease(dataProvider);
CGContextRelease(context); 
if (destData)
    free(destData); // this line breaks things
if (finalData)
    free(finalData);

I suspect the cgImage is somehow loaded lazily? I don't know. If you don't free destData, everything works fine. Except, of course, that you're now leaking memory.


Would have been a lot easier if you had referenced the original source for your code - which is (c) Jeff LaMarche

As you will see from the discussion thread there, the answer is to use the dataprovider callback correctly which releases the memory at the correct time.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号