views:

68

answers:

3

I have a UIScrollView decendent that implements a takeScreenshot method that looks like this:

-(void)takeScreenshot {  
  CGRect contextRect  = CGRectMake(0, 0, 768, 1004);
  UIGraphicsBeginImageContext(contextRect.size);    
  [self.layer renderInContext:UIGraphicsGetCurrentContext()];
  UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();

  // do something with the viewImage here.
}

This basically moves to the top of the scroll view, and takes a screenshot of the visible area. It works fine when the iPad is oriented portrait, but when it's in landscape the bottom of the image is cut off (as the height of the visible area is only 748, not 1004).

Is it possible to get a snapshot of the UIScrollView, including areas not on screen? Or do I need to scroll the view down, take a second photo and stitch them together?

A: 

I don't know much but I can guess that if we set the size of the contextRect like this for landscape, it may work well:

  CGRect contextRect  = CGRectMake(0, 0, 1004, 768*2);

Because this contextRect will determine the size of the UIGraphicsBeginImageContext so I hope that double the height can solve your problem

vodkhang
It seems that it merely cuts off at the end of the visible area. Increasing the height doesn't help.
Tim Sullivan
+1  A: 

Here is code that works ...

- (IBAction) renderScrollViewToImage
{
    UIImage* image = nil;

    UIGraphicsBeginImageContext(_scrollView.contentSize);
    {
        CGPoint savedContentOffset = _scrollView.contentOffset;
        CGRect savedFrame = _scrollView.frame;

        _scrollView.contentOffset = CGPointZero;
        _scrollView.frame = CGRectMake(0, 0, _scrollView.contentSize.width, _scrollView.contentSize.height);

        [_scrollView.layer renderInContext: UIGraphicsGetCurrentContext()];     
        image = UIGraphicsGetImageFromCurrentImageContext();

        _scrollView.contentOffset = savedContentOffset;
        _scrollView.frame = savedFrame;
    }
    UIGraphicsEndImageContext();

    if (image != nil) {
        [UIImagePNGRepresentation(image) writeToFile: @"/tmp/test.png" atomically: YES];
        system("open /tmp/test.png");
    }
}

The last few lines simply write the image to /tmp/test.png and then opens it in Preview.app. This obviously only works on in the Simulator :-)

Complete project in the ScrollViewScreenShot Github Repository

St3fan
That seems to render each item on top of each other, so it doesn't look like the original display!
Tim Sullivan
Oh but then you are close! Just set a transform to move the origin for each view before you render it.
St3fan
@St3fan: I've spent hours trying to figure out how to do that without success. Can you give me any guidance?
Tim Sullivan
Give my new answer a try :-)
St3fan
You, sir, are my personal hero today.
Tim Sullivan
A: 

Why are you not making the new context rect the size of the scrollview contentSize? It got chopped off because you said to chop it off, by specifying too small a context rect to render into!

Kendall Helmstetter Gelner
It still cuts it off, and the image displays the visible portion only.
Tim Sullivan
Just to be clear, the image that is created is the proper size of the entire scrollview, but anything not actually visible on the screen is ignored, leaving a large white area. I'm doing 1004, since that's the maximum visible area I'd like to display: the visible height of the iPad.
Tim Sullivan