I'm using a UIWebView
. I call a web service to get the content for that. In web service response I get HTML string as below:
<div style='text-align: center;'> <div style=' display: inline-block; width: 120px;height: 120px; text-align:center; '; ><img src='http://assetdetailsdemo.azurewebsites.net/QRUpload/4774.jpg' style='height:100px; width:100px' /><br /><div>4774</div></div> <br /><br /></div>
This is just an example. I may get 'n' number of above kind of 'div' tags which may have images 1 in each. I have load this in UIWebView
using:
[_webView loadHTMLString:_HTMLStr baseURL:[[NSBundle mainBundle] bundleURL]];
where _HTMLStr
contains above HTML string.
My main issue is I have a requirement to get hole content of UIWebView
and need to generate an image. I have already tried below code to get the image:
UIGraphicsBeginImageContext(_webView.bounds.size);
[_webView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
This method avail me to convert the content of UIWebView
to UIImage
. But, I want a pice of code which allow me to generate image only from the content of webview. Or we can say that I'm finding another method to get the image.
So I've experienced the same issue here. After a while struggling with it, I found out that:
loadHTMLString:baseURL:
Doesn't actually load the string. It'll perform lots of stuff then callback in the delegate webViewDidFinishLoad:(UIWebView *)webView
You'll have to keep the VC until it rendered the HTML. Otherwise, the VC will be disposed before the calling back delegate webViewDidFinishLoad:
. In my case, I use singleton object to retain it.
Solution:
- Create singleton object of the VC.
- Set webView.delegate = VC
- Implement the image rendering in
webViewDidFinishLoad:(UIWebView *)webView
- You can store a callback or a delegate or something to notify back that the webView has completely rendered.
EDIT:
Because loadHTML
doesn't actually load right away, but perform something (not sure what it does tho...) then callback when complete in webViewDidFinishLoad:(UIWebView *)webView
, therefore you'll need to wait until that method got called.
So, you declare webView
and callbackBlock
in your VC (or any object, depend on you):
@interface MyObject () <UIWebViewDelegate>
@property (strong, nonatomic) UIWebView *webView;
@property (strong, nonatomic) void(^callbackBlock)(UIImage *generatedImage);
@end
So when you call generateImageFromHTML:(NSString *)html callback:(callbackBlock)callback
, it'll wait until the image completely generated then callback.
You'll need something to retain the webView
and callbackBlock
. In my case, I just use singleton to keep it.
+ (instanceType)loadHTML:(NSSTring *)html callBack:(callbackBlock)callback {
static dispatch_once_t onceToken;
static MyObject *instance;
// Keep reference
dispatch_once(&onceToken, ^{
instance = [MyObject new];
instance.webView = [UIWebView new];
instance.webView.delegate = instance;
instance.webView.scalesPageToFit = YES;
});
// Perform load here
[instance.webView loadHTMLString:html baseURL: [[NSBundle mainBundle] bundleURL]];
// Wait until done
instance.callbackBlock = callback;
return instance;
}
Next is actual create the image from htmlContent image and return it:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
if (self.callbackBlock) {
self.callbackBlock([self imageFromWebView:webView]);
}
}
- (UIImage *)imageFromWebView:(UIWebView *)view
{
// Adjust the image size to fit webContent
// get the width and height of webpage using js (you might need to use another call, this doesn't work always)
// CGFloat contentWidth = [view stringByEvaluatingJavaScriptFromString:@"document.getElementsByClassName(\"content\")[0].offsetWidth"].floatValue;
// CGFloat contentHeight = [view stringByEvaluatingJavaScriptFromString:@"document.getElementsByClassName(\"content\")[0].offsetHeight"].floatValue;
CGSize documentSize = CGSizeMake(contentWidth, contentHeight);
view.frame = CGRectMake(0, 0, contentWidth, contentHeight);
//make the snapshot
UIGraphicsBeginImageContext(documentSize);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}