Понимание TBitmap.Scanline в Delphi & C ++ Builder - PullRequest
6 голосов
/ 19 сентября 2011

Delphi & C ++ Builder имеет класс TBitmap со свойством Scanline, которое возвращает память пикселей растрового изображения.Это выглядит иначе, когда я смотрю в шестнадцатеричном редакторе файла BMP.

Я пытаюсь перенести приложение C ++ Builder на Java и хотел бы понять алгоритм в Scanline.Если у меня есть файл, как мне сгенерировать массив памяти, как Scanline?Какова точная спецификация Scanline?

Пояснение: BMP - это 24-битный DIB для Windows.Я не предоставляю никакой другой информации в коде;C ++ Builder, кажется, загружает его в некоторый тип структуры памяти, но это не побайтно.Хотелось бы узнать, какова спецификация этой структуры.

1 Ответ

8 голосов
/ 19 сентября 2011

Файл растрового изображения начинается с BITMAPFILEHEADER, элемент bfOffBits указывает начальный адрес данных изображения.Это DWORD в Dh (11-14-е байты).Delphi VCL имеет структуру, определенную как TBitmapFileHeader в «windows.pas».

Последняя строка ScanLine указывает на эти данные изображения (снизу вверх).VCL имеет это значение в bmBits члене dsBm (a BITMAP) члена или DIBSECTION изображения.Когда запрашивается строка сканирования, VCL вычисляет смещение в зависимости от запрошенной строки, количества пикселей в строке (ширины изображения) и того, сколько бит составляют пиксель, и возвращает указатель на адрес, добавляющий это смещениеbmBits.Это действительно побайтовые данные изображения.

Приведенный ниже пример кода Delphi считывает 24-битное растровое изображение в файловый поток и сравнивает каждый считанный пиксель с данными пикселя Bitmap.ScanLine аналога:

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;

Картинка о нахождении начальных данных пикселей растрового файла в hex-редакторе:enter image description here

...