bcsvgviewer.pas 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. // SPDX-License-Identifier: LGPL-3.0-linking-exception
  2. {******************************* CONTRIBUTOR(S) ******************************
  3. - Edivando S. Santos Brasil | [email protected]
  4. (Compatibility with delphi VCL 11/2018)
  5. ***************************** END CONTRIBUTOR(S) *****************************}
  6. unit BCSVGViewer;
  7. {$I bgracontrols.inc}
  8. interface
  9. uses
  10. Classes, SysUtils, Forms, Controls, Graphics, Dialogs, BGRAGraphicControl,
  11. {$IFDEF FPC}LResources, LCLType, {$ENDIF}
  12. {$IFNDEF FPC}Types, BGRAGraphics, GraphType, FPImage, {$ENDIF}
  13. BGRABitmap, BGRABitmapTypes, BGRASVG, BGRAUnits, BCTypes;
  14. type
  15. { TBCSVGViewer }
  16. TBCSVGViewer = class(TCustomBGRAGraphicControl)
  17. private
  18. FDrawCheckers: boolean;
  19. FHorizAlign: TAlignment;
  20. FProportional: boolean;
  21. FStretchMode: TBCStretchMode;
  22. FDestDPI: single;
  23. FUseSVGAlignment: boolean;
  24. FVertAlign: TTextLayout;
  25. Fx: single;
  26. Fy: single;
  27. function GetSVGString: string;
  28. procedure SetDrawCheckers(AValue: boolean);
  29. procedure SetFDestDPI(AValue: single);
  30. procedure SetSVGString(AValue: string);
  31. procedure SetFx(AValue: single);
  32. procedure SetFy(AValue: single);
  33. procedure SetHorizAlign(AValue: TAlignment);
  34. procedure SetProportional(AValue: boolean);
  35. procedure SetStretchMode(AValue: TBCStretchMode);
  36. procedure SetUseSVGAlignment(AValue: boolean);
  37. procedure SetVertAlign(AValue: TTextLayout);
  38. protected
  39. FSVG: TBGRASVG;
  40. procedure RedrawBitmapContent; override;
  41. public
  42. constructor Create(AOwner: TComponent); override;
  43. destructor Destroy; override;
  44. procedure LoadFromFile(AFileName: string);
  45. procedure LoadFromResource(Resource: string);
  46. function GetSVGRectF: TRectF;
  47. function GetSVGContainerRectF: TRectF;
  48. published
  49. { Published declarations }
  50. property Align;
  51. property Anchors;
  52. property OnRedraw;
  53. property Bitmap;
  54. property BorderSpacing;
  55. property Constraints;
  56. property SVG: TBGRASVG read FSVG;
  57. property SVGString: string read GetSVGString write SetSVGString;
  58. property DestDPI: single read FDestDPI write SetFDestDPI {$IFDEF FPC} default
  59. 96{$ENDIF};
  60. property x: single read Fx write SetFx {$IFDEF FPC} default 0{$ENDIF};
  61. property y: single read Fy write SetFy {$IFDEF FPC} default 0{$ENDIF};
  62. property HorizAlign: TAlignment read FHorizAlign write SetHorizAlign default
  63. taCenter;
  64. property VertAlign: TTextLayout read FVertAlign write SetVertAlign default tlCenter;
  65. property StretchMode: TBCStretchMode
  66. read FStretchMode write SetStretchMode default smStretch;
  67. property Proportional: boolean read FProportional write SetProportional default True;
  68. property DrawCheckers: boolean
  69. read FDrawCheckers write SetDrawCheckers default False;
  70. property UseSVGAlignment: boolean read FUseSVGAlignment write SetUseSVGAlignment default False;
  71. property Color;
  72. property ColorOpacity;
  73. property OnClick;
  74. property OnDblClick;
  75. property OnMouseDown;
  76. property OnMouseEnter;
  77. property OnMouseLeave;
  78. property OnMouseMove;
  79. property OnMouseUp;
  80. {$IFDEF FPC}
  81. property OnPaint;
  82. {$ENDIF}
  83. property OnResize;
  84. property Caption;
  85. end;
  86. {$IFDEF FPC}procedure Register;{$ENDIF}
  87. implementation
  88. uses BGRAVectorize, math;
  89. {$IFDEF FPC}
  90. procedure Register;
  91. begin
  92. RegisterComponents('BGRA Controls', [TBCSVGViewer]);
  93. end;
  94. {$ENDIF}
  95. { TBCSVGViewer }
  96. procedure TBCSVGViewer.SetFDestDPI(AValue: single);
  97. begin
  98. if FDestDPI = AValue then
  99. Exit;
  100. FDestDPI := AValue;
  101. DiscardBitmap;
  102. end;
  103. procedure TBCSVGViewer.SetSVGString(AValue: string);
  104. begin
  105. FSVG.ASUTF8String := AValue;
  106. DiscardBitmap;
  107. end;
  108. procedure TBCSVGViewer.SetDrawCheckers(AValue: boolean);
  109. begin
  110. if FDrawCheckers = AValue then
  111. Exit;
  112. FDrawCheckers := AValue;
  113. DiscardBitmap;
  114. end;
  115. function TBCSVGViewer.GetSVGString: string;
  116. begin
  117. Result := FSVG.AsUTF8String;
  118. end;
  119. procedure TBCSVGViewer.SetFx(AValue: single);
  120. begin
  121. if Fx = AValue then
  122. Exit;
  123. Fx := AValue;
  124. DiscardBitmap;
  125. end;
  126. procedure TBCSVGViewer.SetFy(AValue: single);
  127. begin
  128. if Fy = AValue then
  129. Exit;
  130. Fy := AValue;
  131. DiscardBitmap;
  132. end;
  133. procedure TBCSVGViewer.SetHorizAlign(AValue: TAlignment);
  134. begin
  135. if FHorizAlign = AValue then
  136. Exit;
  137. FHorizAlign := AValue;
  138. DiscardBitmap;
  139. end;
  140. procedure TBCSVGViewer.SetProportional(AValue: boolean);
  141. begin
  142. if FProportional = AValue then
  143. Exit;
  144. FProportional := AValue;
  145. DiscardBitmap;
  146. end;
  147. procedure TBCSVGViewer.SetStretchMode(AValue: TBCStretchMode);
  148. begin
  149. if FStretchMode = AValue then
  150. Exit;
  151. FStretchMode := AValue;
  152. DiscardBitmap;
  153. end;
  154. procedure TBCSVGViewer.SetUseSVGAlignment(AValue: boolean);
  155. begin
  156. if FUseSVGAlignment=AValue then Exit;
  157. FUseSVGAlignment:=AValue;
  158. DiscardBitmap;
  159. end;
  160. procedure TBCSVGViewer.SetVertAlign(AValue: TTextLayout);
  161. begin
  162. if FVertAlign = AValue then
  163. Exit;
  164. FVertAlign := AValue;
  165. DiscardBitmap;
  166. end;
  167. procedure TBCSVGViewer.RedrawBitmapContent;
  168. var
  169. r: TRectF;
  170. checkersSize: integer;
  171. begin
  172. if (FBGRA <> nil) and (FBGRA.NbPixels <> 0) then
  173. begin
  174. r := GetSVGRectF;
  175. FBGRA.Fill(ColorToBGRA(ColorToRGB(Color), ColorOpacity));
  176. if FDrawCheckers then
  177. begin
  178. checkersSize := round(8 * DestDPI / 96 * BitmapScale);
  179. with GetSVGContainerRectF do
  180. FBGRA.DrawCheckers(rect(floor(Left), floor(Top),
  181. ceil(right), ceil(Bottom)), CSSWhite, CSSSilver,
  182. checkersSize, checkersSize);
  183. end;
  184. FBGRA.Canvas2D.FontRenderer := TBGRAVectorizedFontRenderer.Create;
  185. FSVG.StretchDraw(FBGRA.Canvas2D, r, UseSVGAlignment);
  186. if Assigned(OnRedraw) then
  187. OnRedraw(self, FBGRA);
  188. end;
  189. end;
  190. constructor TBCSVGViewer.Create(AOwner: TComponent);
  191. begin
  192. inherited Create(AOwner);
  193. FSVG := TBGRASVG.Create(100, 100, TCSSUnit.cuPercent);
  194. FDestDPI := 96;
  195. Fx := 0;
  196. Fy := 0;
  197. FStretchMode := smStretch;
  198. FHorizAlign := taCenter;
  199. FVertAlign := tlCenter;
  200. FProportional := True;
  201. FBitmapAutoScale := False;
  202. FUseSVGAlignment:= false;
  203. end;
  204. destructor TBCSVGViewer.Destroy;
  205. begin
  206. FSVG.Free;
  207. inherited Destroy;
  208. end;
  209. procedure TBCSVGViewer.LoadFromFile(AFileName: string);
  210. begin
  211. FSVG.LoadFromFile(AFileName);
  212. DiscardBitmap;
  213. end;
  214. procedure TBCSVGViewer.LoadFromResource(Resource: string);
  215. begin
  216. FSVG.LoadFromResource(Resource);
  217. DiscardBitmap;
  218. end;
  219. function TBCSVGViewer.GetSVGRectF: TRectF;
  220. var
  221. vbSize: TPointF;
  222. w, h, dpi: single;
  223. containerRect: TRectF;
  224. function NoStretch(AX, AY: single): TRectF;
  225. begin
  226. case HorizAlign of
  227. taCenter: Result.Left := (w - vbSize.x) / 2;
  228. taRightJustify: Result.Left := w - AX - vbSize.x;
  229. else
  230. {taLeftJustify} Result.Left := AX;
  231. end;
  232. case VertAlign of
  233. tlCenter: Result.Top := (h - vbSize.y) / 2;
  234. tlBottom: Result.Top := h - AY - vbSize.y;
  235. else
  236. {tlTop} Result.Top := AY;
  237. end;
  238. Result.Right := Result.Left + vbSize.x;
  239. Result.Bottom := Result.Top + vbSize.y;
  240. end;
  241. begin
  242. if FSVG = nil then exit(EmptyRectF);
  243. containerRect := GetSVGContainerRectF;
  244. w := containerRect.Width;
  245. h := containerRect.Height;
  246. dpi := DestDPI * BitmapScale;
  247. FSVG.Units.ContainerWidth := FloatWithCSSUnit(w * FSVG.Units.DpiX / dpi, cuPixel);
  248. FSVG.Units.ContainerHeight := FloatWithCSSUnit(h * FSVG.Units.DpiY / dpi, cuPixel);
  249. if UseSVGAlignment then
  250. exit(FSVG.GetStretchRectF(containerRect.Left, containerRect.Top, containerRect.Width, containerRect.Height));
  251. vbSize := FSVG.ViewSizeInUnit[cuPixel];
  252. vbSize.x := vbSize.x * (dpi / FSVG.Units.DpiX);
  253. vbSize.y := vbSize.y * (dpi / FSVG.Units.DpiY);
  254. if ((StretchMode = smShrink) and ((vbSize.x > w + 0.1) or (vbSize.y > h + 0.1))) or
  255. (StretchMode in[smStretch, smCover]) then
  256. begin
  257. if Proportional then
  258. Result := FSVG.GetStretchRectF(HorizAlign, VertAlign, 0, 0, w, h, StretchMode = smCover)
  259. else
  260. if StretchMode = smShrink then
  261. begin
  262. NoStretch(0, 0);
  263. if vbSize.x > w then
  264. begin
  265. Result.Left := 0;
  266. Result.Right := w;
  267. end;
  268. if vbSize.y > h then
  269. begin
  270. Result.Top := 0;
  271. Result.Bottom := h;
  272. end;
  273. end
  274. else
  275. Result := RectF(0, 0, w, h);
  276. end
  277. else
  278. result := NoStretch(x, y);
  279. result.Offset(containerRect.Left, containerRect.Top);
  280. end;
  281. function TBCSVGViewer.GetSVGContainerRectF: TRectF;
  282. var
  283. w, h: Integer;
  284. dpi, ratioX, ratioY, ratio: single;
  285. begin
  286. w := BitmapWidth;
  287. h := BitmapHeight;
  288. dpi := DestDPI * BitmapScale;
  289. Result := RectF(0, 0, w, h);
  290. if (FSVG = nil) or not UseSVGAlignment then exit;
  291. FSVG.Units.ContainerWidth := FloatWithCSSUnit(w * FSVG.Units.DpiX / dpi, cuPixel);
  292. FSVG.Units.ContainerHeight := FloatWithCSSUnit(h * FSVG.Units.DpiY / dpi, cuPixel);
  293. if (FSVG = nil) or (FSVG.WidthAsPixel = 0) or
  294. (FSVG.HeightAsPixel = 0) or (BitmapWidth = 0)
  295. or (BitmapHeight = 0) then exit(EmptyRectF);
  296. ratioX := BitmapWidth / FSVG.WidthAsPixel;
  297. ratioY := BitmapHeight / FSVG.HeightAsPixel;
  298. case StretchMode of
  299. smStretch: ratio := min(ratioX, ratioY);
  300. smShrink: ratio := min(1, min(ratioX, ratioY));
  301. smCover: ratio := max(ratioX, ratioY);
  302. else
  303. ratio := 1;
  304. end;
  305. result := RectWithSizeF(0, 0, FSVG.WidthAsPixel * ratio,
  306. FSVG.HeightAsPixel * ratio);
  307. result.Offset((BitmapWidth - result.Width) / 2,
  308. (BitmapHeight - result.Height) / 2);
  309. end;
  310. end.