-
-
Notifications
You must be signed in to change notification settings - Fork 654
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* PDF/A 3b * PDF/A 3b * PDF/A, reorganized into multiple files * PDF/A, make all annotations printable as a default (for pdf/a) * PDF/A, merging /Names when attaching files * PDF/A, extended facturx-rdf * Update pdf/lib/src/pdf/obj/pdfa/README.md Co-authored-by: Colin Ihlenfeldt <[email protected]> --------- Co-authored-by: David PHAM-VAN <[email protected]> Co-authored-by: Colin Ihlenfeldt <[email protected]>
- Loading branch information
1 parent
32c1e5e
commit 41d3237
Showing
11 changed files
with
439 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
Here are some classes to help you creating PDF/A compliant PDFs | ||
plus embedding Facturx invoices. | ||
|
||
### Rules | ||
|
||
1. Your PDF must only use embedded Fonts, | ||
2. For now you cannot use any Annotations in your PDF | ||
3. You must include a special Meta-XML, use below "PdfaRdf" and put the reuslting XML document into your documents metadata | ||
4. You must include a Colorprofile, use the below "PdfaColorProfile" and embed the contents of "sRGB2014.icc" | ||
5. Optionally attach an InvoiceXML using "PdfaFacturxRdf" and "PdfaAttachedFiles" | ||
|
||
### Example | ||
|
||
``` | ||
pw.Document pdf = pw.Document( | ||
... | ||
metadata: PdfaRdf( | ||
... | ||
invoiceRdf: PdfaFacturxRdf().create() | ||
).create(), | ||
); | ||
PdfaColorProfile( | ||
pdf.document, | ||
File('sRGB2014.icc').readAsBytesSync(), | ||
); | ||
PdfaAttachedFiles( | ||
pdf.document, | ||
{ | ||
'factur-x.xml': myInvoiceXmlDocument, | ||
}, | ||
); | ||
``` | ||
|
||
### Validating | ||
|
||
https://demo.verapdf.org | ||
https://avepdf.com/pdfa-validation | ||
https://www.mustangproject.org |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
import 'dart:convert'; | ||
import 'dart:typed_data'; | ||
|
||
import '../../document.dart'; | ||
import '../../format/array.dart'; | ||
import '../../format/base.dart'; | ||
import '../../format/dict.dart'; | ||
import '../../format/dict_stream.dart'; | ||
import '../../format/indirect.dart'; | ||
import '../../format/name.dart'; | ||
import '../../format/num.dart'; | ||
import '../../format/object_base.dart'; | ||
import '../../format/stream.dart'; | ||
import '../../format/string.dart'; | ||
import '../object.dart'; | ||
import 'pdfa_date_format.dart'; | ||
|
||
class PdfaAttachedFiles { | ||
PdfaAttachedFiles( | ||
PdfDocument pdfDocument, | ||
Map<String, String> files, | ||
) { | ||
for (var entry in files.entries) { | ||
_files.add( | ||
_AttachedFileSpec( | ||
pdfDocument, | ||
_AttachedFile( | ||
pdfDocument, | ||
entry.key, | ||
entry.value, | ||
), | ||
), | ||
); | ||
} | ||
_names = _AttachedFileNames( | ||
pdfDocument, | ||
_files, | ||
); | ||
pdfDocument.catalog.attached = this; | ||
} | ||
|
||
final List<_AttachedFileSpec> _files = []; | ||
|
||
late final _AttachedFileNames _names; | ||
|
||
bool get isNotEmpty => _files.isNotEmpty; | ||
|
||
PdfDict catalogNames() { | ||
return PdfDict({ | ||
'/EmbeddedFiles': _names.ref(), | ||
}); | ||
} | ||
|
||
PdfArray catalogAF() { | ||
final tmp = <PdfIndirect>[]; | ||
for (var spec in _files) { | ||
tmp.add(spec.ref()); | ||
} | ||
return PdfArray(tmp); | ||
} | ||
} | ||
|
||
class _AttachedFileNames extends PdfObject<PdfDict> { | ||
_AttachedFileNames( | ||
PdfDocument pdfDocument, | ||
this._files, | ||
) : super( | ||
pdfDocument, | ||
params: PdfDict(), | ||
); | ||
final List<_AttachedFileSpec> _files; | ||
|
||
@override | ||
void prepare() { | ||
super.prepare(); | ||
params['/Names'] = PdfArray( | ||
[ | ||
_PdfRaw(0, _files.first), | ||
], | ||
); | ||
} | ||
} | ||
|
||
class _AttachedFileSpec extends PdfObject<PdfDict> { | ||
_AttachedFileSpec( | ||
PdfDocument pdfDocument, | ||
this._file, | ||
) : super( | ||
pdfDocument, | ||
params: PdfDict(), | ||
); | ||
final _AttachedFile _file; | ||
|
||
@override | ||
void prepare() { | ||
super.prepare(); | ||
|
||
params['/Type'] = const PdfName('/Filespec'); | ||
params['/F'] = PdfString( | ||
Uint8List.fromList(_file.fileName.codeUnits), | ||
); | ||
params['/UF'] = PdfString( | ||
Uint8List.fromList(_file.fileName.codeUnits), | ||
); | ||
params['/EF'] = PdfDict({ | ||
'/F': _file.ref(), | ||
}); | ||
params['/AFRelationship'] = const PdfName('/Unspecified'); | ||
} | ||
} | ||
|
||
class _AttachedFile extends PdfObject<PdfDictStream> { | ||
_AttachedFile( | ||
PdfDocument pdfDocument, | ||
this.fileName, | ||
this.content, | ||
) : super( | ||
pdfDocument, | ||
params: PdfDictStream( | ||
compress: false, | ||
encrypt: false, | ||
), | ||
); | ||
|
||
final String fileName; | ||
final String content; | ||
|
||
@override | ||
void prepare() { | ||
super.prepare(); | ||
|
||
final modDate = PdfaDateFormat().format(dt: DateTime.now()); | ||
params['/Type'] = const PdfName('/EmbeddedFile'); | ||
params['/Subtype'] = const PdfName('/application/octet-stream'); | ||
params['/Params'] = PdfDict({ | ||
'/Size': PdfNum(content.codeUnits.length), | ||
'/ModDate': PdfString( | ||
Uint8List.fromList('D:$modDate+00\'00\''.codeUnits), | ||
), | ||
}); | ||
|
||
params.data = Uint8List.fromList(utf8.encode(content)); | ||
} | ||
} | ||
|
||
class _PdfRaw extends PdfDataType { | ||
const _PdfRaw( | ||
this.nr, | ||
this.spec, | ||
); | ||
|
||
final int nr; | ||
final _AttachedFileSpec spec; | ||
|
||
@override | ||
void output( | ||
PdfObjectBase o, | ||
PdfStream s, [ | ||
int? indent, | ||
]) { | ||
s.putString('(${nr.toString().padLeft(3, '0')}) ${spec.ref()}'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import 'dart:typed_data'; | ||
|
||
import '../../document.dart'; | ||
import '../../format/array.dart'; | ||
import '../../format/dict.dart'; | ||
import '../../format/dict_stream.dart'; | ||
import '../../format/name.dart'; | ||
import '../../format/num.dart'; | ||
import '../../format/string.dart'; | ||
import '../object.dart'; | ||
|
||
class PdfaColorProfile extends PdfObject<PdfDictStream> { | ||
PdfaColorProfile( | ||
PdfDocument pdfDocument, | ||
this.icc, | ||
) : super( | ||
pdfDocument, | ||
params: PdfDictStream( | ||
compress: false, | ||
encrypt: false, | ||
), | ||
) { | ||
pdfDocument.catalog.colorProfile = this; | ||
} | ||
|
||
final Uint8List icc; | ||
|
||
@override | ||
void prepare() { | ||
super.prepare(); | ||
params['/N'] = const PdfNum(3); | ||
params.data = icc; | ||
} | ||
|
||
PdfArray outputIntents() { | ||
return PdfArray<PdfDict>([ | ||
PdfDict({ | ||
'/Type': const PdfName('/OutputIntent'), | ||
'/S': const PdfName('/GTS_PDFA1'), | ||
'/OutputConditionIdentifier': | ||
PdfString(Uint8List.fromList('sRGB2014.icc'.codeUnits)), | ||
'/Info': PdfString(Uint8List.fromList('sRGB2014.icc'.codeUnits)), | ||
'/RegistryName': | ||
PdfString(Uint8List.fromList('http://www.color.org'.codeUnits)), | ||
'/DestOutputProfile': ref(), | ||
}), | ||
]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
class PdfaDateFormat { | ||
String format({ | ||
required DateTime dt, | ||
bool asIso = false, | ||
}) { | ||
final year = dt.year.toString().padLeft(4, '0'); | ||
final month = dt.month.toString().padLeft(2, '0'); | ||
final day = dt.day.toString().padLeft(2, '0'); | ||
final hour = dt.hour.toString().padLeft(2, '0'); | ||
final minute = dt.minute.toString().padLeft(2, '0'); | ||
final second = dt.second.toString().padLeft(2, '0'); | ||
|
||
if (asIso) { | ||
// "yyyy-MM-dd'T'HH:mm:ss" | ||
return '$year-$month-${day}T$hour:$minute:$second'; | ||
} | ||
// "yyyyMMddHHmmss" | ||
return '$year$month$day$hour$minute$second'; | ||
} | ||
} |
Oops, something went wrong.