I'm trying to create a PDF file, with the content of the PDF being text stored in an NSMutableString, and the string is stored on the disk. For some reason though, the PDF is coming out blank. I've been going over this code for a while now and can't figure out why the PDF is not being created with the contents of the string. I NSLogged the string, and the text is definitely in there. Here is the code I'm using, the string in which the data is stored is stringToSave:
- (void)createPDFfromString:(NSMutableString*)string saveToDocumentsWithFileName:(NSString*)aFilename
{
CGRect stringRect = [[UIScreen mainScreen] bounds];
// Creates a mutable data object for updating with binary data, like a byte array
NSMutableData *pdfData = [NSMutableData data];
// Points the pdf converter to the mutable data object and to the UIView to be converted
UIGraphicsBeginPDFContextToData(pdfData, stringRect, myDictionary);
UIGraphicsBeginPDFPage();
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
// draws rect to the view and thus this is captured by UIGraphicsBeginPDFContextToData
UIFont *theFont = [UIFont systemFontOfSize:12];
[stringToSave drawInRect:stringRect withFont:theFont];
// remove PDF rendering context
UIGraphicsEndPDFContext();
}
If anyone could detect where I'm going wrong and let me know how to fix it, it would be much appreciated. Thanks!
EDIT: I didn't put in the code that I'm using to save, because that part is working A-okay.
Related
I’m currently working on a project and I need to generate a PDF based on a bunch of information the user had entered.
I'm using PDFKit, I managed to create a PDFView and add a PDFDocument to it. My problem is that I couldn't really find a way to draw on the document's pages using PDFKit. I don't want to add annotations, I want to draw tables and texts inside that table's cells.
I've found some examples to do that but all of them were not complete and you need to have some knowledge to really understand them. I've also found some examples using Quartz and Core Graphics but I don't know if I can apply it to PDFKit.
I need only an example of drawing a line using PDFKit.
Thanks.
All you need is create pdfData:
-(NSMutableData *)createPDFData {
// Creates a mutable data object for updating with binary data, like a byte array
NSMutableData *pdfData = [NSMutableData data];
// Points the pdf converter to the mutable data object and to the UIView to be converted
CGRect bounds = self.bounds;
UIGraphicsBeginPDFContextToData(pdfData, CGRectZero, nil);
UIGraphicsBeginPDFPageWithInfo(bounds, nil);
CGContextRef currentContext = UIGraphicsGetCurrentContext();
[self drawBottomRect];
[self drawImageView:self.ivBackground];
// draw labels by section
[self drawLabel:self.walletName];
currentContext = UIGraphicsGetCurrentContext();
// remove PDF rendering context
UIGraphicsEndPDFContext();
return pdfData;
}
Example how to draw image view:
-(void) drawImageView: (UIImageView*) imageView
{
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGRect frameRect = [imageView convertRect:imageView.bounds toView:self];
CGContextTranslateCTM(currentContext, frameRect.origin.x,frameRect.origin.y);
[imageView.layer renderInContext:currentContext];
CGContextTranslateCTM(currentContext, -frameRect.origin.x,- frameRect.origin.y);
}
Save PDF data as file.
Please read my scenario carefully,
I have one UITextView and one UIImageView bottom of TextView.
Each time there will be dynamic content in TextView and accordingly that, I am asking User to make a signature and it will be displayed as an image in bottom ImageView.
Now the requirement is I have to pass these details on the server along with Signature in one PDF file, So I have to create PDF file which contains both TextView text and ImageView image.
Note: TextView is containing Html text also, so it should show in the same format in PDF also.
Check below Images as required and current pdfs.
This is required PDF
This is current PDF
Only Put the code which can be helpful for both HTML support and Image merge with text. Please don't show simple PDF creation as I have done it already.
you don't need a 3rd party library, Cocoa and Cocoa touch have rich PDF support. I've stubbed you out a little start, do this in your viewController. There may be a few small errors, Ive been using swift for a couple of years now but I used my very rusty objC here because you tagged the question that way. Let me know any problems, good luck
-(NSData *)drawPDFdata{
// default pdf..
// 8.5 X 11 inch #72dpi
// = 612 x 792
CGRect rct = {{0.0 , 0.0 } , {612.0 , 792.0}}
NSMutableData *pdfData = [[NSMutableData alloc]init];
UIGraphicsBeginPDFContextToData(pdfData, rct, nil);
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
UIGraphicsBeginPDFPage();
//textView drawing
CGContextSaveGState(pdfContext);
CGContextConcatCTM(pdfContext, CGAffineTransformMakeTranslation(50.0,50.0));//this is just an offset for the textView drawing. You will want to play with the values, espeecially if supporting multiple screen sizes you might tranform the scale as well..
[textView.layer renderInContext:pdfContext]
CGContextRestoreGState(pdfContext);
//imageView drawing
CGContextSaveGState(pdfContext);
CGContextConcatCTM(pdfContext, CGAffineTransformMakeTranslation(50.0,50.0)); //this is just an offset for the imageView drawing. Thee same stuff applies as above..
[imageView.layer renderInContext:pdfContext]
CGContextRestoreGState(pdfContext);
//cleanup
UIGraphicsEndPDFContext();
return pdfData;
}
here's a couple of client functions to use this NSData
//ways to use the pdf Data
-(Bool)savePDFtoPath: (NSString *)path {
return [ [self drawPDFdata] writeToFile:path atomically:YES] ;
}
//requires Quartz framework.. (can be drawn straight to a UIView)
// note you MAY owe a CGPDFDocumentRelease() on the result of this function (sorry i've not used objC in a couple of years...)
-(CGPDFDocument *)createPDFdocument {
NSData *data = [self drawPDFdata];
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL , data , sizeof(data) ,NULL);
CGPDFDocument result = CGPDFDocumentCreateWithProvider(provider);
CGDataProviderRelease(provider); //not sure if this is still required under ARC?? (def not in swift)
return result;
}
Try this useful third party library :
https://github.com/iclems/iOS-htmltopdf
Use this function for your problem :
+ (id)createPDFWithHTML:(NSString*)HTML pathForPDF:(NSString*)PDFpath pageSize:(CGSize)pageSize margins:(UIEdgeInsets)pageMargins successBlock:(NDHTMLtoPDFCompletionBlock)successBlock errorBlock:(NDHTMLtoPDFCompletionBlock)errorBlock;
I have this code here that takes my UIView in puts it into a PDF. My issue I am having is that my view is a detail view controller and is scrollable and the PDF only gets what inside the detail view controller at that time and not a full view, if I move around in the detail view, it will capture whatever part I am on, not the full thing. Is what I am trying to do possible?
- (IBAction)Share:(id)sender {
NSMutableData *pdfData = [NSMutableData data];
// Points the pdf converter to the mutable data object and to the UIView to be converted
UIGraphicsBeginPDFContextToData(pdfData, spreadSheet.bounds, nil);
UIGraphicsBeginPDFPage();
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
// draws rect to the view and thus this is captured by UIGraphicsBeginPDFContextToData
[spreadSheet.layer renderInContext:pdfContext];
// remove PDF rendering context
UIGraphicsEndPDFContext();
// Retrieves the document directories from the iOS device
NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString* documentDirectory = [documentDirectories objectAtIndex:0];
NSString* documentDirectoryFilename = [documentDirectory stringByAppendingPathComponent:#"test.pdf"];
// instructs the mutable data object to write its context to a file on disk
[pdfData writeToFile:documentDirectoryFilename atomically:YES];
NSLog(#"documentDirectoryFileName: %#",documentDirectoryFilename);
UIActivityViewController * activityController = [[UIActivityViewController alloc] initWithActivityItems:#[pdfData] applicationActivities:nil];
UIPopoverController *popup = [[UIPopoverController alloc] initWithContentViewController:activityController];
[popup presentPopoverFromRect:CGRectMake(self.view.frame.size.width - 36, 60, 0, 0)inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
UPDATE
I have been really struggling with this, I can't get the full view into a PDF, I have also been thinking of going to route of taking my NSMutableArray and my NSArray which is the data used in my UIView and try to covert that into a PDF but that sounds very time consuming to make format it nicely, unless someone knows of way to do that. I guess I am confused on which route I should take.
From this
My issue I am having is that my view is a detail view controller and
is scrollable and the PDF only gets what inside the detail view
controller at that time and not a full view.
Looks like the problem is your content in view is scrollable and you pdf you creating is only capture the visible area.
Here is your problem
UIGraphicsBeginPDFContextToData(pdfData, spreadSheet.bounds, nil);
You need to fix it you need to give it the scrollable view (UITableView,UICollectionView or Scrollview) content size bounds here is how you do it.
-(NSData*)pdfDataFromTableViewContent
{
NSMutableData *pdfData = [NSMutableData data];
//The real size, not only the visible part use your scrollable view ((UITableView,UICollectionView or Scrollview))
CGSize contentSize = self.tableView.contentSize;
CGRect tableViewRealFrame = self.tableView.frame;
//Size tableView to show the whole content
self.tableView.frame = CGRectMake(0, 0, contentSize.width, contentSize.height);
//Generate PDF (one page)
UIGraphicsBeginPDFContextToData(pdfData,self.tableView.frame, nil);
UIGraphicsBeginPDFPage();
[self.tableView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIGraphicsEndPDFContext();
//Resize frame
self.tableView.frame = tableViewRealFrame;
return pdfData;
}
The above code will generates one page.
For more pages use following code
//MultiPage
CGRect mediaBox = self.tableView.frame;
CGSize pageSize = CGSizeMake(self.view.frame.size.width, 800);
UIGraphicsBeginPDFContextToData(pdfData, CGRectZero, nil);
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
NSInteger currentPage = 0;
BOOL done = NO;
do {
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0.0, pageSize.width, pageSize.height), nil);
CGContextTranslateCTM(pdfContext, 0, -(pageSize.height*currentPage));
[self.view.layer renderInContext:pdfContext];
if ((pageSize.height*(currentPage+1)) > mediaBox.size.height) done = YES;
else currentPage++;
} while (!done);
UIGraphicsEndPDFContext();
You can also look into this working project ScrollViewToPDF.
It uses same scrollview's layer renderInContext but here PDF is created according to your requirement such as one page PDF or multiple page PDF.
It captures all visible as well as invisible part of scrollView
Rendering something into a context only renders what is currently in the view hierarchy. That means that if you're using a UITableView or UICollectionView, not every cell that represents your data is in the hierarchy at any given time. If it were me I would try temporarily setting the view to have a massive frame so that everything would be in the hierarchy. If that didn't work I'd be writing a custom view that on request could layout everything for all the data and then reset to a more efficient layout after the rendering was complete.
Try following code to convert UIView to PDF.
Note that the following method creates just a bitmap of the view; it does not create actual typography.
-(void)createPDFfromUIView:(UIView*)aView saveToDocumentsWithFileName:(NSString*)aFilename
{
// Creates a mutable data object for updating with binary data, like a byte array
NSMutableData *pdfData = [NSMutableData data];
// Points the pdf converter to the mutable data object and to the UIView to be converted
UIGraphicsBeginPDFContextToData(pdfData, aView.bounds, nil);
UIGraphicsBeginPDFPage();
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
// draws rect to the view and thus this is captured by UIGraphicsBeginPDFContextToData
[aView.layer renderInContext:pdfContext];
// remove PDF rendering context
UIGraphicsEndPDFContext();
// Retrieves the document directories from the iOS device
NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString* documentDirectory = [documentDirectories objectAtIndex:0];
NSString* documentDirectoryFilename = [documentDirectory stringByAppendingPathComponent:aFilename];
// instructs the mutable data object to write its context to a file on disk
[pdfData writeToFile:documentDirectoryFilename atomically:YES];
NSLog(#"documentDirectoryFileName: %#",documentDirectoryFilename);
}
Also make sure you import: QuartzCore/QuartzCore.h
this question has been posted before (Creating PDF from UIScrollView in iphone app) and the code I am using is from here.
Here is the code
-(void)createPDFfromUIView:(UIView*)aView saveToDocumentsWithFileName:(NSString*)aFilename
{
// Creates a mutable data object for updating with binary data, like a byte array
NSMutableData *pdfData = [NSMutableData data];
// Points the pdf converter to the mutable data object and to the UIView to be converted
UIGraphicsBeginPDFContextToData(pdfData, aView.bounds, nil);
UIGraphicsBeginPDFPage();
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
// draws rect to the view and thus this is captured by UIGraphicsBeginPDFContextToData
[aView.layer renderInContext:pdfContext];
// remove PDF rendering context
UIGraphicsEndPDFContext();
// Retrieves the document directories from the iOS device
NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString* documentDirectory = [documentDirectories objectAtIndex:0];
documentDirectoryFilename = [documentDirectory stringByAppendingPathComponent:aFilename];
// instructs the mutable data object to write its context to a file on disk
[pdfData writeToFile:documentDirectoryFilename atomically:YES];
}
Setup: I have a UIScrollView, inside is a UIView. I want to save the entire UIView (950,500px) and it's in a space (the UIScrollView size) of (520,500). The PDF being generated is only the size of UIScrollView (520,500)
I read the answer but he apparently changed the code but it doesn't work for me. I've been trying to fix this all day.
I'm a beginner so please indicate anything I should add to my question that I missed. Thank you.
PS - this is an iPad app.
The context should have the size of the scrollview's content size, not the bounds.
Then you need to temporarily resize the scrollview to its content size, render it in the PDF context, and restore the size of the scrollview to its original size.
UIGraphicsBeginPDFContextToData(pdfData, (CGRect){0,0, scrollView.contentSize}, nil);
CGRect origSize = scrollView.frame;
CGRect newSize = origSize;
newSize.size = scrollView.contentSize;
[scrollView setFrame:newSize];
[scrollView.layer renderInContext:pdfContext];
[scrollView setFrame:origSize];
Check ScrollViewToPDF example and you will understand what you need to do.
It uses same scrollview's layer renderInContext but here PDF is created according to your requirement such as one page PDF or multiple page PDF
Note : It captures all visible as well as invisible part of scrollView
If anyone was wondering, I found how to fix this.
Since my UIView is IN a UIScrollView, and I use another class for the UIView, when I call the method and chose the parameter aView, I just put in self.
So in my UIView class, when I want the PDF to be generated I type in
[self createPDFfromUIView:self saveToDocumentsWithFileName:UIViewPDF];
I have an app in which PDF is shown in UIWebView, and on top of that I put some UITextFields that need to be filled. The problem is when I generate new PDF from these views, PDF (from UIWebView) resolution stays ok, but text from UITextFields are fuzzy. How to fix that?
I have the following code to generate PDF:
// Creates a mutable data object for updating with binary data, like a byte array
NSMutableData *pdfData = [NSMutableData data];
// Points the pdf converter to the mutable data object and to the UIView to be converted
UIGraphicsBeginPDFContextToData(pdfData, aView.bounds, nil);
UIGraphicsBeginPDFPage();
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
// draws rect to the view and thus this is captured by UIGraphicsBeginPDFContextToData
[aView.layer renderInContext:pdfContext];
// remove PDF rendering context
UIGraphicsEndPDFContext();
You have to upscale your View. Have a look at this, he gives a nice explanation:
http://cadabracorp.com/blog/2012/09/26/creating-printing-and-emailing-high-resolution-pdfs-in-ios/