2011-09-19 19 views
6

Delphi & C++ Builder tiene una clase TBitmap con una propiedad Scanline que devuelve la memoria de los píxeles del mapa de bits. Esto parece ser diferente cuando miro en un editor hexadecimal del archivo BMP.Comprender TBitmap.Scanline en Delphi & C++ Builder

Estoy tratando de portar una aplicación C++ Builder a Java, y me gustaría entender el algoritmo en Scanline. Si tengo el archivo, ¿cómo puedo generar la matriz de memoria como lo hace Scanline? ¿Cuál es la especificación exacta detrás de Scanline?

Clarificación: El BMP es un DIB de Windows de 24 bits. No proporciono ninguna otra información en el código; C++ Builder parece cargarlo en algún tipo de estructura de memoria, pero no es byte por byte. Me gustaría saber cuál es la especificación de esa estructura.

+0

el nombre "TBitmap" no necesariamente tiene nada que ver con el formato de archivo "mapa de bits" Microsoft, ya sabes ! La propiedad "scanline" en Delphi "TBitmap" es solo una línea de trama, nada más y nada menos. – paulsm4

+1

¿cuál es el formato de píxel del archivo de mapa de bits y cómo lo carga en un TBitmap? ¿Está tu mapa de bits almacenado de arriba hacia abajo o de abajo hacia abajo? –

+0

¿Qué parte de la estructura quieres entender? Los campos TBitmap o los datos de píxeles? –

Respuesta

8

Un archivo de mapa de bits comienza con BITMAPFILEHEADER, el miembro bfOffBits especifica la dirección de inicio de los datos de imagen. Este es un DWORD en Dh (11-14th bytes). Delphi VCL tiene la estructura definida como TBitmapFileHeader en 'windows.pas'.

La última fila del ScanLine apunta a esta información de imagen (de abajo hacia arriba). El VCL tiene este valor en bmBits miembro del miembro dsBm (a BITMAP) o DIBSECTION de la imagen. Cuando se solicita una línea de escaneo, la VCL calcula una compensación en función de la fila solicitada, el número de píxeles en una fila (ancho de la imagen) y cuántos bits componen un píxel, y devuelve un puntero a una dirección que agrega esta compensación a bmBits. En realidad, se trata de datos de imagen byte a byte.

La continuación código de ejemplo Delphi lee un mapa de bits de 24 bits a una secuencia de archivo y compara cada píxel de lectura con los datos de píxeles de la Bitmap.ScanLine contraparte:

procedure TForm1.Button1Click(Sender: TObject); 
var 
    BmpFile: string; 
    Bmp: TBitmap; 

    fs: TFileStream; 
    FileHeader: TBitmapFileHeader; 
    InfoHeader: TBitmapInfoHeader; 
    iHeight, iWidth, Padding: Longint; 

    ScanLine: Pointer; 
    RGBFile, RGBBitmap: TRGBTriple; 
begin 
    BmpFile := ExtractFilePath(Application.ExeName) + 'Attention_128_24.bmp'; 

    // laod bitmap to TBitmap 
    Bmp := TBitmap.Create; 
    Bmp.LoadFromFile(BmpFile); 
    Assert(Bmp.PixelFormat = pf24bit); 

    // read bitmap file with stream 
    fs := TFileStream.Create(BmpFile, fmOpenRead or fmShareDenyWrite); 
    // need to get the start of pixel array 
    fs.Read(FileHeader, SizeOf(FileHeader)); 
    // need to get width and height of bitmap 
    fs.Read(InfoHeader, SizeOf(InfoHeader)); 
    // just a general demo - no top-down image allowed 
    Assert(InfoHeader.biHeight > 0); 
    // size of each row is a multiple of the size of a DWORD 
    Padding := SizeOf(DWORD) - 
     (InfoHeader.biWidth * 3) mod SizeOf(DWORD); // pf24bit -> 3 bytes 

    // start of pixel array 
    fs.Seek(FileHeader.bfOffBits, soFromBeginning); 


    // compare reading from file stream with the value from scanline 
    for iHeight := InfoHeader.biHeight - 1 downto 0 do begin 

    // get the scanline, bottom first 
    ScanLine := Bmp.ScanLine[iHeight]; 

    for iWidth := 0 to InfoHeader.biWidth - 1 do begin 

     // read RGB from file stream 
     fs.Read(RGBFile, SizeOf(RGBFile)); 

     // read RGB from scan line 
     RGBBitmap := TRGBTriple(Pointer(
         Longint(ScanLine) + (iWidth * SizeOf(TRGBTriple)))^); 

     // assert the two values are the same 
     Assert((RGBBitmap.rgbtBlue = RGBFile.rgbtBlue) and 
      (RGBBitmap.rgbtGreen = RGBFile.rgbtGreen) and 
      (RGBBitmap.rgbtRed = RGBFile.rgbtRed)); 
    end; 
    // skip row padding 
    fs.Seek(Padding, soCurrent); 
    end; 
end; 



Una imagen sobre la búsqueda de la puesta en marcha de los datos de píxeles de un archivo de mapa de bits en un editor hexadecimal:

enter image description here

+3

¡Súper respuesta! ¿Estoy en lo cierto al entender que la única diferencia es que TBitmap.ScanLine está en la fila inferior, mientras que el archivo es primero en la fila superior, pero cada uno representará la fila como la misma secuencia de bytes? (Al menos para DIB de 24 bits, que es con lo que estoy tratando). – SRobertJames

+0

La mayoría de los mapas de bits de Windows son de abajo hacia arriba, por lo que un archivo de mapa de bits tiene primero la fila inferior. 'bmBits' es solo un puntero a los mismos datos que están en la memoria (excepto que la alineación de las filas es un poco diferente para el diseño de la memoria). Cuando se solicita una línea de exploración, el VCL cuenta para 'bottom-up'ness' en 'TBitmap.GetScanLine' en graphics.pas. Si usted, fi, solicita la última fila ('Bmp.ScanLine [Bmp.Height - 1]') y el mapa de bits es de abajo hacia arriba, VCL devuelve un puntero a la primera fila de la matriz de píxeles (como la última fila del scanline). –

+0

Aún tengo problemas para entenderlo. Veo claramente en mi editor hexadecimal que los bytes son bastante diferentes. ¿La única diferencia se invierte el orden de las filas? – SRobertJames

Cuestiones relacionadas