iPad UIView to PDF - low resolution - ipad

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/

Related

How to draw on pdf page with PDFKit

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.

renderInContext no longer working in xCode 8

I've been working on an app where I have a UIView that needs to be printed via AirPrint. To accomplish this I first fill out all the details in the view and then pass it to the below code to make a pdf out of before printing it.
In Xcode 7 everything was working fine. Since I did the update to Xcode 8, the view doesn't render to the correct size any more using renderInContext.
- (NSMutableData *)createPDFDataFromUIView:(UIView *)aView {
NSMutableData *pdfDataObject=[NSMutableData data];
// create a PDF-based graphics context with mutable data object as the target
UIGraphicsBeginPDFContextToData(pdfDataObject, [aView bounds], nil);
// mark the beginning of a new page
UIGraphicsBeginPDFPage();
// get the CGContextRef for our PDF drawing
CGContextRef pdfContext= UIGraphicsGetCurrentContext();
// render the UIView’s layer into the PDF context
[[aView layer] renderInContext:pdfContext];
// end the PDF context
UIGraphicsEndPDFContext();
return pdfDataObject;
}
Any help would be appreciated.

Objective-C Full UIView to PDF

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

Create PDF from UIScrollView Objective C

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];

Creating PDF From String Creates Blank Screen

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.

Resources