我正在 GDI+ WinForms 中制作一个绘画应用程序,我有一个想要添加的功能,并且已经尝试添加,但我在网上没有找到任何有关它的信息。
我想拍摄一张图像(或位图,并不重要)并将其裁剪到其中所有内容所在的位置。
举个例子:
我这里有一张图片 它周围有相当多的白色(将图像保存到您的计算机上,看看它周围有白色。)我想将图像裁剪到火柴人所在的区域,我希望它看起来像像这样:
(将其保存到您的计算机中,您可以比较两者)
如果你看第二个,这就是我想要制作的,它已将图像缩减为只有火柴人!
但是,当然,我自己也这么做过。
我在网上查找了很多解决方案,但找不到,所以我决定尝试自己做,但没有成功。
这是我尝试过的:
我有一个带有图片框和按钮的简单表单 - 单击按钮后,它应该向下裁剪图像。我将图片框的背景颜色设置为黑色,并将其置于图像中心,以便图像中不再存在的区域为黑色。
图像存储在名为 ImageToChange
的位图中。
单击按钮后,它应该裁剪图像 - 所以我创建了一个函数来执行此操作,我将从按钮调用该函数
这个函数依赖于我在网上找到的另一个裁剪图像的函数:
public Bitmap CropImage(Image source, int x, int y, int width, int height)
{
Rectangle crop = new Rectangle(x, y, width, height);
var bmp = new Bitmap(crop.Width, crop.Height);
using (var gr = Graphics.FromImage(bmp))
{
gr.DrawImage(source, new Rectangle(0, 0, bmp.Width, bmp.Height), crop, GraphicsUnit.Pixel);
}
return bmp;
}
上面的函数应该只是根据给定的 x、y、宽度和高度进行裁剪和图像 - 我没有编写代码,但我可以看到它的作用。
我的 CropToContent
函数取决于最后的函数。
所以,这是我创建的用于裁剪图像的函数:
public Bitmap CropToContent(Bitmap oldBmp)
{
Rectangle currentRect = new Rectangle();
// Get a base color
for (int y = 0; y < oldBmp.Height; y++)
{
for (int x = 0; x < oldBmp.Width; x++)
{
if (oldBmp.GetPixel(x, y) != Color.White)
{
// We need to interpret this!
if (!currentRect.Contains(new Point(x, y)))
{
// This will run if this is out of the current rectangle
if (x > (currentRect.X + currentRect.Width)) currentRect.Width += ((currentRect.X + currentRect.Width) + x);
if (x < (currentRect.X))
{
// Move the rectangle over there and extend it's width to make the right the same!
int oldRectLeft = currentRect.Left;
currentRect.X = x;
currentRect.Width += oldRectLeft - x;
}
if (y > (currentRect.Y + currentRect.Height)) currentRect.Height += ((currentRect.Y + currentRect.Height) + y);
if (y < (currentRect.Y + currentRect.Height))
{
int oldRectTop = currentRect.Top;
currentRect.Y = y;
currentRect.Height += oldRectTop - y;
}
}
}
}
}
return CropImage(oldBmp, currentRect.X, currentRect.Y, currentRect.Width, currentRect.Height);
}
正如你所看到的,它使用了我之前提到的CropImage
函数!
此函数有一个图像将被裁剪到的矩形 - 随着函数的运行,它会被修改。
该函数循环遍历位图中的所有像素,如果它不是白色,它会忽略它 - 如果它是其他任何像素,它会根据矩形周围的位置执行某些操作,
如果它位于矩形的左侧,它将移动矩形的 X 并更改宽度,以便矩形的右侧仍然相同
如果它位于矩形的顶部,它将向上移动矩形的 Y 并更改高度...
如果它位于矩形的右侧,它将更改宽度以匹配。
如果它位于矩形的底部,它将更改高度以匹配。
如果它在矩形内部,它根本不会关心。
我不明白为什么这个功能不起作用。
在加载
表单时,它运行以下代码:
ImageToChange = Properties.Resources.stickman;
pictureBox1.Image = ImageToChange;
我将未受影响的火柴人放入 Properties.Resources.stickman
中。
然后单击它运行的按钮:
ImageToChange = CropToContent(ImageToChange);
pictureBox1.Image = ImageToChange;
我不明白为什么这行不通,如果您阅读了整篇文章,我将非常感谢。
最佳答案
我对你所说的“不起作用”的意思有点了解,但我想我发现了问题。
错误在于您的逻辑中,例如修改矩形右侧的代码行:
if (x > (currentRect.X + currentRect.Width)) currentRect.Width += ((currentRect.X + currentRect.Width) + x);
这通过添加 x、矩形.X 和矩形.Width 来修改检测到的矩形的宽度,这是错误的。你想要的可能是这样的:
if (x > (currentRect.X + currentRect.Width)) currentRect.Width = x - currentRect.X;
您将需要对其余逻辑进行类似的更改。
关于c# winforms gdi+ - 将图像裁剪为其内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46022742/