procedure ExactTextPixels(const AFont: TFont; const AText: string; const ABackground: TColor; out ABitmap: TBitmap); overload;
var
Bitmap: TBitmap;
PixelX, PixelY, // for the scanning
LeftX, RightX, TopY, BottomY, // store each direction to accurate output AWidth and AHeight
SizeX, SizeY: Integer; // initial bitmap size
LRect: TRect;
begin
// Initialize the output values
LRect.Width := 0;
LRect.Height := 0;
LRect.Top := 0;
LRect.Left := 0;
LRect.Right := 0;
LRect.Bottom := 0;
// Create a bitmap and canvas
Bitmap := TBitmap.Create;
try
// Set the font for the canvas
Bitmap.Canvas.Font := AFont;
// Calculate the needed dimension and add more space for non-normal fonts or font styles
SizeX := Bitmap.Canvas.TextWidth(AText) * 3;
SizeY := Bitmap.Canvas.TextHeight(AText) * 3;
Bitmap.SetSize(SizeX, SizeY);
// Clear the bitmap and draw the text onto the bitmap,
// ensure that we got 2 different colors to check for one of them
Bitmap.Canvas.Brush.Color := ABackground;
Bitmap.Canvas.FillRect(Bitmap.Canvas.ClipRect);
// Bitmap.Canvas.Font.Color := clBlack;
Bitmap.Canvas.TextOut(0, 0, AText);
// Initialize scan variables in opposite manner to use Min() and Max() correct
LeftX := Bitmap.Width;
RightX := 0;
TopY := Bitmap.Height;
BottomY := 0;
// Scan the bitmap from left to right
for PixelX := 0 to Pred(Bitmap.Width) do
for PixelY := 0 to Pred(Bitmap.Height) do
if Bitmap.Canvas.Pixels[PixelX, PixelY] <> ABackground then
LeftX := Min(LeftX, PixelX);
// Scan the bitmap from right to left
for PixelX := Pred(Bitmap.Width) downto 0 do
for PixelY := 0 to Pred(Bitmap.Height) do
if Bitmap.Canvas.Pixels[PixelX, PixelY] <> ABackground then
RightX := Max(RightX, PixelX);
// Scan the bitmap from top to bottom
for PixelY := 0 to Pred(Bitmap.Height) do
for PixelX := 0 to Pred(Bitmap.Width) do
if Bitmap.Canvas.Pixels[PixelX, PixelY] <> ABackground then
TopY := Min(TopY, PixelY);
// Scan the bitmap from bottom to top
for PixelY := Pred(Bitmap.Height) downto 0 do
for PixelX := 0 to Pred(Bitmap.Width) do
if Bitmap.Canvas.Pixels[PixelX, PixelY] <> ABackground then
BottomY := Max(BottomY, PixelY);
// Calculate the width and height based on the scan results
LRect.Top := TopY;
LRect.Left := Succ(LeftX);
LRect.Bottom := Succ(BottomY);
LRect.Right := RightX;
ABitmap.SetSize(LRect.Width, LRect.Height);
ABitmap.Canvas.CopyMode := cmSrcCopy;
ABitmap.Canvas.CopyRect(ABitmap.Canvas.ClipRect, Bitmap.Canvas, LRect);
finally
Bitmap.Free;
end;
end;