Comment redimensionner / optimiser facilement une taille d'image avec iOS?


114

Mon application télécharge un ensemble de fichiers image à partir du réseau et les enregistre sur le disque iPhone local. Certaines de ces images sont assez grandes (largeurs supérieures à 500 pixels, par exemple). Étant donné que l'iPhone n'a même pas un écran assez grand pour afficher l'image dans sa taille d'origine, je prévois de redimensionner l'image à quelque chose d'un peu plus petit pour économiser de l'espace / des performances.

De plus, certaines de ces images sont des JPEG et elles ne sont pas enregistrées selon le paramètre de qualité habituel de 60%.

Comment puis-je redimensionner une image avec le SDK iPhone et comment modifier le paramètre de qualité d'une image JPEG?

Réponses:


246

Quelques suggestions sont fournies pour répondre à cette question . J'avais suggéré la technique décrite dans cet article , avec le code correspondant:

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

   return newImage;
}

En ce qui concerne le stockage de l'image, le format d'image le plus rapide à utiliser avec l'iPhone est PNG, car il a des optimisations pour ce format. Cependant, si vous souhaitez stocker ces images au format JPEG, vous pouvez prendre votre UIImage et effectuer les opérations suivantes:

NSData *dataForJPEGFile = UIImageJPEGRepresentation(theImage, 0.6);

Cela crée une instance NSData contenant les octets bruts d'une image JPEG avec un paramètre de qualité de 60%. Le contenu de cette instance NSData peut ensuite être écrit sur le disque ou mis en cache en mémoire.


1
monsieur ... j'ai écrit la même logique mais une ligne droite blanche apparaîtra (portrait) sur le côté droit plz donnez-moi une solution
Nag_iphone

1
Salut, comment gérer le maintien du rapport hauteur / largeur et des clips à relier lors du redimensionnement? Dans mon cas, lorsque je redimensionne une image qui a une ration différente de celle de "newsize", j'obtiens une image redimensionnée déformée. Merci!
Van Du Tran

1
Cela a fonctionné dans le passé, mais dans iOS5.0.1 et versions ultérieures, cela entraîne une fuite de mémoire. Une autre façon d'accomplir cela?
Usman Nisar

Il est recommandé d'utiliser [image drawInRect: rect blendMode: kCGBlendModeCopy alpha: 1.0] pour améliorer les performances (donc draw n'a pas à faire de calcul de fusion pendant le dessin
cdemiris99

Vous devez utiliser UIGraphicsBeginImageContextWithOptions (size, NO, 0.0); où 0.0 utilisera l'échelle de l'écran principal pour prendre en charge la rétine et au-dessus. Apple déclare "Vous devez généralement éviter d'appeler la fonction UIGraphicsBeginImageContext de même nom (sauf comme solution de secours pour la compatibilité descendante)".
Brad Goss

65

Le moyen le plus simple et le plus simple de redimensionner vos images serait le suivant

float actualHeight = image.size.height;
float actualWidth = image.size.width;
float imgRatio = actualWidth/actualHeight;
float maxRatio = 320.0/480.0;

if(imgRatio!=maxRatio){
    if(imgRatio < maxRatio){
        imgRatio = 480.0 / actualHeight;
        actualWidth = imgRatio * actualWidth;
        actualHeight = 480.0;
    }
    else{
        imgRatio = 320.0 / actualWidth;
        actualHeight = imgRatio * actualHeight;
        actualWidth = 320.0;
    }
}
CGRect rect = CGRectMake(0.0, 0.0, actualWidth, actualHeight);
UIGraphicsBeginImageContext(rect.size);
[image drawInRect:rect];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

C'est beau. J'ai pu réduire les images envoyées à un serveur d'environ 1 Mo à 100 k tout en conservant la résolution d'affichage de la rétine (même si j'ai changé les valeurs 320,0 et 480,0 en 640,0 et 1136,0) et j'ai également effectué une compression JPEG après la mise à l'échelle: UIImageJPEGRepresentation (img, 0,7f);
Keller le

2
Et si le rapport d'image et le rapport maximum s'avéraient égaux? Par exemple, si la taille iamge est de 3200x4800?
akshay1188

Cela a fonctionné dans le passé, mais dans iOS5.0.1 et versions ultérieures, cela entraîne une fuite de mémoire. Une autre façon d'accomplir cela?
Usman Nisar

25

Les méthodes ci-dessus fonctionnent bien pour les petites images, mais lorsque vous essayez de redimensionner une très grande image, vous allez rapidement manquer de mémoire et planter l'application. Un bien meilleur moyen consiste à CGImageSourceCreateThumbnailAtIndexredimensionner l'image sans la décoder complètement au préalable.

Si vous avez le chemin d'accès à l'image que vous souhaitez redimensionner, vous pouvez utiliser ceci:

- (void)resizeImageAtPath:(NSString *)imagePath {
    // Create the image source (from path)
    CGImageSourceRef src = CGImageSourceCreateWithURL((__bridge CFURLRef) [NSURL fileURLWithPath:imagePath], NULL);

    // To create image source from UIImage, use this
    // NSData* pngData =  UIImagePNGRepresentation(image);
    // CGImageSourceRef src = CGImageSourceCreateWithData((CFDataRef)pngData, NULL);

    // Create thumbnail options
    CFDictionaryRef options = (__bridge CFDictionaryRef) @{
            (id) kCGImageSourceCreateThumbnailWithTransform : @YES,
            (id) kCGImageSourceCreateThumbnailFromImageAlways : @YES,
            (id) kCGImageSourceThumbnailMaxPixelSize : @(640)
    };
    // Generate the thumbnail
    CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(src, 0, options); 
    CFRelease(src);
    // Write the thumbnail at path
    CGImageWriteToFile(thumbnail, imagePath);
}

Plus de détails ici .


Merci, cette solution fonctionne à merveille), Connaissez-vous d'autres formats de fichiers qui prennent en charge CGImageSourceen plus des images et des pdfs?
sage444

Merci. Je cherchais un analogue de inSampleSizecelui utilisé par le décodeur d'Android. Et c'est la seule réponse qui offre un moyen de réduire une image d'une manière efficace en mémoire.
Stan Mots

J'ai eu d'excellents résultats avec cela fonctionnant directement avec les fichiers en stockage, fonctionne également avec des images en mémoire mais pas aussi rapidement (pour charger dans la grande image dans une UIImage puis mettre à l'échelle).
Kendall Helmstetter Gelner

Ne fonctionne pas dans l'extension de partage. L'application se bloque toujours avec une très grande image.
George

18

La meilleure façon de redimensionner les images sans perdre le rapport hauteur / largeur (c'est-à-dire sans étirer l'image) est d'utiliser cette méthode:

//to scale images without changing aspect ratio
+ (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize {

    float width = newSize.width;
    float height = newSize.height;

    UIGraphicsBeginImageContext(newSize);
    CGRect rect = CGRectMake(0, 0, width, height);

    float widthRatio = image.size.width / width;
    float heightRatio = image.size.height / height;
    float divisor = widthRatio > heightRatio ? widthRatio : heightRatio;

    width = image.size.width / divisor;
    height = image.size.height / divisor;

    rect.size.width  = width;
    rect.size.height = height;

    //indent in case of width or height difference
    float offset = (width - height) / 2;
    if (offset > 0) {
        rect.origin.y = offset;
    }
    else {
        rect.origin.x = -offset;
    }

    [image drawInRect: rect];

    UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return smallImage;

}

Ajoutez cette méthode à votre classe Utility afin de pouvoir l'utiliser tout au long de votre projet et y accéder comme suit:

xyzImageView.image = [Utility scaleImage:yourUIImage toSize:xyzImageView.frame.size];

Cette méthode prend en charge la mise à l'échelle tout en conservant les proportions. Il ajoute également des retraits à l'image au cas où l'image réduite a plus de largeur que de hauteur (ou vice versa).


8

Si vous avez le contrôle sur le serveur, je vous recommande fortement de redimensionner le côté serveur d'images avec ImageMagik . Le téléchargement d'images de grande taille et leur redimensionnement sur le téléphone est un gaspillage de nombreuses ressources précieuses - bande passante, batterie et mémoire. Tous sont rares sur les téléphones.


2
FTFQ: "Mon application télécharge un ensemble de fichiers image à partir du réseau,"
Rog

Cela pourrait être une réponse pertinente. La question indique que les images sont en cours de téléchargement à partir du réseau. Si l'OP peut travailler avec le côté serveur d'images, il devrait le faire. S'il ne peut pas, la réponse aidera davantage.
Joshua Dance

6

J'ai développé une solution ultime pour la mise à l'échelle d'image dans Swift.

Vous pouvez l'utiliser pour redimensionner l'image pour remplir, remplir d'aspect ou ajuster l'aspect à la taille spécifiée.

Vous pouvez aligner l'image au centre ou à l'un des quatre bords et quatre coins.

Et vous pouvez également réduire l'espace supplémentaire qui est ajouté si les rapports hauteur / largeur de l'image d'origine et de la taille cible ne sont pas égaux.

enum UIImageAlignment {
    case Center, Left, Top, Right, Bottom, TopLeft, BottomRight, BottomLeft, TopRight
}

enum UIImageScaleMode {
    case Fill,
    AspectFill,
    AspectFit(UIImageAlignment)
}

extension UIImage {
    func scaleImage(width width: CGFloat? = nil, height: CGFloat? = nil, scaleMode: UIImageScaleMode = .AspectFit(.Center), trim: Bool = false) -> UIImage {
        let preWidthScale = width.map { $0 / size.width }
        let preHeightScale = height.map { $0 / size.height }
        var widthScale = preWidthScale ?? preHeightScale ?? 1
        var heightScale = preHeightScale ?? widthScale
        switch scaleMode {
        case .AspectFit(_):
            let scale = min(widthScale, heightScale)
            widthScale = scale
            heightScale = scale
        case .AspectFill:
            let scale = max(widthScale, heightScale)
            widthScale = scale
            heightScale = scale
        default:
            break
        }
        let newWidth = size.width * widthScale
        let newHeight = size.height * heightScale
        let canvasWidth = trim ? newWidth : (width ?? newWidth)
        let canvasHeight = trim ? newHeight : (height ?? newHeight)
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(canvasWidth, canvasHeight), false, 0)

        var originX: CGFloat = 0
        var originY: CGFloat = 0
        switch scaleMode {
        case .AspectFit(let alignment):
            switch alignment {
            case .Center:
                originX = (canvasWidth - newWidth) / 2
                originY = (canvasHeight - newHeight) / 2
            case .Top:
                originX = (canvasWidth - newWidth) / 2
            case .Left:
                originY = (canvasHeight - newHeight) / 2
            case .Bottom:
                originX = (canvasWidth - newWidth) / 2
                originY = canvasHeight - newHeight
            case .Right:
                originX = canvasWidth - newWidth
                originY = (canvasHeight - newHeight) / 2
            case .TopLeft:
                break
            case .TopRight:
                originX = canvasWidth - newWidth
            case .BottomLeft:
                originY = canvasHeight - newHeight
            case .BottomRight:
                originX = canvasWidth - newWidth
                originY = canvasHeight - newHeight
            }
        default:
            break
        }
        self.drawInRect(CGRectMake(originX, originY, newWidth, newHeight))
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

Vous trouverez ci-dessous des exemples d'application de cette solution.

Le rectangle gris est l'image du site cible sera redimensionnée. Les cercles bleus dans un rectangle bleu clair sont l'image (j'ai utilisé des cercles car il est facile de voir quand ils sont mis à l'échelle sans préserver l'aspect). La couleur orange clair marque les zones qui seront coupées si vous passez trim: true.

Ajustement de l'aspect avant et après la mise à l'échelle:

Aspect fit 1 (avant) Aspect fit 1 (après)

Un autre exemple d' ajustement d'aspect :

Aspect fit 2 (avant) Aspect fit 2 (après)

Ajustement d'aspect avec alignement supérieur:

Aspect fit 3 (avant) Aspect fit 3 (après)

Remplissage d'aspect :

Remplissage d'aspect (avant) Remplissage d'aspect (après)

Remplir :

Remplir (avant) Remplir (après)

J'ai utilisé la mise à l'échelle dans mes exemples parce que c'est plus simple à démontrer, mais la solution fonctionne également pour la réduction d'échelle comme en question.

Pour la compression JPEG, vous devez utiliser ceci:

let compressionQuality: CGFloat = 0.75 // adjust to change JPEG quality
if let data = UIImageJPEGRepresentation(image, compressionQuality) {
  // ...
}

Vous pouvez consulter mon essentiel avec le terrain de jeu Xcode.


3

Pour Swift 3, le code ci-dessous met l'image à l'échelle en conservant le rapport hauteur / largeur. Vous pouvez en savoir plus sur ImageContext dans la documentation d'Apple :

extension UIImage {
    class func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage {
        let scale = newHeight / image.size.height
        let newWidth = image.size.width * scale
        UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
        image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage!
    }
}

Pour l'utiliser, appelez la resizeImage()méthode:

UIImage.resizeImage(image: yourImageName, newHeight: yourImageNewHeight)

2

vous pouvez utiliser ce code pour redimensionner l'image à la taille requise.

+ (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize
{
    CGSize actSize = image.size;
    float scale = actSize.width/actSize.height;

    if (scale < 1) {
        newSize.height = newSize.width/scale;
    } 
    else {
        newSize.width = newSize.height*scale;
    }

    UIGraphicsBeginImageContext(newSize);
    [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

2

Selon cette session, iOS Memory Deep Dive , nous ferions mieux de l'utiliser ImageIOpour réduire les images.

Le mal d'utiliser des UIImageimages bas de gamme.

  • Décompresse l'image originale en mémoire
  • Les transformations d'espace de coordonnées internes coûtent cher

Utilisation ImageIO

  • ImageIO peut lire les tailles d'image et les informations de métadonnées sans salir la mémoire.

  • ImageIO peut redimensionner les images au prix d'une image redimensionnée uniquement.

À propos de l'image en mémoire

  • L'utilisation de la mémoire est liée aux dimensions des images et non à la taille du fichier.
  • UIGraphicsBeginImageContextWithOptionsutilise toujours le SRGBformat de rendu, qui utilise 4 octets par pixel.
  • Une image comporte load -> decode -> render3 phases.
  • UIImage coûte cher pour le dimensionnement et le redimensionnement

Pour l'image suivante, si vous utilisez, UIGraphicsBeginImageContextWithOptions nous n'avons besoin que de 590 Ko pour charger une image, alors que nous avons besoin de 2048 pixels x 1536 pixels x 4 bytes per pixel= 10 Mo lors du décodage entrez la description de l'image ici

tandis que UIGraphicsImageRenderer, introduit dans iOS 10, choisira automatiquement le meilleur format graphique dans iOS12. Cela signifie que vous pouvez économiser 75% de la mémoire en remplaçant UIGraphicsBeginImageContextWithOptionspar UIGraphicsImageRenderersi vous n'avez pas besoin de SRGB.

Ceci est mon article sur les images iOS en mémoire

func resize(url: NSURL, maxPixelSize: Int) -> CGImage? {
    let imgSource = CGImageSourceCreateWithURL(url, nil)
    guard let imageSource = imgSource else {
        return nil
    }

    var scaledImage: CGImage?
    let options: [NSString: Any] = [
            // The maximum width and height in pixels of a thumbnail.
            kCGImageSourceThumbnailMaxPixelSize: maxPixelSize,
            kCGImageSourceCreateThumbnailFromImageAlways: true,
            // Should include kCGImageSourceCreateThumbnailWithTransform: true in the options dictionary. Otherwise, the image result will appear rotated when an image is taken from camera in the portrait orientation.
            kCGImageSourceCreateThumbnailWithTransform: true
    ]
    scaledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary)

    return scaledImage
}


let filePath = Bundle.main.path(forResource:"large_leaves_70mp", ofType: "jpg")

let url = NSURL(fileURLWithPath: filePath ?? "")

let image = resize(url: url, maxPixelSize: 600)

ou

// Downsampling large images for display at smaller size
func downsample(imageAt imageURL: URL, to pointSize: CGSize, scale: CGFloat) -> UIImage {
    let imageSourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
    let imageSource = CGImageSourceCreateWithURL(imageURL as CFURL, imageSourceOptions)!
    let maxDimensionInPixels = max(pointSize.width, pointSize.height) * scale
    let downsampleOptions =
        [kCGImageSourceCreateThumbnailFromImageAlways: true,
        kCGImageSourceShouldCacheImmediately: true,
        // Should include kCGImageSourceCreateThumbnailWithTransform: true in the options dictionary. Otherwise, the image result will appear rotated when an image is taken from camera in the portrait orientation.
        kCGImageSourceCreateThumbnailWithTransform: true,
        kCGImageSourceThumbnailMaxPixelSize: maxDimensionInPixels] as CFDictionary
    let downsampledImage =
        CGImageSourceCreateThumbnailAtIndex(imageSource, 0, downsampleOptions)!
    return UIImage(cgImage: downsampledImage)
}

1

Un problème qui peut survenir sur les écrans Retina est que l'échelle de l'image est définie par ImageCapture ou plus. Les fonctions de redimensionnement ci-dessus ne changeront pas cela. Dans ces cas, le redimensionnement ne fonctionnera pas correctement.

Dans le code ci-dessous, l'échelle est définie sur 1 (non mise à l'échelle) et l'image renvoyée a la taille que vous attendez. Ceci est fait dans l' UIGraphicsBeginImageContextWithOptionsappel.

-(UIImage *)resizeImage :(UIImage *)theImage :(CGSize)theNewSize {
    UIGraphicsBeginImageContextWithOptions(theNewSize, NO, 1.0);
    [theImage drawInRect:CGRectMake(0, 0, theNewSize.width, theNewSize.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

1

Ajout à la multitude de réponses ici, mais j'ai opté pour une solution qui redimensionne par taille de fichier, plutôt que par dimensions.

Cela réduira à la fois les dimensions et la qualité de l'image jusqu'à ce qu'elle atteigne votre taille donnée.

func compressTo(toSizeInMB size: Double) -> UIImage? {
    let bytes = size * 1024 * 1024
    let sizeInBytes = Int(bytes)
    var needCompress:Bool = true
    var imgData:Data?
    var compressingValue:CGFloat = 1.0

    while (needCompress) {

        if let resizedImage = scaleImage(byMultiplicationFactorOf: compressingValue), let data: Data = UIImageJPEGRepresentation(resizedImage, compressingValue) {

            if data.count < sizeInBytes || compressingValue < 0.1 {
                needCompress = false
                imgData = data
            } else {
                compressingValue -= 0.1
            }
        }
    }

    if let data = imgData {
        print("Finished with compression value of: \(compressingValue)")
        return UIImage(data: data)
    }
    return nil
}

private func scaleImage(byMultiplicationFactorOf factor: CGFloat) -> UIImage? {
    let size = CGSize(width: self.size.width*factor, height: self.size.height*factor)
    UIGraphicsBeginImageContext(size)
    draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
    if let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext() {
        UIGraphicsEndImageContext()
        return newImage;
    }
    return nil
}

Crédit pour la mise à l' échelle par taille de réponse


1

Version Swift

func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage? {

    let scale = newWidth / image.size.width
    let newHeight = CGFloat(200.0)
    UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
    image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))

    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage
}

0

J'ai fini par utiliser la technique de Brads pour créer une scaleToFitWidthméthode UIImage+Extensionssi cela est utile à quelqu'un ...

-(UIImage *)scaleToFitWidth:(CGFloat)width
{
    CGFloat ratio = width / self.size.width;
    CGFloat height = self.size.height * ratio;

    NSLog(@"W:%f H:%f",width,height);

    UIGraphicsBeginImageContext(CGSizeMake(width, height));
    [self drawInRect:CGRectMake(0.0f,0.0f,width,height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

puis où tu veux

#import "UIImage+Extensions.h"

UIImage *newImage = [image scaleToFitWidth:100.0f];

Il convient également de noter que vous pouvez déplacer cela plus bas dans une UIView+Extensionsclasse si vous souhaitez rendre des images à partir d'un UIView


0

Je voulais juste répondre à cette question pour les programmeurs de Cocoa Swift. Cette fonction renvoie NSImage avec une nouvelle taille. Vous pouvez utiliser cette fonction comme ceci.

        let sizeChangedImage = changeImageSize(image, ratio: 2)






 // changes image size

    func changeImageSize (image: NSImage, ratio: CGFloat) -> NSImage   {

    // getting the current image size
    let w = image.size.width
    let h = image.size.height

    // calculating new size
    let w_new = w / ratio 
    let h_new = h / ratio 

    // creating size constant
    let newSize = CGSizeMake(w_new ,h_new)

    //creating rect
    let rect  = NSMakeRect(0, 0, w_new, h_new)

    // creating a image context with new size
    let newImage = NSImage.init(size:newSize)



    newImage.lockFocus()

        // drawing image with new size in context
        image.drawInRect(rect)

    newImage.unlockFocus()


    return newImage

}

0

Si votre image se trouve dans le répertoire de documents, ajoutez cette extension d' URL :

extension URL {
    func compressedImageURL(quality: CGFloat = 0.3) throws -> URL? {
        let imageData = try Data(contentsOf: self)
        debugPrint("Image file size before compression: \(imageData.count) bytes")

        let compressedURL = NSURL.fileURL(withPath: NSTemporaryDirectory() + NSUUID().uuidString + ".jpg")

        guard let actualImage = UIImage(data: imageData) else { return nil }
        guard let compressedImageData = UIImageJPEGRepresentation(actualImage, quality) else {
            return nil
        }
        debugPrint("Image file size after compression: \(compressedImageData.count) bytes")

        do {
            try compressedImageData.write(to: compressedURL)
            return compressedURL
        } catch {
            return nil
        }
    }
}

Usage:

guard let localImageURL = URL(string: "< LocalImagePath.jpg >") else {
    return
}

//Here you will get URL of compressed image
guard let compressedImageURL = try localImageURL.compressedImageURL() else {
    return
}

debugPrint("compressedImageURL: \(compressedImageURL.absoluteString)")

Remarque: - Remplacez <LocalImagePath.jpg> par le chemin de votre image jpg locale.


-1

Si quelqu'un cherche toujours une meilleure option

-(UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)targetSize {


    UIImage *sourceImage = image;
    UIImage *newImage = nil;

    CGSize imageSize = sourceImage.size;
    CGFloat width = imageSize.width;
    CGFloat height = imageSize.height;

    CGFloat targetWidth = targetSize.width;
    CGFloat targetHeight = targetSize.height;

    CGFloat scaleFactor = 0.0;
    CGFloat scaledWidth = targetWidth;
    CGFloat scaledHeight = targetHeight;

    CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

    if (CGSizeEqualToSize(imageSize, targetSize) == NO) {

        CGFloat widthFactor = targetWidth / width;
        CGFloat heightFactor = targetHeight / height;

        if (widthFactor < heightFactor)
            scaleFactor = widthFactor;
        else
            scaleFactor = heightFactor;

        scaledWidth  = width * scaleFactor;
        scaledHeight = height * scaleFactor;

        // center the image


        if (widthFactor < heightFactor) {
            thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
        } else if (widthFactor > heightFactor) {
            thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
        }
    }


    // this is actually the interesting part:

    UIGraphicsBeginImageContext(targetSize);

    CGRect thumbnailRect = CGRectZero;
    thumbnailRect.origin = thumbnailPoint;
    thumbnailRect.size.width  = scaledWidth;
    thumbnailRect.size.height = scaledHeight;

    [sourceImage drawInRect:thumbnailRect];

    newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    if(newImage == nil) NSLog(@"could not scale image");


    return newImage ;

}

-1
- (UIImage *)resizeImage:(UIImage*)image newSize:(CGSize)newSize {
    CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
    CGImageRef imageRef = image.CGImage;

    UIGraphicsBeginImageContextWithOptions(newSize, NO, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
    CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, newSize.height);

    CGContextConcatCTM(context, flipVertical);
    CGContextDrawImage(context, newRect, imageRef);

    CGImageRef newImageRef = CGBitmapContextCreateImage(context);
    UIImage *newImage = [UIImage imageWithCGImage:newImageRef];

    CGImageRelease(newImageRef);
    UIGraphicsEndImageContext();

    return newImage;
}

Veuillez fournir au moins une explication du code dans votre réponse. Et formatez également le code à l'aide de l'éditeur de réponses pour le rendre lisible.
xpereta

-2

Pour redimensionner une image, j'ai de meilleurs résultats (graphiques) en utilisant cette fonction au lieu de DrawInRect:

- (UIImage*) reduceImageSize:(UIImage*) pImage newwidth:(float) pWidth
{
    float lScale = pWidth / pImage.size.width;
    CGImageRef cgImage = pImage.CGImage;
    UIImage   *lResult = [UIImage imageWithCGImage:cgImage scale:lScale
                            orientation:UIImageOrientationRight];
    return lResult;
}

Le rapport hauteur / largeur est pris en charge automatiquement

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.