354 lines
9.2 KiB
ObjectPascal
354 lines
9.2 KiB
ObjectPascal
// SPDX-License-Identifier: LGPL-3.0-linking-exception
|
|
{******************************* CONTRIBUTOR(S) ******************************
|
|
- Edivando S. Santos Brasil | mailedivando@gmail.com
|
|
(Compatibility with delphi VCL 11/2018)
|
|
|
|
***************************** END CONTRIBUTOR(S) *****************************}
|
|
unit BCSVGViewer;
|
|
|
|
{$I bgracontrols.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, BGRAGraphicControl,
|
|
{$IFDEF FPC}LResources, LCLType, {$ENDIF}
|
|
{$IFNDEF FPC}Types, BGRAGraphics, GraphType, FPImage, {$ENDIF}
|
|
BGRABitmap, BGRABitmapTypes, BGRASVG, BGRAUnits, BCTypes;
|
|
|
|
type
|
|
|
|
{ TBCSVGViewer }
|
|
|
|
TBCSVGViewer = class(TCustomBGRAGraphicControl)
|
|
private
|
|
FDrawCheckers: boolean;
|
|
FHorizAlign: TAlignment;
|
|
FProportional: boolean;
|
|
FStretchMode: TBCStretchMode;
|
|
FDestDPI: single;
|
|
FUseSVGAlignment: boolean;
|
|
FVertAlign: TTextLayout;
|
|
Fx: single;
|
|
Fy: single;
|
|
function GetSVGString: string;
|
|
procedure SetDrawCheckers(AValue: boolean);
|
|
procedure SetFDestDPI(AValue: single);
|
|
procedure SetSVGString(AValue: string);
|
|
procedure SetFx(AValue: single);
|
|
procedure SetFy(AValue: single);
|
|
procedure SetHorizAlign(AValue: TAlignment);
|
|
procedure SetProportional(AValue: boolean);
|
|
procedure SetStretchMode(AValue: TBCStretchMode);
|
|
procedure SetUseSVGAlignment(AValue: boolean);
|
|
procedure SetVertAlign(AValue: TTextLayout);
|
|
protected
|
|
FSVG: TBGRASVG;
|
|
procedure RedrawBitmapContent; override;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure LoadFromFile(AFileName: string);
|
|
procedure LoadFromResource(Resource: string);
|
|
function GetSVGRectF: TRectF;
|
|
function GetSVGContainerRectF: TRectF;
|
|
published
|
|
{ Published declarations }
|
|
property Align;
|
|
property Anchors;
|
|
property OnRedraw;
|
|
property Bitmap;
|
|
property BorderSpacing;
|
|
property Constraints;
|
|
property SVG: TBGRASVG read FSVG;
|
|
property SVGString: string read GetSVGString write SetSVGString;
|
|
property DestDPI: single read FDestDPI write SetFDestDPI {$IFDEF FPC} default
|
|
96{$ENDIF};
|
|
property x: single read Fx write SetFx {$IFDEF FPC} default 0{$ENDIF};
|
|
property y: single read Fy write SetFy {$IFDEF FPC} default 0{$ENDIF};
|
|
property HorizAlign: TAlignment read FHorizAlign write SetHorizAlign default
|
|
taCenter;
|
|
property VertAlign: TTextLayout read FVertAlign write SetVertAlign default tlCenter;
|
|
property StretchMode: TBCStretchMode
|
|
read FStretchMode write SetStretchMode default smStretch;
|
|
property Proportional: boolean read FProportional write SetProportional default True;
|
|
property DrawCheckers: boolean
|
|
read FDrawCheckers write SetDrawCheckers default False;
|
|
property UseSVGAlignment: boolean read FUseSVGAlignment write SetUseSVGAlignment default False;
|
|
property Color;
|
|
property ColorOpacity;
|
|
property OnClick;
|
|
property OnDblClick;
|
|
property OnMouseDown;
|
|
property OnMouseEnter;
|
|
property OnMouseLeave;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
{$IFDEF FPC}
|
|
property OnPaint;
|
|
{$ENDIF}
|
|
property OnResize;
|
|
property Caption;
|
|
end;
|
|
|
|
{$IFDEF FPC}procedure Register;{$ENDIF}
|
|
|
|
implementation
|
|
|
|
uses BGRAVectorize, math;
|
|
|
|
{$IFDEF FPC}
|
|
procedure Register;
|
|
begin
|
|
RegisterComponents('BGRA Controls', [TBCSVGViewer]);
|
|
end;
|
|
|
|
{$ENDIF}
|
|
|
|
{ TBCSVGViewer }
|
|
|
|
procedure TBCSVGViewer.SetFDestDPI(AValue: single);
|
|
begin
|
|
if FDestDPI = AValue then
|
|
Exit;
|
|
FDestDPI := AValue;
|
|
DiscardBitmap;
|
|
end;
|
|
|
|
procedure TBCSVGViewer.SetSVGString(AValue: string);
|
|
begin
|
|
FSVG.ASUTF8String := AValue;
|
|
DiscardBitmap;
|
|
end;
|
|
|
|
procedure TBCSVGViewer.SetDrawCheckers(AValue: boolean);
|
|
begin
|
|
if FDrawCheckers = AValue then
|
|
Exit;
|
|
FDrawCheckers := AValue;
|
|
DiscardBitmap;
|
|
end;
|
|
|
|
function TBCSVGViewer.GetSVGString: string;
|
|
begin
|
|
Result := FSVG.AsUTF8String;
|
|
end;
|
|
|
|
procedure TBCSVGViewer.SetFx(AValue: single);
|
|
begin
|
|
if Fx = AValue then
|
|
Exit;
|
|
Fx := AValue;
|
|
DiscardBitmap;
|
|
end;
|
|
|
|
procedure TBCSVGViewer.SetFy(AValue: single);
|
|
begin
|
|
if Fy = AValue then
|
|
Exit;
|
|
Fy := AValue;
|
|
DiscardBitmap;
|
|
end;
|
|
|
|
procedure TBCSVGViewer.SetHorizAlign(AValue: TAlignment);
|
|
begin
|
|
if FHorizAlign = AValue then
|
|
Exit;
|
|
FHorizAlign := AValue;
|
|
DiscardBitmap;
|
|
end;
|
|
|
|
procedure TBCSVGViewer.SetProportional(AValue: boolean);
|
|
begin
|
|
if FProportional = AValue then
|
|
Exit;
|
|
FProportional := AValue;
|
|
DiscardBitmap;
|
|
end;
|
|
|
|
procedure TBCSVGViewer.SetStretchMode(AValue: TBCStretchMode);
|
|
begin
|
|
if FStretchMode = AValue then
|
|
Exit;
|
|
FStretchMode := AValue;
|
|
DiscardBitmap;
|
|
end;
|
|
|
|
procedure TBCSVGViewer.SetUseSVGAlignment(AValue: boolean);
|
|
begin
|
|
if FUseSVGAlignment=AValue then Exit;
|
|
FUseSVGAlignment:=AValue;
|
|
DiscardBitmap;
|
|
end;
|
|
|
|
procedure TBCSVGViewer.SetVertAlign(AValue: TTextLayout);
|
|
begin
|
|
if FVertAlign = AValue then
|
|
Exit;
|
|
FVertAlign := AValue;
|
|
DiscardBitmap;
|
|
end;
|
|
|
|
procedure TBCSVGViewer.RedrawBitmapContent;
|
|
var
|
|
r: TRectF;
|
|
checkersSize: integer;
|
|
begin
|
|
if (FBGRA <> nil) and (FBGRA.NbPixels <> 0) then
|
|
begin
|
|
r := GetSVGRectF;
|
|
FBGRA.Fill(ColorToBGRA(ColorToRGB(Color), ColorOpacity));
|
|
if FDrawCheckers then
|
|
begin
|
|
checkersSize := round(8 * DestDPI / 96 * BitmapScale);
|
|
with GetSVGContainerRectF do
|
|
FBGRA.DrawCheckers(rect(floor(Left), floor(Top),
|
|
ceil(right), ceil(Bottom)), CSSWhite, CSSSilver,
|
|
checkersSize, checkersSize);
|
|
end;
|
|
FBGRA.Canvas2D.FontRenderer := TBGRAVectorizedFontRenderer.Create;
|
|
FSVG.StretchDraw(FBGRA.Canvas2D, r, UseSVGAlignment);
|
|
if Assigned(OnRedraw) then
|
|
OnRedraw(self, FBGRA);
|
|
end;
|
|
end;
|
|
|
|
constructor TBCSVGViewer.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FSVG := TBGRASVG.Create(100, 100, TCSSUnit.cuPercent);
|
|
FDestDPI := 96;
|
|
Fx := 0;
|
|
Fy := 0;
|
|
FStretchMode := smStretch;
|
|
FHorizAlign := taCenter;
|
|
FVertAlign := tlCenter;
|
|
FProportional := True;
|
|
FBitmapAutoScale := False;
|
|
FUseSVGAlignment:= false;
|
|
end;
|
|
|
|
destructor TBCSVGViewer.Destroy;
|
|
begin
|
|
FSVG.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TBCSVGViewer.LoadFromFile(AFileName: string);
|
|
begin
|
|
FSVG.LoadFromFile(AFileName);
|
|
DiscardBitmap;
|
|
end;
|
|
|
|
procedure TBCSVGViewer.LoadFromResource(Resource: string);
|
|
begin
|
|
FSVG.LoadFromResource(Resource);
|
|
DiscardBitmap;
|
|
end;
|
|
|
|
function TBCSVGViewer.GetSVGRectF: TRectF;
|
|
var
|
|
vbSize: TPointF;
|
|
w, h, dpi: single;
|
|
containerRect: TRectF;
|
|
|
|
function NoStretch(AX, AY: single): TRectF;
|
|
begin
|
|
case HorizAlign of
|
|
taCenter: Result.Left := (w - vbSize.x) / 2;
|
|
taRightJustify: Result.Left := w - AX - vbSize.x;
|
|
else
|
|
{taLeftJustify} Result.Left := AX;
|
|
end;
|
|
case VertAlign of
|
|
tlCenter: Result.Top := (h - vbSize.y) / 2;
|
|
tlBottom: Result.Top := h - AY - vbSize.y;
|
|
else
|
|
{tlTop} Result.Top := AY;
|
|
end;
|
|
Result.Right := Result.Left + vbSize.x;
|
|
Result.Bottom := Result.Top + vbSize.y;
|
|
end;
|
|
|
|
begin
|
|
if FSVG = nil then exit(EmptyRectF);
|
|
|
|
containerRect := GetSVGContainerRectF;
|
|
w := containerRect.Width;
|
|
h := containerRect.Height;
|
|
dpi := DestDPI * BitmapScale;
|
|
|
|
FSVG.Units.ContainerWidth := FloatWithCSSUnit(w * FSVG.Units.DpiX / dpi, cuPixel);
|
|
FSVG.Units.ContainerHeight := FloatWithCSSUnit(h * FSVG.Units.DpiY / dpi, cuPixel);
|
|
|
|
if UseSVGAlignment then
|
|
exit(FSVG.GetStretchRectF(containerRect.Left, containerRect.Top, containerRect.Width, containerRect.Height));
|
|
|
|
vbSize := FSVG.ViewSizeInUnit[cuPixel];
|
|
vbSize.x := vbSize.x * (dpi / FSVG.Units.DpiX);
|
|
vbSize.y := vbSize.y * (dpi / FSVG.Units.DpiY);
|
|
if ((StretchMode = smShrink) and ((vbSize.x > w + 0.1) or (vbSize.y > h + 0.1))) or
|
|
(StretchMode in[smStretch, smCover]) then
|
|
begin
|
|
if Proportional then
|
|
Result := FSVG.GetStretchRectF(HorizAlign, VertAlign, 0, 0, w, h, StretchMode = smCover)
|
|
else
|
|
if StretchMode = smShrink then
|
|
begin
|
|
NoStretch(0, 0);
|
|
if vbSize.x > w then
|
|
begin
|
|
Result.Left := 0;
|
|
Result.Right := w;
|
|
end;
|
|
if vbSize.y > h then
|
|
begin
|
|
Result.Top := 0;
|
|
Result.Bottom := h;
|
|
end;
|
|
end
|
|
else
|
|
Result := RectF(0, 0, w, h);
|
|
end
|
|
else
|
|
result := NoStretch(x, y);
|
|
|
|
result.Offset(containerRect.Left, containerRect.Top);
|
|
end;
|
|
|
|
function TBCSVGViewer.GetSVGContainerRectF: TRectF;
|
|
var
|
|
w, h: Integer;
|
|
dpi, ratioX, ratioY, ratio: single;
|
|
begin
|
|
w := BitmapWidth;
|
|
h := BitmapHeight;
|
|
dpi := DestDPI * BitmapScale;
|
|
Result := RectF(0, 0, w, h);
|
|
|
|
if (FSVG = nil) or not UseSVGAlignment then exit;
|
|
|
|
FSVG.Units.ContainerWidth := FloatWithCSSUnit(w * FSVG.Units.DpiX / dpi, cuPixel);
|
|
FSVG.Units.ContainerHeight := FloatWithCSSUnit(h * FSVG.Units.DpiY / dpi, cuPixel);
|
|
|
|
if (FSVG = nil) or (FSVG.WidthAsPixel = 0) or
|
|
(FSVG.HeightAsPixel = 0) or (BitmapWidth = 0)
|
|
or (BitmapHeight = 0) then exit(EmptyRectF);
|
|
|
|
ratioX := BitmapWidth / FSVG.WidthAsPixel;
|
|
ratioY := BitmapHeight / FSVG.HeightAsPixel;
|
|
case StretchMode of
|
|
smStretch: ratio := min(ratioX, ratioY);
|
|
smShrink: ratio := min(1, min(ratioX, ratioY));
|
|
smCover: ratio := max(ratioX, ratioY);
|
|
else
|
|
ratio := 1;
|
|
end;
|
|
result := RectWithSizeF(0, 0, FSVG.WidthAsPixel * ratio,
|
|
FSVG.HeightAsPixel * ratio);
|
|
result.Offset((BitmapWidth - result.Width) / 2,
|
|
(BitmapHeight - result.Height) / 2);
|
|
end;
|
|
|
|
end.
|