117 votes

Quel est le moyen le plus simple de redimensionner/optimiser la taille d'une image avec le SDK de l'iPhone ?

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

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

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

248voto

Brad Larson Points 122629

Quelques suggestions sont fournies en réponse aux questions suivantes cette question . J'avais proposé la technique décrite dans ce poste 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 le PNG, car il est optimisé pour ce format. Cependant, si vous voulez stocker ces images en tant que JPEG, vous pouvez prendre votre UIImage et faire ce qui suit :

NSData *dataForJPEGFile = UIImageJPEGRepresentation(theImage, 0.6);

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

1 votes

J'ai écrit la même logique mais une ligne droite blanche apparaîtra sur le côté droit, donnez-moi la solution.

1 votes

Bonjour, comment faire pour conserver le ratio d'aspect et les clips à lier lors du redimensionnement ? Dans mon cas, lorsque je redimensionne une image qui a un ratio différent de "newsize", j'obtiens une image redimensionnée déformée. Merci de votre compréhension.

1 votes

Cela a fonctionné dans le passé, mais dans iOS5.0.1 et les versions ultérieures, cela entraîne une fuite de mémoire. Y a-t-il un autre moyen d'y parvenir ?

65voto

newgenapps_dev Points 23557

La méthode la plus simple et la plus directe pour redimensionner vos images est la suivante

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

0 votes

C'est magnifique. J'ai pu réduire les images envoyées à un serveur d'environ 1 Mo à 100 Ko tout en conservant la résolution d'un écran rétina (bien que j'aie remplacé les valeurs 320.0 et 480.0 par 640.0 et 1136.0) et j'ai également procédé à une compression JPEG après la mise à l'échelle : UIImageJPEGRepresentation(img, 0.7f) ;

2 votes

Que se passe-t-il si le ratio d'image et le ratio maximum sont égaux ? Par exemple, si la taille de l'image est de 3200x4800 ?

0 votes

Cela a fonctionné dans le passé, mais dans iOS5.0.1 et les versions ultérieures, cela entraîne une fuite de mémoire. Y a-t-il un autre moyen d'y parvenir ?

18voto

codeburn Points 639

La meilleure façon de mettre à l'échelle des images sans perdre le rapport d'aspect (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 pour pouvoir l'utiliser dans tout votre projet, et accédez-y comme suit :

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

Cette méthode prend en charge la mise à l'échelle tout en conservant le rapport d'aspect. Elle ajoute également des retraits à l'image au cas où l'image réduite aurait plus de largeur que de hauteur (ou vice versa).

8voto

Roger Nolan Points 10248

Si vous avez le contrôle du serveur, je vous recommande fortement de redimensionner les images côté serveur avec ImageMagik . Télécharger de grandes images et les redimensionner sur le téléphone est un gaspillage de nombreuses ressources précieuses - bande passante, batterie et mémoire. Toutes ces ressources sont rares sur les téléphones.

2 votes

FTFQ : "Mon application télécharge un ensemble de fichiers images à partir du réseau".

0 votes

Cette réponse pourrait être pertinente. La question indique que les images sont téléchargées à partir du réseau. Si le PO peut travailler avec les images côté serveur, il devrait le faire. Dans le cas contraire, la réponse sera plus utile.

-2voto

Jebu Points 7

Pour redimensionner une image, j'obtiens 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 d'aspect est pris en charge automatiquement

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X