I am maintaining a company's legacy app and am trying to reduce the amounts of crashes and memory leaks in a non-ARC project (sigh). I have identified a massive memory leak in a function that converts a PDF file into a UIImage but do not have enough experience with graphics contexts to identify all the issues properly.
The method which is leaking memory is as follows:
+ (UIImage *) convertPDFToImage:(NSURL *)pdfLocation withResolution:(int)resolution withProductKey:(NSString *) productKey {
CGPDFDocumentRef documentRef = CGPDFDocumentCreateWithURL((CFURLRef)pdfLocation);
if(!CGPDFDocumentIsUnlocked(documentRef))
{
NSString *hashedPassword = [MD5Hash CreateMD5HashForPDFPasswordUsingProductKey:productKey];
CGPDFDocumentUnlockWithPassword(documentRef, [hashedPassword UTF8String]);
}
CGPDFPageRef page = CGPDFDocumentGetPage(documentRef, 1);
CGRect cropBox = CGPDFPageGetBoxRect(page, kCGPDFCropBox);
int pageRotation = CGPDFPageGetRotationAngle(page);
if ((pageRotation == 0) || (pageRotation == 180) ||(pageRotation == -180)) {
UIGraphicsBeginImageContextWithOptions(cropBox.size, NO, resolution / 72);
} else {
UIGraphicsBeginImageContextWithOptions(CGSizeMake(cropBox.size.height, cropBox.size.width), NO, resolution / 72);
}
CGContextRef context = UIGraphicsGetCurrentContext();
CGPoint point = CGPointMake(0, 0);
int rotate = CGPDFPageGetRotationAngle(page);
int zoom = 100;
CGContextSaveGState(context);
// Setup the coordinate system.
// Top left corner of the displayed page must be located at the point specified by the 'point' parameter.
CGContextTranslateCTM(context, point.x, point.y);
// Scale the page to desired zoom level.
CGContextScaleCTM(context, zoom / 100, zoom / 100);
// The coordinate system must be set to match the PDF coordinate system.
switch (rotate) {
case 0:
CGContextTranslateCTM(context, 0, cropBox.size.height);
CGContextScaleCTM(context, 1, -1);
break;
case 90:
CGContextScaleCTM(context, 1, -1);
CGContextRotateCTM(context, -M_PI / 2);
break;
case 180:
case -180:
CGContextScaleCTM(context, 1, -1);
CGContextTranslateCTM(context, cropBox.size.width, 0);
CGContextRotateCTM(context, M_PI);
break;
case 270:
case -90:
CGContextTranslateCTM(context, cropBox.size.height, cropBox.size.width);
CGContextRotateCTM(context, M_PI / 2);
CGContextScaleCTM(context, -1, 1);
break;
}
// The CropBox defines the page visible area, clip everything outside it.
CGRect clipRect = CGRectMake(0, 0, cropBox.size.width, cropBox.size.height);
CGContextAddRect(context, clipRect);
CGContextClip(context);
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(context, clipRect);
CGContextTranslateCTM(context, -cropBox.origin.x, -cropBox.origin.y);
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGContextSetRenderingIntent(context, kCGRenderingIntentDefault);
CGContextDrawPDFPage(context, page);
UIImage *pageImage = UIGraphicsGetImageFromCurrentImageContext();
CGContextRestoreGState(context);
UIGraphicsEndImageContext();
CGPDFPageRelease(page);
CGPDFDocumentRelease(documentRef);
return pageImage;
}
I have already solved one leak where the CGPDFPage was not being released, but the profile shows that this method is still leaking slightly.
Any suggestions would be much appreciated