Issues in generating PDF from uiwebview in objective c - ios

I have open pdf file in uiwebview, add image and text in uiwebview subview.Then i tried created pdf file. Below sample i have used to generate pdf file. Multiple page writing in single page. How can i write sample quality and exact size.
Please check screen shots and below source
UIGraphicsBeginPDFContextToData( pdfData, CGRectZero, nil );
for (int i = 0; i < 10; i++) {
CGRect f = [pdfView frame];
[pdfView setFrame: f];
UIGraphicsBeginPDFPage();
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(currentContext, 72, 72); // Translate for 1" margins
[[[pdfView subviews] lastObject] setContentOffset:CGPointMake(0, 648 * i) animated:NO];
[pdfView.layer renderInContext:currentContext];
}
UIGraphicsEndPDFContext();
and also i have tried this following link but i couldn't add uiwebview subview to write the pdf.
http://b2cloud.com.au/tutorial/drawing-over-a-pdf-in-ios-pdf-template/

You can use the following category on UIView to create a PDF file:
#import <QuartzCore/QuartzCore.h>
#implementation UIView(PDFWritingAdditions)
- (void)renderInPDFFile:(NSString*)path
{
CGRect mediaBox = self.bounds;
CGContextRef ctx = CGPDFContextCreateWithURL((CFURLRef)[NSURL fileURLWithPath:path], &mediaBox, NULL);
CGPDFContextBeginPage(ctx, NULL);
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -mediaBox.size.height);
[self.layer renderInContext:ctx];
CGPDFContextEndPage(ctx);
CFRelease(ctx);
}
#end
Bad news: UIWebView does not create nice shapes and text in the PDF, but renders itself as an image into the PDF.
OR
How to Convert UIView to PDF within iOS?
OR
Creating PDF file from UIWebView
This might helps you :)

I have also used the same its working fine Hope this will be helpful for you.
Create a block:-
typedef void (^PdfCompletion)(BOOL status,NSString *filePath,NSArray *fbArr);
-(void)addData
{
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
NSMutableDictionary *contactDict = [[NSMutableDictionary alloc] init];
[contactDict setObject:contactTextField.text forKey:#"phonenumber"];
[contactDict setObject:emailTextField.text forKey:#"emailid"];
[contactDict setObject:userNameLabel.text forKey:#"displayname"];
[self drawPdf:contactDict completion:^(BOOL status,NSString *filePath,NSArray *fbArr)
{
if (status)
{
NSMutableArray *arr;
arr = [[NSMutableArray alloc] init];
NSData *filedata;
filedata = [NSData dataWithContentsOfFile:filePath];
double locaTotalFileSize = filedata.length +498;
totalFileSize += locaTotalFileSize;
NSMutableDictionary *fileDict = [[NSMutableDictionary alloc] init];
[fileDict setObject:userPicImageView.image forKey:#"image"];
[fileDict setObject:filePath forKey:#"filePath"];
[fileDict setObject:#"txt" forKey:#"fileType"];
[fileDict setObject:[NSString stringWithFormat:#"%#_%#_%#",#"contact",[self getFbID],[self CurrentSystemTime]] forKey:#"fileName"];
[fileDict setObject:#"1" forKey:#"uploadStatus"];
[fileDict setObject:#"0 KB/0 KB" forKey:#"fileSizeStatus"];
[fileDict setObject:#"0 KB/0 KB" forKey:#"ContentSize"];
[arr addObject:fileDict];
[self switchToReviewFiles:arr];
//////NSLog(#"pdf convrt successfull");
}
else
{
//////NSLog(#"Error to convert into pdf");
}
}];
}
// Then Call The DrawPDF Method::--
-(void)drawPdf:(NSMutableDictionary *)drawText completion:(PdfCompletion)callback
{
NSString* fileName = #"contact_card.txt";
NSArray *arrayPaths =
NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *path = [arrayPaths objectAtIndex:0];
NSString* txtFileName = [path stringByAppendingPathComponent:fileName];
NSData *data = [NSJSONSerialization dataWithJSONObject:drawText options:NSJSONWritingPrettyPrinted error:nil];
[data writeToFile:txtFileName atomically:YES];
callback(YES,txtFileName,nil);
}

It looks to me like you're just trying to add content to an existing PDF, right?
- (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];
}
Parts referenced from:
http://b2cloud.com.au/tutorial/drawing-over-a-pdf-in-ios-pdf-template/

You can try this.It worked for me :)
https://github.com/iclems/iOS-htmltopdf/blob/master/NDHTMLtoPDF.h
NSString *html = [webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.outerHTML"];
self.PDFCreator = [NDHTMLtoPDF createPDFWithHTML:html
pathForPDF:[path stringByExpandingTildeInPath]
delegate:self
pageSize:CGSizeMake(595,847)
margins:UIEdgeInsetsMake(105, 0, 0, 0)];
Pass the webView like this

You are actually very close with the code you have. I have a feeling your biggest problem is grabbing a new CGContextRef with each loop iteration..
UIGraphicsBeginPDFContextToData( pdfData, CGRectZero, nil );
CGContextRef currentContext = UIGraphicsGetCurrentContext();//movedByJef
// default pdf..
// 8.5 X 11 inch
// 612 x 792
for (int i = 0; i < 10; i++) {
CGContextSaveGstate( currentContext ); //addedByJef
CGRect f = [pdfView frame];
[pdfView setFrame: f]; // hmm what does this even do??
UIGraphicsBeginPDFPage();
CGContextTranslateCTM(currentContext, -72, -72); // Translate for 1" margins ///editedByJef, you had it backwards..
//assuming you want a 72pt margin on right and bottom as well..
//we want to reduce our size (612 x 792) by 72pts on all four sides..
CGSize printPageSize = CGSizeMake( (612.0 - (72.0 * 2.0)), (792.0 -(72.0*2.0)) );
CGSize layrSize = self.layer.bounds.size;
//so we translate the context so our view fills it nicely..
CGFloat xScaler = layrSize.width / printPageSize.width;
CGFloat yScaler = layrSize.height / printPageSize.height;
CGContextConcatCTM(currentContext, CGAffineTransformMakeScale(xScaler, yScaler) );
[[[pdfView subviews] lastObject] setContentOffset:CGPointMake(0, 648 * i) animated:NO];
[pdfView.layer renderInContext:currentContext];
CGContextRestoreGstate(currentContext);//added by jef
}
UIGraphicsEndPDFContext();
let me know how you go with that, There will undoubtedly be a bit of shuffling in the order of the transforms, maybe a translate needed either side of the scaling, but this should get you really close..

Related

Xcode - Get file from NSDocumentDirectory path

I generated a multi page pdf from my web view and I would like to share the pdf file via an ActivityViewController. I only have the file path and dont know, how to access the file to let them share via the ActivityViewController.
CGRect origframe = webView.frame;
NSString *heightStr = [webView stringByEvaluatingJavaScriptFromString:#"document.body.scrollHeight;"]; // Get the height of our webView
int height = [heightStr intValue];
// Size of the view in the pdf page
CGFloat maxHeight = 568;
CGFloat maxWidth = webView.frame.size.width;
int pages = ceil(height / maxHeight);
// gets the total no:of pages needed in PDF
[webView setFrame:CGRectMake(0.f, 0.f, maxWidth, maxHeight)];
NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString* documentDirectory = [documentDirectories objectAtIndex:0];
NSString *pdfFileName = [documentDirectory stringByAppendingPathComponent:#"mypdf.pdf"];
UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectZero, nil);
int i = 0;
for ( ; i < pages; i++)
{
if (maxHeight * (i+1) > height)
{ // Check to see if page draws more than the height of the UIWebView
CGRect f = [webView frame];
f.size.height -= (((i+1) * maxHeight) - height);
[webView setFrame: f];
}
// Specify the size of the pdf page
CGRect PDFRect = CGRectMake(0, 0, webView.frame.size.width, webView.frame.size.height);
UIGraphicsBeginPDFPageWithInfo(PDFRect, nil);
CGContextRef currentContext = UIGraphicsGetCurrentContext();
// Move the context for the margins
CGContextScaleCTM(currentContext, 1, 1);
// offset the webview content so we're drawing the part of the webview for the current page
[[[webView subviews] lastObject] setContentOffset:CGPointMake(0, maxHeight * i) animated:NO];
// draw the layer to the pdf, ignore the "renderInContext not found" warning.
[webView.layer renderInContext:currentContext];
}
// all done with making the pdf
UIGraphicsEndPDFContext();
// Restore the webview and move it to the top.
[webView setFrame:origframe];
[[[webView subviews] lastObject] setContentOffset:CGPointMake(0, 0) animated:NO];
How can I share the finished file?
Thanks in advance!
You should put you file url into UIActivityViewController
NSString * title =[NSString stringWithFormat:#"Some title string", pdfFileName];
NSArray* pdfToShare = #[title];
UIActivityViewController* activityViewController =[[UIActivityViewController alloc] initWithActivityItems:pdfToShare applicationActivities:nil];
[self presentViewController:activityViewController animated:YES completion:^{}];
UPDATE:
https://developer.apple.com/documentation/foundation/nsdata/1547245-datawithcontentsofurl
NSError* error = nil;
NSData* data = [NSData dataWithContentsOfURL: pdfFileName options:NSDataReadingUncached error:&error];
if (error) {
NSLog(#"%#", [error localizedDescription]);
} else {
// make some stuff with pdf data
}

Converting a UIWebView to PDF/Image gives only one inch wide output

I'm converting a UIWebView to pdf/image with the help of the following code:
NSString *heightStr = [webView stringByEvaluatingJavaScriptFromString:#"document.body.scrollHeight;"];
int height = [heightStr intValue];
CGFloat screenHeight = webView.bounds.size.height;
int pages = ceil(height / screenHeight);
NSMutableData *pdfData = [NSMutableData data];
UIGraphicsBeginPDFContextToData(pdfData, webView.bounds, nil);
CGRect frame = [webView frame];
NSMutableArray *imageArray= [[NSMutableArray alloc]init];
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];
}
UIGraphicsBeginImageContext(frame.size);
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];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
[imageArray insertObject:viewImage atIndex:imageArray.count] ;
UIGraphicsEndImageContext();
}
UIGraphicsEndPDFContext();
[webView setFrame:frame];
//Send all images
NSData *imgData = [self blendImages:imageArray];
//Final Image
UIImage *finalImage = [UIImage imageWithData:imgData];
-(NSData*)blendImages:(NSMutableArray *)arrImage{
// get data from document
CGFloat height=0 ,width=0 ;
UIImage *tempImg = [arrImage objectAtIndex:0] ;
width =tempImg.size.width ;
for (int i = 0 ; i<arrImage.count ; i++){
UIImage *img= [arrImage objectAtIndex:i];
height = img.size.height +height;
}
CGSize size = CGSizeMake(width, height) ;
UIGraphicsBeginImageContext(size);
CGFloat h = 0;
for (int i=0; i<arrImage.count; i++) {
UIImage* uiimage = [arrImage objectAtIndex:i];
[uiimage drawAtPoint:CGPointMake(0, h) blendMode:kCGBlendModeNormal alpha:1.0];
h = uiimage.size.height +h ;
}
NSData *imageData = UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext());
UIGraphicsEndImageContext();
return imageData;
}
But I'm getting only one inch wide output. Also the whole contains fits in one page and make it unreadable. How to make A4 sized output?
This creates a PDF of a screenshot of a webpage - might help get you started :)
- (IBAction)makePDF:(id)sender
{
UIGraphicsBeginImageContextWithOptions(webView.scrollView.contentSize, webView.scrollView.opaque, 0.0);
webView.scrollView.contentOffset = CGPointZero;
webView.scrollView.frame = CGRectMake(0, 0, webView.scrollView.contentSize.width, webView.scrollView.contentSize.height);
[webView.scrollView.layer renderInContext: UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGRect imageFrame = CGRectMake(0, 0, image.size.width, image.size.height);
NSMutableData *pdfData = [NSMutableData data];
UIGraphicsBeginPDFContextToData(pdfData, imageFrame, nil);
//full screenshot
UIGraphicsBeginPDFPage();
UIImageView *imageView = [[UIImageView alloc] initWithFrame:imageFrame];
[imageView setContentMode:UIViewContentModeScaleAspectFit];
[imageView setImage:image];
[imageView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIGraphicsEndPDFContext();
NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString *documentDirectory = [documentDirectories objectAtIndex:0];
NSString *fileName = [NSString stringWithFormat:#"%#.pdf",[NSDate date]];
NSString *path = [documentDirectory stringByAppendingPathComponent:fileName];
// save to disk
[pdfData writeToFile:path atomically:YES];
NSLog(#"pdf in %#", path);
}

Create PDF from UIWebview fails to include subviews in the final PDF

I used web view to load pdf also added an image as subview to my pdfView.
To save the final PDF with subviews,i tried the approach given in the below stack question, it meets the objective but it completely lost quality of the PDF
How to Convert UIView to PDF within iOS?
Now i am try with the below approach,
-(void)savePDFFromWebView:(UIWebView*)webView fileName:(NSString*)_fileName
{
int height, width, header, sidespace;
height = webView.scrollView.contentSize.height;
width = webView.scrollView.contentSize.width;
header = 15;
sidespace = 30;
// set header and footer spaces
UIEdgeInsets pageMargins = UIEdgeInsetsMake(header, sidespace, header, sidespace);
webView.viewPrintFormatter.contentInsets = pageMargins;
UIPrintPageRenderer *renderer = [[UIPrintPageRenderer alloc] init];
[renderer addPrintFormatter:webView.viewPrintFormatter startingAtPageAtIndex:0];
CGSize pageSize = CGSizeMake(width, height);
CGRect printableRect = CGRectMake(pageMargins.left,
pageMargins.top,
pageSize.width - pageMargins.left - pageMargins.right,
pageSize.height - pageMargins.top - pageMargins.bottom);
CGRect paperRect = CGRectMake(0, 0, pageSize.width, pageSize.height);
[renderer setValue:[NSValue valueWithCGRect:paperRect] forKey:#"paperRect"];
[renderer setValue:[NSValue valueWithCGRect:printableRect]
forKey:#"printableRect"];
NSData *pdfData = [self printToPDFWithRenderer:renderer paperRect:paperRect];
// save PDF file
NSString *saveFileName = [NSString stringWithFormat:#"%#%dx%d.pdf",
_fileName, (int)pageSize.width, (int)pageSize.height];
NSString *savePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)
objectAtIndex:0] stringByAppendingPathComponent:saveFileName];
[pdfData writeToFile: savePath atomically: YES];
}
-(NSData*) printToPDFWithRenderer:(UIPrintPageRenderer*)renderer paperRect:(CGRect)paperRect
{
NSMutableData *pdfData = [NSMutableData data];
UIGraphicsBeginPDFContextToData( pdfData, paperRect, nil );
[renderer prepareForDrawingPages: NSMakeRange(0, renderer.numberOfPages)];
CGRect bounds = UIGraphicsGetPDFContextBounds();
for ( int i = 0 ; i < renderer.numberOfPages ; i++ )
{
UIGraphicsBeginPDFPage();
[renderer drawPageAtIndex: i inRect: bounds];
}
UIGraphicsEndPDFContext();
return pdfData;
}
Here the webView which pass as an input for UIPrintPageRenderer includes the
subviews but the final pdf does not includes subviews.
How to include subviews to save the final PDF?

How to generate PDF without page break

I'm converting my WebView to PDf using following code.
UIWebView *webView = self.webView;
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);
f.size.width = self.webView.bounds.size.width*1.6;
[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 stringByAppendingString:#"/pdfFile.PDF"] ;
// instructs the mutable data object to write its context to a file on disk
[pdfData writeToFile:documentDirectoryFilename atomically:YES];
[webView setFrame:frame];
But the issue is its generating PDF with page break as shown in image.
I don't want this page break.can any one suggest what should I do.
You are setting the page size here
UIGraphicsBeginPDFContextToData(pdfData, webView.bounds, nil);
currently set to webView.bounds
Change it with appropriate value.
This little css worked for me.
#media print {
.avoid_pagebreak { display: block; page-break-inside:avoid; page-break-before: auto; }
}
...
<div class="avoid_pagebreak">
...
</div>

iOS embedd page thumbnails in PDF

I need to embed thumbnails in large hq PDF files, which I create using UIGraphicsBeginPDFContextToFile and UIGraphicsBeginPDFPage and drawing text and images on them.
Does anyone know, how to embed page thumbs?
Ciao, Arno
If you want to create a thumbnail from a PDF, then you could use the code below. This code writes it to disk. It's easy to change it so that the method returns the image.
- (void)createPDFThumbnailForFile:(NSString *)theFilename {
if (!theFilename) {return;}
#try {
NSString *path = [FileInfo fullPathForFile:theFilename];
NSURL *pdfFileUrl = [NSURL fileURLWithPath:path];
CFURLRef pdfFileRef = (__bridge CFURLRef) pdfFileUrl;
CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL(pdfFileRef);
CGPDFPageRef page;
CGRect aRect = CGRectMake(0, 0, 70, 100); // thumbnail size
UIGraphicsBeginImageContext(aRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
UIImage *thumbnailImage;
// NSUInteger totalNum = CGPDFDocumentGetNumberOfPages(pdf);
//we only want the first page
for (int i = 0; i < 1; i++) {
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0, aRect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetGrayFillColor(context, 1.0, 1.0);
CGContextFillRect(context, aRect);
// Grab the first PDF page
page = CGPDFDocumentGetPage(pdf, 1);
CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(page, kCGPDFMediaBox, aRect, 0, true);
// And apply the transform.
CGContextConcatCTM(context, pdfTransform);
CGContextDrawPDFPage(context, page);
// Create the new UIImage from the context
thumbnailImage = UIGraphicsGetImageFromCurrentImageContext();
CGContextRestoreGState(context);
}
CGPDFDocumentRelease(pdf);
NSString *pngPath = [path stringByReplacingOccurrencesOfString:#".pdf" withString:#".png"];
// [#"test" writeToFile:pngPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
[UIImagePNGRepresentation(thumbnailImage) writeToFile:pngPath atomically:YES];
}
#catch (NSException *exception) {
DebugLog(#"Could not write thumbnail to : %# /n --> %#", theFileToSave, exception.description);
}
}

Resources