I am struck with this past two days i don't find any proper documents relating to CGPDF. I tried every possible way but i failed. Here is what i am trying to do. I have a PDF to display and i am displaying it in a UIWebView. I have created a CORE GRAPHICS PDF document reference using the path where the pdf is located (NSURL). I created a UIView over it and handled a single touch event. When the PDF loads and user clicks the view i want the page to scroll to a specific page. I know this can be done via calculating Page height and width. I wanted to know if there is a Way in CGPDF to pass a page number and it scroll to the relevant page. Below is my Code
- (void)viewDidLoad
{
[super viewDidLoad];
// set the pdfPafeHeight to -1 so it gets calculated.
self.pdfPageHeight = -1;
// set the delegate of the UIWebView's underlying UIScrollView to self.
self.webView.scrollView.delegate = self;
// create an NSURLRequest to load the PDF file included with the project
_filePath = [[NSBundle mainBundle] pathForResource:#"Sample" ofType:#"pdf"];
_url = [NSURL fileURLWithPath:_filePath isDirectory:NO];
_urlRequest = [NSURLRequest requestWithURL:_url];
// create a Core Graphics PDF Document ref using the same NSURL
_pdf = CGPDFDocumentCreateWithURL((CFURLRef) _url);
// use CGPDFDocumentGetNumberOfPages to get the number of pages in the document
self.pdfPageCount = (int)CGPDFDocumentGetNumberOfPages(_pdf);
// load the PDF file into the UIWebVie
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleFingerTap];
[self.webView loadRequest:_urlRequest];
}
HERE IS HOW I WANTED HANDLE SINGLE TAP ON UIVIEW. I just wanted to know if there is any method in CGPDF to scroll to specific page when i pass a page number to it
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
}
There's no API for what you're trying to achieve, and even if you're able to use private API if this app is just for Enterprise install and doesn't need to go to the App Store - this will be tricky and any workaround will likely break with a major iOS version update. If you want to go this route, you can introspect the view controller hierarchy and will find that Apple internally has a framework called CorePDF which has an internal private API that you might be able to access - but be careful and know that this is not a solution for App Store apps.
The alternative is to start from scratch and use CGContextDrawPDFPage to draw PDF pages, building your own cache, scroll views and view controllers+gesture handling. We did that with the commercial PSPDFKit SDK which I work on since 2010 - it's more work than you'd think. We also eventually moved on and use a custom renderer to improve compatibility with the wide range of PDF files available and to offer a better performance than Apple's renderer, however not every use case might require this.
Related
I need to download a file from api like
http://52.76.226.179/aapc-social-web/sites/default/files/media_docs/2009/content-601938936.ppt
and display a preview of that in my ios app.
Please help.
I have used the quick look framework and UIDocumentInteractionController show me something like this. please see the image and suggest something.
import this pkg
#import <QuickLook/QuickLook.h>
Use this code in View controller.
QLPreviewController *previewController=[[QLPreviewController alloc]init];
previewController.delegate=self;
previewController.dataSource=self;
previewController.view.frame = self.conditionsofUseView.bounds;
[self.conditionsofUseView addSubview:previewController.view];
[self addChildViewController:previewController];
[previewController didMoveToParentViewController:self];
[previewController.navigationItem setRightBarButtonItem:nil];
Add These Delegate methodes
- (NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller
{
return 1;
}
- (id <QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index
{
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"docFileName" ofType:#"file type"]; //doc,ppt,pdf etc
return [NSURL fileURLWithPath:filePath];
}
[UIDocumentInteractionController][1] Is what you are looking for.
The main difference respect QLPreviewController, is that it can display a preview and also it can display a UiActionSheet or popover showing the applications compatible with that format and delegate the display of the document to them.
It's super easy to use it. Check here
.
If you just want to view the Office files, have a look at:
Document Interaction Programming Topics for iOS: Quick Look Framework.
Quick Look Framework Reference
Quick Look Framework supports a lot of file formats as you can see in the links above. It is available in iOS 4.0 and later.
You can also use UIWebView to display them. See Using UIWebView to display select document types.
I am new to iOS app development and I just tried using UIWebView to display a mobile website in my app and was not quite successful.
What I did is just some minimal Xcode project configuration and coding that I found during some Googling efforts:
Create a new iOS application project in Xcode using the Single View
Application template.
Drag a Web View from the Object Library to the View Controller
scene of Main.storyboard.
While holding down the Control key, drag the Web View from the View
Controller scene to the ViewController.h editor, resulting a
source code line like this:
#property (weak, nonatomic) IBOutlet UIWebView *myWebView;
Add the following code in ViewController.m:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSURL *url = [NSURL URLWithString:#"http://www.amazon.com"];
[self.myWebView loadRequest:[NSURLRequest requestWithURL:url]];
}
This is all what I did (and also everything those tutorials told me). After I built and ran the app (on simulator and on real iphone device), the site did load in the app's view (and did load the mobile version instead of the PC version), but it displayed the site as if the view were much larger than the actual iphone screen. Here is a screeshot (Amazon in this case but basically the same for other sites):
What should I do to make the iOS UIWebView display a mobile website correctly?
Just tried Dipen Chudasama's suggestion of disabling the "User Size Classes" option, for the first time of all those suggestions, the result did change a little bit (from left-align to sort of center-align), but still not what I am looking for. Here is the screenshot:
EDIT:
Thanks for all the suggestions given by you enthusiastic people. Loading a site like amazon.com in a UIWebView should be a rather easy task as I understand, nevertheless, I didn't succeed with any of the suggestions.
It would be great if anyone could share with me (via Github or alike) just an sample xcode project (starting from scratch with the latest version of xcode tool chain) with nothing but a UIWebView that could load amazon.com correctly. That way I can do a line by line diff and may be able to find what I did wrong in my own project.
The UIWebView has a property called "scalesPageToFit":
self.myWebView.scalesPageToFit = YES;
self.myWebView.contentMode = UIViewContentModeScaleAspectFit;
should do the trick.
You can scale the page to fit the screen width with this UIWebview property webView.scalesPageToFit = YES;
Otherwise you can run a js command in the UIWebView to do the scale:
NSString *js = [NSString stringWithFormat:#"document.body.style.zoom = 0.8;"];
[webView stringByEvaluatingJavaScriptFromString:js];
I got it..you just set iPhone size view in storyboard instead of any size, means disable Use Size Classes Check box and see, this will work..:)
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:#"http://www.amazon.com"];
[self.myWebView loadRequest:[NSURLRequest requestWithURL:url]];
}
Thats it, Try this one only.
OR
you have to set appropriate constraint for this.
I had the same issue as you #goodbyeera, and then realized I hadn't set the AutoLayout constraints on the UIWebView. Therefore, when the WebView loaded it was too big for the iphone screen. By adding the constraints to fit the UIWebView to the screen fixed it all. Hope this might help you.
I want to allow a user to associate a zoom factor with a document and use it as a starting point when displaying that document inside a UIWebView. It seems, however, that webViewDidFinishLoad: only indicates the end of in-memory loading, not including rendering or layout. Here's sample code to demonstrate the problem:
- (void)viewDidLoad {
[super viewDidLoad];
UIWebView *webView = (UIWebView *)self.view;
webView.delegate = self;
webView.scalesPageToFit = YES;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSString *urlString = [[NSBundle mainBundle] pathForResource:#"Doc" ofType:#"pdf"];
NSURL *file = [NSURL fileURLWithPath:urlString];
[(UIWebView *)self.view loadRequest:[NSURLRequest requestWithURL:file]];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if (!webView.isLoading) {
[webView.scrollView setZoomScale:1.5 animated:YES];
}
}
The call to setZoomScale: executes with no effect (i.e. the file is displayed with a zoom factor of 1.0), apparently because it happens before the scroll view is in some state where it can deal with it. If I change the final method above to what follows, everything works as I'd hoped.
- (void)delayedZoomMethod {
[((UIWebView *)self.view).scrollView setZoomScale:1.5 animated:YES];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[self performSelector:#selector(delayedZoomMethod) withObject:nil afterDelay:1.0];
}
This, of course, is a bad idea because the 1.0 delay is arbitrary, probably too long for the vast majority of cases, and will likely be too short under some unknown set of conditions.
The docs say, "Your application can access the scroll view if it wants to customize the scrolling behavior of the web view." Does anyone know of a notification, or property in the web view or its scroll view, that I could observe to be told when that statement becomes true?
If you have control of the html code this may help. I've been able to have html events trigger objC methods in the following manner.
html event triggers javascript that writes a string to window.location
the uiwebview then uses uiwebviewdelegate to receive the string with this function
webView:shouldStartLoadWithRequest:navigationType:
It's kind of hacky.
But I don't think there is a way to know the web view has finished rendering, unless you wrote the html page and can put a js function in to execute at the end of the page.
If you are using UIWebView to preview PDF files, then it may not be the best way. There is a QLPreViewController (from iOS 4.0) that is intended for this purpose. A Quick Look preview controller can display previews for the following items:
iWork documents
Microsoft Office documents (Office ‘97 and newer)
Rich Text Format (RTF) documents
PDF files
Images
Text files whose uniform type identifier (UTI) conforms to the
public.text type (see Uniform Type Identifiers Reference)
Comma-separated value (csv) files
If I change the final method above to what follows, everything works
as I'd hoped.
This, of course, is a bad idea because the 1.0 delay is arbitrary,
probably too long for the vast majority of cases, and will likely be
too short under some unknown set of conditions.
The docs say, "Your application can access the scroll view if it wants
to customize the scrolling behavior of the web view."
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if (!webView.isLoading) //WEBDIDFINISHLOAD? {
[webView.scrollView setZoomScale:1.5 animated:YES];
}
}
look, the didFinishLoadMethod is called by an asynchronous notification from NSURLConnection,
its not necessarily in the main thread (since your UI update is not working)
The performSelector..after delay method is fine. The delay doesnt even really mean anything,
You are just jumping to the main thread to do your UI update and allowing the
NSURLConnection notification to complete.
It probably wouldnt matter if you said afterDelay:0.0
This is a common situation in iOS and OSX, you have to figure out what threads are capable of updating the UI, GCD, NSOperationQueues, and background runLoops on created threads all complicate this.
You found your solution, but you need to know what it means. Do the call to performSelector on mainThread, set a short delay and its fixed.
We can use the following to calculate the scrollWidth of an HTML page in a UIWebView with a fixed height.
[webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.scrollWidth"]
Is it possible to do this evaluation on local HTML pages without loading a request into a UIWebView?
Would like this to occur on a separate thread.
No(sort of). The html would need to be rendered in some capacity to be able to get any kind of measurements. The reason for this is inherent in the way html/css/javascript work together (javascript modifies html/css properties, css modifies html). If you had to get the width without using a UIWebView, you would be stuck with one of two options:
Render the page yourself, whether it's with your custom code (thousands of man hours, don't do this) or some open source library. I doubt this will be any faster than UIWebView, and will likely introduce unexpected bugs.
Measure the page in the background, and store that value somewhere. This would basically be a form of caching for the size. If the pages are static from when you ship, just do it manually, and hard code it. If they are dynamic, write a class to measure them on startup and store the value. The dynamic measurement would require UIWebView
EDIT:
Are you trying to do this because UIWebView is blocking you're main thread, causing jerkiness in your app? If so, have you considered trying something like this?:
UIWebView *webview = [[UIWebView alloc] initWithFrame:CGRectMake(0,0,320,460)];
webview.delegate = self;
[webview loadRequest: [NSURLRequest requestWithURL:[NSURL urlFromString:#"/path/to/file.html"]]];
... and then later on...
- (void) webViewDidFinishLoad:(UIWebView *)webView
{
// run your code to get scroll width of page
}
I have an UImageView and on click of an button i want to change the UImage in the UImageView. App has 22 UImages with each image exceeding 5 mb size , so the UImageView takes some time to load an image when the button is clicked , is there a way by which we can load these images into the memory so that image view takes lesser time to show the image?
I use the following code to set the image :
[ImageView setImage:[UIImage imageNamed:#"ImageName.jpg"]];
basically i want on swipe the images to be changed , e.g. if a user swipes from right to left the app must show the next image and on left to right click the back image be loaded . please suggest .
like #Gobot mentioned it is the best way du reduce the size of your pictures. For the swipe there is no need to use big pictures like this. You could just create two folders, one with small sized pictures and another with bigger one. If you swipe through, you just use the small pictures. If a user taps a picture you could get the name of the selected UIImage and load just this single picture. That way you also can provide high quality pictures for zooming in. And keep in mind, that your app package gets also bigger the more pictures you have included.
There is a good explanation in a WWDC Stream: iOS App Performance: Graphics and Animations
I also created a method inside a NSMutableArray category for loading all my UIImages once. You could use this method inside viewDidLoad:
- (NSMutableArray *)getImagesWithStartSuffix:(NSString *)start
andEndSuffix:(NSString *)end{
NSMutableArray *imageArray = [[NSMutableArray alloc] init];
for (int i = 1; i < 100 + 2; i++) {
NSString *fileName = [NSString stringWithFormat:#"%#%d%#.jpg",
start, i, end];
if([self fileExistsInProject:fileName]){
[imageArray addObject:[UIImage imageNamed:fileName]];
} else {
break;
}
}
return imageArray;
}
There is also a very easy way to change the size of your pictures by writing an Apple Script. You could run a loop over all pictures and resize them all this way. This is the easiest way and you don't have to use any tools like Gimp or PS:
do shell script "sips [path_to_file]/picture1.jpg -z 666 1000 --out [path]/changedSize/picture1_small.jpg"
From the Documentation:
This method looks in the system caches for an image object with the specified name and returns that object if it exists. If a matching image object is not already in the cache, this method loads the image data from the specified file, caches it, and then returns the resulting object.
if it takes too long, you may want to add a progress indicator in your app till the full view is generated/loaded then display it on your screen.
The first and simplest option would be to reduce your images under 5MB. Do they really need to be that big? Are they thumbnails? The more complex option would be to load/cache images in a background thread (asynchronously) using dispatch queues.