Committed by
David PHAM-VAN
Add support for custom fonts in SVGs.
This adds the interface `SvgCustomFonts` and a corresponding parameter to the SvgImage widget. This provides a mechanism to support SVGs that have known fonts referenced in them. Closes #1731.
Showing
7 changed files
with
53 additions
and
3 deletions
@@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
16 | 16 | ||
17 | import '../../pdf.dart'; | 17 | import '../../pdf.dart'; |
18 | import '../widgets/font.dart'; | 18 | import '../widgets/font.dart'; |
19 | +import '../widgets/svg.dart'; | ||
19 | import 'brush.dart'; | 20 | import 'brush.dart'; |
20 | import 'color.dart'; | 21 | import 'color.dart'; |
21 | import 'group.dart'; | 22 | import 'group.dart'; |
@@ -26,8 +27,9 @@ class SvgPainter { | @@ -26,8 +27,9 @@ class SvgPainter { | ||
26 | this.parser, | 27 | this.parser, |
27 | this._canvas, | 28 | this._canvas, |
28 | this.document, | 29 | this.document, |
29 | - this.boundingBox, | ||
30 | - ); | 30 | + this.boundingBox, { |
31 | + this.customFontLookup, | ||
32 | + }); | ||
31 | 33 | ||
32 | final SvgParser parser; | 34 | final SvgParser parser; |
33 | 35 | ||
@@ -37,6 +39,8 @@ class SvgPainter { | @@ -37,6 +39,8 @@ class SvgPainter { | ||
37 | 39 | ||
38 | final PdfRect boundingBox; | 40 | final PdfRect boundingBox; |
39 | 41 | ||
42 | + final SvgCustomFontLookup? customFontLookup; | ||
43 | + | ||
40 | void paint() { | 44 | void paint() { |
41 | final brush = parser.colorFilter == null | 45 | final brush = parser.colorFilter == null |
42 | ? SvgBrush.defaultContext | 46 | ? SvgBrush.defaultContext |
@@ -59,6 +63,12 @@ class SvgPainter { | @@ -59,6 +63,12 @@ class SvgPainter { | ||
59 | } | 63 | } |
60 | 64 | ||
61 | Font getFont(String fontFamily, String fontStyle, String fontWeight) { | 65 | Font getFont(String fontFamily, String fontStyle, String fontWeight) { |
66 | + final customFont = | ||
67 | + customFontLookup?.call(fontFamily, fontStyle, fontWeight); | ||
68 | + if (customFont != null) { | ||
69 | + return customFont; | ||
70 | + } | ||
71 | + | ||
62 | switch (fontFamily) { | 72 | switch (fontFamily) { |
63 | case 'serif': | 73 | case 'serif': |
64 | switch (fontStyle) { | 74 | switch (fontStyle) { |
@@ -32,6 +32,7 @@ class SvgImage extends Widget { | @@ -32,6 +32,7 @@ class SvgImage extends Widget { | ||
32 | double? width, | 32 | double? width, |
33 | double? height, | 33 | double? height, |
34 | PdfColor? colorFilter, | 34 | PdfColor? colorFilter, |
35 | + SvgCustomFontLookup? customFontLookup, | ||
35 | }) { | 36 | }) { |
36 | final xml = XmlDocument.parse(svg); | 37 | final xml = XmlDocument.parse(svg); |
37 | final parser = SvgParser( | 38 | final parser = SvgParser( |
@@ -46,6 +47,7 @@ class SvgImage extends Widget { | @@ -46,6 +47,7 @@ class SvgImage extends Widget { | ||
46 | clip, | 47 | clip, |
47 | width, | 48 | width, |
48 | height, | 49 | height, |
50 | + customFontLookup, | ||
49 | ); | 51 | ); |
50 | } | 52 | } |
51 | 53 | ||
@@ -56,6 +58,7 @@ class SvgImage extends Widget { | @@ -56,6 +58,7 @@ class SvgImage extends Widget { | ||
56 | this.clip, | 58 | this.clip, |
57 | this.width, | 59 | this.width, |
58 | this.height, | 60 | this.height, |
61 | + this.customFontLookup, | ||
59 | ); | 62 | ); |
60 | 63 | ||
61 | final SvgParser _svgParser; | 64 | final SvgParser _svgParser; |
@@ -70,6 +73,8 @@ class SvgImage extends Widget { | @@ -70,6 +73,8 @@ class SvgImage extends Widget { | ||
70 | 73 | ||
71 | final double? height; | 74 | final double? height; |
72 | 75 | ||
76 | + final SvgCustomFontLookup? customFontLookup; | ||
77 | + | ||
73 | late FittedSizes sizes; | 78 | late FittedSizes sizes; |
74 | 79 | ||
75 | @override | 80 | @override |
@@ -126,6 +131,7 @@ class SvgImage extends Widget { | @@ -126,6 +131,7 @@ class SvgImage extends Widget { | ||
126 | context.page.pageFormat.width, | 131 | context.page.pageFormat.width, |
127 | context.page.pageFormat.height, | 132 | context.page.pageFormat.height, |
128 | ), | 133 | ), |
134 | + customFontLookup: customFontLookup, | ||
129 | ); | 135 | ); |
130 | painter.paint(); | 136 | painter.paint(); |
131 | context.canvas.restoreContext(); | 137 | context.canvas.restoreContext(); |
@@ -154,3 +160,6 @@ class DecorationSvgImage extends DecorationGraphic { | @@ -154,3 +160,6 @@ class DecorationSvgImage extends DecorationGraphic { | ||
154 | ); | 160 | ); |
155 | } | 161 | } |
156 | } | 162 | } |
163 | + | ||
164 | +typedef SvgCustomFontLookup = Font? Function( | ||
165 | + String fontFamily, String fontStyle, String fontWeight); |
@@ -20,6 +20,8 @@ import 'package:pdf/pdf.dart'; | @@ -20,6 +20,8 @@ import 'package:pdf/pdf.dart'; | ||
20 | import 'package:pdf/widgets.dart'; | 20 | import 'package:pdf/widgets.dart'; |
21 | import 'package:test/test.dart'; | 21 | import 'package:test/test.dart'; |
22 | 22 | ||
23 | +import 'utils.dart'; | ||
24 | + | ||
23 | late Document pdf; | 25 | late Document pdf; |
24 | 26 | ||
25 | void main() { | 27 | void main() { |
@@ -195,6 +197,31 @@ void main() { | @@ -195,6 +197,31 @@ void main() { | ||
195 | ); | 197 | ); |
196 | }); | 198 | }); |
197 | 199 | ||
200 | + test('SVG Widgets Text custom fonts', () { | ||
201 | + const customFamilyName1 = 'Test-Font-Family1'; | ||
202 | + const customFamilyName2 = 'Test-Font-Family2'; | ||
203 | + final customFont1 = loadFont('open-sans-bold.ttf'); | ||
204 | + final customFont2 = loadFont('genyomintw.ttf'); | ||
205 | + pdf.addPage( | ||
206 | + Page( | ||
207 | + build: (context) => SvgImage( | ||
208 | + svg: | ||
209 | + '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg viewBox="0 0 1000 300" xmlns="http://www.w3.org/2000/svg" version="1.1"><text x="367.055" y="168.954" font-size="55" fill="darkgreen" font-family="$customFamilyName1" >Custom <tspan font-family="$customFamilyName2">fonts</tspan></text><rect x="1" y="1" width="998" height="298" fill="none" stroke="purple" stroke-width="2" /></svg>', | ||
210 | + customFontLookup: | ||
211 | + (String fontFamily, String fontStyle, String fontWeight) { | ||
212 | + switch (fontFamily) { | ||
213 | + case customFamilyName1: | ||
214 | + return customFont1; | ||
215 | + case customFamilyName2: | ||
216 | + return customFont2; | ||
217 | + default: | ||
218 | + return null; | ||
219 | + } | ||
220 | + }), | ||
221 | + ), | ||
222 | + ); | ||
223 | + }); | ||
224 | + | ||
198 | tearDownAll(() async { | 225 | tearDownAll(() async { |
199 | final file = File('widgets-svg.pdf'); | 226 | final file = File('widgets-svg.pdf'); |
200 | await file.writeAsBytes(await pdf.save()); | 227 | await file.writeAsBytes(await pdf.save()); |
No preview for this file type
No preview for this file type
-
Please register or login to post a comment