Σάββατο 20 Απριλίου 2013

How to save the whole content of a UIWebView in a UIImage

It took me several hours searching how to capture the whole content of a web page in a single UIImage, so I decided to publish my solution.

The problem:
UIWebView renders only the visible area, so the layer contains only whatever is visible. In case of web page that the web page continues beyond the visible area, then you cannot capture it at once.

The solution:
"Split" the UIWebView into visible parts.
Visible area is [window.innerWidth, window.innerHeight].
The size of the result image should be [document.body.scrollWidth, document.body.scrollHeight]
Each part should be equal to the visible area. So the number of parts is roundUp(window.innerWidth/document.body.scrollWidth) per row * roundUp(window.innerHeight/document.body.scrollHeight) per column
Move to each part using window.scrollTo(x,y) function.
Take screenshots and keep them in an array
Create an ImageContext with size [document.body.scrollWidth, document.body.scrollHeight]
Iterate your screenshots and place each one in the proper place. BE CAREFUL FOR THE LAST SCREENSHOT OF EACH ROW AND EACH COLUMN.

Sample code:
I assume that the width of the web page is equal to the width of the visible area


#import "UIWebView+Screenshot.h"

@implementation UIWebView (Screenshot)

- (UIImage *)screenshot {
    //Whole page size in HTML coordinate
    float width= [[self stringByEvaluatingJavaScriptFromString:@"document.body.scrollWidth"] floatValue];
    float height=[[self stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"] floatValue];

    float heightStep=[[self stringByEvaluatingJavaScriptFromString:@"window.innerHeight"] floatValue];

    uint steps=round((height/heightStep)+0.5);
    NSMutableArray* pieces=[[NSMutableArray alloc] initWithCapacity:steps];

    for(uint step=0;step
        [self stringByEvaluatingJavaScriptFromString: [NSString stringWithFormat:@"window.scrollTo(0,%.0f)", step*heightStep]];
        UIGraphicsBeginImageContextWithOptions(self.frame.size, self.scrollView.opaque, 0.0);
        {
            [self.layer renderInContext: UIGraphicsGetCurrentContext()];
      
            UIImage* img = UIGraphicsGetImageFromCurrentImageContext();
            [pieces insertObject:img atIndex:step];
        }
        UIGraphicsEndImageContext();
    }
    [self stringByEvaluatingJavaScriptFromString: [NSString stringWithFormat:@"window.scrollTo(0,0)"]];
    
    CGSize newSize = CGSizeMake(width, height); //size of image view
    UIGraphicsBeginImageContext( newSize );
        for(uint step=0;step
            UIImage* image=[pieces objectAtIndex:step];
            [image drawInRect:CGRectMake(0, (step+1==steps)? height-heightStep:step*heightStep, image.size.width, image.size.height)];
        }
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    [pieces release];
    return newImage;
}
@end

Κυριακή 3 Φεβρουαρίου 2013

Becoming an official employee@Pinnatta

Tomorrow will be my first day as a Pinnatta's employee and I am excited that I will officially join such a startup. It has been more than a year ago, since I started working for Gipht.me Inc. Gipht.me Inc is the company that develops Pinnatta.

Pinnatta is an innovative platform that lets you exchange interactive messages with your friends on mobile devices.






LinkWithin

Blog Widget by LinkWithin

Mobile edition