CGPDFDocument scaling - iphone

I am just starting to build an app that will display PDF documents. I've been experimenting, subclassing UIView and using the code from Apples demo. I have a PDF document that contains an image that is 1024 x 748 pixels at 131 ppi, so that it SHOULD fill the iPad screen in landscape view.
When I run the app the pdf is scaled to approximately .25% of its full size, centered in the iPad screen. Why isn't the PDF being displayed full sized?
Code from my custom UIView:
-(id)initWithFrame:(CGRect)frame PDFName:(NSString *)pdfName
{
self = [super initWithFrame:frame];
if(self != nil)
{
self.backgroundColor = [UIColor blueColor];
self.opaque = YES;
self.clearsContextBeforeDrawing = YES;
CFURLRef pdfURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), (CFStringRef)pdfName, NULL, NULL);
pdf = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL);
CFRelease(pdfURL);
}
return self;
}
- (void)drawRect:(CGRect)rect {
// PDF page drawing expects a Lower-Left coordinate system, so we flip the coordinate system
// before we start drawing.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0.0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// Grab the first PDF page
CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 1);
// We're about to modify the context CTM to draw the PDF page where we want it, so save the graphics state in case we want to do more drawing
CGContextSaveGState(context);
// CGPDFPageGetDrawingTransform provides an easy way to get the transform for a PDF page. It will scale down to fit, including any
// base rotations necessary to display the PDF page correctly.
CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(page, kCGPDFMediaBox, self.bounds, 0, true);
// And apply the transform.
CGContextConcatCTM(context, pdfTransform);
// Finally, we draw the page and restore the graphics state for further manipulations!
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);
}

Answer was easy. Changed the ppi of the image in the PDF to 72 ppi (still 1024 x 748). Now it fills the screen correctly. I thought that I needed to match the iPads pixel density, but I guess not.
Jk

Related

IOS, how to clear context graphics

In my app I have a method that draws a pdf into a context:
CGPDFPageRef page = CGPDFDocumentGetPage(pdf, index + 1);
CGAffineTransform transform = aspectFit(CGPDFPageGetBoxRect(page, kCGPDFTrimBox),
CGContextGetClipBoundingBox(ctx));
CGContextConcatCTM(ctx, transform);
CGContextDrawPDFPage(ctx, page);
Now in drawLayer, that is called when zooming, I do the necessary transformations and call again CGContextDrawPDFPage(ctx, page);
What happens is that a zoomed pdf is drawn on top of the first pdf, the problem is that in a particular page with only text, the back and blurred pdf is shown. That is strange, I thought that pdf page had white background and if this happens it's because the zoomed pdf on top has transparent background.
Now, to solve this how can I clear the context right before the CGContextDrawPDFPage(ctx, page) of drawLayer method? I tried:
//self.view.transform = CGAffineTransformIdentity;
//CGAffineTransform transform = CGAffineTransformIdentity;
//CGContextConcatCTM(ctx, transform);
//CGContextClearRect(ctx, layer.bounds);
Nothing works...thanks in advance
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, self.bounds);
Did you try to flush the context as below?
CGContextFlush(ctx);

saving image from a page of CGPDfDocument is not perfectly fitted in UIImageview

I am having some trouble with saving a PDF page as UIImage...the pdf is loaded from the internet and it has one page(original PDF has been splitted in sever)...but the converted image sometimes is cropped...sometimes it is small and leave white space when it is putted on UIImageview...
here is the code
-(UIImage *)imageFromPdf:(NSString *) pdfUrl{
NSURL *pdfUrlStr=[NSURL URLWithString:pdfUrl];
CFURLRef docURLRef=(CFURLRef)pdfUrlStr;
UIGraphicsBeginImageContext(CGSizeMake(768, 1024)); //840, 960
NSLog(#"save begin");
CGContextRef context = UIGraphicsGetCurrentContext();
//CFURLRef pdfURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("/file.pdf"), NULL, NULL);
CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL(docURLRef);
NSLog(#"save complete");
CGContextTranslateCTM(context, 0.0, 900);//320
CGContextScaleCTM(context, 1.0, -1.0);
CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 1);
CGContextSaveGState(context);
CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, CGRectMake(0, 0, 768, 1024), 0, true);
CGContextConcatCTM(context, pdfTransform);
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);
UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resultingImage;
}
btw I have prepared my UIImageview by coding like this
self.PDFImageVIew.contentMode = UIViewContentModeScaleAspectFit;
self.PDFImageVIew.clipsToBounds = YES;
I just want this image perfectly fitted on UIImageview and may be its reducing the quality of image...can you have suggesion how can I keep the quality also? please help and give me some suggestion
thanks
CGContextTranslateCTM(context, 0.0, 900);//320
Here generally last parameter of translate operation should be the height of context or height of rectangle for which you creating image. So, i think it should be 1024(You have taken height of image context is 1024 so here i am assuming that status bar is not present). This may eliminate the issue of cropping. Some more things that i have noted on your code you should have to save the state of graphics before any operation on context. You have are saving it but after few operations.
Above code will try to make it height fit so if height of actual page is bigger than your context height then it will be scaled down. so you can obviously see white space around page.
One more thing if your original pdf page have white space in it then there is no way to eliminate it as far as i know.

Efficient thumbnail creation for PDF files like iBooks

How is iBooks able to create PDF page thumbnails so fast on first load? I tried using CGContext functions to draw the page and then resize it to get a thumbnail. But this approach takes way to long. Is there an efficient way to get thumbnails of PDF pages?
Thanks in advance,
Anupam
First get all your PDF files Path in an array[here ie:pdfs].Then if you want to show all these PDF thumbnails in UICollectionView,just pass the index obtained from the collection view Delegate Method "CellForRowAtIndexPath" to the following,
-(UIImage *)GeneratingIcon:(int)index
{
NSURL* pdfFileUrl = [NSURL fileURLWithPath:[pdfs objectAtIndex:index]];
CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((__bridge CFURLRef)pdfFileUrl);
CGPDFPageRef page;
CGRect aRect = CGRectMake(0, 0, 102, 141); // thumbnail size
UIGraphicsBeginImageContext(aRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
UIImage* IconImage;
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, 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
IconImage = UIGraphicsGetImageFromCurrentImageContext();
CGContextRestoreGState(context);
UIGraphicsEndImageContext();
CGPDFDocumentRelease(pdf);
return IconImage;
}
Hope this would be fast enough to create thumbnail images for the PDF.
Disclaimer: I have not checked if this is faster or not.
There are some built in methods in ImageIO that are specialized in creating thumbnails. These methods should be optimized for creating thumbnails. You would need to add ImageIO.framework to your project and #import <ImageIO/ImageIO.h> in your code.
// Get PDF-data
NSData *pdfData = [NSData dataWithContentsOfURL:myFileURL];
// Get reference to the source
// NOTE: You are responsible for releasing the created image source
CGImageSourceRef imageSourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)pdfData, NULL);
// Configure how to create the thumbnail
// NOTE: You should change the thumbnail size depending on how large thumbnails you need.
// 512 pixels is probably way too big. Smaller sizes will be faster.
NSDictionary* thumbnailOptions =
#{(id)kCGImageSourceCreateThumbnailWithTransform: (id)kCFBooleanTrue,
(id)kCGImageSourceCreateThumbnailFromImageIfAbsent: (id)kCFBooleanTrue,
(id)kCGImageSourceThumbnailMaxPixelSize: #512}; // no more than 512 px wide or high
// Create thumbnail
// NOTE: You are responsible for releasing the created image
CGImageRef imageRef =
CGImageSourceCreateThumbnailAtIndex(imageSourceRef,
0, // index 0 of the source
(__bridge CFDictionaryRef)thumbnailOptions);
// Do something with the thumbnail ...
// Release the imageRef and imageSourceRef
CGImageRelease (imageRef);
CFRelease(imageSourceRef);

How do you render OpenGL-ES to an external screen using the VGA out adapter?

I've been developing a 3D program for the iPad and iPhone and would like to be able to render it to an external screen. According to my understanding, you have to do something similar to the below code to implement it, (found at: Sunsetlakesoftware.com):
if ([[UIScreen screens] count] > 1)
{
// External screen attached
}
else
{
// Only local screen present
}
CGRect externalBounds = [externalScreen bounds];
externalWindow = [[UIWindow alloc] initWithFrame:externalBounds];
UIView *backgroundView = [[UIView alloc] initWithFrame:externalBounds];
backgroundView.backgroundColor = [UIColor whiteColor];
[externalWindow addSubview:backgroundView];
[backgroundView release];
externalWindow.screen = externalScreen;
[externalWindow makeKeyAndVisible];
However, I'm not sure what to change to do this to an OpenGL project. Does anyone know what you would do to implement this into the defualt openGL project for iPad or iPhone in XCode?
All you need to do to render OpenGL ES content on the external display is to either create a UIView that is backed by a CAEAGLLayer and add it as a subview of the backgroundView above, or take such a view and move it to be a subview of backgroundView.
In fact, you can remove the backgroundView if you want and just place your OpenGL-hosting view directly on the externalWindow UIWindow instance. That window is attached to the UIScreen instance that represents the external display, so anything placed on it will show on that display. This includes OpenGL ES content.
There does appear to be an issue with particular types of OpenGL ES content, as you can see in the experimental support I've tried to add to my Molecules application. If you look in the source code there, I attempt to migrate my rendering view to an external display, but it never appears. I have done the same with other OpenGL ES applications and had their content render fine, so I believe there might be an issue with the depth buffer on the external display. I'm still working to track that down.
I've figured out how to get ANY OpenGL-ES content to render onto an external display. It's actually really straightforward. You just copy your renderbuffer to a UIImage then display that UIImage on the external screen view. The code to take a snapshot of your renderbuffer is below:
- (UIImage*)snapshot:(UIView*)eaglview
{
// Get the size of the backing CAEAGLLayer
GLint backingWidth, backingHeight;
glBindRenderbufferOES(GL_RENDERBUFFER_OES, defaultFramebuffer);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
NSInteger x = 0, y = 0, width = backingWidth, height = backingHeight;
NSInteger dataLength = width * height * 4;
GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte));
// Read pixel data from the framebuffer
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
// Create a CGImage with the pixel data
// If your OpenGL ES content is opaque, use kCGImageAlphaNoneSkipLast to ignore the alpha channel
// otherwise, use kCGImageAlphaPremultipliedLast
CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, data, dataLength, NULL);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGImageRef iref = CGImageCreate(width, height, 8, 32, width * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,
ref, NULL, true, kCGRenderingIntentDefault);
// OpenGL ES measures data in PIXELS
// Create a graphics context with the target size measured in POINTS
NSInteger widthInPoints, heightInPoints;
if (NULL != UIGraphicsBeginImageContextWithOptions) {
// On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions to take the scale into consideration
// Set the scale parameter to your OpenGL ES view's contentScaleFactor
// so that you get a high-resolution snapshot when its value is greater than 1.0
CGFloat scale = eaglview.contentScaleFactor;
widthInPoints = width / scale;
heightInPoints = height / scale;
UIGraphicsBeginImageContextWithOptions(CGSizeMake(widthInPoints, heightInPoints), NO, scale);
}
else {
// On iOS prior to 4, fall back to use UIGraphicsBeginImageContext
widthInPoints = width;
heightInPoints = height;
UIGraphicsBeginImageContext(CGSizeMake(widthInPoints, heightInPoints));
}
CGContextRef cgcontext = UIGraphicsGetCurrentContext();
// UIKit coordinate system is upside down to GL/Quartz coordinate system
// Flip the CGImage by rendering it to the flipped bitmap context
// The size of the destination area is measured in POINTS
CGContextSetBlendMode(cgcontext, kCGBlendModeCopy);
CGContextDrawImage(cgcontext, CGRectMake(0.0, 0.0, widthInPoints, heightInPoints), iref);
// Retrieve the UIImage from the current context
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Clean up
free(data);
CFRelease(ref);
CFRelease(colorspace);
CGImageRelease(iref);
return image;
}
Although, for some reason I've never been able to get glGetRenderbufferParameterivOES to return the proper backingwidth and backingheight, so I've had to use my own function to calculate those. Just pop this into your rendering implementation and place the result onto the external screen using a timer. If anyone can make any improvements to this method, please let me know.

Image drawing on PDF fails to draw image with transformation and outputs wrong

I've a problem with drawing images on PDF. I do apply scaling, rotation, move, etc. to an image and draws that image on the PDF. But drawing is not outputting correctly. When I do rotate image, it just scales and doesn't rotate.
Here, I explain in more detail:
I place an image on UIWebView to make fake effect of image exactly on PDF. Then, I do draw image on PDF which is on the UIWebView while making PDF.
But when I go and prepare PDF with modified image, which has been applied lots of transformations, image scales not rotates.
Here, img_copyright is a Custom class inheriting UIImageView.
CGFloat orgY = (newY-whiteSpace)+img_copyright.frame.size.height;
CGFloat modY = pageRect.size.height-orgY;
CGFloat orgX = img_copyright.frame.origin.x-PDF_PAGE_PADDING_WIDTH;
CGFloat modX = orgX;
//We're getting X,Y of the image here to decide where to put the image on PDF.
CGRect drawRect = CGRectMake (modX, modY, img_copyright.frame.size.width, img_copyright.frame.size.height);
//Preparing the rectangle in which image is to be drawn.
CGContextDrawImage(pdfContext, drawRect, [img_copyright.image CGImage]);
[img_copyright release];
// Actually drawing the image.
But when i see the PDF image is not properly drawn into it.
What would you suggest, is it the problem due to image drawing based on its X,Y?
How could we decide where to put the image on PDF if we don't depend on X, Y?
What is the exact method of drawing image on PDF with rotation, scale?
The Image when I do insert the image onto UIWebView's scrollbar.
http://www.freeimagehosting.net/">
The Image when I do draw the image onto PDF.
http://www.freeimagehosting.net/">
CGFloat angleInRadians =-1*Angle* (M_PI / 180.0);
CGAffineTransform transform=CGAffineTransformIdentity;
transform = CGAffineTransformMakeRotation(angleInRadians);
//transform = CGAffineTransformMakeScale(1, -1);
//transform =CGAffineTransformMakeTranslation(0,80);
CGRect rotatedRect = CGRectApplyAffineTransform(CGRectMake(0,0,Image.size.width,Image.size.height), transform);
UIGraphicsBeginImageContext(rotatedRect.size);
//[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), 0,rotatedRect.size.height);
CGContextScaleCTM(UIGraphicsGetCurrentContext(),1, -1);
//CGContextTranslateCTM(UIGraphicsGetCurrentContext(), +(rotatedRect.size.width/2),+(rotatedRect.size.height/2));
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), (rotatedRect.origin.x)*-1,(rotatedRect.origin.y)*-1);
CGContextRotateCTM(UIGraphicsGetCurrentContext(), angleInRadians);
//CGContextTranslateCTM(UIGraphicsGetCurrentContext(), -(rotatedRect.size.width/2),-(rotatedRect.size.height/2));
CGImageRef temp = [Image CGImage];
CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, Image.size.width,Image.size.height), temp);
//CGContextRotateCTM(UIGraphicsGetCurrentContext(), -angleInRadians);
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return viewImage;