Pregunta

Tengo un búfer de memoria correspondiente a la resolución de mi pantalla (1280x800 a 24 bits por píxel) que contiene el contenido de mi pantalla a 24 bpp.Quiero convertir esto a 8 bpp (es decir.Paleta de colores de semitonos en Windows).Actualmente hago esto:1.Use CreatedIbsection para asignar un nuevo búfer de 1280x800 de 24 bpp y acceder a ella como DC, así como un búfer de memoria simple 2.Use MEMCPY para copiar desde mi búfer original a este nuevo búfer desde el paso 1 3.Utilice BitBlt para permitir que GDI realice la conversión de color

Quiero evitar la memoria adicional del paso 2.Para hacer esto, puedo pensar en dos enfoques:

a.Envuelva mi memoria original en un DC para realizar BitBlt directamente desde él

b.Escribir mi propia conversión de color de 24 bpp a 8 bpp.No puedo encontrar ninguna información sobre cómo Windows implementa esta conversión de color de medios tonos.Además, incluso si me entero, no utilizaré las funciones aceleradas de GDI a las que BitBlt tiene acceso.

Entonces, ¿cómo hago (a) o (b)?

¡gracias!

¿Fue útil?

Solución

Bien, para abordar las dos partes del problema.

  1. El siguiente código muestra cómo llegar a los píxeles dentro de un mapa de bits, cambiarlos y volver a colocarlos en el mapa de bits.Siempre puedes generar un mapa de bits ficticio del tamaño y formato correcto, abrirlo, copiar tus datos y luego tendrás un objeto de mapa de bits con tus datos:

    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);
    }
    

Para convertir el contenido a 8bpp querrás usar la clase System.Drawing.Imaging.ColorMatrix.No tengo a mano los valores de matriz correctos para los medios tonos, pero este ejemplo de escalas de grises y ajuste de los valores debería darle una idea del efecto:

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();

Intentaré actualizar más tarde con los valores de matriz para medios tonos, ¡es probable que haya muchos valores de 0,5 o 0,333 allí!

Otros consejos

Utilice CreateDIBitmap en lugar de CreateDIBSection.

Si desea eliminar la copia (paso 2), simplemente use CreateDIBSection para crear su búfer de memoria original en primer lugar.Luego, puede crear un DC compatible para ese mapa de bits y usarlo como fuente para la operación BitBlt.

Es decir.no es necesario copiar la memoria de un búfer de "memoria simple" a un mapa de bits CreateDIBSection antes de realizar la transferencia si utiliza un mapa de bits CreateDIBSection en lugar de un búfer de "memoria simple" en primer lugar.

Después de todo, un búfer asignado mediante CreateDIBSection es esencialmente un búfer de "memoria simple" que es compatible con CreateCompatibleDC, que es lo que está buscando.

¿Cómo conseguiste el contenido de la pantalla en este búfer de memoria de 24 bpp en primer lugar?

La ruta obvia para evitar una memoria innecesaria es subvertir la captura de pantalla original creando primero la DIBSection de 24 bpp y pasándola a la función de captura de pantalla como búfer de destino.

Si eso no es posible, todavía puedes intentar obligar a GDI a hacer el trabajo duro creando un BITMAPINFOHEADER que describa el formato del buffer de memoria, y simplemente llamar a StretchDIBits para transferirlo a tu DIBSection de 8bpp.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top