Showing
32 changed files
with
2515 additions
and
0 deletions
.gitignore
0 → 100644
1 | +# Files and directories created by pub | ||
2 | +.dart_tool/ | ||
3 | +.packages | ||
4 | +.pub/ | ||
5 | +build/ | ||
6 | +# If you're building an application, you may want to check-in your pubspec.lock | ||
7 | +pubspec.lock | ||
8 | + | ||
9 | +# Directory created by dartdoc | ||
10 | +# If you don't generate documentation locally you can remove this line. | ||
11 | +doc/api/ |
lib/pdf.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General Public | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General Public License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General Public | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +library pdf; | ||
20 | + | ||
21 | +/// http://www.mactech.com/articles/mactech/Vol.15/15.09/PDFIntro/index.html | ||
22 | +/// https://brendanzagaeski.appspot.com/0004.html | ||
23 | +/// http://blog.idrsolutions.com/?s=%22Make+your+own+PDF+file%22 | ||
24 | +/// https://brendanzagaeski.appspot.com/0005.html | ||
25 | +/// https://github.com/Setasign/FPDF | ||
26 | +/// https://github.com/rev42/tfpdf/blob/master/src/tFPDF.php | ||
27 | +/// http://gnujpdf.sourceforge.net | ||
28 | +/// http://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/pdf_reference_1-7.pdf | ||
29 | +/// https://www.w3.org/TR/SVG/paths.html#PathDataGeneralInformation | ||
30 | +/// https://www.pdf-online.com/osa/validate.aspx | ||
31 | + | ||
32 | +import 'dart:convert'; | ||
33 | +import 'dart:io'; | ||
34 | +import 'dart:typed_data'; | ||
35 | +import 'package:vector_math/vector_math_64.dart'; | ||
36 | +import 'package:image/image.dart'; | ||
37 | +import 'package:ttf_parser/ttf_parser.dart'; | ||
38 | + | ||
39 | +part 'src/ascii85.dart'; | ||
40 | +part 'src/array.dart'; | ||
41 | +part 'src/border.dart'; | ||
42 | +part 'src/catalog.dart'; | ||
43 | +part 'src/color.dart'; | ||
44 | +part 'src/document.dart'; | ||
45 | +part 'src/font.dart'; | ||
46 | +part 'src/font_descriptor.dart'; | ||
47 | +part 'src/formxobject.dart'; | ||
48 | +part 'src/info.dart'; | ||
49 | +part 'src/object.dart'; | ||
50 | +part 'src/object_stream.dart'; | ||
51 | +part 'src/outline.dart'; | ||
52 | +part 'src/output.dart'; | ||
53 | +part 'src/page.dart'; | ||
54 | +part 'src/page_format.dart'; | ||
55 | +part 'src/page_list.dart'; | ||
56 | +part 'src/point.dart'; | ||
57 | +part 'src/polygon.dart'; | ||
58 | +part 'src/annotation.dart'; | ||
59 | +part 'src/graphics.dart'; | ||
60 | +part 'src/image.dart'; | ||
61 | +part 'src/rect.dart'; | ||
62 | +part 'src/stream.dart'; | ||
63 | +part 'src/ttffont.dart'; | ||
64 | +part 'src/xobject.dart'; | ||
65 | +part 'src/xref.dart'; |
lib/src/annotation.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFAnnot extends PDFObject { | ||
22 | + /// Solid border. The border is drawn as a solid line. | ||
23 | + static const SOLID = 0; | ||
24 | + | ||
25 | + /// The border is drawn with a dashed line. | ||
26 | + static const DASHED = 1; | ||
27 | + | ||
28 | + /// The border is drawn in a beveled style (faux three-dimensional) such | ||
29 | + /// that it looks as if it is pushed out of the page (opposite of INSET) | ||
30 | + static const BEVELED = 2; | ||
31 | + | ||
32 | + /// The border is drawn in an inset style (faux three-dimensional) such | ||
33 | + /// that it looks as if it is inset into the page (opposite of BEVELED) | ||
34 | + static const INSET = 3; | ||
35 | + | ||
36 | + /// The border is drawn as a line on the bottom of the annotation rectangle | ||
37 | + static const UNDERLINED = 4; | ||
38 | + | ||
39 | + /// The subtype of the outline, ie text, note, etc | ||
40 | + final String subtype; | ||
41 | + | ||
42 | + /// The size of the annotation | ||
43 | + final double l, b, r, t; | ||
44 | + | ||
45 | + /// The text of a text annotation | ||
46 | + final String s; | ||
47 | + | ||
48 | + /// flag used to indicate that the destination should fit the screen | ||
49 | + static const FULL_PAGE = -9999.0; | ||
50 | + | ||
51 | + /// Link to the Destination page | ||
52 | + PDFObject dest; | ||
53 | + | ||
54 | + /// If fl!=FULL_PAGE then this is the region of the destination page shown. | ||
55 | + /// Otherwise they are ignored. | ||
56 | + final double fl, fb, fr, ft; | ||
57 | + | ||
58 | + /// the border for this annotation | ||
59 | + PDFBorder border; | ||
60 | + | ||
61 | + PDFAnnot(PDFPage pdfPage, | ||
62 | + {String type, this.s, this.l, this.b, this.r, this.t, this.subtype, this.dest, this.fl, this.fb, this.fr, this.ft}) | ||
63 | + : super(pdfPage.pdfDocument, type) { | ||
64 | + pdfPage.annotations.add(this); | ||
65 | + } | ||
66 | + | ||
67 | + /// This is used to create an annotation. | ||
68 | + /// @param s Subtype for this annotation | ||
69 | + /// @param l Left coordinate | ||
70 | + /// @param b Bottom coordinate | ||
71 | + /// @param r Right coordinate | ||
72 | + /// @param t Top coordinate | ||
73 | + factory PDFAnnot.annotation(PDFPage pdfPage, String s, double l, double b, double r, double t) => | ||
74 | + new PDFAnnot(pdfPage, type: "/Annot", s: s, l: l, b: b, r: r, t: t); | ||
75 | + | ||
76 | + /// Creates a text annotation | ||
77 | + /// @param l Left coordinate | ||
78 | + /// @param b Bottom coordinate | ||
79 | + /// @param r Right coordinate | ||
80 | + /// @param t Top coordinate | ||
81 | + /// @param s Text for this annotation | ||
82 | + factory PDFAnnot.text(PDFPage pdfPage, double l, double b, double r, double t, String s) => | ||
83 | + new PDFAnnot(pdfPage, type: "/Text", l: l, b: b, r: r, t: t, s: s); | ||
84 | + | ||
85 | + /// Creates a link annotation | ||
86 | + /// @param l Left coordinate | ||
87 | + /// @param b Bottom coordinate | ||
88 | + /// @param r Right coordinate | ||
89 | + /// @param t Top coordinate | ||
90 | + /// @param dest Destination for this link. The page will fit the display. | ||
91 | + /// @param fl Left coordinate | ||
92 | + /// @param fb Bottom coordinate | ||
93 | + /// @param fr Right coordinate | ||
94 | + /// @param ft Top coordinate | ||
95 | + /// <br><br>Rectangle describing what part of the page to be displayed | ||
96 | + /// (must be in User Coordinates) | ||
97 | + factory PDFAnnot.link(PDFPage pdfPage, double l, double b, double r, double t, PDFObject dest, | ||
98 | + [double fl = FULL_PAGE, double fb = FULL_PAGE, double fr = FULL_PAGE, double ft = FULL_PAGE]) => | ||
99 | + new PDFAnnot(pdfPage, type: "/Link", l: l, b: b, r: r, t: t, dest: dest, fl: fl, fb: fb, fr: fr, ft: ft); | ||
100 | + | ||
101 | + /// Sets the border for the annotation. By default, no border is defined. | ||
102 | + /// | ||
103 | + /// <p>If the style is DASHED, then this method uses PDF's default dash | ||
104 | + /// scheme {3} | ||
105 | + /// | ||
106 | + /// <p>Important: the annotation must have been added to the document before | ||
107 | + /// this is used. If the annotation was created using the methods in | ||
108 | + /// PDFPage, then the annotation is already in the document. | ||
109 | + /// | ||
110 | + /// @param style Border style SOLID, DASHED, BEVELED, INSET or UNDERLINED. | ||
111 | + /// @param width Width of the border | ||
112 | + /// @param dash Array of lengths, used for drawing the dashes. If this | ||
113 | + /// is null, then the default of {3} is used. | ||
114 | + void setBorder(double width, {int style = 0, List<double> dash}) { | ||
115 | + border = new PDFBorder(pdfDocument, width, style: style, dash: dash); | ||
116 | + } | ||
117 | + | ||
118 | + /// Output the annotation | ||
119 | + /// | ||
120 | + /// @param os OutputStream to send the object to | ||
121 | + @override | ||
122 | + void prepare() { | ||
123 | + super.prepare(); | ||
124 | + | ||
125 | + params["/Subtype"] = PDFStream.string(subtype); | ||
126 | + params["/Rect"] = PDFStream.string("[$l $b $r $t]"); | ||
127 | + | ||
128 | + // handle the border | ||
129 | + if (border == null) { | ||
130 | + params["/Border"] = PDFStream.string("[0 0 0]"); | ||
131 | + } else { | ||
132 | + params["/BS"] = border.ref(); | ||
133 | + } | ||
134 | + | ||
135 | + // Now the annotation subtypes | ||
136 | + if (subtype == "/Text") { | ||
137 | + params["/Contents"] = PDFStream.string(s); | ||
138 | + } else if (subtype == "/Link") { | ||
139 | + var dests = new List<PDFStream>(); | ||
140 | + dests.add(dest.ref()); | ||
141 | + if (fl == FULL_PAGE) | ||
142 | + dests.add(PDFStream.string("/Fit")); | ||
143 | + else { | ||
144 | + dests.add(PDFStream.string("/FitR $fl $fb $fr $ft")); | ||
145 | + } | ||
146 | + params["/Dest"] = PDFStream.array(dests); | ||
147 | + } | ||
148 | + } | ||
149 | +} |
lib/src/array.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFArrayObject extends PDFObject { | ||
22 | + final List<String> values; | ||
23 | + | ||
24 | + PDFArrayObject(PDFDocument pdfDocument, this.values) : super(pdfDocument); | ||
25 | + | ||
26 | + @override | ||
27 | + void writeContent(PDFStream os) { | ||
28 | + super.writeContent(os); | ||
29 | + | ||
30 | + os.putStringArray(values); | ||
31 | + } | ||
32 | +} |
lib/src/ascii85.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General Public | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General Public License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General Public | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class Ascii85Encoder extends Converter<Uint8List, Uint8List> { | ||
22 | + Uint8List convert(Uint8List input) { | ||
23 | + Uint8List buffer = new Uint8List(_maxEncodedLen(input.length) + 2); | ||
24 | + | ||
25 | + var b = 0; | ||
26 | + var s = 0; | ||
27 | + | ||
28 | + while (s < input.length) { | ||
29 | + buffer[b + 0] = 0; | ||
30 | + buffer[b + 1] = 0; | ||
31 | + buffer[b + 2] = 0; | ||
32 | + buffer[b + 3] = 0; | ||
33 | + buffer[b + 4] = 0; | ||
34 | + | ||
35 | + // Unpack 4 bytes into int to repack into base 85 5-byte. | ||
36 | + int v = 0; | ||
37 | + | ||
38 | + switch (input.length - s) { | ||
39 | + case 3: | ||
40 | + v |= input[s + 0] << 24; | ||
41 | + v |= input[s + 1] << 16; | ||
42 | + v |= input[s + 2] << 8; | ||
43 | + break; | ||
44 | + case 2: | ||
45 | + v |= input[s + 0] << 24; | ||
46 | + v |= input[s + 1] << 16; | ||
47 | + break; | ||
48 | + case 1: | ||
49 | + v |= input[s + 0] << 24; | ||
50 | + break; | ||
51 | + default: | ||
52 | + v |= input[s + 0] << 24; | ||
53 | + v |= input[s + 1] << 16; | ||
54 | + v |= input[s + 2] << 8; | ||
55 | + v |= input[s + 3]; | ||
56 | + } | ||
57 | + | ||
58 | + // Special case: zero (!!!!!) shortens to z. | ||
59 | + if (v == 0 && input.length - s >= 4) { | ||
60 | + buffer[b] = 122; | ||
61 | + b++; | ||
62 | + s += 4; | ||
63 | + continue; | ||
64 | + } | ||
65 | + | ||
66 | + // Otherwise, 5 base 85 digits starting at !. | ||
67 | + for (int i = 4; i >= 0; i--) { | ||
68 | + buffer[b + i] = 33 + v % 85; | ||
69 | + v ~/= 85; | ||
70 | + } | ||
71 | + | ||
72 | + // If input was short, discard the low destination bytes. | ||
73 | + var m = 5; | ||
74 | + if (input.length - s < 4) { | ||
75 | + m -= 4 - (input.length - s); | ||
76 | + break; | ||
77 | + } else { | ||
78 | + s += 4; | ||
79 | + } | ||
80 | + | ||
81 | + b += m; | ||
82 | + } | ||
83 | + | ||
84 | + buffer[b] = 0x7e; | ||
85 | + buffer[b + 1] = 0x3e; | ||
86 | + | ||
87 | + return buffer.sublist(0, b + 2); | ||
88 | + } | ||
89 | + | ||
90 | + int _maxEncodedLen(int n) => (n + 3) ~/ 4 * 5; | ||
91 | +} |
lib/src/border.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFBorder extends PDFObject { | ||
22 | + /// The style of the border | ||
23 | + final int style; | ||
24 | + | ||
25 | + /// The width of the border | ||
26 | + final double width; | ||
27 | + | ||
28 | + /// This array allows the definition of a dotted line for the border | ||
29 | + final List<double> dash; | ||
30 | + | ||
31 | + /// Creates a border using the predefined styles in PDFAnnot. | ||
32 | + /// <p>Note: Do not use PDFAnnot.DASHED with this method. | ||
33 | + /// Use the other constructor. | ||
34 | + /// | ||
35 | + /// @param width The width of the border | ||
36 | + /// @param style The style of the border | ||
37 | + /// @param dash The line pattern definition | ||
38 | + /// @see PDFAnnot | ||
39 | + PDFBorder(PDFDocument pdfDocument, this.width, {this.style = 0, this.dash}) : super(pdfDocument); | ||
40 | + | ||
41 | + /// @param os OutputStream to send the object to | ||
42 | + @override | ||
43 | + void writeContent(PDFStream os) { | ||
44 | + super.writeContent(os); | ||
45 | + | ||
46 | + var data = new List<PDFStream>(); | ||
47 | + data.add(PDFStream.string("/S")); | ||
48 | + data.add(PDFStream.string("/" + "SDBIU".substring(style, style + 1))); | ||
49 | + data.add(PDFStream.string("/W $width")); | ||
50 | + if (dash != null) { | ||
51 | + data.add(PDFStream.string("/D")); | ||
52 | + data.add(PDFStream.array(dash.map((double d) => PDFStream.num(d)))); | ||
53 | + } | ||
54 | + os.putArray(data); | ||
55 | + } | ||
56 | +} |
lib/src/catalog.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFCatalog extends PDFObject { | ||
22 | + /// The pages of the document | ||
23 | + final PDFPageList pdfPageList; | ||
24 | + | ||
25 | + /// The outlines of the document | ||
26 | + PDFOutline outlines; | ||
27 | + | ||
28 | + /// The initial page mode | ||
29 | + final PDFPageMode pageMode; | ||
30 | + | ||
31 | + /// This constructs a PDF Catalog object | ||
32 | + /// | ||
33 | + /// @param pdfPageList The PDFPageList object that's the root | ||
34 | + /// of the documents page tree | ||
35 | + /// @param pagemode How the document should appear when opened. | ||
36 | + /// Allowed values are USENONE, USEOUTLINES, USETHUMBS or FULLSCREEN. | ||
37 | + PDFCatalog(PDFDocument pdfDocument, this.pdfPageList, this.pageMode) : super(pdfDocument, "/Catalog"); | ||
38 | + | ||
39 | + /// @param os OutputStream to send the object to | ||
40 | + @override | ||
41 | + void prepare() { | ||
42 | + super.prepare(); | ||
43 | + | ||
44 | + params["/Pages"] = pdfPageList.ref(); | ||
45 | + | ||
46 | + // the Outlines object | ||
47 | + if (outlines != null && outlines.outlines.length > 0) { | ||
48 | + params["/Outlines"] = outlines.ref(); | ||
49 | + } | ||
50 | + | ||
51 | + // the /PageMode setting | ||
52 | + params["/PageMode"] = PDFStream.string(PDFDocument._PDF_PAGE_MODES[pageMode.index]); | ||
53 | + } | ||
54 | +} |
lib/src/color.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFColor { | ||
22 | + final double a; | ||
23 | + final double r; | ||
24 | + final double g; | ||
25 | + final double b; | ||
26 | + | ||
27 | + static var black = new PDFColor(0.0, 0.0, 0.0); | ||
28 | + | ||
29 | + PDFColor(this.r, this.g, this.b, [this.a = 1.0]); | ||
30 | + | ||
31 | + factory PDFColor.fromInt(int color) { | ||
32 | + return new PDFColor( | ||
33 | + (color >> 16 & 0xff) / 255.0, (color >> 8 & 0xff) / 255.0, (color & 0xff) / 255.0, (color >> 24 & 0xff) / 255.0); | ||
34 | + } | ||
35 | + | ||
36 | + factory PDFColor.fromHex(String color) { | ||
37 | + return new PDFColor( | ||
38 | + (int.parse(color.substring(0, 1), radix: 16) >> 16 & 0xff) / 255.0, | ||
39 | + (int.parse(color.substring(2, 3), radix: 16) >> 8 & 0xff) / 255.0, | ||
40 | + (int.parse(color.substring(4, 5), radix: 16) & 0xff) / 255.0, | ||
41 | + (int.parse(color.substring(6, 7), radix: 16) >> 24 & 0xff) / 255.0); | ||
42 | + } | ||
43 | + | ||
44 | + int toInt() => | ||
45 | + ((((a * 255.0).round() & 0xff) << 24) | | ||
46 | + (((r * 255.0).round() & 0xff) << 16) | | ||
47 | + (((g * 255.0).round() & 0xff) << 8) | | ||
48 | + (((b * 255.0).round() & 0xff) << 0)) & | ||
49 | + 0xFFFFFFFF; | ||
50 | +} |
lib/src/document.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General Public | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General Public License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General Public | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +enum PDFPageMode { | ||
22 | + /// This page mode indicates that the document | ||
23 | + /// should be opened just with the page visible. This is the default | ||
24 | + NONE, | ||
25 | + | ||
26 | + /// This page mode indicates that the Outlines | ||
27 | + /// should also be displayed when the document is opened. | ||
28 | + OUTLINES, | ||
29 | + | ||
30 | + /// This page mode indicates that the Thumbnails should be visible when the | ||
31 | + /// document first opens. | ||
32 | + THUMBS, | ||
33 | + | ||
34 | + /// This page mode indicates that when the document is opened, it is displayed | ||
35 | + /// in full-screen-mode. There is no menu bar, window controls nor any other | ||
36 | + /// window present. | ||
37 | + FULLSCREEN | ||
38 | +} | ||
39 | + | ||
40 | +/// <p>This class is the base of the PDF generator. A PDFDocument class is | ||
41 | +/// created for a document, and each page, object, annotation, | ||
42 | +/// etc is added to the document. | ||
43 | +/// Once complete, the document can be written to a Stream, and the PDF | ||
44 | +/// document's internal structures are kept in sync. | ||
45 | +class PDFDocument { | ||
46 | + /// This is used to allocate objects a unique serial number in the document. | ||
47 | + int _objser; | ||
48 | + | ||
49 | + /// This vector contains each indirect object within the document. | ||
50 | + final Set<PDFObject> objects = new Set<PDFObject>(); | ||
51 | + | ||
52 | + /// This is the Catalog object, which is required by each PDF Document | ||
53 | + PDFCatalog catalog; | ||
54 | + | ||
55 | + /// This is the info object. Although this is an optional object, we | ||
56 | + /// include it. | ||
57 | + PDFInfo info; | ||
58 | + | ||
59 | + /// This is the Pages object, which is required by each PDF Document | ||
60 | + PDFPageList pdfPageList; | ||
61 | + | ||
62 | + /// This is the Outline object, which is optional | ||
63 | + PDFOutline _outline; | ||
64 | + | ||
65 | + /// This holds a PDFObject describing the default border for annotations. | ||
66 | + /// It's only used when the document is being written. | ||
67 | + PDFObject defaultOutlineBorder; | ||
68 | + | ||
69 | + /// True if we will compress the stream in the pdf file | ||
70 | + final bool deflate; | ||
71 | + | ||
72 | + /// <p> | ||
73 | + /// These map the page modes just defined to the pagemodes setting of PDF. | ||
74 | + /// </p> | ||
75 | + static const _PDF_PAGE_MODES = const ["/UseNone", "/UseOutlines", "/UseThumbs", "/FullScreen"]; | ||
76 | + | ||
77 | + /// This holds the current fonts | ||
78 | + final Set<PDFFont> fonts = new Set<PDFFont>(); | ||
79 | + | ||
80 | + /// Creates a new serial number | ||
81 | + int _genSerial() => _objser++; | ||
82 | + | ||
83 | + /// <p>This creates a PDF document</p> | ||
84 | + /// @param pagemode an int, determines how the document will present itself to | ||
85 | + /// the viewer when it first opens. | ||
86 | + PDFDocument({PDFPageMode pageMode = PDFPageMode.NONE, this.deflate = true}) { | ||
87 | + _objser = 1; | ||
88 | + | ||
89 | + // Now create some standard objects | ||
90 | + pdfPageList = new PDFPageList(this); | ||
91 | + catalog = new PDFCatalog(this, pdfPageList, pageMode); | ||
92 | + info = new PDFInfo(this); | ||
93 | + } | ||
94 | + | ||
95 | + /// <p>This returns a specific page. It's used mainly when using a | ||
96 | + /// Serialized template file.</p> | ||
97 | + /// | ||
98 | + /// ?? How does a serialized template file work ??? | ||
99 | + /// | ||
100 | + /// @param page page number to return | ||
101 | + /// @return PDFPage at that position | ||
102 | + PDFPage page(int page) { | ||
103 | + return pdfPageList.getPage(page); | ||
104 | + } | ||
105 | + | ||
106 | + /// @return the root outline | ||
107 | + PDFOutline get outline { | ||
108 | + if (_outline == null) { | ||
109 | + _outline = new PDFOutline(this); | ||
110 | + catalog.outlines = _outline; | ||
111 | + } | ||
112 | + return _outline; | ||
113 | + } | ||
114 | + | ||
115 | + /// This writes the document to an OutputStream. | ||
116 | + /// | ||
117 | + /// <p><b>Note:</b> You can call this as many times as you wish, as long as | ||
118 | + /// the calls are not running at the same time. | ||
119 | + /// | ||
120 | + /// <p>Also, objects can be added or amended between these calls. | ||
121 | + /// | ||
122 | + /// <p>Also, the OutputStream is not closed, but will be flushed on | ||
123 | + /// completion. It is up to the caller to close the stream. | ||
124 | + /// | ||
125 | + /// @param os OutputStream to write the document to | ||
126 | + void write(PDFStream os) { | ||
127 | + PDFOutput pos = new PDFOutput(os); | ||
128 | + | ||
129 | + // Write each object to the PDFStream. We call via the output | ||
130 | + // as that builds the xref table | ||
131 | + for (PDFObject o in objects) { | ||
132 | + pos.write(o); | ||
133 | + } | ||
134 | + | ||
135 | + // Finally close the output, which writes the xref table. | ||
136 | + pos.close(); | ||
137 | + } | ||
138 | + | ||
139 | + Uint8List save() { | ||
140 | + PDFStream os = new PDFStream(); | ||
141 | + write(os); | ||
142 | + return os.output(); | ||
143 | + } | ||
144 | +} |
lib/src/font.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFFont extends PDFObject { | ||
22 | + /// The PDF type of the font, usually /Type1 | ||
23 | + final String subtype; | ||
24 | + | ||
25 | + /// The font's real name | ||
26 | + String baseFont; | ||
27 | + | ||
28 | + /// Constructs a PDFFont. This will attempt to map the font from a known | ||
29 | + /// Java font name to that in PDF, defaulting to Helvetica if not possible. | ||
30 | + /// | ||
31 | + /// @param name The document name, ie /F1 | ||
32 | + /// @param type The pdf type, ie /Type1 | ||
33 | + /// @param font The font name, ie Helvetica | ||
34 | + /// @param style The java.awt.Font style, ie: Font.PLAIN | ||
35 | + PDFFont(PDFDocument pdfDocument, {this.subtype = "/Type1", this.baseFont = "/Helvetica"}) : super(pdfDocument, "/Font") { | ||
36 | + pdfDocument.fonts.add(this); | ||
37 | + } | ||
38 | + | ||
39 | + String get name => "/F$objser"; | ||
40 | + | ||
41 | + /// @param os OutputStream to send the object to | ||
42 | + @override | ||
43 | + void prepare() { | ||
44 | + super.prepare(); | ||
45 | + | ||
46 | + params["/Subtype"] = PDFStream.string(subtype); | ||
47 | + params["/Name"] = PDFStream.string(name); | ||
48 | + params["/BaseFont"] = PDFStream.string(baseFont); | ||
49 | + params["/Encoding"] = PDFStream.string("/WinAnsiEncoding"); | ||
50 | + } | ||
51 | + | ||
52 | + double glyphAdvance(int charCode) { | ||
53 | + return 0.454; | ||
54 | + } | ||
55 | + | ||
56 | + PDFRect glyphBounds(int charCode) { | ||
57 | + return const PDFRect(0.0, 0.0, 0.4, 1.0); | ||
58 | + } | ||
59 | + | ||
60 | + PDFRect stringBounds(String s) { | ||
61 | + var chars = LATIN1.encode(s); | ||
62 | + | ||
63 | + if (chars.length == 0) return const PDFRect(0.0, 0.0, 0.0, 0.0); | ||
64 | + | ||
65 | + var n = 0; | ||
66 | + var c = chars[n]; | ||
67 | + var r = glyphBounds(c); | ||
68 | + var x = r.x; | ||
69 | + var y = r.y; | ||
70 | + var h = r.h; | ||
71 | + var w = n == chars.length - 1 ? r.w : glyphAdvance(c); | ||
72 | + | ||
73 | + while (++n < chars.length) { | ||
74 | + c = chars[n]; | ||
75 | + r = glyphBounds(c); | ||
76 | + if (r.y < y) y = r.y; | ||
77 | + if (r.h > h) h = r.h; | ||
78 | + w += n == chars.length - 1 ? r.w : glyphAdvance(c); | ||
79 | + } | ||
80 | + | ||
81 | + return new PDFRect(x, y, w, h); | ||
82 | + } | ||
83 | + | ||
84 | + PDFPoint stringSize(String s) { | ||
85 | + var chars = LATIN1.encode(s); | ||
86 | + | ||
87 | + var w = 0.0; | ||
88 | + var h = 0.0; | ||
89 | + | ||
90 | + for (var c in chars) { | ||
91 | + var r = glyphBounds(c); | ||
92 | + if (r.h > h) h = r.h; | ||
93 | + w += glyphAdvance(c); | ||
94 | + } | ||
95 | + | ||
96 | + return new PDFPoint(w, h); | ||
97 | + } | ||
98 | +} |
lib/src/font_descriptor.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFFontDescriptor extends PDFObject { | ||
22 | + final PDFObjectStream file; | ||
23 | + final TtfFont font; | ||
24 | + final PDFTTFFont ttfFont; | ||
25 | + | ||
26 | + PDFFontDescriptor(this.ttfFont, this.file, this.font) : super(ttfFont.pdfDocument, "/FontDescriptor"); | ||
27 | + | ||
28 | + @override | ||
29 | + void prepare() { | ||
30 | + super.prepare(); | ||
31 | + | ||
32 | + params["/FontName"] = PDFStream.string(ttfFont.baseFont); | ||
33 | + params["/FontFile2"] = file.ref(); | ||
34 | + params["/Flags"] = PDFStream.intNum(32); | ||
35 | + params["/FontBBox"] = new PDFStream()..putStringArray([font.head.xMin, font.head.yMin, font.head.xMax, font.head.yMax]); | ||
36 | + params["/Ascent"] = PDFStream.intNum(font.hhea.ascent); | ||
37 | + params["/Descent"] = PDFStream.intNum(font.hhea.descent); | ||
38 | + params["/ItalicAngle"] = PDFStream.intNum(0); | ||
39 | + params["/CapHeight"] = PDFStream.intNum(10); | ||
40 | + params["/StemV"] = PDFStream.intNum(79); | ||
41 | + } | ||
42 | +} |
lib/src/formxobject.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General Public | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General Public License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General Public | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFFormXObject extends PDFXObject { | ||
22 | + /// The fonts associated with this page | ||
23 | + final fonts = new Map<String, PDFFont>(); | ||
24 | + | ||
25 | + /// The xobjects or other images in the pdf | ||
26 | + final xobjects = new Map<String, PDFXObject>(); | ||
27 | + | ||
28 | + PDFFormXObject(PDFDocument pdfDocument) : super(pdfDocument, '/Form') { | ||
29 | + params["/FormType"] = PDFStream.string("1"); | ||
30 | + params["/BBox"] = PDFStream.string("[0 0 1000 1000]"); | ||
31 | + } | ||
32 | + | ||
33 | + /// set matrix | ||
34 | + void setMatrix(Matrix4 t) { | ||
35 | + var s = t.storage; | ||
36 | + params["/Matrix"] = PDFStream.string("[${s[0]} ${s[1]} ${s[4]} ${s[5]} ${s[12]} ${s[13]}]"); | ||
37 | + } | ||
38 | + | ||
39 | + @override | ||
40 | + void prepare() { | ||
41 | + super.prepare(); | ||
42 | + | ||
43 | + // Now the resources | ||
44 | + /// This holds any resources for this FormXObject | ||
45 | + final resources = new Map<String, PDFStream>(); | ||
46 | + | ||
47 | + // fonts | ||
48 | + if (fonts.length > 0) { | ||
49 | + resources["/Font"] = new PDFStream()..putObjectDictionary(fonts); | ||
50 | + } | ||
51 | + | ||
52 | + // Now the XObjects | ||
53 | + if (xobjects.length > 0) { | ||
54 | + resources["/XObject"] = new PDFStream()..putObjectDictionary(xobjects); | ||
55 | + } | ||
56 | + | ||
57 | + if (resources.length > 0) { | ||
58 | + params["/Resources"] = PDFStream.dictionary(resources); | ||
59 | + } | ||
60 | + } | ||
61 | +} |
lib/src/graphics.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +enum PDFLineCap { JOIN_MITER, JOIN_ROUND, JOIN_BEVEL } | ||
22 | + | ||
23 | +class PDFGraphics { | ||
24 | + /// Graphic context number | ||
25 | + var _context = 0; | ||
26 | + | ||
27 | + final PDFPage page; | ||
28 | + | ||
29 | + final PDFStream buf; | ||
30 | + | ||
31 | + PDFGraphics(this.page, this.buf); | ||
32 | + | ||
33 | + PDFFont get defaultFont { | ||
34 | + if (page.pdfDocument.fonts.length == 0) { | ||
35 | + new PDFFont(page.pdfDocument); | ||
36 | + } | ||
37 | + | ||
38 | + return page.pdfDocument.fonts.elementAt(0); | ||
39 | + } | ||
40 | + | ||
41 | + void fillPath() { | ||
42 | + buf.putString("f\n"); | ||
43 | + } | ||
44 | + | ||
45 | + void strokePath() { | ||
46 | + buf.putString("S\n"); | ||
47 | + } | ||
48 | + | ||
49 | + void closePath() { | ||
50 | + buf.putString("s\n"); | ||
51 | + } | ||
52 | + | ||
53 | + void clipPath() { | ||
54 | + buf.putString("W n\n"); | ||
55 | + } | ||
56 | + | ||
57 | + /// <p>This releases any resources used by this Graphics object. You must use | ||
58 | + /// this method once finished with it. Leaving it open will leave the PDF | ||
59 | + /// stream in an inconsistent state, and will produce errors.</p> | ||
60 | + /// <p> | ||
61 | + /// <p>If this was created with Graphics.create() then the parent instance | ||
62 | + /// can be used again. If not, then this closes the graphics operations for | ||
63 | + /// this page when used with PDFJob.</p> | ||
64 | + /// <p> | ||
65 | + /// <p>When using PDFPage, you can create another fresh Graphics instance, | ||
66 | + /// which will draw over this one.</p> | ||
67 | + void restoreContext() { | ||
68 | + if (_context > 0) { | ||
69 | + // restore graphics context | ||
70 | + buf.putString("Q\n"); | ||
71 | + _context--; | ||
72 | + } | ||
73 | + } | ||
74 | + | ||
75 | + void saveContext() { | ||
76 | + // save graphics context | ||
77 | + buf.putString("q\n"); | ||
78 | + _context++; | ||
79 | + } | ||
80 | + | ||
81 | + /// <p>Draws an image onto the page.</p> | ||
82 | + /// <p> | ||
83 | + /// <p>This method is implemented with ASCIIbase85 encoding and the | ||
84 | + /// zip stream deflater. It results in a stream that is anywhere | ||
85 | + /// from 3 to 10 times as big as the image. This obviously needs some | ||
86 | + /// improvement, but it works well for small images</p> | ||
87 | + /// | ||
88 | + /// @param img The java.awt.Image | ||
89 | + /// @param x coordinate on page | ||
90 | + /// @param y coordinate on page | ||
91 | + /// @param w Width on page | ||
92 | + /// @param h height on page | ||
93 | + /// @param bgcolor Background colour | ||
94 | + /// @return true if drawn | ||
95 | + void drawImage(PDFImage img, double x, double y, [double w, double h]) { | ||
96 | + if (w == null) w = img.width.toDouble(); | ||
97 | + if (h == null) h = img.height.toDouble() * w / img.width.toDouble(); | ||
98 | + | ||
99 | + // The image needs to be registered in the page resources | ||
100 | + page.xObjects[img.name] = img; | ||
101 | + | ||
102 | + // q w 0 0 h x y cm % the coordinate matrix | ||
103 | + buf.putString("q $w 0 0 $h $x $y cm ${img.name} Do Q\n"); | ||
104 | + } | ||
105 | + | ||
106 | + /// Draws a line between two coordinates. | ||
107 | + /// <p> | ||
108 | + /// If the first coordinate is the same as the last one drawn | ||
109 | + /// (i.e. a previous drawLine, moveto, etc) it is ignored. | ||
110 | + /// | ||
111 | + /// @param x1 coordinate | ||
112 | + /// @param y1 coordinate | ||
113 | + /// @param x2 coordinate | ||
114 | + /// @param y2 coordinate | ||
115 | + void drawLine(double x1, double y1, double x2, double y2) { | ||
116 | + moveTo(x1, y1); | ||
117 | + lineTo(x2, y2); | ||
118 | + } | ||
119 | + | ||
120 | + /// Draws a polygon, linking the first and last coordinates. | ||
121 | + /// | ||
122 | + /// @param xp Array of x coordinates | ||
123 | + /// @param yp Array of y coordinates | ||
124 | + /// @param np number of points in polygon | ||
125 | + void drawPolygon(Polygon p) { | ||
126 | + _polygon(p.points); | ||
127 | + } | ||
128 | + | ||
129 | + void drawEllipse(double x, double y, double r1, double r2) { | ||
130 | + // The best 4-spline magic number | ||
131 | + double m4 = 0.551784; | ||
132 | + | ||
133 | + // Starting point | ||
134 | + moveTo(x, y - r2); | ||
135 | + | ||
136 | + buf.putString("${x + m4 * r1} ${y - r2} ${x + r1} ${y - m4 * r2} ${x + r1} $y c\n"); | ||
137 | + buf.putString("${x + r1} ${y + m4 * r2} ${x + m4 * r1} ${y + r2} $x ${y + r2} c\n"); | ||
138 | + buf.putString("${x - m4 * r1} ${y + r2} ${x - r1} ${y + m4 * r2} ${x - r1} $y c\n"); | ||
139 | + buf.putString("${x - r1} ${y - m4 * r2} ${x - m4 * r1} ${y - r2} $x ${y - r2} c\n"); | ||
140 | + } | ||
141 | + | ||
142 | + /// We override Graphics.drawRect as it doesn't join the 4 lines. | ||
143 | + /// Also, PDF provides us with a Rectangle operator, so we will use that. | ||
144 | + /// | ||
145 | + /// @param x coordinate | ||
146 | + /// @param y coordinate | ||
147 | + /// @param w width | ||
148 | + /// @param h height | ||
149 | + void drawRect( | ||
150 | + double x, | ||
151 | + double y, | ||
152 | + double w, | ||
153 | + double h, | ||
154 | + ) { | ||
155 | + buf.putString("$x $y $w $h re\n"); | ||
156 | + } | ||
157 | + | ||
158 | + /// This draws a string. | ||
159 | + /// | ||
160 | + /// @param x coordinate | ||
161 | + /// @param y coordinate | ||
162 | + /// @oaran s String to draw | ||
163 | + void drawString(PDFFont font, size, String s, double x, double y) { | ||
164 | + if (!page.fonts.containsKey(font.name)) { | ||
165 | + page.fonts[font.name] = font; | ||
166 | + } | ||
167 | + | ||
168 | + buf.putString("BT $x $y Td ${font.name} $size Tf "); | ||
169 | + buf.putText(s); | ||
170 | + buf.putString(" Tj ET\n"); | ||
171 | + } | ||
172 | + | ||
173 | + /// Sets the color for drawing | ||
174 | + /// | ||
175 | + /// @param c Color to use | ||
176 | + void setColor(PDFColor color) { | ||
177 | + buf.putString("${color.r} ${color.g} ${color.b} rg ${color.r} ${color.g} ${color | ||
178 | + .b} RG\n"); | ||
179 | + } | ||
180 | + | ||
181 | + /// Set the transformation Matrix | ||
182 | + void setTransform(Matrix4 t) { | ||
183 | + var s = t.storage; | ||
184 | + buf.putString("${s[0]} ${s[1]} ${s[4]} ${s[5]} ${s[12]} ${s[13]} cm\n"); | ||
185 | + } | ||
186 | + | ||
187 | + /// This adds a line segment to the current path | ||
188 | + /// | ||
189 | + /// @param x coordinate | ||
190 | + /// @param y coordinate | ||
191 | + void lineTo(double x, double y) { | ||
192 | + buf.putString("$x $y l\n"); | ||
193 | + } | ||
194 | + | ||
195 | + /// This moves the current drawing point. | ||
196 | + /// | ||
197 | + /// @param x coordinate | ||
198 | + /// @param y coordinate | ||
199 | + void moveTo(double x, double y) { | ||
200 | + buf.putString("$x $y m\n"); | ||
201 | + } | ||
202 | + | ||
203 | + void drawShape(String d) { | ||
204 | + var sb = new StringBuffer(); | ||
205 | + | ||
206 | + RegExp exp = new RegExp(r"([MmZzLlHhVvCcSsQqTtAa])|(-[\.0-9]+)|([\.0-9]+)"); | ||
207 | + var matches = exp.allMatches(d); | ||
208 | + var action; | ||
209 | + for (var m in matches) { | ||
210 | + var a = m.group(1); | ||
211 | + var b = m.group(0); | ||
212 | + print("$a, $b"); | ||
213 | + if (a != null) { | ||
214 | + if (action != null) { | ||
215 | + sb.write("$action "); | ||
216 | + } | ||
217 | + action = a; | ||
218 | + } else { | ||
219 | + sb.write("$b "); | ||
220 | + } | ||
221 | + } | ||
222 | + print(sb); | ||
223 | + buf.putString(sb.toString()); | ||
224 | + } | ||
225 | + | ||
226 | + /// This is used to add a polygon to the current path. | ||
227 | + /// Used by drawPolygon(), drawPolyline() and fillPolygon() etal | ||
228 | + /// | ||
229 | + /// @param p Array of coordinates | ||
230 | + /// @see #drawPolygon | ||
231 | + /// @see #drawPolyline | ||
232 | + /// @see #fillPolygon | ||
233 | + void _polygon(List<PDFPoint> p) { | ||
234 | + // newPath() not needed here as moveto does it ;-) | ||
235 | + moveTo(p[0].w, p[0].h); | ||
236 | + | ||
237 | + for (int i = 1; i < p.length; i++) lineTo(p[i].w, p[i].h); | ||
238 | + } | ||
239 | + | ||
240 | + void setLineCap(PDFLineCap cap) { | ||
241 | + buf.putString("${cap.index} J\n"); | ||
242 | + } | ||
243 | + | ||
244 | + void setLineJoin(PDFLineCap join) { | ||
245 | + buf.putString("${join.index} j\n"); | ||
246 | + } | ||
247 | + | ||
248 | + void setLineWidth(double width) { | ||
249 | + buf.putString("$width w\n"); | ||
250 | + } | ||
251 | + | ||
252 | + void setMiterLimit(double limit) { | ||
253 | + buf.putString("$limit M\n"); | ||
254 | + } | ||
255 | +} |
lib/src/image.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFImage extends PDFXObject { | ||
22 | + final Image _img; | ||
23 | + String _name; | ||
24 | + | ||
25 | + final bool _alphaChannel; | ||
26 | + | ||
27 | + /// Creates a new <code>PDFImage</code> instance. | ||
28 | + /// | ||
29 | + /// @param img an <code>Image</code> value | ||
30 | + /// @param x an <code>int</code> value | ||
31 | + /// @param y an <code>int</code> value | ||
32 | + /// @param w an <code>int</code> value | ||
33 | + /// @param h an <code>int</code> value | ||
34 | + /// @param obs an <code>ImageObserver</code> value | ||
35 | + PDFImage(PDFDocument pdfDocument, this._img, [this._alphaChannel = false]) : super(pdfDocument, "/Image", isBinary: true) { | ||
36 | + _name = "/Image$objser"; | ||
37 | + params["/Width"] = PDFStream.string(_img.width.toString()); | ||
38 | + params["/Height"] = PDFStream.string(_img.height.toString()); | ||
39 | + params["/BitsPerComponent"] = PDFStream.intNum(8); | ||
40 | + params['/Name'] = PDFStream.string(_name); | ||
41 | + | ||
42 | + if (_alphaChannel == false && _img.numChannels == 4) { | ||
43 | + var _sMask = new PDFImage(pdfDocument, this._img, true); | ||
44 | + params["/SMask"] = PDFStream.string("${_sMask.objser} 0 R"); | ||
45 | + } | ||
46 | + | ||
47 | + if (_alphaChannel) { | ||
48 | + params["/ColorSpace"] = PDFStream.string("/DeviceGray"); | ||
49 | + } else { | ||
50 | + params["/ColorSpace"] = PDFStream.string("/DeviceRGB"); | ||
51 | + } | ||
52 | + | ||
53 | + // write the pixels to the stream | ||
54 | + // print("Processing image ${img.width}x${img.height} pixels"); | ||
55 | + | ||
56 | + int w = _img.width; | ||
57 | + int h = _img.height; | ||
58 | + int s = w * h; | ||
59 | + | ||
60 | + Uint8List out = new Uint8List(_alphaChannel ? s : s * 3); | ||
61 | + | ||
62 | + if (_alphaChannel) { | ||
63 | + for (int i = 0; i < s; i++) { | ||
64 | + final p = _img.data[i]; | ||
65 | + final int alpha = (p >> 24) & 0xff; | ||
66 | + | ||
67 | + out[i] = alpha; | ||
68 | + } | ||
69 | + } else { | ||
70 | + for (int i = 0; i < s; i++) { | ||
71 | + final p = _img.data[i]; | ||
72 | + final int blue = (p >> 16) & 0xff; | ||
73 | + final int green = (p >> 8) & 0xff; | ||
74 | + final int red = p & 0xff; | ||
75 | + | ||
76 | + out[i * 3] = red; | ||
77 | + out[i * 3 + 1] = green; | ||
78 | + out[i * 3 + 2] = blue; | ||
79 | + } | ||
80 | + } | ||
81 | + | ||
82 | + buf.putBytes(out); | ||
83 | + } | ||
84 | + | ||
85 | + /// Get the value of width. | ||
86 | + /// @return value of width. | ||
87 | + int get width => _img.width; | ||
88 | + | ||
89 | + /// Get the value of height. | ||
90 | + /// @return value of height. | ||
91 | + int get height => _img.height; | ||
92 | + | ||
93 | + /// Get the name | ||
94 | + /// | ||
95 | + /// @return a <code>String</code> value | ||
96 | + String get name => _name; | ||
97 | +} |
lib/src/info.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General Public | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General Public License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General Public | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFInfo extends PDFObject { | ||
22 | + String author; | ||
23 | + String creator; | ||
24 | + String title; | ||
25 | + String subject; | ||
26 | + String keywords; | ||
27 | + | ||
28 | + /// @param title Title of this document | ||
29 | + PDFInfo(PDFDocument pdfDocument, {this.title, this.author, this.creator, this.subject, this.keywords}) | ||
30 | + : super(pdfDocument, null) { | ||
31 | + params["/Producer"] = PDFStream.text("dpdf - David PHAM-VAN"); | ||
32 | + } | ||
33 | + | ||
34 | + /// @param os OutputStream to send the object to | ||
35 | + @override | ||
36 | + void prepare() { | ||
37 | + super.prepare(); | ||
38 | + | ||
39 | + if (author != null) params["/Author"] = PDFStream.text(author); | ||
40 | + if (creator != null) params["/Creator"] = PDFStream.text(creator); | ||
41 | + if (title != null) params["/Title"] = PDFStream.text(title); | ||
42 | + if (subject != null) params["/Subject"] = PDFStream.text(subject); | ||
43 | + if (keywords != null) params["/Keywords"] = PDFStream.text(keywords); | ||
44 | + } | ||
45 | +} |
lib/src/object.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General Public | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General Public License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General Public | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFObject { | ||
22 | + /// This is the object parameters. | ||
23 | + final params = new Map<String, PDFStream>(); | ||
24 | + | ||
25 | + /// This is the unique serial number for this object. | ||
26 | + final int objser; | ||
27 | + | ||
28 | + /// This is the generation number for this object. | ||
29 | + final int objgen = 0; | ||
30 | + | ||
31 | + /// This allows any PDF object to refer to the document being constructed. | ||
32 | + final PDFDocument pdfDocument; | ||
33 | + | ||
34 | + /// This is usually called by extensors to this class, and sets the | ||
35 | + /// PDF Object Type | ||
36 | + /// @param type the PDF Object Type | ||
37 | + PDFObject(this.pdfDocument, [String type]) : objser = pdfDocument._genSerial() { | ||
38 | + if (type != null) { | ||
39 | + params["/Type"] = PDFStream.string(type); | ||
40 | + } | ||
41 | + | ||
42 | + pdfDocument.objects.add(this); | ||
43 | + } | ||
44 | + | ||
45 | + /// <p>Writes the object to the output stream. | ||
46 | + /// This method must be overidden.</p> | ||
47 | + /// | ||
48 | + /// <p><b>Note:</b> It should not write any other objects, even if they are | ||
49 | + /// it's Kids, as they will be written by the calling routine.</p> | ||
50 | + /// | ||
51 | + /// @param os OutputStream to send the object to | ||
52 | + void write(PDFStream os) { | ||
53 | + prepare(); | ||
54 | + writeStart(os); | ||
55 | + writeContent(os); | ||
56 | + writeEnd(os); | ||
57 | + } | ||
58 | + | ||
59 | + /// Prepare the object to be written to the stream | ||
60 | + void prepare() {} | ||
61 | + | ||
62 | + /// The write method should call this before writing anything to the | ||
63 | + /// OutputStream. This will send the standard header for each object. | ||
64 | + /// | ||
65 | + /// <p>Note: There are a few rare cases where this method is not called. | ||
66 | + /// | ||
67 | + /// @param os OutputStream to write to | ||
68 | + void writeStart(PDFStream os) { | ||
69 | + os.putString("$objser $objgen obj\n"); | ||
70 | + } | ||
71 | + | ||
72 | + void writeContent(PDFStream os) { | ||
73 | + if (params.length > 0) { | ||
74 | + os.putDictionary(params); | ||
75 | + os.putString("\n"); | ||
76 | + } | ||
77 | + } | ||
78 | + | ||
79 | + /// The write method should call this after writing anything to the | ||
80 | + /// OutputStream. This will send the standard footer for each object. | ||
81 | + /// | ||
82 | + /// <p>Note: There are a few rare cases where this method is not called. | ||
83 | + /// | ||
84 | + /// @param os OutputStream to write to | ||
85 | + void writeEnd(PDFStream os) { | ||
86 | + os.putString("endobj\n"); | ||
87 | + } | ||
88 | + | ||
89 | + /// Returns the unique serial number in PDF format | ||
90 | + /// @return the serial number in PDF format | ||
91 | + PDFStream ref() => PDFStream.string("$objser $objgen R"); | ||
92 | +} |
lib/src/object_stream.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General Public | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General Public License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General Public | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFObjectStream extends PDFObject { | ||
22 | + /// This holds the stream's content. | ||
23 | + final PDFStream buf = new PDFStream(); | ||
24 | + | ||
25 | + /// defines if the stream needs to be converted to ascii85 | ||
26 | + final bool isBinary; | ||
27 | + | ||
28 | + /// Constructs a stream. The supplied type is stored in the stream's header | ||
29 | + /// and is used by other objects that extend the PDFStream class (like | ||
30 | + /// PDFImage). | ||
31 | + /// <p>By default, the stream will be compressed. | ||
32 | + /// @param type type for the stream | ||
33 | + /// @see PDFImage | ||
34 | + PDFObjectStream(PDFDocument pdfDocument, {String type, this.isBinary = false}) : super(pdfDocument, type); | ||
35 | + | ||
36 | + Uint8List _data; | ||
37 | + | ||
38 | + @override | ||
39 | + void prepare() { | ||
40 | + super.prepare(); | ||
41 | + | ||
42 | + if (pdfDocument.deflate) { | ||
43 | + var z = new ZLibCodec(level: ZLibOption.MAX_LEVEL); | ||
44 | + _data = z.encode(buf.output()); | ||
45 | + params["/Filter"] = PDFStream.string("/FlateDecode"); | ||
46 | + } else if (isBinary) { | ||
47 | + // This is a Ascii85 stream | ||
48 | + var e = new Ascii85Encoder(); | ||
49 | + _data = e.convert(buf.output()); | ||
50 | + params["/Filter"] = PDFStream.string("/ASCII85Decode"); | ||
51 | + } else { | ||
52 | + // This is a non-deflated stream | ||
53 | + _data = buf.output(); | ||
54 | + } | ||
55 | + params["/Length"] = PDFStream.intNum(_data.length); | ||
56 | + } | ||
57 | + | ||
58 | + @override | ||
59 | + void writeContent(PDFStream os) { | ||
60 | + super.writeContent(os); | ||
61 | + | ||
62 | + os.putString("stream\n"); | ||
63 | + os.putBytes(_data); | ||
64 | + os.putString("\nendstream\n"); | ||
65 | + } | ||
66 | +} |
lib/src/outline.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General Public | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General Public License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General Public | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFOutline extends PDFObject { | ||
22 | + /// This holds any outlines below us | ||
23 | + List<PDFOutline> outlines = []; | ||
24 | + | ||
25 | + /// For subentries, this points to it's parent outline | ||
26 | + PDFOutline parent; | ||
27 | + | ||
28 | + /// This is this outlines Title | ||
29 | + final String title; | ||
30 | + | ||
31 | + /// The destination page | ||
32 | + PDFPage dest; | ||
33 | + | ||
34 | + /// The region on the destination page | ||
35 | + final double l, b, r, t; | ||
36 | + | ||
37 | + /// When jumping to the destination, display the whole page | ||
38 | + static const bool FITPAGE = false; | ||
39 | + | ||
40 | + /// When jumping to the destination, display the specified region | ||
41 | + static const bool FITRECT = true; | ||
42 | + | ||
43 | + /// How the destination is handled | ||
44 | + bool destMode = FITPAGE; | ||
45 | + | ||
46 | + /// Constructs a PDF Outline object. When selected, the specified region | ||
47 | + /// is displayed. | ||
48 | + /// | ||
49 | + /// @param title Title of the outline | ||
50 | + /// @param dest The destination page | ||
51 | + /// @param l left coordinate | ||
52 | + /// @param b bottom coordinate | ||
53 | + /// @param r right coordinate | ||
54 | + /// @param t top coordinate | ||
55 | + PDFOutline(PDFDocument pdfDocument, {this.title, this.dest, this.l, this.b, this.r, this.t}) | ||
56 | + : super(pdfDocument, "/Outlines"); | ||
57 | + | ||
58 | + /// This method creates an outline, and attaches it to this one. | ||
59 | + /// When the outline is selected, the supplied region is displayed. | ||
60 | + /// | ||
61 | + /// <p>Note: the coordiates are in Java space. They are converted to User | ||
62 | + /// space. | ||
63 | + /// | ||
64 | + /// <p>This allows you to have an outline for say a Chapter, | ||
65 | + /// then under the chapter, one for each section. You are not really | ||
66 | + /// limited on how deep you go, but it's best not to go below say 6 levels, | ||
67 | + /// for the reader's sake. | ||
68 | + /// | ||
69 | + /// @param title Title of the outline | ||
70 | + /// @param dest The destination page | ||
71 | + /// @param x coordinate of region in Java space | ||
72 | + /// @param y coordinate of region in Java space | ||
73 | + /// @param w width of region in Java space | ||
74 | + /// @param h height of region in Java space | ||
75 | + /// @return PDFOutline object created, for creating sub-outlines | ||
76 | + PDFOutline add({String title, PDFPage dest, double x, y, w, h}) { | ||
77 | + var xy1 = dest.cxy(x, y + h); | ||
78 | + var xy2 = dest.cxy(x + w, y); | ||
79 | + PDFOutline outline = new PDFOutline(pdfDocument, title: title, dest: dest, l: xy1.w, b: xy1.h, r: xy2.w, t: xy2.h); | ||
80 | + // Tell the outline of ourselves | ||
81 | + outline.parent = this; | ||
82 | + return outline; | ||
83 | + } | ||
84 | + | ||
85 | + /// @param os OutputStream to send the object to | ||
86 | + @override | ||
87 | + void prepare() { | ||
88 | + super.prepare(); | ||
89 | + | ||
90 | + // These are for kids only | ||
91 | + if (parent != null) { | ||
92 | + params["/Title"] = PDFStream.string(title); | ||
93 | + var dests = new List<PDFStream>(); | ||
94 | + dests.add(dest.ref()); | ||
95 | + | ||
96 | + if (destMode == FITPAGE) { | ||
97 | + dests.add(PDFStream.string("/Fit")); | ||
98 | + } else { | ||
99 | + dests.add(PDFStream.string("/FitR $l $b $r $t")); | ||
100 | + } | ||
101 | + params["/Parent"] = parent.ref(); | ||
102 | + params["/Dest"] = PDFStream.array(dests); | ||
103 | + | ||
104 | + // were a decendent, so by default we are closed. Find out how many | ||
105 | + // entries are below us | ||
106 | + int c = descendants(); | ||
107 | + if (c > 0) { | ||
108 | + params["/Count"] = PDFStream.intNum(-c); | ||
109 | + } | ||
110 | + | ||
111 | + int index = parent.getIndex(this); | ||
112 | + if (index > 0) { | ||
113 | + // Now if were not the first, then we have a /Prev node | ||
114 | + params["/Prev"] = parent.getNode(index - 1).ref(); | ||
115 | + } | ||
116 | + | ||
117 | + if (index < parent.getLast()) { | ||
118 | + // We have a /Next node | ||
119 | + params["/Next"] = parent.getNode(index + 1).ref(); | ||
120 | + } | ||
121 | + } else { | ||
122 | + // the number of outlines in this document | ||
123 | + // were the top level node, so all are open by default | ||
124 | + params["/Count"] = PDFStream.intNum(outlines.length); | ||
125 | + } | ||
126 | + | ||
127 | + // These only valid if we have children | ||
128 | + if (outlines.length > 0) { | ||
129 | + // the number of the first outline in list | ||
130 | + params["/First"] = outlines[0].ref(); | ||
131 | + | ||
132 | + // the number of the last outline in list | ||
133 | + params["/Last"] = outlines[outlines.length - 1].ref(); | ||
134 | + } | ||
135 | + } | ||
136 | + | ||
137 | + /// This is called by children to find their position in this outlines | ||
138 | + /// tree. | ||
139 | + /// | ||
140 | + /// @param outline PDFOutline to search for | ||
141 | + /// @return index within Vector | ||
142 | + int getIndex(PDFOutline outline) => outlines.indexOf(outline); | ||
143 | + | ||
144 | + /// Returns the last index in this outline | ||
145 | + /// @return last index in outline | ||
146 | + int getLast() => outlines.length - 1; | ||
147 | + | ||
148 | + /// Returns the outline at a specified position. | ||
149 | + /// @param i index | ||
150 | + /// @return the node at index i | ||
151 | + PDFOutline getNode(int i) => outlines[i]; | ||
152 | + | ||
153 | + /// Returns the total number of descendants below this one. | ||
154 | + /// @return the number of descendants below this one | ||
155 | + int descendants() { | ||
156 | + int c = outlines.length; // initially the number of kids | ||
157 | + | ||
158 | + // now call each one for their descendants | ||
159 | + for (PDFOutline o in outlines) { | ||
160 | + c += o.descendants(); | ||
161 | + } | ||
162 | + | ||
163 | + return c; | ||
164 | + } | ||
165 | +} |
lib/src/output.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFOutput { | ||
22 | + /// This is the actual PDFStream used to write to. | ||
23 | + final PDFStream os; | ||
24 | + | ||
25 | + /// This vector contains offsets of each object | ||
26 | + List<PDFXref> offsets = []; | ||
27 | + | ||
28 | + /// This is used to track the /Root object (catalog) | ||
29 | + PDFObject rootID; | ||
30 | + | ||
31 | + /// This is used to track the /Info object (info) | ||
32 | + PDFObject infoID; | ||
33 | + | ||
34 | + /// This creates a PDF PDFStream | ||
35 | + /// | ||
36 | + /// @param os The output stream to write the PDF file to. | ||
37 | + PDFOutput(this.os) { | ||
38 | + os.putString("%PDF-1.4\n"); | ||
39 | + os.putBytes([0x25, 0xC2, 0xA5, 0xC2, 0xB1, 0xC3, 0xAB, 0x0A]); | ||
40 | + } | ||
41 | + | ||
42 | + /// This method writes a PDFObject to the stream. | ||
43 | + /// | ||
44 | + /// @param ob PDFObject Obeject to write | ||
45 | + void write(PDFObject ob) { | ||
46 | + // Check the object to see if it's one that is needed in the trailer | ||
47 | + // object | ||
48 | + if (ob is PDFCatalog) rootID = ob; | ||
49 | + if (ob is PDFInfo) infoID = ob; | ||
50 | + | ||
51 | + offsets.add(new PDFXref(ob.objser, os.offset)); | ||
52 | + ob.write(os); | ||
53 | + } | ||
54 | + | ||
55 | + /// This closes the Stream, writing the xref table | ||
56 | + void close() { | ||
57 | + // we use baos to speed things up a little. | ||
58 | + // Also, offset is preserved, and marks the begining of this block. | ||
59 | + // This is required by PDF at the end of the PDF file. | ||
60 | + | ||
61 | + int xref = os.offset; | ||
62 | + | ||
63 | + os.putString("xref\n"); | ||
64 | + | ||
65 | + // Now a single subsection for object 0 | ||
66 | + //os.write("0 1\n0000000000 65535 f \n"); | ||
67 | + | ||
68 | + // Now scan through the offsets list. The should be in sequence, | ||
69 | + // but just in case: | ||
70 | + int firstid = 0; // First id in block | ||
71 | + int lastid = -1; // The last id used | ||
72 | + var block = []; // xrefs in this block | ||
73 | + | ||
74 | + // We need block 0 to exist | ||
75 | + block.add(new PDFXref(0, 0, generation: 65535)); | ||
76 | + | ||
77 | + for (PDFXref x in offsets) { | ||
78 | + if (firstid == -1) firstid = x.id; | ||
79 | + | ||
80 | + // check to see if block is in range (-1 means empty) | ||
81 | + if (lastid > -1 && x.id != (lastid + 1)) { | ||
82 | + // no, so write this block, and reset | ||
83 | + writeblock(firstid, block); | ||
84 | + block = []; | ||
85 | + firstid = -1; | ||
86 | + } | ||
87 | + | ||
88 | + // now add to block | ||
89 | + block.add(x); | ||
90 | + lastid = x.id; | ||
91 | + } | ||
92 | + | ||
93 | + // now write the last block | ||
94 | + if (firstid > -1) writeblock(firstid, block); | ||
95 | + | ||
96 | + // now the trailer object | ||
97 | + os.putString("trailer\n<<\n"); | ||
98 | + | ||
99 | + // the number of entries (REQUIRED) | ||
100 | + os.putString("/Size "); | ||
101 | + os.putString((offsets.length + 1).toString()); | ||
102 | + os.putString("\n"); | ||
103 | + | ||
104 | + // the /Root catalog indirect reference (REQUIRED) | ||
105 | + if (rootID != null) { | ||
106 | + os.putString("/Root "); | ||
107 | + os.putStream(rootID.ref()); | ||
108 | + os.putString("\n"); | ||
109 | + } else | ||
110 | + throw new Exception("Root object is not present in document"); | ||
111 | + | ||
112 | + // the /Info reference (OPTIONAL) | ||
113 | + if (infoID != null) { | ||
114 | + os.putString("/Info "); | ||
115 | + os.putStream(infoID.ref()); | ||
116 | + os.putString("\n"); | ||
117 | + } | ||
118 | + | ||
119 | + // end the trailer object | ||
120 | + os.putString(">>\nstartxref\n$xref\n%%EOF\n"); | ||
121 | + } | ||
122 | + | ||
123 | + /// Writes a block of references to the PDF file | ||
124 | + /// @param firstid ID of the first reference in this block | ||
125 | + /// @param block Vector containing the references in this block | ||
126 | + void writeblock(int firstid, var block) { | ||
127 | + os.putString("$firstid ${block.length}\n"); | ||
128 | + //os.write("\n0000000000 65535 f\n"); | ||
129 | + | ||
130 | + for (PDFXref x in block) { | ||
131 | + os.putString(x.ref()); | ||
132 | + os.putString("\n"); | ||
133 | + } | ||
134 | + } | ||
135 | +} |
lib/src/page.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General Public | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General Public License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General Public | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFPage extends PDFObject { | ||
22 | + /// This is this page format, ie the size of the page, margins, and rotation | ||
23 | + PDFPageFormat pageFormat; | ||
24 | + | ||
25 | + /// This holds the contents of the page. | ||
26 | + List<PDFObjectStream> contents = []; | ||
27 | + | ||
28 | + /// Object ID that contains a thumbnail sketch of the page. | ||
29 | + /// -1 indicates no thumbnail. | ||
30 | + PDFObject thumbnail; | ||
31 | + | ||
32 | + /// This holds any Annotations contained within this page. | ||
33 | + List<PDFAnnot> annotations = []; | ||
34 | + | ||
35 | + /// The fonts associated with this page | ||
36 | + final fonts = new Map<String, PDFFont>(); | ||
37 | + | ||
38 | + /// The xobjects or other images in the pdf | ||
39 | + final xObjects = new Map<String, PDFXObject>(); | ||
40 | + | ||
41 | + /// This constructs a Page object, which will hold any contents for this | ||
42 | + /// page. | ||
43 | + /// | ||
44 | + /// <p>Once created, it is added to the document via the PDF.add() method. | ||
45 | + /// | ||
46 | + /// @param orientation Orientation: 0, 90 or 270 | ||
47 | + /// @see PageFormat#PORTRAIT | ||
48 | + /// @see PageFormat#LANDSCAPE | ||
49 | + /// @see PageFormat#REVERSE_LANDSCAPE | ||
50 | + /// @param pageFormat PageFormat describing the page size | ||
51 | + PDFPage(PDFDocument pdfDocument, {int orientation, this.pageFormat}) : super(pdfDocument, "/Page") { | ||
52 | + pdfDocument.pdfPageList.pages.add(this); | ||
53 | + if (pageFormat == null) pageFormat = new PDFPageFormat(); | ||
54 | + setOrientation(orientation); | ||
55 | + } | ||
56 | + | ||
57 | + /// This returns a PDFGraphics object, which can then be used to render | ||
58 | + /// on to this page. If a previous PDFGraphics object was used, this object | ||
59 | + /// is appended to the page, and will be drawn over the top of any previous | ||
60 | + /// objects. | ||
61 | + /// | ||
62 | + /// @return a new PDFGraphics object to be used to draw this page. | ||
63 | + PDFGraphics getGraphics() { | ||
64 | + var stream = new PDFObjectStream(pdfDocument); | ||
65 | + var g = new PDFGraphics(this, stream.buf); | ||
66 | + contents.add(stream); | ||
67 | + return g; | ||
68 | + } | ||
69 | + | ||
70 | + /// Returns the page's PageFormat. | ||
71 | + /// @return PageFormat describing the page size in device units (72dpi) | ||
72 | + PDFPageFormat getPageFormat() { | ||
73 | + return pageFormat; | ||
74 | + } | ||
75 | + | ||
76 | + /// Gets the dimensions of the page. | ||
77 | + /// @return a Dimension object containing the width and height of the page. | ||
78 | + PDFPoint getDimension() => new PDFPoint(pageFormat.getWidth(), pageFormat.getHeight()); | ||
79 | + | ||
80 | + /// Sets the page's orientation. | ||
81 | + /// | ||
82 | + /// <p>Normally, this should be done when the page is created, to avoid | ||
83 | + /// problems. | ||
84 | + /// | ||
85 | + /// @param orientation a PageFormat orientation constant: | ||
86 | + /// PageFormat.PORTRAIT, PageFormat.LANDSACPE or PageFromat.REVERSE_LANDSACPE | ||
87 | + void setOrientation(int orientation) { | ||
88 | + pageFormat.setOrientation(orientation); | ||
89 | + } | ||
90 | + | ||
91 | + /// Returns the pages orientation: | ||
92 | + /// PageFormat.PORTRAIT, PageFormat.LANDSACPE or PageFromat.REVERSE_LANDSACPE | ||
93 | + /// | ||
94 | + /// @see java.awt.print.PageFormat | ||
95 | + /// @return current orientation of the page | ||
96 | + int getOrientation() => pageFormat.getOrientation(); | ||
97 | + | ||
98 | + /// This adds an Annotation to the page. | ||
99 | + /// | ||
100 | + /// <p>As with other objects, the annotation must be added to the pdf | ||
101 | + /// document using PDF.add() before adding to the page. | ||
102 | + /// | ||
103 | + /// @param ob Annotation to add. | ||
104 | + void addAnnotation(PDFObject ob) { | ||
105 | + annotations.add(ob); | ||
106 | + } | ||
107 | + | ||
108 | + /// This method adds a text note to the document. | ||
109 | + /// @param note Text of the note | ||
110 | + /// @param x Coordinate of note | ||
111 | + /// @param y Coordinate of note | ||
112 | + /// @param w Width of the note | ||
113 | + /// @param h Height of the note | ||
114 | + /// @return Returns the annotation, so other settings can be changed. | ||
115 | + PDFAnnot addNote(String note, double x, y, w, h) { | ||
116 | + var xy1 = cxy(x, y + h); | ||
117 | + var xy2 = cxy(x + w, y); | ||
118 | + PDFAnnot ob = new PDFAnnot.text(this, xy1.w, xy1.h, xy2.w, xy2.h, note); | ||
119 | + return ob; | ||
120 | + } | ||
121 | + | ||
122 | + /// Adds a hyperlink to the document. | ||
123 | + /// @param x Coordinate of active area | ||
124 | + /// @param y Coordinate of active area | ||
125 | + /// @param w Width of the active area | ||
126 | + /// @param h Height of the active area | ||
127 | + /// @param dest Page that will be displayed when the link is activated. When | ||
128 | + /// displayed, the zoom factor will be changed to fit the display. | ||
129 | + /// @param vx Coordinate of view area | ||
130 | + /// @param vy Coordinate of view area | ||
131 | + /// @param vw Width of the view area | ||
132 | + /// @param vh Height of the view area | ||
133 | + /// @return Returns the annotation, so other settings can be changed. | ||
134 | + PDFAnnot addLink(double x, y, w, h, PDFObject dest, | ||
135 | + [double vx = PDFAnnot.FULL_PAGE, vy = PDFAnnot.FULL_PAGE, vw = PDFAnnot.FULL_PAGE, vh = PDFAnnot.FULL_PAGE]) { | ||
136 | + var xy1 = cxy(x, y + h); | ||
137 | + var xy2 = cxy(x + w, y); | ||
138 | + var xy3 = cxy(vx, vy + vh); | ||
139 | + var xy4 = cxy(vx + vw, vy); | ||
140 | + PDFAnnot ob = new PDFAnnot.link(this, xy1.w, xy1.h, xy2.w, xy2.h, dest, xy3.w, xy3.h, xy4.w, xy4.h); | ||
141 | + return ob; | ||
142 | + } | ||
143 | + | ||
144 | + /// This method attaches an outline to the current page being generated. When | ||
145 | + /// selected, the outline displays the top of the page. | ||
146 | + /// @param title Outline title to attach | ||
147 | + /// @param x Left coordinate of region | ||
148 | + /// @param y Bottom coordinate of region | ||
149 | + /// @param w Width of region | ||
150 | + /// @param h Height coordinate of region | ||
151 | + /// @return PDFOutline object created, for addSubOutline if required. | ||
152 | + PDFOutline addOutline(String title, {double x, double y, double w, double h}) { | ||
153 | + PDFPoint xy1 = cxy(x, y + h); | ||
154 | + PDFPoint xy2 = cxy(x + w, y); | ||
155 | + PDFOutline outline = new PDFOutline(pdfDocument, title: title, dest: this, l: xy1.w, b: xy1.h, r: xy2.w, t: xy2.h); | ||
156 | + pdfDocument.outline.outlines.add(outline); | ||
157 | + return outline; | ||
158 | + } | ||
159 | + | ||
160 | + /// @param os OutputStream to send the object to | ||
161 | + @override | ||
162 | + void prepare() { | ||
163 | + super.prepare(); | ||
164 | + | ||
165 | + // the /Parent pages object | ||
166 | + params["/Parent"] = pdfDocument.pdfPageList.ref(); | ||
167 | + | ||
168 | + // the /MediaBox for the page size | ||
169 | + params["/MediaBox"] = new PDFStream()..putStringArray([0, 0, pageFormat.getWidth(), pageFormat.getHeight()]); | ||
170 | + | ||
171 | + // Rotation (if not zero) | ||
172 | +// if(rotate!=0) { | ||
173 | +// os.write("/Rotate "); | ||
174 | +// os.write(Integer.toString(rotate).getBytes()); | ||
175 | +// os.write("\n"); | ||
176 | +// } | ||
177 | + | ||
178 | + // the /Contents pages object | ||
179 | + if (contents.length > 0) { | ||
180 | + if (contents.length == 1) { | ||
181 | + params["/Contents"] = contents[0].ref(); | ||
182 | + } else { | ||
183 | + params["/Contents"] = new PDFStream()..putObjectArray(contents); | ||
184 | + } | ||
185 | + } | ||
186 | + | ||
187 | + // Now the resources | ||
188 | + /// This holds any resources for this page | ||
189 | + final resources = new Map<String, PDFStream>(); | ||
190 | + | ||
191 | + // fonts | ||
192 | + if (fonts.length > 0) { | ||
193 | + resources["/Font"] = new PDFStream()..putObjectDictionary(fonts); | ||
194 | + } | ||
195 | + | ||
196 | + // Now the XObjects | ||
197 | + if (xObjects.length > 0) { | ||
198 | + resources["/XObject"] = new PDFStream()..putObjectDictionary(xObjects); | ||
199 | + } | ||
200 | + | ||
201 | + params["/Resources"] = PDFStream.dictionary(resources); | ||
202 | + | ||
203 | + // The thumbnail | ||
204 | + if (thumbnail != null) { | ||
205 | + params["/Thumb"] = thumbnail.ref(); | ||
206 | + } | ||
207 | + | ||
208 | + // The /Annots object | ||
209 | + if (annotations.length > 0) { | ||
210 | + params["/Annots"] = new PDFStream()..putObjectArray(annotations); | ||
211 | + } | ||
212 | + } | ||
213 | + | ||
214 | + /// This utility method converts the y coordinate from Java to User space | ||
215 | + /// within the page. | ||
216 | + /// @param x Coordinate in Java space | ||
217 | + /// @param y Coordinate in Java space | ||
218 | + /// @return y Coordinate in User space | ||
219 | + double cy(double x, double y) => cxy(x, y).h; | ||
220 | + | ||
221 | + /// This utility method converts the y coordinate from Java to User space | ||
222 | + /// within the page. | ||
223 | + /// @param x Coordinate in Java space | ||
224 | + /// @param y Coordinate in Java space | ||
225 | + /// @return x Coordinate in User space | ||
226 | + double cx(double x, double y) => cxy(x, y).w; | ||
227 | + | ||
228 | + /// This utility method converts the Java coordinates to User space | ||
229 | + /// within the page. | ||
230 | + /// @param x Coordinate in Java space | ||
231 | + /// @param y Coordinate in Java space | ||
232 | + /// @return array containing the x & y Coordinate in User space | ||
233 | + PDFPoint cxy(double x, double y) => new PDFPoint(x, pageFormat.getHeight() - y); | ||
234 | +} |
lib/src/page_format.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General Public | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General Public License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General Public | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFPageFormat { | ||
22 | + static const A4 = const [595.28, 841.89]; | ||
23 | + static const A3 = const [841.89, 1190.55]; | ||
24 | + static const A5 = const [420.94, 595.28]; | ||
25 | + static const LETTER = const [612.0, 792.0]; | ||
26 | + static const LEGAL = const [612.0, 1008.0]; | ||
27 | + | ||
28 | + static const PT = 1.0; | ||
29 | + static const IN = 72.0; | ||
30 | + static const CM = IN / 2.54; | ||
31 | + static const MM = IN / 25.4; | ||
32 | + | ||
33 | + double width; | ||
34 | + double height; | ||
35 | + double imageableX = 10.0; | ||
36 | + double imageableY = 10.0; | ||
37 | + double imageableWidth = 300.0; | ||
38 | + double imageableHeight = 300.0; | ||
39 | + int orientation = 0; | ||
40 | + | ||
41 | + PDFPageFormat([List<double> format]) { | ||
42 | + if (format == null || format.length != 2) format = A4; | ||
43 | + | ||
44 | + width = format[0]; | ||
45 | + height = format[1]; | ||
46 | + } | ||
47 | + | ||
48 | + double getWidth() => width; | ||
49 | + double getHeight() => height; | ||
50 | + | ||
51 | + void setOrientation(int orientation) { | ||
52 | + this.orientation = orientation; | ||
53 | + } | ||
54 | + | ||
55 | + int getOrientation() => orientation; | ||
56 | +} |
lib/src/page_list.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General Public | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General Public License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General Public | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFPageList extends PDFObject { | ||
22 | + /// This holds the pages | ||
23 | + final List<PDFPage> pages = []; | ||
24 | + | ||
25 | + /// This constructs a PDF Pages object. | ||
26 | + PDFPageList(PDFDocument pdfDocument) : super(pdfDocument, "/Pages"); | ||
27 | + | ||
28 | + /// This returns a specific page. Used by the PDF class. | ||
29 | + /// @param page page number to return | ||
30 | + /// @return PDFPage at that position | ||
31 | + PDFPage getPage(int page) => pages[page]; | ||
32 | + | ||
33 | + /// @param os OutputStream to send the object to | ||
34 | + @override | ||
35 | + void prepare() { | ||
36 | + super.prepare(); | ||
37 | + | ||
38 | + params["/Kids"] = new PDFStream()..putObjectArray(pages); | ||
39 | + params["/Count"] = PDFStream.intNum(pages.length); | ||
40 | + } | ||
41 | +} |
lib/src/point.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General Public | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General Public License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General Public | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFPoint { | ||
22 | + final double w, h; | ||
23 | + const PDFPoint(this.w, this.h); | ||
24 | + | ||
25 | + @override | ||
26 | + String toString() => "PDFPoint($w, $h)"; | ||
27 | +} |
lib/src/polygon.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class Polygon { | ||
22 | + List<PDFPoint> points; | ||
23 | + | ||
24 | + Polygon(this.points); | ||
25 | + | ||
26 | + PDFRect getBounds() { | ||
27 | + // TODO: Implement properly | ||
28 | + return const PDFRect(0.0, 0.0, 0.0, 0.0); | ||
29 | + } | ||
30 | +} |
lib/src/rect.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General Public | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General Public License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General Public | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFRect { | ||
22 | + final double x, y, w, h; | ||
23 | + const PDFRect(this.x, this.y, this.w, this.h); | ||
24 | + | ||
25 | + @override | ||
26 | + String toString() => "PDFRect($x, $y, $w, $h)"; | ||
27 | +} |
lib/src/stream.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General Public | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General Public License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General Public | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFStream { | ||
22 | + final _stream = new BytesBuilder(copy: false); | ||
23 | + | ||
24 | + void putStream(PDFStream s) { | ||
25 | + _stream.add(s._stream.toBytes()); | ||
26 | + } | ||
27 | + | ||
28 | + void putString(String s) { | ||
29 | + for (int codeUnit in s.codeUnits) { | ||
30 | + if (codeUnit <= 0x7f) { | ||
31 | + _stream.addByte(codeUnit); | ||
32 | + } else { | ||
33 | + _stream.addByte(0x20); | ||
34 | + } | ||
35 | + } | ||
36 | + } | ||
37 | + | ||
38 | + static PDFStream string(String s) => new PDFStream()..putString(s); | ||
39 | + | ||
40 | + void putStringUtf16(String s) { | ||
41 | + for (int codeUnit in s.codeUnits) { | ||
42 | + _stream.addByte(codeUnit & 0xff); | ||
43 | + _stream.addByte((codeUnit >> 8) & 0xff); | ||
44 | + } | ||
45 | + } | ||
46 | + | ||
47 | + void putBytes(List<int> s) { | ||
48 | + _stream.add(s); | ||
49 | + } | ||
50 | + | ||
51 | + void putNum(double d) { | ||
52 | + putString(d.toString()); | ||
53 | + } | ||
54 | + | ||
55 | + static PDFStream num(double d) => new PDFStream()..putNum(d); | ||
56 | + static PDFStream intNum(int i) => new PDFStream()..putString(i.toString()); | ||
57 | + | ||
58 | + void putText(String s) { | ||
59 | + // Escape special characters | ||
60 | + // \n Line feed (LF) | ||
61 | + // \r Carriage return (CR) | ||
62 | + // \t Horizontal tab (HT) | ||
63 | + // \b Backspace (BS) | ||
64 | + // \f Form feed (FF) | ||
65 | + // \( Left parenthesis | ||
66 | + // \) Right parenthesis | ||
67 | + // \\ Backslash | ||
68 | + // \ddd Character code ddd (octal) | ||
69 | + s = s | ||
70 | + .replaceAll('\\', '\\\\') | ||
71 | + .replaceAll('(', '\\(') | ||
72 | + .replaceAll(')', '\\)') | ||
73 | + .replaceAll('\n', '\\n') | ||
74 | + .replaceAll('\t', '\\t') | ||
75 | + .replaceAll('\b', '\\b') | ||
76 | + .replaceAll('\f', '\\f') | ||
77 | + .replaceAll('\r', '\\r'); | ||
78 | + | ||
79 | + putBytes(LATIN1.encode('(' + s + ')')); | ||
80 | + } | ||
81 | + | ||
82 | + static PDFStream text(String s) => new PDFStream()..putText(s); | ||
83 | + | ||
84 | + void putBool(bool value) { | ||
85 | + putString(value ? "true" : "false"); | ||
86 | + } | ||
87 | + | ||
88 | + void putArray(List<PDFStream> values) { | ||
89 | + putString("["); | ||
90 | + for (var val in values) { | ||
91 | + putStream(val); | ||
92 | + putString(" "); | ||
93 | + } | ||
94 | + putString("]"); | ||
95 | + } | ||
96 | + | ||
97 | + void putObjectArray(List<PDFObject> values) { | ||
98 | + putString("["); | ||
99 | + for (var val in values) { | ||
100 | + putStream(val.ref()); | ||
101 | + putString(" "); | ||
102 | + } | ||
103 | + putString("]"); | ||
104 | + } | ||
105 | + | ||
106 | + void putStringArray(List<dynamic> values) { | ||
107 | + putString("[" + values.join(" ") + "]"); | ||
108 | + } | ||
109 | + | ||
110 | + static PDFStream array(List<PDFStream> values) => new PDFStream()..putArray(values); | ||
111 | + | ||
112 | + void putDictionary(Map<String, PDFStream> values) { | ||
113 | + putString("<< "); | ||
114 | + values.forEach((k, v) { | ||
115 | + putString("$k "); | ||
116 | + putStream(v); | ||
117 | + putString("\n"); | ||
118 | + }); | ||
119 | + putString(">>"); | ||
120 | + } | ||
121 | + | ||
122 | + static PDFStream dictionary(Map<String, PDFStream> values) => new PDFStream()..putDictionary(values); | ||
123 | + | ||
124 | + void putObjectDictionary(Map<String, PDFObject> values) { | ||
125 | + putString("<< "); | ||
126 | + values.forEach((k, v) { | ||
127 | + putString("$k "); | ||
128 | + putStream(v.ref()); | ||
129 | + putString(" "); | ||
130 | + }); | ||
131 | + putString(">>"); | ||
132 | + } | ||
133 | + | ||
134 | + int get offset => _stream.length; | ||
135 | + | ||
136 | + Uint8List output() => _stream.toBytes(); | ||
137 | +} |
lib/src/ttffont.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFTTFFont extends PDFFont { | ||
22 | + PDFObject unicodeCMap; | ||
23 | + PDFFontDescriptor descriptor; | ||
24 | + PDFArrayObject widthsObject; | ||
25 | + final widths = new List<String>(); | ||
26 | + TtfFont _font; | ||
27 | + int _charMin; | ||
28 | + int _charMax; | ||
29 | + | ||
30 | + /// Constructs a PDFTTFFont | ||
31 | + PDFTTFFont(PDFDocument pdfDocument, Uint8List bytes) : super(pdfDocument, subtype: "/TrueType") { | ||
32 | + _font = new TtfParser().parse(bytes); | ||
33 | + baseFont = "/" + _font.name.fontName.replaceAll(" ", ""); | ||
34 | + | ||
35 | + PDFObjectStream file = new PDFObjectStream(pdfDocument, isBinary: true); | ||
36 | + file.buf.putBytes(bytes); | ||
37 | + file.params["/Length1"] = PDFStream.intNum(bytes.length); | ||
38 | + | ||
39 | + _charMin = 32; | ||
40 | + _charMax = 255; | ||
41 | + | ||
42 | + for (var i = _charMin; i <= _charMax; i++) { | ||
43 | + widths.add((glyphAdvance(i) * 1000.0).toString()); | ||
44 | + } | ||
45 | + | ||
46 | + unicodeCMap = new PDFObject(pdfDocument); | ||
47 | + descriptor = new PDFFontDescriptor(this, file, _font); | ||
48 | + widthsObject = new PDFArrayObject(pdfDocument, widths); | ||
49 | + } | ||
50 | + | ||
51 | + @override | ||
52 | + double glyphAdvance(int charCode) { | ||
53 | + var g = _font.cmap.charToGlyphIndexMap[charCode]; | ||
54 | + | ||
55 | + if (g == null) { | ||
56 | + return super.glyphAdvance(charCode); | ||
57 | + } | ||
58 | + | ||
59 | + return _font.hmtx.metrics[g].advanceWidth / _font.head.unitsPerEm; | ||
60 | + } | ||
61 | + | ||
62 | + @override | ||
63 | + PDFRect glyphBounds(int charCode) { | ||
64 | + var g = _font.cmap.charToGlyphIndexMap[charCode]; | ||
65 | + | ||
66 | + if (g == null) { | ||
67 | + return super.glyphBounds(charCode); | ||
68 | + } | ||
69 | + | ||
70 | + var info = _font.glyf.glyphInfoMap[g]; | ||
71 | + return new PDFRect( | ||
72 | + info.xMin.toDouble() / _font.head.unitsPerEm, | ||
73 | + info.yMin.toDouble() / _font.head.unitsPerEm, | ||
74 | + (info.xMax - info.xMin).toDouble() / _font.head.unitsPerEm, | ||
75 | + (info.yMax - info.yMin).toDouble() / _font.head.unitsPerEm); | ||
76 | + } | ||
77 | + | ||
78 | + @override | ||
79 | + void prepare() { | ||
80 | + super.prepare(); | ||
81 | + | ||
82 | + params["/FirstChar"] = PDFStream.intNum(_charMin); | ||
83 | + params["/LastChar"] = PDFStream.intNum(_charMax); | ||
84 | + params["/Widths"] = widthsObject.ref(); | ||
85 | + params["/FontDescriptor"] = descriptor.ref(); | ||
86 | +// params["/Encoding"] = PDFStream.string("/Identity-H"); | ||
87 | +// params["/ToUnicode"] = unicodeCMap.ref(); | ||
88 | + } | ||
89 | +} |
lib/src/xobject.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General Public | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General Public License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General Public | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFXObject extends PDFObjectStream { | ||
22 | + PDFXObject(PDFDocument pdfDocument, String subtype, {bool isBinary = false}) | ||
23 | + : super(pdfDocument, type: '/XObject', isBinary: isBinary) { | ||
24 | + params['/Subtype'] = PDFStream.string(subtype); | ||
25 | + } | ||
26 | +} |
lib/src/xref.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * This library is free software; you can redistribute it and/or | ||
5 | + * modify it under the terms of the GNU Lesser General | ||
6 | + * License as published by the Free Software Foundation; either | ||
7 | + * version 2.1 of the License, or (at your option) any later version. | ||
8 | + * | ||
9 | + * This library is distributed in the hope that it will be useful, | ||
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | + * Lesser General License for more details. | ||
13 | + * | ||
14 | + * You should have received a copy of the GNU Lesser General | ||
15 | + * License along with this library; if not, write to the Free Software | ||
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | + */ | ||
18 | + | ||
19 | +part of pdf; | ||
20 | + | ||
21 | +class PDFXref { | ||
22 | + /// The id of a PDF Object | ||
23 | + int id; | ||
24 | + | ||
25 | + /// The offset within the PDF file | ||
26 | + int offset; | ||
27 | + | ||
28 | + /// The generation of the object, usually 0 | ||
29 | + int generation = 0; | ||
30 | + | ||
31 | + /// Creates a crossreference for a PDF Object | ||
32 | + /// @param id The object's ID | ||
33 | + /// @param offset The object's position in the file | ||
34 | + /// @param generation The object's generation, usually 0 | ||
35 | + PDFXref(this.id, this.offset, {this.generation = 0}); | ||
36 | + | ||
37 | + /// @return The xref in the format of the xref section in the PDF file | ||
38 | + String ref() { | ||
39 | + String rs = offset.toString().padLeft(10, '0') + " " + generation.toString().padLeft(5, '0'); | ||
40 | + | ||
41 | + if (generation == 65535) return rs + " f "; | ||
42 | + return rs + " n "; | ||
43 | + } | ||
44 | +} |
pubspec.yaml
0 → 100644
1 | +name: pdf | ||
2 | +author: David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | +description: A pdf producer for Dart | ||
4 | +homepage: https://github.com/davbfr/dart_pdf | ||
5 | +version: 1.0.0 | ||
6 | + | ||
7 | +dependencies: | ||
8 | + image: "^1.1.29" | ||
9 | + ttf_parser: "^1.0.0" | ||
10 | + vector_math: | ||
11 | + | ||
12 | +dev_dependencies: | ||
13 | + test: "^0.12.32+1" |
test/pdf1_test.dart
0 → 100644
1 | +import 'dart:io'; | ||
2 | + | ||
3 | +import 'package:pdf/pdf.dart'; | ||
4 | +import "package:test/test.dart"; | ||
5 | + | ||
6 | +void main() { | ||
7 | + test('Pdf1', () { | ||
8 | + var pdf = new PDFDocument(deflate: false); | ||
9 | + var page = new PDFPage(pdf, pageFormat: new PDFPageFormat(PDFPageFormat.A4)); | ||
10 | + | ||
11 | + var g = page.getGraphics(); | ||
12 | + g.drawLine(30.0, 30.0, 200.0, 200.0); | ||
13 | + g.strokePath(); | ||
14 | + | ||
15 | + var file = new File('file1.pdf'); | ||
16 | + file.writeAsBytesSync(pdf.save()); | ||
17 | + }); | ||
18 | +} |
test/pdf_test.dart
0 → 100644
1 | +import 'dart:io'; | ||
2 | +import 'dart:math'; | ||
3 | + | ||
4 | +import 'package:image/image.dart'; | ||
5 | +import 'package:pdf/pdf.dart'; | ||
6 | +import 'package:test/test.dart'; | ||
7 | +import 'package:vector_math/vector_math_64.dart'; | ||
8 | + | ||
9 | + | ||
10 | +void main() { | ||
11 | + test('Pdf', () { | ||
12 | + Image img = new Image(10, 10); | ||
13 | + img.fill(0x12345678); | ||
14 | + | ||
15 | + var pdf = new PDFDocument(deflate: false); | ||
16 | + var i = pdf.info; | ||
17 | + i.author = "David PHAM-VAN"; | ||
18 | + i.creator = i.author; | ||
19 | + i.title = "My Title"; | ||
20 | + i.subject = "My Subject"; | ||
21 | + var page = new PDFPage(pdf, pageFormat: new PDFPageFormat([500.0, 300.0])); | ||
22 | + | ||
23 | + var g = page.getGraphics(); | ||
24 | + g.saveContext(); | ||
25 | + var tm = new Matrix4.identity(); | ||
26 | + tm.translate(100.0, 700.0); | ||
27 | + g.setTransform(tm); | ||
28 | +// g.drawShape("M37 0H9C6.24 0 4 2.24 4 5v38c0 2.76 2.24 5 5 5h28c2.76 0 5-2.24 5-5V5c0-2.76-2.24-5-5-5zM23 46c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm15-8H8V6h30v32z"); | ||
29 | + g.restoreContext(); | ||
30 | + var font1 = new PDFFont(pdf); | ||
31 | + | ||
32 | + var font2 = new PDFTTFFont(pdf, new File("../assets/Nunito-Regular.ttf").readAsBytesSync()); | ||
33 | + var s = "Hello World!"; | ||
34 | + var r = font2.stringBounds(s); | ||
35 | + const FS = 20.0; | ||
36 | + g.setColor(new PDFColor(0.0, 1.0, 1.0)); | ||
37 | + g.drawRect(50.0 + r.x * FS, 30.0 + r.y * FS, r.w * FS, r.h * FS); | ||
38 | + g.fillPath(); | ||
39 | + g.setColor(new PDFColor(0.3, 0.3, 0.3)); | ||
40 | + g.drawString(font2, FS, s, 50.0, 30.0); | ||
41 | + | ||
42 | + g.setColor(new PDFColor(1.0, 0.0, 0.0)); | ||
43 | + g.drawString(font2, 20.0, "Hé (Olà)", 50.0, 10.0); | ||
44 | + g.drawLine(30.0, 30.0, 200.0, 200.0); | ||
45 | + g.strokePath(); | ||
46 | + g.setColor(new PDFColor(1.0, 0.0, 0.0)); | ||
47 | + g.drawRect(300.0, 150.0, 50.0, 50.0); | ||
48 | + g.fillPath(); | ||
49 | + g.setColor(new PDFColor(0.0, 0.5, 0.0)); | ||
50 | + var image = new PDFImage(pdf, img); | ||
51 | + for (var i = 10.0; i < 90.0; i += 5.0) { | ||
52 | + g.saveContext(); | ||
53 | + var tm = new Matrix4.identity(); | ||
54 | + tm.rotateZ(i * PI / 360.0); | ||
55 | + tm.translate(300.0, -100.0); | ||
56 | + g.setTransform(tm); | ||
57 | + g.drawString(font1, 12.0, "Hello $i", 20.0, 100.0); | ||
58 | + g.drawImage(image, 100.0, 100.0, 80.0); | ||
59 | + g.restoreContext(); | ||
60 | + } | ||
61 | + | ||
62 | + var file = new File('file.pdf'); | ||
63 | + file.writeAsBytesSync(pdf.save()); | ||
64 | + }); | ||
65 | +} |
-
Please register or login to post a comment