15

我有一个 UIImageView 可以使用手势识别器进行旋转、平移和缩放。结果,它在其封闭视图中被裁剪。一切正常,但我不知道如何以全分辨率保存图片的可见部分。这不是屏幕抓取。

我知道我直接从 UIImageView 的可见内容获得 UIImage ,但它仅限于屏幕的分辨率。

我假设我必须对 UIImage 进行相同的转换并裁剪它。有没有简单的方法可以做到这一点?

更新:例如,我有一个带有高分辨率图像的 UIImageView,比如说一张 8MP iPhone 4s 相机照片,它通过手势进行转换,因此它在其封闭视图中被缩放、旋转和移动。显然有一些裁剪正在进行,所以只显示了图像的一部分。显示的屏幕分辨率和下划线图像分辨率之间存在巨大差异,我需要图像分辨率中的图像。UIImageView 位于UIViewContentModeScaleAspectFit中,但使用 UIViewContentModeScaleAspectFill 的解决方案也可以。

这是我的代码:

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

}
4

3 回答 3

17

以下代码使用计算的比例因子创建封闭视图(设置为faceImageView的父视图)的快照。clipsToBoundsYES

它假设 faceImageView 的内容模式是UIViewContentModeScaleAspectFit,并且 faceImageView 的框架设置为 enclosureView 的边界。

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

根据当前变换,生成的图像将具有不同的大小。例如,当您放大时,尺寸会变小。您还可以设置effectiveScale为恒定值,以获得具有恒定大小的图像。

您的手势识别器代码不限制比例因子,即您可以不受限制地缩小/缩小。这可能非常危险!当您缩小很多时,我的捕获方法可以输出非常大的图像。

如果您已缩小拍摄图像的背景将是黑色的。如果希望它是透明的,则必须将 opaque-parameter 设置UIGraphicsBeginImageContextWithOptionsNO

于 2012-06-24T12:09:06.680 回答
3

如果您有原始图像,为什么要捕获视图?只需将转换应用于它。这样的事情可能是一个开始:

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

如果这是您想要的,您可以轻松裁剪输出(查看-[CIImage imageByCroppingToRect] 或考虑翻译,应用核心图像过滤器等,具体取决于您的确切需求。

于 2012-06-25T10:38:02.077 回答
0

我认为 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;

}

我想你想保存显示屏幕并使用它,所以我发布了这段代码......希望,这对你有帮助...... :)

于 2012-06-21T17:42:39.347 回答