使用System.Drawing,我如何绘制一些模仿黄色突出显示标记效果的东西?

Cor*_*ger 6 .net system.drawing gdi+

我希望黄色的"背后"显示出来.

编辑1:但是,如果我正在画"白色",我希望标记颜色保持其纯黄色.

编辑2:@凯文的回答可能是正确的,我将其标记为正确,即使我没有编写代码.在我的代码中,我正在使用Color.FromArgb解决@ Guffa的问题.

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

Kev*_*eid 9

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

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


Cor*_*ger 1

这段代码有效。它消除了我想要黄色的每个 RGB 的蓝色分量。起初我尝试使用 Bitmap.GetPixel/SetPixel,但速度慢得令人痛苦。使用锁定/解锁来获取原始位的速度足够快。

                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);
Run Code Online (Sandbox Code Playgroud)