在上传时调整宽度,并保持高度比例

本文关键字:高度 调整 | 更新日期: 2023-09-27 18:14:52

我使用以下系统绘图代码来调整上载图像的大小。问题是,风景或肖像图像失真,因为系统绘图使他们成为方形。是否有可能仅调整宽度并保持高度成比例?以及如何?由于

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;
    }

在上传时调整宽度,并保持高度比例

如果你想创建一个新的位图,宽度为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的位图,将旧图像缩放到适合内部,并在必要时使用字母框?

如果你想创建一个固定的200x200大小的图像,并按比例缩小图像以适合和有字母框,应该这样做:

    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());
        }
    }

您的代码中缺少的是:

   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;
    }

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

它所做的是计算原始图像和想要的图像的宽度和高度比,并取其最大值。使用它来划分原始值,这将使它们完全适合所需的矩形。

这将绘制缩放后的图像,根据方向向上或向左对齐,因为最终图像将等于或大于所需图像或原始图像。为了使其在最终图像中居中,您需要调整DrawImage()的左坐标和顶部坐标,方法是取宽度/高度的差值并除以2。

如果结果图像的大小可以不同于用户指定的(nWidth/nHeight),那么你可以简单地用destinationWidth/Height初始化它,并返回它,而不需要居中