2012-06-19 12 views
14

Tengo un UIImageView que se puede rotar, panoramizar y escalar con reconocedores de gestos. Como resultado, es recortada en su vista circundante. Todo funciona bien, pero no sé cómo guardar la parte visible visible de la imagen en su resolución completa. No es una captura de pantalla.¿Cómo obtener una imagen girada, ampliada y panoramizada desde un UIImageView con su resolución completa?

Sé que obtengo el UIImage directamente del contenido visible del UIImageView, pero está limitado a la resolución de la pantalla.

Supongo que tengo que hacer las mismas transformaciones en el UIImage y recortarlo. ¿Hay alguna manera fácil de hacer eso?

actualización: Por ejemplo, tengo una UIImageView con una imagen en alta resolución, digamos que una foto de la cámara del iPhone 8MP 4s, que se transforma con gestos, lo que se convierte a escala, gira y se mueve alrededor en su encerramiento ver. Obviamente, se están produciendo algunos recortes, por lo que solo se muestra una parte de la imagen. Hay una gran diferencia entre la resolución de pantalla mostrada y la resolución de la imagen subrayada, necesito una imagen en la resolución de la imagen. UIImageView está en UIViewContentModeScaleAspectFit, pero una solución con UIViewContentModeScaleAspectFill también está bien.

Este es mi código:

- (void)rotatePiece:(UIRotationGestureRecognizer *)gestureRecognizer { 

    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) { 
     [gestureRecognizer view].transform = CGAffineTransformRotate([[gestureRecognizer view] transform], [gestureRecognizer rotation]); 
     [gestureRecognizer setRotation:0]; 
    } 
} 

- (void)scalePiece:(UIPinchGestureRecognizer *)gestureRecognizer { 

    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) { 
     [gestureRecognizer view].transform = CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]); 
     [gestureRecognizer setScale:1]; 
    } 
} 

-(void)panGestureMoveAround:(UIPanGestureRecognizer *)gestureRecognizer; 
{ 
    UIView *piece = [gestureRecognizer view]; 

    //We pass in the gesture to a method that will help us align our touches so that the pan and pinch will seems to originate between the fingers instead of other points or center point of the UIView  
    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) { 

     CGPoint translation = [gestureRecognizer translationInView:[piece superview]]; 
     [piece setCenter:CGPointMake([piece center].x + translation.x, [piece center].y+translation.y)]; 
     [gestureRecognizer setTranslation:CGPointZero inView:[piece superview]]; 
    } else if([gestureRecognizer state] == UIGestureRecognizerStateEnded) { 
     //Put the code that you may want to execute when the UIView became larger than certain value or just to reset them back to their original transform scale 
    } 
} 


- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { 
    // if the gesture recognizers are on different views, don't allow simultaneous recognition 
    if (gestureRecognizer.view != otherGestureRecognizer.view) 
     return NO; 

    // if either of the gesture recognizers is the long press, don't allow simultaneous recognition 
    if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] || [otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) 
     return NO; 

    return YES; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view from its nib. 
    appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];  
    faceImageView.image = appDelegate.faceImage; 

    UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotatePiece:)]; 
    [faceImageView addGestureRecognizer:rotationGesture]; 
    [rotationGesture setDelegate:self]; 

    UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(scalePiece:)]; 
    [pinchGesture setDelegate:self]; 
    [faceImageView addGestureRecognizer:pinchGesture]; 

    UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureMoveAround:)]; 
    [panRecognizer setMinimumNumberOfTouches:1]; 
    [panRecognizer setMaximumNumberOfTouches:2]; 
    [panRecognizer setDelegate:self]; 
    [faceImageView addGestureRecognizer:panRecognizer]; 


    [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone]; 

    [appDelegate fadeObject:moveIcons StartAlpha:0 FinishAlpha:1 Duration:2]; 
    currentTimer = [NSTimer timerWithTimeInterval:4.0f target:self selector:@selector(fadeoutMoveicons) userInfo:nil repeats:NO]; 

    [[NSRunLoop mainRunLoop] addTimer: currentTimer forMode: NSDefaultRunLoopMode]; 

} 
+0

necesitamos saber qué contentMode usted establece para la vista de la imagen, para que podamos calcular el recorte correcto para la imagen más fácil – Felix

+0

@ phix23 el modo de contenido es UIViewContentModeScaleAspectFit – Tibidabo

Respuesta

17

El siguiente código crea una instantánea de la vista adjunta (supervista de faceImageView con clipsToBounds establecido en YES) utilizando un factor de escala calculado.

Asume que el modo de contenido de faceImageView es UIViewContentModeScaleAspectFit y que el marco de faceImageView se establece en los límites de la vista adjunta.

- (UIImage *)captureView { 

    float imageScale = sqrtf(powf(faceImageView.transform.a, 2.f) + powf(faceImageView.transform.c, 2.f));  
    CGFloat widthScale = faceImageView.bounds.size.width/faceImageView.image.size.width; 
    CGFloat heightScale = faceImageView.bounds.size.height/faceImageView.image.size.height; 
    float contentScale = MIN(widthScale, heightScale); 
    float effectiveScale = imageScale * contentScale; 

    CGSize captureSize = CGSizeMake(enclosingView.bounds.size.width/effectiveScale, enclosingView.bounds.size.height/effectiveScale); 

    NSLog(@"effectiveScale = %0.2f, captureSize = %@", effectiveScale, NSStringFromCGSize(captureSize)); 

    UIGraphicsBeginImageContextWithOptions(captureSize, YES, 0.0);   
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    CGContextScaleCTM(context, 1/effectiveScale, 1/effectiveScale); 
    [enclosingView.layer renderInContext:context]; 
    UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    return img; 
} 

Dependiendo de la transformación actual, la imagen resultante tendrá un tamaño diferente. Por ejemplo, cuando haces zoom, el tamaño se reduce. También puede establecer en un valor constante para obtener una imagen con un tamaño constante.

El código del reconocedor de gestos no limita el factor de escala, es decir, puede acercar/alejar sin estar limitado. Eso puede ser muy peligroso! Mi método de captura puede generar imágenes realmente grandes cuando se ha disminuido mucho.

Si ha alejado, el fondo de la imagen capturada será negro. Si desea que sea transparente, debe establecer el parámetro opaco de UIGraphicsBeginImageContextWithOptions en NO.

+0

¡Gracias! Funciona a las mil maravillas. Código muy elegante. – Tibidabo

+0

¡Gran solución, perfecto! ¡He estado buscando esto por años! todas las otras soluciones solo toman una captura de pantalla efectiva que es calidad de basura – Rich

+0

Intenté su código, pero no funciona para la imagen ampliada, estoy usando scrollview como enclosingView y faceImageView es mi vista de imagen dentro de scrollview. está dando una imagen en blanco. sin zoom, funciona correctamente. ¿Puedes ayudarme? – Vibhooti

0

Creo Código Fuelle capturar su vista actual ...

- (UIImage *)captureView { 

    CGRect rect = [self.view bounds]; 

    UIGraphicsBeginImageContext(rect.size); 
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    [self.yourImage.layer renderInContext:context]; 
    UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    return img; 

} 

Creo que desea guardar la pantalla de visualización y utilizarlo, por lo que publico este código ... Espero que esto te ayude ... :)

+1

lea la pregunta, Q pidió especialmente no para la pantalla agarrar porque está limitado a la resolución del dispositivo. –

+0

Puedo capturar la pantalla, no hay problema, pero necesito una solución con resolución completa. el código ni siquiera captura en la resolución retina. – Tibidabo

+0

creo que quieres capturar toda la imagen ¿estoy en lo cierto? –

3

¿Por qué capturar la vista si tiene la imagen original? Solo aplicale las transformaciones.Algo como esto puede ser un comienzo:

UIImage *image = [UIImage imageNamed:@"<# original #>"]; 

CIImage *cimage = [CIImage imageWithCGImage:image.CGImage]; 

// build the transform you want 
CGAffineTransform t = CGAffineTransformIdentity; 
CGFloat angle = [(NSNumber *)[self.faceImageView valueForKeyPath:@"layer.transform.rotation.z"] floatValue]; 
CGFloat scale = [(NSNumber *)[self.faceImageView valueForKeyPath:@"layer.transform.scale"] floatValue];  
t = CGAffineTransformConcat(t, CGAffineTransformMakeScale(scale, scale)); 
t = CGAffineTransformConcat(t, CGAffineTransformMakeRotation(-angle)); 

// create a new CIImage using the transform, crop, filters, etc. 
CIImage *timage = [cimage imageByApplyingTransform:t]; 

// draw the result 
CIContext *context = [CIContext contextWithOptions:nil]; 
CGImageRef imageRef = [context createCGImage:timage fromRect:[timage extent]]; 
UIImage *result = [UIImage imageWithCGImage:imageRef]; 

// save to disk 
NSData *png = UIImagePNGRepresentation(result); 
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/result.png"]; 
if (png && [png writeToFile:path atomically:NO]) { 
    NSLog(@"\n%@", path); 
} 
CGImageRelease(imageRef); 

Puede recortar fácilmente la salida si eso es lo que quiere (ver -[CIImage imageByCroppingToRect] o tener en cuenta la traducción, aplicar un filtro Core Image, etc., dependiendo de cuáles son su exacta necesita

+0

Quiero una parte visible de la imagen dentro de UIImageview. esto me está dando la misma imagen como original. puedes por favor ayuda. La estructura es como UIImageview dentro de UIscrollview para dar un efecto de zoom. Solo quiero esa parte que es visible con calidad de resolución. – Vibhooti

+0

Tengo el mismo problema que tenía Vibhooti, ​​estoy recortando la vista de desplazamiento visible desde la imagen (Zoomed) y funciona también pero sin rotación, pero ¿cómo tomar la rotación en cuenta aquí? Como estoy convirtiendo el punto visible de la vista de desplazamiento en la imagen (si la imagen gira, entonces no es posible utilizar el marco :() Estoy luchando desde hace 2 semanas, si pudiera ayudarme, sería genial, gracias –

Cuestiones relacionadas