Как получить повернутое, увеличенное и развернутое изображение из UIImageView с полным разрешением?
У меня есть UIImageView, который может быть повернут, развернут и масштабирован с помощью распознавателей жестов. В результате он обрезается в своем закрытом представлении.
Все работает нормально, но я не знаю, как сохранить видимую часть изображения в полном разрешении. Это не захват экрана.
Я знаю, что я получаю UIImage прямо из видимого содержимого UIImageView, но он ограничен разрешением экрана.
Я предполагаю, что я должен делать те же преобразования на 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];
}
Ответы
Ответ 1
Следующий код создает моментальный снимок закрывающего представления (супервизор faceImageView
с clipsToBounds
, установленный на YES
), с использованием расчетного масштабного коэффициента.
Предполагается, что режим содержимого faceImageView равен UIViewContentModeScaleAspectFit
и что для рамки faceImageView задано ограничение окружения.
- (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
на NO
.
Ответ 2
Зачем захватывать представление, если у вас есть исходное изображение? Просто примените к нему преобразования. Что-то вроде этого может быть началом:
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]
или принять во внимание перевод, применить фильтр основного изображения и т.д. в зависимости от ваших конкретных потребностей.
Ответ 3
Я думаю, что 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;
}
Я думаю, вы хотите сохранить экран и использовать его, поэтому я отправляю этот код...
Надеюсь, это поможет вам...
:)