문제

24bpp의 화면 내용을 포함하는 화면 해상도(픽셀당 24비트에서 1280x800)에 해당하는 메모리 버퍼가 있습니다.이것을 8-bpp로 변환하고 싶습니다(예:Windows의 하프톤 색상 팔레트).나는 현재 다음을 수행합니다.1.CreateBsection을 사용하여 새로운 1280x800 24-BPP 버퍼를 할당하고 DC로 액세스하고 일반 메모리 버퍼 2입니다.Memcpy를 사용하여 원래 버퍼에서 1 단계 3 에서이 새로운 버퍼로 복사하십시오.BitBlt를 사용하여 GDI가 색상 변환을 수행하도록 합니다.

2단계의 추가 memcpy를 피하고 싶습니다.이를 위해 두 가지 접근 방식을 생각해 볼 수 있습니다.

ㅏ.내 원본 mem buf를 DC에 래핑하여 DC에서 직접 BitBlt를 수행합니다.

비.나만의 24bpp에서 8bpp 색상 변환을 작성해 보세요.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.드로잉.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 값이 많이 있을 것 같습니다!

다른 팁

CreateDIBSection 대신 CreateDIBitmap을 사용하십시오.

복사본을 제거하려면(2단계) 먼저 CreateDIBSection을 사용하여 원래 메모리 버퍼를 생성하십시오.그런 다음 해당 비트맵에 대해 호환 가능한 DC를 생성하고 이를 BitBlt 작업의 소스로 사용할 수 있습니다.

즉.처음에 "일반 메모리" 버퍼 대신 CreateDIBSection 비트맵을 사용하는 경우 블리팅 전에 "일반 메모리" 버퍼에서 CreateDIBSection 비트맵으로 메모리를 복사할 필요가 없습니다.

결국 CreateDIBSection을 사용하여 할당된 버퍼는 본질적으로 사용자가 찾고 있는 CreateCompatibleDC와 호환되는 "일반 메모리" 버퍼일 뿐입니다.

처음에 이 24bpp 메모리 버퍼에 화면 내용을 어떻게 넣었나요?

불필요한 memcpy를 피하는 확실한 방법은 먼저 24bpp DIBSection을 생성하고 이를 대상 버퍼로 screengrab 함수에 전달하여 원본 screengrab을 파괴하는 것입니다.

이것이 가능하지 않은 경우 메모리 버퍼의 형식을 설명하는 BITMAPINFOHEADER를 생성하여 GDI가 어려운 작업을 수행하도록 강제하고 StretchDIBits를 호출하여 이를 8bpp DIBSection에 블릿할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top