David PHAM-VAN

Add support for Metadata XML

@@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
7 - Improve GraphicState 7 - Improve GraphicState
8 - Add SVG Color filter 8 - Add SVG Color filter
9 - Implement Compressed XREF 9 - Implement Compressed XREF
  10 +- Add support for Metadata XML
10 11
11 ## 3.1.0 12 ## 3.1.0
12 13
@@ -30,6 +30,7 @@ export 'src/pdf/graphic_state.dart'; @@ -30,6 +30,7 @@ export 'src/pdf/graphic_state.dart';
30 export 'src/pdf/graphics.dart'; 30 export 'src/pdf/graphics.dart';
31 export 'src/pdf/image.dart'; 31 export 'src/pdf/image.dart';
32 export 'src/pdf/info.dart'; 32 export 'src/pdf/info.dart';
  33 +export 'src/pdf/metadata.dart';
33 export 'src/pdf/outline.dart'; 34 export 'src/pdf/outline.dart';
34 export 'src/pdf/page.dart'; 35 export 'src/pdf/page.dart';
35 export 'src/pdf/page_format.dart'; 36 export 'src/pdf/page_format.dart';
@@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
17 import 'annotation.dart'; 17 import 'annotation.dart';
18 import 'data_types.dart'; 18 import 'data_types.dart';
19 import 'document.dart'; 19 import 'document.dart';
  20 +import 'metadata.dart';
20 import 'names.dart'; 21 import 'names.dart';
21 import 'object_dict.dart'; 22 import 'object_dict.dart';
22 import 'outline.dart'; 23 import 'outline.dart';
@@ -38,6 +39,9 @@ class PdfCatalog extends PdfObjectDict { @@ -38,6 +39,9 @@ class PdfCatalog extends PdfObjectDict {
38 /// The outlines of the document 39 /// The outlines of the document
39 PdfOutline? outlines; 40 PdfOutline? outlines;
40 41
  42 + /// The document metadata
  43 + PdfMetadata? metadata;
  44 +
41 /// The initial page mode 45 /// The initial page mode
42 final PdfPageMode pageMode; 46 final PdfPageMode pageMode;
43 47
@@ -66,6 +70,10 @@ class PdfCatalog extends PdfObjectDict { @@ -66,6 +70,10 @@ class PdfCatalog extends PdfObjectDict {
66 params['/Outlines'] = outlines!.ref(); 70 params['/Outlines'] = outlines!.ref();
67 } 71 }
68 72
  73 + if (metadata != null) {
  74 + params['/Metadata'] = metadata!.ref();
  75 + }
  76 +
69 // the Names object 77 // the Names object
70 params['/Names'] = names.ref(); 78 params['/Names'] = names.ref();
71 79
@@ -595,15 +595,34 @@ class PdfDict<T extends PdfDataType> extends PdfDataType { @@ -595,15 +595,34 @@ class PdfDict<T extends PdfDataType> extends PdfDataType {
595 } 595 }
596 596
597 class PdfDictStream extends PdfDict<PdfDataType> { 597 class PdfDictStream extends PdfDict<PdfDataType> {
598 - const PdfDictStream({ 598 + factory PdfDictStream({
  599 + required PdfObject object,
  600 + Map<String, PdfDataType>? values,
  601 + Uint8List? data,
  602 + bool isBinary = false,
  603 + bool encrypt = true,
  604 + bool compress = true,
  605 + }) {
  606 + return PdfDictStream.values(
  607 + object: object,
  608 + values: values ?? {},
  609 + data: data ?? Uint8List(0),
  610 + encrypt: encrypt,
  611 + compress: compress,
  612 + isBinary: isBinary,
  613 + );
  614 + }
  615 +
  616 + PdfDictStream.values({
599 required this.object, 617 required this.object,
600 - Map<String, PdfDataType> values = const <String, PdfDataType>{}, 618 + required Map<String, PdfDataType> values,
601 required this.data, 619 required this.data,
602 this.isBinary = false, 620 this.isBinary = false,
603 this.encrypt = true, 621 this.encrypt = true,
  622 + this.compress = true,
604 }) : super.values(values); 623 }) : super.values(values);
605 624
606 - final Uint8List data; 625 + Uint8List data;
607 626
608 final PdfObject object; 627 final PdfObject object;
609 628
@@ -611,6 +630,8 @@ class PdfDictStream extends PdfDict<PdfDataType> { @@ -611,6 +630,8 @@ class PdfDictStream extends PdfDict<PdfDataType> {
611 630
612 final bool encrypt; 631 final bool encrypt;
613 632
  633 + final bool compress;
  634 +
614 @override 635 @override
615 void output(PdfStream s) { 636 void output(PdfStream s) {
616 final _values = PdfDict(values); 637 final _values = PdfDict(values);
@@ -620,7 +641,7 @@ class PdfDictStream extends PdfDict<PdfDataType> { @@ -620,7 +641,7 @@ class PdfDictStream extends PdfDict<PdfDataType> {
620 if (_values.containsKey('/Filter')) { 641 if (_values.containsKey('/Filter')) {
621 // The data is already in the right format 642 // The data is already in the right format
622 _data = data; 643 _data = data;
623 - } else if (object.pdfDocument.deflate != null) { 644 + } else if (compress && object.pdfDocument.deflate != null) {
624 // Compress the data 645 // Compress the data
625 final newData = Uint8List.fromList(object.pdfDocument.deflate!(data)); 646 final newData = Uint8List.fromList(object.pdfDocument.deflate!(data));
626 if (newData.lengthInBytes < data.lengthInBytes) { 647 if (newData.lengthInBytes < data.lengthInBytes) {
@@ -123,6 +123,7 @@ class PdfDocument { @@ -123,6 +123,7 @@ class PdfDocument {
123 123
124 /// This is the info object. Although this is an optional object, we 124 /// This is the info object. Although this is an optional object, we
125 /// include it. 125 /// include it.
  126 + @Deprecated('This can safely be removed.')
126 PdfInfo? info; 127 PdfInfo? info;
127 128
128 /// This is the Pages object, which is required by each Pdf Document 129 /// This is the Pages object, which is required by each Pdf Document
  1 +/*
  2 + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +import 'dart:convert';
  18 +import 'dart:typed_data';
  19 +
  20 +import 'package:xml/xml.dart';
  21 +
  22 +import 'data_types.dart';
  23 +import 'document.dart';
  24 +import 'object.dart';
  25 +
  26 +/// Pdf Metadata
  27 +class PdfMetadata extends PdfObject<PdfDictStream> {
  28 + /// Store an Xml object
  29 + PdfMetadata(
  30 + PdfDocument pdfDocument,
  31 + this.metadata,
  32 + ) : super(
  33 + pdfDocument,
  34 + params: PdfDictStream(
  35 + object: pdfDocument.catalog,
  36 + compress: false,
  37 + encrypt: false,
  38 + ),
  39 + ) {
  40 + pdfDocument.catalog.metadata = this;
  41 + }
  42 +
  43 + final XmlDocument metadata;
  44 +
  45 + @override
  46 + void prepare() {
  47 + super.prepare();
  48 + params['/SubType'] = const PdfName('/XML');
  49 + params.data = Uint8List.fromList(utf8.encode(metadata.toString()));
  50 + }
  51 +}
@@ -36,7 +36,7 @@ class PdfObjectStream extends PdfObjectDict { @@ -36,7 +36,7 @@ class PdfObjectStream extends PdfObjectDict {
36 36
37 @override 37 @override
38 void writeContent(PdfStream os) { 38 void writeContent(PdfStream os) {
39 - PdfDictStream( 39 + PdfDictStream.values(
40 object: this, 40 object: this,
41 isBinary: isBinary, 41 isBinary: isBinary,
42 values: params.values, 42 values: params.values,
@@ -52,10 +52,10 @@ class PdfOutput { @@ -52,10 +52,10 @@ class PdfOutput {
52 final xref = PdfXrefTable(); 52 final xref = PdfXrefTable();
53 53
54 /// This is used to track the /Root object (catalog) 54 /// This is used to track the /Root object (catalog)
55 - PdfObject? rootID; 55 + PdfCatalog? rootID;
56 56
57 /// This is used to track the /Info object (info) 57 /// This is used to track the /Info object (info)
58 - PdfObject? infoID; 58 + PdfInfo? infoID;
59 59
60 /// This is used to track the /Encrypt object (encryption) 60 /// This is used to track the /Encrypt object (encryption)
61 PdfEncryption? encryptID; 61 PdfEncryption? encryptID;
@@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
17 import 'dart:typed_data'; 17 import 'dart:typed_data';
18 18
19 import 'package:pdf/pdf.dart'; 19 import 'package:pdf/pdf.dart';
  20 +import 'package:xml/xml.dart';
20 21
21 import 'page.dart'; 22 import 'page.dart';
22 import 'theme.dart'; 23 import 'theme.dart';
@@ -34,6 +35,7 @@ class Document { @@ -34,6 +35,7 @@ class Document {
34 String? subject, 35 String? subject,
35 String? keywords, 36 String? keywords,
36 String? producer, 37 String? producer,
  38 + XmlDocument? metadata,
37 }) : document = PdfDocument( 39 }) : document = PdfDocument(
38 pageMode: pageMode, 40 pageMode: pageMode,
39 deflate: deflate, 41 deflate: deflate,
@@ -46,7 +48,7 @@ class Document { @@ -46,7 +48,7 @@ class Document {
46 subject != null || 48 subject != null ||
47 keywords != null || 49 keywords != null ||
48 producer != null) { 50 producer != null) {
49 - document.info = PdfInfo( 51 + PdfInfo(
50 document, 52 document,
51 title: title, 53 title: title,
52 author: author, 54 author: author,
@@ -56,6 +58,9 @@ class Document { @@ -56,6 +58,9 @@ class Document {
56 producer: producer, 58 producer: producer,
57 ); 59 );
58 } 60 }
  61 + if (metadata != null) {
  62 + PdfMetadata(document, metadata);
  63 + }
59 } 64 }
60 65
61 Document.load( 66 Document.load(
@@ -82,7 +87,7 @@ class Document { @@ -82,7 +87,7 @@ class Document {
82 subject != null || 87 subject != null ||
83 keywords != null || 88 keywords != null ||
84 producer != null) { 89 producer != null) {
85 - document.info = PdfInfo( 90 + PdfInfo(
86 document, 91 document,
87 title: title, 92 title: title,
88 author: author, 93 author: author,
@@ -28,7 +28,7 @@ void main() { @@ -28,7 +28,7 @@ void main() {
28 img.fillRange(0, img.length - 1, 0x12345678); 28 img.fillRange(0, img.length - 1, 0x12345678);
29 29
30 final pdf = PdfDocument(); 30 final pdf = PdfDocument();
31 - pdf.info = PdfInfo(pdf, 31 + PdfInfo(pdf,
32 author: 'David PHAM-VAN', 32 author: 'David PHAM-VAN',
33 creator: 'David PHAM-VAN', 33 creator: 'David PHAM-VAN',
34 title: 'My Title', 34 title: 'My Title',