2011-09-19 6 views
6

Delphi & C++ Builder ha una classe TBitmap con una proprietà Scanline che restituisce la memoria dei pixel della bitmap. Questo sembra essere diverso quando guardo in un editor esadecimale del file BMP.Informazioni su TBitmap.Scanline in Delphi & C++ Builder

Sto provando a portare un'app C++ Builder su Java e mi piacerebbe capire l'algoritmo in Scanline. Se ho il file, come faccio a generare l'array di memoria come fa Scanline? Qual è la specifica esatta dietro a Scanline?

Chiarificazione: il BMP è un DIB di Windows a 24 bit. Non fornisco altre informazioni nel codice; C++ Builder sembra caricarlo in qualche tipo di struttura di memoria, ma non è byte per byte. Vorrei sapere quali sono le specifiche di quella struttura.

+0

il nome "TBitmap" non significa necessariamente avere a che fare con il formato di file "bitmap" Microsoft, sai ! La proprietà "scanline" in una "TBitmap" di Delphi è solo una linea raster - niente di più, niente di meno. – paulsm4

+1

qual è il formato pixel del file bitmap e come lo si carica in un TBitmap? La tua bitmap è memorizzata in alto o in basso? –

+0

Quale parte della struttura vuoi capire? I campi TBitmap o i dati dei pixel? –

risposta

8

Un file bitmap inizia con un BITMAPFILEHEADER, il membro bfOffBits specifica l'indirizzo iniziale dei dati dell'immagine. Questo è un DWORD a Dh (11-14th byte). Delphi VCL ha la struttura definita come TBitmapFileHeader in "windows.pas".

L'ultima riga del ScanLine punta a questi dati immagine (dal basso verso l'alto). Il VCL ha questo valore nel membro bmBits del membro dsBm (a BITMAP) o nello DIBSECTION dell'immagine. Quando viene richiesta una linea di scansione, il VCL calcola un offset in base alla riga richiesta, al numero di pixel di una riga (larghezza dell'immagine) e al numero di bit che costituiscono un pixel e restituisce un puntatore a un indirizzo aggiungendo questo offset a bmBits. Sono davvero dati di immagine byte per byte.

Il sotto Delphi codice di esempio si legge in una bitmap 24 bit ad un flusso di file e lo confronta ogni pixel di lettura con i dati dei pixel del Bitmap.ScanLine controparte:

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; 



Un'immagine di trovare la partenza dei dati pixel di un file bitmap in un editor esadecimale:

enter image description here

+3

Risposta super! Ho ragione nel capire che l'unica differenza è che TBitmap.ScanLine è il primo della riga inferiore, mentre il file è il primo della riga superiore, ma ognuno rappresenterà la riga come la stessa sequenza di byte? (Almeno per DIB a 24 bit, che è quello che sto trattando.) – SRobertJames

+0

La maggior parte delle bitmap di Windows sono dal basso verso l'alto in modo che un file bitmap abbia prima la riga inferiore. 'bmBits' è solo un puntatore agli stessi dati che sono in memoria (tranne l'allineamento delle righe è leggermente diverso per il layout della memoria). Quando viene richiesta una scanline, i conti VCL per 'bottom-up' in 'TBitmap.GetScanLine' in graphics.pas. Se tu, fi, richiedi l'ultima riga ('Bmp.ScanLine [Bmp.Height - 1]') e la bitmap è bottom-up, VCL restituisce un puntatore alla prima riga dell'array di pixel (come l'ultima riga del linea di scansione). –

+0

Ancora problemi di comprensione. Vedo chiaramente nel mio editor esadecimale che i byte sono molto diversi. L'unica differenza è che l'ordine delle righe è invertito? – SRobertJames