我正在使用以下系统绘图代码来调整上传图像的大小。问题是横向或纵向图像变形,因为系统绘图使它们变成正方形。是否可以仅调整宽度并保持高度成比例?如何?感谢
HttpPostedFile imageFile = UploadImages.PostedFile;
System.Drawing.Image ri = System.Drawing.Image.FromStream(imageFile.InputStream);
ri = ResizeBitmap((Bitmap) ri, 200, 200);
private Bitmap ResizeBitmap(Bitmap b, int nWidth, int nHeight)
{
Bitmap result = new Bitmap(nWidth, nHeight);
using (Graphics g = Graphics.FromImage((System.Drawing.Image)result))
g.DrawImage(b, 0, 0, nWidth, nHeight);
return result;
}
答案 0 :(得分:2)
如果你想要做的是创建一个200像素宽的新位图并按比例缩放高度,你可以这样做:
private static int CalculateProportionalHeight(int oldWidth, int oldHeight, int newWidth)
{
if (oldWidth <= 0 || oldHeight <= 0 || newWidth <= 0)
// For safety.
return oldHeight;
double widthFactor = (double)newWidth / (double)oldWidth;
int newHeight = (int)Math.Round(widthFactor * (double)oldHeight);
if (newHeight < 1)
newHeight = 1; // just in case.
return newHeight;
}
private static Bitmap ResizeBitmap(Bitmap b, int nWidth)
{
int nHeight = CalculateProportionalHeight(b.Width, b.Height, nWidth);
Bitmap result = new Bitmap(nWidth, nHeight);
using (Graphics g = Graphics.FromImage((System.Drawing.Image)result))
g.DrawImage(b, 0, 0, nWidth, nHeight);
return result;
}
或者您是否希望创建一个200x200位图,其中旧图像缩放以适应内部,如果需要,可以letterboxed?
更新
如果您要创建固定的200x200尺寸的图像,并且图像按比例缩小以适合和letterboxed,则应该这样做:
static RectangleF PlaceInside(int oldWidth, int oldHeight, int newWidth, int newHeight)
{
if (oldWidth <= 0 || oldHeight <= 0 || newWidth <= 0 || newHeight <= 0)
return new RectangleF(oldWidth, oldHeight, newWidth, newHeight);
float widthFactor = (float)newWidth / (float)oldWidth;
float heightFactor = (float)newHeight / (float)oldHeight;
if (widthFactor < heightFactor)
{
// prefer width
float scaledHeight = widthFactor * oldHeight;
// new new RectangleF(x, y, width, height)
return new RectangleF(0, (newHeight - scaledHeight) / 2.0f, newWidth, scaledHeight);
}
else
{
// prefer height
float scaledWidth = heightFactor * oldWidth;
// new new RectangleF(x, y, width, height)
return new RectangleF((newWidth - scaledWidth) / 2.0f, 0, scaledWidth, newHeight);
}
}
private static Bitmap ResizeBitmap(Bitmap b, int nWidth, int nHeight)
{
int oldWidth = b.Width;
int oldHeight = b.Height;
Bitmap result = new Bitmap(nWidth, nHeight);
using (Graphics g = Graphics.FromImage((System.Drawing.Image)result))
{
var box = PlaceInside(oldWidth, oldHeight, nWidth, nHeight);
g.DrawImage(b, box);
}
return result;
}
更新2
这是一个版本,如果横向和高度200和比例宽度(如果是肖像),则创建宽度为200且比例高度的图像:
private static Bitmap ResizeBitmapUpto(Bitmap b, int nWidth, int nHeight, System.Drawing.Drawing2D.InterpolationMode interpolationMode)
{
int oldWidth = b.Width;
int oldHeight = b.Height;
var box = PlaceInside(oldWidth, oldHeight, nWidth, nHeight);
int actualNewWidth = (int)Math.Max(Math.Round(box.Width), 1);
int actualNewHeight = (int)Math.Max(Math.Round(box.Height), 1);
Bitmap result = new Bitmap(actualNewWidth, actualNewHeight);
using (Graphics g = Graphics.FromImage((System.Drawing.Image)result))
{
g.InterpolationMode = interpolationMode;
g.DrawImage(b, 0, 0, actualNewWidth, actualNewHeight);
}
return result;
}
我添加了interpolationMode,因此您可以根据Ksv3n的答案尝试不同的品质。
(希望)上次更新
这是我用来验证代码的测试设置。我能够在我的计算机上成功打开,调整大小和保存各种图像。
public static void TestResizeBitmapUpto(string file, string newFile)
{
try
{
using (var image = Bitmap.FromFile(file))
{
if (image == null)
return;
using (Bitmap b = new Bitmap(image))
{
using (var newBitmap = ResizeBitmapUpto(b, 200, 200, System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor))
{
newBitmap.Save(newFile);
}
}
}
}
catch (System.IO.FileNotFoundException e)
{
Debug.WriteLine(e.ToString());
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
}
答案 1 :(得分:1)
您的代码中缺少的是:
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
以下是您可以用来调整图像大小的方法,并保持比例:
private Bitmap ResizeBitmap(Bitmap b, int nWidth, int nHeight)
{
Bitmap result = new Bitmap(nWidth, nHeight);
using (Graphics g = Graphics.FromImage((System.Drawing.Image)result))
{
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
g.DrawImage(b, 0, 0, nWidth, nHeight);
}
return result;
}
答案 2 :(得分:0)
g.DrawImage会将图像拉伸到您定义的图像(在您的情况下为200/200,这是一个正方形)。
您需要计算nWidth和nHeight的实际值:
// original image (b.Width, b.Height)
double originalWidth = 200;
double originalHeight = 100;
// user defined wanted width
double wantedWidth = 200; // nWidth parameter to your method
double wantedHeight = 300; // nHeight parameter to your method
double ratioW = originalWidth / wantedWidth;
double ratioH = originalHeight / wantedHeight;
double ratio = Math.Max(ratioW, ratioH);
// rectangle proportional to the original that fits into the wanted
double destinationWidth = originalWidth / ratio; // what you pass to DrawImage as nWidth
double destinationHeight = originalHeight / ratio; // what you pass to DrawImage as nWidth
它的作用是计算原始图像和想要图像的宽高比,并取最大值。使用它来划分原始值,这将使它们完全适合所需的矩形。
这将根据方向绘制从顶部或左侧对齐的缩放图像,因为生成的图像将等于或大于想要的或原始图像。要使其在生成的图像中居中,您需要通过取宽度/高度的差异并除以2来调整DrawImage()的左坐标和顶坐标。
如果生成的图像的大小可以与用户指定的大小不同(nWidth / nHeight),那么您可以使用destinationWidth / Height简单地初始化它,然后返回它,而不必费心去居中。