C # 가로 세로 비율을 유지하면서 다른 크기로 이미지 크기 조정
새 이미지가 찌그러지지 않도록 원본 이미지의 종횡비를 유지하면서 이미지 크기를 조정하려고합니다.
예 :
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));
}
이것은 종횡비와 치수의 문제를 별도의 방법에 넣습니다.
가로 세로 비율과 크기로 일반화하기 만하면이 기능 외부에서 이미지 작업을 수행 할 수 있습니다.
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;
}
더 빠른 결과를 얻으려면 크기를 얻는 함수를 다음에서 찾을 수 있습니다 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
문을
여기에도 내 코드를 추가하겠습니다. 이 코드를 사용하면 가로 세로 비율을 적용하거나 적용하지 않고 이미지 크기를 조정하거나 패딩으로 크기를 조정할 수 있습니다. 이것은 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);
}
}
}
참고 :이 코드는 패딩 대신 가로 세로 비율을 벗어난 모든 항목의 크기를 조정하고 제거합니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
namespace MyPhotos.Common
{
public class ThumbCreator
{
public enum VerticalAlign
{
Top,
Middle,
Bottom
}
public enum HorizontalAlign
{
Left,
Middle,
Right
}
public void Convert(string sourceFile, string targetFile, ImageFormat targetFormat, int height, int width, VerticalAlign valign, HorizontalAlign halign)
{
using (Image img = Image.FromFile(sourceFile))
{
using (Image targetImg = Convert(img, height, width, valign, halign))
{
string directory = Path.GetDirectoryName(targetFile);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
if (targetFormat == ImageFormat.Jpeg)
{
SaveJpeg(targetFile, targetImg, 100);
}
else
{
targetImg.Save(targetFile, targetFormat);
}
}
}
}
/// <summary>
/// Saves an image as a jpeg image, with the given quality
/// </summary>
/// <param name="path">Path to which the image would be saved.</param>
// <param name="quality">An integer from 0 to 100, with 100 being the
/// highest quality</param>
public static void SaveJpeg(string path, Image img, int quality)
{
if (quality < 0 || quality > 100)
throw new ArgumentOutOfRangeException("quality must be between 0 and 100.");
// Encoder parameter for image quality
EncoderParameter qualityParam =
new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
// Jpeg image codec
ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
img.Save(path, jpegCodec, encoderParams);
}
/// <summary>
/// Returns the image codec with the given mime type
/// </summary>
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
// Get image codecs for all image formats
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
// Find the correct image codec
for (int i = 0; i < codecs.Length; i++)
if (codecs[i].MimeType == mimeType)
return codecs[i];
return null;
}
public Image Convert(Image img, int height, int width, VerticalAlign valign, HorizontalAlign halign)
{
Bitmap result = new Bitmap(width, height);
using (Graphics g = Graphics.FromImage(result))
{
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
float ratio = (float)height / (float)img.Height;
int temp = (int)((float)img.Width * ratio);
if (temp == width)
{
//no corrections are needed!
g.DrawImage(img, 0, 0, width, height);
return result;
}
else if (temp > width)
{
//den e för bred!
int overFlow = (temp - width);
if (halign == HorizontalAlign.Middle)
{
g.DrawImage(img, 0 - overFlow / 2, 0, temp, height);
}
else if (halign == HorizontalAlign.Left)
{
g.DrawImage(img, 0, 0, temp, height);
}
else if (halign == HorizontalAlign.Right)
{
g.DrawImage(img, -overFlow, 0, temp, height);
}
}
else
{
//den e för hög!
ratio = (float)width / (float)img.Width;
temp = (int)((float)img.Height * ratio);
int overFlow = (temp - height);
if (valign == VerticalAlign.Top)
{
g.DrawImage(img, 0, 0, width, temp);
}
else if (valign == VerticalAlign.Middle)
{
g.DrawImage(img, 0, -overFlow / 2, width, temp);
}
else if (valign == VerticalAlign.Bottom)
{
g.DrawImage(img, 0, -overFlow, width, temp);
}
}
}
return result;
}
}
}
// This allows us to resize the image. It prevents skewed images and
// also vertically long images caused by trying to maintain the aspect
// ratio on images who's height is larger than their width
public void ResizeImage(string OriginalFile, string NewFile, int NewWidth, int MaxHeight, bool OnlyResizeIfWider)
{
System.Drawing.Image FullsizeImage = System.Drawing.Image.FromFile(OriginalFile);
// Prevent using images internal thumbnail
FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
if (OnlyResizeIfWider)
{
if (FullsizeImage.Width <= NewWidth)
{
NewWidth = FullsizeImage.Width;
}
}
int NewHeight = FullsizeImage.Height * NewWidth / FullsizeImage.Width;
if (NewHeight > MaxHeight)
{
// Resize with height instead
NewWidth = FullsizeImage.Width * MaxHeight / FullsizeImage.Height;
NewHeight = MaxHeight;
}
System.Drawing.Image NewImage = FullsizeImage.GetThumbnailImage(NewWidth, NewHeight, null, IntPtr.Zero);
// Clear handle to original file so that we can overwrite it if necessary
FullsizeImage.Dispose();
// Save resized picture
NewImage.Save(NewFile);
}
다음은로드 및 저장을 수행하는 대신 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;
}
}
}
aspect Ration을 유지하고 레터 박스와 Pillarbox를 제거합니다.
static Image FixedSize(Image imgPhoto, int Width, int Height)
{
int sourceWidth = imgPhoto.Width;
int sourceHeight = imgPhoto.Height;
int X = 0;
int Y = 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;
}
else
{
nPercent = nPercentW;
}
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap bmPhoto = new Bitmap(destWidth, destHeight, PixelFormat.Format24bppRgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.DrawImage(imgPhoto,
new Rectangle(X, Y, destWidth, destHeight),
new Rectangle(X, Y, sourceWidth, sourceHeight),
GraphicsUnit.Pixel);
grPhoto.Dispose();
return bmPhoto;
}
public static void resizeImage_n_save(Stream sourcePath, string targetPath, int requiredSize)
{
using (var image = System.Drawing.Image.FromStream(sourcePath))
{
double ratio = 0;
var newWidth = 0;
var newHeight = 0;
double w = Convert.ToInt32(image.Width);
double h = Convert.ToInt32(image.Height);
if (w > h)
{
ratio = h / w * 100;
newWidth = requiredSize;
newHeight = Convert.ToInt32(requiredSize * ratio / 100);
}
else
{
ratio = w / h * 100;
newHeight = requiredSize;
newWidth = Convert.ToInt32(requiredSize * ratio / 100);
}
// var newWidth = (int)(image.Width * scaleFactor);
// var newHeight = (int)(image.Height * scaleFactor);
var thumbnailImg = new Bitmap(newWidth, newHeight);
var thumbGraph = Graphics.FromImage(thumbnailImg);
thumbGraph.CompositingQuality = CompositingQuality.HighQuality;
thumbGraph.SmoothingMode = SmoothingMode.HighQuality;
thumbGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
var imageRectangle = new Rectangle(0, 0, newWidth, newHeight);
thumbGraph.DrawImage(image, imageRectangle);
thumbnailImg.Save(targetPath, image.RawFormat);
//var img = FixedSize(image, requiredSize, requiredSize);
//img.Save(targetPath, image.RawFormat);
}
}
private static Size CalculateDimensions(Size originalSize, Size targetSize)
{
Size newSize = new Size();
int cooficientA = targetSize.Height * originalSize.Width;
int cooficientB = targetSize.Width * originalSize.Height;
if (cooficientA < cooficientB)
{
newSize.Width = (int)Math.Round((double)cooficientA / originalSize.Height);
newSize.Height = targetSize.Height;
}
else
{
newSize.Width = targetSize.Width;
newSize.Height = (int)Math.Round((double)cooficientB / originalSize.Width);
}
return newSize;
}
Size newSize = CalculateDimensions(originalSize, targetSize);
x = (targetSize.Width - newSize.Width) / 2;
y = (targetSize.Height - newSize.Height) / 2;
나는 이미 여기에 이미 충분히 간단한 대답이 없었기 때문에 이것을 썼습니다. 원하는대로 하드 코딩 된 128을 대체하거나 원본 이미지의 크기를 기반으로 할 수 있습니다. 내가 원했던 것은 이미지를 128x128 이미지로 재조정하여 종횡비를 유지하고 결과를 새 이미지의 중앙에 배치하는 것입니다.
private Bitmap CreateLargeIconForImage(Bitmap src)
{
Bitmap bmp = new Bitmap(128, 128);
Graphics g = Graphics.FromImage(bmp);
float scale = Math.Max((float)src.Width / 128.0f, (float)src.Height / 128.0f);
PointF p = new PointF(128.0f - ((float)src.Width / scale), 128.0f - ((float)src.Height / scale));
SizeF size = new SizeF((float)src.Width / scale, (float)src.Height / scale);
g.DrawImage(src, new RectangleF(p, size));
return bmp;
}
'your programing' 카테고리의 다른 글
Django REST Framework에서 필드 이름을 변경하는 방법 (0) | 2020.10.15 |
---|---|
회계 응용 프로그램 달러 금액에 부동 소수점 또는 소수점을 사용합니까? (0) | 2020.10.15 |
특정 비트를 바이트 단위로 설정 (0) | 2020.10.15 |
csproj를 사용하여 .NET Core 클래스 라이브러리를 어떻게 다중 대상으로 지정합니까? (0) | 2020.10.14 |
국가와 도시 (0) | 2020.10.14 |