代码之家  ›  专栏  ›  技术社区  ›  Corey Trager

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

  •  6
  • Corey Trager  · 技术社区  · 15 年前

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

    编辑1:但是,如果我画的是“白色”,我希望标记的颜色保持它的纯黄色。

    编辑二:@kevin的答案可能是正确的,我把它标对了,尽管我没有把它编码。在我的代码中,我使用color.fromargb来接受@guffa的答案。

    编辑3:我发布了性能良好的代码。是的,减去蓝色是基本的想法,但是你不能用高级的api来做,setpixel太慢了。性能良好的解决方案使用bitmap.lockbits,unlockbits。

    5 回复  |  直到 13 年前
        1
  •  9
  •   Kevin Reid    13 年前

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

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

        2
  •  3
  •   Guffa    15 年前

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

    Color.FromArgb(128, Color.Yellow)
    

    使用较低的alpha值时,将显示更多的背景。

        3
  •  2
  •   Dan Byström    15 年前

    这是您需要的代码:

        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 );
            }
        }
    
        4
  •  1
  •   Corey Trager    14 年前

    这个代码有效。它抹去了我想要黄色的每个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);
    
        5
  •  0
  •   AakashM    15 年前

    尝试使用 SolidBrush 缩写为 Color alpha小于255的值。这将创建一个半透明的刷你使用的颜色。