LazMapViewer: Rework text drawing in TRGBGraphicsDrawingEngine to avoid by-pass to LazIntfImage in favour of built-in graphics routines.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9313 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2024-04-03 16:06:28 +00:00
parent 9be8f8eb5e
commit 7d571238f8
2 changed files with 151 additions and 93 deletions

View File

@ -17,9 +17,9 @@ unit mvDE_RGBGraphics;
interface
uses
Classes, SysUtils, Types, Graphics, IntfGraphics,
mvDrawingEngine, mvCache,
rgbGraphics, rgbTypes;
Classes, SysUtils, Types, Graphics,
mvTypes, mvDrawingEngine, mvCache,
rgbGraphics, rgbTypes, rgbRoutines;
type
@ -51,6 +51,7 @@ type
FPenStyle: TPenStyle;
FPenWidth: Integer;
protected
procedure DrawBitmapOT(X, Y: Integer; ABitmap: TCustomBitmap; AOpaqueColor, ATransparentColor: TColor);
function GetPenStyle: TPenStyle; override;
function GetBrushColor: TColor; override;
function GetBrushStyle: TBrushStyle; override;
@ -100,35 +101,106 @@ procedure Register;
implementation
uses
GraphType, LCLType, FPImage, Math,
mvTypes, RGBRoutines;
GraphType, LCLType, FPImage, Math;
procedure Register;
begin
RegisterComponents(PALETTE_PAGE, [TMvRGBGraphicsDrawingEngine]);
end;
{ We must duplicate some routines from rgbTypes which are not accessible. }
{$ifdef LCLwin32}
{$define RGB}
{$endif}
{$ifdef LCLqt}
{$define RGB}
{$endif}
{$ifdef LCLqt5}
{$define RGB}
{$endif}
{$ifdef LCLqt6}
{$define RGB}
{$endif}
function GetRedInline(P: TRGB32Pixel): Byte; inline;
begin
{$IFDEF RGB}
Result := (P and $FF0000) shr 16;
{$ELSE}
Result := P and $FF;
{$ENDIF}
end;
function GetGreenInline(P: TRGB32Pixel): Byte; inline;
begin
{$IFDEF RGB}
Result := (P and $FF00) shr 8;
{$ELSE}
Result := (P and $FF00) shr 8;
{$ENDIF}
end;
function GetBlueInline(P: TRGB32Pixel): Byte; inline;
begin
{$IFDEF RGB}
Result := P and $FF;
{$ELSE}
Result := (P and $FF0000) shr 16;
{$ENDIF}
end;
function RGBToRGB32PixelInline(R, G, B: Byte): TRGB32Pixel; inline;
begin
{$IFDEF RGB}
Result := B or (G shl 8) or (R shl 16);
{$ELSE}
Result := R or (G shl 8) or (B shl 16);
{$ENDIF}
end;
function ColorToRGB32PixelInline(C: TColor): TRGB32Pixel; inline;
begin
{$IFDEF RGB}
Result := ((C and $FF0000) shr 16) or (C and $FF00) or ((C and $FF) shl 16);
{$ELSE}
Result := C and $FFFFFF;
{$ENDIF}
end;
function CalculateGray(P: TRGB32Pixel): Byte; inline;
var
r, g, b: Byte;
begin
r := GetRedInline(P);
g := GetGreenInline(P);
b := GetBlueInline(P);
Result := round(0.299 * r + 0.587 * g + 0.114 * b);
end;
// P1 points to background pixel, P2 to overlay image pixel
procedure AlphaBlendRGB32Pixel(Alpha: Byte; P1, P2, AResult: PRGB32Pixel); inline;
var
r1, g1, b1: Byte;
r2, g2, b2: Byte;
begin
r1 := P1^;
g1 := P1^ shr 8;
b1 := P1^ shr 16;
r1 := GetRedInline(P1^);
g1 := GetGreenInline(P1^);
b1 := GetBlueInline(P1^);
r2 := P2^;
g2 := P2^ shr 8;
b2 := P2^ shr 16;
r2 := GetRedInline(P2^);
g2 := GetGreenInline(P2^);
b2 := GetBlueInline(P2^);
r1 := (word((255 - Alpha) * r1) + word(Alpha) * r2) shr 8;
g1 := (word((255 - Alpha) * g1) + word(Alpha) * g2) shr 8;
b1 := (word((255 - Alpha) * b1) + word(Alpha) * b2) shr 8;
AResult^ := r1 + g1 shl 8 + b1 shl 16;
AResult^ := RGBToRGB32PixelInline(r1, g1, b1);
end;
procedure AlphaBlendImages(ABackground, ABitmap: TRGB32Bitmap; X, Y: Integer; AAlpha: Byte);
procedure AlphaBlendImages(ABackground, ABitmap: TRGB32Bitmap; X, Y: Integer;
AAlpha: Byte = -1);
var
BkgX, BkgY, XMax, YMax, I, J, ImgX, ImgY: Integer;
P1, P2: PRGB32Pixel;
@ -145,7 +217,7 @@ begin
begin
P1 := ABackground.Get32PixelPtr(BkgX, BkgY + J);
P2 := ABitmap.Get32PixelPtr(ImgX, ImgY + J);
if AAlpha > 0 then
if AAlpha >= 0 then
for I := 0 to XMax do
begin
AlphaBlendRGB32Pixel(AAlpha, P1, P2, P1);
@ -166,6 +238,7 @@ begin
end;
end;
{ TRGB32BitmapCacheItem }
function TRGB32BitmapCacheItem.GetImage: TRGB32Bitmap;
@ -215,33 +288,74 @@ begin
FBuffer := TRGB32Bitmap.Create(AWidth, AHeight);
end;
procedure TMvRGBGraphicsDrawingEngine.DrawBitmap(X,Y: Integer;
procedure TMvRGBGraphicsDrawingEngine.DrawBitmap(X, Y: Integer;
ABitmap: TCustomBitmap; UseAlphaChannel: Boolean);
var
intfImg: TLazIntfImage;
i, j: Integer;
cimg, cbuf: TFPColor;
alpha: Double;
bmp32: TRGB32Bitmap;
begin
intfImg := ABitmap.CreateIntfImage;
bmp32 := TRGB32Bitmap.CreateFromBitmap(ABitmap);
try
if UseAlphaChannel then begin
for j := 0 to intfImg.Height - 1 do
for i := 0 to intfImg.Width - 1 do begin
cimg := intfImg.Colors[i, j];
alpha := cimg.Alpha / word($FFFF);
cbuf := TColorToFPColor(FBuffer.Canvas.GetColor(i + X, j + Y));
cbuf.Red := Round(alpha * cimg.Red + (1 - alpha) * cbuf.Red);
cbuf.Green := Round(alpha * cimg.Green + (1 - alpha) * cbuf.Green);
cbuf.Blue := Round(alpha * cimg.Blue + (1 - alpha) * cbuf.Blue);
FBuffer.Canvas.SetColor(i + X, j + Y, FPColorToTColor(cbuf));
end;
end else
for j := 0 to intfImg.Height - 1 do
for i := 0 to intfImg.Width - 1 do
FBuffer.Canvas.SetColor(i + X, j + Y, FPColorToTColor(intfImg.Colors[i, j]));
if UseAlphaChannel then
AlphaBlendImages(FBuffer, bmp32, X, Y)
else
FBuffer.Draw(X, Y, bmp32);
finally
intfimg.Free;
bmp32.Free;
end;
end;
procedure TMvRGBGraphicsDrawingEngine.DrawBitmapOT(X, Y: Integer;
ABitmap: TCustomBitmap; AOpaqueColor, ATransparentColor: TColor);
var
bmp32: TRGB32Bitmap;
BkgX, BkgY, XMax, YMax, I, J, ImgX, ImgY: Integer;
P1, P2: PRGB32Pixel;
alpha: PRGB8Pixel;
transpPixel, opaquePixel, workPixel: TRGB32Pixel;
gray, bkGray: Word;
begin
BkgX := Max(0, X);
BkgY := Max(0, Y);
ImgX := Max(0, -X);
ImgY := Max(0, -Y);
XMax := Min(ABitmap.Width - ImgX, FBuffer.Width - BkgX) - 1;
YMax := Min(ABitmap.Height - ImgY, FBuffer.Height - BkgY) - 1;
opaquePixel := ColorToRGB32PixelInline(AOpaqueColor);
transpPixel := ColorToRGB32PixelInline(ATransparentColor);
bkGray := CalculateGray(transpPixel);
bmp32 := TRGB32Bitmap.CreateFromBitmap(ABitmap);
try
for J := YMax downto 0 do
begin
P1 := FBuffer.Get32PixelPtr(BkgX, BkgY + J);
P2 := bmp32.Get32PixelPtr(ImgX, ImgY + J);
alpha := bmp32.Mask.Get8PixelPtr(ImgX, ImgY + J);
for I := 0 to XMax do
begin
workPixel := P2^ and $00FFFFFF;
if workPixel = transpPixel then
alpha^ := 0
else
if workPixel = opaquePixel then
alpha^ := 255
else
begin
gray := CalculateGray(P2^);
workPixel := opaquePixel;
if gray > bkGray then
alpha^ := gray - bkGray
else
alpha^ := bkGray - gray;
end;
AlphaBlendRGB32Pixel(alpha^, P1, @workPixel, P1);
inc(P1);
inc(P2);
inc(alpha);
end;
end;
finally
bmp32.Free;
end;
end;
@ -527,60 +641,6 @@ begin
end;
end;
(*
procedure TMvRGBGraphicsDrawingEngine.TextOut(X, Y: Integer; const AText: String);
var
bmp: TBitmap;
ex: TSize;
img: TLazIntfImage;
brClr: TFPColor;
imgClr: TFPColor;
i, j: Integer;
begin
if (AText = '') then
exit;
bmp := TBitmap.Create;
try
bmp.PixelFormat := pf32Bit;
bmp.SetSize(1, 1);
bmp.Canvas.Font.Name := FFontName;
bmp.Canvas.Font.Size := FFontSize;
bmp.Canvas.Font.Style := FFontStyle;
bmp.Canvas.Font.Color := FFontColor;
ex := bmp.Canvas.TextExtent(AText);
bmp.SetSize(ex.CX, ex.CY);
bmp.Canvas.Brush.Color := GetBrushColor;
if GetBrushStyle = bsClear then
bmp.Canvas.Brush.Style := bsSolid
else
bmp.Canvas.Brush.Style := GetBrushStyle;
bmp.Canvas.FillRect(0, 0, bmp.Width, bmp.Height);
bmp.Canvas.TextOut(0, 0, AText);
img := bmp.CreateIntfImage;
try
if GetBrushStyle = bsClear then begin
brClr := TColorToFPColor(GetBrushColor);
for j := 0 to img.Height - 1 do
for i := 0 to img.Width - 1 do begin
imgClr := img.Colors[i, j];
if (imgClr.Red = brClr.Red) and (imgClr.Green = brClr.Green) and (imgClr.Blue = brClr.Blue) then
Continue;
FBuffer.Canvas.SetColor(X + i, Y + j, FPColorToTColor(imgClr));
end;
end else
for j := 0 to img.Height - 1 do
for i := 0 to img.Width - 1 do
FBuffer.Canvas.SetColor(X + i, Y + j, FPColorToTColor(img.Colors[i, j]));
finally
img.Free;
end;
finally
bmp.Free;
end;
end;
*)
procedure TMvRGBGraphicsDrawingEngine.TextOut(X, Y: Integer; const AText: String);
var
bmp: TBitmap;
@ -590,8 +650,7 @@ begin
exit;
bmp := TBitmap.Create;
try
bmp.PixelFormat := pf32Bit;
bmp.SetSize(1, 1);
bmp.PixelFormat := pf24Bit; // Does not work with 32 bpp...
bmp.Canvas.Font.Name := FFontName;
bmp.Canvas.Font.Size := FFontSize;
bmp.Canvas.Font.Style := FFontStyle;

View File

@ -53,7 +53,6 @@ type
procedure CreateBuffer(AWidth, AHeight: Integer); virtual; abstract;
procedure DrawBitmap(X, Y: Integer; ABitmap: TCustomBitmap;
UseAlphaChannel: Boolean); virtual; abstract;
// Drawing bitmap with a given opaque and transparent colors
procedure DrawCacheItem(X, Y: Integer; AImg: TPictureCacheItem;
ADrawMode: TItemDrawMode = idmDraw; AOpacity: Single = 1.0); virtual; abstract;
procedure DrawScaledCacheItem(DestRect, SrcRect: TRect; AImg: TPictureCacheItem); virtual; abstract;