c# - 如何将现有内存缓冲区包装为 GDI 的 DC

标签 c# .net c++ vb.net gdi+

我有一个与我的屏幕分辨率(1280x800,每像素 24 位)相对应的内存缓冲区,其中包含我的 24bpp 屏幕内容。我想将其转换为 8-bpp(即 Windows 中的半色调调色板)。 我目前这样做: 1. 使用 CreateDIBSection 分配一个新的 1280x800 24-bpp 缓冲区并将其作为 DC 以及普通内存缓冲区访问 2. 使用 memcpy 从我的原始缓冲区复制到步骤 1 中的这个新缓冲区 3.使用BitBlt让GDI进行颜色转换

我想避免步骤 2 的额外 memcpy。为此,我可以想到两种方法:

一个。将我原来的 mem buf 包装在一个 DC 中以直接从它执行 BitBlt

编写我自己的 24-bpp 到 8-bpp 颜色转换。我找不到有关 Windows 如何实现此半色调颜色转换的任何信息。此外,即使我知道了,我也不会使用 BitBlt 可以访问的 GDI 加速功能。

那么我该怎么做 (a) 或 (b)?

谢谢!

最佳答案

好的,解决问题的两个部分。

  1. 以下代码展示了如何获取位图中的像素、更改它们并将它们放回位图中。你总是可以生成一个正确大小和格式的虚拟位图,打开它,复制你的数据,然后你有一个包含你的数据的位图对象:

    private void LockUnlockBitsExample(PaintEventArgs e)
    {
    
       // Create a new bitmap.
       Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg");
    
       // Lock the bitmap's bits.  
       Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
       System.Drawing.Imaging.BitmapData bmpData =
             bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
             bmp.PixelFormat);
    
       // Get the address of the first line.
       IntPtr ptr = bmpData.Scan0;
    
       // Declare an array to hold the bytes of the bitmap.
       int bytes  = bmpData.Stride * bmp.Height;
       byte[] rgbValues = new byte[bytes];
    
       // Copy the RGB values into the array.
       System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
    
       // Set every third value to 255. A 24bpp bitmap will look red.  
       for (int counter = 2; counter < rgbValues.Length; counter += 3)
           rgbValues[counter] = 255;
    
       // Copy the RGB values back to the bitmap
       System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
    
       // Unlock the bits.
       bmp.UnlockBits(bmpData);
    
       // Draw the modified image.
       e.Graphics.DrawImage(bmp, 0, 150);
    }
    

要将内容转换为 8bpp,您需要使用 System.Drawing.Imaging.ColorMatrix 类。我手边没有正确的半色调矩阵值,但是这个示例灰度和值的调整应该让您了解效果:

Graphics g = e.Graphics;
Bitmap bmp = new Bitmap("sample.jpg");
g.FillRectangle(Brushes.White, this.ClientRectangle);

// Create a color matrix
// The value 0.6 in row 4, column 4 specifies the alpha value
float[][] matrixItems = {
                            new float[] {1, 0, 0, 0, 0},
                            new float[] {0, 1, 0, 0, 0},
                            new float[] {0, 0, 1, 0, 0},
                            new float[] {0, 0, 0, 0.6f, 0}, 
                            new float[] {0, 0, 0, 0, 1}};
ColorMatrix colorMatrix = new ColorMatrix(matrixItems);

// Create an ImageAttributes object and set its color matrix
ImageAttributes imageAtt = new ImageAttributes();
imageAtt.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

// Now draw the semitransparent bitmap image.
g.DrawImage(bmp, this.ClientRectangle, 0.0f, 0.0f, bmp.Width, bmp.Height, 
            GraphicsUnit.Pixel, imageAtt);

imageAtt.Dispose();

稍后我将尝试更新半色调的矩阵值,其中可能有很多 0.5 或 0.333 值!

关于c# - 如何将现有内存缓冲区包装为 GDI 的 DC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/91511/

相关文章:

c++ - 在关闭套接字之前发送数据包

c++ - 带有 RTTI 的 C++11 元组中的树

c++ - 解析 PE 文件中导入和导出表的 RVA

c# - 有没有一种方法可以使用 Adob​​e reader 类型库从 pdf 文件中读取表格数据(解析)

c# - 具有类型约束的扩展方法

c# - 在 Windows 窗体中加载没有 CrystalReportViewer 的 Crystal 报表模板

c# - 忽略排队的鼠标事件

c# - 根据 x64/x86 更改 C# DllImport 目标代码

c# - 在数组中的每个项目之后打印一个逗号 (,)

c# - KDB 简单键控表性能