Redimensionamento da imagem - às vezes muito má qualidade?
-
03-07-2019 - |
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:
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
.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:
- Como de perto a resolução destino corresponde a uma escala "natural" da resolução original
- A profundidade da fonte cor da imagem
- O tipo de imagem (s) - alguns são mais perdas do que outros