David PHAM-VAN

Add Barcode and QRCode Widgets

1 # Changelog 1 # Changelog
2 2
  3 +## 1.3.28
  4 +
  5 +- Add Barcode Widget
  6 +- Add QrCode Widget
  7 +
3 ## 1.3.27 8 ## 1.3.27
4 9
5 - Add Roll Paper support 10 - Add Roll Paper support
@@ -22,9 +22,12 @@ import 'dart:typed_data'; @@ -22,9 +22,12 @@ import 'dart:typed_data';
22 22
23 import 'package:meta/meta.dart'; 23 import 'package:meta/meta.dart';
24 import 'package:pdf/pdf.dart'; 24 import 'package:pdf/pdf.dart';
  25 +import 'package:qr/qr.dart';
  26 +import 'package:barcode/barcode.dart';
25 import 'package:vector_math/vector_math_64.dart'; 27 import 'package:vector_math/vector_math_64.dart';
26 28
27 part 'widgets/annotations.dart'; 29 part 'widgets/annotations.dart';
  30 +part 'widgets/barcode.dart';
28 part 'widgets/basic.dart'; 31 part 'widgets/basic.dart';
29 part 'widgets/clip.dart'; 32 part 'widgets/clip.dart';
30 part 'widgets/container.dart'; 33 part 'widgets/container.dart';
@@ -40,6 +43,7 @@ part 'widgets/page.dart'; @@ -40,6 +43,7 @@ part 'widgets/page.dart';
40 part 'widgets/page_theme.dart'; 43 part 'widgets/page_theme.dart';
41 part 'widgets/placeholders.dart'; 44 part 'widgets/placeholders.dart';
42 part 'widgets/progress.dart'; 45 part 'widgets/progress.dart';
  46 +part 'widgets/qrcode.dart';
43 part 'widgets/stack.dart'; 47 part 'widgets/stack.dart';
44 part 'widgets/table.dart'; 48 part 'widgets/table.dart';
45 part 'widgets/text.dart'; 49 part 'widgets/text.dart';
  1 +/*
  2 + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +// ignore_for_file: omit_local_variable_types
  18 +
  19 +part of widget;
  20 +
  21 +class _BarcodeWidget extends Widget {
  22 + _BarcodeWidget({
  23 + @required this.data,
  24 + this.barcode,
  25 + this.color = PdfColors.black,
  26 + });
  27 +
  28 + /// the barcode data
  29 + final String data;
  30 +
  31 + final Barcode barcode;
  32 +
  33 + final PdfColor color;
  34 +
  35 + @override
  36 + void layout(Context context, BoxConstraints constraints,
  37 + {bool parentUsesSize = false}) {
  38 + box = PdfRect.fromPoints(PdfPoint.zero, constraints.biggest);
  39 + }
  40 +
  41 + @override
  42 + void paint(Context context) {
  43 + super.paint(context);
  44 +
  45 + final BarcodeDraw draw = barcode.draw;
  46 + if (draw is _BarcodeDraw) {
  47 + draw
  48 + ..canvas = context.canvas
  49 + ..left = box.left
  50 + ..top = box.top;
  51 + }
  52 +
  53 + context.canvas.setFillColor(color);
  54 + barcode.make(data, box.width, box.height);
  55 + context.canvas.fillPath();
  56 + }
  57 +}
  58 +
  59 +class _BarcodeDraw extends BarcodeDraw {
  60 + PdfGraphics canvas;
  61 + double left;
  62 + double top;
  63 +
  64 + @override
  65 + void fillRect(
  66 + double left, double top, double width, double height, bool black) {
  67 + if (black) {
  68 + canvas.drawRect(this.left + left, this.top + top - height, width, height);
  69 + }
  70 + }
  71 +}
  72 +
  73 +class BarcodeWidget extends StatelessWidget {
  74 + BarcodeWidget({
  75 + @required this.data,
  76 + this.type = BarcodeType.Code39,
  77 + this.color = PdfColors.black,
  78 + this.backgroundColor,
  79 + this.decoration,
  80 + this.margin,
  81 + this.padding,
  82 + this.width,
  83 + this.height,
  84 + this.drawText = true,
  85 + this.textStyle,
  86 + });
  87 +
  88 + /// the barcode data
  89 + final String data;
  90 +
  91 + final BarcodeType type;
  92 +
  93 + final PdfColor color;
  94 +
  95 + final PdfColor backgroundColor;
  96 +
  97 + final EdgeInsets padding;
  98 +
  99 + final EdgeInsets margin;
  100 +
  101 + final double width;
  102 +
  103 + final double height;
  104 +
  105 + final bool drawText;
  106 +
  107 + final TextStyle textStyle;
  108 +
  109 + final BoxDecoration decoration;
  110 +
  111 + @override
  112 + Widget build(Context context) {
  113 + final TextStyle _textStyle = textStyle ?? TextStyle(font: Font.courier());
  114 +
  115 + Widget barcode = _BarcodeWidget(
  116 + data: data,
  117 + color: color,
  118 + barcode: Barcode.fromType(
  119 + type: type,
  120 + draw: _BarcodeDraw(),
  121 + ),
  122 + );
  123 +
  124 + if (drawText) {
  125 + barcode = Column(
  126 + children: <Widget>[
  127 + Flexible(child: barcode),
  128 + Text(
  129 + data,
  130 + style: _textStyle,
  131 + textAlign: TextAlign.center,
  132 + softWrap: false,
  133 + ),
  134 + ],
  135 + );
  136 + }
  137 +
  138 + if (padding != null) {
  139 + barcode = Padding(padding: padding, child: barcode);
  140 + }
  141 +
  142 + if (decoration != null) {
  143 + barcode = DecoratedBox(
  144 + decoration: decoration,
  145 + child: barcode,
  146 + );
  147 + } else if (backgroundColor != null) {
  148 + barcode = DecoratedBox(
  149 + decoration: BoxDecoration(color: backgroundColor),
  150 + child: barcode,
  151 + );
  152 + }
  153 +
  154 + if (width != null || height != null) {
  155 + barcode = SizedBox(width: width, height: height, child: barcode);
  156 + }
  157 +
  158 + if (margin != null) {
  159 + barcode = Padding(padding: margin, child: barcode);
  160 + }
  161 +
  162 + return barcode;
  163 + }
  164 +}
  1 +/*
  2 + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +// ignore_for_file: omit_local_variable_types
  18 +
  19 +part of widget;
  20 +
  21 +typedef QrError = void Function(dynamic error);
  22 +
  23 +class _QrCodeWidget extends Widget {
  24 + _QrCodeWidget({
  25 + @required String data,
  26 + this.version,
  27 + this.errorCorrectionLevel,
  28 + this.color,
  29 + this.onError,
  30 + this.gapless = false,
  31 + }) : assert(data != null),
  32 + _qr = version == null
  33 + ? QrCode.fromData(
  34 + data: data,
  35 + errorCorrectLevel: errorCorrectionLevel,
  36 + )
  37 + : QrCode(
  38 + version,
  39 + errorCorrectionLevel,
  40 + ) {
  41 + // configure and make the QR code data
  42 + try {
  43 + if (version != null) {
  44 + _qr.addData(data);
  45 + }
  46 + _qr.make();
  47 + } catch (ex) {
  48 + if (onError != null) {
  49 + _hasError = true;
  50 + onError(ex);
  51 + }
  52 + }
  53 + }
  54 +
  55 + @override
  56 + void layout(Context context, BoxConstraints constraints,
  57 + {bool parentUsesSize = false}) {
  58 + box = PdfRect.fromPoints(PdfPoint.zero, constraints.biggest);
  59 + }
  60 +
  61 + /// the qr code version
  62 + final int version;
  63 +
  64 + /// the qr code error correction level
  65 + final int errorCorrectionLevel;
  66 +
  67 + /// the color of the dark squares
  68 + final PdfColor color;
  69 +
  70 + final QrError onError;
  71 +
  72 + final bool gapless;
  73 +
  74 + // our qr code data
  75 + final QrCode _qr;
  76 +
  77 + bool _hasError = false;
  78 +
  79 + @override
  80 + void paint(Context context) {
  81 + super.paint(context);
  82 +
  83 + if (_hasError) {
  84 + return;
  85 + }
  86 +
  87 + final double shortestSide = box.width < box.height ? box.width : box.height;
  88 + assert(shortestSide > 0);
  89 +
  90 + context.canvas.setFillColor(color);
  91 + final double squareSize = shortestSide / _qr.moduleCount.toDouble();
  92 + final int pxAdjustValue = gapless ? 1 : 0;
  93 + for (int x = 0; x < _qr.moduleCount; x++) {
  94 + for (int y = 0; y < _qr.moduleCount; y++) {
  95 + if (_qr.isDark(y, x)) {
  96 + context.canvas.drawRect(
  97 + box.left + x * squareSize,
  98 + box.top - (y + 1) * squareSize,
  99 + squareSize + pxAdjustValue,
  100 + squareSize + pxAdjustValue,
  101 + );
  102 + }
  103 + }
  104 + }
  105 +
  106 + context.canvas.fillPath();
  107 + }
  108 +}
  109 +
  110 +class QrCodeWidget extends StatelessWidget {
  111 + QrCodeWidget({
  112 + @required this.data,
  113 + this.version,
  114 + this.errorCorrectionLevel = QrErrorCorrectLevel.L,
  115 + this.color = PdfColors.black,
  116 + this.backgroundColor,
  117 + this.decoration,
  118 + this.margin,
  119 + this.onError,
  120 + this.gapless = false,
  121 + this.size,
  122 + this.padding,
  123 + });
  124 +
  125 + /// the qr code data
  126 + final String data;
  127 +
  128 + /// the qr code version
  129 + final int version;
  130 +
  131 + /// the qr code error correction level
  132 + final int errorCorrectionLevel;
  133 +
  134 + /// the color of the dark squares
  135 + final PdfColor color;
  136 +
  137 + final PdfColor backgroundColor;
  138 +
  139 + final EdgeInsets margin;
  140 +
  141 + final QrError onError;
  142 +
  143 + final bool gapless;
  144 +
  145 + final double size;
  146 +
  147 + final EdgeInsets padding;
  148 +
  149 + final BoxDecoration decoration;
  150 +
  151 + @override
  152 + Widget build(Context context) {
  153 + Widget qrcode = AspectRatio(
  154 + aspectRatio: 1.0,
  155 + child: _QrCodeWidget(
  156 + data: data,
  157 + version: version,
  158 + errorCorrectionLevel: errorCorrectionLevel,
  159 + color: color,
  160 + onError: onError,
  161 + gapless: gapless,
  162 + ));
  163 +
  164 + if (padding != null) {
  165 + qrcode = Padding(padding: padding, child: qrcode);
  166 + }
  167 +
  168 + if (decoration != null) {
  169 + qrcode = DecoratedBox(
  170 + decoration: decoration,
  171 + child: qrcode,
  172 + );
  173 + } else if (backgroundColor != null) {
  174 + qrcode = DecoratedBox(
  175 + decoration: BoxDecoration(color: backgroundColor),
  176 + child: qrcode,
  177 + );
  178 + }
  179 +
  180 + if (size != null) {
  181 + qrcode = SizedBox(width: size, height: size, child: qrcode);
  182 + }
  183 +
  184 + if (margin != null) {
  185 + qrcode = Padding(padding: margin, child: qrcode);
  186 + }
  187 +
  188 + return qrcode;
  189 + }
  190 +}
@@ -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: 1.3.27 7 +version: 1.3.28
8 8
9 environment: 9 environment:
10 sdk: ">=2.3.0 <3.0.0" 10 sdk: ">=2.3.0 <3.0.0"
@@ -15,6 +15,8 @@ dependencies: @@ -15,6 +15,8 @@ dependencies:
15 utf: ^0.9.0 15 utf: ^0.9.0
16 crypto: ^2.0.6 16 crypto: ^2.0.6
17 archive: ^2.0.10 17 archive: ^2.0.10
  18 + qr: ^1.2.0
  19 + barcode: ^0.1.0
18 20
19 dev_dependencies: 21 dev_dependencies:
20 test: 22 test:
@@ -28,6 +28,7 @@ import 'orientation_test.dart' as orientation; @@ -28,6 +28,7 @@ import 'orientation_test.dart' as orientation;
28 import 'roll_paper_test.dart' as roll; 28 import 'roll_paper_test.dart' as roll;
29 import 'ttf_test.dart' as ttf; 29 import 'ttf_test.dart' as ttf;
30 import 'type1_test.dart' as type1; 30 import 'type1_test.dart' as type1;
  31 +import 'widget_barcode_test.dart' as widget_barcode;
31 import 'widget_basic_test.dart' as widget_basic; 32 import 'widget_basic_test.dart' as widget_basic;
32 import 'widget_clip_test.dart' as widget_clip; 33 import 'widget_clip_test.dart' as widget_clip;
33 import 'widget_container_test.dart' as widget_container; 34 import 'widget_container_test.dart' as widget_container;
@@ -54,6 +55,7 @@ void main() { @@ -54,6 +55,7 @@ void main() {
54 ttf.main(); 55 ttf.main();
55 type1.main(); 56 type1.main();
56 widget_basic.main(); 57 widget_basic.main();
  58 + widget_barcode.main();
57 widget_clip.main(); 59 widget_clip.main();
58 widget_container.main(); 60 widget_container.main();
59 widget_flex.main(); 61 widget_flex.main();
  1 +/*
  2 + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +// ignore_for_file: omit_local_variable_types
  18 +
  19 +import 'dart:io';
  20 +
  21 +import 'package:pdf/pdf.dart';
  22 +import 'package:pdf/widgets.dart';
  23 +import 'package:test/test.dart';
  24 +
  25 +Document pdf;
  26 +
  27 +void main() {
  28 + setUpAll(() {
  29 + Document.debug = true;
  30 + pdf = Document();
  31 + });
  32 +
  33 + test('Barcode Widgets Code39', () {
  34 + pdf.addPage(
  35 + Page(
  36 + build: (Context context) => BarcodeWidget(
  37 + data: 'HELLO 123',
  38 + width: 200,
  39 + height: 50,
  40 + ),
  41 + ),
  42 + );
  43 + });
  44 +
  45 + test('QrCode Widgets', () {
  46 + pdf.addPage(
  47 + Page(
  48 + build: (Context context) => QrCodeWidget(
  49 + data: 'HELLO 123',
  50 + size: 200,
  51 + padding: const EdgeInsets.all(20),
  52 + margin: const EdgeInsets.all(20),
  53 + decoration: BoxDecoration(
  54 + borderRadius: 20,
  55 + color: PdfColors.white,
  56 + border: BoxBorder(
  57 + color: PdfColors.blue,
  58 + top: true,
  59 + bottom: true,
  60 + left: true,
  61 + right: true,
  62 + )),
  63 + ),
  64 + ),
  65 + );
  66 + });
  67 +
  68 + tearDownAll(() {
  69 + final File file = File('widgets-barcode.pdf');
  70 + file.writeAsBytesSync(pdf.save());
  71 + });
  72 +}
1 import 'package:meta/meta.dart'; 1 import 'package:meta/meta.dart';
2 import 'package:pdf/pdf.dart'; 2 import 'package:pdf/pdf.dart';
3 import 'package:pdf/widgets.dart'; 3 import 'package:pdf/widgets.dart';
4 -import 'package:qr/qr.dart';  
5 4
6 const PdfColor green = PdfColor.fromInt(0xff9ce5d0); 5 const PdfColor green = PdfColor.fromInt(0xff9ce5d0);
7 const PdfColor lightGreen = PdfColor.fromInt(0xffcdf1e7); 6 const PdfColor lightGreen = PdfColor.fromInt(0xffcdf1e7);
@@ -109,152 +108,6 @@ class Category extends StatelessWidget { @@ -109,152 +108,6 @@ class Category extends StatelessWidget {
109 } 108 }
110 } 109 }
111 110
112 -typedef QrError = void Function(dynamic error);  
113 -  
114 -class _QrCodeWidget extends Widget {  
115 - _QrCodeWidget({  
116 - @required String data,  
117 - this.version,  
118 - this.errorCorrectionLevel,  
119 - this.color,  
120 - this.onError,  
121 - this.gapless = false,  
122 - }) : assert(data != null),  
123 - _qr = version == null  
124 - ? QrCode.fromData(  
125 - data: data,  
126 - errorCorrectLevel: errorCorrectionLevel,  
127 - )  
128 - : QrCode(  
129 - version,  
130 - errorCorrectionLevel,  
131 - ) {  
132 - // configure and make the QR code data  
133 - try {  
134 - if (version != null) {  
135 - _qr.addData(data);  
136 - }  
137 - _qr.make();  
138 - } catch (ex) {  
139 - if (onError != null) {  
140 - _hasError = true;  
141 - onError(ex);  
142 - }  
143 - }  
144 - }  
145 -  
146 - @override  
147 - void layout(Context context, BoxConstraints constraints,  
148 - {bool parentUsesSize = false}) {  
149 - box = PdfRect.fromPoints(PdfPoint.zero, constraints.biggest);  
150 - }  
151 -  
152 - /// the qr code version  
153 - final int version;  
154 -  
155 - /// the qr code error correction level  
156 - final int errorCorrectionLevel;  
157 -  
158 - /// the color of the dark squares  
159 - final PdfColor color;  
160 -  
161 - final QrError onError;  
162 -  
163 - final bool gapless;  
164 -  
165 - // our qr code data  
166 - final QrCode _qr;  
167 -  
168 - bool _hasError = false;  
169 -  
170 - @override  
171 - void paint(Context context) {  
172 - super.paint(context);  
173 -  
174 - if (_hasError) {  
175 - return;  
176 - }  
177 -  
178 - final double shortestSide = box.width < box.height ? box.width : box.height;  
179 - assert(shortestSide > 0);  
180 -  
181 - context.canvas.setFillColor(color);  
182 - final double squareSize = shortestSide / _qr.moduleCount.toDouble();  
183 - final int pxAdjustValue = gapless ? 1 : 0;  
184 - for (int x = 0; x < _qr.moduleCount; x++) {  
185 - for (int y = 0; y < _qr.moduleCount; y++) {  
186 - if (_qr.isDark(y, x)) {  
187 - context.canvas.drawRect(  
188 - box.left + x * squareSize,  
189 - box.top - (y + 1) * squareSize,  
190 - squareSize + pxAdjustValue,  
191 - squareSize + pxAdjustValue,  
192 - );  
193 - }  
194 - }  
195 - }  
196 -  
197 - context.canvas.fillPath();  
198 - }  
199 -}  
200 -  
201 -class QrCodeWidget extends StatelessWidget {  
202 - QrCodeWidget({  
203 - @required this.data,  
204 - this.version,  
205 - this.errorCorrectionLevel = QrErrorCorrectLevel.L,  
206 - this.color = PdfColors.black,  
207 - this.onError,  
208 - this.gapless = false,  
209 - this.size,  
210 - this.padding,  
211 - });  
212 -  
213 - /// the qr code data  
214 - final String data;  
215 -  
216 - /// the qr code version  
217 - final int version;  
218 -  
219 - /// the qr code error correction level  
220 - final int errorCorrectionLevel;  
221 -  
222 - /// the color of the dark squares  
223 - final PdfColor color;  
224 -  
225 - final QrError onError;  
226 -  
227 - final bool gapless;  
228 -  
229 - final double size;  
230 -  
231 - final EdgeInsets padding;  
232 -  
233 - @override  
234 - Widget build(Context context) {  
235 - Widget qrcode = AspectRatio(  
236 - aspectRatio: 1.0,  
237 - child: _QrCodeWidget(  
238 - data: data,  
239 - version: version,  
240 - errorCorrectionLevel: errorCorrectionLevel,  
241 - color: color,  
242 - onError: onError,  
243 - gapless: gapless,  
244 - ));  
245 -  
246 - if (padding != null) {  
247 - qrcode = Padding(padding: padding, child: qrcode);  
248 - }  
249 -  
250 - if (size != null) {  
251 - qrcode = SizedBox(width: size, height: size, child: qrcode);  
252 - }  
253 -  
254 - return qrcode;  
255 - }  
256 -}  
257 -  
258 class Percent extends StatelessWidget { 111 class Percent extends StatelessWidget {
259 Percent({ 112 Percent({
260 @required this.size, 113 @required this.size,
@@ -13,7 +13,6 @@ dependencies: @@ -13,7 +13,6 @@ dependencies:
13 path_provider: 13 path_provider:
14 flutter_full_pdf_viewer: 14 flutter_full_pdf_viewer:
15 cupertino_icons: 15 cupertino_icons:
16 - qr:  
17 markdown: 16 markdown:
18 17
19 dev_dependencies: 18 dev_dependencies: