Improving Image Scaling Quality in Delphi with StretchBlt and SetStretchBltMode (HALFTONE)
When scaling images in Delphi, the TCanvas.StretchDraw method may cause thin lines or small dots
to disappear. This happens because the default COLORONCOLOR stretch mode often produces noticeable
quality degradation.
This page explains how to achieve smoother and higher‑quality image scaling by using the Windows API
functions StretchBlt and SetStretchBltMode with the HALFTONE mode enabled.
The examples include proper handling of HDCs, raster operation flags, and other details required for
stable and high‑quality image processing in Delphi.
By setting the stretch mode to HALFTONE using
SetStretchBltMode and performing the copy with
StretchBlt, you can often achieve noticeably better scaling
results compared to the default behavior.
SetStretchBltMode API Function
function SetStretchBltMode(DC: HDC; StretchMode: Integer): Integer; stdcall;
- HDC
-
Specifies the handle to the device context.
(Example)Canvas.Handle - StretchMode
-
Specifies the stretch mode to use when scaling the image.
BLACKONWHITE
or
STRETCH_ANDSCANSSets each destination pixel to the result of a bitwise AND operation between the corresponding source and destination pixels. COLORONCOLOR
or
STRETCH_DELETESCANSReplaces each destination pixel with the corresponding source pixel. This is the default mode and may cause visible quality loss when shrinking images. HALFTONE
or
STRETCH_HALFTONEReplaces each destination pixel with a color value computed from the average of the surrounding source pixels. This mode provides the highest quality when reducing image size. WHITEONBLACK
or
STRETCH_ORSCANSSets each destination pixel to the result of a bitwise OR operation between the corresponding source and destination pixels. - Return Value
-
If the function succeeds, it returns the previous stretch mode.
If it fails, the return value is0.
StretchBlt API Function
function StretchBlt(
DestDC: HDC;
XDest, YDest, DestWidth, DestHeight: Integer;
SrcDC: HDC;
XSrc, YSrc, SrcWidth, SrcHeight: Integer;
Rop: DWORD
): BOOL; stdcall;
- HDC
- Specifies the handle to the destination device context.
- XDest
- Specifies the X‑coordinate of the upper‑left corner of the destination rectangle.
- YDest
- Specifies the Y‑coordinate of the upper‑left corner of the destination rectangle.
- DestWidth
- Specifies the width of the destination rectangle.
- DestHeight
- Specifies the height of the destination rectangle.
- HDC
- Specifies the handle to the source device context.
- XSrc
- Specifies the X‑coordinate of the upper‑left corner of the source rectangle.
- YSrc
- Specifies the Y‑coordinate of the upper‑left corner of the source rectangle.
- SrcWidth
- Specifies the width of the source rectangle.
- SrcHeight
- Specifies the height of the source rectangle.
- Rop
-
Specifies the raster‑operation code (ROP) used during the copy.
Common values include:
BLACKNESS Fills the destination area with black. DSTINVERT Inverts the destination pixels. NOTSRCERASE Sets each destination pixel to the inverse of the bitwise OR between the source and destination pixels. SRCAND Sets each destination pixel to the bitwise AND of the source and destination pixels. SRCCOPY Copies the source pixels directly to the destination. SRCERASE Sets each destination pixel to the inverse of the bitwise AND between the source and destination pixels. SRCINVERT Sets each destination pixel to the bitwise XOR of the source and destination pixels. SRCPAINT Sets each destination pixel to the bitwise OR of the source and destination pixels. WHITENESS Fills the destination area with white.
Try It Out
Designing the Form and Adding the Source Code
Start the Delphi IDE and create a new project by selecting
[File] → [New] → [Windows VCL Application – Delphi].
Place two TImage components and two TButton components on the form.
Copy and paste the following source code into your project.
Assign FormCreate to the TForm1.OnCreate event.
Assign Button1Click to the Button1.OnClick event.
Assign Button2Click to the Button2.OnClick event.
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;
type
TForm1 = class(TForm)
Image1: TImage;
Image2: TImage;
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var src,dest:TBitmap;
begin
src := Image1.Picture.Bitmap;
dest := Image2.Picture.Bitmap;
dest.Canvas.CopyMode := cmSrcCopy;
dest.Canvas.StretchDraw(
Rect(
0, 0, dest.Width, dest.Height
),
src
);
end;
procedure TForm1.Button2Click(Sender: TObject);
var src,dest:TBitmap;
begin
src := Image1.Picture.Bitmap;
dest := Image2.Picture.Bitmap;
SetStretchBltMode(dest.Canvas.Handle, HALFTONE);
StretchBlt(
dest.Canvas.Handle,
0, 0, dest.Width, dest.Height,
src.Canvas.Handle,
0, 0, src.Width, src.Height,
SRCCOPY
);
Image2.Invalidate;
end;
procedure TForm1.FormCreate(Sender: TObject);
var c:TCanvas;
w,h:Integer;
x,y:Integer;
begin
w := 200;
h := 200;
Image1.Width := w;
Image1.Height := h;
Image1.Picture.Bitmap.SetSize(w,h);
Image2.Width := w div 2;
Image2.Height := h div 2;
Image2.Picture.Bitmap.SetSize(w div 2, h div 2);
c := Image1.Picture.Bitmap.Canvas;
c.Brush.Color := $F8FFF8;
c.FillRect(Rect(0,0,w,h));
// Draw vertical red lines
c.Pen.Width := 1;
c.Pen.Color := clRed;
x := 20;
while x < w do
begin
c.MoveTo(x, 0);
c.LineTo(x, h);
Inc(x, 32);
end;
// Draw horizontal blue lines
c.Pen.Width := 2;
c.Pen.Color := clBlue;
y := 20;
while y < h do
begin
c.MoveTo(0, y);
c.LineTo(w, y);
Inc(y, 32);
end;
end;
end.
Running the Example
Run the application.
When you click Button1, the image in Image1 is scaled down to half size
and displayed in Image2.
Since this uses TCanvas.StretchDraw, the result may look blurry or lose detail.
When you click Button2, the image is again scaled to half size and drawn into Image2.
Because this version uses SetStretchBltMode together with
StretchBlt, the result is noticeably smoother and clearer.
