David PHAM-VAN

Fix SVG fit alignment

1 # Changelog 1 # Changelog
2 2
  3 +## 2.1.0
  4 +
  5 +- Fix SVG fit alignment
  6 +
3 ## 2.0.0 7 ## 2.0.0
4 8
5 - A borderRadius can only be given for a uniform Border 9 - A borderRadius can only be given for a uniform Border
@@ -27,43 +27,52 @@ class SvgImage extends Widget { @@ -27,43 +27,52 @@ class SvgImage extends Widget {
27 factory SvgImage({ 27 factory SvgImage({
28 @required String svg, 28 @required String svg,
29 BoxFit fit = BoxFit.contain, 29 BoxFit fit = BoxFit.contain,
  30 + Alignment alignment = Alignment.center,
30 bool clip = true, 31 bool clip = true,
31 double width, 32 double width,
32 double height, 33 double height,
33 }) { 34 }) {
34 assert(clip != null); 35 assert(clip != null);
  36 + assert(alignment != null);
35 37
36 final xml = XmlDocument.parse(svg); 38 final xml = XmlDocument.parse(svg);
37 final parser = SvgParser(xml: xml); 39 final parser = SvgParser(xml: xml);
38 40
39 - return SvgImage._fromPainter( 41 + return SvgImage._fromParser(
40 parser, 42 parser,
41 fit, 43 fit,
  44 + alignment,
42 clip, 45 clip,
43 width, 46 width,
44 height, 47 height,
45 ); 48 );
46 } 49 }
47 50
48 - SvgImage._fromPainter( 51 + SvgImage._fromParser(
49 this._svgParser, 52 this._svgParser,
50 this.fit, 53 this.fit,
  54 + this.alignment,
51 this.clip, 55 this.clip,
52 this.width, 56 this.width,
53 this.height, 57 this.height,
54 ) : assert(_svgParser != null), 58 ) : assert(_svgParser != null),
55 - assert(fit != null); 59 + assert(fit != null),
  60 + assert(alignment != null);
56 61
57 final SvgParser _svgParser; 62 final SvgParser _svgParser;
58 63
59 final BoxFit fit; 64 final BoxFit fit;
60 65
  66 + final Alignment alignment;
  67 +
61 final bool clip; 68 final bool clip;
62 69
63 final double width; 70 final double width;
64 71
65 final double height; 72 final double height;
66 73
  74 + FittedSizes sizes;
  75 +
67 @override 76 @override
68 void layout(Context context, BoxConstraints constraints, 77 void layout(Context context, BoxConstraints constraints,
69 {bool parentUsesSize = false}) { 78 {bool parentUsesSize = false}) {
@@ -78,10 +87,7 @@ class SvgImage extends Widget { @@ -78,10 +87,7 @@ class SvgImage extends Widget {
78 ? constraints.maxHeight 87 ? constraints.maxHeight
79 : constraints.constrainHeight(_svgParser.viewBox.height); 88 : constraints.constrainHeight(_svgParser.viewBox.height);
80 89
81 - final sizes = applyBoxFit(  
82 - fit,  
83 - PdfPoint(_svgParser.viewBox.width, _svgParser.viewBox.height),  
84 - PdfPoint(w, h)); 90 + sizes = applyBoxFit(fit, _svgParser.viewBox.size, PdfPoint(w, h));
85 box = PdfRect.fromPoints(PdfPoint.zero, sizes.destination); 91 box = PdfRect.fromPoints(PdfPoint.zero, sizes.destination);
86 } 92 }
87 93
@@ -89,19 +95,20 @@ class SvgImage extends Widget { @@ -89,19 +95,20 @@ class SvgImage extends Widget {
89 void paint(Context context) { 95 void paint(Context context) {
90 super.paint(context); 96 super.paint(context);
91 97
92 - final mat = Matrix4.identity();  
93 - mat.translate(  
94 - box.x,  
95 - box.y + box.height,  
96 - );  
97 - mat.scale(  
98 - box.width / _svgParser.viewBox.width,  
99 - -box.height / _svgParser.viewBox.height,  
100 - );  
101 - mat.translate(  
102 - -_svgParser.viewBox.x,  
103 - -_svgParser.viewBox.y,  
104 - ); 98 + final _alignment = Alignment(alignment.x, -alignment.y);
  99 + final sourceRect = _alignment.inscribe(sizes.source, _svgParser.viewBox);
  100 + final sx = sizes.destination.x / sizes.source.x;
  101 + final sy = sizes.destination.y / sizes.source.y;
  102 + final dx = sourceRect.x * sx;
  103 + final dy = sourceRect.y * sy;
  104 +
  105 + final mat = Matrix4.identity()
  106 + ..translate(
  107 + box.x - dx,
  108 + box.y + dy + box.height,
  109 + )
  110 + ..scale(sx, -sy);
  111 +
105 context.canvas.saveContext(); 112 context.canvas.saveContext();
106 if (clip) { 113 if (clip) {
107 context.canvas 114 context.canvas
@@ -4,7 +4,7 @@ description: A pdf producer for Dart. It can create pdf files for both web or fl @@ -4,7 +4,7 @@ description: A pdf producer for Dart. It can create pdf files for both web or fl
4 homepage: https://github.com/DavBfr/dart_pdf/tree/master/pdf 4 homepage: https://github.com/DavBfr/dart_pdf/tree/master/pdf
5 repository: https://github.com/DavBfr/dart_pdf 5 repository: https://github.com/DavBfr/dart_pdf
6 issue_tracker: https://github.com/DavBfr/dart_pdf/issues 6 issue_tracker: https://github.com/DavBfr/dart_pdf/issues
7 -version: 2.0.0 7 +version: 2.1.0
8 8
9 environment: 9 environment:
10 sdk: ">=2.3.0 <3.0.0" 10 sdk: ">=2.3.0 <3.0.0"
@@ -110,6 +110,72 @@ void main() { @@ -110,6 +110,72 @@ void main() {
110 ); 110 );
111 }); 111 });
112 112
  113 + test('SVG Widgets BoxFit.cover and alignment', () {
  114 + const svg =
  115 + '<?xml version="1.0" encoding="utf-8"?><svg version="1.1" viewBox="10 20 200 200" xmlns="http://www.w3.org/2000/svg"><circle style="fill-opacity: 0.19; fill: rgb(0, 94, 255);" cx="110" cy="120" r="90"/><rect x="10" y="20" width="200" height="200" stroke="blue" fill="none"/><line style="stroke: black;" x1="110" y1="110" x2="110" y2="130"/><line style="stroke: black" x1="100" y1="120" x2="120" y2="120"/></svg>';
  116 +
  117 + pdf.addPage(
  118 + Page(
  119 + build: (context) => Column(
  120 + children: [
  121 + GridView(
  122 + crossAxisCount: 3,
  123 + mainAxisSpacing: 10,
  124 + crossAxisSpacing: 10,
  125 + childAspectRatio: 0.3,
  126 + children: [
  127 + for (final align in <Alignment>[
  128 + Alignment.topLeft,
  129 + Alignment.topCenter,
  130 + Alignment.topRight,
  131 + Alignment.centerLeft,
  132 + Alignment.center,
  133 + Alignment.centerRight,
  134 + Alignment.bottomLeft,
  135 + Alignment.bottomCenter,
  136 + Alignment.bottomRight,
  137 + ])
  138 + SvgImage(
  139 + svg: svg,
  140 + fit: BoxFit.cover,
  141 + alignment: align,
  142 + ),
  143 + ],
  144 + ),
  145 + SizedBox(height: 10),
  146 + SizedBox(
  147 + width: 180,
  148 + child: GridView(
  149 + crossAxisCount: 3,
  150 + mainAxisSpacing: 10,
  151 + crossAxisSpacing: 10,
  152 + childAspectRatio: 3.3,
  153 + children: [
  154 + for (final align in <Alignment>[
  155 + Alignment.topLeft,
  156 + Alignment.topCenter,
  157 + Alignment.topRight,
  158 + Alignment.centerLeft,
  159 + Alignment.center,
  160 + Alignment.centerRight,
  161 + Alignment.bottomLeft,
  162 + Alignment.bottomCenter,
  163 + Alignment.bottomRight,
  164 + ])
  165 + SvgImage(
  166 + svg: svg,
  167 + fit: BoxFit.cover,
  168 + alignment: align,
  169 + ),
  170 + ],
  171 + ),
  172 + ),
  173 + ],
  174 + ),
  175 + ),
  176 + );
  177 + });
  178 +
113 tearDownAll(() async { 179 tearDownAll(() async {
114 final file = File('widgets-svg.pdf'); 180 final file = File('widgets-svg.pdf');
115 await file.writeAsBytes(await pdf.save()); 181 await file.writeAsBytes(await pdf.save());
@@ -16,9 +16,11 @@ @@ -16,9 +16,11 @@
16 16
17 import 'dart:typed_data'; 17 import 'dart:typed_data';
18 18
  19 +import 'package:flutter/widgets.dart';
19 import 'package:flutter_test/flutter_test.dart'; 20 import 'package:flutter_test/flutter_test.dart';
20 import 'package:mockito/mockito.dart'; 21 import 'package:mockito/mockito.dart';
21 import 'package:pdf/pdf.dart'; 22 import 'package:pdf/pdf.dart';
  23 +
22 import 'package:plugin_platform_interface/plugin_platform_interface.dart'; 24 import 'package:plugin_platform_interface/plugin_platform_interface.dart';
23 import 'package:printing/printing.dart'; 25 import 'package:printing/printing.dart';
24 import 'package:printing/src/interface.dart'; 26 import 'package:printing/src/interface.dart';
@@ -112,6 +114,19 @@ void main() { @@ -112,6 +114,19 @@ void main() {
112 null, 114 null,
113 ); 115 );
114 }); 116 });
  117 +
  118 + test('test image', () async {
  119 + final bytes = Uint8List.fromList([
  120 + 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 1, //
  121 + 0, 0, 0, 1, 0, 1, 3, 0, 0, 0, 102, 188, 58, 37, 0, 0, 0, 3, 80, 76, 84,
  122 + 69, 181, 208, 208, 99, 4, 22, 234, 0, 0, 0, 31, 73, 68, 65, 84, 104,
  123 + 129, 237, 193, 1, 13, 0, 0, 0, 194, 160, 247, 79, 109, 14, 55, 160, 0, 0,
  124 + 0, 0, 0, 0, 0, 0, 190, 13, 33, 0, 0, 1, 154, 96, 225, 213, 0, 0, 0, 0, 73,
  125 + 69, 78, 68, 174, 66, 96, 130
  126 + ]);
  127 + final imageProvider = Image.memory(bytes).image;
  128 + expect(await flutterImageProvider(imageProvider), isNotNull);
  129 + });
115 } 130 }
116 131
117 class MockPrinting extends Mock 132 class MockPrinting extends Mock