Pergunta

Estou redimensionar algumas imagens para a resolução da tela do usuário; se a relação de aspecto está errado, a imagem deve ser cortado. Meus olhares código como este:

protected void ConvertToBitmap(string filename)
    {
        var origImg = System.Drawing.Image.FromFile(filename);
        var widthDivisor = (double)origImg.Width / (double)System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;
        var heightDivisor = (double)origImg.Height / (double)System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;
        int newWidth, newHeight;

        if (widthDivisor < heightDivisor)
        {
            newWidth = (int)((double)origImg.Width / widthDivisor);
            newHeight = (int)((double)origImg.Height / widthDivisor);
        }
        else
        {
            newWidth = (int)((double)origImg.Width / heightDivisor);
            newHeight = (int)((double)origImg.Height / heightDivisor);
        }

         var newImg = origImg.GetThumbnailImage(newWidth, newHeight, null, IntPtr.Zero);
        newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
    }

Na maioria dos casos, esta multa funciona. Mas para algumas imagens, o resultado tem um extremamente de má qualidade. Parece que o teria sido redimensionada para algo muito pequeno (tamanho de miniatura) e ampliado novamente .. Mas a resolução da imagem é correta. O que posso fazer?

imagem Exemplo orig: texto alt http://img523.imageshack.us/img523/1430/naturaerowoods.jpg

Exemplo redimensionada imagem: text alt

Nota: Eu tenho um aplicativo WPF, mas eu uso as WinForms funcionar para redimensionar porque é mais fácil e porque eu já precisa de uma referência para System.Windows.Forms por um ícone da bandeja

.
Foi útil?

Solução

Alterar as duas últimas linhas do seu método para isso:

var newImg = new Bitmap(newWidth, newHeight);
Graphics g = Graphics.FromImage(newImg);
g.DrawImage(origImg, new Rectangle(0,0,newWidth,newHeight));
newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
g.Dispose();

Outras dicas

Eu não posso espreitar a fonte .NET no momento, mas muito provavelmente o problema está no método Image.GetThumbnailImage. Mesmo MSDN diz que "ele funciona bem quando o pedido miniatura da imagem tem um tamanho de cerca de 120 x 120 pixels, mas você solicitar uma imagem em miniatura grande (por exemplo, 300 x 300) a partir de uma imagem que tem uma miniatura embutida, não poderia ser uma perda perceptível de qualidade na imagem em miniatura". Para a verdadeira redimensionamento (ou seja, não thumbnailing), você deve usar o método Graphics.DrawImage. Você também pode precisar de jogar com o Graphics.InterpolationMode para obter uma melhor qualidade, se necessário.

Se você não está criando uma miniatura, usando um método chamado GetThumbnailImage provavelmente não é uma boa idéia ...

Para outras opções, dê uma olhada no este artigo CodeProject . Em particular, ele cria uma nova imagem, cria uma Graphics para ele e define o modo de interpolação para HighQualityBicubic e desenha a imagem original para os gráficos. Vale a pena tentar, pelo menos.

Como indicado na MSDN , GetThumbnailImage() não é projetado para fazer dimensionamento de imagem arbitrária. Qualquer coisa acima de 120x120 deve ser escalado manualmente. Tente isto em vez disso:

using(var newImg = new Bitmap(origImg, newWidth, newHeight))
{
    newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
}

Editar

Como um ponto de esclarecimento, essa sobrecarga do construtor Bitmap chama Graphics.DrawImage, embora você não tem nenhum controle sobre a interpolação.

em vez de este código:

newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);

usar este:

System.Drawing.Imaging.ImageCodecInfo[] info = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders();
System.Drawing.Imaging.EncoderParameters param = new System.Drawing.Imaging.EncoderParameters(1);
param.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
newImg.Save(dest_img, info[1], param);

Por exemplo, a imagem original é JPG e a imagem redimensionada é PNG. Você conversão entre formatos de propósito? Alternar entre diferentes esquemas de compressão lossey pode causar perda de qualidade.

Você está aumentando ou diminuindo o tamanho da imagem quando você redimensioná-la? Se você estiver criando uma imagem maior de um menor, este tipo de degradação é de se esperar.

Imagens definitivamente vai ser degradado se você ampliá-las.

colocar alguns da câmera um redimensionada em miniatura no próprio presumivelmente ficheiro para fins de visualização no próprio dispositivo.

O método GetThumbnail realmente fica esta imagem Miniatura que está incorporado dentro do arquivo de imagem em vez de obter o maior método res.

A solução mais fácil é para enganar .Net para jogar fora essa miniatura informações antes de fazer o seu redimensionamento ou outra operação. como assim ....

img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX); 
//removes thumbnails from digital camera shots
img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX);

Se você está tentando redimensionar constranger proporções que eu escrevi um método de extensão em System.Drawing.Image que você pode achar útil.

/// <summary>
/// 
/// </summary>
/// <param name="img"></param>
/// <param name="size">Size of the constraining proportion</param>
/// <param name="constrainOnWidth"></param>
/// <returns></returns>
public static System.Drawing.Image ResizeConstrainProportions(this System.Drawing.Image img,
    int size, bool constrainOnWidth, bool dontResizeIfSmaller)
{
    if (dontResizeIfSmaller && (img.Width < size))
        return img;
    img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX); 
    img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX);
    float ratio = 0;
    ratio = (float)img.Width / (float)img.Height;

    int height, width = 0;
    if (constrainOnWidth)
    {
        height = (int)(size / ratio);
        width = size;
    }
    else
    {
        width = (int)(size * ratio);
        height = size;
    }
    return img.GetThumbnailImage(width, height, null, (new System.IntPtr(0)));
}

Isso vai variar muito com base nos seguintes fatores:

  1. Como de perto a resolução destino corresponde a uma escala "natural" da resolução original
  2. A profundidade da fonte cor da imagem
  3. O tipo de imagem (s) - alguns são mais perdas do que outros
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top