PDF in webview performance - iphone

I am using the following (simple) code to load a PDF from the documents folder in my app into a UIWebView. The performance is very poor. I tried loading the same PDF from the web via Safari and the performance was great. Does anyone have any ideas? (this viewController is being presented as a modalViewController).
- firstView.m
InfoViewController *mcontroller = [[InfoViewController alloc] init];
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *docsPath = [paths objectAtIndex:0];
NSString *pathToPDF = [NSString stringWithFormat:#"%#/myPDF.PDF",docsPath];
NSURL *targetURL = [NSURL fileURLWithPath:pathToPDF];
mcontroller.urlToFile = targetURL;
[self presentModalViewController:mcontroller animated:YES];
modalViewController.m -
- (void)viewDidLoad {
[super viewDidLoad];
NSURLRequest *request = [NSURLRequest requestWithURL:urlToFile];
[webView loadRequest:request];
}

I ended up using the documentInteractionController for this to display the PDF in Quick Look. There is a great tutorial for this in the 2010 WWDC vids.
No idea why it wasn't working well in webView, but it's smooth as silk in Quick Look.

The first thing I would look at is the PDF its self. Often people try loading huge PDF files and expect them to perform wonderfully. Can you post the PDF for us to see? How large is the file? Remember that the PDF file size is the compressed size, to display images in the PDF they will be uncompressed when stored in RAM. Its not uncommon for a 500KB image on disk to use 20 MB in memory (This applies for all raster graphics, not just PDFs). This is usually the case when PDF performance is poor from what I've seen around here.
I know you said it works great in Safari, however we don't know what all Apple does in Safari's internals vs a UIWebView. Also Safari is usually running in the background, so it is using memory even when your app is running. This reduces mem that you app can use, but when you are running safari as the foremost app, 3rd party apps aren't using much memory, so safari could potentially cache more of the PDF at a time.

Related

Loading PDF into UIWebView - Anything faster?

I'm doing an application, which loads PDFs from an URL, but is there anything better then using UIWebView? Or any way of loading it page-by-page instead of loading the whole file at once?
I mean it does the job, but it takes 30seconds - 3 minutes to load a PDF on an iPhone 5 while standing NEXT to the router...
I can't imagine what would happen when I ran this code on an iPhone 4 with crappy internet...
Code which does the loading:
CatalogsWebViewController *webViewController = [[CatalogsWebViewController alloc] initWithNibName:#"CatalogsWebView" bundle:nil];
NSString *urlString = [[NSString alloc] initWithFormat:#"http://%#.s3.amazonaws.com/%#",kAmazonAWSBucketName,[catalogs objectAtIndex:indexPath.row]];
NSLog(#"%#",urlString);
webViewController.pdfRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]];
[self.navigationController pushViewController:webViewController animated:YES];
//Here self is webViewController, which got pushed into the navigation controller.
[self.webView loadRequest:self.pdfRequest];
Hum... it turns out, it's not due to the webView, it's cause it takes an immense time to download the file from the S3 bucket. When loading it from [NSBundle mainBundle], it does it it seconds.
As the problem comes from network connectivity, you should display a loading bar while downloading the PDF so the user understands what is going on. Then, upon download completion, save the PDF in the documents folder of your app if the user wants to reopen it later

Open pdf with other apps

I am displaying a pdf file in an app. I want to show "open with" option on nag bar showing apps installed on iPhone that can open same pdf and if user selects any of the app (for e.g. pdf viewer) then the pdf should get open with pdf viewer app.
How do I do this?
Please help
Thanks in advance.
To open a file in an available application on the device, use the UIDocumentInteractionController class.
A document interaction controller, along with a delegate object, provides in-app support for managing user interactions with files in the local system. For example, an email program might use this class to allow the user to preview attachments and open them in other apps. Use this class to present an appropriate user interface for previewing, opening, copying, or printing a specified file.
There are a lot of questions around it on SO if you get stuck. search results for UIDocumentInteractionController
This code will present the OpenIn interaction you're looking for. It works for iPhone and iPad. On iPad its in a popover. I'm generating the PDF but if you're just using one you have you don't need to writeToFile, just hand in the filePath.
// In your header. MyViewController.h
#interface MyViewController : UIViewController <UIDocumentInteractionControllerDelegate>
{
UIDocumentInteractionController *docController;
}
// In your implementation. MyViewController.m Open Results is hooked up to a button.
- (void)openResults
{
// Generate PDF Data.
NSData *pdfData = [self makePDF];
// Create a filePath for the pdf.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"Report.pdf"];
// Save the PDF. UIDocumentInteractionController has to use a physical PDF, not just the data.
[pdfData writeToFile:filePath atomically:YES];
// Open the controller.
docController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]];
docController.delegate = self;
docController.UTI = #"com.adobe.pdf";
[docController presentOpenInMenuFromBarButtonItem:shareButton animated:YES];
}
You can check with Apple Default api of "UIDocumentInteractionController".
Below is url:
http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIDocumentInteractionController_class/Reference/Reference.html
Hope, it will resolve your issue.
Cheers.

Xcode UIWEBVIEW download , save HTML file and show

I want to download a page and show this in WEBVIEW local, but the images are missing. The images are only shown, when I'm online, in offline mode they are missing. How can I solve this? This is the code I used up until now:
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
NSURL *url = [NSURL URLWithString:#"http://livedemo00.template-help.com/wt_37587/index.html"];
//[WEBVIEW loadRequest:reqURL];
// Determile cache file path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [NSString stringWithFormat:#"%#/%#", [paths objectAtIndex:0],#"index.html"];
// Download and write to file
NSData *urlData = [NSData dataWithContentsOfURL:url];
[urlData writeToFile:filePath atomically:YES];
// Load file in UIWebView
[WEBVIEW loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:filePath]]];
[super viewDidLoad];
}
I've been meaning to write this up for a few weeks now, and this question finally got me to do it. See Drop-in offline caching for UIWebView (and NSURLProtocol).
The short answer, in my experience, is that the easiest solution is to use an NSURLProtocol to intercept NSURLConnection requests (including the ones made by UIWebView) and write the results to disk. If the request is made when you're offline, just read the response from disk and replay it. This is extremely transparent to the rest of the application, and avoids all kinds of edge-cases related to subclassing NSURLCache. (For more information on how to subclass NSURLCache see Substituting local data for remote UIWebView requests on Cocoa With Love, and AFCache.)
My NSURLProtocol approach is very simple, and is not a general-purpose caching solution. It's just intended to assist a UIWebView when you're offline. But for that, I think it solves the problem well.

How to show TXT or ASCII file into UIWebView correctly

I'm trying to show TXT file (ASCII) into UIVewView. For example, using the site www.partisani.net/35.txt in Safari on MacBook works fine, Safari on iPhone doesn't. Safari's iPhone shows the file with another layout. Could someone help me, please?
As far as I can tell, the layout of the file on the Mac vs iOS is exactly the same. Are you talking about text wrapping? You can see that on the Mac by resizing the browser.
If you want to handle the line length differently you'll need to do so by setting up scrolling.
UPDATE with more detail:
This "sort of" changes the original content :). Basically, you need to tweak both the contentSize of the webview and embed the text file in some boilerplate HTML to reflow the text rather than have the default viewport width assigned to the text document. The latter I accomplish with something like:
NSURL* url = [NSURL URLWithString:#"http://www.partisani.net/35.txt"];
UIWebView* vw = (UIWebView*)self.view;
vw.delegate = self;
NSData* Data = [NSData dataWithContentsOfURL:url];
NSString* aStr = [[NSString alloc] initWithData:Data encoding:NSASCIIStringEncoding];
NSString* responseStr = [NSString stringWithFormat:
#"<HTML>"
"<head>"
"<title>Text View</title>"
"</head>"
"<BODY>"
"<pre>"
"%#"
"/pre>"
"</BODY>"
"</HTML>",
aStr];
[vw loadHTMLString:responseStr baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];
[aStr release];
The vw.delegate = self is important, as you also need to have your controller conform to the UIWebViewDelegate protocol and implement the webViewDidFinishLoad: method. There you can set the scroll width and height of your webview as needed:
- (void) webViewDidFinishLoad:(UIWebView *)webview {
UIScrollView* sview = (UIScrollView*)[[webview subviews] objectAtIndex:0];
sview.contentSize = CGSizeMake(1000, 800);
}
This is an extremely barebones implementation--presumably you would also want logic to calculate the necessary width and height based upon the loaded text rather than use constants as shown here; you'll need some parsing logic associated with the original data for that, but this should get you started.
Setting the scalesPageToFit property to yes might fix your problem.
I'm not sure this is actually something to do with TXT or ASCII, but rather the UIWebview resizing the content.
The file you mentioned loaded into a landscape ipad screen has exactly the same layout as on Mac Safari:
You can change whether or not the UIWebView scales its content with the scalesPageToFit property.

Emailing full screen of iPhone app

I am developing an iPhone app for creating images using built in graphics and user defined text.
I want to be able to have my app, with built in graphics and user defined text, which can then be sent as a single image (much like a screenshot) to the email app to be emailed.
Is there a way to do this without taking a screenshot, leaving the app, going into the Photos app, selecting the screenshot, and emailing it from there?
Ultimately I would like to be able to have a button in my app that the user could tap, and the whole screen would be captured and sent directly to the mail app.
Any pointers gratefully accepted!
To expand upon Brent's answer, the following code will grab a screenshot and save it out to the Documents directory as a PNG called screenshot.png:
UIWindow *screenWindow = [[UIApplication sharedApplication] keyWindow];
UIGraphicsBeginImageContext(screenWindow.frame.size);
[screenWindow.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *screenshotPNG = UIImagePNGRepresentation(screenshot);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSError *error = nil;
[screenshotPNG writeToFile:[documentsDirectory stringByAppendingPathComponent:#"screenshot.png"] options:NSAtomicWrite error:&error];
This is a little crude, as it will leave a blank spot near the top of the screen for the title bar, and doesn't appear to grab the content from CAEAGLLayers.
Also, I don't believe you can use the standard mailto:// URL construction, followed by openURL, to send MIME-encoded attachments. Maybe the 3.0 SDK fixes this, but I've yet to play with it. You may need to use something like sksmtpmessage to send the message directly from within your application.
There's also the private API UIGetScreenImage. It is used like so:
CGImageRef UIGetScreenImage();
#interface UIImage (ScreenImage)
+ (UIImage *)imageWithScreenContents;
#end
#implementation UIImage (ScreenImage)
+ (UIImage *)imageWithScreenContents
{
CGImageRef cgScreen = UIGetScreenImage();
if (cgScreen) {
UIImage *result = [UIImage imageWithCGImage:cgScreen];
CGImageRelease(cgScreen);
return result;
}
return nil;
}
#end
This function may be combined with UIImagePNGRepresentation to produce a PNG.
Apple is now allowing applications to use the;
CGImageRef UIGetScreenImage(void);
function. Although you must remember that it returns a retained CGImageRef and you'll have to manage your memory accordingly.
They also say that, "...a future release of iPhone OS may provide a public API equivalent of this functionality. At such time, all applications using UIGetScreenImage() will be required to adopt the public API."
skpsmtpmessage is great. If fact, it's so good, I went and cloned it and added sample project on github. The sample GUI below adds a few bells and whistles, like a progress bar and some other goodies, but it basically maintains the core skpsmtpmessage code.
http://github.com/kailoa/iphone-smtp/tree/master
I have no idea if this will work, but you can try creating a bitmap-backed graphics context, then getting your root view's Core Animation layer and calling its -renderInContext: method. That might do it, but I've never tried it.
Perhaps, though, you should consider a different approach. Is it just that you've written a bunch of custom drawing code that's visible on screen and you want to be able to draw into a file or memory buffer too? If so, perhaps you should factor that drawing code out of your view and into a separate object that your view simply uses. That would allow you to very easily draw it both ways.
In OS 3.0, you can use MFMailComposeViewController:
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[picker addAttachmentData:screenshotPNG mimeType:#"image/png" fileName:#"PNGfromMyApp"];