1 // Copyright 2018 Google LLC.
2 // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3 #ifndef SkPDFDocument_DEFINED
4 #define SkPDFDocument_DEFINED
5
6 #include "include/core/SkDocument.h"
7
8 #include <vector>
9
10 #include "include/core/SkColor.h"
11 #include "include/core/SkMilestone.h"
12 #include "include/core/SkScalar.h"
13 #include "include/core/SkString.h"
14 #include "include/core/SkTime.h"
15 #include "include/private/base/SkNoncopyable.h"
16
17 #define SKPDF_STRING(X) SKPDF_STRING_IMPL(X)
18 #define SKPDF_STRING_IMPL(X) #X
19
20 class SkExecutor;
21 class SkPDFArray;
22 class SkPDFTagTree;
23
24 namespace SkPDF {
25
26 /** Attributes for nodes in the PDF tree. */
27 class SK_API AttributeList : SkNoncopyable {
28 public:
29 AttributeList();
30 ~AttributeList();
31
32 // Each attribute must have an owner (e.g. "Layout", "List", "Table", etc)
33 // and an attribute name (e.g. "BBox", "RowSpan", etc.) from PDF32000_2008 14.8.5,
34 // and then a value of the proper type according to the spec.
35 void appendInt(const char* owner, const char* name, int value);
36 void appendFloat(const char* owner, const char* name, float value);
37 void appendName(const char* owner, const char* attrName, const char* value);
38 void appendFloatArray(const char* owner,
39 const char* name,
40 const std::vector<float>& value);
41 void appendNodeIdArray(const char* owner,
42 const char* attrName,
43 const std::vector<int>& nodeIds);
44
45 private:
46 friend class ::SkPDFTagTree;
47
48 std::unique_ptr<SkPDFArray> fAttrs;
49 };
50
51 /** A node in a PDF structure tree, giving a semantic representation
52 of the content. Each node ID is associated with content
53 by passing the SkCanvas and node ID to SkPDF::SetNodeId() when drawing.
54 NodeIDs should be unique within each tree.
55 */
56 struct StructureElementNode {
57 SkString fTypeString;
58 std::vector<std::unique_ptr<StructureElementNode>> fChildVector;
59 int fNodeId = 0;
60 std::vector<int> fAdditionalNodeIds;
61 AttributeList fAttributes;
62 SkString fAlt;
63 SkString fLang;
64 };
65
66 /** Optional metadata to be passed into the PDF factory function.
67 */
68 struct Metadata {
69 /** The document's title.
70 */
71 SkString fTitle;
72
73 /** The name of the person who created the document.
74 */
75 SkString fAuthor;
76
77 /** The subject of the document.
78 */
79 SkString fSubject;
80
81 /** Keywords associated with the document. Commas may be used to delineate
82 keywords within the string.
83 */
84 SkString fKeywords;
85
86 /** If the document was converted to PDF from another format,
87 the name of the conforming product that created the
88 original document from which it was converted.
89 */
90 SkString fCreator;
91
92 /** The product that is converting this document to PDF.
93 */
94 SkString fProducer = SkString("Skia/PDF m" SKPDF_STRING(SK_MILESTONE));
95
96 /** The date and time the document was created.
97 The zero default value represents an unknown/unset time.
98 */
99 SkTime::DateTime fCreation = {0, 0, 0, 0, 0, 0, 0, 0};
100
101 /** The date and time the document was most recently modified.
102 The zero default value represents an unknown/unset time.
103 */
104 SkTime::DateTime fModified = {0, 0, 0, 0, 0, 0, 0, 0};
105
106 /** The DPI (pixels-per-inch) at which features without native PDF support
107 will be rasterized (e.g. draw image with perspective, draw text with
108 perspective, ...) A larger DPI would create a PDF that reflects the
109 original intent with better fidelity, but it can make for larger PDF
110 files too, which would use more memory while rendering, and it would be
111 slower to be processed or sent online or to printer.
112 */
113 SkScalar fRasterDPI = SK_ScalarDefaultRasterDPI;
114
115 /** If true, include XMP metadata, a document UUID, and sRGB output intent
116 information. This adds length to the document and makes it
117 non-reproducable, but are necessary features for PDF/A-2b conformance
118 */
119 bool fPDFA = false;
120
121 /** Encoding quality controls the trade-off between size and quality. By
122 default this is set to 101 percent, which corresponds to lossless
123 encoding. If this value is set to a value <= 100, and the image is
124 opaque, it will be encoded (using JPEG) with that quality setting.
125 */
126 int fEncodingQuality = 101;
127
128 /** An optional tree of structured document tags that provide
129 a semantic representation of the content. The caller
130 should retain ownership.
131 */
132 StructureElementNode* fStructureElementTreeRoot = nullptr;
133
134 /** Executor to handle threaded work within PDF Backend. If this is nullptr,
135 then all work will be done serially on the main thread. To have worker
136 threads assist with various tasks, set this to a valid SkExecutor
137 instance. Currently used for executing Deflate algorithm in parallel.
138
139 If set, the PDF output will be non-reproducible in the order and
140 internal numbering of objects, but should render the same.
141
142 Experimental.
143 */
144 SkExecutor* fExecutor = nullptr;
145
146 /** PDF streams may be compressed to save space.
147 Use this to specify the desired compression vs time tradeoff.
148 */
149 enum class CompressionLevel : int {
150 Default = -1,
151 None = 0,
152 LowButFast = 1,
153 Average = 6,
154 HighButSlow = 9,
155 } fCompressionLevel = CompressionLevel::Default;
156
157 /** Preferred Subsetter. Only respected if both are compiled in.
158
159 The Sfntly subsetter is deprecated.
160
161 Experimental.
162 */
163 enum Subsetter {
164 kHarfbuzz_Subsetter,
165 kSfntly_Subsetter,
166 } fSubsetter = kHarfbuzz_Subsetter;
167 };
168
169 /** Associate a node ID with subsequent drawing commands in an
170 SkCanvas. The same node ID can appear in a StructureElementNode
171 in order to associate a document's structure element tree with
172 its content.
173
174 A node ID of zero indicates no node ID.
175
176 @param canvas The canvas used to draw to the PDF.
177 @param nodeId The node ID for subsequent drawing commands.
178 */
179 SK_API void SetNodeId(SkCanvas* dst, int nodeID);
180
181 /** Create a PDF-backed document, writing the results into a SkWStream.
182
183 PDF pages are sized in point units. 1 pt == 1/72 inch == 127/360 mm.
184
185 @param stream A PDF document will be written to this stream. The document may write
186 to the stream at anytime during its lifetime, until either close() is
187 called or the document is deleted.
188 @param metadata a PDFmetadata object. Any fields may be left empty.
189
190 @returns NULL if there is an error, otherwise a newly created PDF-backed SkDocument.
191 */
192 SK_API sk_sp<SkDocument> MakeDocument(SkWStream* stream, const Metadata& metadata);
193
MakeDocument(SkWStream * stream)194 static inline sk_sp<SkDocument> MakeDocument(SkWStream* stream) {
195 return MakeDocument(stream, Metadata());
196 }
197
198 } // namespace SkPDF
199
200 #undef SKPDF_STRING
201 #undef SKPDF_STRING_IMPL
202 #endif // SkPDFDocument_DEFINED
203