7

我尝试使用此方法从 UIWebView 捕获图像,但图像仅包含屏幕的可见区域。如何捕获 UIWebView 的全部内容,包括不可见区域,即整个网页到一个图像中?

-(UIImage*)captureScreen:(UIView*) viewToCapture{
  UIGraphicsBeginImageContext(viewToCapture.bounds.size);
  [viewToCapture.layer renderInContext:UIGraphicsGetCurrentContext()];
  UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();
  return viewImage;
}
4

3 回答 3

6

检查这一点将 UIWebView 渲染到 ImageContext中

或者只是使用这个:):

    (UIImage*) imageFromWebview:(UIWebView*) webview{

//store the original framesize to put it back after the snapshot
CGRect originalFrame = webview.frame;

//get the width and height of webpage using js (you might need to use another call, this doesn't work always)
int webViewHeight = [[webview stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight;"] integerValue];
int webViewWidth = [[webview stringByEvaluatingJavaScriptFromString:@"document.body.scrollWidth;"] integerValue];

//set the webview's frames to match the size of the page
[webview setFrame:CGRectMake(0, 0, webViewWidth, webViewHeight)];

//make the snapshot
UIGraphicsBeginImageContextWithOptions(webview.frame.size, false, 0.0);
[webview.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

//set the webview's frame to the original size
[webview setFrame:originalFrame];

//and VOILA :)
return image;
}
于 2014-02-19T16:07:19.297 回答
4

编辑(来自Vad的评论)

解决方案是打电话

webView.scalesPageToFit = YES;

在初始化中,和

[webView sizeToFit]

当页面完成加载时。

您当前仅捕获可见部分,因为您将图像上下文限制为可见部分。您应该将其限制在可用的范围内。

UIView有一个scrollView属性 has contentSize,告诉你滚动视图中的 web 视图的大小。您可以使用该大小来设置图像上下文,如下所示:

-(UIImage*)captureScreen:(UIView*) viewToCapture{
    CGSize overallSize = overallSize;
    UIGraphicsBeginImageContext(viewToCapture.scrollView.contentSize);
    // Save the current bounds
    CGRect tmp = viewToCapture.bounds;
    viewToCapture.bounds = CGRectMake(0, 0, overallSize.width, overallSize.height);
    // Wait for the view to finish loading.
    // This is not very nice, but it should work. A better approach would be
    // to use a delegate, and run the capturing on the did finish load event.
    while (viewToCapture.loading) {
         [NSThread sleepForTimeInterval:0.1];
    }
    [viewToCapture.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    // Restore the bounds
    viewToCapture.bounds = tmp;
    return viewImage;
}
于 2012-08-20T15:31:30.270 回答
1

编辑:我用经过测试的代码给出的新答案。

在下面添加method到. 它也将捕获。capture UIWebViewUIImageunvisible area

- (UIImage*)webviewToImage:(UIWebView*)webView
{
  int currentWebViewHeight = webView.scrollView.contentSize.height;
  int scrollByY = webView.frame.size.height;

  [webView.scrollView setContentOffset:CGPointMake(0, 0)];

  NSMutableArray* images = [[NSMutableArray alloc] init];

  CGRect screenRect = webView.frame;

  int pages = currentWebViewHeight/scrollByY;
  if (currentWebViewHeight%scrollByY > 0) {
      pages ++;
  } 

  for (int i = 0; i< pages; i++)
  {
    if (i == pages-1) {
        if (pages>1)
            screenRect.size.height = currentWebViewHeight - scrollByY;
    }

    if (IS_RETINA)
        UIGraphicsBeginImageContextWithOptions(screenRect.size, NO, 0);
    else
        UIGraphicsBeginImageContext( screenRect.size );
    if ([webView.layer respondsToSelector:@selector(setContentsScale:)]) {
        webView.layer.contentsScale = [[UIScreen mainScreen] scale];
    }
    //UIGraphicsBeginImageContext(screenRect.size);
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    [[UIColor blackColor] set];
    CGContextFillRect(ctx, screenRect);

    [webView.layer renderInContext:ctx];

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    if (i == 0)
    {
        scrollByY = webView.frame.size.height;
    }
    else
    {
        scrollByY += webView.frame.size.height;
    }
    [webView.scrollView setContentOffset:CGPointMake(0, scrollByY)];
    [images addObject:newImage];
  }

  [webView.scrollView setContentOffset:CGPointMake(0, 0)];

  UIImage *resultImage;

  if(images.count > 1) {
    //join all images together..
    CGSize size;
    for(int i=0;i<images.count;i++) {

        size.width = MAX(size.width, ((UIImage*)[images objectAtIndex:i]).size.width );
        size.height += ((UIImage*)[images objectAtIndex:i]).size.height;
    }

    if (IS_RETINA)
        UIGraphicsBeginImageContextWithOptions(size, NO, 0);
    else
        UIGraphicsBeginImageContext(size);
    if ([webView.layer respondsToSelector:@selector(setContentsScale:)]) {
        webView.layer.contentsScale = [[UIScreen mainScreen] scale];
    }
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    [[UIColor blackColor] set];
    CGContextFillRect(ctx, screenRect);

    int y=0;
    for(int i=0;i<images.count;i++) {

        UIImage* img = [images objectAtIndex:i];
        [img drawAtPoint:CGPointMake(0,y)];
        y += img.size.height;
    }

    resultImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
  } else {

    resultImage = [images objectAtIndex:0];
  }
  [images removeAllObjects];
  return resultImage;
}

还添加这些macro以检查iOS是否retina显示

#define IS_RETINA ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)] && ([UIScreen mainScreen].scale == 2.0))
于 2012-08-20T15:31:49.647 回答