【问题标题】:How to wrap an existing memory buffer as a DC for GDI如何将现有内存缓冲区包装为 GDI 的 DC
【发布时间】:2008-09-18 10:36:08
【问题描述】:

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

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

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

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

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

谢谢!

【问题讨论】:

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


    【解决方案1】:

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

    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 的值!

    【讨论】:

    • 是否可以将Scan0 传递到非托管代码中进行操作?
    • 我相信是的,只要你不释放你的锁,它就会被 GC 固定。
    【解决方案2】:

    使用 CreateDIBitmap 而不是 CreateDIBSection。

    【讨论】:

      【解决方案3】:

      如果您想消除副本(第 2 步),只需首先使用 CreateDIBSection 创建您的原始内存缓冲区。然后,您可以为该位图创建一个兼容的 DC,并将其用作 BitBlt 操作的源。

      即如果您首先使用 CreateDIBSection 位图而不是“普通内存”缓冲区,则无需在传输之前将内存从“普通内存”缓冲区复制到 CreateDIBSection 位图。

      毕竟,使用 CreateDIBSection 分配的缓冲区本质上只是一个与 CreateCompatibleDC 兼容的“普通内存”缓冲区,这正是您要寻找的。​​p>

      【讨论】:

      【解决方案4】:

      你最初是如何将屏幕内容放入这个 24bpp 内存缓冲区的?

      避免不必要的 memcpy 的明显方法是通过首先创建 24bpp DIBSection 并将其作为目标缓冲区传递给 screengrab 函数来颠覆原始屏幕抓取。

      如果那不可能,您仍然可以尝试通过创建一个描述内存缓冲区格式的 BITMAPINFOHEADER 来强制 GDI 执行艰难的提升,然后只需调用 StretchDIBits 将其 blit 到您的 8bpp DIBSection 上。

      【讨论】:

        猜你喜欢
        • 2012-01-01
        • 2015-01-25
        • 2013-04-08
        • 2014-04-23
        • 1970-01-01
        • 2015-08-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多