From e9f8ac9e42a3c361f37416267febf88aae0fe2b9 Mon Sep 17 00:00:00 2001 From: wqmeng Date: Sun, 24 Aug 2025 02:17:56 +0800 Subject: [PATCH] Try to use the Paths bounds to set the Viewbox rectangle, so let all the paths show in the SVG window which may help to resolve some ViewBox problem. Get the KeepAspectRatio to be configurable, and default is true. --- source/Img32.SVG.Reader.pas | 59 +++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/source/Img32.SVG.Reader.pas b/source/Img32.SVG.Reader.pas index 4907b403..52cbb027 100644 --- a/source/Img32.SVG.Reader.pas +++ b/source/Img32.SVG.Reader.pas @@ -165,6 +165,9 @@ TSvgReader = class fRootElement : TSvgElement; fFontCache : TFontCache; fKeepAspectRatio : Boolean; + fFlipHorizontal : Boolean; + fFlipVertical : Boolean; + function LoadInternal: Boolean; function GetIsEmpty: Boolean; function GetTempImage: TImage32; @@ -188,6 +191,9 @@ TSvgReader = class function LoadFromString(const str: string): Boolean; function GetImageSize: TSize; + function GetPathBounds: TRectD; + function DrawFullPathsInCenter: Boolean; + // The following two methods are deprecated and intended only for ... // https://github.com/EtheaDev/SVGIconImageList procedure SetOverrideFillColor(color: TColor32); //deprecated; @@ -199,9 +205,10 @@ TSvgReader = class property IsEmpty : Boolean read GetIsEmpty; // KeepAspectRatio: this property has also been added for the convenience of // the third-party SVGIconImageList. (IMHO it should always = true) - property KeepAspectRatio: Boolean - read fKeepAspectRatio write fKeepAspectRatio; + property KeepAspectRatio : Boolean read fKeepAspectRatio write fKeepAspectRatio; property RootElement : TSvgElement read fRootElement; + property FlipHorizontal : Boolean read fFlipHorizontal write fFlipHorizontal; + property FlipVertical : Boolean read fFlipVertical write fFlipVertical; end; var @@ -5645,6 +5652,23 @@ procedure TSvgReader.ResetPaths; end; //------------------------------------------------------------------------------ +function TSvgReader.DrawFullPathsInCenter: Boolean; +var + LRectD: TRectD; +begin + Result := false; + LRectD:= GetPathBounds; + if LRectD.IsEmpty then + Exit; + + Self.RootElement.viewboxWH.Left := LRectD.Left; + Self.RootElement.viewboxWH.Top := LRectD.Top; + Self.RootElement.viewboxWH.Width := LRectD.Width; + Self.RootElement.viewboxWH.Height := LRectD.Height; + Result := true; +end; +//------------------------------------------------------------------------------ + procedure TSvgReader.DrawImage(img: TImage32; scaleToImage: Boolean); var scale, scaleH: double; @@ -5669,6 +5693,25 @@ procedure TSvgReader.DrawImage(img: TImage32; scaleToImage: Boolean); MatrixTranslate(di.matrix, -viewboxWH.Left, -viewboxWH.Top); + // flips done in *viewbox space* (unit = SVG units), not with -scale + if fFlipHorizontal and fFlipVertical then + begin + MatrixScale(di.matrix, -1, -1); + MatrixTranslate(di.matrix, viewboxWH.Width, viewboxWH.Height); + end else + if fFlipHorizontal then + begin + // mirror around vertical axis of viewbox + MatrixScale(di.matrix, -1, 1); + MatrixTranslate(di.matrix, viewboxWH.Width, 0); + end else + if fFlipVertical then + begin + // mirror around horizontal axis of viewbox + MatrixScale(di.matrix, 1, -1); + MatrixTranslate(di.matrix, 0, viewboxWH.Height); + end; + //the width and height attributes generally indicate the size of the //rendered image unless they are percentage values. Nevertheless, these //values can be still overridden by the scaleToImage parameter above @@ -5698,7 +5741,6 @@ procedure TSvgReader.DrawImage(img: TImage32; scaleToImage: Boolean); Round(viewboxWH.Height * scaleH)); end else img.SetSize(Round(viewboxWH.Width), Round(viewboxWH.Height)); - end; if fBkgndColor <> clNone32 then @@ -5844,6 +5886,17 @@ function TSvgReader.GetIsEmpty: Boolean; begin Result := not Assigned(fRootElement); end; +//------------------------------------------------------------------------------ + +function TSvgReader.GetPathBounds: TRectD; +begin + if not Assigned(Self.fRootElement) then begin + Result := NullRectD; + Exit; + end; + Result := Self.fRootElement.GetBounds; +end; + //------------------------------------------------------------------------------ //------------------------------------------------------------------------------