2009-09-10 9 views
7

Dado un UIImage de cualquier dimensión, deseo para generar un "icono" cuadrado versión en tamaño, px píxeles a un lado, sin ninguna distorsión (estiramiento). Sin embargo, me encuentro con un pequeño inconveniente. No estoy seguro de dónde está el problema. Esto es lo que estoy haciendo hasta ahora.El uso apropiado de UIRectClip para escalar un UIImage hacia abajo para el tamaño del icono

En primer lugar, dado un uImagesize, puedo determinar tres cosas: la ratio de usar cuando se escala por la imagen; un delta (la diferencia entre nuestro tamaño deseado icono y el lado más largo), y un offset (que se utiliza para averiguar nuestro origen de coordenadas al recortar la imagen):

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

Ahora, supongamos que usted tiene una imagen 640px de ancho por 480px de alto, y queremos obtener un ícono de 50px x 50px de esto. La anchura es mayor que la altura, por lo que nuestros cálculos son:

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

A continuación, se crea un CGRectrect que es lo suficientemente grande como para ser cultivada hasta nuestro tamaño del icono deseado sin distorsión, además de un clipRect de recorte propósitos:

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

Sustituyendo nuestros valores desde arriba, obtenemos:

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} 

Ahora tenemos un rect alto de 62.5px de ancho por 50px, y un rectángulo de recorte que agarra la porción "media" de 50x50.

¡En la recta final! A continuación, configuramos nuestro contexto de imagen, dibuje el UIImage (llamado myImage aquí) en la rect, establezca el rectángulo de recorte, obtenga la imagen (presumiblemente recortada), úselo y finalmente limpie nuestro contexto de imagen:

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

// Do something with the icon here ... 

UIGraphicsEndImageContext(); 

Un solo problema: ¡el recorte nunca ocurre! Termino con una imagen de 63 px de ancho x 50 px de alto. :(

Quizás estoy haciendo un mal uso/malentendido UIRectClip? He intentado barajar varias cosas: cambiar el uso de rect y clipRect, moviendo UIRectClip antes de drawInRect:. No dados.

Traté de buscar un ejemplo de este método en línea también, en vano. Para el registro, UIRectClip se define como:

modifica la trayectoria actual de recorte por intersección con la especificada rectángulo.

Barajar las cosas no nos lleva un poco más cerca:

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

Ahora que no tienen distorsión, pero la imagen recortada no está centrada en el original como lo esperaba.Aún así, al menos la imagen es de 50x50, aunque los nombres de las variables ahora están sucios como resultado de dicha mezcla. (Respetuosamente dejaré el cambio de nombre como un ejercicio para el lector.)

Respuesta

7

Eureka! Tenía cosas un poco confusas. Esto funciona:

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

No hay más necesidad de rect. El truco parece estar usando un negativo offset en el rectángulo de recorte, alineando así el origen de donde queremos tomar nuestra imagen de 50 x 50 (en este ejemplo).

Quizás haya una manera más fácil. Si es así, por favor, pesen!

1

Quería lograr algo similar, pero encontré que la respuesta del cartel original no funcionaba del todo. Distorsionó la imagen. Esto bien puede ser únicamente porque no le envió toda la solución y había cambiado alguna de cómo se inicializan las variables:

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

estaba mal que mi solución (que quería utilizar la plaza más grande posible a partir de la imagen de origen) Tampoco es necesario utilizar UIClipRect: si configura el contexto del tamaño de la imagen que desea extraer, de todos modos, no se realizará ningún dibujo fuera de ese rectángulo. Solo se trata de escalar el tamaño de la imagen rect y compensar una de las coordenadas de origen. He publicado mi solución a continuación:

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

Gracias por compartir esto! Ha pasado un tiempo desde que miré con lo que terminé. Definitivamente no quería ni pretendo ninguna distorsión usando mi método. Tu "cuadro más grande posible" suena sensato, y estoy muy feliz de escuchar que UIRectClip no es necesario. (¡Otros lectores, pesen y vean cómo esto también vuela para ustedes!) –

+0

Gracias, específicamente por la frase "Además, no es necesario usar UIClipRect - si se hace el contexto del tamaño de la imagen que desea extraer, no se hará ningún dibujo real fuera de ese rect de todos modos " – xaphod

0

respuestas wheeliebin es correcta, pero se olvidó de un signo menos delante de Desty

destRect = CGRectMake(0, -destY, destSize, destHeight); 
Cuestiones relacionadas