Utilisation correcte de UIRectClip pour redimensionner un UIImage à la taille d'une icône

StackOverflow https://stackoverflow.com/questions/1405994

  •  05-07-2019
  •  | 
  •  

Question

Étant donné une UIImage de toute dimension, je souhaite générer un carré "icône". version de taille, px pixels sur un côté, sans aucune distorsion (étirement). Cependant, je me heurte à un petit problème. Je ne sais pas trop où est le problème. Voici ce que je fais jusqu'à présent.

D'abord, étant donné une UImage taille , je détermine trois choses: le ratio à utiliser lors de la réduction de la taille de l'image; un delta (la différence entre la taille de l'icône souhaitée et le côté le plus long) et un offset (utilisé pour déterminer notre coordonnée d'origine lors du découpage de l'image):

 if (size.width > size.height) {
   ratio = px / size.width;
   delta = (ratio*size.width - ratio*size.height);
   offset = CGPointMake(delta/2, 0);
 } else {
   ratio = px / size.height;
   delta = (ratio*size.height - ratio*size.width);
   offset = CGPointMake(0, delta/2);
 }

Maintenant, supposons que vous ayez une image de 640px de large par 480px de haut et que nous voulions en faire une icône de 50px x 50px. La largeur étant supérieure à la hauteur, nos calculs sont les suivants:

ratio = 50px / 640px = 0.078125
delta = (ratio * 640px) - (ratio * 480px) = 50px - 37.5px = 12.5px
offset = {x=6.25, y=0}

Ensuite, je crée un CGRect rect suffisamment grand pour être rogné à la taille de l'icône souhaitée sans distorsion, plus un clipRect . à des fins de découpage:

CGRect rect = CGRectMake(0.0, 0.0, (ratio * size.width) + delta,
                                   (ratio * size.height) + delta);
CGRect clipRect = CGRectMake(offset.x, offset.y, px, px);

En substituant nos valeurs par le haut, nous obtenons:

rect = origin {x=0.0, y=0.0}, size {width=62.5, height=50.0}
clipRect = origin {x=6.25, y=0}, size {width=50.0, height=50.0}

Nous avons maintenant un rect droit de 62,5 px de large sur 50 px de hauteur avec lequel travailler, ainsi qu'un rectangle de découpage qui saisit le "milieu". Portion 50x50.

À la maison! Ensuite, nous définissons notre contexte d’image, dessinons l’image UIImage (appelée myImage ici), définissons le rectangle de découpage, récupérons l’image (supposément maintenant coupée), utilisez-le et nettoyez enfin notre contexte d'image:

 UIGraphicsBeginImageContext(rect.size);
 [myImage drawInRect:rect]; 
 UIRectClip(clipRect);
 UIImage *icon = UIGraphicsGetImageFromCurrentImageContext();

 // Do something with the icon here ...

 UIGraphicsEndImageContext();

Un seul problème: l'écrêtage ne se produit jamais! Je me retrouve avec une image 63px large x 50px haut. : (

Peut-être que j'utilise mal / comprend mal le UIRectClip ? J'ai essayé de mélanger diverses méthodes: remplacer l'utilisation de rect et de clipRect , déplacer UIRectClip avant drawInRect: . Pas de dés.

J'ai également essayé de chercher un exemple de cette méthode en ligne, mais en vain. Pour mémoire, UIRectClip est défini comme suit:

  

Modifie le tracé de détourage actuel par   l'intersection avec le spécifié   rectangle.

Mélanger les choses nous rapproche un peu plus:

UIGraphicsBeginImageContext(clipRect.size);
UIRectClip(rect);
[myImage drawInRect:rect];

Nous n'avons pas de distorsion, mais l'image découpée n'est pas centrée sur l'original, comme je m'y attendais. Néanmoins, au moins l’image est au format 50x50, bien que les noms de variables soient maintenant encrassés à la suite de ce brassage. (Je laisserai respectueusement le renommage comme exercice pour le lecteur.)

Était-ce utile?

La solution

Eureka! J'ai eu des choses un peu mélangées. Cela fonctionne:

CGRect clipRect = CGRectMake(-offset.x, -offset.y,
                             (ratio * size.width) + delta,
                             (ratio * size.height) + delta);
UIGraphicsBeginImageContext(CGSizeMake(px, px));
UIRectClip(clipRect);
[myImage drawInRect:clipRect];
UIImage *icon = UIGraphicsGetImageFromCurrentImageContext();

// Do something with the icon here ...

UIGraphicsEndImageContext();

Plus besoin de rect . L’astuce semble utiliser un décalage négatif dans le rectangle de découpage, alignant ainsi l’origine de l’endroit où nous voulons récupérer notre image 50 x 50 (dans cet exemple).

Peut-être y a-t-il un moyen plus facile. Si tel est le cas, pesez-vous!

Autres conseils

Je voulais faire la même chose mais j'ai trouvé que la réponse de l'affiche originale ne fonctionnait pas vraiment. Cela a déformé l'image. Cela s'explique peut-être uniquement par le fait qu’il n’a pas publié la solution complète et qu’il avait modifié une partie de la manière dont les variables sont initialisées:

 (if (size.width > size.height) 
       ratio = px / size.width;

J'avais tort pour ma solution (qui souhaitait utiliser le plus grand carré possible de l'image source). De plus, il n'est pas nécessaire d'utiliser UIClipRect - si vous donnez au contexte la taille de l'image que vous voulez extraire, aucun dessin réel ne sera fait en dehors de ce recto de toute façon. Il suffit simplement de redimensionner la taille de l'image et de décaler l'une des coordonnées d'origine. J'ai posté ma solution ci-dessous:

+(UIImage *)makeIconImage:(UIImage *)image
{
    CGFloat destSize = 400.0;
    CGRect rect = CGRectMake(0, 0, destSize, destSize);

    UIGraphicsBeginImageContext(rect.size);

    if(image.size.width != image.size.height)
    {
        CGFloat ratio;
        CGRect destRect;

        if (image.size.width > image.size.height)
        {
            ratio = destSize / image.size.height;

            CGFloat destWidth = image.size.width * ratio;
            CGFloat destX = (destWidth - destSize) / 2.0;

            destRect = CGRectMake(-destX, 0, destWidth, destSize);

        }
        else
        {
            ratio = destSize / image.size.width;

            CGFloat destHeight = image.size.height * ratio;
            CGFloat destY = (destHeight - destSize) / 2.0;

            destRect = CGRectMake(0, destY, destSize, destHeight);
        }
        [image drawInRect:destRect];
    }
    else
    {
        [image drawInRect:rect];
    }
    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return scaledImage;
}

la réponse de wheeliebin est correcte mais il a oublié un signe moins devant le destin

destRect = CGRectMake(0, -destY, destSize, destHeight);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top