【问题标题】:Resize a Bitmap in C#在 C# 中调整位图的大小
【发布时间】:2015-09-22 05:02:38
【问题描述】:

我正在寻找一种在不丢失其实际形状的情况下调整位图大小的方法,同时牢记新大小不得与原始图像尺寸成比例。

确切地说,我想将一个直立八 (40x110) 的图像调整为 29x29 位图,我正在寻找一个函数来将原始比例相对于它的新图像,同时填充新创建的空间(宽度)具有白色并且从实际 8 到其白色基线具有相同的侧间隙。

很遗憾,这并不能满足我的要求:

 public static Bitmap ResizeImage(Image image, int width, int height)
    {
        var destRect = new Rectangle(0, 0, width, height);
        var destImage = new Bitmap(width, height);

        destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);

        using (var graphics = Graphics.FromImage(destImage))
        {
            graphics.CompositingMode = CompositingMode.SourceCopy;
            graphics.CompositingQuality = CompositingQuality.HighQuality;
            graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphics.SmoothingMode = SmoothingMode.HighQuality;
            graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

            using (var wrapMode = new ImageAttributes())
            {
                wrapMode.SetWrapMode(WrapMode.TileFlipXY);
                graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
            }
        }

        return destImage;
    }

更新 1: 比例调整新功能:

 public static Bitmap ResizeImageProportional(Bitmap bitmap, int width, int height)
    {
        Bitmap destImage;
        Rectangle destRect;
        int destH, destW, destX, dextY;

        if (bitmap.Height > bitmap.Width)
        {
            destH = height;
            destW = bitmap.Width / bitmap.Height * height;
            destX = (width - destW) / 2;
            dextY = 0;
        }
        else if (bitmap.Height < bitmap.Width) 
        {
            destH = bitmap.Height / bitmap.Width * width;
            destW = width;
            destX = 0;
            dextY = (height - destH) / 2;
        }
        else
        // if (bitmap.Width == bitmap.Height)
        {
            destH = height;
            destW = width;
            destX = 0;
            dextY = 0;
        }

        destRect = new Rectangle(destX, dextY, destW, destH);
        destImage = new Bitmap(width, height);

        destImage.SetResolution(bitmap.HorizontalResolution, bitmap.VerticalResolution);

        using (var graphics = Graphics.FromImage(destImage))
        {
            graphics.CompositingMode = CompositingMode.SourceCopy;
            graphics.CompositingQuality = CompositingQuality.HighQuality;
            graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphics.SmoothingMode = SmoothingMode.HighQuality;
            graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

            using (var wrapMode = new ImageAttributes())
            {
                wrapMode.SetWrapMode(WrapMode.TileFlipXY);
                graphics.DrawImage(bitmap, destRect, 0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, wrapMode);
            }
        }

        return destImage;
    }

不幸的是,我使用这个解决方案总是得到一个空位图。我首先将原始位图裁剪为一个矩形,其中我的位图元素完全适合。否则将位图本身的左基线也是其中图形元素的基线,而整个背景是白色的。 然后我将这个位图(大约 40x80)放入“ResizeImageProportional”(原始后期编辑)函数中,宽度和高度值为 29。

【问题讨论】:

  • 目前的解决方案有什么问题?
  • 您将 (0,0) 用于源 目标位置。这不是你想要的,对吧?您需要计算目的地位置!

标签: c# .net image bitmap resize


【解决方案1】:

如果要保持比例,则需要计算目标矩形。

这是我想不到的措施:

destH = height;
destW = image.Width / image.Height * height; 
destX = (width - destW) / 2;
dextY = 0;

您应该将背景清除为之前想要的颜色:Graphics.Clear(someColor);

如果您不使用源图像和目标图像的边界,则会扭曲图像。你似乎有什么......,不是吗?

在这种情况下,当然没有新空间了。

计算时,必要时使用float..

更新:

也许您想分析原始图像并保留或删除从前景到边缘的空间。这意味着要么查看像素,要么返回原件的创建方式。

对于示例,我添加了图形的边界。

这是一个简单的裁剪功能;它假定左上角保存背景颜色并返回一个裁剪矩形:

public static Rectangle CropBounds(Image image)
{
    Bitmap bmp = (Bitmap)image;
    int x0 = 0;
    int x1 = bmp.Width - 1;
    int y0 = 0;
    int y1 = bmp.Height - 1;
    Color c = bmp.GetPixel(0, 0);
    while (x0==0)
    {  for (int x = 0; x < x1; x++)
            if ((x0==0)) for (int y = 0; y < y1; y++)
                if ( bmp.GetPixel(x,y)!= c) {x0 = x-1; break;} }
    while (x1 == bmp.Width - 1)
    {
        for (int x = bmp.Width - 1; x > 0; x--)
            if ((x1 == bmp.Width - 1)) for (int y = 0; y < y1; y++)
                    if (bmp.GetPixel(x, y) != c) { x1 = x + 1; break; }  }
    while (y0 == 0)
    {
        for (int y = 0; y < y1; y++)
            if ((y0 == 0)) for (int x = 0; x < bmp.Width; x++)
                    if (bmp.GetPixel(x, y) != c) { y0 = y - 1; break; }
    }
    while (y1 == bmp.Height - 1)
    {
        for (int y = bmp.Height - 1; y > 0; y--)
            if ((y1 == bmp.Height - 1)) for (int x = 0; x < bmp.Width; x++)
                    if (bmp.GetPixel(x, y) != c) { y1 = y + 1; break; }
    }

    return new Rectangle(x0, y0, x1 - x0, y1 - y0);
}

现在您可以更改代码以像这样使用它:

graphics.DrawImage(image, destRect, CropBounds(image) , GraphicsUnit.Pixel);

如果你真的需要翻转,只需存储矩形并更改为适当的格式..!

更新 2:

我写是有原因的

在您的ResizeImageProportional 函数中,您需要避免整数精度损失!将部门更改为:

destW = (int) (1f * bitmap.Width / bitmap.Height * height);

destH =  (int) (1f *bitmap.Height / bitmap.Width * width);

【讨论】:

  • 感谢您的帮助。不幸的是,我总是用这个解决方案得到一个空位图。我首先将原始位图裁剪为我的位图元素完全适合的形状。否则将位图本身的左基线也是其中图形元素的基线,而整个背景是白色的。然后我将这个位图(大约 40x80)放入“ResizeImageProportional”(原始后期编辑)函数中,宽度和高度值为 29。
  • 查看我的代码以了解裁剪方法!您的原始代码在其他方面很好,因为您似乎拥有.. - 同样在更新 2 中,我展示了如何更正您的计算!
  • 这其实是我想绕过的裁剪方法。 8看起来不像原来的。在这种情况下,裁剪方法应该以不会失去其实际比例形状的方式对其进行裁剪。如果它不适合这种方式进入新的盒子,其余的空间应该用空白填充。
猜你喜欢
  • 2012-03-23
  • 1970-01-01
  • 2011-08-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多