renderInContext no longer working in xCode 8 - ios

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.

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.

how to use drawViewHierarchyInRect

I want to create a snapshot image for a UIView, I used to use renderInRect, but it is slow, and I found that drawViewHierarchyInRect is a newer API since iOS 7, so I want to try it.
I write below code, but it never create a valid image, just a blank image.
-(void)drawRect:(CGRect)rect {
UIGraphicsBeginImageContextWithOptions(_mapView.bounds.size, _mapView.opaque, [[UIScreen mainScreen] scale]);
CGContextRef context = UIGraphicsGetCurrentContext();
// Used to use renderInContext, but it's slow
// [mapView.layer renderInContext:context];
[_mapView drawViewHierarchyInRect:_mapView.bounds afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.thumbImageView = [[UIImageView alloc] initWithImage:image];
[self addSubview:self.thumbImageView];
}
The -drawViewHierarchyInRect:afterScreenUpdates:, which lets you render a snapshot of the complete view hierarchy as visible onscreen into a bitmap context.
renderInContext: renders directly from a CALayer's render tree to valid Core Graphics context.
If you want to render the view to a UIImage rather than having it on the View Hierarchy, you should using renderInContext.

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

Taking a screenshot of a view that is currently not on screen on iOS

I'm trying to make a transition between two ViewControllers. My Transition class has a property for the destination view controller. When I try to get a screenshot of the destination's view, I use this method:
+ (UIImage *)renderImageFromView:(UIView *)view withRect:(CGRect)frame {
// Create a new context the size of the frame
UIGraphicsBeginImageContextWithOptions(frame.size, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
// Render the view
[view.layer renderInContext:context];
// Get the image from the context
UIImage *renderedImage = UIGraphicsGetImageFromCurrentImageContext();
// Cleanup the context you created
UIGraphicsEndImageContext();
return renderedImage;
}
So when I want the image, I'll do this:
UIImage *image = [UIImage renderImageFromView:destinationController.view withRect:destinationController.view.bounds];
I tried it on a blank UIViewController with an orange background color and a label. I get the orange background color, but I do not get the label that was created in IB. Is there a way to get a proper screenshot of the new view I plan on showing? Thanks!
You need to make sure the view's layer is drawn to first. Calling renderInContext on a CALayer will only recursively call additional child CALayers. You need your child UIViews to draw themselves, not just using the CALayer.
Try calling
[view drawrect:frame];
instead of
[view.layer renderInContext:context];
As long as you have an open graphics context(which you do at that point), drawrect should draw directly into that.

iPad UIView to PDF - low resolution

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/

Resources