Crash on rendering pdf page in CA Tiled layer - iphone

I am trying to render pdf pages on CGContext by converting them into images and then rendering them in tiled layer. The application runs well on simulator but crashes on device for particular pdf page. On running the app on istruments, it seems to consume a lot of memory.
There have been many questions on this before on this platform and have tried all the solution but the problem persists. Please find the code below. It always crashes on calling CGContextDrawPDFPage
CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
pdfScale = self.frame.size.width/pageRect.size.width;
originalPdfScale = 2 * pdfScale;
//pdfScale = 1.39444;
pageRect.size = CGSizeMake(pageRect.size.width*pdfScale, pageRect.size.height*pdfScale);
//---Create a low res image representation of the PDF page to display before the TiledPDFView renders its content---
UIGraphicsBeginImageContext(pageRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
//---First fill the background with white---
CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
CGContextFillRect(context,pageRect);
NSLog(#"context = %# :::: pdfScale = %f ::::: page=%# ", context, pdfScale, page );
CGContextSaveGState(context);
//---Flip the context so that the PDF page is rendered right side up---
CGContextTranslateCTM(context, 0.0, pageRect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
//---Scale the context so that the PDF page is rendered at the correct size for the zoom level---
CGContextScaleCTM(context, pdfScale,pdfScale);
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGContextSetRenderingIntent(context, kCGRenderingIntentDefault);
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);
UIImage *backgroundImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if (backgroundImageView) {
[backgroundImageView removeFromSuperview];
[backgroundImageView release];
backgroundImageView = nil;
}
backgroundImageView = [[UIImageView alloc] initWithImage:backgroundImage];
backgroundImageView.frame = pageRect;
backgroundImageView.userInteractionEnabled =YES;
backgroundImageView.contentMode = UIViewContentModeScaleAspectFit;
[self addSubview:backgroundImageView];
[self sendSubviewToBack:backgroundImageView];
// Create the TiledPDFView based on the size of the PDF page and scale it to fit the view.
if (pdfView) {
[pdfView removeFromSuperview];
[pdfView release];
pdfView = nil;
}
pdfView = [[ProM_TiledPDFView alloc] initWithFrame:pageRect andScale:pdfScale];
[pdfView setPage:page];
[self addSubview:pdfView];
[backgroundImage release];

Related

PDF thumbnails in iPad are blurry

I am creating thumbnails and showing those thumbnails in gridView(using AQgridView). Thumbnails shown in gridView is too blurry and is not what I want. I am attached my code. Please help.
Here is my code:-
- (void)viewDidLoad
{
[super viewDidLoad];
imageArray = [[NSMutableArray alloc] init];
self.gridView = [[AQGridView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
self.gridView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
self.gridView.autoresizesSubviews = YES;
self.gridView.delegate = self;
self.gridView.dataSource = self;
[self.view addSubview:gridView];
[self makeThumbs];
// Do any additional setup after loading the view from its nib.
}
///////////Making thumb from PDF file///////////////
-(void)makeThumbs{
NSString* finalPath = [[NSBundle mainBundle] pathForResource:#"Maths" ofType:#"pdf" inDirectory:nil];
NSURL* pdfFileUrl = [NSURL fileURLWithPath:finalPath];
CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((__bridge CFURLRef)pdfFileUrl);
CGPDFPageRef page;
CGRect aRect = CGRectMake(0, 0, 70, 100); // thumbnail size
UIGraphicsBeginImageContext(aRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
NSUInteger totalNum = CGPDFDocumentGetNumberOfPages(pdf);
for(int i = 0; i < totalNum; i++ ) {
UIImage* thumbnailImage;
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0, aRect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetGrayFillColor(context, 1.0, 1.0);
CGContextFillRect(context, aRect);
// Grab the first PDF page
page = CGPDFDocumentGetPage(pdf, i + 1);
CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(page, kCGPDFMediaBox, aRect, 0, true);
// And apply the transform.
CGContextConcatCTM(context, pdfTransform);
CGContextDrawPDFPage(context, page);
// Create the new UIImage from the context
thumbnailImage = UIGraphicsGetImageFromCurrentImageContext();
//Use thumbnailImage (e.g. drawing, saving it to a file, etc)
CGContextRestoreGState(context);
[imageArray addObject:thumbnailImage];
}
NSLog(#"image array count is %d",[imageArray count]);
if ([imageArray count]>0) {
[self.gridView reloadData];
}
UIGraphicsEndImageContext();
CGPDFDocumentRelease(pdf);
}
Here image showing blurry thumbnails that are created on iPad Simulator
Try using UIGraphicsBeginImageContextWithOptions passing 0.0 as scale (to use the screen scale).

UIView Greyscale , animation and performance issues

I'm developing an app and i'm implementing an application to manage orders some orders of a client.
In this view i have implemented a facebook style menu ( the new one that appears by shifting the whole window right) and i'have added a greyscale effect to the main view when it's shifted to right.
I've accomplished it by creating a UIImage of the current screen and by adding it over the real view and animating it's alpha from 1 to 0
Here's the code i've used to
-(void)toggleMenu {
UIGraphicsBeginImageContext(self.view.bounds.size);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
if (![menu isOpened]){
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImage *blackAndWhiteImage = [UIImage getBlackAndWhiteVersionOfImage:viewImage];
overlayImage = [[UIImageView alloc]initWithImage:blackAndWhiteImage];
overlayImage.alpha = 0.1;
overlayImage.userInteractionEnabled=NO;
[self.view addSubview:overlayImage];
}
[UIView animateWithDuration:0.3 animations:^{
CGRect newRect = [self tabBarController].view.frame;
if (![menu isOpened]){
newRect.origin.x += 150;
[menu setOpened:YES];
overlayImage.alpha = 1.0;
} else {
newRect.origin.x -= 150;
[menu setOpened:NO];
overlayImage.alpha = 0;
}
[self tabBarController].view.frame = newRect;
} completion:^(BOOL finished){
if(![menu isOpened]){
[overlayImage removeFromSuperview];
overlayImage = nil;
}
}];
}
The problem is that i'm having issues with performances during animation ( little with iPhone 4 i'm trying an 3gs in next hours... )
Does anyone have any suggestions on what to do to get better performances ?
Regards
+ (UIImage *)getBlackAndWhiteVersionOfImage:(UIImage *)anImage {
UIImage *newImage;
if (anImage) {
CGColorSpaceRef colorSapce = CGColorSpaceCreateDeviceGray();
CGContextRef context = CGBitmapContextCreate(nil, anImage.size.width * anImage.scale, anImage.size.height * anImage.scale, 8, anImage.size.width * anImage.scale, colorSapce, kCGImageAlphaNone);
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGContextSetShouldAntialias(context, NO);
CGContextDrawImage(context, CGRectMake(0, 0, anImage.size.width, anImage.size.height), [anImage CGImage]);
CGImageRef bwImage = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSapce);
UIImage *resultImage = [UIImage imageWithCGImage:bwImage];
CGImageRelease(bwImage);
UIGraphicsBeginImageContextWithOptions(anImage.size, NO, anImage.scale);
[resultImage drawInRect:CGRectMake(0.0, 0.0, anImage.size.width, anImage.size.height)];
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
return newImage;
}
Making an image of the screen is costly. I'm not clear exactly what effect you want but I would overlay another view instead or animate a move of the main view instead.
For example, you can overlay a UIView that has a black background but an alpha of 0.1 to grey out a region.

why some UIimages don't show up in iphone

hi I am currently developing a small app on ios 4.3 , using objective c
as part of the app I need to manipulate an Image that I have downloaded from the web.
the following code shows up a missing image:
(the original is in a class but I just put this together as a test scenario so that it could be easily copy pasted)
- (void)viewDidLoad
{
[super viewDidLoad];
[self loadImage:#"http://www.night-net.net/images/ms/microsoft_vista_home_basic.jpg"];
[self getCroped:CGRectMake(10, 50, 80, 160)];
[self getCroped:CGRectMake(90, 50, 80, 80)];
[self getCroped:CGRectMake(90, 130, 40, 80)];
[self getCroped:CGRectMake(130, 130, 40, 40)];
[self getCroped:CGRectMake(130, 170, 40, 40)];
}
-(void) loadImage : (NSString*) url
{
_data = [NSData dataWithContentsOfURL:
[NSURL URLWithString: url]];
}
-(UIImageView*) getCroped:(CGRect) imageSize{
UIImage *temp = [[UIImage alloc] initWithData:_data];
UIImage *myImage = [self resizedImage:temp and:CGSizeMake(160,160) interpolationQuality:kCGInterpolationHigh];
UIImage *image = [self croppedImage:myImage and:imageSize];
UIImageView *imageView = [[UIImageView alloc] init];
imageView.image = image;
imageView.frame = imageSize;
[[self view] addSubview:imageView];
return imageView;
}
- (UIImage *)croppedImage:(UIImage*) image and: (CGRect)bounds {
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], bounds);
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return croppedImage;
}
- (UIImage *)resizedImage:(UIImage*) image and:(CGSize)newSize interpolationQuality:(CGInterpolationQuality)quality {
BOOL drawTransposed = NO;
return [self resizedImage:image
and:newSize
transform:[self transformForOrientation:newSize]
drawTransposed:drawTransposed
interpolationQuality:quality];
}
// Returns a copy of the image that has been transformed using the given affine transform and scaled to the new size
// The new image's orientation will be UIImageOrientationUp, regardless of the current image's orientation
// If the new size is not integral, it will be rounded up
- (UIImage *)resizedImage:(UIImage*) image and:(CGSize)newSize
transform:(CGAffineTransform)transform
drawTransposed:(BOOL)transpose
interpolationQuality:(CGInterpolationQuality)quality {
CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
CGRect transposedRect = CGRectMake(0, 0, newRect.size.height, newRect.size.width);
CGImageRef imageRef = image.CGImage;
// Build a context that's the same dimensions as the new size
CGContextRef bitmap = CGBitmapContextCreate(NULL,
newRect.size.width,
newRect.size.height,
CGImageGetBitsPerComponent(imageRef),
0,
CGImageGetColorSpace(imageRef),
CGImageGetBitmapInfo(imageRef));
// Rotate and/or flip the image if required by its orientation
CGContextConcatCTM(bitmap, transform);
// Set the quality level to use when rescaling
CGContextSetInterpolationQuality(bitmap, quality);
// Draw into the context; this scales the image
CGContextDrawImage(bitmap, transpose ? transposedRect : newRect, imageRef);
// Get the resized image from the context and a UIImage
CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap);
UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
// Clean up
CGContextRelease(bitmap);
CGImageRelease(newImageRef);
return newImage;
}
// Returns an affine transform that takes into account the image orientation when drawing a scaled image
- (CGAffineTransform)transformForOrientation:(CGSize)newSize {
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformTranslate(transform, newSize.width, 0);
transform = CGAffineTransformScale(transform, -1, 1);
return transform;
}
at first I thought this is caused by a lack of memory, but I have tested for that and that doesnt seem to be the problem,thanks in advance ofir
I've had issues in the past with images not appearing within UIWebViews if they contain unicode characters in the filename. I wonder if this might be the same thing. Try renaming your image?
doing this should be possible and low on memory cost as I did the same test,using flash to create an iphone app that does the same thing, and it works.
but I would much prefer using objective c so the question still stands

Rendering a CGPDFPage into a UIImage

I'm trying to render a CGPDFPage (selected from a CGPDFDocument) into a UIImage to display on a view.
I have the following code in MonoTouch which gets me part way there.
RectangleF PDFRectangle = new RectangleF(0, 0, UIScreen.MainScreen.Bounds.Width, UIScreen.MainScreen.Bounds.Height);
public override void ViewDidLoad ()
{
UIGraphics.BeginImageContext(new SizeF(PDFRectangle.Width, PDFRectangle.Height));
CGContext context = UIGraphics.GetCurrentContext();
context.SaveState();
CGPDFDocument pdfDoc = CGPDFDocument.FromFile("test.pdf");
CGPDFPage pdfPage = pdfDoc.GetPage(1);
context.DrawPDFPage(pdfPage);
UIImage testImage = UIGraphics.GetImageFromCurrentImageContext();
pdfDoc.Dispose();
context.RestoreState();
UIImageView imageView = new UIImageView(testImage);
UIGraphics.EndImageContext();
View.AddSubview(imageView);
}
A section of the CGPDFPage is displayed but rotated back-to-front and upside down. My question is, how do I select the full pdf page and flip it round to display correctly. I have seen a few examples using ScaleCTM and TranslateCTM but couldn't seem to get them working.
Any examples in ObjectiveC are fine, I'll take all the help I can get :)
Thanks
I haven't worked with MonoTouch. However, in objective-C you would get an image for a PDF page like this (notice the CTM transforms):
-(UIImage *)getThumbForPage:(int)page_number{
CGFloat width = 60.0;
// Get the page
CGPDFPageRef myPageRef = CGPDFDocumentGetPage(myDocumentRef, page);
// Changed this line for the line above which is a generic line
//CGPDFPageRef page = [self getPage:page_number];
CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
CGFloat pdfScale = width/pageRect.size.width;
pageRect.size = CGSizeMake(pageRect.size.width*pdfScale, pageRect.size.height*pdfScale);
pageRect.origin = CGPointZero;
UIGraphicsBeginImageContext(pageRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
// White BG
CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
CGContextFillRect(context,pageRect);
CGContextSaveGState(context);
// ***********
// Next 3 lines makes the rotations so that the page look in the right direction
// ***********
CGContextTranslateCTM(context, 0.0, pageRect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextConcatCTM(context, CGPDFPageGetDrawingTransform(page, kCGPDFMediaBox, pageRect, 0, true));
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);
UIImage *thm = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return thm;
}

reseting CGContextRef after drawing pdf page using CGContextDrawPDFPage

I am trying to create thumb images for every pdf page in PDF document and place it in a UISCrollVIew. I have succeeded in this, but scrolling is not so smooth as I want when it's too fast.
And I want to optimize thumb images creating for Pdf page.
I want to create one CGContextRef and reset its content after CGContextDrawPDFPage, as a consequence I wouldn't have to create a context each time and perform some other calculation, which takes a lot of resources.
Is it possible to reset CGContextRef content after CGContextDrawPDFPage? CGContextRestoreGState and CGContextSaveGState seems to doesn't help in this situation.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
GCPdfSource *pdfSource = [GCPdfSource sharedInstance];
for (int i = pageRange.location; i <= pageRange.length; i++) {
UIView *thumbPdfView = [scrollView viewWithTag:i+1];
if (thumbPdfView == nil) {
CGPDFPageRef pdfPage = [pdfSource pageAt:i + 1];
float xPosition = THUMB_H_PADDING + THUMB_H_PADDING * i + THUMB_WIDTH * i;
CGRect frame = CGRectMake(xPosition, THUMB_H_PADDING, THUMB_WIDTH, THUMB_HEIGHT);
thumbPdfView = [[UIView alloc] initWithFrame:frame];
thumbPdfView.opaque = YES;
thumbPdfView.backgroundColor = [UIColor whiteColor];
[thumbPdfView setTag:i+1];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL,
frame.size.width,
frame.size.height,
8, /* bits per component*/
frame.size.width * 4, /* bytes per row */
colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextClipToRect(context, CGRectMake(0, 0, frame.size.width,frame.size.height));
CGRect pdfPageRect = CGPDFPageGetBoxRect(pdfPage, kCGPDFMediaBox);
CGRect contextRect = CGContextGetClipBoundingBox(context);
CGAffineTransform transform = aspectFit(pdfPageRect, contextRect);
CGContextConcatCTM(context, transform);
CGContextDrawPDFPage(context, pdfPage);
CGImageRef image = CGBitmapContextCreateImage(context);
CGContextRelease(context);
UIImage *uiImage = [[UIImage alloc]initWithCGImage:image];
CGImageRelease(image);
UIImageView *imageVIew = [[UIImageView alloc]initWithImage:uiImage];
[uiImage release];
[thumbPdfView addSubview:imageVIew];
[imageVIew release];
[scrollView addSubview:thumbPdfView];
[thumbPdfView release];
}
}
[pool release];//release
and aspectFit function...
CGAffineTransform aspectFit(CGRect innerRect, CGRect outerRect) {
CGFloat scaleFactor = MIN(outerRect.size.width/innerRect.size.width, outerRect.size.height/innerRect.size.height);
CGAffineTransform scale = CGAffineTransformMakeScale(scaleFactor, scaleFactor);
CGRect scaledInnerRect = CGRectApplyAffineTransform(innerRect, scale);
CGAffineTransform translation =
CGAffineTransformMakeTranslation((outerRect.size.width - scaledInnerRect.size.width) / 2 - scaledInnerRect.origin.x,
(outerRect.size.height - scaledInnerRect.size.height) / 2 - scaledInnerRect.origin.y);
return CGAffineTransformConcat(scale, translation);
}
Try CGContextClearRect(context, contextBounds).
CGContextSaveGState and CGContextRestoreGState do not have any effect on the content of a context. They push and pop changes made to state aspects of the context like the current fill color.