Question

i have an UITableView in my app and i have to load some images that have a fixed width but different heights. I download the images async using an NSOperationQueue and for resizing and cropping i tried to use the solution provided by Jane Sales in this post link text.

i made a custom UITableViewCell class and in it i have a method that is called when the queued operation finishes to download the image. The method is called properly and the images are displayed. When i try to resize the images using the method proposed by Jane the problems appear. When it reaches [sourceImage drawInRect:thumbnailRect]; i receive an exec bad access error and i can't figure out why. I call the method like this:

- (void) setupImage:(UIImage *) anImage{
    UIImage *resized = [anImage imageByScalingAndCroppingForSize:CGSizeMake(64, 59)];
    if(resized == nil)
        resized = [UIImage newImageFromResource:@"thumb2.png"];
    [thumbnailView setImage:resized];
}

setupImage is the function called when the NSOperationQueue finishes the download action of anImage.

Could someone give me a clue why i receive the exec bad access error when i try to resize and crop the images? I tried using the same function outside the table view. 80% of the cases it works but there are cases when i receive the same exec bad access error.

Thank you in advance, Sorin

Was it helpful?

Solution

this is what i'm using for resizing and croping the UIImages (the code is from Jane Sales solution)

@implementation UIImage (Extras) 
#pragma mark -
#pragma mark Scale and crop image

- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize
{
UIImage *sourceImage = self;
UIImage *newImage = nil;        
CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGFloat scaleFactor = 0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;
CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

if (CGSizeEqualToSize(imageSize, targetSize) == NO) 
        {
        CGFloat widthFactor = targetWidth / width;
        CGFloat heightFactor = targetHeight / height;

        if (widthFactor > heightFactor) 
                scaleFactor = widthFactor; // scale to fit height
        else
                scaleFactor = heightFactor; // scale to fit width
        scaledWidth  = width * scaleFactor;
        scaledHeight = height * scaleFactor;

        // center the image
        if (widthFactor > heightFactor)
                {
                thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 
                }
        else 
                if (widthFactor < heightFactor)
                        {
                        thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
                        }
        }       

UIGraphicsBeginImageContext(targetSize); // this will crop

CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width  = scaledWidth;
thumbnailRect.size.height = scaledHeight;

[sourceImage drawInRect:thumbnailRect];

newImage = UIGraphicsGetImageFromCurrentImageContext();
if(newImage == nil) 
        NSLog(@"could not scale image");

//pop the context to get back to the default
UIGraphicsEndImageContext();
return newImage;
}

i call the above function like i said before:

- (void) setupImage:(UIImage *) anImage
{
    UIImage *resized = [anImage imageByScalingAndCroppingForSize:CGSizeMake(64, 59)];
    [thumbnailView setImage:resized];
}

the images are downloaded async when a cell is displayed in the table view. the setupImage function receives the image from an NSOperation that downloads it async. the problem is, like i said above, when it reaches [sourceImage drawInRect:thumbnailRect];

thumbnailView is an UIImageView that is a subview of my custom TableViewCell.

hope this clears things a bit about what i'm using in my code. Thank you for the help. Sorin

OTHER TIPS

Try the following code. The createImage:image:width:height method requires a source CGImageRef and the new width and height of the final UIImage that will be returned. When using as source an UIImage, you can obtain the corresponding CGImageRef as follows:

UIImage *sourceImage;
CGImageRef *sourceRef = [sourceImage CGImage];

        // 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;
        }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top