Get UIWebView content and convert it to image

2019-08-02 01:21发布

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.

1条回答
别忘想泡老子
2楼-- · 2019-08-02 01:46

So I've experienced the same issue here. After a while struggling with it, I found out that:

  1. loadHTMLString:baseURL: Doesn't actually load the string. It'll perform lots of stuff then callback in the delegate webViewDidFinishLoad:(UIWebView *)webView

  2. 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:

  1. Create singleton object of the VC.
  2. Set webView.delegate = VC
  3. Implement the image rendering in webViewDidFinishLoad:(UIWebView *)webView
  4. 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;
}
查看更多
登录 后发表回答