views:

868

answers:

4

I'm new to the iPhone App development so it's likely that I'm doing something wrong.

Basically, I'm loading a bunch of images from the internet, and then cropping them. I managed to find examples of loading images asynchronous and adding them into views. I've managed to do that by adding an image with NSData, through a NSOperation, which was added into a NSOperationQueue.

Then, because I had to make fixed-sized thumbs, I needed a way to crop this images, so I found a script on the net which basically uses UIGraphicsBeginImageContext(), UIGraphicsGetImageFromCurrentImageContext() and UIGraphicsEndImageContext() to draw the cropped image, along with unimportant size calculations.

The thing is, the method works, but since it's generating like 20 of this images, it randomly crashes after a few of them were generated, or sometimes after I close and re-open the app one or two more times.

What should I do in this cases? I tried to make this methods run asynchronous somehow, as well, with NSOperations and a NSOperationQueue, but no luck.

If the crop code is more relevant than I think, here it is:

UIGraphicsBeginImageContext(CGSizeMake(50, 50));
CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = CGPointMake(0.0,0.0); //this is actually generated
                                             // based on the sourceImage size
thumbnailRect.size.width  = 50;
thumbnailRect.size.height = 50;
[sourceImage drawInRect:thumbnailRect];
newImage = UIGraphicsGetImageFromCurrentImageContext();

Thanks!

+5  A: 

The code to scale the images looks too much simple. Here is the one I am using. As you can see, there are no leaks, objects are released when no longer needed. Hope this helps.

    // Draw the image into a pixelsWide x pixelsHigh bitmap and use that bitmap to 
// create a new UIImage 
- (UIImage *) createImage: (CGImageRef) image width: (int) pixelWidth height: (int) pixelHeight
{ 
    // Set the size of the output image 
    CGRect aRect = CGRectMake(0.0f, 0.0f, pixelWidth, pixelHeight); 
    // Create a bitmap context to store the new thumbnail 
    CGContextRef context = MyCreateBitmapContext(pixelWidth, pixelHeight); 
    // Clear the context and draw the image into the rectangle 
    CGContextClearRect(context, aRect); 
    CGContextDrawImage(context, aRect, image); 
    // Return a UIImage populated with the new resized image 
    CGImageRef myRef = CGBitmapContextCreateImage (context); 

    UIImage *img = [UIImage imageWithCGImage:myRef];

    free(CGBitmapContextGetData(context)); 
    CGContextRelease(context);
    CGImageRelease(myRef);

    return img; 
} 


// MyCreateBitmapContext: Source based on Apple Sample Code
CGContextRef MyCreateBitmapContext (int pixelsWide,
            int pixelsHigh)
{
    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    void *          bitmapData;
    int             bitmapByteCount;
    int             bitmapBytesPerRow;

    bitmapBytesPerRow   = (pixelsWide * 4);
    bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh);

    colorSpace = CGColorSpaceCreateDeviceRGB();
    bitmapData = malloc( bitmapByteCount );
    if (bitmapData == NULL)
    {
        fprintf (stderr, "Memory not allocated!");
     CGColorSpaceRelease( colorSpace );
        return NULL;
    }
    context = CGBitmapContextCreate (bitmapData,
             pixelsWide,
             pixelsHigh,
             8,
             bitmapBytesPerRow,
             colorSpace,
             kCGImageAlphaPremultipliedLast);
    if (context== NULL)
    {
        free (bitmapData);
     CGColorSpaceRelease( colorSpace );
        fprintf (stderr, "Context not created!");
        return NULL;
    }
    CGColorSpaceRelease( colorSpace );

    return context;
}
unforgiven
Hi, it's been a while but I still have this problem so now I decided to review your answers. I'm trying to use your code but I have my images as a UIImage, and your function needs CGImageRef. Also, this script only scales an image, right? I also need to crop it.
treznik
For posterity, `UIImage` defines a property `CGImage` that gives you a `CGImageRef` for that image.
Sixten Otto
+1  A: 

It does sounds suspiciously like an out of memory crash. Fire up the Leaks tool and see your overall memory trends.

Kailoa Kadano
+2  A: 

Your app is crashing because the calls you're using (e.g., UIGraphicsBeginImageContext) manipulate UIKit's context stack which you can only safely do from the main thread.

unforgiven's solution won't crash when used in a thread as it doesn't manipulate the context stack.

Aral Balkan
That makes sense. As a matter a fact, I was suspecting this, and I attempted to use unforgiven's solution, but I don't know how to use his function since it expects CGImageRef and I'm loading external images into UIImage. Do you think you can clear this out for me? Thanks.
treznik
+1  A: 

i had the exact same problem. unforgivens solution is excellent. thanks

brian