David PHAM-VAN

Use PdfDataTypes for internal structures

@@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
4 4
5 - Improve Annotations 5 - Improve Annotations
6 - Implement table row vertical alignment 6 - Implement table row vertical alignment
  7 +- Improve Internal data structure
7 8
8 ## 1.5.0 9 ## 1.5.0
9 10
@@ -38,6 +38,7 @@ part 'src/catalog.dart'; @@ -38,6 +38,7 @@ part 'src/catalog.dart';
38 part 'src/color.dart'; 38 part 'src/color.dart';
39 part 'src/colors.dart'; 39 part 'src/colors.dart';
40 part 'src/compatibility.dart'; 40 part 'src/compatibility.dart';
  41 +part 'src/data_types.dart';
41 part 'src/document.dart'; 42 part 'src/document.dart';
42 part 'src/encryption.dart'; 43 part 'src/encryption.dart';
43 part 'src/exif.dart'; 44 part 'src/exif.dart';
@@ -86,7 +86,7 @@ class PdfAnnot extends PdfObject { @@ -86,7 +86,7 @@ class PdfAnnot extends PdfObject {
86 @override 86 @override
87 void _prepare() { 87 void _prepare() {
88 super._prepare(); 88 super._prepare();
89 - annot.build(pdfPage, params); 89 + annot.build(pdfPage, this, params);
90 } 90 }
91 } 91 }
92 92
@@ -145,44 +145,44 @@ abstract class PdfAnnotBase { @@ -145,44 +145,44 @@ abstract class PdfAnnotBase {
145 145
146 @protected 146 @protected
147 @mustCallSuper 147 @mustCallSuper
148 - void build(PdfPage page, Map<String, PdfStream> params) {  
149 - params['/Subtype'] = PdfStream.string(subtype);  
150 - params['/Rect'] = PdfStream()  
151 - ..putNumArray(<double>[rect.left, rect.bottom, rect.right, rect.top]); 148 + void build(PdfPage page, PdfObject object, PdfDict params) {
  149 + params['/Subtype'] = PdfName(subtype);
  150 + params['/Rect'] = PdfArray.fromNum(
  151 + <double>[rect.left, rect.bottom, rect.right, rect.top]);
152 152
153 params['/P'] = page.ref(); 153 params['/P'] = page.ref();
154 154
155 // handle the border 155 // handle the border
156 if (border == null) { 156 if (border == null) {
157 - params['/Border'] = PdfStream.string('[0 0 0]'); 157 + params['/Border'] = PdfArray.fromNum(const <int>[0, 0, 0]);
158 } else { 158 } else {
159 params['/BS'] = border.ref(); 159 params['/BS'] = border.ref();
160 } 160 }
161 161
162 if (content != null) { 162 if (content != null) {
163 - params['/Contents'] = PdfStream()..putLiteral(content); 163 + params['/Contents'] = PdfSecString.fromString(object, content);
164 } 164 }
165 165
166 if (name != null) { 166 if (name != null) {
167 - params['/NM'] = PdfStream()..putLiteral(name); 167 + params['/NM'] = PdfSecString.fromString(object, name);
168 } 168 }
169 169
170 if (flags != null) { 170 if (flags != null) {
171 - params['/F'] = PdfStream.intNum(flagValue); 171 + params['/F'] = PdfNum(flagValue);
172 } 172 }
173 173
174 if (date != null) { 174 if (date != null) {
175 - params['/M'] = PdfStream()..putDate(date); 175 + params['/M'] = PdfSecString.fromDate(object, date);
176 } 176 }
177 177
178 if (color != null) { 178 if (color != null) {
179 if (color is PdfColorCmyk) { 179 if (color is PdfColorCmyk) {
180 final PdfColorCmyk k = color; 180 final PdfColorCmyk k = color;
181 - params['/C'] = PdfStream()  
182 - ..putNumList(<double>[k.cyan, k.magenta, k.yellow, k.black]); 181 + params['/C'] =
  182 + PdfArray.fromNum(<double>[k.cyan, k.magenta, k.yellow, k.black]);
183 } else { 183 } else {
184 - params['/C'] = PdfStream()  
185 - ..putNumList(<double>[color.red, color.green, color.blue]); 184 + params['/C'] =
  185 + PdfArray.fromNum(<double>[color.red, color.green, color.blue]);
186 } 186 }
187 } 187 }
188 } 188 }
@@ -231,13 +231,12 @@ class PdfAnnotNamedLink extends PdfAnnotBase { @@ -231,13 +231,12 @@ class PdfAnnotNamedLink extends PdfAnnotBase {
231 final String dest; 231 final String dest;
232 232
233 @override 233 @override
234 - void build(PdfPage page, Map<String, PdfStream> params) {  
235 - super.build(page, params);  
236 - params['/A'] = PdfStream()  
237 - ..putDictionary(  
238 - <String, PdfStream>{  
239 - '/S': PdfStream()..putString('/GoTo'),  
240 - '/D': PdfStream()..putText(dest), 234 + void build(PdfPage page, PdfObject object, PdfDict params) {
  235 + super.build(page, object, params);
  236 + params['/A'] = PdfDict(
  237 + <String, PdfDataType>{
  238 + '/S': const PdfName('/GoTo'),
  239 + '/D': PdfSecString.fromString(object, dest),
241 }, 240 },
242 ); 241 );
243 } 242 }
@@ -264,13 +263,12 @@ class PdfAnnotUrlLink extends PdfAnnotBase { @@ -264,13 +263,12 @@ class PdfAnnotUrlLink extends PdfAnnotBase {
264 final String url; 263 final String url;
265 264
266 @override 265 @override
267 - void build(PdfPage page, Map<String, PdfStream> params) {  
268 - super.build(page, params);  
269 - params['/A'] = PdfStream()  
270 - ..putDictionary(  
271 - <String, PdfStream>{  
272 - '/S': PdfStream()..putString('/URI'),  
273 - '/URI': PdfStream()..putText(url), 266 + void build(PdfPage page, PdfObject object, PdfDict params) {
  267 + super.build(page, object, params);
  268 + params['/A'] = PdfDict(
  269 + <String, PdfDataType>{
  270 + '/S': const PdfName('/URI'),
  271 + '/URI': PdfSecString.fromString(object, url),
274 }, 272 },
275 ); 273 );
276 } 274 }
@@ -289,7 +287,6 @@ abstract class PdfAnnotWidget extends PdfAnnotBase { @@ -289,7 +287,6 @@ abstract class PdfAnnotWidget extends PdfAnnotBase {
289 DateTime date, 287 DateTime date,
290 PdfColor color, 288 PdfColor color,
291 this.highlighting, 289 this.highlighting,
292 - this.value,  
293 }) : super( 290 }) : super(
294 subtype: '/Widget', 291 subtype: '/Widget',
295 rect: rect, 292 rect: rect,
@@ -305,20 +302,14 @@ abstract class PdfAnnotWidget extends PdfAnnotBase { @@ -305,20 +302,14 @@ abstract class PdfAnnotWidget extends PdfAnnotBase {
305 302
306 final PdfAnnotHighlighting highlighting; 303 final PdfAnnotHighlighting highlighting;
307 304
308 - final PdfStream value;  
309 -  
310 @override 305 @override
311 - void build(PdfPage page, Map<String, PdfStream> params) {  
312 - super.build(page, params); 306 + void build(PdfPage page, PdfObject object, PdfDict params) {
  307 + super.build(page, object, params);
313 308
314 - params['/FT'] = PdfStream.string(fieldType); 309 + params['/FT'] = PdfName(fieldType);
315 310
316 if (fieldName != null) { 311 if (fieldName != null) {
317 - params['/T'] = PdfStream()..putLiteral(fieldName);  
318 - }  
319 -  
320 - if (value != null) {  
321 - params['/V'] = value; 312 + params['/T'] = PdfSecString.fromString(object, fieldName);
322 } 313 }
323 } 314 }
324 } 315 }
@@ -344,8 +335,8 @@ class PdfAnnotSign extends PdfAnnotWidget { @@ -344,8 +335,8 @@ class PdfAnnotSign extends PdfAnnotWidget {
344 ); 335 );
345 336
346 @override 337 @override
347 - void build(PdfPage page, Map<String, PdfStream> params) {  
348 - super.build(page, params); 338 + void build(PdfPage page, PdfObject object, PdfDict params) {
  339 + super.build(page, object, params);
349 assert(page.pdfDocument.sign != null); 340 assert(page.pdfDocument.sign != null);
350 params['/V'] = page.pdfDocument.sign.ref(); 341 params['/V'] = page.pdfDocument.sign.ref();
351 } 342 }
@@ -19,17 +19,17 @@ part of pdf; @@ -19,17 +19,17 @@ part of pdf;
19 class PdfArrayObject extends PdfObject { 19 class PdfArrayObject extends PdfObject {
20 PdfArrayObject( 20 PdfArrayObject(
21 PdfDocument pdfDocument, 21 PdfDocument pdfDocument,
22 - this.values,  
23 - ) : assert(values != null), 22 + this.array,
  23 + ) : assert(array != null),
24 super(pdfDocument); 24 super(pdfDocument);
25 25
26 - final List<String> values; 26 + final PdfArray array;
27 27
28 @override 28 @override
29 void _writeContent(PdfStream os) { 29 void _writeContent(PdfStream os) {
30 super._writeContent(os); 30 super._writeContent(os);
31 31
32 - os.putStringArray(values); 32 + array.output(os);
33 os.putBytes(<int>[0x0a]); 33 os.putBytes(<int>[0x0a]);
34 } 34 }
35 } 35 }
@@ -66,18 +66,15 @@ class PdfBorder extends PdfObject { @@ -66,18 +66,15 @@ class PdfBorder extends PdfObject {
66 66
67 /// @param os OutputStream to send the object to 67 /// @param os OutputStream to send the object to
68 @override 68 @override
69 - void _writeContent(PdfStream os) {  
70 - super._writeContent(os); 69 + void _prepare() {
  70 + super._prepare();
  71 +
  72 + params['/S'] =
  73 + PdfName('/' + 'SDBIU'.substring(style.index, style.index + 1));
  74 + params['/W'] = PdfNum(width);
71 75
72 - final List<PdfStream> data = <PdfStream>[];  
73 - data.add(PdfStream.string('/S'));  
74 - data.add(PdfStream.string(  
75 - '/' + 'SDBIU'.substring(style.index, style.index + 1)));  
76 - data.add(PdfStream.string('/W $width'));  
77 if (dash != null) { 76 if (dash != null) {
78 - data.add(PdfStream.string('/D'));  
79 - data.add(PdfStream.array(dash.map((double d) => PdfStream.num(d)))); 77 + params['/D'] = PdfArray.fromNum(dash);
80 } 78 }
81 - os.putArray(data);  
82 } 79 }
83 } 80 }
@@ -52,7 +52,7 @@ class PdfCatalog extends PdfObject { @@ -52,7 +52,7 @@ class PdfCatalog extends PdfObject {
52 super._prepare(); 52 super._prepare();
53 53
54 /// the PDF specification version, overrides the header version starting from 1.4 54 /// the PDF specification version, overrides the header version starting from 1.4
55 - params['/Version'] = PdfStream.string('/${pdfDocument.version}'); 55 + params['/Version'] = PdfName('/${pdfDocument.version}');
56 56
57 params['/Pages'] = pdfPageList.ref(); 57 params['/Pages'] = pdfPageList.ref();
58 58
@@ -65,11 +65,10 @@ class PdfCatalog extends PdfObject { @@ -65,11 +65,10 @@ class PdfCatalog extends PdfObject {
65 params['/Names'] = names.ref(); 65 params['/Names'] = names.ref();
66 66
67 // the /PageMode setting 67 // the /PageMode setting
68 - params['/PageMode'] =  
69 - PdfStream.string(PdfDocument._PdfPageModes[pageMode.index]); 68 + params['/PageMode'] = PdfName(PdfDocument._PdfPageModes[pageMode.index]);
70 69
71 if (pdfDocument.sign != null) { 70 if (pdfDocument.sign != null) {
72 - params['/Perms'] = PdfStream.dictionary(<String, PdfStream>{ 71 + params['/Perms'] = PdfDict(<String, PdfDataType>{
73 '/DocMDP': pdfDocument.sign.ref(), 72 '/DocMDP': pdfDocument.sign.ref(),
74 }); 73 });
75 } 74 }
@@ -84,9 +83,9 @@ class PdfCatalog extends PdfObject { @@ -84,9 +83,9 @@ class PdfCatalog extends PdfObject {
84 } 83 }
85 84
86 if (widgets.isNotEmpty) { 85 if (widgets.isNotEmpty) {
87 - params['/AcroForm'] = PdfStream.dictionary(<String, PdfStream>{  
88 - '/SigFlags': PdfStream.intNum(pdfDocument.sign?.flagsValue ?? 0),  
89 - '/Fields': PdfStream()..putObjectArray(widgets), 86 + params['/AcroForm'] = PdfDict(<String, PdfDataType>{
  87 + '/SigFlags': PdfNum(pdfDocument.sign?.flagsValue ?? 0),
  88 + '/Fields': PdfArray.fromObjects(widgets),
90 }); 89 });
91 } 90 }
92 } 91 }
@@ -73,7 +73,7 @@ class PDFAnnot extends PdfAnnot { @@ -73,7 +73,7 @@ class PDFAnnot extends PdfAnnot {
73 @deprecated 73 @deprecated
74 class PDFArrayObject extends PdfArrayObject { 74 class PDFArrayObject extends PdfArrayObject {
75 PDFArrayObject(PdfDocument pdfDocument, List<String> values) 75 PDFArrayObject(PdfDocument pdfDocument, List<String> values)
76 - : super(pdfDocument, values); 76 + : super(pdfDocument, null);
77 } 77 }
78 78
79 @deprecated 79 @deprecated
  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 +// ignore_for_file: avoid_unused_constructor_parameters
  19 +
  20 +part of pdf;
  21 +
  22 +abstract class PdfDataType {
  23 + const PdfDataType();
  24 +
  25 + void output(PdfStream s);
  26 +
  27 + PdfStream toStream() {
  28 + final PdfStream s = PdfStream();
  29 + output(s);
  30 + return s;
  31 + }
  32 +
  33 + @override
  34 + String toString() {
  35 + return String.fromCharCodes(toStream().output());
  36 + }
  37 +
  38 + List<int> toList() {
  39 + return toStream().output();
  40 + }
  41 +}
  42 +
  43 +class PdfBool extends PdfDataType {
  44 + const PdfBool(this.value);
  45 +
  46 + final bool value;
  47 +
  48 + @override
  49 + void output(PdfStream s) {
  50 + s.putString(value ? 'true' : 'false');
  51 + }
  52 +}
  53 +
  54 +class PdfNum extends PdfDataType {
  55 + const PdfNum(this.value);
  56 +
  57 + final num value;
  58 +
  59 + @override
  60 + void output(PdfStream s) {
  61 + if (value is int) {
  62 + s.putString(value.toInt().toString());
  63 + } else {
  64 + s.putNum(value);
  65 + }
  66 + }
  67 +}
  68 +
  69 +enum PdfStringFormat { binary, litteral }
  70 +
  71 +class PdfString extends PdfDataType {
  72 + const PdfString(this.value, [this.format = PdfStringFormat.litteral]);
  73 +
  74 + factory PdfString.fromString(String value) {
  75 + try {
  76 + return PdfString(latin1.encode(value), PdfStringFormat.litteral);
  77 + } catch (e) {
  78 + return PdfString(
  79 + Uint8List.fromList(<int>[0xfe, 0xff] + encodeUtf16be(value)),
  80 + PdfStringFormat.litteral,
  81 + );
  82 + }
  83 + }
  84 +
  85 + factory PdfString.fromDate(DateTime date) {
  86 + final DateTime utcDate = date.toUtc();
  87 + final String year = utcDate.year.toString().padLeft(4, '0');
  88 + final String month = utcDate.month.toString().padLeft(2, '0');
  89 + final String day = utcDate.day.toString().padLeft(2, '0');
  90 + final String hour = utcDate.hour.toString().padLeft(2, '0');
  91 + final String minute = utcDate.minute.toString().padLeft(2, '0');
  92 + final String second = utcDate.second.toString().padLeft(2, '0');
  93 + return PdfString.fromString('D:$year$month$day$hour$minute${second}Z');
  94 + }
  95 +
  96 + final Uint8List value;
  97 +
  98 + final PdfStringFormat format;
  99 +
  100 + /// Returns the ASCII/Unicode code unit corresponding to the hexadecimal digit
  101 + /// [digit].
  102 + int _codeUnitForDigit(int digit) =>
  103 + digit < 10 ? digit + 0x30 : digit + 0x61 - 10;
  104 +
  105 + @override
  106 + void output(PdfStream s) {
  107 + switch (format) {
  108 + case PdfStringFormat.binary:
  109 + s.putByte(0x3c);
  110 + for (int byte in value) {
  111 + s.putByte(_codeUnitForDigit((byte & 0xF0) >> 4));
  112 + s.putByte(_codeUnitForDigit(byte & 0x0F));
  113 + }
  114 + s.putByte(0x3e);
  115 +
  116 + break;
  117 + case PdfStringFormat.litteral:
  118 + s.putByte(40);
  119 + s.putTextBytes(value);
  120 + s.putByte(41);
  121 + break;
  122 + }
  123 + }
  124 +}
  125 +
  126 +class PdfSecString extends PdfString {
  127 + const PdfSecString(this.object, Uint8List value,
  128 + [PdfStringFormat format = PdfStringFormat.binary])
  129 + : super(value, format);
  130 +
  131 + factory PdfSecString.fromString(PdfObject object, String value) {
  132 + try {
  133 + return PdfSecString(
  134 + object, latin1.encode(value), PdfStringFormat.litteral);
  135 + } catch (e) {
  136 + return PdfSecString(
  137 + object,
  138 + Uint8List.fromList(<int>[0xfe, 0xff] + encodeUtf16be(value)),
  139 + PdfStringFormat.litteral,
  140 + );
  141 + }
  142 + }
  143 +
  144 + factory PdfSecString.fromDate(PdfObject object, DateTime date) {
  145 + final DateTime utcDate = date.toUtc();
  146 + final String year = utcDate.year.toString().padLeft(4, '0');
  147 + final String month = utcDate.month.toString().padLeft(2, '0');
  148 + final String day = utcDate.day.toString().padLeft(2, '0');
  149 + final String hour = utcDate.hour.toString().padLeft(2, '0');
  150 + final String minute = utcDate.minute.toString().padLeft(2, '0');
  151 + final String second = utcDate.second.toString().padLeft(2, '0');
  152 + return PdfSecString.fromString(
  153 + object, 'D:$year$month$day$hour$minute${second}Z');
  154 + }
  155 +
  156 + final PdfObject object;
  157 +
  158 + @override
  159 + void output(PdfStream s) {
  160 + if (object.pdfDocument.encryption == null) {
  161 + return super.output(s);
  162 + }
  163 +
  164 + final List<int> enc = object.pdfDocument.encryption.encrypt(value, object);
  165 + switch (format) {
  166 + case PdfStringFormat.binary:
  167 + s.putByte(0x3c);
  168 + for (int byte in enc) {
  169 + s.putByte(_codeUnitForDigit((byte & 0xF0) >> 4));
  170 + s.putByte(_codeUnitForDigit(byte & 0x0F));
  171 + }
  172 + s.putByte(0x3e);
  173 +
  174 + break;
  175 + case PdfStringFormat.litteral:
  176 + s.putByte(40);
  177 + s.putTextBytes(enc);
  178 + s.putByte(41);
  179 + break;
  180 + }
  181 + }
  182 +}
  183 +
  184 +class PdfName extends PdfDataType {
  185 + const PdfName(this.value);
  186 +
  187 + final String value;
  188 +
  189 + @override
  190 + void output(PdfStream s) {
  191 + assert(value[0] == '/');
  192 + s.putString(value);
  193 + }
  194 +}
  195 +
  196 +class PdfNull extends PdfDataType {
  197 + const PdfNull();
  198 +
  199 + @override
  200 + void output(PdfStream s) {
  201 + s.putString('null');
  202 + }
  203 +}
  204 +
  205 +class PdfIndirect extends PdfDataType {
  206 + const PdfIndirect(this.ser, this.gen);
  207 +
  208 + final int ser;
  209 +
  210 + final int gen;
  211 +
  212 + @override
  213 + void output(PdfStream s) {
  214 + s.putString('$ser $gen R');
  215 + }
  216 +}
  217 +
  218 +class PdfArray extends PdfDataType {
  219 + PdfArray([Iterable<PdfDataType> values]) {
  220 + if (values != null) {
  221 + this.values.addAll(values);
  222 + }
  223 + }
  224 +
  225 + factory PdfArray.fromObjects(List<PdfObject> objects) {
  226 + return PdfArray(
  227 + objects.map<PdfIndirect>((PdfObject e) => e.ref()).toList());
  228 + }
  229 +
  230 + factory PdfArray.fromNum(List<num> list) {
  231 + return PdfArray(list.map<PdfNum>((num e) => PdfNum(e)).toList());
  232 + }
  233 +
  234 + // factory PdfArray.fromStrings(List<String> list) {
  235 + // return PdfArray(
  236 + // list.map<PdfString>((String e) => PdfString.fromString(e)).toList());
  237 + // }
  238 +
  239 + final List<PdfDataType> values = <PdfDataType>[];
  240 +
  241 + void add(PdfDataType v) {
  242 + values.add(v);
  243 + }
  244 +
  245 + @override
  246 + void output(PdfStream s) {
  247 + s.putString('[');
  248 + if (values.isNotEmpty) {
  249 + for (int n = 0; n < values.length - 1; n++) {
  250 + final PdfDataType val = values[n];
  251 + val.output(s);
  252 + s.putString(' ');
  253 + }
  254 + values.last.output(s);
  255 + }
  256 + s.putString(']');
  257 + }
  258 +}
  259 +
  260 +class PdfDict extends PdfDataType {
  261 + PdfDict([Map<String, PdfDataType> values]) {
  262 + if (values != null) {
  263 + this.values.addAll(values);
  264 + }
  265 + }
  266 +
  267 + factory PdfDict.fromObjectMap(Map<String, PdfObject> objects) {
  268 + return PdfDict(
  269 + objects.map<String, PdfIndirect>(
  270 + (String key, PdfObject value) =>
  271 + MapEntry<String, PdfIndirect>(key, value.ref()),
  272 + ),
  273 + );
  274 + }
  275 +
  276 + final Map<String, PdfDataType> values = <String, PdfDataType>{};
  277 +
  278 + bool get isNotEmpty => values.isNotEmpty;
  279 +
  280 + operator []=(String k, PdfDataType v) {
  281 + values[k] = v;
  282 + }
  283 +
  284 + @override
  285 + void output(PdfStream s) {
  286 + s.putString('<< ');
  287 + values.forEach((String k, PdfDataType v) {
  288 + s.putString('$k ');
  289 + v.output(s);
  290 + s.putString('\n');
  291 + });
  292 + s.putString('>>');
  293 + }
  294 +
  295 + bool containsKey(String key) {
  296 + return values.containsKey(key);
  297 + }
  298 +}
@@ -119,9 +119,9 @@ abstract class PdfFont extends PdfObject { @@ -119,9 +119,9 @@ abstract class PdfFont extends PdfObject {
119 void _prepare() { 119 void _prepare() {
120 super._prepare(); 120 super._prepare();
121 121
122 - params['/Subtype'] = PdfStream.string(subtype);  
123 - params['/Name'] = PdfStream.string(name);  
124 - params['/Encoding'] = PdfStream.string('/WinAnsiEncoding'); 122 + params['/Subtype'] = PdfName(subtype);
  123 + params['/Name'] = PdfName(name);
  124 + params['/Encoding'] = const PdfName('/WinAnsiEncoding');
125 } 125 }
126 126
127 @Deprecated('Use `glyphMetrics` instead') 127 @Deprecated('Use `glyphMetrics` instead')
@@ -166,9 +166,9 @@ See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management @@ -166,9 +166,9 @@ See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management
166 PdfStream putText(String text) { 166 PdfStream putText(String text) {
167 try { 167 try {
168 return PdfStream() 168 return PdfStream()
169 - ..putBytes(latin1.encode('(')) 169 + ..putByte(40)
170 ..putTextBytes(latin1.encode(text)) 170 ..putTextBytes(latin1.encode(text))
171 - ..putBytes(latin1.encode(')')); 171 + ..putByte(41);
172 } catch (e) { 172 } catch (e) {
173 assert(false, '''\n--------------------------------------------- 173 assert(false, '''\n---------------------------------------------
174 Can not decode the string to Latin1. 174 Can not decode the string to Latin1.
@@ -32,20 +32,19 @@ class PdfFontDescriptor extends PdfObject { @@ -32,20 +32,19 @@ class PdfFontDescriptor extends PdfObject {
32 void _prepare() { 32 void _prepare() {
33 super._prepare(); 33 super._prepare();
34 34
35 - params['/FontName'] = PdfStream.string('/' + ttfFont.fontName); 35 + params['/FontName'] = PdfName('/' + ttfFont.fontName);
36 params['/FontFile2'] = file.ref(); 36 params['/FontFile2'] = file.ref();
37 - params['/Flags'] = PdfStream.intNum(ttfFont.font.unicode ? 4 : 32);  
38 - params['/FontBBox'] = PdfStream()  
39 - ..putIntArray(<int>[ 37 + params['/Flags'] = PdfNum(ttfFont.font.unicode ? 4 : 32);
  38 + params['/FontBBox'] = PdfArray.fromNum(<int>[
40 (ttfFont.font.xMin / ttfFont.font.unitsPerEm * 1000).toInt(), 39 (ttfFont.font.xMin / ttfFont.font.unitsPerEm * 1000).toInt(),
41 (ttfFont.font.yMin / ttfFont.font.unitsPerEm * 1000).toInt(), 40 (ttfFont.font.yMin / ttfFont.font.unitsPerEm * 1000).toInt(),
42 (ttfFont.font.xMax / ttfFont.font.unitsPerEm * 1000).toInt(), 41 (ttfFont.font.xMax / ttfFont.font.unitsPerEm * 1000).toInt(),
43 (ttfFont.font.yMax / ttfFont.font.unitsPerEm * 1000).toInt() 42 (ttfFont.font.yMax / ttfFont.font.unitsPerEm * 1000).toInt()
44 ]); 43 ]);
45 - params['/Ascent'] = PdfStream.intNum((ttfFont.ascent * 1000).toInt());  
46 - params['/Descent'] = PdfStream.intNum((ttfFont.descent * 1000).toInt());  
47 - params['/ItalicAngle'] = PdfStream.intNum(0);  
48 - params['/CapHeight'] = PdfStream.intNum(10);  
49 - params['/StemV'] = PdfStream.intNum(79); 44 + params['/Ascent'] = PdfNum((ttfFont.ascent * 1000).toInt());
  45 + params['/Descent'] = PdfNum((ttfFont.descent * 1000).toInt());
  46 + params['/ItalicAngle'] = const PdfNum(0);
  47 + params['/CapHeight'] = const PdfNum(10);
  48 + params['/StemV'] = const PdfNum(79);
50 } 49 }
51 } 50 }
@@ -20,8 +20,8 @@ part of pdf; @@ -20,8 +20,8 @@ part of pdf;
20 20
21 class PdfFormXObject extends PdfXObject { 21 class PdfFormXObject extends PdfXObject {
22 PdfFormXObject(PdfDocument pdfDocument) : super(pdfDocument, '/Form') { 22 PdfFormXObject(PdfDocument pdfDocument) : super(pdfDocument, '/Form') {
23 - params['/FormType'] = PdfStream.string('1');  
24 - params['/BBox'] = PdfStream.string('[0 0 1000 1000]'); 23 + params['/FormType'] = const PdfNum(1);
  24 + params['/BBox'] = PdfArray.fromNum(const <int>[0, 0, 1000, 1000]);
25 } 25 }
26 26
27 /// The fonts associated with this page 27 /// The fonts associated with this page
@@ -34,7 +34,7 @@ class PdfFormXObject extends PdfXObject { @@ -34,7 +34,7 @@ class PdfFormXObject extends PdfXObject {
34 void setMatrix(Matrix4 t) { 34 void setMatrix(Matrix4 t) {
35 final Float64List s = t.storage; 35 final Float64List s = t.storage;
36 params['/Matrix'] = 36 params['/Matrix'] =
37 - PdfStream.string('[${s[0]} ${s[1]} ${s[4]} ${s[5]} ${s[12]} ${s[13]}]'); 37 + PdfArray.fromNum(<double>[s[0], s[1], s[4], s[5], s[12], s[13]]);
38 } 38 }
39 39
40 @override 40 @override
@@ -43,20 +43,20 @@ class PdfFormXObject extends PdfXObject { @@ -43,20 +43,20 @@ class PdfFormXObject extends PdfXObject {
43 43
44 // Now the resources 44 // Now the resources
45 /// This holds any resources for this FormXObject 45 /// This holds any resources for this FormXObject
46 - final Map<String, PdfStream> resources = <String, PdfStream>{}; 46 + final PdfDict resources = PdfDict();
47 47
48 // fonts 48 // fonts
49 if (fonts.isNotEmpty) { 49 if (fonts.isNotEmpty) {
50 - resources['/Font'] = PdfStream()..putObjectDictionary(fonts); 50 + resources['/Font'] = PdfDict.fromObjectMap(fonts);
51 } 51 }
52 52
53 // Now the XObjects 53 // Now the XObjects
54 if (xobjects.isNotEmpty) { 54 if (xobjects.isNotEmpty) {
55 - resources['/XObject'] = PdfStream()..putObjectDictionary(xobjects); 55 + resources['/XObject'] = PdfDict.fromObjectMap(xobjects);
56 } 56 }
57 57
58 if (resources.isNotEmpty) { 58 if (resources.isNotEmpty) {
59 - params['/Resources'] = PdfStream.dictionary(resources); 59 + params['/Resources'] = resources;
60 } 60 }
61 } 61 }
62 } 62 }
@@ -27,15 +27,15 @@ class PdfGraphicState { @@ -27,15 +27,15 @@ class PdfGraphicState {
27 final double opacity; 27 final double opacity;
28 28
29 @protected 29 @protected
30 - PdfStream _output() {  
31 - final Map<String, PdfStream> params = <String, PdfStream>{}; 30 + PdfDict _output() {
  31 + final PdfDict params = PdfDict();
32 32
33 if (opacity != null) { 33 if (opacity != null) {
34 - params['/CA'] = PdfStream.num(opacity);  
35 - params['/ca'] = PdfStream.num(opacity); 34 + params['/CA'] = PdfNum(opacity);
  35 + params['/ca'] = PdfNum(opacity);
36 } 36 }
37 37
38 - return PdfStream.dictionary(params); 38 + return params;
39 } 39 }
40 40
41 @override 41 @override
@@ -78,10 +78,10 @@ class PdfImage extends PdfXObject { @@ -78,10 +78,10 @@ class PdfImage extends PdfXObject {
78 _height = height, 78 _height = height,
79 super(pdfDocument, '/Image', isBinary: true) { 79 super(pdfDocument, '/Image', isBinary: true) {
80 _name = '/Image$objser'; 80 _name = '/Image$objser';
81 - params['/Width'] = PdfStream.string(width.toString());  
82 - params['/Height'] = PdfStream.string(height.toString());  
83 - params['/BitsPerComponent'] = PdfStream.intNum(8);  
84 - params['/Name'] = PdfStream.string(_name); 81 + params['/Width'] = PdfNum(width);
  82 + params['/Height'] = PdfNum(height);
  83 + params['/BitsPerComponent'] = const PdfNum(8);
  84 + params['/Name'] = PdfName(_name);
85 85
86 if (alphaChannel == false && alpha) { 86 if (alphaChannel == false && alpha) {
87 final PdfImage _sMask = PdfImage._( 87 final PdfImage _sMask = PdfImage._(
@@ -95,17 +95,17 @@ class PdfImage extends PdfXObject { @@ -95,17 +95,17 @@ class PdfImage extends PdfXObject {
95 jpeg: jpeg, 95 jpeg: jpeg,
96 orientation: orientation, 96 orientation: orientation,
97 ); 97 );
98 - params['/SMask'] = PdfStream.string('${_sMask.objser} 0 R'); 98 + params['/SMask'] = PdfIndirect(_sMask.objser, 0);
99 } 99 }
100 100
101 if (isRGB) { 101 if (isRGB) {
102 - params['/ColorSpace'] = PdfStream.string('/DeviceRGB'); 102 + params['/ColorSpace'] = const PdfName('/DeviceRGB');
103 } else { 103 } else {
104 - params['/ColorSpace'] = PdfStream.string('/DeviceGray'); 104 + params['/ColorSpace'] = const PdfName('/DeviceGray');
105 } 105 }
106 106
107 if (jpeg) { 107 if (jpeg) {
108 - params['/Intent'] = PdfStream.string('/RelativeColorimetric'); 108 + params['/Intent'] = const PdfName('/RelativeColorimetric');
109 } 109 }
110 } 110 }
111 111
@@ -163,7 +163,7 @@ class PdfImage extends PdfXObject { @@ -163,7 +163,7 @@ class PdfImage extends PdfXObject {
163 void _prepare() { 163 void _prepare() {
164 if (jpeg) { 164 if (jpeg) {
165 buf.putBytes(image); 165 buf.putBytes(image);
166 - params['/Filter'] = PdfStream.string('/DCTDecode'); 166 + params['/Filter'] = const PdfName('/DCTDecode');
167 super._prepare(); 167 super._prepare();
168 return; 168 return;
169 } 169 }
@@ -27,28 +27,28 @@ class PdfInfo extends PdfObject { @@ -27,28 +27,28 @@ class PdfInfo extends PdfObject {
27 this.producer}) 27 this.producer})
28 : super(pdfDocument, null) { 28 : super(pdfDocument, null) {
29 if (author != null) { 29 if (author != null) {
30 - params['/Author'] = PdfStream()..putLiteral(author); 30 + params['/Author'] = PdfSecString.fromString(this, author);
31 } 31 }
32 if (creator != null) { 32 if (creator != null) {
33 - params['/Creator'] = PdfStream()..putLiteral(creator); 33 + params['/Creator'] = PdfSecString.fromString(this, creator);
34 } 34 }
35 if (title != null) { 35 if (title != null) {
36 - params['/Title'] = PdfStream()..putLiteral(title); 36 + params['/Title'] = PdfSecString.fromString(this, title);
37 } 37 }
38 if (subject != null) { 38 if (subject != null) {
39 - params['/Subject'] = PdfStream()..putLiteral(subject); 39 + params['/Subject'] = PdfSecString.fromString(this, subject);
40 } 40 }
41 if (keywords != null) { 41 if (keywords != null) {
42 - params['/Keywords'] = PdfStream()..putLiteral(keywords); 42 + params['/Keywords'] = PdfSecString.fromString(this, keywords);
43 } 43 }
44 if (producer != null) { 44 if (producer != null) {
45 - params['/Producer'] = PdfStream()  
46 - ..putLiteral('$producer ($_libraryName)'); 45 + params['/Producer'] =
  46 + PdfSecString.fromString(this, '$producer ($_libraryName)');
47 } else { 47 } else {
48 - params['/Producer'] = PdfStream()..putLiteral(_libraryName); 48 + params['/Producer'] = PdfSecString.fromString(this, _libraryName);
49 } 49 }
50 50
51 - params['/CreationDate'] = PdfStream()..putDate(DateTime.now()); 51 + params['/CreationDate'] = PdfSecString.fromDate(this, DateTime.now());
52 } 52 }
53 53
54 static const String _libraryName = 'https://github.com/DavBfr/dart_pdf'; 54 static const String _libraryName = 'https://github.com/DavBfr/dart_pdf';
@@ -20,7 +20,7 @@ class PdfNames extends PdfObject { @@ -20,7 +20,7 @@ class PdfNames extends PdfObject {
20 /// This constructs a Pdf Name object 20 /// This constructs a Pdf Name object
21 PdfNames(PdfDocument pdfDocument) : super(pdfDocument); 21 PdfNames(PdfDocument pdfDocument) : super(pdfDocument);
22 22
23 - final List<PdfStream> _dests = <PdfStream>[]; 23 + final PdfArray _dests = PdfArray();
24 24
25 void addDest( 25 void addDest(
26 String name, 26 String name,
@@ -32,16 +32,14 @@ class PdfNames extends PdfObject { @@ -32,16 +32,14 @@ class PdfNames extends PdfObject {
32 assert(page.pdfDocument == pdfDocument); 32 assert(page.pdfDocument == pdfDocument);
33 assert(name != null); 33 assert(name != null);
34 34
35 - _dests.add(PdfStream()..putText(name));  
36 - _dests.add(PdfStream()  
37 - ..putDictionary(<String, PdfStream>{  
38 - '/D': PdfStream()  
39 - ..putArray(<PdfStream>[ 35 + _dests.add(PdfSecString.fromString(this, name));
  36 + _dests.add(PdfDict(<String, PdfDataType>{
  37 + '/D': PdfArray(<PdfDataType>[
40 page.ref(), 38 page.ref(),
41 - PdfStream.string('/XYZ'),  
42 - if (posX == null) PdfStream.string('null') else PdfStream.num(posX),  
43 - if (posY == null) PdfStream.string('null') else PdfStream.num(posY),  
44 - if (posZ == null) PdfStream.string('null') else PdfStream.num(posZ), 39 + const PdfName('/XYZ'),
  40 + if (posX == null) const PdfNull() else PdfNum(posX),
  41 + if (posY == null) const PdfNull() else PdfNum(posY),
  42 + if (posZ == null) const PdfNull() else PdfNum(posZ),
45 ]), 43 ]),
46 })); 44 }));
47 } 45 }
@@ -50,9 +48,6 @@ class PdfNames extends PdfObject { @@ -50,9 +48,6 @@ class PdfNames extends PdfObject {
50 void _prepare() { 48 void _prepare() {
51 super._prepare(); 49 super._prepare();
52 50
53 - params['/Dests'] = PdfStream()  
54 - ..putDictionary(<String, PdfStream>{  
55 - '/Names': PdfStream()..putArray(_dests),  
56 - }); 51 + params['/Dests'] = PdfDict(<String, PdfDataType>{'/Names': _dests});
57 } 52 }
58 } 53 }
@@ -24,14 +24,14 @@ class PdfObject { @@ -24,14 +24,14 @@ class PdfObject {
24 : assert(pdfDocument != null), 24 : assert(pdfDocument != null),
25 objser = pdfDocument._genSerial() { 25 objser = pdfDocument._genSerial() {
26 if (type != null) { 26 if (type != null) {
27 - params['/Type'] = PdfStream.string(type); 27 + params['/Type'] = PdfName(type);
28 } 28 }
29 29
30 pdfDocument.objects.add(this); 30 pdfDocument.objects.add(this);
31 } 31 }
32 32
33 /// This is the object parameters. 33 /// This is the object parameters.
34 - final Map<String, PdfStream> params = <String, PdfStream>{}; 34 + final PdfDict params = PdfDict();
35 35
36 /// This is the unique serial number for this object. 36 /// This is the unique serial number for this object.
37 final int objser; 37 final int objser;
@@ -72,7 +72,7 @@ class PdfObject { @@ -72,7 +72,7 @@ class PdfObject {
72 72
73 void _writeContent(PdfStream os) { 73 void _writeContent(PdfStream os) {
74 if (params.isNotEmpty) { 74 if (params.isNotEmpty) {
75 - os.putDictionary(params); 75 + params.output(os);
76 os.putString('\n'); 76 os.putString('\n');
77 } 77 }
78 } 78 }
@@ -89,5 +89,5 @@ class PdfObject { @@ -89,5 +89,5 @@ class PdfObject {
89 89
90 /// Returns the unique serial number in Pdf format 90 /// Returns the unique serial number in Pdf format
91 /// @return the serial number in Pdf format 91 /// @return the serial number in Pdf format
92 - PdfStream ref() => PdfStream.string('$objser $objgen R'); 92 + PdfIndirect ref() => PdfIndirect(objser, objgen);
93 } 93 }
@@ -46,12 +46,12 @@ class PdfObjectStream extends PdfObject { @@ -46,12 +46,12 @@ class PdfObjectStream extends PdfObject {
46 _data = buf.output(); 46 _data = buf.output();
47 } else if (pdfDocument.deflate != null) { 47 } else if (pdfDocument.deflate != null) {
48 _data = pdfDocument.deflate(buf.output()); 48 _data = pdfDocument.deflate(buf.output());
49 - params['/Filter'] = PdfStream.string('/FlateDecode'); 49 + params['/Filter'] = const PdfName('/FlateDecode');
50 } else if (isBinary) { 50 } else if (isBinary) {
51 // This is a Ascii85 stream 51 // This is a Ascii85 stream
52 final Ascii85Encoder e = Ascii85Encoder(); 52 final Ascii85Encoder e = Ascii85Encoder();
53 _data = e.convert(buf.output()); 53 _data = e.convert(buf.output());
54 - params['/Filter'] = PdfStream.string('/ASCII85Decode'); 54 + params['/Filter'] = const PdfName('/ASCII85Decode');
55 } else { 55 } else {
56 // This is a non-deflated stream 56 // This is a non-deflated stream
57 _data = buf.output(); 57 _data = buf.output();
@@ -59,7 +59,7 @@ class PdfObjectStream extends PdfObject { @@ -59,7 +59,7 @@ class PdfObjectStream extends PdfObject {
59 if (pdfDocument.encryption != null) { 59 if (pdfDocument.encryption != null) {
60 _data = pdfDocument.encryption.encrypt(_data, this); 60 _data = pdfDocument.encryption.encrypt(_data, this);
61 } 61 }
62 - params['/Length'] = PdfStream.intNum(_data.length); 62 + params['/Length'] = PdfNum(_data.length);
63 } 63 }
64 64
65 @override 65 @override
@@ -87,24 +87,27 @@ class PdfOutline extends PdfObject { @@ -87,24 +87,27 @@ class PdfOutline extends PdfObject {
87 87
88 // These are for kids only 88 // These are for kids only
89 if (parent != null) { 89 if (parent != null) {
90 - params['/Title'] = PdfStream.string(title);  
91 - final List<PdfStream> dests = <PdfStream>[]; 90 + params['/Title'] = PdfSecString.fromString(this, title);
  91 + final PdfArray dests = PdfArray();
92 dests.add(dest.ref()); 92 dests.add(dest.ref());
93 93
94 if (destMode == PdfOutlineMode.fitpage) { 94 if (destMode == PdfOutlineMode.fitpage) {
95 - dests.add(PdfStream.string('/Fit')); 95 + dests.add(const PdfName('/Fit'));
96 } else { 96 } else {
97 - dests.add(PdfStream.string(  
98 - '/FitR ${rect.left} ${rect.bottom} ${rect.right} ${rect.top}')); 97 + dests.add(const PdfName('/FitR'));
  98 + dests.add(PdfNum(rect.left));
  99 + dests.add(PdfNum(rect.bottom));
  100 + dests.add(PdfNum(rect.right));
  101 + dests.add(PdfNum(rect.top));
99 } 102 }
100 params['/Parent'] = parent.ref(); 103 params['/Parent'] = parent.ref();
101 - params['/Dest'] = PdfStream.array(dests); 104 + params['/Dest'] = dests;
102 105
103 // were a descendent, so by default we are closed. Find out how many 106 // were a descendent, so by default we are closed. Find out how many
104 // entries are below us 107 // entries are below us
105 final int c = descendants(); 108 final int c = descendants();
106 if (c > 0) { 109 if (c > 0) {
107 - params['/Count'] = PdfStream.intNum(-c); 110 + params['/Count'] = PdfNum(-c);
108 } 111 }
109 112
110 final int index = parent.getIndex(this); 113 final int index = parent.getIndex(this);
@@ -120,7 +123,7 @@ class PdfOutline extends PdfObject { @@ -120,7 +123,7 @@ class PdfOutline extends PdfObject {
120 } else { 123 } else {
121 // the number of outlines in this document 124 // the number of outlines in this document
122 // were the top level node, so all are open by default 125 // were the top level node, so all are open by default
123 - params['/Count'] = PdfStream.intNum(outlines.length); 126 + params['/Count'] = PdfNum(outlines.length);
124 } 127 }
125 128
126 // These only valid if we have children 129 // These only valid if we have children
@@ -113,16 +113,17 @@ class PdfOutput { @@ -113,16 +113,17 @@ class PdfOutput {
113 // now the trailer object 113 // now the trailer object
114 os.putString('trailer\n'); 114 os.putString('trailer\n');
115 115
116 - final Map<String, PdfStream> params = <String, PdfStream>{}; 116 + final PdfDict params = PdfDict();
117 117
118 // the number of entries (REQUIRED) 118 // the number of entries (REQUIRED)
119 - params['/Size'] = PdfStream.intNum(offsets.length + 1); 119 + params['/Size'] = PdfNum(offsets.length + 1);
120 120
121 // the /Root catalog indirect reference (REQUIRED) 121 // the /Root catalog indirect reference (REQUIRED)
122 if (rootID != null) { 122 if (rootID != null) {
123 params['/Root'] = rootID.ref(); 123 params['/Root'] = rootID.ref();
124 - final PdfStream id = PdfStream.binary(rootID.pdfDocument.documentID);  
125 - params['/ID'] = PdfStream.array(<PdfStream>[id, id]); 124 + final PdfString id =
  125 + PdfString(rootID.pdfDocument.documentID, PdfStringFormat.binary);
  126 + params['/ID'] = PdfArray(<PdfDataType>[id, id]);
126 } else { 127 } else {
127 throw Exception('Root object is not present in document'); 128 throw Exception('Root object is not present in document');
128 } 129 }
@@ -138,7 +139,7 @@ class PdfOutput { @@ -138,7 +139,7 @@ class PdfOutput {
138 } 139 }
139 140
140 // end the trailer object 141 // end the trailer object
141 - os.putDictionary(params); 142 + params.output(os);
142 os.putString('\nstartxref\n$xref\n%%EOF\n'); 143 os.putString('\nstartxref\n$xref\n%%EOF\n');
143 144
144 if (signatureID != null) { 145 if (signatureID != null) {
@@ -94,8 +94,8 @@ class PdfPage extends PdfObject { @@ -94,8 +94,8 @@ class PdfPage extends PdfObject {
94 params['/Parent'] = pdfDocument.pdfPageList.ref(); 94 params['/Parent'] = pdfDocument.pdfPageList.ref();
95 95
96 // the /MediaBox for the page size 96 // the /MediaBox for the page size
97 - params['/MediaBox'] = PdfStream()  
98 - ..putNumArray(<double>[0, 0, pageFormat.width, pageFormat.height]); 97 + params['/MediaBox'] =
  98 + PdfArray.fromNum(<double>[0, 0, pageFormat.width, pageFormat.height]);
99 99
100 // Rotation (if not zero) 100 // Rotation (if not zero)
101 // if(rotate!=0) { 101 // if(rotate!=0) {
@@ -109,39 +109,38 @@ class PdfPage extends PdfObject { @@ -109,39 +109,38 @@ class PdfPage extends PdfObject {
109 if (contents.length == 1) { 109 if (contents.length == 1) {
110 params['/Contents'] = contents.first.ref(); 110 params['/Contents'] = contents.first.ref();
111 } else { 111 } else {
112 - params['/Contents'] = PdfStream()..putObjectArray(contents); 112 + params['/Contents'] = PdfArray.fromObjects(contents);
113 } 113 }
114 } 114 }
115 115
116 // Now the resources 116 // Now the resources
117 /// This holds any resources for this page 117 /// This holds any resources for this page
118 - final Map<String, PdfStream> resources = <String, PdfStream>{}; 118 + final PdfDict resources = PdfDict();
119 119
120 // fonts 120 // fonts
121 if (fonts.isNotEmpty) { 121 if (fonts.isNotEmpty) {
122 - resources['/Font'] = PdfStream()..putObjectDictionary(fonts); 122 + resources['/Font'] = PdfDict.fromObjectMap(fonts);
123 } 123 }
124 124
125 // Now the XObjects 125 // Now the XObjects
126 if (xObjects.isNotEmpty) { 126 if (xObjects.isNotEmpty) {
127 - resources['/XObject'] = PdfStream()..putObjectDictionary(xObjects); 127 + resources['/XObject'] = PdfDict.fromObjectMap(xObjects);
128 } 128 }
129 129
130 if (pdfDocument.hasGraphicStates) { 130 if (pdfDocument.hasGraphicStates) {
131 // Declare Transparency Group settings 131 // Declare Transparency Group settings
132 - params['/Group'] = PdfStream()  
133 - ..putDictionary(<String, PdfStream>{  
134 - '/Type': PdfStream.string('/Group'),  
135 - '/S': PdfStream.string('/Transparency'),  
136 - '/CS': PdfStream.string('/DeviceRGB'),  
137 - '/I': PdfStream()..putBool(isolatedTransparency),  
138 - '/K': PdfStream()..putBool(knockoutTransparency), 132 + params['/Group'] = PdfDict(<String, PdfDataType>{
  133 + '/Type': const PdfName('/Group'),
  134 + '/S': const PdfName('/Transparency'),
  135 + '/CS': const PdfName('/DeviceRGB'),
  136 + '/I': PdfBool(isolatedTransparency),
  137 + '/K': PdfBool(knockoutTransparency),
139 }); 138 });
140 139
141 resources['/ExtGState'] = pdfDocument.graphicStates.ref(); 140 resources['/ExtGState'] = pdfDocument.graphicStates.ref();
142 } 141 }
143 142
144 - params['/Resources'] = PdfStream.dictionary(resources); 143 + params['/Resources'] = resources;
145 144
146 // The thumbnail 145 // The thumbnail
147 if (thumbnail != null) { 146 if (thumbnail != null) {
@@ -150,7 +149,7 @@ class PdfPage extends PdfObject { @@ -150,7 +149,7 @@ class PdfPage extends PdfObject {
150 149
151 // The /Annots object 150 // The /Annots object
152 if (annotations.isNotEmpty) { 151 if (annotations.isNotEmpty) {
153 - params['/Annots'] = PdfStream()..putObjectArray(annotations); 152 + params['/Annots'] = PdfArray.fromObjects(annotations);
154 } 153 }
155 } 154 }
156 } 155 }
@@ -32,7 +32,7 @@ class PdfPageList extends PdfObject { @@ -32,7 +32,7 @@ class PdfPageList extends PdfObject {
32 void _prepare() { 32 void _prepare() {
33 super._prepare(); 33 super._prepare();
34 34
35 - params['/Kids'] = PdfStream()..putObjectArray(pages);  
36 - params['/Count'] = PdfStream.intNum(pages.length); 35 + params['/Kids'] = PdfArray.fromObjects(pages);
  36 + params['/Count'] = PdfNum(pages.length);
37 } 37 }
38 } 38 }
@@ -42,7 +42,7 @@ class PdfSignature extends PdfObject { @@ -42,7 +42,7 @@ class PdfSignature extends PdfObject {
42 42
43 @override 43 @override
44 void _write(PdfStream os) { 44 void _write(PdfStream os) {
45 - crypto.preSign(params); 45 + crypto.preSign(this, params);
46 46
47 _offsetStart = os.offset + '$objser $objgen obj\n'.length; 47 _offsetStart = os.offset + '$objser $objgen obj\n'.length;
48 super._write(os); 48 super._write(os);
@@ -53,13 +53,13 @@ class PdfSignature extends PdfObject { @@ -53,13 +53,13 @@ class PdfSignature extends PdfObject {
53 assert(_offsetStart != null && _offsetEnd != null, 53 assert(_offsetStart != null && _offsetEnd != null,
54 'Must reserve the object space before signing the document'); 54 'Must reserve the object space before signing the document');
55 55
56 - crypto.sign(os, params, _offsetStart, _offsetEnd); 56 + crypto.sign(this, os, params, _offsetStart, _offsetEnd);
57 } 57 }
58 } 58 }
59 59
60 abstract class PdfSignatureBase { 60 abstract class PdfSignatureBase {
61 - void preSign(Map<String, PdfStream> params); 61 + void preSign(PdfObject object, PdfDict params);
62 62
63 - void sign(PdfStream os, Map<String, PdfStream> params, int offsetStart, 63 + void sign(PdfObject object, PdfStream os, PdfDict params, int offsetStart,
64 int offsetEnd); 64 int offsetEnd);
65 } 65 }
@@ -36,13 +36,8 @@ class PdfStream { @@ -36,13 +36,8 @@ class PdfStream {
36 } 36 }
37 } 37 }
38 38
39 - static PdfStream string(String s) => PdfStream()..putString(s);  
40 -  
41 - void putStringUtf16(String s) {  
42 - for (int codeUnit in s.codeUnits) {  
43 - _stream.add(codeUnit & 0xff);  
44 - _stream.add((codeUnit >> 8) & 0xff);  
45 - } 39 + void putByte(int s) {
  40 + _stream.add(s);
46 } 41 }
47 42
48 void putBytes(List<int> s) { 43 void putBytes(List<int> s) {
@@ -61,13 +56,6 @@ class PdfStream { @@ -61,13 +56,6 @@ class PdfStream {
61 }).join(' ')); 56 }).join(' '));
62 } 57 }
63 58
64 - void putIntList(List<int> d) {  
65 - putString(d.map((int v) => v.toString()).join(' '));  
66 - }  
67 -  
68 - static PdfStream num(double d) => PdfStream()..putNum(d);  
69 - static PdfStream intNum(int i) => PdfStream()..putString(i.toString());  
70 -  
71 /// Escape special characters 59 /// Escape special characters
72 /// \ddd Character code ddd (octal) 60 /// \ddd Character code ddd (octal)
73 void putTextBytes(List<int> s) { 61 void putTextBytes(List<int> s) {
@@ -111,105 +99,6 @@ class PdfStream { @@ -111,105 +99,6 @@ class PdfStream {
111 } 99 }
112 } 100 }
113 101
114 - void putText(String s) {  
115 - putBytes(latin1.encode('('));  
116 - putTextBytes(latin1.encode(s));  
117 - putBytes(latin1.encode(')'));  
118 - }  
119 -  
120 - void putLiteral(String s) {  
121 - putBytes(latin1.encode('('));  
122 - putBytes(<int>[0xfe, 0xff]);  
123 - putTextBytes(encodeUtf16be(s));  
124 - putBytes(latin1.encode(')'));  
125 - }  
126 -  
127 - void putBool(bool value) {  
128 - putString(value ? 'true' : 'false');  
129 - }  
130 -  
131 - /// Returns the ASCII/Unicode code unit corresponding to the hexadecimal digit  
132 - /// [digit].  
133 - int _codeUnitForDigit(int digit) =>  
134 - digit < 10 ? digit + 0x30 : digit + 0x61 - 10;  
135 -  
136 - void putBinary(List<int> s) {  
137 - _stream.add(0x3c);  
138 - for (int byte in s) {  
139 - _stream.add(_codeUnitForDigit((byte & 0xF0) >> 4));  
140 - _stream.add(_codeUnitForDigit(byte & 0x0F));  
141 - }  
142 - _stream.add(0x3e);  
143 - }  
144 -  
145 - static PdfStream binary(List<int> s) => PdfStream()..putBinary(s);  
146 -  
147 - void putArray(List<PdfStream> values) {  
148 - putString('[');  
149 - for (PdfStream val in values) {  
150 - putStream(val);  
151 - putString(' ');  
152 - }  
153 - putString(']');  
154 - }  
155 -  
156 - void putObjectArray(List<PdfObject> values) {  
157 - putString('[');  
158 - for (PdfObject val in values) {  
159 - putStream(val.ref());  
160 - putString(' ');  
161 - }  
162 - putString(']');  
163 - }  
164 -  
165 - void putStringArray(List<String> values) {  
166 - putString('[' + values.join(' ') + ']');  
167 - }  
168 -  
169 - void putDate(DateTime date) {  
170 - final DateTime utcDate = date.toUtc();  
171 - final String year = utcDate.year.toString().padLeft(4, '0');  
172 - final String month = utcDate.month.toString().padLeft(2, '0');  
173 - final String day = utcDate.day.toString().padLeft(2, '0');  
174 - final String hour = utcDate.hour.toString().padLeft(2, '0');  
175 - final String minute = utcDate.minute.toString().padLeft(2, '0');  
176 - final String second = utcDate.second.toString().padLeft(2, '0');  
177 - putText('D:$year$month$day$hour$minute${second}Z');  
178 - }  
179 -  
180 - void putNumArray(List<double> values) {  
181 - putString('[');  
182 - putNumList(values);  
183 - putString(']');  
184 - }  
185 -  
186 - void putIntArray(List<int> values) {  
187 - putString('[');  
188 - putIntList(values);  
189 - putString(']');  
190 - }  
191 -  
192 - static PdfStream array(List<PdfStream> values) =>  
193 - PdfStream()..putArray(values);  
194 -  
195 - void putDictionary(Map<String, PdfStream> values) {  
196 - putString('<< ');  
197 - values.forEach((String k, PdfStream v) {  
198 - putString('$k ');  
199 - putStream(v);  
200 - putString('\n');  
201 - });  
202 - putString('>>');  
203 - }  
204 -  
205 - static PdfStream dictionary(Map<String, PdfStream> values) =>  
206 - PdfStream()..putDictionary(values);  
207 -  
208 - void putObjectDictionary(Map<String, PdfObject> values) {  
209 - putDictionary(values.map((String string, PdfObject object) =>  
210 - MapEntry<String, PdfStream>(string, object.ref())));  
211 - }  
212 -  
213 int get offset => _stream.length; 102 int get offset => _stream.length;
214 103
215 List<int> output() => _stream; 104 List<int> output() => _stream;
@@ -26,7 +26,7 @@ class PdfTtfFont extends PdfFont { @@ -26,7 +26,7 @@ class PdfTtfFont extends PdfFont {
26 file = PdfObjectStream(pdfDocument, isBinary: true); 26 file = PdfObjectStream(pdfDocument, isBinary: true);
27 unicodeCMap = PdfUnicodeCmap(pdfDocument, protect); 27 unicodeCMap = PdfUnicodeCmap(pdfDocument, protect);
28 descriptor = PdfFontDescriptor(this, file); 28 descriptor = PdfFontDescriptor(this, file);
29 - widthsObject = PdfArrayObject(pdfDocument, <String>[]); 29 + widthsObject = PdfArrayObject(pdfDocument, PdfArray());
30 } 30 }
31 31
32 @override 32 @override
@@ -62,67 +62,64 @@ class PdfTtfFont extends PdfFont { @@ -62,67 +62,64 @@ class PdfTtfFont extends PdfFont {
62 return font.glyphInfoMap[g] ?? PdfFontMetrics.zero; 62 return font.glyphInfoMap[g] ?? PdfFontMetrics.zero;
63 } 63 }
64 64
65 - void _buildTrueType(Map<String, PdfStream> params) { 65 + void _buildTrueType(PdfDict params) {
66 int charMin; 66 int charMin;
67 int charMax; 67 int charMax;
68 68
69 file.buf.putBytes(font.bytes.buffer.asUint8List()); 69 file.buf.putBytes(font.bytes.buffer.asUint8List());
70 - file.params['/Length1'] = PdfStream.intNum(font.bytes.lengthInBytes); 70 + file.params['/Length1'] = PdfNum(font.bytes.lengthInBytes);
71 71
72 - params['/BaseFont'] = PdfStream.string('/' + fontName); 72 + params['/BaseFont'] = PdfName('/' + fontName);
73 params['/FontDescriptor'] = descriptor.ref(); 73 params['/FontDescriptor'] = descriptor.ref();
74 charMin = 32; 74 charMin = 32;
75 charMax = 255; 75 charMax = 255;
76 for (int i = charMin; i <= charMax; i++) { 76 for (int i = charMin; i <= charMax; i++) {
77 - widthsObject.values  
78 - .add((glyphMetrics(i).advanceWidth * 1000.0).toInt().toString()); 77 + widthsObject.array
  78 + .add(PdfNum((glyphMetrics(i).advanceWidth * 1000.0).toInt()));
79 } 79 }
80 - params['/FirstChar'] = PdfStream.intNum(charMin);  
81 - params['/LastChar'] = PdfStream.intNum(charMax); 80 + params['/FirstChar'] = PdfNum(charMin);
  81 + params['/LastChar'] = PdfNum(charMax);
82 params['/Widths'] = widthsObject.ref(); 82 params['/Widths'] = widthsObject.ref();
83 } 83 }
84 84
85 - void _buildType0(Map<String, PdfStream> params) { 85 + void _buildType0(PdfDict params) {
86 int charMin; 86 int charMin;
87 int charMax; 87 int charMax;
88 88
89 final TtfWriter ttfWriter = TtfWriter(font); 89 final TtfWriter ttfWriter = TtfWriter(font);
90 final Uint8List data = ttfWriter.withChars(unicodeCMap.cmap); 90 final Uint8List data = ttfWriter.withChars(unicodeCMap.cmap);
91 file.buf.putBytes(data); 91 file.buf.putBytes(data);
92 - file.params['/Length1'] = PdfStream.intNum(data.length); 92 + file.params['/Length1'] = PdfNum(data.length);
93 93
94 - final PdfStream descendantFont = PdfStream.dictionary(<String, PdfStream>{  
95 - '/Type': PdfStream.string('/Font'),  
96 - '/BaseFont': PdfStream.string('/' + fontName), 94 + final PdfDict descendantFont = PdfDict(<String, PdfDataType>{
  95 + '/Type': const PdfName('/Font'),
  96 + '/BaseFont': PdfName('/' + fontName),
97 '/FontFile2': file.ref(), 97 '/FontFile2': file.ref(),
98 '/FontDescriptor': descriptor.ref(), 98 '/FontDescriptor': descriptor.ref(),
99 - '/W': PdfStream.array(<PdfStream>[  
100 - PdfStream.intNum(0), 99 + '/W': PdfArray(<PdfDataType>[
  100 + const PdfNum(0),
101 widthsObject.ref(), 101 widthsObject.ref(),
102 ]), 102 ]),
103 - '/CIDToGIDMap': PdfStream.string('/Identity'),  
104 - '/DW': PdfStream.string('1000'),  
105 - '/Subtype': PdfStream.string('/CIDFontType2'),  
106 - '/CIDSystemInfo': PdfStream.dictionary(<String, PdfStream>{  
107 - '/Supplement': PdfStream.intNum(0),  
108 - '/Registry': PdfStream()..putText('Adobe'),  
109 - '/Ordering': PdfStream()..putText('Identity-H'), 103 + '/CIDToGIDMap': const PdfName('/Identity'),
  104 + '/DW': const PdfNum(1000),
  105 + '/Subtype': const PdfName('/CIDFontType2'),
  106 + '/CIDSystemInfo': PdfDict(<String, PdfDataType>{
  107 + '/Supplement': const PdfNum(0),
  108 + '/Registry': PdfSecString.fromString(this, 'Adobe'),
  109 + '/Ordering': PdfSecString.fromString(this, 'Identity-H'),
110 }) 110 })
111 }); 111 });
112 112
113 - params['/BaseFont'] = PdfStream.string('/' + fontName);  
114 - params['/Encoding'] = PdfStream.string('/Identity-H');  
115 - params['/DescendantFonts'] = PdfStream()  
116 - ..putArray(<PdfStream>[descendantFont]); 113 + params['/BaseFont'] = PdfName('/' + fontName);
  114 + params['/Encoding'] = const PdfName('/Identity-H');
  115 + params['/DescendantFonts'] = PdfArray(<PdfDataType>[descendantFont]);
117 params['/ToUnicode'] = unicodeCMap.ref(); 116 params['/ToUnicode'] = unicodeCMap.ref();
118 117
119 charMin = 0; 118 charMin = 0;
120 charMax = unicodeCMap.cmap.length - 1; 119 charMax = unicodeCMap.cmap.length - 1;
121 for (int i = charMin; i <= charMax; i++) { 120 for (int i = charMin; i <= charMax; i++) {
122 - widthsObject.values.add(  
123 - (glyphMetrics(unicodeCMap.cmap[i]).advanceWidth * 1000.0)  
124 - .toInt()  
125 - .toString()); 121 + widthsObject.array.add(PdfNum(
  122 + (glyphMetrics(unicodeCMap.cmap[i]).advanceWidth * 1000.0).toInt()));
126 } 123 }
127 } 124 }
128 125
@@ -145,7 +142,7 @@ class PdfTtfFont extends PdfFont { @@ -145,7 +142,7 @@ class PdfTtfFont extends PdfFont {
145 142
146 final Runes runes = text.runes; 143 final Runes runes = text.runes;
147 final PdfStream stream = PdfStream(); 144 final PdfStream stream = PdfStream();
148 - stream.putBytes(latin1.encode('<')); 145 + stream.putByte(0x3c);
149 for (int rune in runes) { 146 for (int rune in runes) {
150 int char = unicodeCMap.cmap.indexOf(rune); 147 int char = unicodeCMap.cmap.indexOf(rune);
151 if (char == -1) { 148 if (char == -1) {
@@ -155,7 +152,7 @@ class PdfTtfFont extends PdfFont { @@ -155,7 +152,7 @@ class PdfTtfFont extends PdfFont {
155 152
156 stream.putBytes(latin1.encode(char.toRadixString(16).padLeft(4, '0'))); 153 stream.putBytes(latin1.encode(char.toRadixString(16).padLeft(4, '0')));
157 } 154 }
158 - stream.putBytes(latin1.encode('>')); 155 + stream.putByte(0x3e);
159 return stream; 156 return stream;
160 } 157 }
161 158
@@ -44,7 +44,7 @@ class PdfType1Font extends PdfFont { @@ -44,7 +44,7 @@ class PdfType1Font extends PdfFont {
44 void _prepare() { 44 void _prepare() {
45 super._prepare(); 45 super._prepare();
46 46
47 - params['/BaseFont'] = PdfStream.string('/' + fontName); 47 + params['/BaseFont'] = PdfName('/' + fontName);
48 } 48 }
49 49
50 @override 50 @override
@@ -19,6 +19,6 @@ part of pdf; @@ -19,6 +19,6 @@ part of pdf;
19 class PdfXObject extends PdfObjectStream { 19 class PdfXObject extends PdfObjectStream {
20 PdfXObject(PdfDocument pdfDocument, String subtype, {bool isBinary = false}) 20 PdfXObject(PdfDocument pdfDocument, String subtype, {bool isBinary = false})
21 : super(pdfDocument, type: '/XObject', isBinary: isBinary) { 21 : super(pdfDocument, type: '/XObject', isBinary: isBinary) {
22 - params['/Subtype'] = PdfStream.string(subtype); 22 + params['/Subtype'] = PdfName(subtype);
23 } 23 }
24 } 24 }
@@ -20,6 +20,7 @@ import '../example/main.dart' as example; @@ -20,6 +20,7 @@ import '../example/main.dart' as example;
20 import 'annotations_test.dart' as annotations; 20 import 'annotations_test.dart' as annotations;
21 import 'colors_test.dart' as colors; 21 import 'colors_test.dart' as colors;
22 import 'complex_test.dart' as complex; 22 import 'complex_test.dart' as complex;
  23 +import 'data_types_test.dart' as data_types;
23 import 'isolate_test.dart' as isolate; 24 import 'isolate_test.dart' as isolate;
24 import 'jpeg_test.dart' as jpeg; 25 import 'jpeg_test.dart' as jpeg;
25 import 'metrics_test.dart' as metrics; 26 import 'metrics_test.dart' as metrics;
@@ -47,6 +48,7 @@ void main() { @@ -47,6 +48,7 @@ void main() {
47 annotations.main(); 48 annotations.main();
48 colors.main(); 49 colors.main();
49 complex.main(); 50 complex.main();
  51 + data_types.main();
50 example.main(); 52 example.main();
51 isolate.main(); 53 isolate.main();
52 jpeg.main(); 54 jpeg.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:typed_data';
  20 +
  21 +import 'package:pdf/pdf.dart';
  22 +import 'package:test/test.dart';
  23 +
  24 +void main() {
  25 + test('PdfDataTypes Bool ', () {
  26 + expect(const PdfBool(true).toString(), 'true');
  27 + expect(const PdfBool(false).toString(), 'false');
  28 + });
  29 +
  30 + test('PdfDataTypes Num', () {
  31 + expect(const PdfNum(0).toString(), '0');
  32 + expect(const PdfNum(.5).toString(), '0.50000');
  33 + expect(const PdfNum(50).toString(), '50');
  34 + expect(const PdfNum(50.1).toString(), '50.10000');
  35 + });
  36 +
  37 + test('PdfDataTypes String', () {
  38 + expect(PdfString.fromString('test').toString(), '(test)');
  39 + expect(PdfString.fromString('Zoé').toString(), '(Zoé)');
  40 + expect(PdfString.fromString('\r\n\t\b\f)()(\\').toString(),
  41 + r'(\r\n\t\b\f\)\(\)\(\\)');
  42 + expect(
  43 + PdfString.fromString('你好').toList(),
  44 + <int>[40, 254, 255, 79, 96, 89, 125, 41],
  45 + );
  46 + expect(
  47 + PdfString.fromDate(DateTime.fromMillisecondsSinceEpoch(1583606302000))
  48 + .toString(),
  49 + '(D:20200307183822Z)',
  50 + );
  51 + expect(
  52 + PdfString(
  53 + Uint8List.fromList(const <int>[0, 1, 2, 3, 4, 5, 6]),
  54 + PdfStringFormat.binary,
  55 + ).toString(),
  56 + '<00010203040506>',
  57 + );
  58 + });
  59 +
  60 + test('PdfDataTypes Name', () {
  61 + expect(const PdfName('/Hello').toString(), '/Hello');
  62 + });
  63 +
  64 + test('PdfDataTypes Null', () {
  65 + expect(const PdfNull().toString(), 'null');
  66 + });
  67 +
  68 + test('PdfDataTypes Indirect', () {
  69 + expect(const PdfIndirect(30, 4).toString(), '30 4 R');
  70 + });
  71 +
  72 + test('PdfDataTypes Array', () {
  73 + expect(PdfArray(<PdfDataType>[]).toString(), '[]');
  74 + expect(
  75 + PdfArray(<PdfDataType>[const PdfNum(1), const PdfNum(2)]).toString(),
  76 + '[1 2]',
  77 + );
  78 + });
  79 +
  80 + test('PdfDataTypes Dict', () {
  81 + expect(PdfDict(<String, PdfDataType>{}).toString(), '<< >>');
  82 +
  83 + expect(
  84 + PdfDict(<String, PdfDataType>{
  85 + '/Name': const PdfName('/Value'),
  86 + '/Bool': const PdfBool(true),
  87 + '/Num': const PdfNum(42),
  88 + '/String': PdfString.fromString('hello'),
  89 + '/Null': const PdfNull(),
  90 + '/Indirect': const PdfIndirect(55, 0),
  91 + '/Array': PdfArray(<PdfDataType>[]),
  92 + '/Dict': PdfDict(<String, PdfDataType>{}),
  93 + }).toString(),
  94 + '<< /Name /Value\n/Bool true\n/Num 42\n/String (hello)\n/Null null\n/Indirect 55 0 R\n/Array []\n/Dict << >>\n>>',
  95 + );
  96 + });
  97 +}