.net 使用System.Drawing,我怎样才能画出模仿黄色高亮标记效果的东西?

.net 使用System.Drawing,我怎样才能画出模仿黄色高亮标记效果的东西?,.net,gdi+,system.drawing,.net,Gdi+,System.drawing,我想让黄色后面的东西显示出来 编辑1:但是,如果我在“白色”上绘图,我希望标记颜色保留其纯黄色 编辑2:@Kevin的答案可能是正确的,我把它标记为正确的,尽管我没有编写代码。在我的代码中,我接受@Guffa的答案,使用Color.FromArgb 编辑3:我发布了性能良好的代码。是的,减去蓝色是基本的想法,但是你不能用高级API来做,而且SetPixel太慢了。性能良好的解决方案使用位图.LockBits和UnlockBits。您使用半透明颜色,例如50%alpha不透明度: Color.Fr

我想让黄色后面的东西显示出来

编辑1:但是,如果我在“白色”上绘图,我希望标记颜色保留其纯黄色

编辑2:@Kevin的答案可能是正确的,我把它标记为正确的,尽管我没有编写代码。在我的代码中,我接受@Guffa的答案,使用Color.FromArgb


编辑3:我发布了性能良好的代码。是的,减去蓝色是基本的想法,但是你不能用高级API来做,而且SetPixel太慢了。性能良好的解决方案使用位图.LockBits和UnlockBits。

您使用半透明颜色,例如50%alpha不透明度:

Color.FromArgb(128, Color.Yellow)

如果alpha值较低,则会显示更多背景。

尝试使用alpha值小于255的
颜色初始化的
SolidBrush
。这将创建一个半透明的画笔,与你使用的颜色相同。

荧光笔是颜料,所以它本质上是减色的——你想把白色变成黄色,但不是黑色变成黄色。我不知道.NET,但是你想要的是一个非默认的“混合模式”,特别是减法。具体来说,将混合模式设置为减法,将颜色设置为纯蓝色(要减法的颜色,保留黄色)。黑色将被单独留下,因为没有蓝色可以减去,而白色将变成黄色


不幸的是,许多现代绘图界面忽略了alpha以外的混合模式,看起来这可能是其中之一。如果您有权访问位图,您可以自己实现它-获取每个像素值并将蓝色分量设置为零。或者,如果要突出显示的区域比较复杂,则:复制图像,在副本中突出显示的区域上绘制黑色,然后将原始图像中的红色和绿色通道以及副本中的蓝色通道组合到最终结果图像中。

这是您需要的代码:

    protected override void OnPaint( PaintEventArgs e )
    {
        using ( var bmp = new Bitmap( 100, 100 ) )
        using ( var g = Graphics.FromImage( bmp ) )
        using ( var ia = new ImageAttributes() )
        {
            // 1. create a sample bitmap
            g.Clear( Color.White );
            var p = Point.Empty;
            foreach ( var color in new Color[] { Color.Black, Color.Gray, Color.LightBlue, Color.Green, Color.Red, Color.Magenta } )
                using ( var brush = new SolidBrush( color ) )
                {
                    g.DrawString( "Some sample text", SystemFonts.DefaultFont, brush, p );
                    p.Offset( 0, 16 );
                }
            // 2. transfer the bitmap on screen
            e.Graphics.DrawImage( bmp, Point.Empty );
            // 3. transfer a part of the bitmap on screen again, this time removing all blue
            ia.SetColorMatrix( new ColorMatrix( new float[][] {
                        new float[] {1, 0, 0, 0, 0},
                        new float[] {0, 1, 0, 0, 0},
                        new float[] {0, 0, 0, 0, 0},
                        new float[] {0, 0, 0, 1, 0},
                        new float[] {0, 0, 0, 0, 1}} ) );
            e.Graphics.DrawImage(
                bmp,
                new Rectangle( 30, 0, 40, 100 ),
                30, 0, 40, 100,
                GraphicsUnit.Pixel,
                ia );
        }
    }

这个代码有效。它清除了每个RGB中我想要的黄色部分的蓝色部分。起初我尝试使用Bitmap.GetPixel/SetPixel,但速度非常慢。使用Lock/Unlock获取原始位的速度足够快

                using (Bitmap tempBitmap = new Bitmap(bitmap.Width, bitmap.Height))
                {
                    using (Graphics tempG = Graphics.FromImage(tempBitmap))
                    {

                        tempG.DrawLines(penYellowHighlighter, stroke.points.ToArray());

                        // get the raw bits of the source and target and remove the blue from every
                        // bit of the target where there is a yellow bit of the source
                        Rectangle rect = new Rectangle(0, 0, bitmapWithStrokes.Width, bitmapWithStrokes.Height);

                        // lock
                        System.Drawing.Imaging.BitmapData sourceData =
                            tempBitmap.LockBits(
                                rect,
                                System.Drawing.Imaging.ImageLockMode.ReadOnly,
                                tempBitmap.PixelFormat);

                        System.Drawing.Imaging.BitmapData targetData =
                            bitmapWithStrokes.LockBits(
                                rect,
                                System.Drawing.Imaging.ImageLockMode.ReadWrite,
                                bitmapWithStrokes.PixelFormat);

                        // Get the address of the first line.
                        IntPtr sourcePtr = sourceData.Scan0;
                        IntPtr targetPtr = targetData.Scan0;

                        // Declare an array to hold the bytes of the bitmap.
                        int numberOfBytes = Math.Abs(sourceData.Stride) * tempBitmap.Height;

                        byte[] sourceRgbValues = new byte[numberOfBytes];
                        byte[] targetRgbValues = new byte[numberOfBytes];

                        // Copy the RGB values into the array.
                        System.Runtime.InteropServices.Marshal.Copy(sourcePtr, sourceRgbValues, 0, numberOfBytes);
                        System.Runtime.InteropServices.Marshal.Copy(targetPtr, targetRgbValues, 0, numberOfBytes);

                        for (int p = 0; p < numberOfBytes; p += 4)
                        {
                            // if the source's red is yellows's red
                            if (sourceRgbValues[p + 2] == yellowsRedComponent)
                            {
                                // wipe out the target's blue
                                targetRgbValues[p] = 0;
                            }
                        }

                        // Copy the RGB values back to the bitmap
                        System.Runtime.InteropServices.Marshal.Copy(targetRgbValues, 0, targetPtr, numberOfBytes);

                        // Unlock the bits.
                        tempBitmap.UnlockBits(sourceData);
                        bitmapWithStrokes.UnlockBits(targetData);
使用(位图tempBitmap=新位图(Bitmap.Width、Bitmap.Height))
{
使用(Graphics tempG=Graphics.FromImage(tempBitmap))
{
临时抽绳(笔黄色荧光笔、笔划点、ToArray());
//获取源和目标的原始位,并从每个源中删除蓝色
//目标的位,其中有源的黄色位
矩形rect=新矩形(0,0,bitmapWithStrokes.Width,bitmapWithStrokes.Height);
//锁
System.Drawing.Imaging.BitmapData源数据=
临时位图.锁位(
直肠,
System.Drawing.Imaging.ImageLockMode.ReadOnly,
tempBitmap.PixelFormat);
System.Drawing.Imaging.BitmapData targetData=
bitmapWithStrokes.LockBits(
直肠,
System.Drawing.Imaging.ImageLockMode.ReadWrite,
bitmapWithStrokes.PixelFormat);
//获取第一行的地址。
IntPtr sourcePtr=sourceData.Scan0;
IntPtr targetPtr=targetData.Scan0;
//声明一个数组以保存位图的字节。
int numberOfBytes=Math.Abs(sourceData.Stride)*tempBitmap.Height;
byte[]sourceRgbValues=新字节[numberOfBytes];
byte[]targetRgbValues=新字节[numberOfBytes];
//将RGB值复制到数组中。
System.Runtime.InteropServices.Marshal.Copy(sourcePtr,sourcergbvalue,0,numberOfBytes);
System.Runtime.InteropServices.Marshal.Copy(targetPtr,targetRgbValues,0,numberOfBytes);
对于(int p=0;p
谢谢-这是可行的,但不是我所希望的。我希望黄色本身更……黄色。@Corey:是的,这不完全是黄色标记的效果,但它与内置的绘图功能非常接近。增加alpha值会使黄色更清晰,但会减少背景光泽通过。Yikes!这超出了我的雄心壮志,但如果我不想影响效果,如果我希望黄色变成黄色,你的答案似乎是正确的。嗯,这很简单-只要一个参数设置-如果你有一个支持混合模式的绘图系统。这和“颜色燃烧”是一样的吗在一些图形应用程序中?例如,paint.net?(每天学习新东西!:D)从未听说过颜色灼伤。如果颜色灼伤是准确的,那么就不一样了:在那篇文章的示例1中,使用减法模式首先不会