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

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

一种。将我的原始内存buf包裹在DC中,以直接从中执行BitBlt

b。编写我自己的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值!

    08-28 23:06