Delphi - объектно-ориентированный язык программирования, разработанный компанией Borland в 1995 году. Он основан на языке программирования Pascal, но имеет более расширенные возможности и добавлены новые функции.
Delphi является интегрированной средой разработки (IDE), которая позволяет разрабатывать программное обеспечение для различных платформ, включая Windows, macOS, Android и iOS. Delphi достигает многоплатформенности с помощью...
functionMyGetMem(Size: DWORD): Pointer; begin
Result := Pointer(GlobalAlloc(GPTR, Size)); end
; procedure
MyFreeMem(p: Pointer); begin
if
p = nil
then
Exit; GlobalFree(THandle(p)); end
; { This code will fill a bitmap by stretching an image coming from a big bitmap on disk. FileName.- Name of the uncompressed bitmap to read DestBitmap.- Target bitmap where the bitmap on disk will be resampled. BufferSize.- The size of a memory buffer used for reading scanlines from the physical bitmap on disk. This value will decide how many scanlines can be read from disk at the same time, with always a minimum value of 2 scanlines. Will return false on error. } function
GetDIBInBands(const
FileName: string
; DestBitmap: TBitmap; BufferSize: Integer; out TotalBitmapWidth, TotalBitmapHeight: Integer): Boolean; var
FileSize: integer; // calculated file size ImageSize: integer; // calculated image size dest_MaxScans: integer; // number of scanline from source bitmap dsty_top: Integer; // used to calculate number of passes NumPasses: integer; // number of passed needed dest_Residual: integer; // number of scanlines on last band Stream: TStream; // stream used for opening the bitmap bmf: TBITMAPFILEHEADER; // the bitmap header lpBitmapInfo: PBITMAPINFO; // bitmap info record BitmapHeaderSize: integer; // size of header of bitmap SourceIsTopDown: Boolean; // is reversed bitmap ? SourceBytesPerScanLine: integer; // number of bytes per scanline SourceLastScanLine: Extended; // last scanline processes SourceBandHeight: Extended; // BitmapInfo: PBITMAPINFO; img_start: integer; img_end: integer; img_numscans: integer; OffsetInFile: integer; OldHeight: Integer; bits: Pointer; CurrentTop: Integer; CurrentBottom: Integer; begin
Result := False; // open the big bitmap Stream := TFileStream.Create(FileName, fmOpenRead or
fmShareDenyWrite); // total size of bitmap FileSize := Stream.Size; // read the header Stream.ReadBuffer(bmf, SizeOf(TBITMAPFILEHEADER)); // calculate header size BitmapHeaderSize := bmf.bfOffBits - SizeOf(TBITMAPFILEHEADER); // calculate size of bitmap bits ImageSize := FileSize - Integer(bmf.bfOffBits); // check for valid bitmap and exit if not if
((bmf.bfType <> $4D42) or
(Integer(bmf.bfOffBits) < 1) or
(FileSize < 1) or
(BitmapHeaderSize < 1) or
(ImageSize < 1) or
(FileSize < (SizeOf(TBITMAPFILEHEADER) + BitmapHeaderSize + ImageSize))) then
begin
Stream.Free; Exit; end
; lpBitmapInfo := MyGetMem(BitmapHeaderSize); try
Stream.ReadBuffer(lpBitmapInfo^, BitmapHeaderSize); // check for uncompressed bitmap if
((lpBitmapInfo^.bmiHeader.biCompression = BI_RLE4) or
(lpBitmapInfo^.bmiHeader.biCompression = BI_RLE8)) then
begin
Exit; end
; // bitmap dimensions TotalBitmapWidth := lpBitmapInfo^.bmiHeader.biWidth; TotalBitmapHeight := abs(lpBitmapInfo^.bmiHeader.biHeight); // is reversed order ? SourceIsTopDown := (lpBitmapInfo^.bmiHeader.biHeight < 0); // calculate number of bytes used per scanline SourceBytesPerScanLine := ((((lpBitmapInfo^.bmiHeader.biWidth * lpBitmapInfo^.bmiHeader.biBitCount) + 31) and
not
31) div
8); // adjust buffer size if
BufferSize < Abs(SourceBytesPerScanLine) then
BufferSize := Abs(SourceBytesPerScanLine); // calculate number of scanlines for every pass on the destination bitmap dest_MaxScans := round(BufferSize / abs(SourceBytesPerScanLine)); dest_MaxScans := round(dest_MaxScans * (DestBitmap.Height / TotalBitmapHeight)); if
dest_MaxScans < 2 then
dest_MaxScans := 2; // at least two scan lines // is not big enough ? if
dest_MaxScans > TotalBitmapHeight then
dest_MaxScans := TotalBitmapHeight; { count the number of passes needed to fill the destination bitmap } dsty_top := 0; NumPasses := 0; while
(dsty_Top + dest_MaxScans) <= DestBitmap.Height do
begin
Inc(NumPasses); Inc(dsty_top, dest_MaxScans); end
; if
NumPasses = 0 then
Exit; // calculate scanlines on last pass dest_Residual := DestBitmap.Height mod
dest_MaxScans; // now calculate how many scanlines in source bitmap needed for every band on the destination bitmap SourceBandHeight := (TotalBitmapHeight * (1 - (dest_Residual / DestBitmap.Height))) / NumPasses; // initialize first band CurrentTop := 0; CurrentBottom := dest_MaxScans; // a floating point used in order to not loose last scanline precision on source bitmap // because every band on target could be a fraction (not integral) on the source bitmap SourceLastScanLine := 0.0; while
CurrentTop < DestBitmap.Height do
begin
// scanline start of band in source bitmap img_start := Round(SourceLastScanLine); SourceLastScanLine := SourceLastScanLine + SourceBandHeight; // scanline finish of band in source bitmap img_end := Round(SourceLastScanLine); if
img_end > TotalBitmapHeight - 1 then
img_end := TotalBitmapHeight - 1; img_numscans := img_end - img_start; if
img_numscans < 1 then
Break; OldHeight := lpBitmapInfo^.bmiHeader.biHeight; if
SourceIsTopDown then
lpBitmapInfo^.bmiHeader.biHeight := -img_numscans else
lpBitmapInfo^.bmiHeader.biHeight := img_numscans; // memory used to read only the current band bits := MyGetMem(Abs(SourceBytesPerScanLine) * img_numscans); try
// calculate offset of band on disk OffsetInFile := TotalBitmapHeight - (img_start + img_numscans); Stream.Seek(Integer(bmf.bfOffBits) + (OffsetInFile * abs(SourceBytesPerScanLine)), soFromBeginning); Stream.ReadBuffer(bits^, abs(SourceBytesPerScanLine) * img_numscans); SetStretchBltMode(DestBitmap.Canvas.Handle, COLORONCOLOR); // now stretch the band readed to the destination bitmap StretchDIBits(DestBitmap.Canvas.Handle, 0, CurrentTop, DestBitmap.Width, Abs(CurrentBottom - CurrentTop), 0, 0, TotalBitmapWidth, img_numscans, Bits, lpBitmapInfo^, DIB_RGB_COLORS, SRCCOPY); finally
MyFreeMem(bits); lpBitmapInfo^.bmiHeader.biHeight := OldHeight; end
; CurrentTop := CurrentBottom; CurrentBottom := CurrentTop + dest_MaxScans; if
CurrentBottom > DestBitmap.Height then
CurrentBottom := DestBitmap.Height; end
; finally
Stream.Free; MyFreeMem(lpBitmapInfo); end
; Result := True; end
; // example of usage procedure
TForm1.Button1Click(Sender: TObject); var
bmw, bmh: Integer; Bitmap: TBitmap; begin
Bitmap := TBitmap.Create; with
TOpenDialog.Create(nil
) do
try
DefaultExt := 'BMP'; Filter := 'Bitmaps (*.bmp)|*.bmp'; Title := 'Define bitmap to display'; if
not
Execute then
Exit; { define the size of the required bitmap } Bitmap.Width := Self.ClientWidth; Bitmap.Height := Self.ClientHeight; Bitmap.PixelFormat := pf24Bit; Screen.Cursor := crHourglass; // use 100 KB of buffer if
not
GetDIBInBands(FileName, Bitmap, 100 * 1024, bmw, bmh) then
Exit; // original bitmap width = bmw // original bitmap height = bmh Self.Canvas.Draw(0,0,Bitmap); finally
Free; Bitmap.Free; Screen.Cursor := crDefault; end
; end
;