59 votes

Obtenir une capture d'écran d'un UIScrollView, y compris des parties hors écran

J'ai un UIScrollView decendent qui implémente un takeScreenshot méthode qui ressemble à ceci:

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

En fait cela se déplace vers le haut de défilement de la vue, et prend une capture d'écran de la zone visible. Il fonctionne très bien lorsque l'iPad est orientée vers le portrait, mais quand il est dans le paysage du bas de l'image est coupée (comme la hauteur de la zone visible est seulement 748, pas 1004).

Est-il possible d'obtenir un instantané de l'UIScrollView, y compris les zones qui ne sont pas sur l'écran? Ou ai-je besoin pour faire défiler l'affichage vers le bas, prendre une deuxième photo et de les coudre ensemble?

113voto

St3fan Points 16196

Voici le code qui fonctionne ...

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

Les dernières lignes écrivent simplement l'image dans /tmp/test.png, puis l'ouvrent dans Preview.app. Cela ne fonctionne évidemment que dans le simulateur :-)

Projet complet dans le référentiel ScrollViewScreenShot Github

2voto

Adam Points 407

Voici une autre manière de faire, qui prend le niveau de zoom en compte. J'ai un scrollview avec 4 différents UIImageView couches en elle, et je veux prendre une capture d'écran de leur état actuel:

float theScale = 1.0f / theScrollView.zoomScale;
// The viewing rectangle in absolute coordinates
CGRect visibleArea = CGRectMake((int)(theScrollView.contentOffset.x * theScale), (int)(theScrollView.contentOffset.y * theScale),
                                (int)(theScrollView.bounds.size.width * theScale), (int)(theScrollView.bounds.size.height * theScale));

NSArray *layers = [NSArray arrayWithObjects:imageLayer1, imageLayer2, imageLayer3, imageLayer4, nil];
UIGraphicsBeginImageContext(visibleArea.size);
for (UIImageView *layer in layers) {
    CALayer *coreLayer = layer.layer;
    coreLayer.bounds = CGRectMake(layer.frame.origin.x - visibleArea.origin.x, layer.frame.origin.y - visibleArea.origin.y, layer.frame.size.width, layer.frame.size.height);
    [coreLayer renderInContext:UIGraphicsGetCurrentContext()];
}
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Cela prend la capture d'écran en coordonnées absolues. C'est, si vous avez un 2048*2048 image dans la scrollview et vous pouvez voir environ un quart d'elle, alors quelle que soit la résolution de votre écran, il serait prendre une capture d'écran de 512*512. Si vous voulez prendre une capture d'écran à la résolution de votre écran (par exemple, 320*480), alors vous avez à régler l'image comme suit, directement après le code ci-dessus:

UIGraphicsBeginImageContext(theScrollView.frame.size);
[screenshot drawInRect:CGRectMake(0, 0, theScrollView.frame.size.width, theScrollView.frame.size.height)];
UIImage *smallScreenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

-2voto

vodkhang Points 11222

Je ne sais pas grand-chose, mais je suppose que si nous définissons la taille du contextRect comme ceci pour le paysage, cela fonctionnera peut-être bien:

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

Parce que ce contextRect déterminera la taille du UIGraphicsBeginImageContext , j'espère qu'un double de la hauteur pourra résoudre votre problème

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X