David PHAM-VAN

Fix dart lint warnings

Too many changes to show.

To preserve performance only 44 of 44+ files are displayed.

# 1.3.3
* Fix dart lint warnings
# 1.3.2
* Update Readme
... ...
... ... @@ -120,7 +120,7 @@ linter:
# - parameter_assignments # we do this commonly
- prefer_adjacent_string_concatenation
- prefer_asserts_in_initializer_lists
- prefer_collection_literals
# - prefer_collection_literals # temporary until all platforms support set literals
- prefer_conditional_assignment
- prefer_const_constructors
- prefer_const_constructors_in_immutables
... ... @@ -151,7 +151,7 @@ linter:
- sort_constructors_first
- sort_pub_dependencies
- sort_unnamed_constructors_first
- super_goes_last
# - super_goes_last # no longer needed w/ Dart 2
- test_types_in_equals
- throw_in_finally
# - type_annotate_public_apis # subset of always_specify_types
... ...
... ... @@ -4,22 +4,24 @@ import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart';
void main() {
final pdf = Document(deflate: zlib.encode);
final Document pdf = Document(deflate: zlib.encode);
pdf.addPage(MultiPage(
pageFormat:
PdfPageFormat.letter.copyWith(marginBottom: 1.5 * PdfPageFormat.cm),
crossAxisAlignment: CrossAxisAlignment.start,
header: (Context context) {
if (context.pageNumber == 1) return null;
if (context.pageNumber == 1) {
return null;
}
return Container(
alignment: Alignment.centerRight,
margin: EdgeInsets.only(bottom: 3.0 * PdfPageFormat.mm),
padding: EdgeInsets.only(bottom: 3.0 * PdfPageFormat.mm),
decoration: BoxDecoration(
margin: const EdgeInsets.only(bottom: 3.0 * PdfPageFormat.mm),
padding: const EdgeInsets.only(bottom: 3.0 * PdfPageFormat.mm),
decoration: const BoxDecoration(
border:
BoxBorder(bottom: true, width: 0.5, color: PdfColor.grey)),
child: Text("Portable Document Format",
child: Text('Portable Document Format',
style: Theme.of(context)
.defaultTextStyle
.copyWith(color: PdfColor.grey)));
... ... @@ -27,8 +29,8 @@ void main() {
footer: (Context context) {
return Container(
alignment: Alignment.centerRight,
margin: EdgeInsets.only(top: 1.0 * PdfPageFormat.cm),
child: Text("Page ${context.pageNumber}",
margin: const EdgeInsets.only(top: 1.0 * PdfPageFormat.cm),
child: Text('Page ${context.pageNumber}',
style: Theme.of(context)
.defaultTextStyle
.copyWith(color: PdfColor.grey)));
... ... @@ -39,111 +41,111 @@ void main() {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text("Portable Document Format", textScaleFactor: 2.0),
Text('Portable Document Format', textScaleFactor: 2.0),
PdfLogo()
])),
Paragraph(
text:
"The Portable Document Format (PDF) is a file format developed by Adobe in the 1990s to present documents, including text formatting and images, in a manner independent of application software, hardware, and operating systems. Based on the PostScript language, each PDF file encapsulates a complete description of a fixed-layout flat document, including the text, fonts, vector graphics, raster images and other information needed to display it. PDF was standardized as an open format, ISO 32000, in 2008, and no longer requires any royalties for its implementation."),
'The Portable Document Format (PDF) is a file format developed by Adobe in the 1990s to present documents, including text formatting and images, in a manner independent of application software, hardware, and operating systems. Based on the PostScript language, each PDF file encapsulates a complete description of a fixed-layout flat document, including the text, fonts, vector graphics, raster images and other information needed to display it. PDF was standardized as an open format, ISO 32000, in 2008, and no longer requires any royalties for its implementation.'),
Paragraph(
text:
"Today, PDF files may contain a variety of content besides flat text and graphics including logical structuring elements, interactive elements such as annotations and form-fields, layers, rich media (including video content) and three dimensional objects using U3D or PRC, and various other data formats.[citation needed] The PDF specification also provides for encryption and digital signatures, file attachments and metadata to enable workflows requiring these features."),
Header(level: 1, text: "History and standardization"),
'Today, PDF files may contain a variety of content besides flat text and graphics including logical structuring elements, interactive elements such as annotations and form-fields, layers, rich media (including video content) and three dimensional objects using U3D or PRC, and various other data formats.[citation needed] The PDF specification also provides for encryption and digital signatures, file attachments and metadata to enable workflows requiring these features.'),
Header(level: 1, text: 'History and standardization'),
Paragraph(
text:
"Adobe Systems made the PDF specification available free of charge in 1993. In the early years PDF was popular mainly in desktop publishing workflows, and competed with a variety of formats such as DjVu, Envoy, Common Ground Digital Paper, Farallon Replica and even Adobe's own PostScript format."),
Paragraph(
text:
"PDF was a proprietary format controlled by Adobe until it was released as an open standard on July 1, 2008, and published by the International Organization for Standardization as ISO 32000-1:2008, at which time control of the specification passed to an ISO Committee of volunteer industry experts. In 2008, Adobe published a Public Patent License to ISO 32000-1 granting royalty-free rights for all patents owned by Adobe that are necessary to make, use, sell, and distribute PDF compliant implementations."),
'PDF was a proprietary format controlled by Adobe until it was released as an open standard on July 1, 2008, and published by the International Organization for Standardization as ISO 32000-1:2008, at which time control of the specification passed to an ISO Committee of volunteer industry experts. In 2008, Adobe published a Public Patent License to ISO 32000-1 granting royalty-free rights for all patents owned by Adobe that are necessary to make, use, sell, and distribute PDF compliant implementations.'),
Paragraph(
text:
"PDF 1.7, the sixth edition of the PDF specification that became ISO 32000-1, includes some proprietary technologies defined only by Adobe, such as Adobe XML Forms Architecture (XFA) and JavaScript extension for Acrobat, which are referenced by ISO 32000-1 as normative and indispensable for the full implementation of the ISO 32000-1 specification. These proprietary technologies are not standardized and their specification is published only on Adobe's website. Many of them are also not supported by popular third-party implementations of PDF."),
Paragraph(
text:
"On July 28, 2017, ISO 32000-2:2017 (PDF 2.0) was published. ISO 32000-2 does not include any proprietary technologies as normative references."),
Header(level: 1, text: "Technical foundations"),
Paragraph(text: "The PDF combines three technologies:"),
'On July 28, 2017, ISO 32000-2:2017 (PDF 2.0) was published. ISO 32000-2 does not include any proprietary technologies as normative references.'),
Header(level: 1, text: 'Technical foundations'),
Paragraph(text: 'The PDF combines three technologies:'),
Bullet(
text:
"A subset of the PostScript page description programming language, for generating the layout and graphics."),
'A subset of the PostScript page description programming language, for generating the layout and graphics.'),
Bullet(
text:
"A font-embedding/replacement system to allow fonts to travel with the documents."),
'A font-embedding/replacement system to allow fonts to travel with the documents.'),
Bullet(
text:
"A structured storage system to bundle these elements and any associated content into a single file, with data compression where appropriate."),
Header(level: 2, text: "PostScript"),
'A structured storage system to bundle these elements and any associated content into a single file, with data compression where appropriate.'),
Header(level: 2, text: 'PostScript'),
Paragraph(
text:
"PostScript is a page description language run in an interpreter to generate an image, a process requiring many resources. It can handle graphics and standard features of programming languages such as if and loop commands. PDF is largely based on PostScript but simplified to remove flow control features like these, while graphics commands such as lineto remain."),
'PostScript is a page description language run in an interpreter to generate an image, a process requiring many resources. It can handle graphics and standard features of programming languages such as if and loop commands. PDF is largely based on PostScript but simplified to remove flow control features like these, while graphics commands such as lineto remain.'),
Paragraph(
text:
"Often, the PostScript-like PDF code is generated from a source PostScript file. The graphics commands that are output by the PostScript code are collected and tokenized. Any files, graphics, or fonts to which the document refers also are collected. Then, everything is compressed to a single file. Therefore, the entire PostScript world (fonts, layout, measurements) remains intact."),
'Often, the PostScript-like PDF code is generated from a source PostScript file. The graphics commands that are output by the PostScript code are collected and tokenized. Any files, graphics, or fonts to which the document refers also are collected. Then, everything is compressed to a single file. Therefore, the entire PostScript world (fonts, layout, measurements) remains intact.'),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Paragraph(
text:
"As a document format, PDF has several advantages over PostScript:"),
'As a document format, PDF has several advantages over PostScript:'),
Bullet(
text:
"PDF contains tokenized and interpreted results of the PostScript source code, for direct correspondence between changes to items in the PDF page description and changes to the resulting page appearance."),
'PDF contains tokenized and interpreted results of the PostScript source code, for direct correspondence between changes to items in the PDF page description and changes to the resulting page appearance.'),
Bullet(
text:
"PDF (from version 1.4) supports graphic transparency; PostScript does not."),
'PDF (from version 1.4) supports graphic transparency; PostScript does not.'),
Bullet(
text:
"PostScript is an interpreted programming language with an implicit global state, so instructions accompanying the description of one page can affect the appearance of any following page. Therefore, all preceding pages in a PostScript document must be processed to determine the correct appearance of a given page, whereas each page in a PDF document is unaffected by the others. As a result, PDF viewers allow the user to quickly jump to the final pages of a long document, whereas a PostScript viewer needs to process all pages sequentially before being able to display the destination page (unless the optional PostScript Document Structuring Conventions have been carefully complied with)."),
'PostScript is an interpreted programming language with an implicit global state, so instructions accompanying the description of one page can affect the appearance of any following page. Therefore, all preceding pages in a PostScript document must be processed to determine the correct appearance of a given page, whereas each page in a PDF document is unaffected by the others. As a result, PDF viewers allow the user to quickly jump to the final pages of a long document, whereas a PostScript viewer needs to process all pages sequentially before being able to display the destination page (unless the optional PostScript Document Structuring Conventions have been carefully complied with).'),
]),
Header(level: 1, text: "Content"),
Header(level: 1, text: 'Content'),
Paragraph(
text:
"A PDF file is often a combination of vector graphics, text, and bitmap graphics. The basic types of content in a PDF are:"),
'A PDF file is often a combination of vector graphics, text, and bitmap graphics. The basic types of content in a PDF are:'),
Bullet(
text:
"Text stored as content streams (i.e., not encoded in plain text)"),
'Text stored as content streams (i.e., not encoded in plain text)'),
Bullet(
text:
"Vector graphics for illustrations and designs that consist of shapes and lines"),
'Vector graphics for illustrations and designs that consist of shapes and lines'),
Bullet(
text:
"Raster graphics for photographs and other types of image"),
Bullet(text: "Multimedia objects in the document"),
'Raster graphics for photographs and other types of image'),
Bullet(text: 'Multimedia objects in the document'),
Paragraph(
text:
"In later PDF revisions, a PDF document can also support links (inside document or web page), forms, JavaScript (initially available as plugin for Acrobat 3.0), or any other types of embedded contents that can be handled using plug-ins."),
'In later PDF revisions, a PDF document can also support links (inside document or web page), forms, JavaScript (initially available as plugin for Acrobat 3.0), or any other types of embedded contents that can be handled using plug-ins.'),
Paragraph(
text:
"PDF 1.6 supports interactive 3D documents embedded in the PDF - 3D drawings can be embedded using U3D or PRC and various other data formats."),
'PDF 1.6 supports interactive 3D documents embedded in the PDF - 3D drawings can be embedded using U3D or PRC and various other data formats.'),
Paragraph(
text:
"Two PDF files that look similar on a computer screen may be of very different sizes. For example, a high resolution raster image takes more space than a low resolution one. Typically higher resolution is needed for printing documents than for displaying them on screen. Other things that may increase the size of a file is embedding full fonts, especially for Asiatic scripts, and storing text as graphics. "),
Header(level: 1, text: "File formats and Adobe Acrobat versions"),
'Two PDF files that look similar on a computer screen may be of very different sizes. For example, a high resolution raster image takes more space than a low resolution one. Typically higher resolution is needed for printing documents than for displaying them on screen. Other things that may increase the size of a file is embedding full fonts, especially for Asiatic scripts, and storing text as graphics. '),
Header(level: 1, text: 'File formats and Adobe Acrobat versions'),
Paragraph(
text:
"The PDF file format has changed several times, and continues to evolve, along with the release of new versions of Adobe Acrobat. There have been nine versions of PDF and the corresponding version of the software:"),
Table.fromTextArray(context: context, data: [
["Date", "PDF Version", "Acrobat Version"],
["1993", "PDF 1.0", "Acrobat 1"],
["1994", "PDF 1.1", "Acrobat 2"],
["1996", "PDF 1.2", "Acrobat 3"],
["1999", "PDF 1.3", "Acrobat 4"],
["2001", "PDF 1.4", "Acrobat 5"],
["2003", "PDF 1.5", "Acrobat 6"],
["2005", "PDF 1.6", "Acrobat 7"],
["2006", "PDF 1.7", "Acrobat 8"],
["2008", "PDF 1.7", "Acrobat 9"],
["2009", "PDF 1.7", "Acrobat 9.1"],
["2010", "PDF 1.7", "Acrobat X"],
["2012", "PDF 1.7", "Acrobat XI"],
["2017", "PDF 2.0", "Acrobat DC"],
'The PDF file format has changed several times, and continues to evolve, along with the release of new versions of Adobe Acrobat. There have been nine versions of PDF and the corresponding version of the software:'),
Table.fromTextArray(context: context, data: const <List<String>>[
<String>['Date', 'PDF Version', 'Acrobat Version'],
<String>['1993', 'PDF 1.0', 'Acrobat 1'],
<String>['1994', 'PDF 1.1', 'Acrobat 2'],
<String>['1996', 'PDF 1.2', 'Acrobat 3'],
<String>['1999', 'PDF 1.3', 'Acrobat 4'],
<String>['2001', 'PDF 1.4', 'Acrobat 5'],
<String>['2003', 'PDF 1.5', 'Acrobat 6'],
<String>['2005', 'PDF 1.6', 'Acrobat 7'],
<String>['2006', 'PDF 1.7', 'Acrobat 8'],
<String>['2008', 'PDF 1.7', 'Acrobat 9'],
<String>['2009', 'PDF 1.7', 'Acrobat 9.1'],
<String>['2010', 'PDF 1.7', 'Acrobat X'],
<String>['2012', 'PDF 1.7', 'Acrobat XI'],
<String>['2017', 'PDF 2.0', 'Acrobat DC'],
]),
Padding(padding: EdgeInsets.all(10)),
Padding(padding: const EdgeInsets.all(10)),
Paragraph(
text:
"Text is available under the Creative Commons Attribution Share Alike License.")
'Text is available under the Creative Commons Attribution Share Alike License.')
]));
var file = File('example.pdf');
final File file = File('example.pdf');
file.writeAsBytesSync(pdf.document.save());
}
... ...
... ... @@ -17,8 +17,8 @@
library pdf;
import 'dart:convert';
import 'dart:typed_data';
import 'dart:math' as math;
import 'dart:typed_data';
import 'package:meta/meta.dart';
import 'package:utf/utf.dart';
... ...
... ... @@ -17,25 +17,6 @@
part of pdf;
class PdfAnnot extends PdfObject {
/// The subtype of the outline, ie text, note, etc
final String subtype;
/// The size of the annotation
final PdfRect srcRect;
/// The text of a text annotation
final String content;
/// Link to the Destination page
final PdfObject dest;
/// If destRect is null then this is the region of the destination page shown.
/// Otherwise they are ignored.
final PdfRect destRect;
/// the border for this annotation
final PdfBorder border;
PdfAnnot._create(PdfPage pdfPage,
{String type,
this.content,
... ... @@ -56,7 +37,7 @@ class PdfAnnot extends PdfObject {
@required String content,
PdfBorder border}) =>
PdfAnnot._create(pdfPage,
subtype: "/Text", srcRect: rect, content: content, border: border);
subtype: '/Text', srcRect: rect, content: content, border: border);
/// Creates a link annotation
/// @param srcRect coordinates
... ... @@ -69,12 +50,31 @@ class PdfAnnot extends PdfObject {
PdfRect destRect,
PdfBorder border}) =>
PdfAnnot._create(pdfPage,
subtype: "/Link",
subtype: '/Link',
srcRect: srcRect,
dest: dest,
destRect: destRect,
border: border);
/// The subtype of the outline, ie text, note, etc
final String subtype;
/// The size of the annotation
final PdfRect srcRect;
/// The text of a text annotation
final String content;
/// Link to the Destination page
final PdfObject dest;
/// If destRect is null then this is the region of the destination page shown.
/// Otherwise they are ignored.
final PdfRect destRect;
/// the border for this annotation
final PdfBorder border;
/// Output the annotation
///
/// @param os OutputStream to send the object to
... ... @@ -82,30 +82,30 @@ class PdfAnnot extends PdfObject {
void _prepare() {
super._prepare();
params["/Subtype"] = PdfStream.string(subtype);
params["/Rect"] = PdfStream.string(
"[${srcRect.left} ${srcRect.bottom} ${srcRect.right} ${srcRect.top}]");
params['/Subtype'] = PdfStream.string(subtype);
params['/Rect'] = PdfStream.string(
'[${srcRect.left} ${srcRect.bottom} ${srcRect.right} ${srcRect.top}]');
// handle the border
if (border == null) {
params["/Border"] = PdfStream.string("[0 0 0]");
params['/Border'] = PdfStream.string('[0 0 0]');
} else {
params["/BS"] = border.ref();
params['/BS'] = border.ref();
}
// Now the annotation subtypes
if (subtype == "/Text") {
params["/Contents"] = PdfStream()..putLiteral(content);
} else if (subtype == "/Link") {
var dests = List<PdfStream>();
if (subtype == '/Text') {
params['/Contents'] = PdfStream()..putLiteral(content);
} else if (subtype == '/Link') {
final List<PdfStream> dests = <PdfStream>[];
dests.add(dest.ref());
if (destRect == null)
dests.add(PdfStream.string("/Fit"));
dests.add(PdfStream.string('/Fit'));
else {
dests.add(PdfStream.string(
"/FitR ${destRect.left} ${destRect.bottom} ${destRect.right} ${destRect.top}"));
'/FitR ${destRect.left} ${destRect.bottom} ${destRect.right} ${destRect.top}'));
}
params["/Dest"] = PdfStream.array(dests);
params['/Dest'] = PdfStream.array(dests);
}
}
}
... ...
... ... @@ -17,10 +17,10 @@
part of pdf;
class PdfArrayObject extends PdfObject {
final List<String> values;
PdfArrayObject(PdfDocument pdfDocument, this.values) : super(pdfDocument);
final List<String> values;
@override
void _writeContent(PdfStream os) {
super._writeContent(os);
... ...
... ... @@ -17,11 +17,12 @@
part of pdf;
class Ascii85Encoder extends Converter<List<int>, List<int>> {
@override
List<int> convert(List<int> input) {
Uint8List buffer = Uint8List(_maxEncodedLen(input.length) + 2);
final Uint8List buffer = Uint8List(_maxEncodedLen(input.length) + 2);
var b = 0;
var s = 0;
int b = 0;
int s = 0;
while (s < input.length) {
buffer[b + 0] = 0;
... ... @@ -68,7 +69,7 @@ class Ascii85Encoder extends Converter<List<int>, List<int>> {
}
// If input was short, discard the low destination bytes.
var m = 5;
int m = 5;
if (input.length - s < 4) {
m -= 4 - (input.length - s);
break;
... ...
/*
* Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
... ... @@ -36,15 +36,6 @@ enum PdfBorderStyle {
}
class PdfBorder extends PdfObject {
/// The style of the border
final PdfBorderStyle 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].
/// Note: Do not use [PdfAnnot.dashed] with this method.
/// Use the other constructor.
... ... @@ -57,18 +48,27 @@ class PdfBorder extends PdfObject {
{this.style = PdfBorderStyle.solid, this.dash})
: super(pdfDocument);
/// The style of the border
final PdfBorderStyle 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;
/// @param os OutputStream to send the object to
@override
void _writeContent(PdfStream os) {
super._writeContent(os);
var data = List<PdfStream>();
data.add(PdfStream.string("/S"));
final List<PdfStream> data = <PdfStream>[];
data.add(PdfStream.string('/S'));
data.add(PdfStream.string(
"/" + "SDBIU".substring(style.index, style.index + 1)));
data.add(PdfStream.string("/W $width"));
'/' + 'SDBIU'.substring(style.index, style.index + 1)));
data.add(PdfStream.string('/W $width'));
if (dash != null) {
data.add(PdfStream.string("/D"));
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>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
... ... @@ -17,6 +17,14 @@
part of pdf;
class PdfCatalog extends PdfObject {
/// 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');
/// The pages of the document
final PdfPageList pdfPageList;
... ... @@ -26,28 +34,20 @@ class PdfCatalog extends PdfObject {
/// 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();
params['/Pages'] = pdfPageList.ref();
// the Outlines object
if (outlines != null && outlines.outlines.isNotEmpty) {
params["/Outlines"] = outlines.ref();
params['/Outlines'] = outlines.ref();
}
// the /PageMode setting
params["/PageMode"] =
params['/PageMode'] =
PdfStream.string(PdfDocument._PdfPageModes[pageMode.index]);
}
}
... ...
... ... @@ -17,33 +17,6 @@
part of pdf;
class PdfColor {
final double a;
final double r;
final double g;
final double b;
static const black = PdfColor(0.0, 0.0, 0.0);
static const white = PdfColor(1.0, 1.0, 1.0);
static const red = PdfColor(0.95686, 0.26274, 0.21176);
static const pink = PdfColor(0.91372, 0.11764, 0.38823);
static const purple = PdfColor(0.91372, 0.11764, 0.38823);
static const deepPurple = PdfColor(0.40392, 0.22745, 0.71765);
static const indigo = PdfColor(0.24705, 0.31765, 0.70980);
static const blue = PdfColor(0.12941, 0.58823, 0.95294);
static const lightBlue = PdfColor(0.01176, 0.66274, 0.95686);
static const cyan = PdfColor(0.0, 0.73725, 0.83137);
static const teal = PdfColor(0.0, 0.58823, 0.53333);
static const green = PdfColor(0.29803, 0.68627, 0.31372);
static const lightGreen = PdfColor(0.54509, 0.76470, 0.29020);
static const lime = PdfColor(0.80392, 0.86274, 0.22353);
static const yellow = PdfColor(1.0, 0.92157, 0.23137);
static const amber = PdfColor(1.0, 0.75686, 0.02745);
static const orange = PdfColor(1.0, 0.59608, 0.0);
static const deepOrange = PdfColor(1.0, 0.34118, 0.13333);
static const brown = PdfColor(0.47451, 0.33333, 0.28235);
static const grey = PdfColor(0.61961, 0.61961, 0.61961);
static const blueGrey = PdfColor(0.37647, 0.49020, 0.54510);
const PdfColor(this.r, this.g, this.b, [this.a = 1.0]);
const PdfColor.fromInt(int color)
... ... @@ -60,6 +33,33 @@ class PdfColor {
(int.parse(color.substring(6, 7), radix: 16) >> 24 & 0xff) / 255.0);
}
final double a;
final double r;
final double g;
final double b;
static const PdfColor black = PdfColor(0.0, 0.0, 0.0);
static const PdfColor white = PdfColor(1.0, 1.0, 1.0);
static const PdfColor red = PdfColor(0.95686, 0.26274, 0.21176);
static const PdfColor pink = PdfColor(0.91372, 0.11764, 0.38823);
static const PdfColor purple = PdfColor(0.91372, 0.11764, 0.38823);
static const PdfColor deepPurple = PdfColor(0.40392, 0.22745, 0.71765);
static const PdfColor indigo = PdfColor(0.24705, 0.31765, 0.70980);
static const PdfColor blue = PdfColor(0.12941, 0.58823, 0.95294);
static const PdfColor lightBlue = PdfColor(0.01176, 0.66274, 0.95686);
static const PdfColor cyan = PdfColor(0.0, 0.73725, 0.83137);
static const PdfColor teal = PdfColor(0.0, 0.58823, 0.53333);
static const PdfColor green = PdfColor(0.29803, 0.68627, 0.31372);
static const PdfColor lightGreen = PdfColor(0.54509, 0.76470, 0.29020);
static const PdfColor lime = PdfColor(0.80392, 0.86274, 0.22353);
static const PdfColor yellow = PdfColor(1.0, 0.92157, 0.23137);
static const PdfColor amber = PdfColor(1.0, 0.75686, 0.02745);
static const PdfColor orange = PdfColor(1.0, 0.59608, 0.0);
static const PdfColor deepOrange = PdfColor(1.0, 0.34118, 0.13333);
static const PdfColor brown = PdfColor(0.47451, 0.33333, 0.28235);
static const PdfColor grey = PdfColor(0.61961, 0.61961, 0.61961);
static const PdfColor blueGrey = PdfColor(0.37647, 0.49020, 0.54510);
int toInt() =>
((((a * 255.0).round() & 0xff) << 24) |
(((r * 255.0).round() & 0xff) << 16) |
... ... @@ -80,7 +80,9 @@ class PdfColor {
}
static double _linearizeColorComponent(double component) {
if (component <= 0.03928) return component / 12.92;
if (component <= 0.03928) {
return component / 12.92;
}
return math.pow((component + 0.055) / 1.055, 2.4);
}
... ... @@ -91,21 +93,14 @@ class PdfColor {
return 0.2126 * R + 0.7152 * G + 0.0722 * B;
}
String toString() => "$runtimeType($r, $g, $b, $a)";
@override
String toString() => '$runtimeType($r, $g, $b, $a)';
}
class PdfColorCmyk extends PdfColor {
final double c;
final double m;
final double y;
final double k;
const PdfColorCmyk(this.c, this.m, this.y, this.k, [double a = 1.0])
: super(
(1.0 - c) * (1.0 - k),
(1.0 - m) * (1.0 - k),
(1.0 - y) * (1.0 - k),
);
: super((1.0 - c) * (1.0 - k), (1.0 - m) * (1.0 - k),
(1.0 - y) * (1.0 - k), a);
const PdfColorCmyk.fromRgb(double r, double g, double b, [double a = 1.0])
: k = 1.0 - r > g ? r : g > b ? r > g ? r : g : b,
... ... @@ -117,12 +112,18 @@ class PdfColorCmyk extends PdfColor {
(1.0 - (1.0 - r > g ? r : g > b ? r > g ? r : g : b)),
super(r, g, b, a);
final double c;
final double m;
final double y;
final double k;
@override
PdfColorCmyk toCmyk() {
return this;
}
String toString() => "$runtimeType($c, $m, $y, $k, $a)";
@override
String toString() => '$runtimeType($c, $m, $y, $k, $a)';
}
double _getHue(
... ... @@ -144,14 +145,6 @@ double _getHue(
}
class PdfColorHsv extends PdfColor {
final double hue;
final double saturation;
final double value;
const PdfColorHsv._(this.hue, this.saturation, this.value, double red,
double green, double blue, double alpha)
: super(red, green, blue, alpha);
factory PdfColorHsv(double hue, double saturation, double value,
[double alpha = 1.0]) {
final double chroma = saturation * value;
... ... @@ -192,35 +185,36 @@ class PdfColorHsv extends PdfColor {
blue + match, alpha);
}
const PdfColorHsv._(this.hue, this.saturation, this.value, double red,
double green, double blue, double alpha)
: super(red, green, blue, alpha);
factory PdfColorHsv.fromRgb(double red, double green, double blue,
[double alpha]) {
final double max = math.max(red, math.max(green, blue));
final double min = math.min(red, math.min(green, blue));
final double delta = max - min;
final hue = _getHue(red, green, blue, max, delta);
final double hue = _getHue(red, green, blue, max, delta);
final double saturation = max == 0.0 ? 0.0 : delta / max;
return PdfColorHsv._(hue, saturation, max, red, green, blue, alpha);
}
final double hue;
final double saturation;
final double value;
@override
PdfColorHsv toHsv() {
return this;
}
String toString() => "$runtimeType($hue, $saturation, $value, $a)";
@override
String toString() => '$runtimeType($hue, $saturation, $value, $a)';
}
class PdfColorHsl extends PdfColor {
final double hue;
final double saturation;
final double lightness;
const PdfColorHsl._(this.hue, this.saturation, this.lightness, double alpha,
double red, double green, double blue)
: super(red, green, blue, alpha);
factory PdfColorHsl(double hue, double saturation, double lightness,
[double alpha]) {
final double chroma = (1.0 - (2.0 * lightness - 1.0).abs()) * saturation;
... ... @@ -260,6 +254,10 @@ class PdfColorHsl extends PdfColor {
green + match, blue + match);
}
const PdfColorHsl._(this.hue, this.saturation, this.lightness, double alpha,
double red, double green, double blue)
: super(red, green, blue, alpha);
factory PdfColorHsl.fromRgb(double red, double green, double blue,
[double alpha]) {
final double max = math.max(red, math.max(green, blue));
... ... @@ -275,6 +273,10 @@ class PdfColorHsl extends PdfColor {
return PdfColorHsl._(hue, saturation, lightness, alpha, red, green, blue);
}
final double hue;
final double saturation;
final double lightness;
@override
PdfColorHsl toHsl() {
return this;
... ...
... ... @@ -18,13 +18,6 @@ part of pdf;
@deprecated
class PDFAnnot extends PdfAnnot {
static const SOLID = PdfBorderStyle.solid;
static const DASHED = PdfBorderStyle.dashed;
static const BEVELED = PdfBorderStyle.beveled;
static const INSET = PdfBorderStyle.inset;
static const UNDERLINED = PdfBorderStyle.underlined;
static const FULL_PAGE = -9999.0;
PDFAnnot(PdfPage pdfPage,
{String type,
String s,
... ... @@ -48,11 +41,11 @@ class PDFAnnot extends PdfAnnot {
factory PDFAnnot.annotation(
PdfPage pdfPage, String s, double l, double b, double r, double t) =>
PDFAnnot(pdfPage, type: "/Annot", s: s, l: l, b: b, r: r, t: t);
PDFAnnot(pdfPage, type: '/Annot', s: s, l: l, b: b, r: r, t: t);
factory PDFAnnot.text(
PdfPage pdfPage, double l, double b, double r, double t, String s) =>
PDFAnnot(pdfPage, type: "/Text", l: l, b: b, r: r, t: t, s: s);
PDFAnnot(pdfPage, type: '/Text', l: l, b: b, r: r, t: t, s: s);
factory PDFAnnot.link(PdfPage pdfPage, double l, double b, double r, double t,
PdfObject dest,
... ... @@ -61,7 +54,7 @@ class PDFAnnot extends PdfAnnot {
double fr = FULL_PAGE,
double ft = FULL_PAGE]) =>
PDFAnnot(pdfPage,
type: "/Link",
type: '/Link',
l: l,
b: b,
r: r,
... ... @@ -71,6 +64,13 @@ class PDFAnnot extends PdfAnnot {
fb: fb,
fr: fr,
ft: ft);
static const PdfBorderStyle SOLID = PdfBorderStyle.solid;
static const PdfBorderStyle DASHED = PdfBorderStyle.dashed;
static const PdfBorderStyle BEVELED = PdfBorderStyle.beveled;
static const PdfBorderStyle INSET = PdfBorderStyle.inset;
static const PdfBorderStyle UNDERLINED = PdfBorderStyle.underlined;
static const double FULL_PAGE = -9999.0;
}
@deprecated
... ... @@ -106,12 +106,12 @@ class PDFColor extends PdfColor {
PDFColor(double r, double g, double b, [double a = 1.0]) : super(r, g, b, a);
factory PDFColor.fromInt(int color) {
final c = PdfColor.fromInt(color);
final PdfColor c = PdfColor.fromInt(color);
return PDFColor(c.r, c.g, c.b, c.a);
}
factory PDFColor.fromHex(String color) {
final c = PdfColor.fromHex(color);
final PdfColor c = PdfColor.fromHex(color);
return PDFColor(c.r, c.g, c.b, c.a);
}
}
... ... @@ -125,6 +125,7 @@ class PDFFontDescriptor extends PdfFontDescriptor {
@deprecated
class PDFFont extends PdfFont {
factory PDFFont(PdfDocument pdfDocument, {String subtype, String baseFont}) {
subtype ??= baseFont;
return PdfFont.helvetica(pdfDocument);
}
}
... ... @@ -184,16 +185,16 @@ class PDFObject extends PdfObject {
@deprecated
class PDFOutline extends PdfOutline {
PDFOutline(PdfDocument pdfDocument,
{String title, PdfPage dest, double l, double b, double r, double t})
: super(pdfDocument,
title: title, dest: dest, rect: PdfRect.fromLTRB(l, t, r, b));
@deprecated
static const PdfOutlineMode FITPAGE = PdfOutlineMode.fitpage;
@deprecated
static const PdfOutlineMode FITRECT = PdfOutlineMode.fitrect;
PDFOutline(PdfDocument pdfDocument,
{String title, PdfPage dest, double l, double b, double r, double t})
: super(pdfDocument,
title: title, dest: dest, rect: PdfRect.fromLTRB(l, t, r, b));
}
@deprecated
... ... @@ -203,26 +204,26 @@ class PDFOutput extends PdfOutput {
@deprecated
class PDFPageFormat extends PdfPageFormat {
static const a4 = PdfPageFormat.a4;
static const a3 = PdfPageFormat.a3;
static const a5 = PdfPageFormat.a5;
static const letter = PdfPageFormat.letter;
static const legal = PdfPageFormat.legal;
static const point = PdfPageFormat.point;
static const inch = PdfPageFormat.inch;
static const cm = PdfPageFormat.cm;
static const mm = PdfPageFormat.mm;
static const A4 = a4;
static const A3 = a3;
static const A5 = a5;
static const LETTER = letter;
static const LEGAL = legal;
static const PT = point;
static const IN = inch;
static const CM = cm;
static const MM = mm;
const PDFPageFormat(double width, double height) : super(width, height);
static const PdfPageFormat a4 = PdfPageFormat.a4;
static const PdfPageFormat a3 = PdfPageFormat.a3;
static const PdfPageFormat a5 = PdfPageFormat.a5;
static const PdfPageFormat letter = PdfPageFormat.letter;
static const PdfPageFormat legal = PdfPageFormat.legal;
static const double point = PdfPageFormat.point;
static const double inch = PdfPageFormat.inch;
static const double cm = PdfPageFormat.cm;
static const double mm = PdfPageFormat.mm;
static const PdfPageFormat A4 = a4;
static const PdfPageFormat A3 = a3;
static const PdfPageFormat A5 = a5;
static const PdfPageFormat LETTER = letter;
static const PdfPageFormat LEGAL = legal;
static const double PT = point;
static const double IN = inch;
static const double CM = cm;
static const double MM = mm;
}
@deprecated
... ... @@ -257,10 +258,10 @@ class PDFPage extends PdfPage {
/// @param h Height of the note
/// @return Returns the annotation, so other settings can be changed.
@deprecated
PdfAnnot addNote(String note, double x, y, w, h) {
var xy1 = cxy(x, y + h);
var xy2 = cxy(x + w, y);
PdfAnnot ob = PdfAnnot.text(this,
PdfAnnot addNote(String note, double x, double y, double w, double h) {
final PdfPoint xy1 = cxy(x, y + h);
final PdfPoint xy2 = cxy(x + w, y);
final PdfAnnot ob = PdfAnnot.text(this,
rect: PdfRect.fromLTRB(xy1.x, xy1.y, xy2.x, xy2.y), content: note);
return ob;
}
... ... @@ -278,16 +279,16 @@ class PDFPage extends PdfPage {
/// @param vh Height of the view area
/// @return Returns the annotation, so other settings can be changed.
@deprecated
PdfAnnot addLink(double x, y, w, h, PdfObject dest,
PdfAnnot addLink(double x, double y, double w, double 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 = PdfAnnot.link(this,
double vy = PDFAnnot.FULL_PAGE,
double vw = PDFAnnot.FULL_PAGE,
double vh = PDFAnnot.FULL_PAGE]) {
final PdfPoint xy1 = cxy(x, y + h);
final PdfPoint xy2 = cxy(x + w, y);
final PdfPoint xy3 = cxy(vx, vy + vh);
final PdfPoint xy4 = cxy(vx + vw, vy);
final PdfAnnot ob = PdfAnnot.link(this,
srcRect: PdfRect.fromLTRB(xy1.x, xy1.y, xy2.x, xy2.y),
dest: dest,
destRect: PdfRect.fromLTRB(xy3.x, xy3.y, xy4.x, xy4.y));
... ... @@ -305,9 +306,9 @@ class PDFPage extends PdfPage {
@deprecated
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 = PdfOutline(pdfDocument,
final PdfPoint xy1 = cxy(x, y + h);
final PdfPoint xy2 = cxy(x + w, y);
final PdfOutline outline = PdfOutline(pdfDocument,
title: title,
dest: this,
rect: PdfRect.fromLTRB(xy1.x, xy2.y, xy2.x, xy1.y));
... ... @@ -342,7 +343,7 @@ class PDFPage extends PdfPage {
@deprecated
class PDFPoint extends PdfPoint {
PDFPoint(double w, double h) : super(w, h);
const PDFPoint(double w, double h) : super(w, h);
}
@deprecated
... ...
/*
* Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
... ... @@ -35,7 +35,7 @@ enum PdfPageMode {
fullscreen
}
typedef List<int> DeflateCallback(List<int> data);
typedef DeflateCallback = List<int> Function(List<int> data);
/// This class is the base of the Pdf generator. A [PdfDocument] class is
/// created for a document, and each page, object, annotation,
... ... @@ -43,6 +43,17 @@ typedef List<int> DeflateCallback(List<int> data);
/// Once complete, the document can be written to a Stream, and the Pdf
/// document's internal structures are kept in sync.
class PdfDocument {
/// This creates a Pdf document
/// @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}) {
_objser = 1;
// Now create some standard objects
pdfPageList = PdfPageList(this);
catalog = PdfCatalog(this, pdfPageList, pageMode);
}
/// This is used to allocate objects a unique serial number in the document.
int _objser;
... ... @@ -72,11 +83,11 @@ class PdfDocument {
final DeflateCallback deflate;
/// These map the page modes just defined to the pagemodes setting of Pdf.
static const _PdfPageModes = [
"/UseNone",
"/UseOutlines",
"/UseThumbs",
"/FullScreen"
static const List<String> _PdfPageModes = <String>[
'/UseNone',
'/UseOutlines',
'/UseThumbs',
'/FullScreen'
];
/// This holds the current fonts
... ... @@ -85,17 +96,6 @@ class PdfDocument {
/// Creates a new serial number
int _genSerial() => _objser++;
/// This creates a Pdf document
/// @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}) {
_objser = 1;
// Now create some standard objects
pdfPageList = PdfPageList(this);
catalog = PdfCatalog(this, pdfPageList, pageMode);
}
/// This returns a specific page. It's used mainly when using a
/// Serialized template file.
///
... ... @@ -128,20 +128,18 @@ class PdfDocument {
///
/// @param os OutputStream to write the document to
void _write(PdfStream os) {
PdfOutput pos = PdfOutput(os);
final PdfOutput pos = 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);
}
objects.forEach(pos.write);
// Finally close the output, which writes the xref table.
pos.close();
}
List<int> save() {
PdfStream os = PdfStream();
final PdfStream os = PdfStream();
_write(os);
return os.output();
}
... ...
... ... @@ -17,9 +17,6 @@
part of pdf;
class PdfFont extends PdfObject {
/// The df type of the font, usually /Type1
final String subtype;
/// Constructs a [PdfFont]. This will attempt to map the font from a known
/// font name to that in Pdf, defaulting to Helvetica if not possible.
///
... ... @@ -27,94 +24,33 @@ class PdfFont extends PdfObject {
/// @param subtype The pdf type, ie /Type1
/// @param baseFont The font name, ie /Helvetica
PdfFont._create(PdfDocument pdfDocument, {@required this.subtype})
: super(pdfDocument, "/Font") {
: super(pdfDocument, '/Font') {
pdfDocument.fonts.add(this);
}
String get name => "/F$objser";
String get fontName => null;
/// @param os OutputStream to send the object to
@override
void _prepare() {
super._prepare();
params["/Subtype"] = PdfStream.string(subtype);
params["/Name"] = PdfStream.string(name);
params["/Encoding"] = PdfStream.string("/WinAnsiEncoding");
}
double glyphAdvance(int charCode) {
return 0.454;
}
PdfRect glyphBounds(int charCode) {
return PdfRect(0.0, 0.0, glyphAdvance(charCode), 1.0);
}
PdfRect stringBounds(String s) {
var chars = latin1.encode(s);
if (chars.isEmpty) 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.height;
var w = n == chars.length - 1 ? r.width : glyphAdvance(c);
while (++n < chars.length) {
c = chars[n];
r = glyphBounds(c);
if (r.y < y) y = r.y;
if (r.height > h) h = r.height;
w += n == chars.length - 1 ? r.width : glyphAdvance(c);
}
return 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.height > h) h = r.height;
w += glyphAdvance(c);
}
return PdfPoint(w, h);
}
factory PdfFont.courier(PdfDocument pdfDocument) {
return PdfType1Font._create(pdfDocument, "Courier", 0.910, -0.220,
return PdfType1Font._create(pdfDocument, 'Courier', 0.910, -0.220,
List<double>.generate(256, (int index) => 0.600));
}
factory PdfFont.courierBold(PdfDocument pdfDocument) {
return PdfType1Font._create(pdfDocument, "Courier-Bold", 0.910, -0.220,
return PdfType1Font._create(pdfDocument, 'Courier-Bold', 0.910, -0.220,
List<double>.generate(256, (int index) => 0.600));
}
factory PdfFont.courierBoldOblique(PdfDocument pdfDocument) {
return PdfType1Font._create(pdfDocument, "Courier-BoldOblique", 0.910,
return PdfType1Font._create(pdfDocument, 'Courier-BoldOblique', 0.910,
-0.220, List<double>.generate(256, (int index) => 0.600));
}
factory PdfFont.courierOblique(PdfDocument pdfDocument) {
return PdfType1Font._create(pdfDocument, "Courier-Oblique", 0.910, -0.220,
return PdfType1Font._create(pdfDocument, 'Courier-Oblique', 0.910, -0.220,
List<double>.generate(256, (int index) => 0.600));
}
factory PdfFont.helvetica(PdfDocument pdfDocument) {
return PdfType1Font._create(
pdfDocument, "Helvetica", 0.931, -0.225, <double>[
pdfDocument, 'Helvetica', 0.931, -0.225, const <double>[
0.500,
0.500,
0.500,
... ... @@ -376,7 +312,7 @@ class PdfFont extends PdfObject {
factory PdfFont.helveticaBold(PdfDocument pdfDocument) {
return PdfType1Font._create(
pdfDocument, "Helvetica-Bold", 0.962, -0.228, <double>[
pdfDocument, 'Helvetica-Bold', 0.962, -0.228, const <double>[
0.278,
0.278,
0.278,
... ... @@ -638,7 +574,7 @@ class PdfFont extends PdfObject {
factory PdfFont.helveticaBoldOblique(PdfDocument pdfDocument) {
return PdfType1Font._create(
pdfDocument, "Helvetica-BoldOblique", 0.962, -0.228, <double>[
pdfDocument, 'Helvetica-BoldOblique', 0.962, -0.228, const <double>[
0.278,
0.278,
0.278,
... ... @@ -900,7 +836,7 @@ class PdfFont extends PdfObject {
factory PdfFont.helveticaOblique(PdfDocument pdfDocument) {
return PdfType1Font._create(
pdfDocument, "Helvetica-Oblique", 0.931, -0.225, <double>[
pdfDocument, 'Helvetica-Oblique', 0.931, -0.225, <double>[
0.278,
0.278,
0.278,
... ... @@ -1162,7 +1098,7 @@ class PdfFont extends PdfObject {
factory PdfFont.times(PdfDocument pdfDocument) {
return PdfType1Font._create(
pdfDocument, "Times-Roman", 0.898, -0.218, <double>[
pdfDocument, 'Times-Roman', 0.898, -0.218, <double>[
0.250,
0.250,
0.250,
... ... @@ -1424,7 +1360,7 @@ class PdfFont extends PdfObject {
factory PdfFont.timesBold(PdfDocument pdfDocument) {
return PdfType1Font._create(
pdfDocument, "Times-Bold", 0.935, -0.218, <double>[
pdfDocument, 'Times-Bold', 0.935, -0.218, <double>[
0.250,
0.250,
0.250,
... ... @@ -1686,7 +1622,7 @@ class PdfFont extends PdfObject {
factory PdfFont.timesBoldItalic(PdfDocument pdfDocument) {
return PdfType1Font._create(
pdfDocument, "Times-BoldItalic", 0.921, -0.218, <double>[
pdfDocument, 'Times-BoldItalic', 0.921, -0.218, <double>[
0.250,
0.250,
0.250,
... ... @@ -1948,7 +1884,7 @@ class PdfFont extends PdfObject {
factory PdfFont.timesItalic(PdfDocument pdfDocument) {
return PdfType1Font._create(
pdfDocument, "Times-Italic", 0.883, -0.217, <double>[
pdfDocument, 'Times-Italic', 0.883, -0.217, <double>[
0.250,
0.250,
0.250,
... ... @@ -2209,7 +2145,7 @@ class PdfFont extends PdfObject {
}
factory PdfFont.symbol(PdfDocument pdfDocument) {
return PdfType1Font._create(pdfDocument, "Symbol", 1.010, -0.293, <double>[
return PdfType1Font._create(pdfDocument, 'Symbol', 1.010, -0.293, <double>[
0.587,
0.587,
0.587,
... ... @@ -2471,7 +2407,7 @@ class PdfFont extends PdfObject {
factory PdfFont.zapfDingbats(PdfDocument pdfDocument) {
return PdfType1Font._create(
pdfDocument, "ZapfDingbats", 0.820, -0.143, <double>[
pdfDocument, 'ZapfDingbats', 0.820, -0.143, <double>[
0.746,
0.746,
0.746,
... ... @@ -2730,4 +2666,76 @@ class PdfFont extends PdfObject {
0.746
]);
}
/// The df type of the font, usually /Type1
final String subtype;
String get name => '/F$objser';
String get fontName => null;
/// @param os OutputStream to send the object to
@override
void _prepare() {
super._prepare();
params['/Subtype'] = PdfStream.string(subtype);
params['/Name'] = PdfStream.string(name);
params['/Encoding'] = PdfStream.string('/WinAnsiEncoding');
}
double glyphAdvance(int charCode) {
return 0.454;
}
PdfRect glyphBounds(int charCode) {
return PdfRect(0.0, 0.0, glyphAdvance(charCode), 1.0);
}
PdfRect stringBounds(String s) {
final Uint8List chars = latin1.encode(s);
if (chars.isEmpty) {
return const PdfRect(0.0, 0.0, 0.0, 0.0);
}
int n = 0;
int c = chars[n];
PdfRect r = glyphBounds(c);
final double x = r.x;
double y = r.y;
double h = r.height;
double w = n == chars.length - 1 ? r.width : glyphAdvance(c);
while (++n < chars.length) {
c = chars[n];
r = glyphBounds(c);
if (r.y < y) {
y = r.y;
}
if (r.height > h) {
h = r.height;
}
w += n == chars.length - 1 ? r.width : glyphAdvance(c);
}
return PdfRect(x, y, w, h);
}
PdfPoint stringSize(String s) {
final Uint8List chars = latin1.encode(s);
double w = 0.0;
double h = 0.0;
for (int c in chars) {
final PdfRect r = glyphBounds(c);
if (r.height > h) {
h = r.height;
}
w += glyphAdvance(c);
}
return PdfPoint(w, h);
}
}
... ...
... ... @@ -17,30 +17,31 @@
part of pdf;
class PdfFontDescriptor extends PdfObject {
PdfFontDescriptor(this.ttfFont, this.file)
: super(ttfFont.pdfDocument, '/FontDescriptor');
final PdfObjectStream file;
final PdfTtfFont ttfFont;
PdfFontDescriptor(this.ttfFont, this.file)
: super(ttfFont.pdfDocument, "/FontDescriptor");
final PdfTtfFont ttfFont;
@override
void _prepare() {
super._prepare();
params["/FontName"] = PdfStream.string(ttfFont.fontName);
params["/FontFile2"] = file.ref();
params["/Flags"] = PdfStream.intNum(32);
params["/FontBBox"] = PdfStream()
..putStringArray([
params['/FontName'] = PdfStream.string(ttfFont.fontName);
params['/FontFile2'] = file.ref();
params['/Flags'] = PdfStream.intNum(32);
params['/FontBBox'] = PdfStream()
..putIntArray(<int>[
ttfFont.font.xMin,
ttfFont.font.yMin,
ttfFont.font.xMax,
ttfFont.font.yMax
]);
params["/Ascent"] = PdfStream.intNum(ttfFont.font.ascent);
params["/Descent"] = PdfStream.intNum(ttfFont.font.descent);
params["/ItalicAngle"] = PdfStream.intNum(0);
params["/CapHeight"] = PdfStream.intNum(10);
params["/StemV"] = PdfStream.intNum(79);
params['/Ascent'] = PdfStream.intNum(ttfFont.font.ascent);
params['/Descent'] = PdfStream.intNum(ttfFont.font.descent);
params['/ItalicAngle'] = PdfStream.intNum(0);
params['/CapHeight'] = PdfStream.intNum(10);
params['/StemV'] = PdfStream.intNum(79);
}
}
... ...
... ... @@ -17,22 +17,22 @@
part of pdf;
class PdfFormXObject extends PdfXObject {
PdfFormXObject(PdfDocument pdfDocument) : super(pdfDocument, '/Form') {
params['/FormType'] = PdfStream.string('1');
params['/BBox'] = PdfStream.string('[0 0 1000 1000]');
}
/// The fonts associated with this page
final fonts = Map<String, PdfFont>();
final Map<String, PdfFont> fonts = <String, PdfFont>{};
/// The xobjects or other images in the pdf
final xobjects = Map<String, PdfXObject>();
PdfFormXObject(PdfDocument pdfDocument) : super(pdfDocument, '/Form') {
params["/FormType"] = PdfStream.string("1");
params["/BBox"] = PdfStream.string("[0 0 1000 1000]");
}
final Map<String, PdfXObject> xobjects = <String, PdfXObject>{};
/// 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]}]");
final Float64List s = t.storage;
params['/Matrix'] =
PdfStream.string('[${s[0]} ${s[1]} ${s[4]} ${s[5]} ${s[12]} ${s[13]}]');
}
@override
... ... @@ -41,20 +41,20 @@ class PdfFormXObject extends PdfXObject {
// Now the resources
/// This holds any resources for this FormXObject
final resources = Map<String, PdfStream>();
final Map<String, PdfStream> resources = <String, PdfStream>{};
// fonts
if (fonts.isNotEmpty) {
resources["/Font"] = PdfStream()..putObjectDictionary(fonts);
resources['/Font'] = PdfStream()..putObjectDictionary(fonts);
}
// Now the XObjects
if (xobjects.isNotEmpty) {
resources["/XObject"] = PdfStream()..putObjectDictionary(xobjects);
resources['/XObject'] = PdfStream()..putObjectDictionary(xobjects);
}
if (resources.isNotEmpty) {
params["/Resources"] = PdfStream.dictionary(resources);
params['/Resources'] = PdfStream.dictionary(resources);
}
}
}
... ...
... ... @@ -19,18 +19,18 @@ part of pdf;
enum PdfLineCap { joinMiter, joinRound, joinBevel }
class PdfGraphics {
PdfGraphics(this.page, this.buf);
/// Ellipse 4-spline magic number
static const _m4 = 0.551784;
static const double _m4 = 0.551784;
/// Graphic context number
var _context = 0;
int _context = 0;
final PdfPage page;
final PdfStream buf;
PdfGraphics(this.page, this.buf);
PdfFont get defaultFont {
if (page.pdfDocument.fonts.isEmpty) {
PdfFont.helvetica(page.pdfDocument);
... ... @@ -40,19 +40,19 @@ class PdfGraphics {
}
void fillPath() {
buf.putString("f\n");
buf.putString('f\n');
}
void strokePath() {
buf.putString("S\n");
buf.putString('S\n');
}
void closePath() {
buf.putString("s\n");
buf.putString('s\n');
}
void clipPath() {
buf.putString("W n\n");
buf.putString('W n\n');
}
/// This releases any resources used by this Graphics object. You must use
... ... @@ -63,14 +63,14 @@ class PdfGraphics {
void restoreContext() {
if (_context > 0) {
// restore graphics context
buf.putString("Q\n");
buf.putString('Q\n');
_context--;
}
}
void saveContext() {
// save graphics context
buf.putString("q\n");
buf.putString('q\n');
_context++;
}
... ... @@ -89,16 +89,16 @@ class PdfGraphics {
/// @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();
w ??= img.width.toDouble();
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 ");
buf.putString('q ');
buf.putNumList(<double>[w, 0.0, 0.0, h, x, y]);
buf.putString(" cm ${img.name} Do Q\n");
buf.putString(' cm ${img.name} Do Q\n');
}
/// Draws a line between two coordinates.
... ... @@ -145,7 +145,7 @@ class PdfGraphics {
double h,
) {
buf.putNumList(<double>[x, y, w, h]);
buf.putString(" re\n");
buf.putString(' re\n');
}
/// Draws a Rounded Rectangle
... ... @@ -179,13 +179,13 @@ class PdfGraphics {
page.fonts[font.name] = font;
}
buf.putString("BT ");
buf.putString('BT ');
buf.putNumList(<double>[x, y]);
buf.putString(" Td ${font.name} ");
buf.putString(' Td ${font.name} ');
buf.putNum(size);
buf.putString(" Tf ");
buf.putString(' Tf ');
buf.putText(s);
buf.putString(" Tj ET\n");
buf.putString(' Tj ET\n');
}
/// Sets the color for drawing
... ... @@ -202,10 +202,10 @@ class PdfGraphics {
void setFillColor(PdfColor color) {
if (color is PdfColorCmyk) {
buf.putNumList(<double>[color.c, color.m, color.y, color.k]);
buf.putString(" k\n");
buf.putString(' k\n');
} else {
buf.putNumList(<double>[color.r, color.g, color.b]);
buf.putString(" rg\n");
buf.putString(' rg\n');
}
}
... ... @@ -215,18 +215,18 @@ class PdfGraphics {
void setStrokeColor(PdfColor color) {
if (color is PdfColorCmyk) {
buf.putNumList(<double>[color.c, color.m, color.y, color.k]);
buf.putString(" K\n");
buf.putString(' K\n');
} else {
buf.putNumList(<double>[color.r, color.g, color.b]);
buf.putString(" RG\n");
buf.putString(' RG\n');
}
}
/// Set the transformation Matrix
void setTransform(Matrix4 t) {
var s = t.storage;
final Float64List s = t.storage;
buf.putNumList(<double>[s[0], s[1], s[4], s[5], s[12], s[13]]);
buf.putString(" cm\n");
buf.putString(' cm\n');
}
/// This adds a line segment to the current path
... ... @@ -235,7 +235,7 @@ class PdfGraphics {
/// @param y coordinate
void lineTo(double x, double y) {
buf.putNumList(<double>[x, y]);
buf.putString(" l\n");
buf.putString(' l\n');
}
/// This moves the current drawing point.
... ... @@ -244,7 +244,7 @@ class PdfGraphics {
/// @param y coordinate
void moveTo(double x, double y) {
buf.putNumList(<double>[x, y]);
buf.putString(" m\n");
buf.putString(' m\n');
}
/// Draw a cubic bézier curve from the current point to (x3,y3)
... ... @@ -260,17 +260,22 @@ class PdfGraphics {
void curveTo(
double x1, double y1, double x2, double y2, double x3, double y3) {
buf.putNumList(<double>[x1, y1, x2, y2, x3, y3]);
buf.putString(" c\n");
buf.putString(' c\n');
}
double _vectorAngle(double ux, double uy, double vx, double vy) {
final d = math.sqrt(ux * ux + uy * uy) * math.sqrt(vx * vx + vy * vy);
if (d == 0.0) return 0.0;
var c = (ux * vx + uy * vy) / d;
final double d =
math.sqrt(ux * ux + uy * uy) * math.sqrt(vx * vx + vy * vy);
if (d == 0.0) {
return 0.0;
}
double c = (ux * vx + uy * vy) / d;
if (c < -1.0) {
c = -1.0;
} else if (c > 1.0) c = 1.0;
final s = ux * vy - uy * vx;
} else if (c > 1.0) {
c = 1.0;
}
final double s = ux * vy - uy * vx;
c = math.acos(c);
return c.sign == s.sign ? c : -c;
}
... ... @@ -282,35 +287,44 @@ class PdfGraphics {
rx = rx.abs();
ry = ry.abs();
final x1d = 0.5 * (x1 - x2);
final y1d = 0.5 * (y1 - y2);
final double x1d = 0.5 * (x1 - x2);
final double y1d = 0.5 * (y1 - y2);
var r = x1d * x1d / (rx * rx) + y1d * y1d / (ry * ry);
double r = x1d * x1d / (rx * rx) + y1d * y1d / (ry * ry);
if (r > 1.0) {
var rr = math.sqrt(r);
final double rr = math.sqrt(r);
rx *= rr;
ry *= rr;
r = x1d * x1d / (rx * rx) + y1d * y1d / (ry * ry);
} else if (r != 0.0) r = 1.0 / r - 1.0;
} else if (r != 0.0) {
r = 1.0 / r - 1.0;
}
if (-1e-10 < r && r < 0.0) r = 0.0;
if (-1e-10 < r && r < 0.0) {
r = 0.0;
}
r = math.sqrt(r);
if (large == sweep) r = -r;
if (large == sweep) {
r = -r;
}
final cxd = (r * rx * y1d) / ry;
final cyd = -(r * ry * x1d) / rx;
final double cxd = (r * rx * y1d) / ry;
final double cyd = -(r * ry * x1d) / rx;
final cx = cxd + 0.5 * (x1 + x2);
final cy = cyd + 0.5 * (y1 + y2);
final double cx = cxd + 0.5 * (x1 + x2);
final double cy = cyd + 0.5 * (y1 + y2);
final theta = _vectorAngle(1.0, 0.0, (x1d - cxd) / rx, (y1d - cyd) / ry);
var dTheta = _vectorAngle((x1d - cxd) / rx, (y1d - cyd) / ry,
final double theta =
_vectorAngle(1.0, 0.0, (x1d - cxd) / rx, (y1d - cyd) / ry);
double dTheta = _vectorAngle((x1d - cxd) / rx, (y1d - cyd) / ry,
(-x1d - cxd) / rx, (-y1d - cyd) / ry) %
(math.pi * 2.0);
if (sweep == false && dTheta > 0.0)
dTheta -= math.pi * 2.0;
else if (sweep == true && dTheta < 0.0) dTheta += math.pi * 2.0;
else if (sweep == true && dTheta < 0.0) {
dTheta += math.pi * 2.0;
}
_bezierArcFromCentre(cx, cy, rx, ry, -theta, -dTheta);
}
... ... @@ -330,21 +344,23 @@ class PdfGraphics {
return;
}
final halfFragment = fragmentsAngle * 0.5;
var kappa =
final double halfFragment = fragmentsAngle * 0.5;
double kappa =
(4.0 / 3.0 * (1.0 - math.cos(halfFragment)) / math.sin(halfFragment))
.abs();
if (fragmentsAngle < 0.0) kappa = -kappa;
if (fragmentsAngle < 0.0) {
kappa = -kappa;
}
var theta = startAngle;
final startFragment = theta + fragmentsAngle;
double theta = startAngle;
final double startFragment = theta + fragmentsAngle;
var c1 = math.cos(theta);
var s1 = math.sin(theta);
for (var i = 0; i < fragmentsCount; i++) {
final c0 = c1;
final s0 = s1;
double c1 = math.cos(theta);
double s1 = math.sin(theta);
for (int i = 0; i < fragmentsCount; i++) {
final double c0 = c1;
final double s0 = s1;
theta = startFragment + i * fragmentsAngle;
c1 = math.cos(theta);
s1 = math.sin(theta);
... ... @@ -365,7 +381,7 @@ class PdfGraphics {
/// contribute to the automatic calculations and help determine how the arc is drawn.
void _bezierArc(
double x1, double y1, double rx, double ry, double x2, double y2,
{large = false, sweep = false, phi = 0.0}) {
{bool large = false, bool sweep = false, double phi = 0.0}) {
if (x1 == x2 && y1 == y2) {
// From https://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes:
// If the endpoints (x1, y1) and (x2, y2) are identical, then this is
... ... @@ -381,10 +397,10 @@ class PdfGraphics {
if (phi != 0.0) {
// Our box bézier arcs can't handle rotations directly
// move to a well known point, eliminate phi and transform the other point
final mat = Matrix4.identity();
final Matrix4 mat = Matrix4.identity();
mat.translate(-x1, -y1);
mat.rotateZ(-phi);
final tr = mat.transform3(Vector3(x2, y2, 0.0));
final Vector3 tr = mat.transform3(Vector3(x2, y2, 0.0));
_endToCenterParameters(0.0, 0.0, tr[0], tr[1], large, sweep, rx, ry);
} else {
_endToCenterParameters(x1, y1, x2, y2, large, sweep, rx, ry);
... ... @@ -392,17 +408,18 @@ class PdfGraphics {
}
/// https://github.com/deeplook/svglib/blob/master/svglib/svglib.py#L911
void drawShape(String d, {stroke = true}) {
final exp = RegExp(r"([MmZzLlHhVvCcSsQqTtAaE])|(-[\.0-9]+)|([\.0-9]+)");
final matches = exp.allMatches(d + " E");
void drawShape(String d, {bool stroke = true}) {
final RegExp exp =
RegExp(r'([MmZzLlHhVvCcSsQqTtAaE])|(-[\.0-9]+)|([\.0-9]+)');
final Iterable<Match> matches = exp.allMatches(d + ' E');
String action;
String lastAction;
List<double> points;
PdfPoint lastControl = PdfPoint(0.0, 0.0);
PdfPoint lastPoint = PdfPoint(0.0, 0.0);
for (var m in matches) {
var a = m.group(1);
var b = m.group(0);
PdfPoint lastControl = const PdfPoint(0.0, 0.0);
PdfPoint lastPoint = const PdfPoint(0.0, 0.0);
for (Match m in matches) {
final String a = m.group(1);
final String b = m.group(0);
if (a == null) {
points.add(double.parse(b));
... ... @@ -446,7 +463,7 @@ class PdfGraphics {
lineTo(lastPoint.x, lastPoint.y);
break;
case 'C': // cubic bezier, absolute
var len = 0;
int len = 0;
while (len < points.length) {
curveTo(points[len + 0], points[len + 1], points[len + 2],
points[len + 3], points[len + 4], points[len + 5]);
... ... @@ -475,7 +492,7 @@ class PdfGraphics {
}
break;
case 'c': // cubic bezier, relative
var len = 0;
int len = 0;
while (len < points.length) {
points[len + 0] += lastPoint.x;
points[len + 1] += lastPoint.y;
... ... @@ -518,7 +535,7 @@ class PdfGraphics {
// case 't': // quadratic bezier, relative
// break;
case 'A': // elliptical arc, absolute
var len = 0;
int len = 0;
while (len < points.length) {
_bezierArc(lastPoint.x, lastPoint.y, points[len + 0],
points[len + 1], points[len + 5], points[len + 6],
... ... @@ -530,7 +547,7 @@ class PdfGraphics {
}
break;
case 'a': // elliptical arc, relative
var len = 0;
int len = 0;
while (len < points.length) {
points[len + 5] += lastPoint.x;
points[len + 6] += lastPoint.y;
... ... @@ -545,15 +562,17 @@ class PdfGraphics {
break;
case 'Z': // close path
case 'z': // close path
if (stroke) closePath();
if (stroke) {
closePath();
}
break;
default:
print("Unknown path action: $action");
print('Unknown path action: $action');
}
}
lastAction = action;
action = a;
points = List<double>();
points = <double>[];
}
}
... ... @@ -568,24 +587,26 @@ class PdfGraphics {
// newPath() not needed here as moveto does it ;-)
moveTo(p[0].x, p[0].y);
for (int i = 1; i < p.length; i++) lineTo(p[i].x, p[i].y);
for (int i = 1; i < p.length; i++) {
lineTo(p[i].x, p[i].y);
}
}
void setLineCap(PdfLineCap cap) {
buf.putString("${cap.index} J\n");
buf.putString('${cap.index} J\n');
}
void setLineJoin(PdfLineCap join) {
buf.putString("${join.index} j\n");
buf.putString('${join.index} j\n');
}
void setLineWidth(double width) {
buf.putNum(width);
buf.putString(" w\n");
buf.putString(' w\n');
}
void setMiterLimit(double limit) {
buf.putNum(limit);
buf.putString(" M\n");
buf.putString(' M\n');
}
}
... ...
... ... @@ -17,26 +17,6 @@
part of pdf;
class PdfImage extends PdfXObject {
/// RGBA Image Data
final Uint8List image;
/// Image width
final int width;
/// Image height
final int height;
/// Image has alpha channel
final bool alpha;
String _name;
/// Process alphaChannel only
final bool alphaChannel;
/// The image data is a jpeg image
final bool jpeg;
/// Creates a new [PdfImage] instance.
///
/// @param image an [Uint8List] value
... ... @@ -54,49 +34,69 @@ class PdfImage extends PdfXObject {
: assert(alphaChannel == false || alpha == true),
assert(width != null),
assert(height != null),
super(pdfDocument, "/Image", isBinary: true) {
_name = "/Image$objser";
params["/Width"] = PdfStream.string(width.toString());
params["/Height"] = PdfStream.string(height.toString());
params["/BitsPerComponent"] = PdfStream.intNum(8);
super(pdfDocument, '/Image', isBinary: true) {
_name = '/Image$objser';
params['/Width'] = PdfStream.string(width.toString());
params['/Height'] = PdfStream.string(height.toString());
params['/BitsPerComponent'] = PdfStream.intNum(8);
params['/Name'] = PdfStream.string(_name);
if (alphaChannel == false && alpha) {
var _sMask = PdfImage(pdfDocument,
final PdfImage _sMask = PdfImage(pdfDocument,
image: image,
width: width,
height: height,
alpha: alpha,
alphaChannel: true);
params["/SMask"] = PdfStream.string("${_sMask.objser} 0 R");
params['/SMask'] = PdfStream.string('${_sMask.objser} 0 R');
}
if (alphaChannel) {
params["/ColorSpace"] = PdfStream.string("/DeviceGray");
params['/ColorSpace'] = PdfStream.string('/DeviceGray');
} else {
params["/ColorSpace"] = PdfStream.string("/DeviceRGB");
params['/ColorSpace'] = PdfStream.string('/DeviceRGB');
}
if (jpeg) {
params["/Intent"] = PdfStream.string("/RelativeColorimetric");
params['/Intent'] = PdfStream.string('/RelativeColorimetric');
}
}
/// RGBA Image Data
final Uint8List image;
/// Image width
final int width;
/// Image height
final int height;
/// Image has alpha channel
final bool alpha;
String _name;
/// Process alphaChannel only
final bool alphaChannel;
/// The image data is a jpeg image
final bool jpeg;
/// write the pixels to the stream
@override
void _prepare() {
if (jpeg) {
buf.putBytes(image);
params["/Filter"] = PdfStream.string("/DCTDecode");
params['/Filter'] = PdfStream.string('/DCTDecode');
super._prepare();
return;
}
int w = width;
int h = height;
int s = w * h;
final int w = width;
final int h = height;
final int s = w * h;
Uint8List out = Uint8List(alphaChannel ? s : s * 3);
final Uint8List out = Uint8List(alphaChannel ? s : s * 3);
if (alphaChannel) {
for (int i = 0; i < s; i++) {
... ...
/*
* Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
... ... @@ -17,14 +17,6 @@
part of pdf;
class PdfInfo extends PdfObject {
static const String _libraryName = "https://github.com/DavBfr/dart_pdf";
final String author;
final String creator;
final String title;
final String subject;
final String keywords;
final String producer;
/// @param title Title of this document
PdfInfo(PdfDocument pdfDocument,
{this.title,
... ... @@ -35,25 +27,39 @@ class PdfInfo extends PdfObject {
this.producer})
: super(pdfDocument, null) {
if (author != null) {
params["/Author"] = PdfStream()..putLiteral(author);
params['/Author'] = PdfStream()..putLiteral(author);
}
if (creator != null) {
params["/Creator"] = PdfStream()..putLiteral(creator);
params['/Creator'] = PdfStream()..putLiteral(creator);
}
if (title != null) {
params["/Title"] = PdfStream()..putLiteral(title);
params['/Title'] = PdfStream()..putLiteral(title);
}
if (subject != null) {
params["/Subject"] = PdfStream()..putLiteral(subject);
params['/Subject'] = PdfStream()..putLiteral(subject);
}
if (keywords != null) {
params["/Keywords"] = PdfStream()..putLiteral(keywords);
params['/Keywords'] = PdfStream()..putLiteral(keywords);
}
if (producer != null) {
params["/Producer"] = PdfStream()
..putLiteral("$producer ($_libraryName)");
params['/Producer'] = PdfStream()
..putLiteral('$producer ($_libraryName)');
} else {
params["/Producer"] = PdfStream()..putLiteral(_libraryName);
params['/Producer'] = PdfStream()..putLiteral(_libraryName);
}
}
static const String _libraryName = 'https://github.com/DavBfr/dart_pdf';
final String author;
final String creator;
final String title;
final String subject;
final String keywords;
final String producer;
}
... ...
... ... @@ -17,30 +17,30 @@
part of pdf;
class PdfObject {
/// This is the object parameters.
final params = 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);
params['/Type'] = PdfStream.string(type);
}
pdfDocument.objects.add(this);
}
/// This is the object parameters.
final Map<String, PdfStream> params = <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;
/// Writes the object to the output stream.
/// This method must be overridden.
///
... ... @@ -66,13 +66,13 @@ class PdfObject {
///
/// @param os OutputStream to write to
void _writeStart(PdfStream os) {
os.putString("$objser $objgen obj\n");
os.putString('$objser $objgen obj\n');
}
void _writeContent(PdfStream os) {
if (params.isNotEmpty) {
os.putDictionary(params);
os.putString("\n");
os.putString('\n');
}
}
... ... @@ -83,10 +83,10 @@ class PdfObject {
///
/// @param os OutputStream to write to
void _writeEnd(PdfStream os) {
os.putString("endobj\n");
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");
PdfStream ref() => PdfStream.string('$objser $objgen R');
}
... ...
... ... @@ -17,12 +17,6 @@
part of pdf;
class PdfObjectStream extends PdfObject {
/// This holds the stream's content.
final PdfStream buf = 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]).
... ... @@ -33,36 +27,42 @@ class PdfObjectStream extends PdfObject {
PdfObjectStream(PdfDocument pdfDocument, {String type, this.isBinary = false})
: super(pdfDocument, type);
/// This holds the stream's content.
final PdfStream buf = PdfStream();
/// defines if the stream needs to be converted to ascii85
final bool isBinary;
List<int> _data;
@override
void _prepare() {
super._prepare();
if (params.containsKey("/Filter")) {
if (params.containsKey('/Filter')) {
// The data is already in the right format
_data = buf.output();
} else if (pdfDocument.deflate != null) {
_data = pdfDocument.deflate(buf.output());
params["/Filter"] = PdfStream.string("/FlateDecode");
params['/Filter'] = PdfStream.string('/FlateDecode');
} else if (isBinary) {
// This is a Ascii85 stream
var e = Ascii85Encoder();
final Ascii85Encoder e = Ascii85Encoder();
_data = e.convert(buf.output());
params["/Filter"] = PdfStream.string("/ASCII85Decode");
params['/Filter'] = PdfStream.string('/ASCII85Decode');
} else {
// This is a non-deflated stream
_data = buf.output();
}
params["/Length"] = PdfStream.intNum(_data.length);
params['/Length'] = PdfStream.intNum(_data.length);
}
@override
void _writeContent(PdfStream os) {
super._writeContent(os);
os.putString("stream\n");
os.putString('stream\n');
os.putBytes(_data);
os.putString("\nendstream\n");
os.putString('\nendstream\n');
}
}
... ...
... ... @@ -25,8 +25,17 @@ enum PdfOutlineMode {
}
class PdfOutline extends PdfObject {
/// Constructs a Pdf Outline object. When selected, the specified region
/// is displayed.
///
/// @param title Title of the outline
/// @param dest The destination page
/// @param rect coordinate
PdfOutline(PdfDocument pdfDocument, {this.title, this.dest, this.rect})
: super(pdfDocument, '/Outlines');
/// This holds any outlines below us
List<PdfOutline> outlines = [];
List<PdfOutline> outlines = <PdfOutline>[];
/// For subentries, this points to it's parent outline
PdfOutline parent;
... ... @@ -43,15 +52,6 @@ class PdfOutline extends PdfObject {
/// How the destination is handled
PdfOutlineMode destMode = PdfOutlineMode.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 rect coordinate
PdfOutline(PdfDocument pdfDocument, {this.title, this.dest, this.rect})
: super(pdfDocument, "/Outlines");
/// This method creates an outline, and attaches it to this one.
/// When the outline is selected, the supplied region is displayed.
///
... ... @@ -71,7 +71,7 @@ class PdfOutline extends PdfObject {
/// @param h height of region in User space
/// @return [PdfOutline] object created, for creating sub-outlines
PdfOutline add({String title, PdfPage dest, PdfRect rect}) {
PdfOutline outline =
final PdfOutline outline =
PdfOutline(pdfDocument, title: title, dest: dest, rect: rect);
// Tell the outline of ourselves
outline.parent = this;
... ... @@ -85,49 +85,49 @@ class PdfOutline extends PdfObject {
// These are for kids only
if (parent != null) {
params["/Title"] = PdfStream.string(title);
var dests = List<PdfStream>();
params['/Title'] = PdfStream.string(title);
final List<PdfStream> dests = <PdfStream>[];
dests.add(dest.ref());
if (destMode == PdfOutlineMode.fitpage) {
dests.add(PdfStream.string("/Fit"));
dests.add(PdfStream.string('/Fit'));
} else {
dests.add(PdfStream.string(
"/FitR ${rect.left} ${rect.bottom} ${rect.right} ${rect.top}"));
'/FitR ${rect.left} ${rect.bottom} ${rect.right} ${rect.top}'));
}
params["/Parent"] = parent.ref();
params["/Dest"] = PdfStream.array(dests);
params['/Parent'] = parent.ref();
params['/Dest'] = PdfStream.array(dests);
// were a descendent, so by default we are closed. Find out how many
// entries are below us
int c = descendants();
final int c = descendants();
if (c > 0) {
params["/Count"] = PdfStream.intNum(-c);
params['/Count'] = PdfStream.intNum(-c);
}
int index = parent.getIndex(this);
final 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();
params['/Prev'] = parent.getNode(index - 1).ref();
}
if (index < parent.getLast()) {
// We have a /Next node
params["/Next"] = parent.getNode(index + 1).ref();
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);
params['/Count'] = PdfStream.intNum(outlines.length);
}
// These only valid if we have children
if (outlines.isNotEmpty) {
// the number of the first outline in list
params["/First"] = outlines[0].ref();
params['/First'] = outlines[0].ref();
// the number of the last outline in list
params["/Last"] = outlines[outlines.length - 1].ref();
params['/Last'] = outlines[outlines.length - 1].ref();
}
}
... ...
... ... @@ -17,11 +17,19 @@
part of pdf;
class PdfOutput {
/// 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(const <int>[0x25, 0xC2, 0xA5, 0xC2, 0xB1, 0xC3, 0xAB, 0x0A]);
}
/// This is the actual [PdfStream] used to write to.
final PdfStream os;
/// This vector contains offsets of each object
List<PdfXref> offsets = [];
List<PdfXref> offsets = <PdfXref>[];
/// This is used to track the /Root object (catalog)
PdfObject rootID;
... ... @@ -29,22 +37,18 @@ class PdfOutput {
/// 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] Object 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;
if (ob is PdfCatalog) {
rootID = ob;
}
if (ob is PdfInfo) {
infoID = ob;
}
offsets.add(PdfXref(ob.objser, os.offset));
ob._write(os);
... ... @@ -52,9 +56,9 @@ class PdfOutput {
/// This closes the Stream, writing the xref table
void close() {
int xref = os.offset;
final int xref = os.offset;
os.putString("xref\n");
os.putString('xref\n');
// Now a single subsection for object 0
//os.write("0 1\n0000000000 65535 f \n");
... ... @@ -63,19 +67,21 @@ class PdfOutput {
// but just in case:
int firstid = 0; // First id in block
int lastid = -1; // The last id used
var block = []; // xrefs in this block
final List<PdfXref> block = <PdfXref>[]; // xrefs in this block
// We need block 0 to exist
block.add(PdfXref(0, 0, generation: 65535));
for (PdfXref x in offsets) {
if (firstid == -1) firstid = x.id;
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 = [];
block.clear();
firstid = -1;
}
... ... @@ -85,45 +91,46 @@ class PdfOutput {
}
// now write the last block
if (firstid > -1) writeblock(firstid, block);
if (firstid > -1) {
writeblock(firstid, block);
}
// now the trailer object
os.putString("trailer\n<<\n");
os.putString('trailer\n<<\n');
// the number of entries (REQUIRED)
os.putString("/Size ");
os.putString('/Size ');
os.putString((offsets.length + 1).toString());
os.putString("\n");
os.putString('\n');
// the /Root catalog indirect reference (REQUIRED)
if (rootID != null) {
os.putString("/Root ");
os.putString('/Root ');
os.putStream(rootID.ref());
os.putString("\n");
os.putString('\n');
} else
throw Exception("Root object is not present in document");
throw Exception('Root object is not present in document');
// the /Info reference (OPTIONAL)
if (infoID != null) {
os.putString("/Info ");
os.putString('/Info ');
os.putStream(infoID.ref());
os.putString("\n");
os.putString('\n');
}
// end the trailer object
os.putString(">>\nstartxref\n$xref\n%%EOF\n");
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");
void writeblock(int firstid, List<PdfXref> block) {
os.putString('$firstid ${block.length}\n');
for (PdfXref x in block) {
os.putString(x.ref());
os.putString("\n");
os.putString('\n');
}
}
}
... ...
... ... @@ -17,36 +17,36 @@
part of pdf;
class PdfPage extends PdfObject {
/// This constructs a Page object, which will hold any contents for this
/// page.
///
/// Once created, it is added to the document via the [PdfDocument.add()] method.
///
/// @param pdfDocument Document
/// @param pageFormat [PdfPageFormat] describing the page size
PdfPage(PdfDocument pdfDocument, {this.pageFormat = PdfPageFormat.a4})
: super(pdfDocument, '/Page') {
pdfDocument.pdfPageList.pages.add(this);
}
/// This is this page format, ie the size of the page, margins, and rotation
final PdfPageFormat pageFormat;
/// This holds the contents of the page.
List<PdfObjectStream> contents = [];
List<PdfObjectStream> contents = <PdfObjectStream>[];
/// 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 = [];
List<PdfAnnot> annotations = <PdfAnnot>[];
/// The fonts associated with this page
final fonts = Map<String, PdfFont>();
final Map<String, PdfFont> fonts = <String, PdfFont>{};
/// The xobjects or other images in the pdf
final xObjects = Map<String, PdfXObject>();
/// This constructs a Page object, which will hold any contents for this
/// page.
///
/// Once created, it is added to the document via the [PdfDocument.add()] method.
///
/// @param pdfDocument Document
/// @param pageFormat [PdfPageFormat] describing the page size
PdfPage(PdfDocument pdfDocument, {this.pageFormat = PdfPageFormat.a4})
: super(pdfDocument, "/Page") {
pdfDocument.pdfPageList.pages.add(this);
}
final Map<String, PdfXObject> xObjects = <String, PdfXObject>{};
/// 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
... ... @@ -55,8 +55,8 @@ class PdfPage extends PdfObject {
///
/// @return a new [PdfGraphics] object to be used to draw this page.
PdfGraphics getGraphics() {
var stream = PdfObjectStream(pdfDocument);
var g = PdfGraphics(this, stream.buf);
final PdfObjectStream stream = PdfObjectStream(pdfDocument);
final PdfGraphics g = PdfGraphics(this, stream.buf);
contents.add(stream);
return g;
}
... ... @@ -77,11 +77,11 @@ class PdfPage extends PdfObject {
super._prepare();
// the /Parent pages object
params["/Parent"] = pdfDocument.pdfPageList.ref();
params['/Parent'] = pdfDocument.pdfPageList.ref();
// the /MediaBox for the page size
params["/MediaBox"] = PdfStream()
..putStringArray([0, 0, pageFormat.width, pageFormat.height]);
params['/MediaBox'] = PdfStream()
..putNumArray(<double>[0.0, 0.0, pageFormat.width, pageFormat.height]);
// Rotation (if not zero)
// if(rotate!=0) {
... ... @@ -93,36 +93,36 @@ class PdfPage extends PdfObject {
// the /Contents pages object
if (contents.isNotEmpty) {
if (contents.length == 1) {
params["/Contents"] = contents[0].ref();
params['/Contents'] = contents[0].ref();
} else {
params["/Contents"] = PdfStream()..putObjectArray(contents);
params['/Contents'] = PdfStream()..putObjectArray(contents);
}
}
// Now the resources
/// This holds any resources for this page
final resources = Map<String, PdfStream>();
final Map<String, PdfStream> resources = <String, PdfStream>{};
// fonts
if (fonts.isNotEmpty) {
resources["/Font"] = PdfStream()..putObjectDictionary(fonts);
resources['/Font'] = PdfStream()..putObjectDictionary(fonts);
}
// Now the XObjects
if (xObjects.isNotEmpty) {
resources["/XObject"] = PdfStream()..putObjectDictionary(xObjects);
resources['/XObject'] = PdfStream()..putObjectDictionary(xObjects);
}
params["/Resources"] = PdfStream.dictionary(resources);
params['/Resources'] = PdfStream.dictionary(resources);
// The thumbnail
if (thumbnail != null) {
params["/Thumb"] = thumbnail.ref();
params['/Thumb'] = thumbnail.ref();
}
// The /Annots object
if (annotations.isNotEmpty) {
params["/Annots"] = PdfStream()..putObjectArray(annotations);
params['/Annots'] = PdfStream()..putObjectArray(annotations);
}
}
}
... ...
... ... @@ -17,25 +17,6 @@
part of pdf;
class PdfPageFormat {
static const a3 = PdfPageFormat(29.7 * cm, 42 * cm, marginAll: 2.0 * cm);
static const a4 = PdfPageFormat(21.0 * cm, 29.7 * cm, marginAll: 2.0 * cm);
static const a5 = PdfPageFormat(14.8 * cm, 21.0 * cm, marginAll: 2.0 * cm);
static const letter = PdfPageFormat(8.5 * inch, 11.0 * inch, marginAll: inch);
static const legal = PdfPageFormat(8.5 * inch, 14.0 * inch, marginAll: inch);
static const point = 1.0;
static const inch = 72.0;
static const cm = inch / 2.54;
static const mm = inch / 25.4;
final double width;
final double height;
final double marginTop;
final double marginBottom;
final double marginLeft;
final double marginRight;
const PdfPageFormat(this.width, this.height,
{double marginTop = 0.0,
double marginBottom = 0.0,
... ... @@ -47,6 +28,30 @@ class PdfPageFormat {
marginLeft = marginAll ?? marginLeft,
marginRight = marginAll ?? marginRight;
static const PdfPageFormat a3 =
PdfPageFormat(29.7 * cm, 42 * cm, marginAll: 2.0 * cm);
static const PdfPageFormat a4 =
PdfPageFormat(21.0 * cm, 29.7 * cm, marginAll: 2.0 * cm);
static const PdfPageFormat a5 =
PdfPageFormat(14.8 * cm, 21.0 * cm, marginAll: 2.0 * cm);
static const PdfPageFormat letter =
PdfPageFormat(8.5 * inch, 11.0 * inch, marginAll: inch);
static const PdfPageFormat legal =
PdfPageFormat(8.5 * inch, 14.0 * inch, marginAll: inch);
static const double point = 1.0;
static const double inch = 72.0;
static const double cm = inch / 2.54;
static const double mm = inch / 25.4;
final double width;
final double height;
final double marginTop;
final double marginBottom;
final double marginLeft;
final double marginRight;
PdfPageFormat copyWith(
{double width,
double height,
... ... @@ -80,6 +85,6 @@ class PdfPageFormat {
@override
String toString() {
return "${width}x$height";
return '${width}x$height';
}
}
... ...
... ... @@ -17,11 +17,11 @@
part of pdf;
class PdfPageList extends PdfObject {
/// This holds the pages
final List<PdfPage> pages = [];
/// This constructs a [PdfPageList] object.
PdfPageList(PdfDocument pdfDocument) : super(pdfDocument, "/Pages");
PdfPageList(PdfDocument pdfDocument) : super(pdfDocument, '/Pages');
/// This holds the pages
final List<PdfPage> pages = <PdfPage>[];
/// This returns a specific page. Used by the Pdf class.
/// @param page page number to return
... ... @@ -32,7 +32,7 @@ class PdfPageList extends PdfObject {
void _prepare() {
super._prepare();
params["/Kids"] = PdfStream()..putObjectArray(pages);
params["/Count"] = PdfStream.intNum(pages.length);
params['/Kids'] = PdfStream()..putObjectArray(pages);
params['/Count'] = PdfStream.intNum(pages.length);
}
}
... ...
... ... @@ -18,6 +18,8 @@ part of pdf;
@immutable
class PdfPoint {
const PdfPoint(this.x, this.y);
final double x, y;
@deprecated
... ... @@ -26,10 +28,8 @@ class PdfPoint {
@deprecated
double get h => y;
const PdfPoint(this.x, this.y);
static const zero = PdfPoint(0.0, 0.0);
static const PdfPoint zero = PdfPoint(0.0, 0.0);
@override
String toString() => "PdfPoint($x, $y)";
String toString() => 'PdfPoint($x, $y)';
}
... ...
... ... @@ -17,12 +17,12 @@
part of pdf;
class PdfPolygon {
List<PdfPoint> points;
PdfPolygon(this.points);
List<PdfPoint> points;
PdfRect getBounds() {
// TODO: Implement properly
// TODO(me): Implement properly
return const PdfRect(0.0, 0.0, 0.0, 0.0);
}
}
... ...
... ... @@ -18,10 +18,6 @@ part of pdf;
@immutable
class PdfRect {
final double x, y, width, height;
static const zero = PdfRect(0.0, 0.0, 0.0, 0.0);
const PdfRect(this.x, this.y, this.width, this.height);
factory PdfRect.fromLTRB(
... ... @@ -33,6 +29,10 @@ class PdfRect {
return PdfRect(offset.x, offset.y, size.x, size.y);
}
final double x, y, width, height;
static const PdfRect zero = PdfRect(0.0, 0.0, 0.0, 0.0);
double get left => x;
double get bottom => y;
double get right => x + width;
... ... @@ -52,7 +52,7 @@ class PdfRect {
double get h => height;
@override
String toString() => "PdfRect($x, $y, $width, $height)";
String toString() => 'PdfRect($x, $y, $width, $height)';
PdfRect operator *(double factor) {
return PdfRect(x * factor, y * factor, width * factor, height * factor);
... ...
... ... @@ -17,8 +17,8 @@
part of pdf;
class PdfStream {
static const precision = 5;
final _stream = List<int>();
static const int precision = 5;
final List<int> _stream = <int>[];
void putStream(PdfStream s) {
_stream.addAll(s._stream);
... ... @@ -52,7 +52,11 @@ class PdfStream {
}
void putNumList(List<double> d) {
putString(d.map((v) => v.toStringAsFixed(precision)).join(" "));
putString(d.map((double v) => v.toStringAsFixed(precision)).join(' '));
}
void putIntList(List<int> d) {
putString(d.map((int v) => v.toString()).join(' '));
}
static PdfStream num(double d) => PdfStream()..putNum(d);
... ... @@ -61,7 +65,7 @@ class PdfStream {
/// Escape special characters
/// \ddd Character code ddd (octal)
void putTextBytes(List<int> s) {
for (var c in s) {
for (int c in s) {
switch (c) {
case 0x0a: // \n Line feed (LF)
_stream.add(0x5c);
... ... @@ -109,61 +113,73 @@ class PdfStream {
void putLiteral(String s) {
putBytes(latin1.encode('('));
putBytes([0xfe, 0xff]);
putBytes(<int>[0xfe, 0xff]);
putTextBytes(encodeUtf16be(s));
putBytes(latin1.encode(')'));
}
void putBool(bool value) {
putString(value ? "true" : "false");
putString(value ? 'true' : 'false');
}
void putArray(List<PdfStream> values) {
putString("[");
for (var val in values) {
putString('[');
for (PdfStream val in values) {
putStream(val);
putString(" ");
putString(' ');
}
putString("]");
putString(']');
}
void putObjectArray(List<PdfObject> values) {
putString("[");
for (var val in values) {
putString('[');
for (PdfObject val in values) {
putStream(val.ref());
putString(" ");
putString(' ');
}
putString("]");
putString(']');
}
void putStringArray(List<String> values) {
putString('[' + values.join(' ') + ']');
}
void putNumArray(List<double> values) {
putString('[');
putNumList(values);
putString(']');
}
void putStringArray(List<dynamic> values) {
putString("[" + values.join(" ") + "]");
void putIntArray(List<int> values) {
putString('[');
putIntList(values);
putString(']');
}
static PdfStream array(List<PdfStream> values) =>
PdfStream()..putArray(values);
void putDictionary(Map<String, PdfStream> values) {
putString("<< ");
values.forEach((k, v) {
putString("$k ");
putString('<< ');
values.forEach((String k, PdfStream v) {
putString('$k ');
putStream(v);
putString("\n");
putString('\n');
});
putString(">>");
putString('>>');
}
static PdfStream dictionary(Map<String, PdfStream> values) =>
PdfStream()..putDictionary(values);
void putObjectDictionary(Map<String, PdfObject> values) {
putString("<< ");
values.forEach((k, v) {
putString("$k ");
putString('<< ');
values.forEach((String k, PdfObject v) {
putString('$k ');
putStream(v.ref());
putString(" ");
putString(' ');
});
putString(">>");
putString('>>');
}
int get offset => _stream.length;
... ...
... ... @@ -17,29 +17,12 @@
part of pdf;
class TtfParser {
static const _HEAD = "head";
static const _NAME = "name";
static const _HMTX = "hmtx";
static const _HHEA = "hhea";
static const _CMAP = "cmap";
static const _MAXP = "maxp";
static const _LOCA = "loca";
static const _GLYF = "glyf";
final ByteData bytes;
final _tableOffsets = Map<String, int>();
String _fontName;
final advanceWidth = List<double>();
final charToGlyphIndexMap = Map<int, int>();
final glyphOffsets = List<int>();
final glyphInfoMap = Map<int, PdfRect>();
TtfParser(this.bytes) {
final numTables = bytes.getUint16(4);
final int numTables = bytes.getUint16(4);
for (var i = 0; i < numTables; i++) {
final name = utf8.decode(bytes.buffer.asUint8List(i * 16 + 12, 4));
final offset = bytes.getUint32(i * 16 + 20);
for (int i = 0; i < numTables; i++) {
final String name = utf8.decode(bytes.buffer.asUint8List(i * 16 + 12, 4));
final int offset = bytes.getUint32(i * 16 + 20);
_tableOffsets[name] = offset;
}
... ... @@ -50,38 +33,55 @@ class TtfParser {
_parseGlyf();
}
get unitsPerEm => bytes.getUint16(_tableOffsets[_HEAD] + 18);
static const String _HEAD = 'head';
static const String _NAME = 'name';
static const String _HMTX = 'hmtx';
static const String _HHEA = 'hhea';
static const String _CMAP = 'cmap';
static const String _MAXP = 'maxp';
static const String _LOCA = 'loca';
static const String _GLYF = 'glyf';
final ByteData bytes;
final Map<String, int> _tableOffsets = <String, int>{};
String _fontName;
final List<double> advanceWidth = <double>[];
final Map<int, int> charToGlyphIndexMap = <int, int>{};
final List<int> glyphOffsets = <int>[];
final Map<int, PdfRect> glyphInfoMap = <int, PdfRect>{};
int get unitsPerEm => bytes.getUint16(_tableOffsets[_HEAD] + 18);
get xMin => bytes.getInt16(_tableOffsets[_HEAD] + 36);
int get xMin => bytes.getInt16(_tableOffsets[_HEAD] + 36);
get yMin => bytes.getInt16(_tableOffsets[_HEAD] + 38);
int get yMin => bytes.getInt16(_tableOffsets[_HEAD] + 38);
get xMax => bytes.getInt16(_tableOffsets[_HEAD] + 40);
int get xMax => bytes.getInt16(_tableOffsets[_HEAD] + 40);
get yMax => bytes.getInt16(_tableOffsets[_HEAD] + 42);
int get yMax => bytes.getInt16(_tableOffsets[_HEAD] + 42);
get indexToLocFormat => bytes.getInt16(_tableOffsets[_HEAD] + 50);
int get indexToLocFormat => bytes.getInt16(_tableOffsets[_HEAD] + 50);
get ascent => bytes.getInt16(_tableOffsets[_HHEA] + 4);
int get ascent => bytes.getInt16(_tableOffsets[_HHEA] + 4);
get descent => bytes.getInt16(_tableOffsets[_HHEA] + 6);
int get descent => bytes.getInt16(_tableOffsets[_HHEA] + 6);
get numOfLongHorMetrics => bytes.getInt16(_tableOffsets[_HHEA] + 34);
int get numOfLongHorMetrics => bytes.getInt16(_tableOffsets[_HHEA] + 34);
get numGlyphs => bytes.getInt16(_tableOffsets[_MAXP] + 4);
int get numGlyphs => bytes.getInt16(_tableOffsets[_MAXP] + 4);
get fontName => _fontName;
String get fontName => _fontName;
void _parseFontName() {
final basePosition = _tableOffsets[_NAME];
final count = bytes.getUint16(basePosition + 2);
final stringOffset = bytes.getUint16(basePosition + 4);
final int basePosition = _tableOffsets[_NAME];
final int count = bytes.getUint16(basePosition + 2);
final int stringOffset = bytes.getUint16(basePosition + 4);
int pos = basePosition + 6;
for (var i = 0; i < count; i++) {
int platformID = bytes.getUint16(pos);
int nameID = bytes.getUint16(pos + 6);
int length = bytes.getUint16(pos + 8);
int offset = bytes.getUint16(pos + 10);
for (int i = 0; i < count; i++) {
final int platformID = bytes.getUint16(pos);
final int nameID = bytes.getUint16(pos + 6);
final int length = bytes.getUint16(pos + 8);
final int offset = bytes.getUint16(pos + 10);
pos += 12;
if (platformID == 1 && nameID == 6) {
_fontName = utf8.decode(bytes.buffer
... ... @@ -93,20 +93,20 @@ class TtfParser {
}
void _parseHmtx() {
final offset = _tableOffsets[_HMTX];
final unitsPerEm = this.unitsPerEm;
for (var i = 0; i < numOfLongHorMetrics; i++) {
final int offset = _tableOffsets[_HMTX];
final int unitsPerEm = this.unitsPerEm;
for (int i = 0; i < numOfLongHorMetrics; i++) {
advanceWidth.add(bytes.getInt16(offset + i * 4).toDouble() / unitsPerEm);
}
}
void _parseCMap() {
final basePosition = _tableOffsets[_CMAP];
final numSubTables = bytes.getUint16(basePosition + 2);
for (var i = 0; i < numSubTables; i++) {
final offset = bytes.getUint32(basePosition + i * 8 + 8);
final format = bytes.getUint16(basePosition + offset);
final length = bytes.getUint16(basePosition + offset + 2);
final int basePosition = _tableOffsets[_CMAP];
final int numSubTables = bytes.getUint16(basePosition + 2);
for (int i = 0; i < numSubTables; i++) {
final int offset = bytes.getUint32(basePosition + i * 8 + 8);
final int format = bytes.getUint16(basePosition + offset);
final int length = bytes.getUint16(basePosition + offset + 2);
switch (format) {
case 0:
... ... @@ -125,9 +125,9 @@ class TtfParser {
void _parseCMapFormat0(int basePosition, int length) {
assert(length == 262);
for (var i = 0; i < 256; i++) {
int charCode = i;
int glyphIndex = bytes.getUint8(basePosition + i);
for (int i = 0; i < 256; i++) {
final int charCode = i;
final int glyphIndex = bytes.getUint8(basePosition + i);
if (glyphIndex > 0) {
charToGlyphIndexMap[charCode] = glyphIndex;
}
... ... @@ -135,36 +135,36 @@ class TtfParser {
}
void _parseCMapFormat4(int basePosition, int length) {
final segCount = bytes.getUint16(basePosition + 2) ~/ 2;
final endCodes = List<int>();
for (var i = 0; i < segCount; i++) {
final int segCount = bytes.getUint16(basePosition + 2) ~/ 2;
final List<int> endCodes = <int>[];
for (int i = 0; i < segCount; i++) {
endCodes.add(bytes.getUint16(basePosition + i * 2 + 10));
}
final startCodes = List<int>();
for (var i = 0; i < segCount; i++) {
final List<int> startCodes = <int>[];
for (int i = 0; i < segCount; i++) {
startCodes.add(bytes.getUint16(basePosition + (segCount + i) * 2 + 12));
}
final idDeltas = List<int>();
for (var i = 0; i < segCount; i++) {
final List<int> idDeltas = <int>[];
for (int i = 0; i < segCount; i++) {
idDeltas.add(bytes.getUint16(basePosition + (segCount * 2 + i) * 2 + 12));
}
final idRangeOffsetBasePos = basePosition + segCount * 6 + 12;
final idRangeOffsets = List<int>();
for (var i = 0; i < segCount; i++) {
final int idRangeOffsetBasePos = basePosition + segCount * 6 + 12;
final List<int> idRangeOffsets = <int>[];
for (int i = 0; i < segCount; i++) {
idRangeOffsets.add(bytes.getUint16(idRangeOffsetBasePos + i * 2));
}
for (var s = 0; s < segCount - 1; s++) {
final startCode = startCodes[s];
final endCode = endCodes[s];
final idDelta = idDeltas[s];
final idRangeOffset = idRangeOffsets[s];
final idRangeOffsetAddress = idRangeOffsetBasePos + s * 2;
for (var c = startCode; c <= endCode; c++) {
var glyphIndex;
for (int s = 0; s < segCount - 1; s++) {
final int startCode = startCodes[s];
final int endCode = endCodes[s];
final int idDelta = idDeltas[s];
final int idRangeOffset = idRangeOffsets[s];
final int idRangeOffsetAddress = idRangeOffsetBasePos + s * 2;
for (int c = startCode; c <= endCode; c++) {
int glyphIndex;
if (idRangeOffset == 0) {
glyphIndex = (idDelta + c) % 65536;
} else {
final glyphIndexAddress =
final int glyphIndexAddress =
idRangeOffset + 2 * (c - startCode) + idRangeOffsetAddress;
glyphIndex = bytes.getUint16(glyphIndexAddress);
}
... ... @@ -174,11 +174,11 @@ class TtfParser {
}
void _parseCMapFormat6(int basePosition, int length) {
final firstCode = bytes.getUint16(basePosition + 2);
final entryCount = bytes.getUint16(basePosition + 4);
for (var i = 0; i < entryCount; i++) {
final charCode = firstCode + i;
final glyphIndex = bytes.getUint16(basePosition + i * 2 + 6);
final int firstCode = bytes.getUint16(basePosition + 2);
final int entryCount = bytes.getUint16(basePosition + 4);
for (int i = 0; i < entryCount; i++) {
final int charCode = firstCode + i;
final int glyphIndex = bytes.getUint16(basePosition + i * 2 + 6);
if (glyphIndex > 0) {
charToGlyphIndexMap[charCode] = glyphIndex;
}
... ... @@ -186,28 +186,28 @@ class TtfParser {
}
void _parseIndexes() {
final basePosition = _tableOffsets[_LOCA];
final numGlyphs = this.numGlyphs;
final int basePosition = _tableOffsets[_LOCA];
final int numGlyphs = this.numGlyphs;
if (indexToLocFormat == 0) {
for (var i = 0; i < numGlyphs; i++) {
for (int i = 0; i < numGlyphs; i++) {
glyphOffsets.add(bytes.getUint16(basePosition + i * 2) * 2);
}
} else {
for (var i = 0; i < numGlyphs; i++) {
for (int i = 0; i < numGlyphs; i++) {
glyphOffsets.add(bytes.getUint32(basePosition + i * 4));
}
}
}
void _parseGlyf() {
final baseOffset = _tableOffsets[_GLYF];
final unitsPerEm = this.unitsPerEm;
final int baseOffset = _tableOffsets[_GLYF];
final int unitsPerEm = this.unitsPerEm;
int glyphIndex = 0;
for (var offset in glyphOffsets) {
final xMin = bytes.getInt16(baseOffset + offset + 2); // 2
final yMin = bytes.getInt16(baseOffset + offset + 4); // 4
final xMax = bytes.getInt16(baseOffset + offset + 6); // 6
final yMax = bytes.getInt16(baseOffset + offset + 8); // 8
for (int offset in glyphOffsets) {
final int xMin = bytes.getInt16(baseOffset + offset + 2); // 2
final int yMin = bytes.getInt16(baseOffset + offset + 4); // 4
final int xMax = bytes.getInt16(baseOffset + offset + 6); // 6
final int yMax = bytes.getInt16(baseOffset + offset + 8); // 8
glyphInfoMap[glyphIndex] = PdfRect(
xMin.toDouble() / unitsPerEm,
yMin.toDouble() / unitsPerEm,
... ...
... ... @@ -17,27 +17,19 @@
part of pdf;
class PdfTtfFont extends PdfFont {
PdfObject unicodeCMap;
PdfFontDescriptor descriptor;
PdfArrayObject widthsObject;
final widths = List<String>();
final TtfParser font;
int _charMin;
int _charMax;
/// Constructs a [PdfTtfFont]
PdfTtfFont(PdfDocument pdfDocument, ByteData bytes)
: font = TtfParser(bytes),
super._create(pdfDocument, subtype: "/TrueType") {
PdfObjectStream file = PdfObjectStream(pdfDocument, isBinary: true);
final data = bytes.buffer.asUint8List();
super._create(pdfDocument, subtype: '/TrueType') {
final PdfObjectStream file = PdfObjectStream(pdfDocument, isBinary: true);
final Uint8List data = bytes.buffer.asUint8List();
file.buf.putBytes(data);
file.params["/Length1"] = PdfStream.intNum(data.length);
file.params['/Length1'] = PdfStream.intNum(data.length);
_charMin = 32;
_charMax = 255;
for (var i = _charMin; i <= _charMax; i++) {
for (int i = _charMin; i <= _charMax; i++) {
widths.add((glyphAdvance(i) * 1000.0).toString());
}
... ... @@ -46,12 +38,26 @@ class PdfTtfFont extends PdfFont {
widthsObject = PdfArrayObject(pdfDocument, widths);
}
PdfObject unicodeCMap;
PdfFontDescriptor descriptor;
PdfArrayObject widthsObject;
final List<String> widths = <String>[];
final TtfParser font;
int _charMin;
int _charMax;
@override
String get fontName => "/" + font.fontName.replaceAll(" ", "");
String get fontName => '/' + font.fontName.replaceAll(' ', '');
@override
double glyphAdvance(int charCode) {
var g = font.charToGlyphIndexMap[charCode];
final int g = font.charToGlyphIndexMap[charCode];
if (g == null) {
return super.glyphAdvance(charCode);
... ... @@ -63,7 +69,7 @@ class PdfTtfFont extends PdfFont {
@override
PdfRect glyphBounds(int charCode) {
var g = font.charToGlyphIndexMap[charCode];
final int g = font.charToGlyphIndexMap[charCode];
if (g == null) {
return super.glyphBounds(charCode);
... ... @@ -76,12 +82,12 @@ class PdfTtfFont extends PdfFont {
void _prepare() {
super._prepare();
params["/BaseFont"] = PdfStream.string(fontName);
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();
params['/BaseFont'] = PdfStream.string(fontName);
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();
}
}
... ...
... ... @@ -17,23 +17,27 @@
part of pdf;
class PdfType1Font extends PdfFont {
/// Constructs a [PdfTtfFont]
PdfType1Font._create(PdfDocument pdfDocument, this.fontName, this.ascent,
this.descent, this.widths)
: super._create(pdfDocument, subtype: '/Type1');
/// The font's real name
@override
final String fontName;
final double ascent;
final double descent;
final List<double> widths;
/// Constructs a [PdfTtfFont]
PdfType1Font._create(PdfDocument pdfDocument, this.fontName, this.ascent,
this.descent, this.widths)
: super._create(pdfDocument, subtype: "/Type1") {}
final List<double> widths;
/// @param os OutputStream to send the object to
@override
void _prepare() {
super._prepare();
params["/BaseFont"] = PdfStream.string("/" + fontName);
params['/BaseFont'] = PdfStream.string('/' + fontName);
}
@override
... ...
... ... @@ -17,6 +17,12 @@
part of pdf;
class PdfXref {
/// Creates a cross-reference 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});
/// The id of a Pdf Object
int id;
... ... @@ -26,19 +32,15 @@ class PdfXref {
/// The generation of the object, usually 0
int generation = 0;
/// Creates a cross-reference 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') +
" " +
final String rs = offset.toString().padLeft(10, '0') +
' ' +
generation.toString().padLeft(5, '0');
if (generation == 65535) return rs + " f ";
return rs + " n ";
if (generation == 65535) {
return rs + ' f ';
}
return rs + ' n ';
}
}
... ...
... ... @@ -45,7 +45,7 @@ class LimitedBox extends SingleChildWidget {
@override
void layout(Context context, BoxConstraints constraints,
{parentUsesSize = false}) {
{bool parentUsesSize = false}) {
PdfPoint size;
if (child != null) {
child.layout(context, _limitConstraints(constraints),
... ... @@ -69,9 +69,9 @@ class Padding extends SingleChildWidget {
@override
void layout(Context context, BoxConstraints constraints,
{parentUsesSize = false}) {
{bool parentUsesSize = false}) {
if (child != null) {
final childConstraints = constraints.deflate(padding);
final BoxConstraints childConstraints = constraints.deflate(padding);
child.layout(context, childConstraints, parentUsesSize: parentUsesSize);
box = constraints.constrainRect(
width: child.box.width + padding.horizontal,
... ... @@ -100,12 +100,14 @@ class Padding extends SingleChildWidget {
@override
void paint(Context context) {
assert(() {
if (Document.debug) debugPaint(context);
if (Document.debug) {
debugPaint(context);
}
return true;
}());
if (child != null) {
final mat = Matrix4.identity();
final Matrix4 mat = Matrix4.identity();
mat.translate(box.x + padding.left, box.y + padding.bottom);
context.canvas
..saveContext()
... ... @@ -163,29 +165,39 @@ class Transform extends SingleChildWidget {
final Alignment alignment;
Matrix4 get _effectiveTransform {
if (origin == null && alignment == null) return transform;
if (origin == null && alignment == null) {
return transform;
}
final Matrix4 result = Matrix4.identity();
if (origin != null) result.translate(origin.x, origin.y);
if (origin != null) {
result.translate(origin.x, origin.y);
}
PdfPoint translation;
if (alignment != null) {
translation = alignment.alongSize(box.size);
result.translate(translation.x, translation.y);
}
result.multiply(transform);
if (alignment != null) result.translate(-translation.x, -translation.y);
if (origin != null) result.translate(-origin.x, -origin.y);
if (alignment != null) {
result.translate(-translation.x, -translation.y);
}
if (origin != null) {
result.translate(-origin.x, -origin.y);
}
return result;
}
@override
void paint(Context context) {
assert(() {
if (Document.debug) debugPaint(context);
if (Document.debug) {
debugPaint(context);
}
return true;
}());
if (child != null) {
final mat = _effectiveTransform;
final Matrix4 mat = _effectiveTransform;
context.canvas
..saveContext()
..setTransform(mat);
... ... @@ -219,7 +231,7 @@ class Align extends SingleChildWidget {
@override
void layout(Context context, BoxConstraints constraints,
{parentUsesSize = false}) {
{bool parentUsesSize = false}) {
final bool shrinkWrapWidth =
widthFactor != null || constraints.maxWidth == double.infinity;
final bool shrinkWrapHeight =
... ... @@ -256,7 +268,7 @@ class ConstrainedBox extends SingleChildWidget {
@override
void layout(Context context, BoxConstraints constraints,
{parentUsesSize = false}) {
{bool parentUsesSize = false}) {
if (child != null) {
child.layout(context, this.constraints.enforce(constraints),
parentUsesSize: true);
... ... @@ -292,7 +304,7 @@ class FittedBox extends SingleChildWidget {
@override
void layout(Context context, BoxConstraints constraints,
{parentUsesSize = false}) {
{bool parentUsesSize = false}) {
PdfPoint size;
if (child != null) {
child.layout(context, const BoxConstraints(), parentUsesSize: true);
... ... @@ -316,7 +328,7 @@ class FittedBox extends SingleChildWidget {
final PdfRect destinationRect =
alignment.inscribe(sizes.destination, box);
final mat =
final Matrix4 mat =
Matrix4.translationValues(destinationRect.x, destinationRect.y, 0.0)
..scale(scaleX, scaleY, 1.0)
..translate(-sourceRect.x, -sourceRect.y);
... ... @@ -341,7 +353,9 @@ class AspectRatio extends SingleChildWidget {
final double aspectRatio;
PdfPoint _applyAspectRatio(BoxConstraints constraints) {
if (constraints.isTight) return constraints.smallest;
if (constraints.isTight) {
return constraints.smallest;
}
double width = constraints.maxWidth;
double height;
... ... @@ -378,7 +392,7 @@ class AspectRatio extends SingleChildWidget {
@override
void layout(Context context, BoxConstraints constraints,
{parentUsesSize = false}) {
{bool parentUsesSize = false}) {
box = PdfRect.fromPoints(PdfPoint.zero, _applyAspectRatio(constraints));
if (child != null)
child.layout(context,
... ... @@ -386,7 +400,7 @@ class AspectRatio extends SingleChildWidget {
}
}
typedef CustomPainter(PdfGraphics canvas, PdfPoint size);
typedef CustomPainter = Function(PdfGraphics canvas, PdfPoint size);
class CustomPaint extends SingleChildWidget {
CustomPaint(
... ... @@ -402,7 +416,7 @@ class CustomPaint extends SingleChildWidget {
@override
void layout(Context context, BoxConstraints constraints,
{parentUsesSize = false}) {
{bool parentUsesSize = false}) {
if (child != null) {
child.layout(context, constraints.tighten(width: size.x, height: size.y),
parentUsesSize: parentUsesSize);
... ... @@ -415,18 +429,26 @@ class CustomPaint extends SingleChildWidget {
@override
void paint(Context context) {
assert(() {
if (Document.debug) debugPaint(context);
if (Document.debug) {
debugPaint(context);
}
return true;
}());
final mat = Matrix4.identity();
final Matrix4 mat = Matrix4.identity();
mat.translate(box.x, box.y);
context.canvas
..saveContext()
..setTransform(mat);
if (painter != null) painter(context.canvas, box.size);
if (child != null) child.paint(context);
if (foregroundPainter != null) foregroundPainter(context.canvas, box.size);
if (painter != null) {
painter(context.canvas, box.size);
}
if (child != null) {
child.paint(context);
}
if (foregroundPainter != null) {
foregroundPainter(context.canvas, box.size);
}
context.canvas.restoreContext();
}
}
... ...
... ... @@ -19,7 +19,7 @@ part of widget;
class ClipRect extends SingleChildWidget {
ClipRect({Widget child}) : super(child: child);
@protected
@override
void debugPaint(Context context) {
context.canvas
..setStrokeColor(PdfColor.deepPurple)
... ... @@ -30,12 +30,14 @@ class ClipRect extends SingleChildWidget {
@override
void paint(Context context) {
assert(() {
if (Document.debug) debugPaint(context);
if (Document.debug) {
debugPaint(context);
}
return true;
}());
if (child != null) {
final mat = Matrix4.identity();
final Matrix4 mat = Matrix4.identity();
mat.translate(box.x, box.y);
context.canvas
..saveContext()
... ... @@ -58,7 +60,7 @@ class ClipRRect extends SingleChildWidget {
final double horizontalRadius;
final double verticalRadius;
@protected
@override
void debugPaint(Context context) {
context.canvas
..setStrokeColor(PdfColor.deepPurple)
... ... @@ -70,12 +72,14 @@ class ClipRRect extends SingleChildWidget {
@override
void paint(Context context) {
assert(() {
if (Document.debug) debugPaint(context);
if (Document.debug) {
debugPaint(context);
}
return true;
}());
if (child != null) {
final mat = Matrix4.identity();
final Matrix4 mat = Matrix4.identity();
mat.translate(box.x, box.y);
context.canvas
..saveContext()
... ... @@ -92,10 +96,10 @@ class ClipRRect extends SingleChildWidget {
class ClipOval extends SingleChildWidget {
ClipOval({Widget child}) : super(child: child);
@protected
@override
void debugPaint(Context context) {
final rx = box.width / 2.0;
final ry = box.height / 2.0;
final double rx = box.width / 2.0;
final double ry = box.height / 2.0;
context.canvas
..setStrokeColor(PdfColor.deepPurple)
... ... @@ -106,15 +110,17 @@ class ClipOval extends SingleChildWidget {
@override
void paint(Context context) {
assert(() {
if (Document.debug) debugPaint(context);
if (Document.debug) {
debugPaint(context);
}
return true;
}());
final rx = box.width / 2.0;
final ry = box.height / 2.0;
final double rx = box.width / 2.0;
final double ry = box.height / 2.0;
if (child != null) {
final mat = Matrix4.identity();
final Matrix4 mat = Matrix4.identity();
mat.translate(box.x, box.y);
context.canvas
..saveContext()
... ...
... ... @@ -219,7 +219,9 @@ class Container extends StatelessWidget {
if (alignment != null)
current = Align(alignment: alignment, child: current);
if (padding != null) current = Padding(padding: padding, child: current);
if (padding != null) {
current = Padding(padding: padding, child: current);
}
if (decoration != null)
current = DecoratedBox(decoration: decoration, child: current);
... ... @@ -234,7 +236,9 @@ class Container extends StatelessWidget {
if (constraints != null)
current = ConstrainedBox(constraints: constraints, child: current);
if (margin != null) current = Padding(padding: margin, child: current);
if (margin != null) {
current = Padding(padding: margin, child: current);
}
if (transform != null)
current = Transform(transform: transform, child: current);
... ...
... ... @@ -17,13 +17,13 @@
part of widget;
class Header extends StatelessWidget {
Header({this.level = 1, this.text, this.child})
: assert(level >= 0 && level <= 5);
final String text;
final Widget child;
final int level;
Header({this.level = 1, this.text, this.child})
: assert(level >= 0 && level <= 5);
@override
Widget build(Context context) {
BoxDecoration _decoration;
... ... @@ -32,36 +32,36 @@ class Header extends StatelessWidget {
double _textSize;
switch (level) {
case 0:
_margin = EdgeInsets.only(bottom: 5.0 * PdfPageFormat.mm);
_padding = EdgeInsets.only(bottom: 1.0 * PdfPageFormat.mm);
_margin = const EdgeInsets.only(bottom: 5.0 * PdfPageFormat.mm);
_padding = const EdgeInsets.only(bottom: 1.0 * PdfPageFormat.mm);
_decoration =
BoxDecoration(border: BoxBorder(bottom: true, width: 1.0));
const BoxDecoration(border: BoxBorder(bottom: true, width: 1.0));
_textSize = 2.0;
break;
case 1:
_margin = EdgeInsets.only(
_margin = const EdgeInsets.only(
top: 3.0 * PdfPageFormat.mm, bottom: 5.0 * PdfPageFormat.mm);
_decoration =
BoxDecoration(border: BoxBorder(bottom: true, width: 0.2));
const BoxDecoration(border: BoxBorder(bottom: true, width: 0.2));
_textSize = 1.5;
break;
case 2:
_margin = EdgeInsets.only(
_margin = const EdgeInsets.only(
top: 2.0 * PdfPageFormat.mm, bottom: 4.0 * PdfPageFormat.mm);
_textSize = 1.4;
break;
case 3:
_margin = EdgeInsets.only(
_margin = const EdgeInsets.only(
top: 2.0 * PdfPageFormat.mm, bottom: 4.0 * PdfPageFormat.mm);
_textSize = 1.3;
break;
case 4:
_margin = EdgeInsets.only(
_margin = const EdgeInsets.only(
top: 2.0 * PdfPageFormat.mm, bottom: 4.0 * PdfPageFormat.mm);
_textSize = 1.2;
break;
case 5:
_margin = EdgeInsets.only(
_margin = const EdgeInsets.only(
top: 2.0 * PdfPageFormat.mm, bottom: 4.0 * PdfPageFormat.mm);
_textSize = 1.1;
break;
... ... @@ -77,14 +77,14 @@ class Header extends StatelessWidget {
}
class Paragraph extends StatelessWidget {
final String text;
Paragraph({this.text});
final String text;
@override
Widget build(Context context) {
return Container(
margin: EdgeInsets.only(bottom: 5.0 * PdfPageFormat.mm),
margin: const EdgeInsets.only(bottom: 5.0 * PdfPageFormat.mm),
child: Text(
text,
textAlign: TextAlign.justify,
... ... @@ -95,26 +95,26 @@ class Paragraph extends StatelessWidget {
}
class Bullet extends StatelessWidget {
final String text;
Bullet({this.text});
final String text;
@override
Widget build(Context context) {
return Container(
margin: EdgeInsets.only(bottom: 2.0 * PdfPageFormat.mm),
margin: const EdgeInsets.only(bottom: 2.0 * PdfPageFormat.mm),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: 2.0 * PdfPageFormat.mm,
height: 2.0 * PdfPageFormat.mm,
margin: EdgeInsets.only(
margin: const EdgeInsets.only(
top: 0.5 * PdfPageFormat.mm,
left: 5.0 * PdfPageFormat.mm,
right: 2.0 * PdfPageFormat.mm,
),
decoration: BoxDecoration(
decoration: const BoxDecoration(
color: PdfColor.black, shape: BoxShape.circle),
),
Expanded(child: Text(text, style: Theme.of(context).bulletStyle))
... ...
... ... @@ -17,40 +17,36 @@
part of widget;
abstract class BasePage {
final PdfPageFormat pageFormat;
BasePage({@required this.pageFormat}) : assert(pageFormat != null);
BasePage({this.pageFormat}) : assert(pageFormat != null);
final PdfPageFormat pageFormat;
@protected
void generate(Document document);
}
class Document {
static var debug = false;
final PdfDocument document;
final Theme theme;
Document(
{PdfPageMode pageMode = PdfPageMode.none,
DeflateCallback deflate,
this.theme})
: document = PdfDocument(pageMode: pageMode, deflate: deflate);
static bool debug = false;
final PdfDocument document;
final Theme theme;
void addPage(BasePage page) {
page.generate(this);
}
}
typedef Widget BuildCallback(Context context);
typedef List<Widget> BuildListCallback(Context context);
typedef BuildCallback = Widget Function(Context context);
typedef BuildListCallback = List<Widget> Function(Context context);
class Page extends BasePage {
final EdgeInsets margin;
final BuildCallback _build;
final Theme theme;
Page(
{PdfPageFormat pageFormat = PdfPageFormat.a4,
BuildCallback build,
... ... @@ -62,6 +58,12 @@ class Page extends BasePage {
_build = build,
super(pageFormat: pageFormat);
final EdgeInsets margin;
final BuildCallback _build;
final Theme theme;
void debugPaint(Context context) {
context.canvas
..setFillColor(PdfColor.lightGreen)
... ... @@ -78,18 +80,19 @@ class Page extends BasePage {
@override
void generate(Document document) {
final pdfPage = PdfPage(document.document, pageFormat: pageFormat);
final canvas = pdfPage.getGraphics();
final constraints = BoxConstraints(
final PdfPage pdfPage = PdfPage(document.document, pageFormat: pageFormat);
final PdfGraphics canvas = pdfPage.getGraphics();
final BoxConstraints constraints = BoxConstraints(
maxWidth: pageFormat.width, maxHeight: pageFormat.height);
final calculatedTheme = theme ?? document.theme ?? Theme(document.document);
final inherited = Map<Type, Inherited>();
final Theme calculatedTheme =
theme ?? document.theme ?? Theme(document.document);
final Map<Type, Inherited> inherited = <Type, Inherited>{};
inherited[calculatedTheme.runtimeType] = calculatedTheme;
final context =
final Context context =
Context(page: pdfPage, canvas: canvas, inherited: inherited);
if (_build != null) {
final child = _build(context);
final Widget child = _build(context);
layout(child, context, constraints);
paint(child, context);
}
... ... @@ -97,9 +100,9 @@ class Page extends BasePage {
@protected
void layout(Widget child, Context context, BoxConstraints constraints,
{parentUsesSize = false}) {
{bool parentUsesSize = false}) {
if (child != null) {
final childConstraints = BoxConstraints(
final BoxConstraints childConstraints = BoxConstraints(
minWidth: constraints.minWidth,
minHeight: constraints.minHeight,
maxWidth: constraints.hasBoundedWidth
... ... @@ -120,7 +123,9 @@ class Page extends BasePage {
@protected
void paint(Widget child, Context context) {
assert(() {
if (Document.debug) debugPaint(context);
if (Document.debug) {
debugPaint(context);
}
return true;
}());
... ... @@ -131,11 +136,6 @@ class Page extends BasePage {
}
class MultiPage extends Page {
final BuildListCallback _buildList;
final CrossAxisAlignment crossAxisAlignment;
final BuildCallback header;
final BuildCallback footer;
MultiPage(
{PdfPageFormat pageFormat = PdfPageFormat.a4,
BuildListCallback build,
... ... @@ -146,39 +146,53 @@ class MultiPage extends Page {
: _buildList = build,
super(pageFormat: pageFormat, margin: margin);
final BuildListCallback _buildList;
final CrossAxisAlignment crossAxisAlignment;
final BuildCallback header;
final BuildCallback footer;
@override
void generate(Document document) {
if (_buildList == null) return;
if (_buildList == null) {
return;
}
final constraints = BoxConstraints(
final BoxConstraints constraints = BoxConstraints(
maxWidth: pageFormat.width, maxHeight: pageFormat.height);
final childConstraints =
final BoxConstraints childConstraints =
BoxConstraints(maxWidth: constraints.maxWidth - margin.horizontal);
final calculatedTheme = theme ?? document.theme ?? Theme(document.document);
final inherited = Map<Type, Inherited>();
final Theme calculatedTheme =
theme ?? document.theme ?? Theme(document.document);
final Map<Type, Inherited> inherited = <Type, Inherited>{};
inherited[calculatedTheme.runtimeType] = calculatedTheme;
Context context;
double offsetEnd;
double offsetStart;
var index = 0;
final children = _buildList(Context(inherited: inherited));
int index = 0;
final List<Widget> children = _buildList(Context(inherited: inherited));
WidgetContext widgetContext;
while (index < children.length) {
final child = children[index];
final Widget child = children[index];
if (context == null) {
final pdfPage = PdfPage(document.document, pageFormat: pageFormat);
final canvas = pdfPage.getGraphics();
final PdfPage pdfPage =
PdfPage(document.document, pageFormat: pageFormat);
final PdfGraphics canvas = pdfPage.getGraphics();
context = Context(page: pdfPage, canvas: canvas, inherited: inherited);
assert(() {
if (Document.debug) debugPaint(context);
if (Document.debug) {
debugPaint(context);
}
return true;
}());
offsetStart = pageFormat.height - margin.top;
offsetEnd = margin.bottom;
if (header != null) {
final headerWidget = header(context);
final Widget headerWidget = header(context);
if (headerWidget != null) {
headerWidget.layout(context, childConstraints,
parentUsesSize: false);
... ... @@ -193,7 +207,7 @@ class MultiPage extends Page {
}
if (footer != null) {
final footerWidget = footer(context);
final Widget footerWidget = footer(context);
if (footerWidget != null) {
footerWidget.layout(context, childConstraints,
parentUsesSize: false);
... ... @@ -206,7 +220,7 @@ class MultiPage extends Page {
}
if (widgetContext != null && child is SpanningWidget) {
(child as SpanningWidget).restoreContext(widgetContext);
child.restoreContext(widgetContext);
widgetContext = null;
}
... ... @@ -222,7 +236,7 @@ class MultiPage extends Page {
throw Exception("Widget won't fit into the page");
}
final span = child as SpanningWidget;
final SpanningWidget span = child;
child.layout(context,
childConstraints.copyWith(maxHeight: offsetStart - offsetEnd),
... ...
... ... @@ -93,11 +93,11 @@ class Flex extends MultiChildWidget {
double inflexibleSpace = 0.0;
double maxFlexFractionSoFar = 0.0;
for (var child in children) {
final int flex = child._flex;
for (Widget child in children) {
final int flex = child is Expanded ? child.flex : 0;
totalFlex += flex;
if (flex > 0) {
final double flexFraction = childSize(child, extent) / child._flex;
final double flexFraction = childSize(child, extent) / flex;
maxFlexFractionSoFar = math.max(maxFlexFractionSoFar, flexFraction);
} else {
inflexibleSpace += childSize(child, extent);
... ... @@ -115,8 +115,8 @@ class Flex extends MultiChildWidget {
int totalFlex = 0;
double inflexibleSpace = 0.0;
double maxCrossSize = 0.0;
for (var child in children) {
final int flex = child._flex;
for (Widget child in children) {
final int flex = child is Expanded ? child.flex : 0;
totalFlex += flex;
double mainSize;
double crossSize;
... ... @@ -142,8 +142,8 @@ class Flex extends MultiChildWidget {
math.max(0.0, (availableMainSpace - inflexibleSpace) / totalFlex);
// Size remaining (flexible) items, find the maximum cross size.
for (var child in children) {
final int flex = child._flex;
for (Widget child in children) {
final int flex = child is Expanded ? child.flex : 0;
if (flex > 0)
maxCrossSize =
math.max(maxCrossSize, childSize(child, spacePerFlex * flex));
... ... @@ -203,10 +203,10 @@ class Flex extends MultiChildWidget {
@override
void layout(Context context, BoxConstraints constraints,
{parentUsesSize = false}) {
{bool parentUsesSize = false}) {
// Determine used flex factor, size inflexible items, calculate free space.
int totalFlex = 0;
final totalChildren = children.length;
final int totalChildren = children.length;
Widget lastFlexChild;
assert(constraints != null);
final double maxMainSize = direction == Axis.horizontal
... ... @@ -218,22 +218,22 @@ class Flex extends MultiChildWidget {
double allocatedSize =
0.0; // Sum of the sizes of the non-flexible children.
for (var child in children) {
final int flex = child._flex;
for (Widget child in children) {
final int flex = child is Expanded ? child.flex : 0;
final FlexFit fit = child is Expanded ? child.fit : FlexFit.loose;
if (flex > 0) {
assert(() {
final String dimension =
direction == Axis.horizontal ? 'width' : 'height';
if (!canFlex &&
(mainAxisSize == MainAxisSize.max ||
child._fit == FlexFit.tight)) {
(mainAxisSize == MainAxisSize.max || fit == FlexFit.tight)) {
throw Exception(
'Flex children have non-zero flex but incoming $dimension constraints are unbounded.');
} else {
return true;
}
}());
totalFlex += child._flex;
totalFlex += flex;
} else {
BoxConstraints innerConstraints;
if (crossAxisAlignment == CrossAxisAlignment.stretch) {
... ... @@ -275,8 +275,9 @@ class Flex extends MultiChildWidget {
final double spacePerFlex =
canFlex && totalFlex > 0 ? (freeSpace / totalFlex) : double.nan;
for (var child in children) {
final int flex = child._flex;
for (Widget child in children) {
final int flex = child is Expanded ? child.flex : 0;
final FlexFit fit = child is Expanded ? child.fit : FlexFit.loose;
if (flex > 0) {
final double maxChildExtent = canFlex
? (child == lastFlexChild
... ... @@ -284,7 +285,7 @@ class Flex extends MultiChildWidget {
: spacePerFlex * flex)
: double.infinity;
double minChildExtent;
switch (child._fit) {
switch (fit) {
case FlexFit.tight:
assert(maxChildExtent < double.infinity);
minChildExtent = maxChildExtent;
... ... @@ -404,7 +405,7 @@ class Flex extends MultiChildWidget {
direction == Axis.vertical);
double childMainPosition =
flipMainAxis ? actualSize - leadingSpace : leadingSpace;
for (var child in children) {
for (Widget child in children) {
double childCrossPosition;
switch (crossAxisAlignment) {
case CrossAxisAlignment.start:
... ... @@ -423,7 +424,9 @@ class Flex extends MultiChildWidget {
break;
}
if (flipMainAxis) childMainPosition -= _getMainSize(child);
if (flipMainAxis) {
childMainPosition -= _getMainSize(child);
}
switch (direction) {
case Axis.horizontal:
child.box = PdfRect(box.x + childMainPosition,
... ... @@ -446,12 +449,12 @@ class Flex extends MultiChildWidget {
void paint(Context context) {
super.paint(context);
final mat = Matrix4.identity();
final Matrix4 mat = Matrix4.identity();
mat.translate(box.x, box.y);
context.canvas
..saveContext()
..setTransform(mat);
for (var child in children) {
for (Widget child in children) {
child.paint(context);
}
context.canvas.restoreContext();
... ... @@ -494,20 +497,22 @@ class Column extends Flex {
class Expanded extends SingleChildWidget {
Expanded({
int flex = 1,
this.flex = 1,
this.fit = FlexFit.tight,
@required Widget child,
}) : super(child: child) {
this._flex = flex;
this._fit = FlexFit.tight;
}
}) : super(child: child);
final int flex;
final FlexFit fit;
}
class ListView extends Flex {
ListView(
{Axis direction = Axis.vertical,
EdgeInsets padding,
double spacing = 0.0,
List<Widget> children = const []})
// EdgeInsets padding,
// double spacing = 0.0,
List<Widget> children = const <Widget>[]})
: super(
direction: direction,
mainAxisAlignment: MainAxisAlignment.start,
... ...
... ... @@ -18,6 +18,27 @@ part of widget;
@immutable
class BoxConstraints {
/// Creates box constraints with the given constraints.
const BoxConstraints(
{this.minWidth = 0.0,
this.maxWidth = double.infinity,
this.minHeight = 0.0,
this.maxHeight = double.infinity});
/// Creates box constraints that require the given width or height.
const BoxConstraints.tightFor({double width, double height})
: minWidth = width != null ? width : 0.0,
maxWidth = width != null ? width : double.infinity,
minHeight = height != null ? height : 0.0,
maxHeight = height != null ? height : double.infinity;
/// Creates box constraints that expand to fill another box constraints.
const BoxConstraints.expand({double width, double height})
: minWidth = width != null ? width : double.infinity,
maxWidth = width != null ? width : double.infinity,
minHeight = height != null ? height : double.infinity,
maxHeight = height != null ? height : double.infinity;
/// The minimum width that satisfies the constraints.
final double minWidth;
... ... @@ -34,13 +55,6 @@ class BoxConstraints {
/// Might be [double.infinity].
final double maxHeight;
/// Creates box constraints with the given constraints.
const BoxConstraints(
{this.minWidth = 0.0,
this.maxWidth = double.infinity,
this.minHeight = 0.0,
this.maxHeight = double.infinity});
bool get hasBoundedWidth => maxWidth < double.infinity;
bool get hasBoundedHeight => maxHeight < double.infinity;
... ... @@ -65,13 +79,15 @@ class BoxConstraints {
bool get isTight => hasTightWidth && hasTightHeight;
PdfPoint constrain(PdfPoint size) {
final result = PdfPoint(constrainWidth(size.x), constrainHeight(size.y));
final PdfPoint result =
PdfPoint(constrainWidth(size.x), constrainHeight(size.y));
return result;
}
PdfRect constrainRect(
{double width = double.infinity, double height = double.infinity}) {
final result = PdfPoint(constrainWidth(width), constrainHeight(height));
final PdfPoint result =
PdfPoint(constrainWidth(width), constrainHeight(height));
return PdfRect.fromPoints(PdfPoint.zero, result);
}
... ... @@ -86,8 +102,7 @@ class BoxConstraints {
/// Returns a size that attempts to meet the conditions
PdfPoint constrainSizeAndAttemptToPreserveAspectRatio(PdfPoint size) {
if (isTight) {
PdfPoint result = smallest;
final PdfPoint result = smallest;
return result;
}
... ... @@ -117,7 +132,8 @@ class BoxConstraints {
width = height * aspectRatio;
}
PdfPoint result = PdfPoint(constrainWidth(width), constrainHeight(height));
final PdfPoint result =
PdfPoint(constrainWidth(width), constrainHeight(height));
return result;
}
... ... @@ -134,20 +150,6 @@ class BoxConstraints {
height == null ? maxHeight : height.clamp(minHeight, maxHeight));
}
/// Creates box constraints that require the given width or height.
const BoxConstraints.tightFor({double width, double height})
: minWidth = width != null ? width : 0.0,
maxWidth = width != null ? width : double.infinity,
minHeight = height != null ? height : 0.0,
maxHeight = height != null ? height : double.infinity;
/// Creates box constraints that expand to fill another box constraints.
const BoxConstraints.expand({double width, double height})
: minWidth = width != null ? width : double.infinity,
maxWidth = width != null ? width : double.infinity,
minHeight = height != null ? height : double.infinity,
maxHeight = height != null ? height : double.infinity;
/// Returns new box constraints that are smaller by the given edge dimensions.
BoxConstraints deflate(EdgeInsets edges) {
assert(edges != null);
... ... @@ -194,7 +196,7 @@ class BoxConstraints {
@override
String toString() {
return "BoxConstraint <$minWidth, $maxWidth> <$minHeight, $maxHeight>";
return 'BoxConstraint <$minWidth, $maxWidth> <$minHeight, $maxHeight>';
}
}
... ... @@ -327,7 +329,7 @@ class Alignment {
}
@override
String toString() => "($x, $y)";
String toString() => '($x, $y)';
}
/// The pair of sizes returned by [applyBoxFit].
... ... @@ -411,10 +413,10 @@ PdfPoint transformPoint(Matrix4 transform, PdfPoint point) {
}
PdfRect transformRect(Matrix4 transform, PdfRect rect) {
final point1 = transformPoint(transform, rect.topLeft);
final point2 = transformPoint(transform, rect.topRight);
final point3 = transformPoint(transform, rect.bottomLeft);
final point4 = transformPoint(transform, rect.bottomRight);
final PdfPoint point1 = transformPoint(transform, rect.topLeft);
final PdfPoint point2 = transformPoint(transform, rect.topRight);
final PdfPoint point3 = transformPoint(transform, rect.bottomLeft);
final PdfPoint point4 = transformPoint(transform, rect.bottomRight);
return PdfRect.fromLTRB(
math.min(point1.x, math.min(point2.x, math.min(point3.x, point4.x))),
math.min(point1.y, math.min(point2.y, math.min(point3.y, point4.y))),
... ...
... ... @@ -24,7 +24,7 @@ class GridView extends MultiChildWidget {
this.mainAxisSpacing = 0.0,
this.crossAxisSpacing = 0.0,
this.childAspectRatio = double.infinity,
List<Widget> children = const []})
List<Widget> children = const <Widget>[]})
: assert(padding != null),
super(children: children);
... ... @@ -43,7 +43,7 @@ class GridView extends MultiChildWidget {
@override
void layout(Context context, BoxConstraints constraints,
{parentUsesSize = false}) {
{bool parentUsesSize = false}) {
double mainAxisExtent;
double crossAxisExtent;
switch (direction) {
... ... @@ -69,10 +69,10 @@ class GridView extends MultiChildWidget {
_totalCross = (_childCrossAxis + crossAxisSpacing) * crossAxisCount -
crossAxisSpacing;
var startX = padding.left;
var startY = 0.0;
var mainAxis;
var crossAxis;
final double startX = padding.left;
const double startY = 0.0;
double mainAxis;
double crossAxis;
BoxConstraints innerConstraints;
switch (direction) {
case Axis.vertical:
... ... @@ -89,8 +89,8 @@ class GridView extends MultiChildWidget {
break;
}
var c = 0;
for (var child in children) {
int c = 0;
for (Widget child in children) {
child.layout(context, innerConstraints);
switch (direction) {
... ... @@ -157,7 +157,7 @@ class GridView extends MultiChildWidget {
..lineTo(box.right - padding.right, box.bottom + padding.bottom)
..fillPath();
for (var c = 1; c < crossAxisCount; c++) {
for (int c = 1; c < crossAxisCount; c++) {
switch (direction) {
case Axis.vertical:
context.canvas
... ... @@ -176,7 +176,7 @@ class GridView extends MultiChildWidget {
}
}
for (var c = 1; c < _mainAxisCount; c++) {
for (int c = 1; c < _mainAxisCount; c++) {
switch (direction) {
case Axis.vertical:
context.canvas
... ... @@ -200,12 +200,12 @@ class GridView extends MultiChildWidget {
void paint(Context context) {
super.paint(context);
final mat = Matrix4.identity();
final Matrix4 mat = Matrix4.identity();
mat.translate(box.x, box.y);
context.canvas
..saveContext()
..setTransform(mat);
for (var child in children) {
for (Widget child in children) {
child.paint(context);
}
context.canvas.restoreContext();
... ...
... ... @@ -17,21 +17,23 @@
part of widget;
class Image extends Widget {
Image(this.image, {this.fit = BoxFit.contain})
: assert(image != null),
aspectRatio = image.height.toDouble() / image.width.toDouble();
final PdfImage image;
final double aspectRatio;
final BoxFit fit;
Image(this.image, {this.fit = BoxFit.contain})
: assert(image != null),
aspectRatio = (image.height.toDouble() / image.width.toDouble());
final BoxFit fit;
@override
void layout(Context context, BoxConstraints constraints,
{parentUsesSize = false}) {
final w = constraints.hasBoundedWidth
{bool parentUsesSize = false}) {
final double w = constraints.hasBoundedWidth
? constraints.maxWidth
: constraints.constrainWidth(image.width.toDouble());
final h = constraints.hasBoundedHeight
final double h = constraints.hasBoundedHeight
? constraints.maxHeight
: constraints.constrainHeight(image.height.toDouble());
... ... @@ -51,14 +53,6 @@ class Image extends Widget {
}
class Shape extends Widget {
final String shape;
final PdfColor strokeColor;
final PdfColor fillColor;
final double width;
final double height;
final double aspectRatio;
final BoxFit fit;
Shape(
this.shape, {
this.strokeColor,
... ... @@ -70,13 +64,27 @@ class Shape extends Widget {
assert(height != null && height > 0.0),
aspectRatio = height / width;
final String shape;
final PdfColor strokeColor;
final PdfColor fillColor;
final double width;
final double height;
final double aspectRatio;
final BoxFit fit;
@override
void layout(Context context, BoxConstraints constraints,
{parentUsesSize = false}) {
final w = constraints.hasBoundedWidth
{bool parentUsesSize = false}) {
final double w = constraints.hasBoundedWidth
? constraints.maxWidth
: constraints.constrainWidth(width);
final h = constraints.hasBoundedHeight
final double h = constraints.hasBoundedHeight
? constraints.maxHeight
: constraints.constrainHeight(height);
... ... @@ -89,7 +97,7 @@ class Shape extends Widget {
void paint(Context context) {
super.paint(context);
final mat = Matrix4.identity();
final Matrix4 mat = Matrix4.identity();
mat.translate(box.x, box.y + box.height);
mat.scale(box.width / width, -box.height / height);
context.canvas
... ...
... ... @@ -17,20 +17,23 @@
part of widget;
class Placeholder extends Widget {
final PdfColor color;
final double strokeWidth;
final double fallbackWidth;
final double fallbackHeight;
Placeholder(
{this.color = const PdfColor.fromInt(0xFF455A64),
this.strokeWidth = 2.0,
this.fallbackWidth = 400.0,
this.fallbackHeight = 400.0});
final PdfColor color;
final double strokeWidth;
final double fallbackWidth;
final double fallbackHeight;
@override
void layout(Context context, BoxConstraints constraints,
{parentUsesSize = false}) {
{bool parentUsesSize = false}) {
box = PdfRect(
0.0,
0.0,
... ... @@ -41,7 +44,7 @@ class Placeholder extends Widget {
: fallbackHeight));
}
@protected
@override
void paint(Context context) {
super.paint(context);
... ... @@ -63,8 +66,8 @@ class PdfLogo extends StatelessWidget {
final PdfColor color;
final BoxFit fit;
static const pdf =
"M 2.424 26.712 L 2.424 26.712 C 2.076 26.712 1.742 26.599 1.457 26.386 C 0.416 25.605 0.276 24.736 0.342 24.144 C 0.524 22.516 2.537 20.812 6.327 19.076 C 7.831 15.78 9.262 11.719 10.115 8.326 C 9.117 6.154 8.147 3.336 8.854 1.683 C 9.102 1.104 9.411 0.66 9.988 0.468 C 10.216 0.392 10.792 0.296 11.004 0.296 C 11.508 0.296 11.951 0.945 12.265 1.345 C 12.56 1.721 13.229 2.518 11.892 8.147 C 13.24 10.931 15.15 13.767 16.98 15.709 C 18.291 15.472 19.419 15.351 20.338 15.351 C 21.904 15.351 22.853 15.716 23.24 16.468 C 23.56 17.09 23.429 17.817 22.85 18.628 C 22.293 19.407 21.525 19.819 20.63 19.819 C 19.414 19.819 17.998 19.051 16.419 17.534 C 13.582 18.127 10.269 19.185 7.591 20.356 C 6.755 22.13 5.954 23.559 5.208 24.607 C 4.183 26.042 3.299 26.712 2.424 26.712 Z M 5.086 21.586 C 2.949 22.787 2.078 23.774 2.015 24.33 C 2.005 24.422 1.978 24.664 2.446 25.022 C 2.595 24.975 3.465 24.578 5.086 21.586 Z M 18.723 17.144 C 19.538 17.771 19.737 18.088 20.27 18.088 C 20.504 18.088 21.171 18.078 21.48 17.647 C 21.629 17.438 21.687 17.304 21.71 17.232 C 21.587 17.167 21.424 17.035 20.535 17.035 C 20.03 17.036 19.395 17.058 18.723 17.144 Z M 11.253 10.562 C 10.538 13.036 9.594 15.707 8.579 18.126 C 10.669 17.315 12.941 16.607 15.075 16.106 C 13.725 14.538 12.376 12.58 11.253 10.562 Z M 10.646 2.1 C 10.548 2.133 9.316 3.857 10.742 5.316 C 11.691 3.201 10.689 2.086 10.646 2.1 Z";
static const String pdf =
'M 2.424 26.712 L 2.424 26.712 C 2.076 26.712 1.742 26.599 1.457 26.386 C 0.416 25.605 0.276 24.736 0.342 24.144 C 0.524 22.516 2.537 20.812 6.327 19.076 C 7.831 15.78 9.262 11.719 10.115 8.326 C 9.117 6.154 8.147 3.336 8.854 1.683 C 9.102 1.104 9.411 0.66 9.988 0.468 C 10.216 0.392 10.792 0.296 11.004 0.296 C 11.508 0.296 11.951 0.945 12.265 1.345 C 12.56 1.721 13.229 2.518 11.892 8.147 C 13.24 10.931 15.15 13.767 16.98 15.709 C 18.291 15.472 19.419 15.351 20.338 15.351 C 21.904 15.351 22.853 15.716 23.24 16.468 C 23.56 17.09 23.429 17.817 22.85 18.628 C 22.293 19.407 21.525 19.819 20.63 19.819 C 19.414 19.819 17.998 19.051 16.419 17.534 C 13.582 18.127 10.269 19.185 7.591 20.356 C 6.755 22.13 5.954 23.559 5.208 24.607 C 4.183 26.042 3.299 26.712 2.424 26.712 Z M 5.086 21.586 C 2.949 22.787 2.078 23.774 2.015 24.33 C 2.005 24.422 1.978 24.664 2.446 25.022 C 2.595 24.975 3.465 24.578 5.086 21.586 Z M 18.723 17.144 C 19.538 17.771 19.737 18.088 20.27 18.088 C 20.504 18.088 21.171 18.078 21.48 17.647 C 21.629 17.438 21.687 17.304 21.71 17.232 C 21.587 17.167 21.424 17.035 20.535 17.035 C 20.03 17.036 19.395 17.058 18.723 17.144 Z M 11.253 10.562 C 10.538 13.036 9.594 15.707 8.579 18.126 C 10.669 17.315 12.941 16.607 15.075 16.106 C 13.725 14.538 12.376 12.58 11.253 10.562 Z M 10.646 2.1 C 10.548 2.133 9.316 3.857 10.742 5.316 C 11.691 3.201 10.689 2.086 10.646 2.1 Z';
@override
Widget build(Context context) {
... ... @@ -79,38 +82,42 @@ class LoremText {
final math.Random random;
static final words =
"ad adipiscing aliqua aliquip amet anim aute cillum commodo consectetur consequat culpa cupidatat deserunt do dolor dolore duis ea eiusmod elit enim esse est et eu ex excepteur exercitation fugiat id in incididunt ipsum irure labore laboris laborum lorem magna minim mollit nisi non nostrud nulla occaecat officia pariatur proident qui quis reprehenderit sed sint sit sunt tempor ullamco ut velit veniam voluptate"
.split(" ");
static final List<String> words =
'ad adipiscing aliqua aliquip amet anim aute cillum commodo consectetur consequat culpa cupidatat deserunt do dolor dolore duis ea eiusmod elit enim esse est et eu ex excepteur exercitation fugiat id in incididunt ipsum irure labore laboris laborum lorem magna minim mollit nisi non nostrud nulla occaecat officia pariatur proident qui quis reprehenderit sed sint sit sunt tempor ullamco ut velit veniam voluptate'
.split(' ');
String word() {
return words[random.nextInt(words.length - 1)];
}
String sentence(int length) {
final wordList = List<String>();
for (var i = 0; i < length; i++) {
var w = word();
if (i < length - 1 && random.nextInt(10) == 0) w += ",";
final List<String> wordList = <String>[];
for (int i = 0; i < length; i++) {
String w = word();
if (i < length - 1 && random.nextInt(10) == 0) {
w += ',';
}
wordList.add(w);
}
var text = wordList.join(" ") + ".";
final String text = wordList.join(' ') + '.';
return text[0].toUpperCase() + text.substring(1);
}
String paragraph(int length) {
var wordsCount = 0;
final sentenceList = List<String>();
var n = 0;
int wordsCount = 0;
final List<String> sentenceList = <String>[];
int n = 0;
while (wordsCount < length) {
n++;
if (n > 100) break;
var count = math.min(length,
if (n > 100) {
break;
}
final int count = math.min(length,
math.max(10, math.min(3, random.nextInt(length - wordsCount))));
sentenceList.add(sentence(count));
wordsCount += count;
}
return sentenceList.join(" ");
return sentenceList.join(' ');
}
}
... ... @@ -134,8 +141,8 @@ class Lorem extends StatelessWidget {
@override
Widget build(Context context) {
final lorem = LoremText(random: random);
final text = lorem.paragraph(length);
final LoremText lorem = LoremText(random: random);
final String text = lorem.paragraph(length);
return Text(text,
style: style,
... ...
... ... @@ -59,8 +59,8 @@ class TableBorder extends BoxBorder {
super.paintBorders(context, box);
if (verticalInside) {
var offset = box.x;
for (var width in widths.sublist(0, widths.length - 1)) {
double offset = box.x;
for (double width in widths.sublist(0, widths.length - 1)) {
offset += width;
context.canvas.moveTo(offset, box.y);
context.canvas.lineTo(offset, box.top);
... ... @@ -69,8 +69,8 @@ class TableBorder extends BoxBorder {
}
if (horizontalInside) {
var offset = box.top;
for (var height in heights.sublist(0, heights.length - 1)) {
double offset = box.top;
for (double height in heights.sublist(0, heights.length - 1)) {
offset -= height;
context.canvas.moveTo(box.x, offset);
context.canvas.lineTo(box.right, offset);
... ... @@ -81,8 +81,8 @@ class TableBorder extends BoxBorder {
}
class _TableContext extends WidgetContext {
var firstLine = 0;
var lastLine = 0;
int firstLine = 0;
int lastLine = 0;
}
/// A widget that uses the table layout algorithm for its children.
... ... @@ -95,6 +95,33 @@ class Table extends Widget implements SpanningWidget {
: assert(children != null),
super();
factory Table.fromTextArray(
{@required Context context, @required List<List<String>> data}) {
final List<TableRow> rows = <TableRow>[];
for (List<String> row in data) {
final List<Widget> tableRow = <Widget>[];
if (row == data.first) {
for (String cell in row) {
tableRow.add(Container(
alignment: Alignment.center,
margin: const EdgeInsets.all(5),
child: Text(cell, style: Theme.of(context).tableHeader)));
}
} else {
for (String cell in row) {
tableRow.add(Container(
margin: const EdgeInsets.all(5),
child: Text(cell, style: Theme.of(context).tableCell)));
}
}
rows.add(TableRow(children: tableRow, repeat: row == data.first));
}
return Table(
border: const TableBorder(),
tableWidth: TableWidth.max,
children: rows);
}
@override
bool get canSpan => true;
... ... @@ -107,10 +134,10 @@ class Table extends Widget implements SpanningWidget {
final TableWidth tableWidth;
final _widths = List<double>();
final _heights = List<double>();
final List<double> _widths = <double>[];
final List<double> _heights = <double>[];
var _context = _TableContext();
_TableContext _context = _TableContext();
@override
WidgetContext saveContext() {
... ... @@ -125,20 +152,21 @@ class Table extends Widget implements SpanningWidget {
@override
void layout(Context context, BoxConstraints constraints,
{parentUsesSize = false}) {
{bool parentUsesSize = false}) {
// Compute required width for all row/columns width flex
final flex = List<double>();
final List<double> flex = <double>[];
_widths.clear();
_heights.clear();
var index = 0;
int index = 0;
for (var row in children) {
var n = 0;
for (var child in row.children) {
child.layout(context, BoxConstraints());
final calculatedWidth =
for (TableRow row in children) {
int n = 0;
for (Widget child in row.children) {
child.layout(context, const BoxConstraints());
final double calculatedWidth =
child.box.width == double.infinity ? 0.0 : child.box.width;
final childFlex = child._flex.toDouble();
final double childFlex =
child is Expanded ? child.flex.toDouble() : 0.0;
if (flex.length < n + 1) {
flex.add(childFlex);
_widths.add(calculatedWidth);
... ... @@ -152,15 +180,15 @@ class Table extends Widget implements SpanningWidget {
}
}
final maxWidth = _widths.reduce((a, b) => a + b);
final double maxWidth = _widths.reduce((double a, double b) => a + b);
// Compute column widths using flex and estimated width
if (constraints.hasBoundedWidth) {
final totalFlex = flex.reduce((a, b) => a + b);
var flexSpace = 0.0;
for (var n = 0; n < _widths.length; n++) {
final double totalFlex = flex.reduce((double a, double b) => a + b);
double flexSpace = 0.0;
for (int n = 0; n < _widths.length; n++) {
if (flex[n] == 0.0) {
var newWidth = _widths[n] / maxWidth * constraints.maxWidth;
final double newWidth = _widths[n] / maxWidth * constraints.maxWidth;
if ((tableWidth == TableWidth.max && totalFlex == 0.0) ||
newWidth < _widths[n]) {
_widths[n] = newWidth;
... ... @@ -168,32 +196,35 @@ class Table extends Widget implements SpanningWidget {
flexSpace += _widths[n];
}
}
final spacePerFlex = totalFlex > 0.0
final double spacePerFlex = totalFlex > 0.0
? ((constraints.maxWidth - flexSpace) / totalFlex)
: double.nan;
for (var n = 0; n < _widths.length; n++) {
for (int n = 0; n < _widths.length; n++) {
if (flex[n] > 0.0) {
var newWidth = spacePerFlex * flex[n];
final double newWidth = spacePerFlex * flex[n];
_widths[n] = newWidth;
}
}
}
final totalWidth = _widths.reduce((a, b) => a + b);
final double totalWidth = _widths.reduce((double a, double b) => a + b);
// Compute final widths
var totalHeight = 0.0;
double totalHeight = 0.0;
index = 0;
for (var row in children) {
if (index++ < _context.firstLine && !row.repeat) continue;
for (TableRow row in children) {
if (index++ < _context.firstLine && !row.repeat) {
continue;
}
var n = 0;
var x = 0.0;
int n = 0;
double x = 0.0;
var lineHeight = 0.0;
for (var child in row.children) {
final childConstraints = BoxConstraints.tightFor(width: _widths[n]);
double lineHeight = 0.0;
for (Widget child in row.children) {
final BoxConstraints childConstraints =
BoxConstraints.tightFor(width: _widths[n]);
child.layout(context, childConstraints);
child.box = PdfRect(x, totalHeight, child.box.width, child.box.height);
x += _widths[n];
... ... @@ -212,10 +243,12 @@ class Table extends Widget implements SpanningWidget {
// Compute final y position
index = 0;
for (var row in children) {
if (index++ < _context.firstLine && !row.repeat) continue;
for (TableRow row in children) {
if (index++ < _context.firstLine && !row.repeat) {
continue;
}
for (var child in row.children) {
for (Widget child in row.children) {
child.box = PdfRect(
child.box.x,
totalHeight - child.box.y - child.box.height,
... ... @@ -223,7 +256,9 @@ class Table extends Widget implements SpanningWidget {
child.box.height);
}
if (index >= _context.lastLine) break;
if (index >= _context.lastLine) {
break;
}
}
box = PdfRect(0.0, 0.0, totalWidth, totalHeight);
... ... @@ -233,19 +268,23 @@ class Table extends Widget implements SpanningWidget {
void paint(Context context) {
super.paint(context);
final mat = Matrix4.identity();
final Matrix4 mat = Matrix4.identity();
mat.translate(box.x, box.y);
context.canvas
..saveContext()
..setTransform(mat);
var index = 0;
for (var row in children) {
if (index++ < _context.firstLine && !row.repeat) continue;
for (var child in row.children) {
int index = 0;
for (TableRow row in children) {
if (index++ < _context.firstLine && !row.repeat) {
continue;
}
for (Widget child in row.children) {
child.paint(context);
}
if (index >= _context.lastLine) break;
if (index >= _context.lastLine) {
break;
}
}
context.canvas.restoreContext();
... ... @@ -253,29 +292,4 @@ class Table extends Widget implements SpanningWidget {
border.paintBorders(context, box, _widths, _heights);
}
}
factory Table.fromTextArray(
{@required Context context, @required List<List<String>> data}) {
final rows = List<TableRow>();
for (var row in data) {
final tableRow = List<Widget>();
if (row == data.first) {
for (var cell in row) {
tableRow.add(Container(
alignment: Alignment.center,
margin: EdgeInsets.all(5),
child: Text(cell, style: Theme.of(context).tableHeader)));
}
} else {
for (var cell in row) {
tableRow.add(Container(
margin: EdgeInsets.all(5),
child: Text(cell, style: Theme.of(context).tableCell)));
}
}
rows.add(TableRow(children: tableRow, repeat: row == data.first));
}
return Table(
border: TableBorder(), tableWidth: TableWidth.max, children: rows);
}
}
... ...