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.