我有一个与我的屏幕分辨率(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)?
谢谢!
最佳答案
好的,解决问题的两个部分。
以下代码展示了如何获取位图中的像素、更改它们并将它们放回位图中。你总是可以生成一个正确大小和格式的虚拟位图,打开它,复制你的数据,然后你有一个包含你的数据的位图对象:
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/