3

画面の解像度 (24 ビット/ピクセルで 1280x800) に対応するメモリ バッファーがあり、24bpp の画面コンテンツが含まれています。これを 8 bpp (つまり、Windows のハーフトーン カラー パレット) に変換したいと考えています。私は現在これを行っています: 1. CreateDIBSection を使用して新しい 1280x800 24 bpp バッファーを割り当て、DC およびプレーン メモリ バッファーとしてアクセスします 2. memcpy を使用して、元のバッファーからステップ 1 のこの新しいバッファーにコピーします 3 . BitBlt を使用して GDI に色変換を実行させる

ステップ 2 の余分な memcpy を避けたいと考えています。これを行うには、次の 2 つの方法が考えられます。

を。元の mem buf を DC にラップして、そこから直接 BitBlt を実行します

b. 独自の 24 bpp から 8 bpp への色変換を記述します。Windows がこのハーフトーン カラー変換をどのように実装しているかについての情報が見つかりません。それに、わかったとしても、BitBlt がアクセスできる GDI のアクセラレーション機能を使用するつもりはありません。

では、(a) または (b) のいずれかを行うにはどうすればよいでしょうか。

ありがとう!

4

4 に答える 4

2

OK、問題の 2 つの部分に対処します。

  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 の値がある可能性があります。

于 2008-09-18T10:50:36.557 に答える
1

CreateDIBSection ではなく CreateDIBitmap を使用します。

于 2008-09-18T13:22:37.360 に答える
1

コピーを削除したい場合 (ステップ 2)、最初に CreateDIBSection を使用して元のメモリ バッファーを作成します。次に、そのビットマップに互換性のある DC を作成し、それを BitBlt 操作のソースとして使用できます。

つまり、最初に「プレーン メモリ」バッファの代わりに CreateDIBSection ビットマップを使用する場合、ブリッティングの前に「プレーン メモリ」バッファから CreateDIBSection ビットマップにメモリをコピーする必要はありません。

結局のところ、CreateDIBSection を使用して割り当てられたバッファーは、基本的に、探している CreateCompatibleDC と互換性のある単なる "プレーン メモリ" バッファーです。

于 2008-09-18T18:18:49.660 に答える
0

そもそもどうやってこの 24bpp メモリ バッファに画面の内容を入れたのでしょうか?

不必要な memcpy を回避する明白な方法は、最初に 24bpp DIBSection を作成し、それをスクリーングラブ関数に宛先バッファーとして渡すことによって、元のスクリーングラブを破壊することです。

それが不可能な場合でも、メモリ バッファーの形式を記述する BITMAPINFOHEADER を作成することで、GDI にハード リフトを実行させ、StretchDIBits を呼び出してそれを 8bpp DIBSection にブリットすることができます。

于 2008-10-13T15:51:32.430 に答える