In my application I have to show a PDF reader (PDF from a server) and copy everything to another PDF. I am using Reader to show the PDF.
But it is unable to format the text inside the PDF. Bold text is shown in some different narrow font other than Bold. Can you please give me a solution?
Again, while writing I am using Saving a PDF document to disk using Quartz. But here I am facing the same problem. The new PDF is showing the font other than what is used in the source PDF.
I tried the code below also. Still I am getting the same O/P. Please help me with this. I have not tested it with another text font like italic / underline. It should work for these fonts also.
- (void) generatePdfWithFilePath: (NSString *)thefilePath {
UIGraphicsBeginPDFContextToFile(thefilePath, CGRectZero, NULL);
BOOL done = NO;
do {
//Start a new page.
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, pageSize.width, pageSize.height), nil);
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"MyPdf" ofType:#"pdf"];
CFURLRef url = (CFURLRef)[NSURL fileURLWithPath:filePath];
CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL(url);
CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 1);
CGRect paperSize = CGPDFPageGetBoxRect(CGPDFDocumentGetPage (pdf, 1), kCGPDFMediaBox);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, paperSize.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawPDFPage(context, page);
done = YES;
} while (!done);
UIGraphicsEndPDFContext();
}
It is happening if the source PDF is generated from a source other than an iOS device.
A couple of thoughts:
The font you're looking to display is not in any of the iOS devices, nor is it embedded in the PDF. Thus, it substitutes a font it thinks is similar.
You don't have to use Reader to display a PDF, you can use a web view, the UIDocumentInteraction Controller, or CGPDFController. You might have more luck using one of these built-in displays, rather than Reader.
I'm creating a grid of cells that represent downloaded files of various types (PDF, Images, Videos, HTML, .pages, .numbers, Word, etc.) in an ios application and am looking for a way to preemptively create preview thumbnails for these documents to show in the cells. I'm currently using the UIDocumentInteractionController for previewing these documents after the user selects one and was hoping that the icons array would return the preview images. Unfortunately, it only returns a generic icon.
I see that Pages and Numbers do this, but they own the documents and the format. I was hoping that the Quicklook framework would provide a solution, but I haven't yet found it. Has anybody else found a way to easily generate these thumbnails?
I'd prefer to use an actual UIImage and not a UIWebView as others have suggested. That solution seems to be a hack and I have to believe there's a better solution out there.
My next option is to generate a preview after they open the document by essentially capturing the view as an image, but that still seems hackish.
Anybody have any thoughts or clearer options?
Thanks,
My solution:
I never found a complete solution this particular problem, but I was able to handle PDF's fairly efficiently. I honestly don't remember if I wrote this or found an example. If it's your code that was posted somewhere else, thanks! The end result here is docImage is either null, or contains the first page of the PDF as an image. When loading my table rows, I set the image preview to a default image and then run this code on a background thread using blocks. Once complete, I simply animate the preview back into the cell.
NSURL *pdfFileURL = [NSURL fileURLWithPath:localFilePath];
CGPDFDocumentRef pdfDoc = CGPDFDocumentCreateWithURL((__bridge CFURLRef) pdfFileURL);
NSUInteger numPages = CGPDFDocumentGetNumberOfPages(pdfDoc);
if(numPages > 0) {
docImage = [UIImage imageFromPDFDocumentRef:pdfDoc];
}
CGPDFDocumentRelease(pdfDoc);
UIImage Category:
#implementation UIImage (CGPDFDocument)
+(UIImage *)imageFromPDFDocumentRef:(CGPDFDocumentRef)documentRef {
return [self imageFromPDFDocumentRef:documentRef page:1];
}
+(UIImage *)imageFromPDFDocumentRef:(CGPDFDocumentRef)documentRef page:(NSUInteger)page {
CGPDFPageRef pageRef = CGPDFDocumentGetPage(documentRef, page);
CGRect pageRect = CGPDFPageGetBoxRect(pageRef, kCGPDFCropBox);
UIGraphicsBeginImageContext(pageRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, CGRectGetMinX(pageRect),CGRectGetMaxY(pageRect));
CGContextScaleCTM(context, 1, -1);
CGContextTranslateCTM(context, -(pageRect.origin.x), -(pageRect.origin.y));
CGContextDrawPDFPage(context, pageRef);
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return finalImage;
}
#end
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);
I have an app that allows users to sign a contract. The contract has 3 boxes that need to be autofilled with prices. The PDF will then need to be printed and emailed.
I already have created a view that allows for signature capture. It works by taking an CGImage of the view after the user signs (obviously there is more to it than that).
I can't seem to figure out 2 things:
How to autofill the boxes with prices
Embed the signature image with the PDF for printing.
Any help would be much appreciated and as always, thank you for your time.
Code to draw PDF file
if(document) {
CGPDFPageRef page = CGPDFDocumentGetPage(document, currentPage);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CGContextTranslateCTM(ctx, 0.0, [self bounds].size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextConcatCTM(ctx, CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, [self bounds], 0, true));
CGContextDrawPDFPage(ctx, page);
CGContextRestoreGState(ctx);
}
Using the CoreGraphics framework is tedious work, in my honest opinion, when it comes to programmatically drawing a PDF file.
I would like to programmatically create a PDF, using various objects from views throughout my app.
I am interested to know if there are any good PDF tutorials around for the iOS SDK, maybe a drop in library.
I've seen this tutorial, PDF Creation Tutorial, but it was mostly written in C. Looking for more Objective-C style. This also seems like a ridiculous way to write to a PDF file, having to calculate where lines and other objects will be placed.
void CreatePDFFile (CGRect pageRect, const char *filename)
{
// This code block sets up our PDF Context so that we can draw to it
CGContextRef pdfContext;
CFStringRef path;
CFURLRef url;
CFMutableDictionaryRef myDictionary = NULL;
// Create a CFString from the filename we provide to this method when we call it
path = CFStringCreateWithCString (NULL, filename,
kCFStringEncodingUTF8);
// Create a CFURL using the CFString we just defined
url = CFURLCreateWithFileSystemPath (NULL, path,
kCFURLPOSIXPathStyle, 0);
CFRelease (path);
// This dictionary contains extra options mostly for 'signing' the PDF
myDictionary = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(myDictionary, kCGPDFContextTitle, CFSTR("My PDF File"));
CFDictionarySetValue(myDictionary, kCGPDFContextCreator, CFSTR("My Name"));
// Create our PDF Context with the CFURL, the CGRect we provide, and the above defined dictionary
pdfContext = CGPDFContextCreateWithURL (url, &pageRect, myDictionary);
// Cleanup our mess
CFRelease(myDictionary);
CFRelease(url);
// Done creating our PDF Context, now it's time to draw to it
// Starts our first page
CGContextBeginPage (pdfContext, &pageRect);
// Draws a black rectangle around the page inset by 50 on all sides
CGContextStrokeRect(pdfContext, CGRectMake(50, 50, pageRect.size.width - 100, pageRect.size.height - 100));
// This code block will create an image that we then draw to the page
const char *picture = "Picture";
CGImageRef image;
CGDataProviderRef provider;
CFStringRef picturePath;
CFURLRef pictureURL;
picturePath = CFStringCreateWithCString (NULL, picture,
kCFStringEncodingUTF8);
pictureURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), picturePath, CFSTR("png"), NULL);
CFRelease(picturePath);
provider = CGDataProviderCreateWithURL (pictureURL);
CFRelease (pictureURL);
image = CGImageCreateWithPNGDataProvider (provider, NULL, true, kCGRenderingIntentDefault);
CGDataProviderRelease (provider);
CGContextDrawImage (pdfContext, CGRectMake(200, 200, 207, 385),image);
CGImageRelease (image);
// End image code
// Adding some text on top of the image we just added
CGContextSelectFont (pdfContext, "Helvetica", 16, kCGEncodingMacRoman);
CGContextSetTextDrawingMode (pdfContext, kCGTextFill);
CGContextSetRGBFillColor (pdfContext, 0, 0, 0, 1);
const char *text = "Hello World!";
CGContextShowTextAtPoint (pdfContext, 260, 390, text, strlen(text));
// End text
// We are done drawing to this page, let's end it
// We could add as many pages as we wanted using CGContextBeginPage/CGContextEndPage
CGContextEndPage (pdfContext);
// We are done with our context now, so we release it
CGContextRelease (pdfContext);
}
EDIT: Here's an example on GitHub using libHaru in an iPhone project.
A couple things...
First, there is a bug with CoreGraphics PDF generation in iOS that results in corrupted PDFs. I know this issue exists up to and including iOS 4.1 (I haven't tested iOS 4.2). The issue is related to fonts and only shows up if you include text in your PDF. The symptom is that, when generating the PDF, you'll see errors in the debug console that look like this:
<Error>: can't get CIDs for glyphs for 'TimesNewRomanPSMT'
The tricky aspect is that the resulting PDF will render fine in some PDF readers, but fail to render in other places. So, if you have control over the software that will be used to open your PDF, you may be able to ignore this issue (e.g., if you only intend to display the PDF on the iPhone or Mac desktops, then you should be fine using CoreGraphics). However, if you need to create a PDF that works anywhere, then you should take a closer look at this issue. Here's some additional info:
http://www.iphonedevsdk.com/forum/iphone-sdk-development/15505-pdf-font-problem-cant-get-cids-glyphs.html#post97854
As a workaround, I've used libHaru successfully on iPhone as a replacement for CoreGraphics PDF generation. It was a little tricky getting libHaru to build with my project initially, but once I got my project setup properly, it worked fine for my needs.
Second, depending on the format/layout of your PDF, you might consider using Interface Builder to create a view that serves as a "template" for your PDF output. You would then write code to load the view, fill in any data (e.g., set text for UILabels, etc.), then render the individual elements of the view into the PDF. In other words, use IB to specify coordinates, fonts, images, etc. and write code to render various elements (e.g., UILabel, UIImageView, etc.) in a generic way so you don't have to hard-code everything. I used this approach and it worked out great for my needs. Again, this may or may not make sense for your situation depending on the formatting/layout needs of your PDF.
EDIT: (response to 1st comment)
My implementation is part of a commercial product meaning that I can't share the full code, but I can give a general outline:
I created a .xib file with a view and sized the view to 850 x 1100 (my PDF was targeting 8.5 x 11 inches, so this makes it easy to translate to/from design-time coordinates).
In code, I load the view:
- (UIView *)loadTemplate
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ReportTemplate" owner:self options:nil];
for (id view in nib) {
if ([view isKindOfClass: [UIView class]]) {
return view;
}
}
return nil;
}
I then fill in various elements. I used tags to find the appropriate elements, but you could do this other ways. Example:
UILabel *label = (UILabel *)[templateView viewWithTag:TAG_FIRST_NAME];
if (label != nil) {
label.text = (firstName != nil) ? firstName : #"None";
Then I call a function to render the view to the PDF file. This function recursively walks the view hierarchy and renders each subview. For my project, I need to support only Label, ImageView, and View (for nested views):
- (void)addObject:(UIView *)view
{
if (view != nil && !view.hidden) {
if ([view isKindOfClass:[UILabel class]]) {
[self addLabel:(UILabel *)view];
} else if ([view isKindOfClass:[UIImageView class]]) {
[self addImageView:(UIImageView *)view];
} else if ([view isKindOfClass:[UIView class]]) {
[self addContainer:view];
}
}
}
As an example, here's my implementation of addImageView (HPDF_ functions are from libHaru):
- (void)addImageView:(UIImageView *)imageView
{
NSData *pngData = UIImagePNGRepresentation(imageView.image);
if (pngData != nil) {
HPDF_Image image = HPDF_LoadPngImageFromMem(_pdf, [pngData bytes], [pngData length]);
if (image != NULL) {
CGRect destRect = [self rectToPDF:imageView.frame];
float x = destRect.origin.x;
float y = destRect.origin.y - destRect.size.height;
float width = destRect.size.width;
float height = destRect.size.height;
HPDF_Page page = HPDF_GetCurrentPage(_pdf);
HPDF_Page_DrawImage(page, image, x, y, width, height);
}
}
}
Hopefully that gives you the idea.
It's a late reply, but as i struggled a lot with pdf generation, i considered it worthwhile to share my views. Instead of Core graphics, to create a context, you can also use UIKit methods to generate a pdf.
Apple has documented it well in the drawing and printing guide.
The PDF functions on iOS are all CoreGraphics based, which makes sense, because the draw primitives in iOS are also CoreGraphics based. If you want to be rendering 2D primitives directly into a PDF, you'll have to use CoreGraphics.
There are some shortcuts for objects that live in UIKit as well, like images. Drawing a PNG to a PDF context still requires the call to CGContextDrawImage, but you can do it with the CGImage that you can get from a UIImage, e.g.:
UIImage * myPNG = [UIImage imageNamed:#"mypng.png"];
CGContextDrawImage (pdfContext, CGRectMake(200, 200, 207, 385), [myPNG CGImage]);
If you want more guidance on overall design, please be more explicit about what you mean by "various objects throughout your app" and what you're trying to accomplish.
Late, but possibly helpful to others. It sounds like a PDF template style of operation might be the approach you want rather than building the PDF in code. Since you want to email it off anyway, you are connected to the net so you could use something like the Docmosis cloud service which is effectively a mail-merge service. Send it the data/images to merge with your template. That type of approach has the benefit of a lot less code and offloading most of the processing from your iPad app. I've seen it used in an iPad app and it was nice.