새 이미지가 찌그러지지 않도록 원본 이미지의 가로 세로 비율을 유지하면서 이미지 크기를 조정하려고합니다.
예 :
150 * 100 이미지를 150 * 150 이미지로 변환합니다.
추가 50 픽셀의 높이는 흰색 배경색으로 채워야합니다.
이것이 내가 사용중인 현재 코드입니다.
크기 조정에는 잘 작동하지만 원본 이미지의 종횡비를 변경하면 새 이미지가 축소됩니다.
private void resizeImage(string path, string originalFilename,
int width, int height)
{
Image image = Image.FromFile(path + originalFilename);
System.Drawing.Image thumbnail = new Bitmap(width, height);
System.Drawing.Graphics graphic =
System.Drawing.Graphics.FromImage(thumbnail);
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
graphic.DrawImage(image, 0, 0, width, height);
System.Drawing.Imaging.ImageCodecInfo[] info =
ImageCodecInfo.GetImageEncoders();
EncoderParameters encoderParameters;
encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,
100L);
thumbnail.Save(path + width + "." + originalFilename, info[1],
encoderParameters);
}
편집 : 잘린 대신 이미지를 패딩하고 싶습니다.
답변
그렇게해야합니다.
private void resizeImage(string path, string originalFilename,
/* note changed names */
int canvasWidth, int canvasHeight,
/* new */
int originalWidth, int originalHeight)
{
Image image = Image.FromFile(path + originalFilename);
System.Drawing.Image thumbnail =
new Bitmap(canvasWidth, canvasHeight); // changed parm names
System.Drawing.Graphics graphic =
System.Drawing.Graphics.FromImage(thumbnail);
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
/* ------------------ new code --------------- */
// Figure out the ratio
double ratioX = (double) canvasWidth / (double) originalWidth;
double ratioY = (double) canvasHeight / (double) originalHeight;
// use whichever multiplier is smaller
double ratio = ratioX < ratioY ? ratioX : ratioY;
// now we can get the new height and width
int newHeight = Convert.ToInt32(originalHeight * ratio);
int newWidth = Convert.ToInt32(originalWidth * ratio);
// Now calculate the X,Y position of the upper-left corner
// (one of these will always be zero)
int posX = Convert.ToInt32((canvasWidth - (originalWidth * ratio)) / 2);
int posY = Convert.ToInt32((canvasHeight - (originalHeight * ratio)) / 2);
graphic.Clear(Color.White); // white padding
graphic.DrawImage(image, posX, posY, newWidth, newHeight);
/* ------------- end new code ---------------- */
System.Drawing.Imaging.ImageCodecInfo[] info =
ImageCodecInfo.GetImageEncoders();
EncoderParameters encoderParameters;
encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,
100L);
thumbnail.Save(path + newWidth + "." + originalFilename, info[1],
encoderParameters);
}
추가하기 위해 편집 :
이 코드를 개선하려는 사람들은 주석이나 새로운 답변에 넣어야합니다. 이 코드를 직접 편집하지 마십시오.
답변
이 CodeProject 기사 에서 학습하여 이미지 크기를 조정하고 패딩하는 방법을 알아 냈습니다 .
static Image FixedSize(Image imgPhoto, int Width, int Height)
{
int sourceWidth = imgPhoto.Width;
int sourceHeight = imgPhoto.Height;
int sourceX = 0;
int sourceY = 0;
int destX = 0;
int destY = 0;
float nPercent = 0;
float nPercentW = 0;
float nPercentH = 0;
nPercentW = ((float)Width / (float)sourceWidth);
nPercentH = ((float)Height / (float)sourceHeight);
if (nPercentH < nPercentW)
{
nPercent = nPercentH;
destX = System.Convert.ToInt16((Width -
(sourceWidth * nPercent)) / 2);
}
else
{
nPercent = nPercentW;
destY = System.Convert.ToInt16((Height -
(sourceHeight * nPercent)) / 2);
}
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap bmPhoto = new Bitmap(Width, Height,
PixelFormat.Format24bppRgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.Clear(Color.Red);
grPhoto.InterpolationMode =
InterpolationMode.HighQualityBicubic;
grPhoto.DrawImage(imgPhoto,
new Rectangle(destX, destY, destWidth, destHeight),
new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
GraphicsUnit.Pixel);
grPhoto.Dispose();
return bmPhoto;
}
답변
다음 방법을 사용하여 원하는 이미지 크기를 계산합니다.
using System.Drawing;
public static Size ResizeKeepAspect(this Size src, int maxWidth, int maxHeight, bool enlarge = false)
{
maxWidth = enlarge ? maxWidth : Math.Min(maxWidth, src.Width);
maxHeight = enlarge ? maxHeight : Math.Min(maxHeight, src.Height);
decimal rnd = Math.Min(maxWidth / (decimal)src.Width, maxHeight / (decimal)src.Height);
return new Size((int)Math.Round(src.Width * rnd), (int)Math.Round(src.Height * rnd));
}
이것은 종횡비와 크기의 문제를 별도의 방법에 넣습니다.
답변
더 빠른 결과를 얻으려면 크기를 얻는 함수를 다음에서 찾을 수 있습니다 resultSize
.
Size original = new Size(640, 480);
int maxSize = 100;
float percent = (new List<float> { (float)maxSize / (float)original.Width , (float)maxSize / (float)original.Height }).Min();
Size resultSize = new Size((int)Math.Floor(original.Width * percent), (int)Math.Floor(original.Height * percent));
용도는 Linq
변수 및 재 계산뿐만 아니라 unnecesary 최소화하기 위해 if/else
문을
답변
가로 세로 비율과 크기로 일반화하기 만하면이 기능 외부에서 이미지 작업을 수행 할 수 있습니다.
public static d.RectangleF ScaleRect(d.RectangleF dest, d.RectangleF src,
bool keepWidth, bool keepHeight)
{
d.RectangleF destRect = new d.RectangleF();
float sourceAspect = src.Width / src.Height;
float destAspect = dest.Width / dest.Height;
if (sourceAspect > destAspect)
{
// wider than high keep the width and scale the height
destRect.Width = dest.Width;
destRect.Height = dest.Width / sourceAspect;
if (keepHeight)
{
float resizePerc = dest.Height / destRect.Height;
destRect.Width = dest.Width * resizePerc;
destRect.Height = dest.Height;
}
}
else
{
// higher than wide – keep the height and scale the width
destRect.Height = dest.Height;
destRect.Width = dest.Height * sourceAspect;
if (keepWidth)
{
float resizePerc = dest.Width / destRect.Width;
destRect.Width = dest.Width;
destRect.Height = dest.Height * resizePerc;
}
}
return destRect;
}
답변
여기에도 내 코드를 추가하겠습니다. 이 코드를 사용하면 가로 세로 비율을 적용하거나 적용하지 않고 이미지 크기를 조정하거나 패딩으로 크기를 조정할 수 있습니다. 이것은 egrunin 코드의 수정 된 버전입니다.
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
namespace ConsoleApplication1
{
public class Program
{
public static void Main(string[] args)
{
var path = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName;
ResizeImage(path, "large.jpg", path, "new.jpg", 100, 100, true, true);
}
/// <summary>Resizes an image to a new width and height.</summary>
/// <param name="originalPath">The folder which holds the original image.</param>
/// <param name="originalFileName">The file name of the original image.</param>
/// <param name="newPath">The folder which will hold the resized image.</param>
/// <param name="newFileName">The file name of the resized image.</param>
/// <param name="maximumWidth">When resizing the image, this is the maximum width to resize the image to.</param>
/// <param name="maximumHeight">When resizing the image, this is the maximum height to resize the image to.</param>
/// <param name="enforceRatio">Indicates whether to keep the width/height ratio aspect or not. If set to false, images with an unequal width and height will be distorted and padding is disregarded. If set to true, the width/height ratio aspect is maintained and distortion does not occur.</param>
/// <param name="addPadding">Indicates whether fill the smaller dimension of the image with a white background. If set to true, the white padding fills the smaller dimension until it reach the specified max width or height. This is used for maintaining a 1:1 ratio if the max width and height are the same.</param>
private static void ResizeImage(string originalPath, string originalFileName, string newPath, string newFileName, int maximumWidth, int maximumHeight, bool enforceRatio, bool addPadding)
{
var image = Image.FromFile(originalPath + "\\" + originalFileName);
var imageEncoders = ImageCodecInfo.GetImageEncoders();
EncoderParameters encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
var canvasWidth = maximumWidth;
var canvasHeight = maximumHeight;
var newImageWidth = maximumWidth;
var newImageHeight = maximumHeight;
var xPosition = 0;
var yPosition = 0;
if (enforceRatio)
{
var ratioX = maximumWidth / (double)image.Width;
var ratioY = maximumHeight / (double)image.Height;
var ratio = ratioX < ratioY ? ratioX : ratioY;
newImageHeight = (int)(image.Height * ratio);
newImageWidth = (int)(image.Width * ratio);
if (addPadding)
{
xPosition = (int)((maximumWidth - (image.Width * ratio)) / 2);
yPosition = (int)((maximumHeight - (image.Height * ratio)) / 2);
}
else
{
canvasWidth = newImageWidth;
canvasHeight = newImageHeight;
}
}
var thumbnail = new Bitmap(canvasWidth, canvasHeight);
var graphic = Graphics.FromImage(thumbnail);
if (enforceRatio && addPadding)
{
graphic.Clear(Color.White);
}
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
graphic.DrawImage(image, xPosition, yPosition, newImageWidth, newImageHeight);
thumbnail.Save(newPath + "\\" + newFileName, imageEncoders[1], encoderParameters);
}
}
}
답변
다음은로드 및 저장을 수행하는 대신 Image와 함께 작동하는 덜 구체적인 확장 방법입니다. 또한 보간 방법을 지정하고 NearestNeighbour 보간을 사용할 때 가장자리를 올바르게 렌더링 할 수 있습니다.
이미지는 지정한 영역의 경계 내에서 렌더링되므로 항상 출력 너비와 높이를 알 수 있습니다. 예 :
namespace YourApp
{
#region Namespaces
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
#endregion
/// <summary>Generic helper functions related to graphics.</summary>
public static class ImageExtensions
{
/// <summary>Resizes an image to a new width and height value.</summary>
/// <param name="image">The image to resize.</param>
/// <param name="newWidth">The width of the new image.</param>
/// <param name="newHeight">The height of the new image.</param>
/// <param name="mode">Interpolation mode.</param>
/// <param name="maintainAspectRatio">If true, the image is centered in the middle of the returned image, maintaining the aspect ratio of the original image.</param>
/// <returns>The new image. The old image is unaffected.</returns>
public static Image ResizeImage(this Image image, int newWidth, int newHeight, InterpolationMode mode = InterpolationMode.Default, bool maintainAspectRatio = false)
{
Bitmap output = new Bitmap(newWidth, newHeight, image.PixelFormat);
using (Graphics gfx = Graphics.FromImage(output))
{
gfx.Clear(Color.FromArgb(0, 0, 0, 0));
gfx.InterpolationMode = mode;
if (mode == InterpolationMode.NearestNeighbor)
{
gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
gfx.SmoothingMode = SmoothingMode.HighQuality;
}
double ratioW = (double)newWidth / (double)image.Width;
double ratioH = (double)newHeight / (double)image.Height;
double ratio = ratioW < ratioH ? ratioW : ratioH;
int insideWidth = (int)(image.Width * ratio);
int insideHeight = (int)(image.Height * ratio);
gfx.DrawImage(image, new Rectangle((newWidth / 2) - (insideWidth / 2), (newHeight / 2) - (insideHeight / 2), insideWidth, insideHeight));
}
return output;
}
}
}