I just want to know if it's possible to know the size of a pdf after loading it in a UIWebView ?
When we use a code like this :
[self.siteWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.test.fr/test.pdf"]]];
Yes. It is absolutely possible to get height of pdf (1 page height or anything) in uiwebview. I have done before. Below code show how to get 1 page height in uiwebview.
-(void)getPDFInfo
{
NSURL* pdfFileUrl = self.fileLocation;
CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((CFURLRef)pdfFileUrl);
CGPDFPageRef page;
// CGRect aRect = CGRectMake(0, 0, 100, 200); // thumbnail size
NSUInteger totalNum = CGPDFDocumentGetNumberOfPages(pdf);
numberOfPage= totalNum;
for(int i = 0; i < totalNum; i++ ) {
CGPDFPageRef myPageRef=CGPDFDocumentGetPage(pdf, i+1);
//aRect=CGPDFPageGetBoxRect(myPageRef, kCGPDFCropBox);
CGRect cropBox = CGPDFPageGetBoxRect(myPageRef, kCGPDFCropBox);
pdfWidth= cropBox.size.width;
pdfHeight=cropBox.size.height;
NSLog(#"cropbox size is %#",NSStringFromCGRect(cropBox));
int pageRotation = CGPDFPageGetRotationAngle(myPageRef);
CGSize pageVisibleSize = CGSizeMake(cropBox.size.width, cropBox.size.height);
if ((pageRotation == 90) || (pageRotation == 270) ||(pageRotation == -90)) {
pageVisibleSize = CGSizeMake(cropBox.size.height, cropBox.size.width);
}
}
}
After you call this function, call this line to get your pdf file size in uiwebview.
documentHeightInWebview = pdfHeight * (documentWidthInWebview/pdfWidth);
where documentWidthInWebview is your real uiwebview width which will show your pdf file.
You can use javascript to get information. put it in webview did load. For example, the following will get the height of the page.
-(void) webViewDidFinishLoad:(UIWebView *)webView {
//get the height of the chunk, and store it.
CGFloat height = [[webView stringByEvaluatingJavaScriptFromString:#"document.height;"] floatValue];
Related
I am trying to make a UIWebView with "dynamic screen height". This webview is inside a UIScrollView, below other components. See the layout (it uses autolayout):
My idea is to provide just one scroll (from UIScrollView - its working) and make the WebView viewport grow depending the content size. And its not working.
What I did to try to do this:
UIWebView property "scale page to fit " is on;
UIWebView is unpaginated;
UIWebView does not allow user interaction.
In my UIViewController:
- (void) viewDidAppear:(BOOL)animated {
NSString *urlString = #"MY URL GOES HERE";
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[_webViewDescription loadRequest:urlRequest];
_webViewDescription.delegate = self;
_webViewDescription.scrollView.scrollEnabled = NO;
_webViewDescription.scrollView.bounces = NO;
}
My UIWebViewDelegate:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
CGRect frame = webView.frame;
frame.size.height = 1;
webView.frame = frame;
CGSize fittingSize = [webView sizeThatFits:CGSizeZero];
frame.size = fittingSize;
webView.frame = frame;
NSLog(#"size: %f, %f", fittingSize.width, fittingSize.height);
_myScrollView.contentSize = webView.bounds.size;
}
When I run the code, it prints the correct UIScrollView size and UIWebView size. The UIScrollView height got bigger, but the UIWebView maintains the same height from the first loading.
I am testing in a real device.
add a height constraint to your webView and make a IBOutlet of that like
#property(strong, nonatomic) IBOutlet NSLayoutConstraint *webViewHeightConstraint;
load your webview and in web view delegate
- (void)webViewDidFinishLoad:(UIWebView *)webView
get webview content height and set webViewHeightConstraint.constant
like below:-
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString *str = [webView stringByEvaluatingJavaScriptFromString:#"(document.height !== undefined) ? document.height : document.body.offsetHeight;"];
CGFloat height = str.floatValue;
webViewHeightConstraint.constant = height;
}
hope it may help you.
Try to set webView.frame = frame; in viewDidLayoutSubviews()
For setting dynamic height for UIWebView, you need to set the height in webViewDidFinishLoadView method
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
CGFloat height = [[webview stringByEvaluatingJavaScriptFromString:#"document.height"] floatValue];
//For Width
//CGFloat width = [[webview stringByEvaluatingJavaScriptFromString:#"document.width"] floatValue];
CGRect frame = webview1.frame;
frame.size.height = height;
//frame.size.width = width; //Width
webview.frame = frame;
CGRect screenBounds = [UIScreen mainScreen].bounds ;
CGFloat widthForIpad = CGRectGetWidth(screenBounds) ;
CGFloat heightForIpad = CGRectGetHeight(screenBounds) ;
NSLog(#"The iPad width is - %fl",widthForIpad);
NSLog(#"The iPad height is - %fl",heightForIpad);
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
if ([[UIScreen mainScreen] bounds].size.height == 568)
scrollView.contentSize = CGSizeMake(320, height+370); //set your required height
else
scrollView.contentSize = CGSizeMake(320, height+350); //set your required height
}
else
{
if ([[UIScreen mainScreen] bounds].size.height == 1024)
scrollView.contentSize = CGSizeMake(320, height+370); //For iPad
}
}
You can get the content size of webview content using webView.scrollView.contentSize.height.
and than you can use this webView.scrollView.contentSize.height to set the contentSize of the scrollview inside webViewDidFinishLoad method.
Like this in webViewDidFinishLoad method
[objWebView setFrame:CGRectMake(objWebView.frame.origin.x, objWebView.frame.origin.y, objWebView.frame.size.width, webView.scrollView.contentSize.height)];
if(objWebView.frame.origin.y+objWebView.frame.size.height > objScrollView.contentSize.height) {
[objScrollView setContentSize:CGSizeMake(objScrollView.frame.size.width, objWebView.frame.origin.y+objWebView.frame.size.height)];
}
I have a view controller with outlets of scrollview (initial size: 390, 170) and page control. I need it to display an image per page from my array. But i have unexpected result (see image below).
Images are not full-width and after 2nd page scrollView ends.
Here is code
- (void)viewDidLoad {
[super viewDidLoad];
//Put the names of our image files in our array.
imageArray = [[NSArray alloc] initWithObjects:#"header1.jpg", #"header2.jpg", #"header3.jpg", nil];
[self.articlesPageControll setNumberOfPages:imageArray.count];
for (int i = 0; i < [imageArray count]; i++) {
//We'll create an imageView object in every 'page' of our scrollView.
CGRect frame;
frame.origin.x = 390 * i;
frame.origin.y = 0;
frame.size = self.articlesScrollView.frame.size;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
[imageView setContentMode:UIViewContentModeScaleToFill];
imageView.image = [UIImage imageNamed:[imageArray objectAtIndex:i]];
[self.articlesScrollView addSubview:imageView];
}
//Set the content size of our scrollview according to the total width of our imageView objects.
self.articlesScrollView.contentSize = CGSizeMake(self.articlesScrollView.frame.size.width * [imageArray count], 170);
}
- (void)scrollViewDidScroll:(UIScrollView *)sender
{
// Update the page when more than 50% of the previous/next page is visible
CGFloat pageWidth = self.articlesScrollView.frame.size.width;
int page = floor((self.articlesScrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
self.articlesPageControll.currentPage = page;
}
UPD: 3rd page with image actually exists, but it's impossible to scroll to this page
Thanks in advance!
Solution self.articlesScrollView.contentSize = CGSizeMake(390 * [imageArray count], 170);
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 am working on an iPhone application, where i am opening an URL to my UIWebView. The problem is URL is not loading perfectly. As per my requirement, i need to add UIWebView as footer view of my table. but the problem is after getting the web view content height size from webViewDidFinishLoad method, i am setting frame of my footer view. here is my code :
- (void)webViewDidFinishLoad:(UIWebView *)aWebView {
aWebView.scrollView.scrollEnabled = NO;
CGRect frame = aWebView.frame;
frame.size.height = 1;
aWebView.frame = frame;
CGSize fittingSize = [aWebView sizeThatFits:CGSizeZero];
frame.size = fittingSize;
aWebView.frame = frame;
[self setFooterView:fittingSize.height + aWebView.frame.origin.y];
}
-(void)setFooterView:(float)fittingHeight
{
bottomView.frame = CGRectMake(0, 0, 320, fittingHeight);
webViewSocial.frame = bottomView.frame;
[tableView reloadData];
}
But when i am scrolling my table view, then my UIWebView (footer view) is not scrolling completely. Can you please tell me how can i achieve my output. Thanks!
try to set like this
- (void)webViewDidFinishLoad:(UIWebView *)aWebView {
CGFloat height = [[self.webView stringByEvaluatingJavaScriptFromString:#"document.height"] floatValue];
CGFloat width = [[self.webView stringByEvaluatingJavaScriptFromString:#"document.width"] floatValue];
CGRect frame = self.webView.frame;
frame.size.height = height;
frame.size.width = width;
self.webView.frame = frame;
self.tableView.tableFooterView = webView;
}
My app takes in the contents of a UIWebView and generates a PDF of the web page. This works fine on smaller pages but when it reaches about 10 pages it crashes "Due to Memory Pressure". Also, this is an ARC app.
The predominant answer I have seen is to use UIGraphicsBeginPDFContextToFile instead of UIGraphicsBeginPDFContextToData and after changing to use File I still get a Memory Pressure crash. I don't understand why it's not clearing the pages from memory. I also added the #autoreleasepool { ... } in the loop as recommended in another question. Any ideas on what I am doing wrong here?
Here's the PDF creation code:
UIGraphicsBeginPDFContextToFile(dataFile, CGRectZero, nil);
for (int i = 0; i < pages; i++) {
#autoreleasepool {
NSLog(#"Creating Page %i", i);
// Check to see if page draws more than the height of the UIWebView
if ((i+1) * 720 > height) {
CGRect f = [_appWebView frame];
f.size.height -= (((i+1) * 720.0) - height);
[_appWebView setFrame: f];
}
UIGraphicsBeginPDFPage();
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(currentContext, 36, 36); // Translate for 0.5" margins
[[[_appWebView subviews] lastObject] setContentOffset:CGPointMake(0, 720 * i) animated:NO];
[_appWebView.layer renderInContext:currentContext];
}
}
UIGraphicsEndPDFContext();
Here's the full method if it helps any:
-(void) generatePDF {
startingFrame = _appWebView.frame;
// Memory warning seems to happen on almost every PDF, clear cache here to be proactive.
[[NSURLCache sharedURLCache] removeAllCachedResponses];
UIWebView *webView = [[UIWebView alloc] initWithFrame: CGRectMake(0, 0, 6.5 * 72, 9 * 72)];
[webView setDelegate: self];
// Adjust to letter size paper size in portrait mode
CGRect frame = _appWebView.frame;
frame.size.height = 10*72; // 11" - 1" Margins = 720px (72px / inch)
frame.size.width = 7.5*72; // 8.5 - 1" Margins = 612px (72px / inch)
_appWebView.frame = frame;
[_appWebView stringByEvaluatingJavaScriptFromString:#"window.scroll(0, 0);"];
// Get the height of our webView
NSString *heightStr = [_appWebView stringByEvaluatingJavaScriptFromString:#"document.body.scrollHeight;"];
int height = [heightStr intValue];
// Get the number of pages needed to print. 10 * 72 = 720
int pages = ceil(height / 720.0);
// File
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dataFile = [documentsDirectory stringByAppendingPathComponent:#"Configuration.pdf"];
NSLog(#"File: %#", dataFile);
UIGraphicsBeginPDFContextToFile(dataFile, CGRectZero, nil);
for (int i = 0; i < pages; i++) {
#autoreleasepool {
NSLog(#"Creating Page %i", i);
// Check to see if page draws more than the height of the UIWebView
if ((i+1) * 720 > height) {
CGRect f = [_appWebView frame];
f.size.height -= (((i+1) * 720.0) - height);
[_appWebView setFrame: f];
}
UIGraphicsBeginPDFPage();
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(currentContext, 36, 36); // Translate for 0.5" margins
[[[_appWebView subviews] lastObject] setContentOffset:CGPointMake(0, 720 * i) animated:NO];
[_appWebView.layer renderInContext:currentContext];
}
}
UIGraphicsEndPDFContext();
// Adjust to original size
_appWebView.frame = startingFrame;
}
I don't know of a reason you are getting the memory error, but I had a similar issue with searching of PDF's. Basically the OS was loading the entire PDF into memory, then searching, then removing the pdf even thought I was going page by page. My solution was to only do one page at a time, and that resolved the memory issue for me.
My code looks like this:
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
operationQueue.MaxConcurrentOperationCount = 1;
for(int i = 1; i <= totalPages; i++)
{
// a block of operation
[operationQueue addOperationWithBlock: ^ {
}];
}