이미지 크기 조정 - 때로는 품질이 매우 열악한가요?
-
03-07-2019 - |
문제
일부 이미지를 사용자의 화면 해상도로 크기를 조정하고 있습니다. 종횡비가 잘못되면 이미지를 잘라야합니다. 내 코드는 다음과 같습니다.
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);
}
대부분의 경우, 이것은 잘 작동합니다. 그러나 일부 이미지의 경우 결과에는 다음과 같습니다 극도로 품질이 좋지. 그것은 매우 작은 (썸네일 크기)로 크기를 조정하고 다시 확대 된 것 같습니다. 그러나 이미지의 해상도가 정확합니다. 어떡해?
기존 기본 이미지 :Alt Text http://img523.imageshack.us/img523/1430/naturaerowoods.jpg
참고 : WPF 애플리케이션이 있지만 더 쉽고 이미 트레이 아이콘에 대한 System.Windows.forms에 대한 참조가 필요하기 때문에 크기 조정에 WinForms 기능을 사용합니다.
해결책
방법의 마지막 두 줄을 이것으로 변경하십시오.
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();
다른 팁
현재 .NET 소스를 들여다 볼 수는 없지만 문제는 Image.GetThumbnailImage
방법. MSDN조차도 "요청 된 썸네일 이미지의 크기가 약 120 x 120 픽셀의 크기를 가질 때 잘 작동하지만, 썸네일이 포함 된 이미지에서 큰 썸네일 이미지 (예 : 300 x 300)를 요청할 수 있습니다. 썸네일 이미지에서 눈에 띄는 품질 손실이 되십시오 ". 진정한 크기 조정 (즉, 썸네일이 아님)을 위해서는 다음을 사용해야합니다. Graphics.DrawImage
방법. 당신은 또한 놀아야 할 수도 있습니다 Graphics.InterpolationMode
필요한 경우 더 나은 품질을 얻으려면.
썸네일을 만들지 않으면 GetThumbnailImage
아마 좋은 생각이 아닙니다 ...
다른 옵션의 경우 살펴보십시오 이 CodeProject 기사. 특히 새로운 이미지를 만들고 Graphics
그것을 위해 보간 모드를 설정합니다 HighQualityBicubic
그래픽에 원본 이미지를 그립니다. 적어도 시도해 볼 가치가 있습니다.
표시된대로 MSDN, GetThumbnailImage()
임의의 이미지 스케일링을 수행하도록 설계되지 않았습니다. 120x120을 초과하는 것은 수동으로 조정해야합니다. 대신 시도해보십시오.
using(var newImg = new Bitmap(origImg, newWidth, newHeight))
{
newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
}
편집하다
설명의 지점으로,이 과부하는 Bitmap
생성자 호출 Graphics.DrawImage
, 보간을 통제 할 수는 없지만.
이 코드 대신 :
newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
이것을 사용하십시오 :
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);
예를 들어, 원본 이미지는 JPG이고 크기가 크기가 큰 이미지는 PNG입니다. 의도적 인 형식간에 변환하고 있습니까? 다른 LOSSEY 압축 체계 사이를 전환하면 품질 손실이 발생할 수 있습니다.
이미지 크기를 조정할 때 이미지의 크기를 증가 시키거나 줄이고 있습니까? 작은 이미지에서 더 큰 이미지를 만들고 있다면 이런 종류의 저하가 예상됩니다.
이미지를 확대하면 이미지가 분해됩니다.
일부 카메라는 아마도 장치 자체의 미리보기 목적으로 파일 자체에 크기가 큰 썸네일을 넣습니다.
getThumbnail 메소드는 실제로이 썸네일 이미지를 가져옵니다.
쉬운 솔루션은 크기 조정 또는 기타 작업을 수행하기 전에 .NET을 속이는 것입니다. 그렇게 ....
img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX);
//removes thumbnails from digital camera shots
img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX);
제약 제한 비율을 조정하려는 경우 System.Drawing.image에 확장 메소드를 작성하여 편리하게 찾을 수 있습니다.
/// <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)));
}
이것은 다음 요소에 따라 크게 다를 것입니다.
- 대상 해상도가 원래 해상도의 "자연"척도와 얼마나 밀접한 일과 일치 하는가
- 소스 이미지 색상 깊이
- 이미지 유형 - 일부는 다른 것보다 더 손실입니다.