简体   繁体   English

如何从UIImageView以全分辨率获得旋转,缩放和平移图像?

[英]How to get a rotated, zoomed and panned image from an UIImageView at its full resolution?

I have an UIImageView which can be rotated, panned and scaled with gesture recognisers. 我有一个UIImageView,可以通过手势识别器旋转,平移和缩放。 As a result it is cropped in its enclosing view. 因此,它在其封闭视图中被裁剪 Everything is working fine but I don't know how to save the visible part of the picture in its full resolution . 一切都很好,但我不知道如何以完整的分辨率保存图片的可见部分 It's not a screen grab. 这不是一个屏幕抓取。

I know I get the UIImage straight from the visible content of the UIImageView but it is limited to the resolution of the screen. 我知道我直接从UIImageView的可见内容中获取UIImage,但它仅限于屏幕的分辨率。

I assume that I have to do the same transformations on the UIImage and crop it. 我假设我必须在UIImage上进行相同的转换并裁剪它。 IS there an easy way to do that? 有一个简单的方法吗?

Update : For example, I have an UIImageView with an image in high resolution, let's say a 8MP iPhone 4s camera photo, which is transformed with gestures, so it becomes scaled, rotated and moved around in its enclosing view. 更新 :例如,我有一个高分辨率图像的UIImageView,让我们说一张800万像素的iPhone 4s相机照片,它是用手势转换的,因此它会在其封闭视图中缩放,旋转和移动。 Obviously there is some cropping going on so only a part of the image is displayed. 显然有一些裁剪正在进行,因此只显示了部分图像。 There is a huge difference between the displayed screen resolution and the underlining image resolution, I need an image in the image resolution. 显示的屏幕分辨率和下划线图像分辨率之间存在巨大差异,我需要图像分辨率中的图像。 The UIImageView is in UIViewContentModeScaleAspectFit , but a solution with UIViewContentModeScaleAspectFill is also fine. UIImageView位于UIViewContentModeScaleAspectFit中 ,但是使用UIViewContentModeScaleAspectFill的解决方案也没问题。

This is my code: 这是我的代码:

- (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];

}

The following code creates a snapshot of the enclosing view (superview of faceImageView with clipsToBounds set to YES ) using a calculated scale factor. 以下代码使用计算的比例因子创建封闭视图的快照( faceImageViewclipsToBounds视图,其中clipsToBounds设置为YES )。

It assumes that the content mode of faceImageView is UIViewContentModeScaleAspectFit and that the frame of faceImageView is set to the enclosingView's bounds. 它假定faceImageView的内容模式是UIViewContentModeScaleAspectFit并且faceImageView的框架设置为enclosingView的边界。

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

Depending on the current transform the resulting image will have a different size. 根据当前变换,生成的图像将具有不同的大小。 For example when you zoom in, the size gets smaller. 例如,放大时,尺寸会变小。 You can also set effectiveScale to a constant value in order to get an image with a constant size. 您还可以将effectiveScale设置为常量值,以获得具有恒定大小的图像。

Your gesture recognizer code does not limit the scale factor, ie you can zoom out/in without being limited. 您的手势识别器代码不会限制比例因子,即您可以缩小/缩小而不受限制。 That can be very dangerous! 那可能非常危险! My capture method can output really large images when you've zoomed out very much. 当你缩小时,我的捕捉方法可以输出非常大的图像。

If you have zoomed out the background of the captured image will be black. 如果缩小,捕获图像的背景将为黑色。 If you want it to be transparent, you must set the opaque-parameter of UIGraphicsBeginImageContextWithOptions to NO . 如果希望它是透明的,则必须将UIGraphicsBeginImageContextWithOptions的opaque参数设置为NO

Why capturing the view if you have the original image? 如果您有原始图像,为什么要捕获视图? Just apply the transformations to it. 只需将转换应用于它。 Something like this may be a start: 这样的事情可能是一个开始:

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);

You can easily crop the output if that's what you want (see -[CIImage imageByCroppingToRect] or take into account the translation, apply a Core Image filter, etc. depending on what are your exact needs. 如果这是您想要的,您可以轻松裁剪输出(请参阅-[CIImage imageByCroppingToRect]或考虑转换,应用核心图像过滤器等,具体取决于您的确切需求。

I think Bellow Code Capture Your Current View ... 我认为Bellow Code捕捉你当前的观点......

- (UIImage *)captureView {

    CGRect rect = [self.view bounds];

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

    return img;

}

I think you want to save the display screen and use it ,so i post this code... Hope,this help you... :) 我想你要保存显示屏并使用它,所以我发布这个代码...希望,这有助于你...... :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM