如何用“透明白色”涂绘位图区域?

12

我想用“透明白色”替换位图的矩形区域中的所有像素-即,a = 0,b = 255,r = 255,g = 255。

FillRectangle无法实现此功能-使用透明画笔时,现有像素不会改变。

我需要逐个使用SetPixel来处理矩形内的每个像素吗?

6个回答

15

您需要设置 Graphics.CompositingMode 属性。例如:

protected override void OnPaint(PaintEventArgs e) {
    using (var img = Properties.Resources.Chrysanthemum) {
        e.Graphics.DrawImage(img, 0, 0); 
        e.Graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
        using (var br = new SolidBrush(Color.FromArgb(0, 255, 255, 255))) {
            e.Graphics.FillRectangle(br, new Rectangle(50, 50, 100, 100));
        }
    }
}

实际使用的颜色并不重要,您将获得一个 alpha 值为 0 的黑色矩形。


1
在数据处理中使用颜色通道并不是很罕见,比如在游戏地形图中,水、道路、岩石和雪都可以用ARGB表示。因此,有时候你需要创建alpha值为零但RGB值非零的位图。 - Pete Kirkham
1
顺便提一下,在我的情况下,颜色很重要,因为后续处理会将透明区域的颜色与其他区域的颜色混合。 - mackenir

6

我相信你需要使用SetPixel(或直接设置颜色值的等效方法)来使像素变为“透明白”。

您可以使用Graphics.Clear方法设置颜色或像素,但无法将其设置为透明和颜色。我尝试使用此方法来设置位图的一部分中的像素:

using (Graphics g = Graphics.FromImage(theBitmap)) {
  g.Clip = new Region(new Rectangle(10, 10, 80, 80));
  g.Clear(Color.FromArgb(0, Color.White));
}

该区域中的像素最终变为“透明黑色”:0,0,0,0。即使在清除之前绘制一个纯白色矩形也无济于事。当颜色中的Alpha值为零时,其他颜色分量也为零。

使用接近透明的Alpha(如1)是可以的,像素最终变为“几乎透明白色”:1,255,255,255。


3
如果您使用复合绘画方法,则alpha将用于混合颜色,因此不会发生任何事情。
如果您想设置位图,则可以使用所需背景从数据创建它,或使用LockBits设置背景以批量操作数据。
您可能还可以使用适当的标志通过bitblt方法来完成,但我不知道如何将其翻译为托管代码。

1

重要提示:

创建图像时,请确保按照以下步骤进行操作。

mainImage = new Bitmap(totalWidth, maxHeight, PixelFormat.Format32bppARgb);

而不是

mainImage = new Bitmap(totalWidth, maxHeight, PixelFormat.Format32bppRgb);

这将节省您一些麻烦。不要假设32位表示Alpha通道 ;-)


0

这个小技巧应该可以解决问题:

Graphics g = Graphics.FromImage(myBitmap);
g.SetClip(new RectangleF(10, 10, 20, 20));
g.Clear(Color.Transparent);
g.RestoreClip();
g.Dispose();

1
不对。这会将像素设置为“透明黑色”:0,0,0,0,而不是“透明白色”:0,255,255,255。 - Guffa
你可以将它改为g.Clear(Color.FromArgb(0, 255, 255, 255));虽然Hans Passant的答案可能更好 - C.Evenhuis

0
FillRectangle不会这样做 - 给定一个透明的画刷,现有的像素不会改变。
这很有道理,因为你是用0%的不透明度绘制的。 :)
对于控件的快速解决方案是使用颜色键。您可以将控件的关键颜色设置为特定颜色(即品红色); 所有此颜色的像素都将被渲染为透明。(如果控件支持的话)
或者是用bitmap.MakeTransparent(color)进行一般性的处理。问题是,再次指定的颜色将是透明的,因此您必须选择图像中不存在的颜色。(这里有另一个例子:https://web.archive.org/web/20131030025202/http://msdn.microsoft.com/en-us/library/ms172507(v=VS.80).aspx

编辑: 最后,其他评论中提到的 LockBits() 方法可能是您寻找的。一旦您了解了宽度和步幅值如何相互作用,就可以在可能的最低级别上操作图像。 这是一个通用示例:https://web.archive.org/web/20141229164101/http://bobpowell.net/lockingbits.aspx 只需确保图像支持透明度(参见 PixelFormat),然后使用适当的模式锁定图像(即 PixelFormat.Format32bppArgb),循环遍历每个像素,读取字节,编写新颜色等。


是的,完全有道理 :) 我只是在说。除此之外,我认为你的回答不相关 - 我正在使用位图,而不是控件。虽然我可以绘制特定颜色的矩形(并希望该颜色在图像的任何其他位置都不存在),然后使其透明,但我能指定“透明白色”吗?我认为不行。 - mackenir
你的Bitmap.MakeTransparent(Color.White)应该可以做到这一点。缺点是所有白色都会变成透明,这是真的。问题在于并非每种图像格式都支持透明度,因此这可能还取决于您的图像对象是如何创建的。请查看PixelFormat枚举和成员。当然,还有一种方法是锁定位图以在“不安全”指针维度中工作。就像Pete所说的那样。 :) - sunside

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接