Yes, I know, this is far from news, but since I just spent several hours trying to find out why my code didn’t work, I’ll document it here so I can look it up later.
There are various ways to draw a bitmap on a paintbox in Delphi. I’ll focus on the Windows API function StretchBlt.
// first, get the bitmap from somewhere if not GetBitmap(FPreviewBmp) then FPreviewBmp.Assign(nil); // calculate the available size to display the bitmap // keeping the aspect ratio cnv := pb_Preview.Canvas; BoxWidth := pb_Preview.Width; BoxHeight := pb_Preview.Height; BmpWidth := FPreviewBmp.Width; BmpHeight := FPreviewBmp.Height; HeightFactor := BoxHeight / BmpHeight; WidthFactor := BoxWidth / BmpWidth; if HeightFactor > WidthFactor then Factor := WidthFactor else Factor := HeightFactor; // we do not want to enlarge the picture if Factor > 1 then Factor := 1; // calculate size and offsets so it is shown centered BmpWidth := Trunc(BmpWidth * Factor); BmpHeight := Trunc(BmpHeight * Factor); BmpTop := (BoxHeight - BmpHeight) div 2; BmpLeft := (BoxWidth - BmpWidth) div 2; // set the StretchBlt mode (you basically always want COLORONCOLOR) SetStretchBltMode(cnv.Handle, COLORONCOLOR); // draw the bitmap to the paintbox // note that you need to use the Canvas handle of the bitmap, // not the handle of the bitmap itself Res := StretchBlt( cnv.Handle, BmpLeft, BmpTop, BmpWidth, BmpHeight, FPreviewBmp.Canvas.Handle, 0, 0, FPreviewBmp.Width, FPreviewBmp.Height, SRCCOPY); if not Res then begin err := GetLastError; cnv.TextOut(0, 0, Format('LastError: %d %s', [err, SysErrorMessage(err)])); end;
It took me hours to find out why in my original code StretchBlt failed with error code 6 (The handle is invalid). It was very simple:
StretchBlt must be passed FPreviewBmp.Canvas.Handle rather than FPreviewBmp.Handle.
After changing that, it simply worked.