在 C# 中调整位图的大小

Resize a Bitmap in C#

我正在寻找一种方法来调整位图的大小,而不会丢失其实际形状,同时要记住新的大小不能与原始图像尺寸成比例。

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

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

 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"(原始 post 编辑。)函数中,宽度和高度值为 29.

如果你想保留你需要计算目标矩形的比例。

以下是我想到的措施:

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

你应该先把背景清除成你想要的颜色:Graphics.Clear(someColor);

如果不这样做,您将使用源图像和目标图像的边界,从而扭曲图像。哪个是你似乎拥有的..,不是吗?

那么当然没有新的 space。

计算时,必要时使用浮点数..

更新:

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

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

这是一个简单的裁剪功能;它假定左上角包含背景颜色和 returns 裁剪矩形:

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

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

更新二:

我写是有原因的,计算时,如果需要的话,使用float..:

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

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

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