Как обрезать UIImageView до Нового UIImage в режиме' aspect fit'?
Я хотел бы создать новый UIImage, обрезав изображение внутри UIImageView. Например, на приведенном выше рисунке я хочу получить новое изображение области, выделенной зеленым цветом. Я нашел код для этого, обычно он выглядит примерно так (как категория UIImage):
- (UIImage *)croppedImage:(CGRect)bounds {
CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], bounds);
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return croppedImage;
}
Имеет смысл. Тем не менее, мой UIImageView находится в contentMode 'aspect fit'. Похоже, что это усложняет вычисления CGRect для CGImageCreateWithImageInRect, и я не смог выяснить правильное решение.
Я полагаю, что мне нужно применить те же преобразования к зеленой прямой кишке, что и к изображению?
Также: я нашел здесь этот другой вопрос ( Как узнать размер изображения после применения аспекта, подходящего для изображения в UIImageView), который, кажется, показывает грубый способ получения размера, но я все еще не уверен, как это вписывается в ситуацию обрезки.
Есть идеи?
EDIT : в моем случае у меня буквально есть квадрат, как показано выше, нарисованное в виде наложения поверх UIImageView. Поэтому, хотя я понимаю, что обрезаю UIImage (внутри UIImageView), мне нужно каким-то образом изменить зеленый CGRect таким образом, чтобы он "соответствовал" преобразованию, выполненному при применении "подгонки аспекта". Например, если я оставляю свой UIImageView в "верхнем левом" режиме, то все работает нормально, потому что существует сопоставление 1:1 между базовым UIImage и UIImageView. Проблема в режиме "сверху слева" заключается в том, что не всегда все изображение дисплей, потому что он может быть больше, чем мой UIImageView.
4 ответа:
Основываясь на моем другом ответе на аналогичный вопрос, я написал этот метод для категории UIImageView:
-(CGRect) cropRectForFrame:(CGRect)frame { NSAssert(self.contentMode == UIViewContentModeScaleAspectFit, @"content mode must be aspect fit"); CGFloat widthScale = self.bounds.size.width / self.image.size.width; CGFloat heightScale = self.bounds.size.height / self.image.size.height; float x, y, w, h, offset; if (widthScale<heightScale) { offset = (self.bounds.size.height - (self.image.size.height*widthScale))/2; x = frame.origin.x / widthScale; y = (frame.origin.y-offset) / widthScale; w = frame.size.width / widthScale; h = frame.size.height / widthScale; } else { offset = (self.bounds.size.width - (self.image.size.width*heightScale))/2; x = (frame.origin.x-offset) / heightScale; y = frame.origin.y / heightScale; w = frame.size.width / heightScale; h = frame.size.height / heightScale; } return CGRectMake(x, y, w, h); }
Вы можете пройти в кадр вашего зеленого rect (предполагая, что это подвид изображения) и получить кадрирование rect обратно для обрезки UIImage. Обратите внимание, что он работает только для режима "aspect fit"! Но я его не проверял. Так скажи мне, если это сработает!
Я знаю, что ответ был, но у меня были некоторые проблемы с получением выше прямо так, я обычно публикую свое решение тоже.
Проблема заключается в том, что изображение масштабируется с учетом аспекта, но мы знаем масштабный коэффициент как для ширины, так и для высоты. Тогда мы можем вычислить правильный прямоугольник обрезки довольно легко:-(UIImage*)crop:(CGRect)frame { // Find the scalefactors UIImageView's widht and height / UIImage width and height CGFloat widthScale = self.bounds.size.width / self.image.size.width; CGFloat heightScale = self.bounds.size.height / self.image.size.height; // Calculate the right crop rectangle frame.origin.x = frame.origin.x * (1 / widthScale); frame.origin.y = frame.origin.y * (1 / heightScale); frame.size.width = frame.size.width * (1 / widthScale); frame.size.height = frame.size.height * (1 / heightScale); // Create a new UIImage CGImageRef imageRef = CGImageCreateWithImageInRect(self.image.CGImage, frame); UIImage *croppedImage = [UIImage imageWithCGImage:imageRef]; CGImageRelease(imageRef); return croppedImage; }
Я думаю, что вы не понимаете, что вы делаете. Вы не можете "обрезать" UIImageView-только UIImages. Поэтому ваш метод croppedImage должен быть в категории UIImage, а не в категории UIImageView. Границы rect, которые вы передаете методу crop, должны быть связаны с размером изображения, а не с границами imageview. Не имеет значения, что такое contentMode представления изображения - обрезка изображения всегда будет работать одинаково. Сначала получите изображение из представления изображения. Затем создайте новое обрезанное изображение из него и, наконец, установить обрезанное изображение для просмотра изображения. Это можно сделать в одной строке кода:
imageView.image = [imageView.image croppedImage:rect];
Так как ваш contentMode - это 'aspect fit', новое изображение будет автоматически растягиваться, чтобы поместиться в рамке вида. Вы также можете попробовать изменить рамку вида на основе изображения.размер, чтобы избежать эффектов пикселизации.
Я использую следующий метод.
-(UIImage *)getNeedImageFrom:(UIImage*)image cropRect:(CGRect)rect { CGSize cropSize = rect.size; CGFloat widthScale = image.size.width/self.imageViewOriginal.bounds.size.width; CGFloat heightScale = image.size.height/self.imageViewOriginal.bounds.size.height; cropSize = CGSizeMake(rect.size.width*widthScale, rect.size.height*heightScale); CGPoint pointCrop = CGPointMake(rect.origin.x*widthScale, rect.origin.y*heightScale); rect = CGRectMake(pointCrop.x, pointCrop.y, cropSize.width, cropSize.height); CGImageRef subImage = CGImageCreateWithImageInRect(image.CGImage, rect); UIImage *croppedImage = [UIImage imageWithCGImage:subImage]; CGImageRelease(subImage); return croppedImage; }