Как узнать размер изображения после применения аспектного соответствия для изображения в UIImageView

Я загружаю изображение в режим просмотра изображений с режимом «Aspect Fit». Мне нужно знать размер, на который масштабируется мой образ. Пожалуйста помоги.

Пожалуйста, см. Ответ @ Paul-de-Lange вместо этого


Я не мог найти ничего в легкодоступной переменной, которая имела бы это, так что вот грубая сила:

- (CGSize) aspectScaledImageSizeForImageView:(UIImageView *)iv image:(UIImage *)im { float x,y; float a,b; x = iv.frame.size.width; y = iv.frame.size.height; a = im.size.width; b = im.size.height; if ( x == a && y == b ) { // image fits exactly, no scaling required // return iv.frame.size; } else if ( x > a && y > b ) { // image fits completely within the imageview frame if ( xa > yb ) { // image height is limiting factor, scale by height a = y/b * a; b = y; } else { b = x/a * b; // image width is limiting factor, scale by width a = x; } } else if ( x < a && y < b ) { // image is wider and taller than image view if ( a - x > b - y ) { // height is limiting factor, scale by height a = y/b * a; b = y; } else { // width is limiting factor, scale by width b = x/a * b; a = x; } } else if ( x < a && y > b ) { // image is wider than view, scale by width b = x/a * b; a = x; } else if ( x > a && y < b ) { // image is taller than view, scale by height a = y/b * a; b = y; } else if ( x == a ) { a = y/b * a; b = y; } else if ( y == b ) { b = x/a * b; a = x; } return CGSizeMake(a,b); } 

Почему бы не использовать функцию ОС AVMakeRectWithAspectRatioInsideRect ?

Я хотел использовать AVMakeRectWithAspectRatioInsideRect() без включения frameworks AVFoundation .

Поэтому я реализовал следующие две функции утилиты:

 CGSize CGSizeAspectFit(CGSize aspectRatio, CGSize boundingSize) { float mW = boundingSize.width / aspectRatio.width; float mH = boundingSize.height / aspectRatio.height; if( mH < mW ) boundingSize.width = boundingSize.height / aspectRatio.height * aspectRatio.width; else if( mW < mH ) boundingSize.height = boundingSize.width / aspectRatio.width * aspectRatio.height; return boundingSize; } CGSize CGSizeAspectFill(CGSize aspectRatio, CGSize minimumSize) { float mW = minimumSize.width / aspectRatio.width; float mH = minimumSize.height / aspectRatio.height; if( mH > mW ) minimumSize.width = minimumSize.height / aspectRatio.height * aspectRatio.width; else if( mW > mH ) minimumSize.height = minimumSize.width / aspectRatio.width * aspectRatio.height; return minimumSize; } 

Изменить: оптимизировано ниже, удаляя дубликаты разделов.

 CGSize CGSizeAspectFit(const CGSize aspectRatio, const CGSize boundingSize) { CGSize aspectFitSize = CGSizeMake(boundingSize.width, boundingSize.height); float mW = boundingSize.width / aspectRatio.width; float mH = boundingSize.height / aspectRatio.height; if( mH < mW ) aspectFitSize.width = mH * aspectRatio.width; else if( mW < mH ) aspectFitSize.height = mW * aspectRatio.height; return aspectFitSize; } CGSize CGSizeAspectFill(const CGSize aspectRatio, const CGSize minimumSize) { CGSize aspectFillSize = CGSizeMake(minimumSize.width, minimumSize.height); float mW = minimumSize.width / aspectRatio.width; float mH = minimumSize.height / aspectRatio.height; if( mH > mW ) aspectFillSize.width = mH * aspectRatio.width; else if( mW > mH ) aspectFillSize.height = mW * aspectRatio.height; return aspectFillSize; } 

Конец редактирования

Это принимает заданный размер (первый параметр) и поддерживает его соотношение сторон. Затем он заполняет заданные границы (второй параметр) как можно больше, не нарушая соотношение сторон.

Используя это, чтобы ответить на исходный вопрос:

 // Using aspect fit, scale the image (size) to the image view's size. CGSize sizeBeingScaledTo = CGSizeAspectFit(theImage.size, theImageView.frame.size); 

Обратите внимание, как изображение определяет соотношение сторон, в то время как представление изображения определяет размер, который необходимо заполнить.

Обратная связь очень приветствуется.

Эта простая функция рассчитает размер изображения после соответствия аспекту:

  -(CGSize)imageSizeAfterAspectFit:(UIImageView*)imgview{ float newwidth; float newheight; UIImage *image=imgview.image; if (image.size.height>=image.size.width){ newheight=imgview.frame.size.height; newwidth=(image.size.width/image.size.height)*newheight; if(newwidth>imgview.frame.size.width){ float diff=imgview.frame.size.width-newwidth; newheight=newheight+diff/newheight*newheight; newwidth=imgview.frame.size.width; } } else{ newwidth=imgview.frame.size.width; newheight=(image.size.height/image.size.width)*newwidth; if(newheight>imgview.frame.size.height){ float diff=imgview.frame.size.height-newheight; newwidth=newwidth+diff/newwidth*newwidth; newheight=imgview.frame.size.height; } } NSLog(@"image after aspect fit: width=%f height=%f",newwidth,newheight); //adapt UIImageView size to image size //imgview.frame=CGRectMake(imgview.frame.origin.x+(imgview.frame.size.width-newwidth)/2,imgview.frame.origin.y+(imgview.frame.size.height-newheight)/2,newwidth,newheight); return CGSizeMake(newwidth, newheight); } 

Возможно, это не подходит вашему делу, но этот простой подход решает мою проблему в аналогичном случае:

  UIImageView *imageView = [[UIImageView alloc] initWithImage:bigSizeImage]; [imageView sizeToFit]; 

После просмотра изображения выполняется sizeToFit, если вы запрашиваете imageView.frame.size, вы получите новый размер изображения, соответствующий размеру нового изображения.

Для Swift используйте код ниже

 func imageSizeAspectFit(imgview: UIImageView) -> CGSize { var newwidth: CGFloat var newheight: CGFloat let image: UIImage = imgFeed.image! if image.size.height >= image.size.width { newheight = imgview.frame.size.height; newwidth = (image.size.width / image.size.height) * newheight if newwidth > imgview.frame.size.width { let diff: CGFloat = imgview.frame.size.width - newwidth newheight = newheight + diff / newheight * newheight newwidth = imgview.frame.size.width } } else { newwidth = imgview.frame.size.width newheight = (image.size.height / image.size.width) * newwidth if newheight > imgview.frame.size.height { let diff: CGFloat = imgview.frame.size.height - newheight newwidth = newwidth + diff / newwidth * newwidth newheight = imgview.frame.size.height } } print(newwidth, newheight) //adapt UIImageView size to image size return CGSizeMake(newwidth, newheight) } 

И функция вызова

 imgFeed.sd_setImageWithURL(NSURL(string:"Your image URL"))) self.imageSizeAfterAspectFit(imgFeed) 

Я также хотел рассчитать высоту после применения соотношения сторон, чтобы вычислить высоту ячейки таблицы. Итак, я достиг небольшой математики

 ratio = width / height 

и высота

 height = width / ratio 

Таким образом, fragment кода будет

 UIImage *img = [UIImage imageNamed:@"anImage"]; float aspectRatio = img.size.width/img.size.height; float requiredHeight = self.view.bounds.size.width / aspectRatio; 

Swift 3 Человеческая читабельность

 extension UIImageView { /// Find the size of the image, once the parent imageView has been given a contentMode of .scaleAspectFit /// Querying the image.size returns the non-scaled size. This helper property is needed for accurate results. var aspectFitSize: CGSize { guard let image = image else { return CGSize.zero } var aspectFitSize = CGSize(width: frame.size.width, height: frame.size.height) let newWidth: CGFloat = frame.size.width / image.size.width let newHeight: CGFloat = frame.size.height / image.size.height if newHeight < newWidth { aspectFitSize.width = newHeight * image.size.width } else if newWidth < newHeight { aspectFitSize.height = newWidth * image.size.height } return aspectFitSize } /// Find the size of the image, once the parent imageView has been given a contentMode of .scaleAspectFill /// Querying the image.size returns the non-scaled, vastly too large size. This helper property is needed for accurate results. var aspectFillSize: CGSize { guard let image = image else { return CGSize.zero } var aspectFillSize = CGSize(width: frame.size.width, height: frame.size.height) let newWidth: CGFloat = frame.size.width / image.size.width let newHeight: CGFloat = frame.size.height / image.size.height if newHeight > newWidth { aspectFillSize.width = newHeight * image.size.width } else if newWidth > newHeight { aspectFillSize.height = newWidth * image.size.height } return aspectFillSize } } 
 +(UIImage *)CreateAResizeImage:(UIImage *)Img ThumbSize:(CGSize)ThumbSize { float actualHeight = Img.size.height; float actualWidth = Img.size.width; if(actualWidth==actualHeight) { actualWidth = ThumbSize.width; actualHeight = ThumbSize.height; } float imgRatio = actualWidth/actualHeight; float maxRatio = ThumbSize.width/ThumbSize.height; //320.0/480.0; if(imgRatio!=maxRatio) { if(imgRatio < maxRatio) { imgRatio = ThumbSize.height / actualHeight; //480.0 / actualHeight; actualWidth = imgRatio * actualWidth; actualHeight = ThumbSize.height; //480.0; } else { imgRatio = ThumbSize.width / actualWidth; //320.0 / actualWidth; actualHeight = imgRatio * actualHeight; actualWidth = ThumbSize.width; //320.0; } } else { actualWidth = ThumbSize.width; actualHeight = ThumbSize.height; } CGRect rect = CGRectMake(0, 0, (int)actualWidth, (int)actualHeight); UIGraphicsBeginImageContext(rect.size); [Img drawInRect:rect]; UIImage *NewImg = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return NewImg; } 

Принятый ответ невероятно сложный и не подходит для некоторых краевых случаев. Я думаю, что это решение намного элегантнее:

 - (CGSize) sizeOfImage:(UIImage*)image inAspectFitImageView:(UIImageView*)imageView { UKAssert(imageView.contentMode == UIViewContentModeScaleAspectFit, @"Image View must use contentMode = UIViewContentModeScaleAspectFit"); CGFloat imageViewWidth = imageView.bounds.size.width; CGFloat imageViewHeight = imageView.bounds.size.height; CGFloat imageWidth = image.size.width; CGFloat imageHeight = image.size.height; CGFloat scaleFactor = MIN(imageViewWidth / imageWidth, imageViewHeight / imageHeight); return CGSizeMake(image.size.width*scaleFactor, image.size.height*scaleFactor); } 

Вот мое решение для той же проблемы: https://github.com/alexgarbarev/UIImageView-ImageFrame

Преимущества:

  • Поддерживаются режимы UIViewContentMode
  • Может запрашивать весы и отдельно
  • Может спросить о кадре изображения прямо из UIImageView

Эта единственная строка может выполнять эту работу

CGSize sizeInView = AVMakeRectWithAspectRatioInsideRect (imgViewFake.image.size, imgViewFake.bounds) .size;

Я использую следующее в Swift:

 private func CGSizeAspectFit(aspectRatio:CGSize,boundingSize:CGSize) -> CGSize { var aspectFitSize = boundingSize let mW = boundingSize.width / aspectRatio.width let mH = boundingSize.height / aspectRatio.height if( mH < mW ) { aspectFitSize.width = mH * aspectRatio.width } else if( mW < mH ) { aspectFitSize.height = mW * aspectRatio.height } return aspectFitSize } private func CGSizeAspectFill(aspectRatio:CGSize,minimumSize:CGSize) -> CGSize { var aspectFillSize = minimumSize let mW = minimumSize.width / aspectRatio.width let mH = minimumSize.height / aspectRatio.height if( mH > mW ) { aspectFillSize.width = mH * aspectRatio.width } else if( mW > mH ) { aspectFillSize.height = mW * aspectRatio.height } return aspectFillSize } 

Я использую его вот так:

 let aspectSize = contentMode == .ScaleAspectFill ? CGSizeAspectFill(oldSize,minimumSize: newSize) : CGSizeAspectFit(oldSize, boundingSize: newSize) let newRect = CGRect( x: (newSize.width - aspectSize.width)/2, y: (newSize.height - aspectSize.height)/2, width: aspectSize.width, height: aspectSize.height) CGContextSetFillColorWithColor(context,IOSXColor.whiteColor().CGColor) CGContextFillRect(context, CGRect(origin: CGPointZero,size: newSize)) CGContextDrawImage(context, newRect, cgImage) 

Swift 3 Расширение UIImageView:

 import AVFoundation extension UIImageView { var imageSize: CGSize { if let image = image { return AVMakeRect(aspectRatio: image.size, insideRect: bounds).size } return CGSize.zero } } 

Swift 4: Рамка для изображения .aspectFit

 import AVFoundation 

let x: CGRect = AVMakeRect(aspectRatio: myImage.size, insideRect: sampleImageView.frame)

Вышеупомянутые методы никогда не дают требуемых значений. Поскольку аспект соответствия поддерживает тот же формат, нам просто нужны простые математические вычисления для вычисления значений

Обнаружить соотношение сторон

 CGFloat imageViewAspectRatio = backgroundImageView.bounds.size.width / backgroundImageView.bounds.size.height; CGFloat imageAspectRatio = backgroundImageView.image.size.width / backgroundImageView.image.size.height; CGFloat mulFactor = imageViewAspectRatio/imageAspectRatio; 

Получить новые значения

 CGFloat newImageWidth = mulFactor * backgroundImageView.bounds.size.width; CGFloat newImageHeight = mulFactor * backgroundImageView.bounds.size.height; 

Если вы знаете только ширину изображения и когда высота изображения динамическая, вам необходимо масштабировать высоту изображения в соответствии с заданной шириной, чтобы удалить белые пробелы выше и ниже вашего изображения. Используйте следующий метод для масштабирования высоты изображения в соответствии со стандартной шириной экрана.

 -(UIImage*)imageWithImage: (UIImage*) sourceImage scaledToWidth: (float) i_width { float oldWidth = sourceImage.size.width; float scaleFactor = i_width / oldWidth; float newHeight = sourceImage.size.height * scaleFactor; float newWidth = oldWidth * scaleFactor; UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight)); [sourceImage drawInRect:CGRectMake(0, 0, newWidth, newHeight)]; UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; } 

И назовите это из вашего метода cellForRowAtIndexPath: вроде этого:

 UIImage *img = [dictImages objectForKey:yourImageKey]; // loaded the image cell.imgView.image = [self imageWithImage:img scaledToWidth:self.view.frame.size.width]; 

Вот мое решение без AVFoundation.

Прежде всего, это расширение CGSize для вычисления размера, который бы соответствовал другому размеру:

 extension CGSize { func sizeThatFitsSize(_ aSize: CGSize) -> CGSize { let width = min(self.width * aSize.height / self.height, aSize.width) return CGSize(width: width, height: self.height * width / self.width) } } 

Таким образом, решение проблемы OP сводится к:

 let resultSize = image.size.sizeThatFitsSize(imageView.bounds.size) 

Также есть еще одно расширение для установки прямоугольника в другом прямоугольнике (в нем используется указанное расширение CGSize):

 extension CGRect { func rectThatFitsRect(_ aRect:CGRect) -> CGRect { let sizeThatFits = self.size.sizeThatFitsSize(aRect.size) let xPos = (aRect.size.width - sizeThatFits.width) / 2 let yPos = (aRect.size.height - sizeThatFits.height) / 2 let ret = CGRect(x: xPos, y: yPos, width: sizeThatFits.width, height: sizeThatFits.height) return ret } } 
  • Как сделать ImageView UITableViewCell фиксированным, даже когда изображение меньше
  • Изменение размера UI-изображений, снятых с камеры, также приводит к вращению UI-образа?
  • Как отобразить изображение base64 в UIImageView?
  • Сохранить изображение в папку документов приложений из UIView на IOS
  • Создание UIImage из повернутого UIImageView
  • Метод доступа после завершения анимации UIImageView
  • Давайте будем гением компьютера.