Comment connaître la taille de l’image après avoir appliqué l’aspect à l’image dans un UIImageView

Je charge une image dans une vue d’image avec le mode “Aspect Fit”. J’ai besoin de connaître la taille de mon image. S’il vous plaît aider.

S’il vous plaît voir la réponse de @ Paul-de-Lange au lieu de celle-ci


Je ne pouvais rien trouver dans une variable facilement accessible qui avait ceci, alors voici le moyen de la force brute:

- (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); } 

Pourquoi ne pas utiliser la fonction OS AVMakeRectWithAspectRatioInsideRect ?

Je voulais utiliser AVMakeRectWithAspectRatioInsideRect() sans inclure le framework AVFoundation .

J’ai donc implémenté les deux fonctions suivantes:

 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; } 

Edit: Optimisé ci-dessous en supprimant les divisions en double.

 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; } 

Fin de l’édition

Cela prend une taille donnée (premier paramètre) et conserve ses proportions. Il remplit ensuite les limites données (second paramètre) autant que possible sans violer les proportions.

En utilisant ceci pour répondre à la question initiale:

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

Notez comment l’image détermine le rapport d’aspect, tandis que la vue d’image détermine la taille à remplir.

Les commentaires sont les bienvenus.

Cette fonction simple calculera la taille de l’image après ajustement de l’aspect:

  -(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); } 

Peut-être ne correspond pas à votre cas, mais cette approche simple résout mon problème dans un cas similaire:

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

Une fois que la vue image exécute sizeToFit si vous interrogez l’ imageView.frame.size, vous obtiendrez la nouvelle taille d’affichage de l’image qui correspond à la nouvelle taille d’image.

Pour une utilisation rapide sous le code

 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) } 

Et fonction d’appel

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

Je voulais également calculer la hauteur après l’application du format d’image pour pouvoir calculer la hauteur de la cellule de la vue de table. Donc, j’ai réalisé grâce à peu de maths

 ratio = width / height 

et la hauteur deviendrait

 height = width / ratio 

Donc l’extrait de code serait

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

Swift 3 Version lisible par l’homme

 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; } 

La réponse acceptée est incroyablement compliquée et échoue pour certains cas extrêmes. Je pense que cette solution est beaucoup plus élégante:

 - (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); } 

Voici ma solution pour le même problème: https://github.com/alexgarbarev/UIImageView-ImageFrame

Avantages:

  • Modes UIViewContentMode pris en charge
  • Peut interroger pour les balances et pour rect séparément
  • Peut poser des questions sur le cadre d’image directement depuis UIImageView

Cette ligne unique peut faire ce travail

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

J’utilise ce qui suit dans 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 } 

Je l’utilise comme ceci:

 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) 

Extension 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: l’ image pour l’image .aspectFit est –

 import AVFoundation 

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

Les méthodes mentionnées ci-dessus ne donnent jamais les valeurs requirejses.Comme l’ajustement d’aspect conserve le même rapport d’aspect, nous avons simplement besoin de calculs simples pour calculer les valeurs

Détecter le ratio d’aspect

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

Obtenez les nouvelles valeurs

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

Si vous ne connaissez que la largeur de l’image et que la hauteur de l’image est dynamic, vous devez mettre à l’échelle la hauteur de l’image en fonction de la largeur donnée pour supprimer les espaces blancs au-dessus et au-dessous de votre image. Utilisez la méthode suivante pour mettre à l’échelle la hauteur de l’image en fonction de la largeur standard de votre écran.

 -(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; } 

Et appelez-le depuis votre méthode cellForRowAtIndexPath:

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

Voici ma solution AVFoundation-less.

Voici d’abord une extension CGSize pour calculer une taille qui conviendrait à une autre taille:

 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) } } 

Donc, la solution au problème d’OP se résume à:

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

En outre, voici une autre extension pour ajuster un rect dans un autre rect (il utilise l’extension CGSize ci-dessus):

 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 } }