Redimensionner UIImage en conservant le rapport hauteur / largeur et la largeur


136

J'ai vu dans de nombreux articles pour redimensionner l'image en gardant les proportions. Ces fonctions utilisent les points fixes (Largeur et Hauteur) pour RECT lors du redimensionnement. Mais dans mon projet, je dois redimensionner la vue en fonction de la largeur seule, la hauteur doit être prise automatiquement en fonction du rapport hauteur / largeur. n'importe qui m'aide à y parvenir.

Réponses:


228

La méthode de Srikar fonctionne très bien, si vous connaissez à la fois la hauteur et la largeur de votre nouvelle taille. Si, par exemple, vous ne connaissez que la largeur à laquelle vous souhaitez mettre à l'échelle et que vous ne vous souciez pas de la hauteur, vous devez d'abord calculer le facteur d'échelle de la hauteur.

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

22
Vous n'avez pas vraiment besoin de la newWidthvariable ici, c'est déjà i_width.
Matthew Quiros

2
Vous devez également diviser par hauteur et comparer les facteurs d'échelle en utilisant celui qui est le plus proche de 0. le code ci-dessus ne fonctionnera qu'avec des images plus larges que hautes
IceForge

1
J'aurais juste besoin de diviser par hauteur si je voulais également connaître mon rapport de hauteur et l'ajuster en mettant à l'échelle la largeur ou la hauteur. mais puisque le TO a demandé explicitement de garder le rapport et la largeur, et non la largeur ou la hauteur, ma réponse est tout à fait correcte.
Maverick1er

12
Excellente réponse, merci. Une dernière chose: si vous rencontrez une perte de qualité d'image en utilisant cette méthode, utilisez UIGraphicsBeginImageContextWithOptions(CGSizeMake(newWidth, newHeight), NO, 0);plutôtUIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
skornos

57

Si vous ne savez pas si l'image sera portrait ou paysage (par exemple, l'utilisateur prend une photo avec un appareil photo), j'ai créé une autre méthode qui prend les paramètres de largeur et de hauteur maximum.

Disons que vous avez un UIImage *myLargeImagerapport 4: 3.

UIImage *myResizedImage = [ImageUtilities imageWithImage:myLargeImage 
                                        scaledToMaxWidth:1024 
                                               maxHeight:1024];

La UIImage redimensionnée sera 1024x768 si paysage; 768x1024 si portrait. Cette méthode générera également des images de résolution plus élevée pour l'affichage de la rétine.

+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)size {
    if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
        UIGraphicsBeginImageContextWithOptions(size, NO, [[UIScreen mainScreen] scale]);
    } else {
        UIGraphicsBeginImageContext(size);
    }
    [image drawInRect:CGRectMake(0, 0, size.width, size.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();    
    UIGraphicsEndImageContext();

    return newImage;
}

+ (UIImage *)imageWithImage:(UIImage *)image scaledToMaxWidth:(CGFloat)width maxHeight:(CGFloat)height {
    CGFloat oldWidth = image.size.width;
    CGFloat oldHeight = image.size.height;

    CGFloat scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;

    CGFloat newHeight = oldHeight * scaleFactor;
    CGFloat newWidth = oldWidth * scaleFactor;
    CGSize newSize = CGSizeMake(newWidth, newHeight);

    return [ImageUtilities imageWithImage:image scaledToSize:newSize];
}

1
C'est la meilleure chose, mais cela retourne toujours le double de ma taille définie
Mashhadi

2
Si vous ne voulez que réduire la taille, pas augmenter la taille, n'oubliez pas de démarrer la méthode imageWithImage: scaledToMaxWidth: maxHeight: avec: if (image.size.width <width && image.size.height <height) {return image; }
Arjan

5
Pour tenir dans une largeur max et hauteur max, vous avez besoin du ratio minimum comme le facteur d'échelle: min(ratioX, ratioY). Sinon, si la largeur est plus grande, elle peut ne pas correspondre à la hauteur maximale.
Jason Sturges

ImageUtilities où il est?
tong

42

Meilleure réponse Maverick 1st est correctement traduite en Swift (fonctionne avec le dernier swift 3 ):

func imageWithImage (sourceImage:UIImage, scaledToWidth: CGFloat) -> UIImage {
    let oldWidth = sourceImage.size.width
    let scaleFactor = scaledToWidth / oldWidth

    let newHeight = sourceImage.size.height * scaleFactor
    let newWidth = oldWidth * scaleFactor

    UIGraphicsBeginImageContext(CGSize(width:newWidth, height:newHeight))
    sourceImage.draw(in: CGRect(x:0, y:0, width:newWidth, height:newHeight))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage!
}

38

merci @ Maverick1st l'algorithme, je l'ai implémenté Swift, dans mon cas, la hauteur est le paramètre d'entrée

class func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage {

    let scale = newHeight / image.size.height
    let newWidth = image.size.width * scale
    UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight))
    image.drawInRect(CGRectMake(0, 0, newWidth, newHeight))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage
}

18

Cette méthode est une catégorie sur UIImage. S'adapte à quelques lignes de code à l'aide d'AVFoundation. N'oubliez pas d'importer #import <AVFoundation/AVFoundation.h>.

@implementation UIImage (Helper)

- (UIImage *)imageScaledToFitToSize:(CGSize)size
{
    CGRect scaledRect = AVMakeRectWithAspectRatioInsideRect(self.size, CGRectMake(0, 0, size.width, size.height));
    UIGraphicsBeginImageContextWithOptions(size, NO, 0);
    [self drawInRect:scaledRect];
    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return scaledImage;
}

@end

2
J'ai trouvé cela pour me donner les meilleurs résultats avec la plus petite empreinte mémoire. +1
Tommie C.

11

Version Swift 5 d'ajustement de l'aspect à la hauteur , basée sur la réponse de @ János

Utilise l' UIGraphicsImageRendererAPI moderne , donc un UIImageretour valide est garanti.

extension UIImage
{
    /// Given a required height, returns a (rasterised) copy
    /// of the image, aspect-fitted to that height.

    func aspectFittedToHeight(_ newHeight: CGFloat) -> UIImage
    {
        let scale = newHeight / self.size.height
        let newWidth = self.size.width * scale
        let newSize = CGSize(width: newWidth, height: newHeight)
        let renderer = UIGraphicsImageRenderer(size: newSize)

        return renderer.image { _ in
            self.draw(in: CGRect(origin: .zero, size: newSize))
        }
    }
}

Vous pouvez l'utiliser en conjonction avec un élément d'image PDF (vectoriel), pour préserver la qualité quelle que soit la taille de rendu.


7

Le moyen le plus simple consiste à définir le cadre de votre UIImageViewet à définir l' contentModeune des options de redimensionnement.

Le code va comme ceci - Cela peut être utilisé comme une méthode utilitaire -

+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize
{
    UIGraphicsBeginImageContext(newSize);
    [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();    
    UIGraphicsEndImageContext();
    return newImage;
}

Gardez à l'esprit que l'OP n'a pas mentionné d'UIImageView. Au lieu de cela, il voulait vraisemblablement ajuster l'aspect d'une [copie d'une] UIImage directement, ce qui est une chose très pratique à avoir lorsque vous travaillez avec CoreGraphics.
Womble

6

Par programme:

imageView.contentMode = UIViewContentModeScaleAspectFit;

Storyboard:

entrez la description de l'image ici


cela fonctionne, MAIS en réduisant les empreintes mémoire, vous pouvez faire fonctionner l'application plus rapidement, par exemple en chargeant beaucoup de vignettes.
ingconti

C'est une UIImageView, pas une UIImage. Parfois, vous devez dessiner sans UIImageView.
Womble

5

Eh bien, nous avons quelques bonnes réponses ici pour redimensionner l'image, mais je modifie simplement selon mes besoins. J'espère que cela aidera quelqu'un comme moi.

Ma condition était

  1. Si la largeur de l'image est supérieure à 1920, redimensionnez-la avec une largeur de 1920 et en maintenant la hauteur avec le rapport hauteur / largeur d'origine.
  2. Si la hauteur de l'image est supérieure à 1080, redimensionnez-la avec une hauteur de 1080 et en conservant la largeur avec le rapport hauteur / largeur d'origine.

 if (originalImage.size.width > 1920)
 {
        CGSize newSize;
        newSize.width = 1920;
        newSize.height = (1920 * originalImage.size.height) / originalImage.size.width;
        originalImage = [ProfileEditExperienceViewController imageWithImage:originalImage scaledToSize:newSize];        
 }

 if (originalImage.size.height > 1080)
 {
            CGSize newSize;
            newSize.width = (1080 * originalImage.size.width) / originalImage.size.height;
            newSize.height = 1080;
            originalImage = [ProfileEditExperienceViewController imageWithImage:originalImage scaledToSize:newSize];

 }

+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize
{
        UIGraphicsBeginImageContext(newSize);
        [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return newImage;
}

Merci à @ Srikar Appal , pour le redimensionnement, j'ai utilisé sa méthode.

Vous pouvez également vérifier cela pour le calcul de redimensionnement.


4

Importez simplement AVFoundation et utilisez AVMakeRectWithAspectRatioInsideRect(CGRectCurrentSize, CGRectMake(0, 0, YOUR_WIDTH, CGFLOAT_MAX)


2

Pour améliorer la réponse de Ryan:

   + (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)size {
CGFloat oldWidth = image.size.width;
        CGFloat oldHeight = image.size.height;

//You may need to take some retina adjustments into consideration here
        CGFloat scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;

return [UIImage imageWithCGImage:image.CGImage scale:scaleFactor orientation:UIImageOrientationUp];
    }

2
extension UIImage {

    /// Returns a image that fills in newSize
    func resizedImage(newSize: CGSize) -> UIImage? {
        guard size != newSize else { return self }

    let hasAlpha = false
    let scale: CGFloat = 0.0
    UIGraphicsBeginImageContextWithOptions(newSize, !hasAlpha, scale)
        UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)

        draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
        let newImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }

    /// Returns a resized image that fits in rectSize, keeping it's aspect ratio
    /// Note that the new image size is not rectSize, but within it.
    func resizedImageWithinRect(rectSize: CGSize) -> UIImage? {
        let widthFactor = size.width / rectSize.width
        let heightFactor = size.height / rectSize.height

        var resizeFactor = widthFactor
        if size.height > size.width {
            resizeFactor = heightFactor
        }

        let newSize = CGSize(width: size.width / resizeFactor, height: size.height / resizeFactor)
        let resized = resizedImage(newSize: newSize)

        return resized
    }
}

Lorsque l'échelle est définie sur 0,0, le facteur d'échelle de l'écran principal est utilisé, qui pour les écrans Retina est de 2,0 ou plus (3,0 sur l'iPhone 6 Plus).


1

Solution de Ryan @Ryan en code SWIFT

utilisation:

 func imageWithSize(image: UIImage,size: CGSize)->UIImage{
    if UIScreen.mainScreen().respondsToSelector("scale"){
        UIGraphicsBeginImageContextWithOptions(size,false,UIScreen.mainScreen().scale);
    }
    else
    {
         UIGraphicsBeginImageContext(size);
    }

    image.drawInRect(CGRectMake(0, 0, size.width, size.height));
    var newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

//Summon this function VVV
func resizeImageWithAspect(image: UIImage,scaledToMaxWidth width:CGFloat,maxHeight height :CGFloat)->UIImage
{
    let oldWidth = image.size.width;
    let oldHeight = image.size.height;

    let scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;

    let newHeight = oldHeight * scaleFactor;
    let newWidth = oldWidth * scaleFactor;
    let newSize = CGSizeMake(newWidth, newHeight);

    return imageWithSize(image, size: newSize);
}

1

Dans Swift 3, il y a quelques changements. Voici une extension de UIImage:

public extension UIImage {
    public func resize(height: CGFloat) -> UIImage? {
        let scale = height / self.size.height
        let width = self.size.width * scale
        UIGraphicsBeginImageContext(CGSize(width: width, height: height))
        self.draw(in: CGRect(x:0, y:0, width:width, height:height))
        let resultImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return resultImage
    }
}

1

Zeeshan Tufail et Womble répondent dans Swift 5 avec de petites améliorations. Ici, nous avons une extension avec 2 fonctions pour redimensionner l'image maxLengthde n'importe quelle dimension et la compression jpeg.

extension UIImage {
    func aspectFittedToMaxLengthData(maxLength: CGFloat, compressionQuality: CGFloat) -> Data {
        let scale = maxLength / max(self.size.height, self.size.width)
        let format = UIGraphicsImageRendererFormat()
        format.scale = scale
        let renderer = UIGraphicsImageRenderer(size: self.size, format: format)
        return renderer.jpegData(withCompressionQuality: compressionQuality) { context in
            self.draw(in: CGRect(origin: .zero, size: self.size))
        }
    }
    func aspectFittedToMaxLengthImage(maxLength: CGFloat, compressionQuality: CGFloat) -> UIImage? {
        let newImageData = aspectFittedToMaxLengthData(maxLength: maxLength, compressionQuality: compressionQuality)
        return UIImage(data: newImageData)
    }
}

0

Celui-ci était parfait pour moi. Conserve le rapport hauteur / largeur et prend un maxLength. La largeur ou la hauteur ne dépassera pasmaxLength

-(UIImage*)imageWithImage: (UIImage*) sourceImage maxLength: (float) maxLength
{
    CGFloat scaleFactor = maxLength / MAX(sourceImage.size.width, sourceImage.size.height);

    float newHeight = sourceImage.size.height * scaleFactor;
    float newWidth = sourceImage.size.width * scaleFactor;

    UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
    [sourceImage drawInRect:CGRectMake(0, 0, newWidth, newHeight)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

0

Calcule la meilleure hauteur de l'image pour la largeur disponible.

import Foundation

public extension UIImage {
    public func height(forWidth width: CGFloat) -> CGFloat {
        let boundingRect = CGRect(
            x: 0,
            y: 0,
            width: width,
            height: CGFloat(MAXFLOAT)
        )
        let rect = AVMakeRect(
            aspectRatio: size,
            insideRect: boundingRect
        )
        return rect.size.height
    }
}

-1

Je l'ai résolu d'une manière beaucoup plus simple

UIImage *placeholder = [UIImage imageNamed:@"OriginalImage.png"];
self.yourImageview.image = [UIImage imageWithCGImage:[placeholder CGImage] scale:(placeholder.scale * 1.5)
                                  orientation:(placeholder.imageOrientation)];

Le multiplicateur de l'échelle définira l'écaillage de l'image, plus le multiplicateur est petit l'image. afin que vous puissiez vérifier ce qui convient à votre écran.

Ou vous pouvez également obtenir le multiplicateur en divisant la largeur de l'image / la largeur de l'écran.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.