L'uso corretto di UIRectClip per ridimensionare un UIImage fino alla dimensione dell'icona

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

  •  05-07-2019
  •  | 
  •  

Domanda

Dato un UIImage di qualsiasi dimensione, desidero generare un quadrato " icona " versione graduata, pixel px su un lato, senza distorsioni (allungamento). Tuttavia, sto incontrando un piccolo intoppo. Non sono sicuro di dove sia il problema. Ecco cosa sto facendo finora.

Per prima cosa, dato un UImage size , ho determinato tre cose: il ratio da usare per ridimensionare l'immagine; un delta (la differenza tra la dimensione dell'icona desiderata e il lato più lungo) e un offset (che viene utilizzato per capire la nostra coordinata di origine quando si ritaglia l'immagine):

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

Ora, supponiamo che tu abbia un'immagine di 640 pixel di larghezza per 480 pixel di altezza, e vogliamo ottenere un'icona 50px x 50px da questo. La larghezza è maggiore dell'altezza, quindi i nostri calcoli sono:

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

Successivamente, creo un CGRect rect che è abbastanza grande da essere ritagliato alla dimensione dell'icona desiderata senza distorsione, oltre a un clipRect per scopi di ritaglio:

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

Sostituendo i nostri valori dall'alto, otteniamo:

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}

Quindi ora abbiamo un rettangolo di 62,5 px di larghezza per 50 px di altezza con cui lavorare e un rettangolo di ritaglio che afferra il "mezzo" Porzione 50x50.

Sul tratto di casa! Successivamente, impostiamo il nostro contesto di immagine, disegniamo UIImage (qui chiamato myImage ) nel rettangolo, impostiamo il rettangolo di ritaglio, otteniamo l'immagine (presumibilmente ora ritagliata), usalo e finalmente pulisci il nostro contesto di immagine:

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

 // Do something with the icon here ...

 UIGraphicsEndImageContext();

Un solo problema: il ritaglio non si verifica mai! Finisco con un'immagine larga 63px x alta 50px. : (

Forse sto abusando / fraintendendo UIRectClip ? Ho provato a mescolare varie cose: scambiando l'uso di rect e clipRect , spostando UIRectClip prima di drawInRect: . Nessun dado.

Ho provato a cercare un esempio di questo metodo anche online, senza risultati. Per la cronaca, UIRectClip è definito come:

  

Modifica il tracciato di ritaglio corrente di   intersecandolo con il specificato   rettangolo.

Mescolare le cose in giro ci avvicina un po 'di più:

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

Ora non abbiamo distorsioni, ma l'immagine ritagliata non è centrata sull'originale come mi aspettavo. Tuttavia, almeno l'immagine è 50x50, anche se i nomi delle variabili ora sono sporchi a causa di detto shuffle. (Lascerò rispettosamente la ridenominazione come esercizio per il lettore.)

È stato utile?

Soluzione

Eureka! Ho avuto un po 'di confusione. Questo funziona:

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

Non è più necessario rect . Il trucco sembra utilizzare un offset negativo nel rettangolo di ritaglio, allineando così l'origine di dove vogliamo catturare la nostra immagine 50 x 50 (in questo esempio).

Forse c'è un modo più semplice. In tal caso, ti preghiamo di soppesare!

Altri suggerimenti

Volevo ottenere qualcosa di simile ma ho trovato che la risposta del poster originale non funzionava. Ha distorto l'immagine. Questo potrebbe essere dovuto esclusivamente al fatto che non ha pubblicato l'intera soluzione e ha modificato alcune delle modalità di inizializzazione delle variabili:

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

Era sbagliato per la mia soluzione (che voleva usare il quadrato più grande possibile dall'immagine sorgente). Inoltre, non è necessario utilizzare UIClipRect: se si rende il contesto delle dimensioni dell'immagine che si desidera estrarre, al di fuori di quel rettangolo non verrà comunque eseguito alcun disegno reale. Si tratta solo di ridimensionare la dimensione dell'immagine retta e compensare una delle coordinate di origine. Di seguito ho pubblicato la mia soluzione:

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

le risposte al wheeliebin sono corrette ma ha dimenticato un segno meno davanti a destY

destRect = CGRectMake(0, -destY, destSize, destHeight);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top