繁体   English   中英

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

[英]Resize width on upload and keep the height ratio proportional

我正在使用以下系统绘图代码来调整上传图像的大小。 问题是横向或纵向图像变形,因为系统绘图使它们变成正方形。 是否可以仅调整宽度并保持高度成比例? 如何? 谢谢

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位图,其中旧图像缩放以适应内部,并在必要时使用letterbox

更新

如果您要创建一个固定的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());
        }
    }

您的代码中缺少的是:

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

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简单地初始化它,然后返回它,而不必费心去居中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM