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

次のコードは、計算された倍率を使用して、囲んでいるビュー (faceImageViewclipsToBounds設定されたのスーパービュー) のスナップショットを作成します。YES

faceImageView のコンテンツ モードが であり、faceImageViewUIViewContentModeScaleAspectFitのフレームが 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;
}

現在の変換に応じて、結果の画像のサイズが異なります。たとえば、拡大するとサイズが小さくなります。effectiveScale一定のサイズの画像を取得するために、一定の値に設定することもできます。

ジェスチャ認識コードは倍率を制限しません。つまり、制限されることなくズームアウト/ズームインできます。それは非常に危険です!私のキャプチャ方法は、非常にズームアウトしたときに非常に大きな画像を出力できます。

ズームアウトすると、キャプチャされた画像の背景が黒くなります。透明にしたい場合は、 opaque-parameter を に設定する必要がありUIGraphicsBeginImageContextWithOptionsますNO

于 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] 正確なニーズに応じて、翻訳を確認または考慮したり、Core Image フィルターを適用したりします。

于 2012-06-25T10:38:02.077 に答える
0

次のコードが現在のビューをキャプチャすると思います...

- (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 に答える