I have a set of local HTML pages that I would like batch generate thumbnails for on the fly (I only want to show the thumbnails, not the full web pages). This is the way I'm accomplishing this:
NSString* path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:link];
NSURL* url = [NSURL fileURLWithPath:path];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
UIWebView* webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 725, 1004)];
webView.delegate = cell;
[webView loadRequest:request];
[self.view addSubview:webView]; // doesn't work without this line, but then the UIWebView is onscreen
Then in the delegate:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
[self performSelector: #selector(render:) withObject: webView afterDelay: 0.01f];
}
- (void) render: (id) obj
{
UIWebView* webView = (UIWebView*) obj;
CGSize thumbsize = CGSizeMake(96,72);
UIGraphicsBeginImageContext(thumbsize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGFloat scalingFactor = thumbsize.width/webView.frame.size.width;
CGContextScaleCTM(context, scalingFactor,scalingFactor);
[webView.layer renderInContext: context];
UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.thumbnail.image = resultImage;
}
Here are my questions:
1) Is my general approach correct? Is this the most efficient way to batch process thumbnails of webpages on the fly?
2) I want to be able to render the thumbnail from an offscreen UIWebView, but the webViewDidFinishLoad: doesn't get called unless I add the UIWebView to the view hierarchy. Is there a way I can avoid this?
3) If I attempt to capture an image of the UIWebView in webViewDidFinishLoad:, I get a blank image. I have to put an artificial delay for the capture to work. Any way around this?
Thanks!
1) This seems to be the only way I know of to do this, without relying on a third party server-based API (if one exists)
2) You can draw the UIWebView off-screen by setting its frame to a position that is off-screen. For example 320,568,725,1008. I haven't tested it, but you should even be able to set the view as a 1 x 1px frame.
3) I imagine this is because when webViewDidFinishLoad: is called, a SetNeedsDisplay() has been called on the web view, but the web view has not yet redrawn itself. I'm not sure about a way around this.
Related
I am trying to view the web-page in UIWebView in iOS. Below is the link I am trying to view.
http://almaktab.com/forms/flight.html
The problem is width of table is 255px and when I open this in webview, it covers only half screen which looks odd. Below is the code I am using for viewing web page in UIWebView.
-(void)openWebPage:(NSString*)address {
NSURL*url=[NSURL URLWithString:address];
NSURLRequest*request=[NSURLRequest requestWithURL:url];
myWebView.scalesPageToFit = YES;
myWebView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
myWebView.contentMode = UIViewContentModeScaleAspectFit;
myWebView.autoresizesSubviews = YES;
[myWebView loadRequest:request];
[myWebView setAutoresizingMask:(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth)];
}
I want to stretch this webview so that form can fit for whole page.
I know solution for this would be width=100%, but client don't want to do any changes in their website now. Client asked to do changes in iOS only.
Any idea how this can be get done.
Screenshot (myWebView.scalesPageToFit = YES;)
Screenshot (myWebView.scalesPageToFit = NO;)
Try:
webView.scalesPageToFit = NO;
And in webViewDidFinishLoad:
[view stringByEvaluatingJavaScriptFromString:#"document.getElementById('table3').width='100%'"];
You should have not use AutoresizingMask.
I tried every permutation known to mankind and I cannot get a UIWebView to size properly in a modal form view for the iPad. The web page still displays the full iPad portrait width of 768 points.
Where and how do I tell UIWebView to display width 540 points?
I thought 'scalesPageToFit' is supposed to do this but it does not work.
I tried setting the web view to the size of form view which is 540 x 576 with navigation and status bar. Height is irrelevant though.
I tried adding a UIWebView to a UIView in a storyboard with all resizing set. I then removed the UIWebView and added it programmatically.
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect aFrame = self.view.frame;
if (IS_IPAD)
{
aFrame = CGRectMake(0, 0, FORM_VIEW_WIDTH, FORM_VIEW_HEIGHT);
}
_webView = [[UIWebView alloc] initWithFrame:aFrame];
[_webView setOpaque:NO];
[_webView setDelegate:self];
[_webView setScalesPageToFit:YES];
self.view = _webView;
...
}
I also tried loading in viewDidAppear (in addition to viewDidLoad, viewWillAppear, etc.)
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[[self webView] setFrame:CGRectMake(0, 0, FORM_VIEW_WIDTH, FORM_VIEW_HEIGHT)];
[[self webView] setScalesPageToFit:YES];
NSURL *webURL = [NSURL URLWithString:#"http://www.google.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:webURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0f];
[[self webView] loadRequest:request];
}
Any recommendations appreciated.
This keeps happening to me. I post a lengthy question, then two seconds later I find the answer.
Anyway, someone posted a solution to this problem here:
UIWebView -- load external website, programmatically set initial zoom scale, and allow user to zoom afterwards
However, I altered the script to set the width to the iPad width:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString* js =
#"var meta = document.createElement('meta'); "
#"meta.setAttribute( 'name', 'viewport' ); "
#"meta.setAttribute( 'content', 'width = 540px, initial-scale = 1.0, user-scalable = yes' ); "
#"document.getElementsByTagName('head')[0].appendChild(meta)";
[[self webView] stringByEvaluatingJavaScriptFromString: js];
}
Note the portion 'width = 540px, initial-scale = 1.0, user-scalable = yes'
I changed the width to the form width and scale to 1.0.
I also need to handle iPhone, and so I will make adjustments for that next. I think this fix may only be needed for the iPad form view.
UPDATE: Answer is short-lived. If I load any other page the sizing is thrown off again. Back to square one.
SOLUTION: This view will only need to access a few web pages that I developed. Therefore, I updated the few web pages that I need to access by adding the meta tag to each of them. I only need to access these pages and so this is the solution I plan to go with. This means I need to set the viewport width to 540px only for iPad somehow. I will figure that out next.
<meta name="viewport" content="width:540, initial-scale=1, maximum-scale=1">
This piece of code dispalys a document in a scrollable UIWebView:
- (void)viewDidLoad
{
[super viewDidLoad];
_myWebView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 760)];
NSURL *myUrl = [NSURL URLWithString:#"http://pathToDoc/myDoc.doc"];
NSURLRequest *myRequest = [NSURLRequest requestWithURL:myUrl];
[_myWebView loadRequest:myRequest];
[self.view addSubview:_myWebView];
}
This works fine except when trying to display a landscape document which has been created with custom margins which are smaller than standard.
The result is the contents of the right-hand edge of the document are chopped off.
Is there any way to display the whole document?
Well, after several months of frustration with this (can barely believe how long it took!), it turned out to need only a single line of code to solve the problem.
_documentWebView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
Add that just after the last line and suddenly all is well in the world.
I'm trying to generate thumbnails of several pages that will be displayed through a UIWebView. The problem is all of the images come out as gray or as the background color I set for the UIWebView. Could it be that I am not allowing the web view enough time to load the page?
I believe I want to do the following:
Create a UIWebView that is not visible on the screen
Setup graphics context
For each page:
Call loadRequest on the web view
Render web view in graphics context
capture screenshot
End graphic context
Here is the code I have for a single image:
UIWebView *screenWebView = _screenshotWebView;
UIView *screenView = _screenshotView;
if ([UIScreen instancesRespondToSelector:#selector(scale)] && [[UIScreen mainScreen] scale] == 2.0f) {
UIGraphicsBeginImageContextWithOptions(screenView.bounds.size, NO, 2.0f);
} else {
UIGraphicsBeginImageContext(screenView.bounds.size);
}
[screenWebView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:path ofType:#"html"]isDirectory:NO]]];
[screenView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
I defined _screenshotWebView and _screenshotView within a XIB file because I thought I may not have been initializing them correctly.
Any thoughts? Thanks!
Edit: Here is some code that implements this functionality in case someone else needs it: https://github.com/rmcl/webview_screenshot
As you theorized, there isn't time for the UIWebView to load the page. That method will asynchronously start the page load; the UIWebView probably won't get a chance to do any work until you've returned to the run loop.
Try implementing webViewDidFinishLoad: and do your rendering after it has completed.
I'm creating ipad application. It has just 2 views.
One view has few buttons. On click of a button it will open another view. This view has a webview which shows PDF file. I'm using the following code to show the PDF
- (void)viewDidLoad {
[super viewDidLoad];
NSString* path = [[NSBundle mainBundle] pathForResource:#"mypdf" ofType:#"pdf"];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]]];
}
Now the problem is that, when I change the orientation, whole view is rotating, but the pdf is being disturbed and not rendering properly. how can I avoid this?
As the PDF is having 250 pages, reloading the whole PDF on willRotateToInterfaceOrientation and didRotateFromInterfaceOrientation will delay the display.
How to avoid this situation.
There has to be a way a better to avoid/fix this, for now i just read the y scroll position with:
int scrollPosition = [[webView stringByEvaluatingJavaScriptFromString:#"window.pageYOffset"] intValue];
Then reloaded the document in:
(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation;
and then set the scroll position again with:
[webView stringByEvaluatingJavaScriptFromString: [NSString stringWithFormat:#"scrollTo(0,%d)",scrollPosition];