diff --git a/src/actions.rs b/src/actions.rs index d38bfe4..6595189 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -186,22 +186,32 @@ pub enum ActionType { /// Go to a destination in another document. RemoteGoTo, /// Launch an application. + /// + /// This action type is forbidden in PDF/A. Launch, /// Open a URI. Uri, /// Set an annotation's hidden flag. PDF 1.2+. SubmitForm, /// Set form fields to their default values. PDF 1.2+. + /// + /// This action type is forbidden in PDF/A. ResetForm, /// Import form field values from a file. PDF 1.2+. + /// + /// This action type is forbidden in PDF/A. ImportData, /// Execute a JavaScript action. PDF 1.2+. /// /// See Adobe's /// [JavaScript for Acrobat API Reference](https://opensource.adobe.com/dc-acrobat-sdk-docs/acrobatsdk/pdfs/acrobatsdk_jsapiref.pdf) /// and ISO 21757. + /// + /// This action type is forbidden in PDF/A. JavaScript, /// A rendition action to control the playing of multimedia content. PDF 1.5+. + /// + /// This action type is forbidden in PDF/A. Rendition, } diff --git a/src/annotations.rs b/src/annotations.rs index f1b2b4f..f66c035 100644 --- a/src/annotations.rs +++ b/src/annotations.rs @@ -58,6 +58,8 @@ impl<'a> Annotation<'a> { } /// Write the `/F` attribute. + /// + /// Required for all annotations in PDF/A except for `Popup`. pub fn flags(&mut self, flags: AnnotationFlags) -> &mut Self { self.pair(Name(b"F"), flags.bits() as i32); self @@ -66,6 +68,8 @@ impl<'a> Annotation<'a> { /// Start writing the `/AP` dictionary to set how the annotation shall /// be presented visually. If this dictionary contains sub dictionaries, /// [`Self::appearance_state`] must be set. PDF 1.2+. + /// + /// Required for many annotations in PDF/A. pub fn appearance(&mut self) -> Appearance<'_> { self.insert(Name(b"AP")).start() } @@ -147,12 +151,16 @@ impl<'a> Annotation<'a> { /// Start writing the `/A` dictionary. Only permissible for the subtypes /// `Link` and `Widget`. + /// + /// Note that this attribute is forbidden in PDF/A. pub fn action(&mut self) -> Action<'_> { self.insert(Name(b"A")).start() } /// Start writing the `/AA` dictionary. Only permissible for the subtype /// `Widget`. PDF 1.3+. + /// + /// Note that this attribute is forbidden in PDF/A. pub fn additional_actions(&mut self) -> AdditionalActions<'_> { self.insert(Name(b"AA")).start() } @@ -246,10 +254,15 @@ pub enum AnnotationType { /// Strike out the text on the page. PDF 1.3+. StrikeOut, /// A reference to another file. PDF 1.3+. + /// + /// Note that this annotation type is forbidden in PDF/A-1 and restricted in + /// other PDF/A parts. FileAttachment, /// A widget annotation. PDF 1.2+. Widget, /// A screen annotation. PDF 1.5+. + /// + /// Note that this annotation type is forbidden in PDF/A. Screen, } @@ -326,20 +339,32 @@ bitflags::bitflags! { /// This will hide the annotation if the viewer does not recognize its /// subtype. Otherwise, it will be rendered as specified in its appearance /// stream. + /// + /// Must not be set for PDF/A. const INVISIBLE = 1 << 0; /// This hides the annotation from view and disallows interaction. PDF 1.2+. + /// + /// Must not be set for PDF/A. const HIDDEN = 1 << 1; /// Print the annotation. If not set, it will be always hidden on print. /// PDF 1.2+. + /// + /// Must be set for PDF/A. const PRINT = 1 << 2; /// Do not zoom the annotation appearance if the document is zoomed in. /// PDF 1.3+. + /// + /// Must be set for text annotations in PDF/A. const NO_ZOOM = 1 << 3; /// Do not rotate the annotation appearance if the document is zoomed in. /// PDF 1.3+. + /// + /// Must be set for text annotations in PDF/A. const NO_ROTATE = 1 << 4; /// Do not view the annotation on screen. It may still show on print. /// PDF 1.3+. + /// + /// Must not be set for PDF/A. const NO_VIEW = 1 << 5; /// Do not allow interactions. PDF 1.3+. const READ_ONLY = 1 << 6; @@ -348,6 +373,8 @@ bitflags::bitflags! { const LOCKED = 1 << 7; /// Invert the interpretation of the `no_view` flag for certain events. /// PDF 1.5+. + /// + /// Must not be set for PDF/A. const TOGGLE_NO_VIEW = 1 << 8; /// Do not allow content changes. PDF 1.7+. const LOCKED_CONTENTS = 1 << 9; diff --git a/src/color.rs b/src/color.rs index 9a8efa0..3c354ad 100644 --- a/src/color.rs +++ b/src/color.rs @@ -353,6 +353,11 @@ impl ColorSpace<'_> { } /// Device color spaces. +/// +/// Please note that the use of the device color spaces is restricted by several +/// PDF standards such as PDF/A, PDF/X, et cetera. Their appearance will be +/// governed by any applicable [output intent](crate::writers::OutputIntent) and +/// default color spaces. impl ColorSpace<'_> { /// Write a `DeviceRGB` color space. pub fn device_rgb(self) { @@ -647,7 +652,8 @@ impl DeviceNAttrs<'_> { /// Start writing the `/Colorants` dictionary. Its keys are the colorant /// names and its values are separation color space arrays. /// - /// Required if the `/Subtype` attribute is `NChannel`. + /// Required if the `/Subtype` attribute is `NChannel`. Required for spot + /// colors in PDF/A-2, PDF/A-3, and PDF/A-4. pub fn colorants(&mut self) -> TypedDict<'_, Dict> { self.dict.insert(Name(b"Colorants")).dict().typed() } @@ -1234,7 +1240,7 @@ impl SeparationInfo<'_> { /// Writer for an _output intent dictionary_. PDF 1.4+. /// /// This describes the output conditions under which the document may be -/// rendered. +/// rendered. Encouraged by PDF/A. pub struct OutputIntent<'a> { dict: Dict<'a>, } @@ -1289,6 +1295,8 @@ impl OutputIntent<'_> { /// Required if `/OutputConditionIdentifier` does not contain a well-known /// identifier for the output condition. /// Must reference an [ICC profile](IccProfile) stream. + /// + /// Required for PDF/A. The profile must have the `prtr` or `mntr` tag. pub fn dest_output_profile(&mut self, profile: Ref) -> &mut Self { self.dict.pair(Name(b"DestOutputProfile"), profile); self @@ -1300,6 +1308,8 @@ pub enum OutputIntentSubtype<'a> { /// `GTS_PDFX` PDFX, /// `GTS_PDFA1` + /// + /// This is the right value for PDF/A-1 through PDF/A-4. PDFA, /// `ISO_PDFE1` PDFE, diff --git a/src/content.rs b/src/content.rs index 38ecf3c..354ff32 100644 --- a/src/content.rs +++ b/src/content.rs @@ -876,7 +876,7 @@ impl Content { } } -// TODO: Inline images. +// TODO: Inline images. Also check clause 6.1.10 of PDF/A-2 spec. /// XObjects. impl Content { @@ -992,6 +992,8 @@ impl<'a> PropertyList<'a> { deref!('a, PropertyList<'a> => Dict<'a>, dict); /// Writer for an _actifact property list dictionary_. PDF 1.4+. +/// +/// Required for marking up pagination artifacts in some PDF/A profiles. pub struct Artifact<'a> { dict: Dict<'a>, } @@ -1342,6 +1344,8 @@ impl<'a> ExtGraphicsState<'a> { /// Write the `OPM` attribute to set the overprint mode for components that /// have been zeroed out. PDF 1.3+. + /// + /// Note that this attribute is restricted by PDF/A. pub fn overprint_mode(&mut self, mode: OverprintMode) -> &mut Self { self.pair(Name(b"OPM"), mode.to_int()); self @@ -1385,6 +1389,8 @@ impl<'a> ExtGraphicsState<'a> { } /// Write the `TR` attribute to set the transfer function. + /// + /// Note that this key is illegal in PDF/A. pub fn transfer(&mut self, func: Ref) -> &mut Self { self.pair(Name(b"TR"), func); self @@ -1398,6 +1404,8 @@ impl<'a> ExtGraphicsState<'a> { } /// Write the `HT` attribute to set the halftone. + /// + /// Note that this value may be ignored in PDF/A. pub fn halftone(&mut self, ht: Ref) -> &mut Self { self.pair(Name(b"HT"), ht); self @@ -1411,6 +1419,8 @@ impl<'a> ExtGraphicsState<'a> { } /// Write the `FL` attribute to set the flatness tolerance. PDF 1.3+. + /// + /// Note that this key may be ignored in PDF/A. pub fn flatness(&mut self, tolerance: f32) -> &mut Self { self.pair(Name(b"FL"), tolerance); self @@ -1429,23 +1439,31 @@ impl<'a> ExtGraphicsState<'a> { } /// Write the `BM` attribute to set the blend mode. PDF 1.4+. + /// + /// Note that this key is restricted in PDF/A-1. pub fn blend_mode(&mut self, mode: BlendMode) -> &mut Self { self.pair(Name(b"BM"), mode.to_name()); self } /// Start writing the `SMask` attribute. PDF 1.4+. + /// + /// Note that this key is forbidden in PDF/A-1. pub fn soft_mask(&mut self) -> SoftMask<'_> { self.insert(Name(b"SMask")).start() } /// Write the `SMask` attribute using a name. PDF 1.4+. + /// + /// Note that this key is forbidden in PDF/A-1. pub fn soft_mask_name(&mut self, mask: Name) -> &mut Self { self.pair(Name(b"SMask"), mask); self } /// Write the `CA` attribute to set the stroking alpha constant. PDF 1.4+. + /// + /// Note that this key is restricted in PDF/A-1. pub fn stroking_alpha(&mut self, alpha: f32) -> &mut Self { self.pair(Name(b"CA"), alpha); self @@ -1453,6 +1471,8 @@ impl<'a> ExtGraphicsState<'a> { /// Write the `ca` attribute to set the non-stroking alpha constant. PDF /// 1.4+. + /// + /// Note that this key is restricted in PDF/A-1. pub fn non_stroking_alpha(&mut self, alpha: f32) -> &mut Self { self.pair(Name(b"ca"), alpha); self @@ -1529,6 +1549,9 @@ pub enum OverprintMode { /// An overprint operation will only discard the underlying colorant /// component (e.g. cyan in CMYK) if the new corresponding colorant is /// non-zero. + /// + /// Note that this value is forbidden by PDF/A for ICCBased color spaces + /// when overprinting is enabled. IgnoreZeroChannel, } diff --git a/src/files.rs b/src/files.rs index 6c5e446..3fb8894 100644 --- a/src/files.rs +++ b/src/files.rs @@ -54,7 +54,10 @@ impl<'a> FileSpec<'a> { /// /// This only sets an embedded file for the `F` attribute corresponding to /// the [`path`](Self::path) method. You will need to write this dictionary - /// manually if you need to set `UF`. + /// manually if you need to set `UF` which is required in PDF/A-3. + /// + /// Note that this key is forbidden in PDF/A-1 and restricted in PDF/A-2 and + /// PDF/A-4. pub fn embedded_file(&mut self, id: Ref) -> &mut Self { self.insert(Name(b"EF")).dict().pair(Name(b"F"), id); self diff --git a/src/font.rs b/src/font.rs index a864d88..4a0c9a5 100644 --- a/src/font.rs +++ b/src/font.rs @@ -27,6 +27,9 @@ impl<'a> Type1Font<'a> { /// Write the `/BaseFont` attribute. This is the PostScript name of the /// font. Required. + /// + /// In PDF/A files, the standard 14 fonts are unavailable, so you must + /// embed the font data. pub fn base_font(&mut self, name: Name) -> &mut Self { self.pair(Name(b"BaseFont"), name); self @@ -180,6 +183,10 @@ impl<'a> Type3Font<'a> { /// Write the `/ToUnicode` attribute. PDF 1.2+. /// /// A suitable character map can be built with [`UnicodeCmap`]. + /// + /// This attribute is required in some profiles of PDF/A-2, PDF/A-3, and + /// PDF/A-4 for some fonts. When present, these standards require that no + /// character may be mapped to `0`, `U+FEFF`, or `U+FFFE`. pub fn to_unicode(&mut self, id: Ref) -> &mut Self { self.pair(Name(b"ToUnicode"), id); self @@ -350,6 +357,10 @@ impl<'a> CidFont<'a> { } /// Write the `/CIDToGIDMap` attribute as a predefined name. + /// + /// The attribute must be present for PDF/A. The only permissible predefined + /// name is `Identity`, otherwise [`Self::cid_to_gid_map_stream`] must be + /// used. pub fn cid_to_gid_map_predefined(&mut self, name: Name) -> &mut Self { self.pair(Name(b"CIDToGIDMap"), name); self @@ -357,6 +368,8 @@ impl<'a> CidFont<'a> { /// Write the `/CIDToGIDMap` attribute as a reference to a stream, whose /// bytes directly map from CIDs to glyph indices. + /// + /// The attribute must be present for PDF/A. pub fn cid_to_gid_map_stream(&mut self, stream: Ref) -> &mut Self { self.pair(Name(b"CIDToGIDMap"), stream); self @@ -559,14 +572,143 @@ impl<'a> FontDescriptor<'a> { /// Write the `/CharSet` attribute, encoding the character names of a font /// subset as a string. This is only relevant for Type 1 fonts. PDF 1.1+. + /// + /// If present in PDF/A, this must include all characters in the subset, + /// even if they are not used in the document. pub fn char_set(&mut self, names: Str) -> &mut Self { self.pair(Name(b"CharSet"), names); self } } +/// Additional `FontDescriptor` attributes for CIDFonts. +impl FontDescriptor<'_> { + /// Write the `/Style` attribute. Optional. + /// + /// The class and subclass values should be extracted from the + /// `sFamilyClass` field of the OS/2 table. The `panose` array should be + /// extracted from the `panose` field of the OS/2 table. + pub fn style(&mut self, class: u8, subclass: u8, panose: [u8; 10]) -> &mut Self { + let mut bytes = [0; 12]; + bytes[0] = class; + bytes[1] = subclass; + bytes[2..].copy_from_slice(&panose); + self.insert(Name(b"Style")).dict().pair(Name(b"Panose"), Str(&bytes)); + self + } + + /// Start writing the `/FD` attribute. Optional. + /// + /// Overrides the global font descriptor for specific glyphs. + pub fn descriptor_override(&mut self) -> FontDescriptorOverride<'_> { + self.insert(Name(b"FD")).start() + } + + /// Write the `/CIDSet` attribute. + /// + /// If present in PDF/A, this must include all characters in the subset, + /// even if they are not used in the document. + pub fn cid_set(&mut self, id: Ref) -> &mut Self { + self.pair(Name(b"CIDSet"), id); + self + } +} + deref!('a, FontDescriptor<'a> => Dict<'a>, dict); +/// Writer for a _font descriptor override dictionary_. +/// +/// This struct is created by [`FontDescriptor::descriptor_override`]. +/// +/// The font descriptor dictionaries within can only contain metrics data. +pub struct FontDescriptorOverride<'a> { + dict: Dict<'a>, +} + +writer!(FontDescriptorOverride: |obj| { + Self { dict: obj.dict() } +}); + +impl FontDescriptorOverride<'_> { + /// Start writing a `FontDescriptor` dictionary for a custom character + /// class. + pub fn custom_class(&mut self, class: Name) -> FontDescriptor<'_> { + self.insert(class).start() + } + + /// Write a class override referencing a `FontDescriptor` dictionary + /// indirectly. + pub fn custom_class_ref(&mut self, class: Name, id: Ref) -> &mut Self { + self.pair(class, id); + self + } + + /// Start writing a `FontDescriptor` dictionary for a predefined CJK class. + pub fn cjk_class(&mut self, class: CjkClass) -> FontDescriptor<'_> { + self.insert(class.to_name()).start() + } + + /// Write a class override for a predefined CJK class referencing a + /// `FontDescriptor` dictionary indirectly. + pub fn cjk_class_ref(&mut self, class: CjkClass, id: Ref) -> &mut Self { + self.pair(class.to_name(), id); + self + } +} + +deref!('a, FontDescriptorOverride<'a> => Dict<'a>, dict); + +/// Glyph classes for CJK fonts as defined in ISO 32000-1:2008. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[allow(missing_docs)] +pub enum CjkClass { + Alphabetic, + AlphaNum, + Dingbats, + DingbatsRot, + Generic, + GenericRot, + Hangul, + Hanja, + Hanzi, + HRoman, + HRomanRot, + HKana, + HKanaRot, + HojoKanji, + Kana, + Kanji, + Proportional, + ProportionalRot, + Ruby, +} + +impl CjkClass { + pub(crate) fn to_name(self) -> Name<'static> { + match self { + Self::Alphabetic => Name(b"Alphabetic"), + Self::AlphaNum => Name(b"AlphaNum"), + Self::Dingbats => Name(b"Dingbats"), + Self::DingbatsRot => Name(b"DingbatsRot"), + Self::Generic => Name(b"Generic"), + Self::GenericRot => Name(b"GenericRot"), + Self::Hangul => Name(b"Hangul"), + Self::Hanja => Name(b"Hanja"), + Self::Hanzi => Name(b"Hanzi"), + Self::HRoman => Name(b"HRoman"), + Self::HRomanRot => Name(b"HRomanRot"), + Self::HKana => Name(b"HKana"), + Self::HKanaRot => Name(b"HKanaRot"), + Self::HojoKanji => Name(b"HojoKanji"), + Self::Kana => Name(b"Kana"), + Self::Kanji => Name(b"Kanji"), + Self::Proportional => Name(b"Proportional"), + Self::ProportionalRot => Name(b"ProportionalRot"), + Self::Ruby => Name(b"Ruby"), + } + } +} + /// The width of a font's glyphs. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] #[allow(missing_docs)] @@ -650,10 +792,61 @@ impl<'a> Cmap<'a> { info.write(self.insert(Name(b"CIDSystemInfo"))); self } + + /// Write the `/WMode` attribute. Optional. + /// + /// This describes whether the CMap applies to a font with horizontal or + /// vertical writing mode. The default is whatever is specified in the CMap. + /// + /// This is required in PDF/A and must match the writing mode of the + /// embedded CMap. + pub fn writing_mode(&mut self, mode: WMode) -> &mut Self { + self.pair(Name(b"WMode"), mode.to_int()); + self + } + + /// Write the `/UseCMap` attribute using a stream reference. Optional. + /// + /// This allows specifying a base CMap to extend. + /// + /// Note that this attribute is restricted in PDF/A and may only be used + /// with the well-known CMap names from the PDF standard. Use + /// [`Self::use_cmap_predefined`] to specify a predefined name. + pub fn use_cmap_stream(&mut self, cmap: Ref) -> &mut Self { + self.pair(Name(b"UseCMap"), cmap); + self + } + + /// Write the `/UseCMap` attribute using a predefined name. Optional. + /// + /// This allows specifying a base CMap to extend. + /// + /// Note that this attribute is restricted in PDF/A. + pub fn use_cmap_predefined(&mut self, name: Name) -> &mut Self { + self.pair(Name(b"UseCMap"), name); + self + } } deref!('a, Cmap<'a> => Stream<'a>, stream); +/// The writing mode of a character map. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[allow(missing_docs)] +pub enum WMode { + Horizontal, + Vertical, +} + +impl WMode { + pub(crate) fn to_int(self) -> i32 { + match self { + Self::Horizontal => 0, + Self::Vertical => 1, + } + } +} + /// A builder for a `/ToUnicode` character map stream. pub struct UnicodeCmap { buf: Vec, @@ -666,8 +859,15 @@ impl UnicodeCmap where G: GlyphId, { - /// Create a new, empty unicode character map. + /// Create a new, empty unicode character map for a horizontal writing mode + /// font. pub fn new(name: Name, info: SystemInfo) -> Self { + Self::with_writing_mode(name, info, WMode::Horizontal) + } + + /// Create a new, empty unicode character map while specifying the writing + /// mode. + pub fn with_writing_mode(name: Name, info: SystemInfo, mode: WMode) -> Self { // https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5014.CIDFont_Spec.pdf let mut buf = Vec::new(); @@ -713,6 +913,9 @@ where buf.extend(b" def\n"); buf.extend(b"/CMapVersion 1 def\n"); buf.extend(b"/CMapType 0 def\n"); + buf.extend(b"/WMode "); + buf.push_int(mode.to_int()); + buf.extend(b" def\n"); // We just cover the whole unicode codespace. buf.extend(b"1 begincodespacerange\n"); diff --git a/src/forms.rs b/src/forms.rs index 1bdcdb8..1dfe1ff 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -1,6 +1,5 @@ -use crate::types::AnnotationType; - use super::*; +use crate::types::AnnotationType; /// Writer for an _interactive forms dictionary_. PDF 1.2+. /// @@ -154,6 +153,8 @@ impl<'a> Field<'a> { /// Start writing the `/AA` dictionary to set the field's response to /// various trigger events. + /// + /// Note that this attribute is forbidden in PDF/A. pub fn additional_actions(&mut self) -> AdditionalActions<'_> { self.insert(Name(b"AA")).start() } diff --git a/src/lib.rs b/src/lib.rs index f0d9c69..293e7bb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -127,8 +127,8 @@ pub mod writers { }; pub use files::{EmbeddedFile, EmbeddingParams, FileSpec}; pub use font::{ - CidFont, Cmap, Differences, Encoding, FontDescriptor, Type0Font, Type1Font, - Type3Font, Widths, + CidFont, Cmap, Differences, Encoding, FontDescriptor, FontDescriptorOverride, + Type0Font, Type1Font, Type3Font, Widths, }; pub use forms::{Field, Form}; pub use functions::{ @@ -167,7 +167,9 @@ pub mod types { LineCapStyle, LineJoinStyle, MaskType, OverprintMode, ProcSet, RenderingIntent, TextRenderingMode, }; - pub use font::{CidFontType, FontFlags, FontStretch, SystemInfo, UnicodeCmap}; + pub use font::{ + CidFontType, CjkClass, FontFlags, FontStretch, SystemInfo, UnicodeCmap, + }; pub use forms::{ CheckBoxState, ChoiceOptions, FieldFlags, FieldType, Quadding, SigFlags, }; @@ -260,7 +262,7 @@ impl Pdf { /// The file identifier is a pair of two byte strings that shall be used to /// uniquely identify a particular file. The first string should always stay /// the same for a document, the second should change for each revision. It - /// is optional, but recommended. PDF 1.1+. + /// is optional, but recommended. In PDF/A, this is required. PDF 1.1+. pub fn set_file_id(&mut self, id: (Vec, Vec)) { self.file_id = Some(id); } diff --git a/src/object.rs b/src/object.rs index 1752c06..ea34a1f 100644 --- a/src/object.rs +++ b/src/object.rs @@ -863,13 +863,25 @@ deref!('a, Stream<'a> => Dict<'a>, dict); pub enum Filter { AsciiHexDecode, Ascii85Decode, + /// Lempel-Ziv-Welch (LZW) compression. + /// + /// Note that this filter is forbidden in PDF/A. LzwDecode, FlateDecode, RunLengthDecode, CcittFaxDecode, Jbig2Decode, + /// Decodes JPEG/JFIF files with a SOF0, SOF1, or (PDF 1.3+) SOF2 marker. + /// + /// See ISO 32000-1:2008, Section 7.4.8 and Adobe Technical Note #5116. DctDecode, + /// Decodes JPEG2000 files with a JPX baseline marker. + /// + /// Note that additional restrictions are imposed by PDF/A and PDF/X. JpxDecode, + /// Encrypt the stream. + /// + /// Note that this filter is restricted in PDF/A. Crypt, } diff --git a/src/structure.rs b/src/structure.rs index b493e4b..fb2e53a 100644 --- a/src/structure.rs +++ b/src/structure.rs @@ -1,6 +1,5 @@ -use crate::color::SeparationInfo; - use super::*; +use crate::color::SeparationInfo; /// Writer for a _document catalog dictionary_. /// @@ -67,18 +66,24 @@ impl<'a> Catalog<'a> { /// Start writing the `/StructTreeRoot` attribute to specify the root of the /// document's structure tree. PDF 1.3+. + /// + /// Must be present in some PDF/A profiles like PDF/A-2a. pub fn struct_tree_root(&mut self) -> StructTreeRoot<'_> { self.insert(Name(b"StructTreeRoot")).start() } /// Start writing the `/MarkInfo` dictionary to specify this document's /// conformance with the tagged PDF specification. PDF 1.4+. + /// + /// Must be present in some PDF/A profiles like PDF/A-2a. pub fn mark_info(&mut self) -> MarkInfo<'_> { self.insert(Name(b"MarkInfo")).start() } /// Write the `/Lang` attribute to specify the language of the document as a /// RFC 3066 language tag. PDF 1.4+. + /// + /// Required in some PDF/A profiles like PDF/A-2a. pub fn lang(&mut self, lang: TextStr) -> &mut Self { self.pair(Name(b"Lang"), lang); self @@ -93,6 +98,8 @@ impl<'a> Catalog<'a> { /// Start writing the `/AA` dictionary. This sets the additional actions for /// the whole document. PDF 1.4+. + /// + /// Note that this attribute is forbidden in PDF/A. pub fn additional_actions(&mut self) -> AdditionalActions<'_> { self.insert(Name(b"AA")).start() } @@ -133,6 +140,8 @@ impl<'a> Catalog<'a> { /// /// Each entry in the array is an [output intent /// dictionary.](writers::OutputIntent) + /// + /// Must be present in PDF/X documents, encouraged in PDF/A documents. pub fn output_intents(&mut self) -> TypedArray<'_, OutputIntent> { self.insert(Name(b"OutputIntents")).array().typed() } @@ -383,6 +392,9 @@ impl<'a> StructElement<'a> { /// Write the `/S` attribute to specify the role of this structure element /// as a custom name. Required if no standard type is specified with /// [`Self::kind`]. + /// + /// In some PDF/A profiles like PDF/A-2a, custom kinds must be mapped to + /// their closest standard type in the role map. pub fn custom_kind(&mut self, name: Name) -> &mut Self { self.dict.pair(Name(b"S"), name); self @@ -808,6 +820,8 @@ writer!(MarkInfo: |obj| Self { dict: obj.dict() }); impl<'a> MarkInfo<'a> { /// Write the `/Marked` attribute to indicate whether the document conforms /// to the Tagged PDF specification. + /// + /// Must be `true` in some PDF/A profiles like PDF/A-2a. pub fn marked(&mut self, conformant: bool) -> &mut Self { self.pair(Name(b"Marked"), conformant); self @@ -1154,6 +1168,9 @@ impl<'a> Page<'a> { /// Start writing the `/Group` dictionary to set the transparency settings /// for the page. PDF 1.4+. + /// + /// Required for pages with transparency in PDF/A if no output intent is + /// present. pub fn group(&mut self) -> Group<'_> { self.insert(Name(b"Group")).start() } @@ -1208,6 +1225,8 @@ impl<'a> Page<'a> { /// Start writing the `/AA` dictionary. This sets the actions to perform /// when a page is opened or closed. PDF 1.2+. + /// + /// Note that this attribute is forbidden in PDF/A. pub fn additional_actions(&mut self) -> AdditionalActions<'_> { self.insert(Name(b"AA")).start() } @@ -1216,6 +1235,8 @@ impl<'a> Page<'a> { /// 1.4+. /// /// The reference shall point to a [metadata stream](Metadata). + /// + /// Required in PDF/A. pub fn metadata(&mut self, id: Ref) -> &mut Self { self.pair(Name(b"Metadata"), id); self @@ -1416,12 +1437,17 @@ impl Names<'_> { /// Start writing the `/EmbeddedFiles` attribute to name [embedded /// files](EmbeddedFile). PDF 1.4+. + /// + /// Note that this key is forbidden in PDF/A-1, and restricted in PDF/A-2 + /// and PDF/A-4. pub fn embedded_files(&mut self) -> NameTree<'_, Ref> { self.dict.insert(Name(b"EmbeddedFiles")).start() } /// Start writing the `/AlternatePresentations` attribute to name alternate /// presentations. PDF 1.4+. + /// + /// Note that this key is forbidden in PDF/A. pub fn alternate_presentations(&mut self) -> NameTree<'_, Ref> { self.dict.insert(Name(b"AlternatePresentations")).start() } diff --git a/src/xobject.rs b/src/xobject.rs index 0957700..8ccc72e 100644 --- a/src/xobject.rs +++ b/src/xobject.rs @@ -93,6 +93,8 @@ impl<'a> ImageXObject<'a> { } /// Write the `/Interpolate` attribute. + /// + /// Must be false or unset for PDF/A files. pub fn interpolate(&mut self, interpolate: bool) -> &mut Self { self.pair(Name(b"Interpolate"), interpolate); self @@ -101,6 +103,8 @@ impl<'a> ImageXObject<'a> { /// Write the `/Alternates` attribute. PDF 1.3+. /// /// Images that may replace this image. The order is not relevant. + /// + /// Note that this key is forbidden in PDF/A. pub fn alternates(&mut self, alternates: impl IntoIterator) -> &mut Self { self.insert(Name(b"Alternates")).array().items(alternates); self @@ -109,10 +113,14 @@ impl<'a> ImageXObject<'a> { /// Start writing the `/SMask` attribute. PDF 1.4+. /// /// Must not be used if this image already is an image soft mask. + /// + /// Note that this key is forbidden in PDF/A-1. pub fn s_mask(&mut self, x_object: Ref) -> &mut Self { self.pair(Name(b"SMask"), x_object); self } + /// + /// Note that this key is forbidden in PDF/A-1. /// Write the `/SMaskInData` attribute. PDF 1.5+. /// @@ -235,6 +243,8 @@ impl<'a> FormXObject<'a> { /// Start writing the `/Ref` dictionary to identify the page from an /// external document that the XObject is a reference to. PDF 1.4+. + /// + /// Note that this key is forbidden in PDF/A. pub fn reference(&mut self) -> Reference<'_> { self.insert(Name(b"Ref")).start() } @@ -282,6 +292,8 @@ impl<'a> Group<'a> { /// /// This is optional for isolated groups and required for groups where the /// color space cannot be derived from the parent. + /// + /// Required in PDF/A-2 through PDF/A-4 if there is no OutputIntent. pub fn color_space(&mut self) -> ColorSpace<'_> { self.insert(Name(b"CS")).start() } @@ -312,6 +324,8 @@ deref!('a, Group<'a> => Dict<'a>, dict); /// Writer for an _external XObject reference dictionary_. PDF 1.4+. /// /// This struct is created by [`FormXObject::reference`]. +/// +/// Reference XObjects are forbidden in PDF/A. pub struct Reference<'a> { dict: Dict<'a>, }