Trying to create thumb pictures of documents that has been opened in my app with openurl.
My app can open and save .doc .xls and .pdf file, but when I try to save the screenshot it can correctly save the .doc content, for pdf and xls it only saves a blank white picture.
here are some sample documents I am testing:
.doc,
.pdf,
excel
Here is my code:
-(void)webViewDidFinishLoad:(UIWebView *)webViewCapture
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSLog(#"webViewDidFinishLoad");
NSLog(#"webview %#",webView);
NSLog(#"webViewCapture %#",webViewCapture);
UIGraphicsBeginImageContext(webView.bounds.size);
[webView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Convert UIImage to JPEG
NSData *imgData = UIImageJPEGRepresentation(viewImage, 1);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePathLocal = [documentsDirectory stringByAppendingPathComponent:#"Inbox"];
NSArray *partialDates =[self.imageFilename componentsSeparatedByString:#"."];//split string where - chars are found
NSString* fileDescription= [partialDates objectAtIndex: 0];
//creatre unique name for image _AKIAIVLFQKM11111
NSString *uniqueFileName=[NSString stringWithFormat:#"%#_AKIAIVLFQKM11111_%#.jpeg",fileDescription,[partialDates objectAtIndex: 1]];
NSString *finalFileName= [filePathLocal stringByAppendingPathComponent:uniqueFileName];
NSError *error = nil;
if ([imgData writeToFile:finalFileName options:NSDataWritingAtomic error:&error]) {
// file saved
} else {
// error writing file
NSLog(#"Unable to write PDF to %#. Error: %#", finalFileName, error);
}
}
NSLOG:
webViewDidFinishLoad
webview <UIWebView: 0xaa79070; frame = (0 44; 768 960); autoresize = W+H; layer = <CALayer: 0xaa51000>>
webViewCapture <UIWebView: 0xaa79070; frame = (0 44; 768 960); autoresize = W+H; layer = <CALayer: 0xaa51000>>
Why I cant save real content for other types of documents with above code?
Perhaps it's a problem with the methode you are using to take the screenShot, use the one indicated by apple :
- (UIImage*)screenshot
{
// Create a graphics context with the target size
// On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions to take the scale into consideration
// On iOS prior to 4, fall back to use UIGraphicsBeginImageContext
CGSize imageSize = [[UIScreen mainScreen] bounds].size;
if (NULL != UIGraphicsBeginImageContextWithOptions)
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
else
UIGraphicsBeginImageContext(imageSize);
CGContextRef context = UIGraphicsGetCurrentContext();
// Iterate over every window from back to front
for (UIWindow *window in [[UIApplication sharedApplication] windows])
{
if (![window respondsToSelector:#selector(screen)] || [window screen] == [UIScreen mainScreen])
{
// -renderInContext: renders in the coordinate space of the layer,
// so we must first apply the layer's geometry to the graphics context
CGContextSaveGState(context);
// Center the context around the window's anchor point
CGContextTranslateCTM(context, [window center].x, [window center].y);
// Apply the window's transform about the anchor point
CGContextConcatCTM(context, [window transform]);
// Offset by the portion of the bounds left of and above the anchor point
CGContextTranslateCTM(context,
-[window bounds].size.width * [[window layer] anchorPoint].x,
-[window bounds].size.height * [[window layer] anchorPoint].y);
// Render the layer hierarchy to the current context
[[window layer] renderInContext:context];
// Restore the context
CGContextRestoreGState(context);
}
}
// Retrieve the screenshot image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
For more detail : Screen Capture in UIKit Applications
So two ways I can think of working this out are as follows:
1.) Subclass UIWebview and implement drawRect. in drawRect save a screenshot as you have direct access to the graphicsContext. After you have a screenshot assign it to a custom property on the webview. Then whenever you need it, it should be readily available.
2.) take screenshot asynchronously and guarantee that the webview will exist or do proper error handling on the asynch task to handle the event that the webview no longer exists.
I personally would prefer #2 as it pulls some heavy lifting off the main thread and should still work properly.
Related
I have this method here that takes my UIWebView and convert into a PDF and its working well. But when I print off this PDF or email it, its cut off. Its like its only generating what the size of the UIWebView that I set (which is width: 688 & height: 577) If I increase the size of the UIWebView to lets say 900 or 1024 my PDF is empty. My UIWebView is bigger than 577, but in my app, I am able to scroll.
Here is method....
-(void)webViewDidFinishLoad:(UIWebView *)webViewPDF
{
CGRect origframe = webViewPDF.frame;
NSString *heightStr = [webViewPDF stringByEvaluatingJavaScriptFromString:#"document.body.scrollHeight;"]; // Get the height of our webView
int height = [heightStr intValue];
CGFloat maxHeight = kDefaultPageHeight - 2*kMargin;
int pages = floor(height / maxHeight);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
self.pdfPath = [path stringByAppendingPathComponent:[NSString stringWithFormat:#"Purchase Order.pdf"]];
UIGraphicsBeginPDFContextToFile(self.pdfPath, CGRectZero, nil);
for (int i = 0; i < pages; i++)
{
if (maxHeight * (i+1) > height) {
CGRect f = [webViewPDF frame];
f.size.height -= (((i+1) * maxHeight) - height);
[webViewPDF setFrame: f];
}
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, kDefaultPageWidth, kDefaultPageHeight), nil);
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(currentContext, kMargin, kMargin);
[webViewPDF.layer renderInContext:currentContext];
}
UIGraphicsEndPDFContext();
[webViewPDF setFrame:origframe];
[[[webViewPDF subviews] lastObject] setContentOffset:CGPointMake(0, 0) animated:NO];
}
I hope this makes sense....Does anyone have any suggestions on how to fix this, so the PDF is not cut off?
I forgot to mention these variables:
#define kDefaultPageHeight 850
#define kDefaultPageWidth 850
#define kMargin 50
Here is my share button:
- (IBAction)Share:(id)sender {
NSData *pdfData = [NSData dataWithContentsOfFile:self.pdfPath];
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];
}
I've done this in the past using UIPrintPageRenderer. It's a more versetile way of creating a PDF from a UIWebView, and it's been working well for me so far. I've tested this solution with Xcode 6 and iOS 8.2. Also, tried printing the resulting PDF and everything printed out fine.
When I read the OP, I did some testing with various page sizes, to see if I can get a blank PDF. There are a few key items that I identified, that could contribute to a blank PDF file. I've identified them in the code.
When webViewDidFinishLoad() gets called, the view might not be 100% loaded. A check is necessary, to see if the view is still loading. This is important, as it might be the source of your problem. If it's not, then we are good to go. There is a very important note here. Some web pages are loaded dynamically (defined in the page itself). Take youtube.com for example. The page displays almost immediately, with a "loading" screen. This will trick our web view, and it's "isLoading" property will be set to "false", while the web page is still loading content dynamically. This is a pretty rare case though, and in the general case this solution will work well. If you need to generate a PDF file from such a dynamic loading web page, you might need to move the actual generation to a different spot. Even with a dynamic loading web page, you will end up with a PDF showing the loading screen, and not an empty PDF file.
Another key aspect is setting the printableRect and pageRect. Note that those are set separately. If the printableRect is smaller than the paperRect, you will end up with some padding around the content - see code for example. Here is a link to Apple's API doc with some short descriptions for both.
The example code below adds a Category to UIPrintPageRenderer to create the actual PDF data. The code in this sample has been put together using various resources online in the past, and I wasn't able to find which ones were used to credit them properly.
#interface UIPrintPageRenderer (PDF)
- (NSData*) createPDF;
#end
#implementation UIPrintPageRenderer (PDF)
- (NSData*) createPDF
{
NSMutableData *pdfData = [NSMutableData data];
UIGraphicsBeginPDFContextToData( pdfData, self.paperRect, nil );
[self prepareForDrawingPages: NSMakeRange(0, self.numberOfPages)];
CGRect bounds = UIGraphicsGetPDFContextBounds();
for ( int i = 0 ; i < self.numberOfPages ; i++ )
{
UIGraphicsBeginPDFPage();
[self drawPageAtIndex: i inRect: bounds];
}
UIGraphicsEndPDFContext();
return pdfData;
}
#end
And here is what I have in webViewDidFinishLoad()
- (void)webViewDidFinishLoad:(UIWebView *)webViewIn {
NSLog(#"web view did finish loading");
// webViewDidFinishLoad() could get called multiple times before
// the page is 100% loaded. That's why we check if the page is still loading
if (webViewIn.isLoading)
return;
UIPrintPageRenderer *render = [[UIPrintPageRenderer alloc] init];
[render addPrintFormatter:webViewIn.viewPrintFormatter startingAtPageAtIndex:0];
// Padding is desirable, but optional
float padding = 10.0f;
// Define the printableRect and paperRect
// If the printableRect defines the printable area of the page
CGRect paperRect = CGRectMake(0, 0, PDFSize.width, PDFSize.height);
CGRect printableRect = CGRectMake(padding, padding, PDFSize.width-(padding * 2), PDFSize.height-(padding * 2));
[render setValue:[NSValue valueWithCGRect:paperRect] forKey:#"paperRect"];
[render setValue:[NSValue valueWithCGRect:printableRect] forKey:#"printableRect"];
// Call the printToPDF helper method that will do the actual PDF creation using values set above
NSData *pdfData = [render createPDF];
// Save the PDF to a file, if creating one is successful
if (pdfData) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
NSString *pdfPath = [path stringByAppendingPathComponent:[NSString stringWithFormat:#"Purchase Order.pdf"]];
[pdfData writeToFile:pdfPath atomically:YES];
}
else
{
NSLog(#"error creating PDF");
}
}
PDFSize is defined as a constant, set to a standard A4 page size. It can be edited to meet your needs.
#define PDFSize CGSizeMake(595.2,841.8)
In order to create your PDF file in memory, you need to draw the layer of the UIWebBrowserView instance that lies underneath the UIWebView's scrollView. In order to do that, try changing your renderInContext: call the following way :
UIView* contentView = webViewPDF.scrollView.subviews.firstObject;
[contentView.layer renderInContext:currentContext];
Also, if you target iOS >= 7.0, then you can avoid using renderInContext: and use one of the snapshotViewAfterScreenUpdates:
or drawViewHierarchyInRect:afterScreenUpdates: methods.
This question already has answers here:
Creating PDF file from UIWebView
(6 answers)
Closed 5 years ago.
In my iOS application, I want to create a PDF from UIWebView/UIView (including subviews). In my app, I will first load the original incoming PDF in UIWebView, and then add an image as a subview on UIWebView. I want to create a PDF from the UIWebview with this image (subview) with original clarity and no data loss.
PS : Image in rendered PDF should be in the same place as in the UIWebView.
I am able to create a PDF from UIWebView, but it lacks the PDF clarity and creates a border issue.
Can anyone please provide a clear solution for PDF rendering from UIWebView (including subviews)?
EDITED CONTENT:
Above is the screenshot of UIWebView. Signature(test) is the image in the subview. I want to render this as a PDF with clarity and without any data loss.
In the below answers, UIPrintPageRenderer renders the PDF from UIWebView, but it ignores the subviews above UIWebView. This is the major issue with this option.
Another answer using the createPDFfromUIView method lacks the original clarity:
-(void)createPDFfromUIView:(UIView*)aView saveToDocumentsWithFileName:(NSString*)aFilename;
A border issue also occurs with this method.
I have also tried to write on the PDF directly, without taking a screenshot, using the below code from this reference.
- (void) drawCustomPDFContent
{
// Put your drawing calls here
// Draw a red box
[[UIColor redColor] set];
UIRectFill(CGRectMake(20, 20, 100, 100));
// Example of drawing your view into PDF, note that this will be a rasterized bitmap, including the text.
// To get smoother text you'll need to use the NSString draw methods
CGContextRef ctx = UIGraphicsGetCurrentContext();
[view.layer renderInContext:ctx];
}
- (void) createCustomPDF
{
NSURL* pdfURL = ... /* URL to pdf file */;
CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL);
const size_t numberOfPages = CGPDFDocumentGetNumberOfPages(pdf);
NSMutableData* data = [NSMutableData data];
UIGraphicsBeginPDFContextToData(data, CGRectZero, nil);
for(size_t page = 1; page <= numberOfPages; page++)
{
// Get the current page and page frame
CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdf, page);
const CGRect pageFrame = CGPDFPageGetBoxRect(pdfPage, kCGPDFMediaBox);
UIGraphicsBeginPDFPageWithInfo(pageFrame, nil);
// Draw the page (flipped)
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -pageFrame.size.height);
CGContextDrawPDFPage(ctx, pdfPage);
CGContextRestoreGState(ctx);
if(page == 1)
{
[self drawCustomPDFContent];
}
}
UIGraphicsEndPDFContext();
CGPDFDocumentRelease(pdf);
pdf = nil;
// Do something with data here
[data writeToFile:... atomically:YES];
}
It does the job. However, (x,y) coordinates in UIWebView differ from the original PDF coordinates, so I can't map the exact coordinates to draw on the PDF to render.
Hopefully, this clears up my issue. Please suggest a way to resolve my issue. If it is likely impossible, please suggest the iOS PDF kit/SDK that meets my requirement.
Use UIPrintPageRenderer from UIWebView Follow below steps :
Add Category of UIPrintPageRenderer for getting PDF Data
#interface UIPrintPageRenderer (PDF)
- (NSData*) printToPDF;
#end
#implementation UIPrintPageRenderer (PDF)
- (NSData*) printToPDF
{
NSMutableData *pdfData = [NSMutableData data];
UIGraphicsBeginPDFContextToData( pdfData, self.paperRect, nil );
[self prepareForDrawingPages: NSMakeRange(0, self.numberOfPages)];
CGRect bounds = UIGraphicsGetPDFContextBounds();
for ( int i = 0 ; i < self.numberOfPages ; i++ )
{
UIGraphicsBeginPDFPage();
[self drawPageAtIndex: i inRect: bounds];
}
UIGraphicsEndPDFContext();
return pdfData;
}
#end
Add these define for A4 size
#define kPaperSizeA4 CGSizeMake(595.2,841.8)
Now in UIWebView's webViewDidFinishLoad delegate use UIPrintPageRenderer property of UIWebView.
- (void)webViewDidFinishLoad:(UIWebView *)awebView
{
if (awebView.isLoading)
return;
UIPrintPageRenderer *render = [[UIPrintPageRenderer alloc] init];
[render addPrintFormatter:awebView.viewPrintFormatter startingAtPageAtIndex:0];
//increase these values according to your requirement
float topPadding = 10.0f;
float bottomPadding = 10.0f;
float leftPadding = 10.0f;
float rightPadding = 10.0f;
CGRect printableRect = CGRectMake(leftPadding,
topPadding,
kPaperSizeA4.width-leftPadding-rightPadding,
kPaperSizeA4.height-topPadding-bottomPadding);
CGRect paperRect = CGRectMake(0, 0, kPaperSizeA4.width, kPaperSizeA4.height);
[render setValue:[NSValue valueWithCGRect:paperRect] forKey:#"paperRect"];
[render setValue:[NSValue valueWithCGRect:printableRect] forKey:#"printableRect"];
NSData *pdfData = [render printToPDF];
if (pdfData) {
[pdfData writeToFile:[NSString stringWithFormat:#"%#/tmp.pdf",NSTemporaryDirectory()] atomically: YES];
}
else
{
NSLog(#"PDF couldnot be created");
}
}
-(void)createPDFfromUIView:(UIView*)aView saveToDocumentsWithFileName:(NSString*)aFilename
{
// Creates a mutable data object for updating with binary data, like a byte array
UIWebView *webView = (UIWebView*)aView;
NSString *heightStr = [webView stringByEvaluatingJavaScriptFromString:#"document.body.scrollHeight;"];
int height = [heightStr intValue];
// CGRect screenRect = [[UIScreen mainScreen] bounds];
// CGFloat screenHeight = (self.contentWebView.hidden)?screenRect.size.width:screenRect.size.height;
CGFloat screenHeight = webView.bounds.size.height;
int pages = ceil(height / screenHeight);
NSMutableData *pdfData = [NSMutableData data];
UIGraphicsBeginPDFContextToData(pdfData, webView.bounds, nil);
CGRect frame = [webView frame];
for (int i = 0; i < pages; i++) {
// Check to screenHeight if page draws more than the height of the UIWebView
if ((i+1) * screenHeight > height) {
CGRect f = [webView frame];
f.size.height -= (((i+1) * screenHeight) - height);
[webView setFrame: f];
}
UIGraphicsBeginPDFPage();
CGContextRef currentContext = UIGraphicsGetCurrentContext();
// CGContextTranslateCTM(currentContext, 72, 72); // Translate for 1" margins
[[[webView subviews] lastObject] setContentOffset:CGPointMake(0, screenHeight * i) animated:NO];
[webView.layer renderInContext:currentContext];
}
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];
[webView setFrame:frame];
}
I've tried to create PDF from HTML (webview). I did it. But, the problem i'm facing badly is i'm getting 1 vertical & 1 horizontal line on each page. As i attached in this link.
Click for image
Zoom it if u can't see the lines.
I've tried this code
// 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, webView.bounds, nil);
UIGraphicsBeginPDFPage();
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
// draws rect to the view and thus this is captured by UIGraphicsBeginPDFContextToData
[webView.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:#"tmp.pdf"];
// instructs the mutable data object to write its context to a file on disk
[pdfData writeToFile:documentDirectoryFilename atomically:YES];
NSLog(#"documentDirectoryFileName: %#",documentDirectoryFilename);
// Creates a mutable data object for updating with binary data, like a byte array
NSString *heightStr = [webView stringByEvaluatingJavaScriptFromString:#"document.body.scrollHeight;"];
int height = [heightStr intValue];
// CGRect screenRect = [[UIScreen mainScreen] bounds];
// CGFloat screenHeight = (self.contentWebView.hidden)?screenRect.size.width:screenRect.size.height;
CGFloat screenHeight = webView.bounds.size.height;
int pages = ceil(height / screenHeight);
UIGraphicsBeginPDFContextToData(pdfData, webView.bounds, nil);
CGRect frame = [webView frame];
for (int i = 0; i < pages; i++) {
// Check to screenHeight if page draws more than the height of the UIWebView
if ((i+1) * screenHeight > height) {
CGRect f = [webView frame];
f.size.height -= (((i+1) * screenHeight) - height);
[webView setFrame: f];
}
UIGraphicsBeginPDFPage();
CGContextRef currentContext = UIGraphicsGetCurrentContext();
//CGContextTranslateCTM(currentContext, 72, 72); // Translate for 1" margins
[[[webView subviews] lastObject] setContentOffset:CGPointMake(0, screenHeight * i) animated:NO];
[webView.layer renderInContext:currentContext];
}
UIGraphicsEndPDFContext();
// instructs the mutable data object to write its context to a file on disk
[pdfData writeToFile:self.PDFpath atomically:YES];
[webView setFrame:frame];
Any one have idea about this ?
Okay, i got it. It wasn't lines the code i was using above makes 4 parts of each page from UIWebView and print them to PDF as image. So it was the gap between those parts.
I'm trying to save all of the contents of a UIScrollView to a .pdf. I found some tutorials for saving the current view, and they all rely on creating a CGContextRef using UIGraphicsGetCurrentContext(). Right now, I capture my view with just
CGContextRef context = UIGraphicsGetCurrentContext();
[myView.layer renderInContext:context];
And that works fine for a plain UIView. However, when I try to pass a UIScrollView as myView, it passes the visible part of the UIScrollView fine, but anything offscreen is just white space. Is there a way I can expand context somehow to get all of the content in my UIScrollView, and not just what is currently visible? I suspect that I can't use UIGraphicsGetCurrentContext() for a UIScrollView, but I don't know what to use instead, and the Apple docs on this aren't really very helpful.
If you have a subview taking the whole content size of the scrollView with the scrolling content you can do it like this:
CGContextRef context = UIGraphicsGetCurrentContext();
UIView *contentView = [scrollView subviews][0];
[contentView.layer renderInContext:context];
If there are multiple views in the scrollView you can do it like this:
UIView *contentView = [[UIView alloc] initWithFrame:CGRectMake(
scrollView.frame.origin.x,
scrollView.frame.origin.y,
scrollView.contentSize.width,
scrollView.contentSize.height)];
for(UIView *view in [scrollView subviews]){
[contentView addSubview: view];
}
CGContextRef context = UIGraphicsGetCurrentContext();
[contentView.layer renderInContext:context];
Then you need to get the views back into the scrollView. Probably there is a way to copy them but I am not sure how. Anyhow here is what should work:
for(UIView *view in [contentView subviews]){
[view removeFromSuperView];
[scrollView addSubview:view];
}
You can set frame of UIScrollView equal to content size of it and content offset to 0 before calling renderInContext. After that revert frame to original.
myView.frame = CGRectMake(myView.frame.origin.x,myView.frame.origin.y,myView.contentSize.with,myView.contentSize.height);
This code i used to make pdf from uiscrollview and it does help but it will not be as good as if we draw on pdf -- please have look -- Pdf from UIScrollView
- (void) createPDF
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *directroyPath = nil;
directroyPath = [documentsDirectory stringByAppendingPathComponent:#"temp"];
NSString *filePath = [directroyPath stringByAppendingPathComponent:#"test.pdf"];
// check for the "PDF" directory
NSError *error;
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
} else {
[[NSFileManager defaultManager] createDirectoryAtPath:directroyPath
withIntermediateDirectories:NO
attributes:nil
error:&error];
}
CGContextRef pdfContext = [self createPDFContext:_scrollView2.bounds path:(CFStringRef)filePath];
NSLog(#"PDF Context created");
/*
Here limit of i is no of pages in your uiscrollview or
you can use hit and trial here because there is a
length of page is going to be equal to
the visible size of uiscrollView in your application
*/
for (int i = 0 ; i< 2 ; i++)
{
// page 1
CGContextBeginPage (pdfContext,nil);
//turn PDF upsidedown
CGAffineTransform transform = CGAffineTransformIdentity;
//here 365 is equal to the height of myScrollView.frame.size.height
transform = CGAffineTransformMakeTranslation(0, (i+1) * 365);
transform = CGAffineTransformScale(transform, 1.0, -1.0);
CGContextConcatCTM(pdfContext, transform);
//Draw view into PDF
[_scrollView2.layer renderInContext:pdfContext];
CGContextEndPage (pdfContext);
[_scrollView2 setContentOffset:CGPointMake(0, (i+1) * 365) animated:NO];
}
CGContextRelease (pdfContext);
}
- (CGContextRef) createPDFContext:(CGRect)inMediaBox path:(CFStringRef) path
{
CGContextRef myOutContext = NULL;
CFURLRef url;
url = CFURLCreateWithFileSystemPath (NULL, path,
kCFURLPOSIXPathStyle,
false);
if (url != NULL) {
myOutContext = CGPDFContextCreateWithURL (url,
&inMediaBox,
NULL);
CFRelease(url);
}
return myOutContext;
}
Check ScrollViewToPDF example and understand it.
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
I found this code which is quite nice:
+ (UIImage *) imageWithView:(UIView *)view
{
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, [[UIScreen mainScreen] scale]);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
But I need to capture UINavigationBar as well because i want to use the image as transition layer in my UIStoryboardSegue. Any ideas?
Use your view's window as the view so the navigation bar and status bar will be included, too. If you need to remove the status bar, you'll have to crop the image.
You should take a screenshot of self.navigationController?.view .
That way you get the whole view with navigationBar but without status bar.
if let view = self.navigationController?.view {
let snapshot = view.snapshotViewAfterScreenUpdates(false)
}
instead of view.layer give reference of appdelegate.window.layer it will work.
Wow, really none of these answers work. This is how you do it to get screenshot of everything including navigation controller
-(void) takeScreenshot
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
//its iphone
CGSize result = [[UIScreen mainScreen] bounds].size;
if(result.height == 480 || result.width == 480)
{
// iPhone Classic
screenRect = CGRectMake(0, 0, 320, 480);
}
if(result.height == 568 || result.width == 568)
{
// iPhone 5
screenRect = CGRectMake(0, 0, 320, 568);
}
}
else
{
//its pad
screenRect = CGRectMake(0, 0, 768, 1024);
}
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
// This code is for high resolution screenshot
UIGraphicsBeginImageContextWithOptions(screenRect.size, NO, 0.0);
//this was pre iOS 7.0
//[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
// iOS 7.x -->
[[[[UIApplication sharedApplication] windows] objectAtIndex:0] drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:YES]; // Set To YES
UIImage *viewImage2 = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData* imageData2 = UIImageJPEGRepresentation(viewImage2, 1.0);
NSString* incrementedImgStr2 = [NSString stringWithFormat: #"UserScreenShotPic.jpg"];
// Now we get the full path to the file
NSString* fullPathToFile3 = [documentsDirectory stringByAppendingPathComponent:incrementedImgStr2];
[imageData2 writeToFile:fullPathToFile3 atomically:NO];
}