我有一个UIImageView,可以通过手势识别器进行旋转,平移和缩放。因此,在其封闭视图中裁剪。 一切正常,但我不知道如何以全分辨率保存图片的可见部分。这不是一个屏幕抓取。
我知道我直接从UIImageView的可见内容中获取UIImage,但它仅限于屏幕的分辨率。
我认为我必须在UIImage上进行相同的转换并裁剪它。有一个简单的方法吗?
更新: 例如,我有一个带有高分辨率图像的UIImageView,让我们说一张800万像素的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];
}
答案 0 :(得分:17)
以下代码使用计算的比例因子创建封闭视图的快照(faceImageView
的超级视图,clipsToBounds
设置为YES
)。
它假定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;
}
根据当前变换,生成的图像将具有不同的大小。例如,放大时,尺寸会变小。您还可以将effectiveScale
设置为常量值,以获得具有恒定大小的图像。
您的手势识别器代码不限制比例因子,即您可以缩小/缩小而不受限制。那可能非常危险!当你缩小时,我的捕捉方法可以输出非常大的图像。
如果缩小后拍摄图像的背景将为黑色。如果您希望它是透明的,则必须将UIGraphicsBeginImageContextWithOptions
的opaque参数设置为NO
。
答案 1 :(得分: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]
或考虑翻译,应用核心图像过滤器等,具体取决于您的具体需求。
答案 2 :(得分: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;
}
我想你要保存显示屏并使用它,所以我发布这个代码...... 希望,这有助于你...... :)