Como posso recortar imagens de usuário escala / para que eu possa exibir fixo miniaturas de tamanho sem distorcer e alongamento?

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

Pergunta

Eu estou trabalhando em permitindo aos usuários fazer upload de fotos de perfil para o meu site. O exemplo clássico do que eu estou tentando evitar é plentyoffish.com onde cada imagem usuários é distorcida e parece muito feio:

text alt

Então, como posso progmatically cortar / criar versões de tamanho padrão de uma imagem sem a distorcer demonstrado acima?

Foi útil?

Solução

Bem, você deve ter uma altura máxima e largura, vamos supor que o tamanho da imagem que você tem disponível é quadrado, dizem 100x100.

Quando um usuário carrega uma imagem obter as dimensões do mesmo, em seguida, descobrir qual é maior, a altura ou a largura.

Em seguida, tomar a maior medição e obter a relação de que a medição da sua medição alvo, em seguida, usar essa relação para dimensionar a altura e largura.

Assim, se o usuário carrega uma imagem de 500 de altura e 450 de largura, como a altura é maior que você dividir 100 por 500, o seu tamanho miniatura. Isso nos dá 0,2 como a razão. o que significa que a largura passará a ser 90, assim você iria encolher para 100x90, e sem distorção poderia ocorrer.

Outras dicas

Aqui está um código (C #) Eu costumava fazer um redimensionamento, semelhante ao método sugerido por blowdart. Basta substituir o "300" é com o tamanho máximo de um lado, no seu caso:

 private Bitmap ScaleImage(Image oldImage)
    {
        double resizeFactor = 1;

        if (oldImage.Width > 300 || oldImage.Height > 300)
        {
            double widthFactor = Convert.ToDouble(oldImage.Width) / 300;
            double heightFactor = Convert.ToDouble(oldImage.Height) / 300;
            resizeFactor = Math.Max(widthFactor, heightFactor);

        }
        int width = Convert.ToInt32(oldImage.Width / resizeFactor);
        int height = Convert.ToInt32(oldImage.Height / resizeFactor);
        Bitmap newImage = new Bitmap(width, height);
        Graphics g = Graphics.FromImage(newImage);
        g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
        g.DrawImage(oldImage, 0, 0, newImage.Width, newImage.Height);
        return newImage;
    }

OR: Se você ainda gostaria dimensões fixas, você siga as instruções do blowdart mas calcular a maior proporção em vez disso: 100px / 450px = .22 ..

  • width: 100px
  • Altura:. 111.11..px -> cultura do chão ((111,11-100) / 2) em cima e para baixo 100px

Editar :. Ou permitir que o usuário escolha a forma de cortar a sua maior dimensão

Use ImageMagick . Sobre o uso de linha de comando:

convert -thumbnail geometry

Eu fiz esta função para PHP há um tempo atrás que funciona muito bem para isso e alguns outros cenários:

<?php

function Image($source, $crop = null, $resize = null)
{
    $source = ImageCreateFromString(file_get_contents($source));

    if (is_resource($source) === true)
    {
        $width = imagesx($source);
        $height = imagesy($source);

        if (isset($crop) === true)
        {
            $crop = array_filter(explode('/', $crop), 'is_numeric');

            if (count($crop) == 2)
            {
                if (($width / $height) > ($crop[0] / $crop[1]))
                {
                    $width = $height * ($crop[0] / $crop[1]);
                    $crop = array((imagesx($source) - $width) / 2, 0);
                }

                else if (($width / $height) < ($crop[0] / $crop[1]))
                {
                    $height = $width / ($crop[0] / $crop[1]);
                    $crop = array(0, (imagesy($source) - $height) / 2);
                }
            }

            else
            {
                $crop = array(0, 0);
            }
        }

        else
        {
            $crop = array(0, 0);
        }

        if (isset($resize) === true)
        {
            $resize = array_filter(explode('*', $resize), 'is_numeric');

            if (count($resize) >= 1)
            {
                if (empty($resize[0]) === true)
                {
                    $resize[0] = round($resize[1] * $width / $height);
                }

                else if (empty($resize[1]) === true)
                {
                    $resize[1] = round($resize[0] * $height / $width);
                }
            }

            else
            {
                $resize = array($width, $height);
            }
        }

        else
        {
            $resize = array($width, $height);
        }

        $result = ImageCreateTrueColor($resize[0], $resize[1]);

        if (is_resource($result) === true)
        {
            ImageCopyResampled($result, $source, 0, 0, $crop[0], $crop[1], $resize[0], $resize[1], $width, $height);
            ImageDestroy($source);

            header('Content-Type: image/jpeg');

            ImageJPEG($result, null, 90);
            ImageDestroy($result);
        }
    }

    return false;
}

Image('/path/to/your/image.jpg', '1/1', '100*');
Image('/path/to/your/image.jpg', '1/1', '100*100');
Image('/path/to/your/image.jpg', '1/1', '100*500');

?>

Aqui está um comando bash que eu joguei junto para alcançar este objetivo utilizando ferramenta de conversão do ImageMagick. Para um conjunto de imagens sentados no diretório pai, alguns retrato, alguns paisagem, para criar imagens no diretório atual dimensionada para 600x400, recorte de imagens retrato do centro e simplesmente escalar as imagens da paisagem:

for f in ../*jpg; do
    echo $f; 
    size=`identify $f|cut -d' ' -f 3`; 
    w=`echo $size|cut -dx -f 1`; 
    h=`echo $size|cut -dx -f 2`; 
    if [ $w -gt $h ]; then 
        convert $f -thumbnail 600x400 `basename $f`; 
    else 
        convert $f -scale 600x -crop 600x400+0+`echo "((600*($h/$w))/2)" | bc | sed 's/\..*//'` `basename $f`; 
    fi;
done;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top