Pergunta

Dado um UIImage de qualquer dimensão, quero gerar um quadrado "ícone" versão feita sob medida, px pixels para um lado, sem qualquer distorção (alongamento). No entanto, eu estou correndo em um pequeno obstáculo. Não tem a certeza onde está o problema. Aqui está o que eu estou fazendo até agora.

Em primeiro lugar, dada a uImage size, eu determinar três coisas: a ratio para uso quando a escala para baixo a imagem; um delta (a diferença entre a nossa tamanho ícone desejado e o lado mais longo), e um offset (que é usado para descobrir a origem das coordenadas, quando o recorte de imagem):

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

Agora, digamos que você tem um 640px imagem de largura por 480px de altura, e queremos ter uma 50px x 50px ícone de fora deste. A largura é maior que a altura, para que nossos cálculos são:

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

Em seguida, eu criar um CGRect rect que é grande o suficiente para ser cortada para baixo para o nosso tamanho do ícone desejado sem distorção, além de um clipRect para fins de recorte:

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

Substituindo os nossos valores de cima, temos:

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}

Então, agora temos um 62.5px de largura por 50px alta rect para trabalhar com, e um retângulo de recorte que agarra o "meio" 50x50 porção.

Por à reta final! Em seguida, montamos nosso contexto imagem, desenhe o UIImage (chamado myImage aqui) para o rect, definir o retângulo de recorte, obtenha a imagem (presumivelmente agora cortada), usá-lo, e até finalmente limpo nosso contexto imagem:

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

 // Do something with the icon here ...

 UIGraphicsEndImageContext();

Apenas um problema: O recorte nunca ocorre! Eu acabar com um 63px imagem de largura x 50px alta. :(

Talvez eu esteja fazendo mau uso / mal-entendido UIRectClip ? Eu tentei baralhar várias coisas ao redor: trocando o uso de rect e clipRect, movendo-se UIRectClip antes de drawInRect: . Não dados.

Eu tentei procurar um exemplo deste método on-line, bem como, sem sucesso. Para o registro, UIRectClip é definido como:

Modifica o caminho de recorte atual interseção com o especificado retângulo.

Baralhar as coisas ao redor fica-nos um pouco mais perto:

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

Agora não temos distorção, mas a imagem recortada não está centrada no original como eu esperava. Ainda assim, pelo menos, a imagem é 50x50, embora os nomes de variáveis ??são agora estragou como resultado da referida baralhar. (Eu vou respeitosamente deixar renomeando como um exercício para o leitor.)

Foi útil?

Solução

Eureka! Eu tinha coisas um pouco misturados. Isso 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();

Não há mais necessidade de rect. O truque parece estar usando um negativo compensado no retângulo de recorte, alinhando assim a origem de onde queremos agarrar a nossa x 50 imagens 50 (neste exemplo).

Talvez haja uma maneira mais fácil. Se assim for, por favor, pesar!

Outras dicas

Eu queria alcançar uma coisa semelhante, mas encontrei a resposta de pelo seu autor não muito trabalho. É distorcida da imagem. Esta pode muito bem ser apenas porque ele não postar toda a solução e mudou alguns de como as variáveis ??são inicializados:

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

Foi errado para minha solução (que queria usar a maior praça possível a partir da imagem de origem). Também não é necessário usar UIClipRect - se você fizer o contexto do tamanho da imagem que você deseja extrair, nenhum desenho real será feito fora que rect de qualquer maneira. É apenas uma questão de dimensionar o tamanho do rect imagem e compensando uma das coordenadas de origem. Tenho postado minha solução abaixo:

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

wheeliebin respostas está correta, mas ele esqueceu um sinal de menos na frente de Desty

destRect = CGRectMake(0, -destY, destSize, destHeight);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top