如何从UIWebView获取整个图像,包括屏幕外的内容

3

我有一个方法用于从我的iOS应用程序中的各个视图中获取图像,以便让用户通过电子邮件发送屏幕。大多数绘制屏幕的屏幕都能正常工作,但是当我在UIWebView上使用此技术时,我只能获得屏幕的可见部分。屏幕外的任何内容都不包含在渲染的图像中。我在Stack上搜索了一番,但到目前为止还没有找到解决办法?!

这是我目前使用的方法:

-(NSData *)getImageFromView:(UIView *)view
{
    NSData *pngImg;
    CGFloat max, scale = 1.0;
    CGSize size = [view bounds].size;

    // Scale down larger images else we run into mem issues with mail widget
    max = (size.width > size.height) ? size.width : size.height;
    if( max > 960 )
        scale = 960/max;

    UIGraphicsBeginImageContextWithOptions( size, YES, scale );

    CGContextRef context = UIGraphicsGetCurrentContext();
    [view.layer renderInContext:context];    
    pngImg = UIImagePNGRepresentation( UIGraphicsGetImageFromCurrentImageContext() );

    UIGraphicsEndImageContext();    
    return pngImg;
}
4个回答

5

哇,答案非常简单...我在各种与打印/PDF相关的地方到处搜索...突然想到,为什么不将视图设置为适合大小的上下文。它有效了!

警告:不能保证您不会遇到内存问题,我建议您在@autoreleasepool池中执行此操作,并考虑像我在示例中那样进行一些缩放,但是这很有效,并且是我最终选择的方法:

-(NSData *)getImageFromView:(UIView *)view  // Mine is UIWebView but should work for any
{
    NSData *pngImg;
    CGFloat max, scale = 1.0;
    CGSize viewSize = [view bounds].size;

    // Get the size of the the FULL Content, not just the bit that is visible
    CGSize size = [view sizeThatFits:CGSizeZero];

    // Scale down if on iPad to something more reasonable
    max = (viewSize.width > viewSize.height) ? viewSize.width : viewSize.height;
    if( max > 960 )
        scale = 960/max;

    UIGraphicsBeginImageContextWithOptions( size, YES, scale );

    // Set the view to the FULL size of the content.
    [view setFrame: CGRectMake(0, 0, size.width, size.height)];

    CGContextRef context = UIGraphicsGetCurrentContext();
    [view.layer renderInContext:context];    
    pngImg = UIImagePNGRepresentation( UIGraphicsGetImageFromCurrentImageContext() );

    UIGraphicsEndImageContext();
    return pngImg;    // Voila an image of the ENTIRE CONTENT, not just visible bit
}

FYI - 处理大页面时这可能会很慢,但是可以在后台队列上进行渲染。(但是必须在主队列上执行帧操作。) - zekel

1

我之前创建了一个类别。 它仅在 Web 视图被缓存到内存中时才能正常工作,否则页面的某些部分将显示为白色。

#import "UIWebView+Screenshot.h"
#import <QuartzCore/QuartzCore.h>

@implementation UIWebView (Screenshot)

- (UIImage *)screenshot {
UIImage *img = nil;

    UIGraphicsBeginImageContextWithOptions(self.scrollView.contentSize, self.scrollView.opaque, 0.0);
    {
        CGPoint savedContentOffset = self.scrollView.contentOffset;
        CGRect savedFrame = self.scrollView.frame;

        self.scrollView.contentOffset = CGPointZero;
        self.scrollView.frame = CGRectMake(0, 0, self.scrollView.contentSize.width, self.scrollView.contentSize.height);
        [self.scrollView.layer renderInContext: UIGraphicsGetCurrentContext()];
        img = UIGraphicsGetImageFromCurrentImageContext();

        self.scrollView.contentOffset = savedContentOffset;
        self.scrollView.frame = savedFrame;
    }
    UIGraphicsEndImageContext();

    return img;
}

@end

0

您可以将UIWebView缩小,以便所有内容都适合屏幕...但是,如果图像在水平方向上不在屏幕之外,则此方法将无效。如果UIWebView比屏幕更长,则这样做并没有太大作用。

[webview.scrollView setZoomScale:webview.scrollView.minimumZoomScale animated:NO];

谢谢,但不幸的是我的大部分内容都是竖向的。 - Cliff Ribaudo

0

现在,WKWebView有更方便的方法来完成它

将此代理分配给webview的导航代理,并实现完成处理程序以获取图像返回

class WebviewDelegate: NSObject, WKNavigationDelegate {

    var completion: ((UIImage?) -> ())?

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        webView.evaluateJavaScript("document.body.offsetHeight;") { (result, error) in
            if let height = result as? CGFloat {
                let config = WKSnapshotConfiguration()
                config.rect = CGRect(x: 0, y: 0, width: webView.scrollView.contentSize.width, height: height)

                webView.takeSnapshot(with: config) { (image, error) in
                    self.completion?(image)
                }
            }
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接