【问题标题】:UIWebView to UIImageUIWebView 到 UIImage
【发布时间】:2012-08-15 22:54:24
【问题描述】:

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

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

【问题讨论】:

    标签: iphone objective-c xcode uiwebview


    【解决方案1】:

    看看Rendering a UIWebView into an 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;
    }
    

    【讨论】:

      【解决方案2】:

      编辑(来自Vad的评论)

      解决办法是调用

      webView.scalesPageToFit = YES;
      

      在初始化中,和

      [webView sizeToFit]
      

      当页面完成加载时。

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

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

      -(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;
      }
      

      【讨论】:

      • 这部分解决了问题。生成的图像大小正确,但不可见区域全是白色。
      • @Vad 我认为问题与viewToCapture.layer 有关。看看临时设置边界是否能解决问题(见更新)。
      • 我认为问题在于 Web 视图在您滚动之前不会显示所有内容。
      • @Vad 你是对的,当你调用renderInContext: 时,Web 视图可能仍在加载其他内容。你能添加NSLog(@"%d", viewToCapture.loading) 看看它打印的是1 还是0
      • 解决方案是在页面完成加载并且 webView.scalesPageToFit = YES 时调用 [webView sizeToFit];在初始化中。
      【解决方案3】:

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

      method下方添加captureUIWebViewUIImage。它还将捕获unvisible 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))
      

      【讨论】:

      • 这会导致图像上的可见内容被拉伸,而不可见内容仍然是全白/空白。
      • 我测试了一个很长的页面,但是当 if(images.count > 1) {~ UIGraphicsBeginImageContextWithOptions(size, NO, 0);由于内存压力。分割是个好主意,但我想在聚合图像时会产生内存压力。你有什么解决办法吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-16
      • 2011-07-25
      • 2011-05-26
      • 2010-10-25
      • 2011-07-16
      • 1970-01-01
      相关资源
      最近更新 更多