David PHAM-VAN

First Import

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