/src/libreoffice/vcl/inc/pdf/pdfwriter_impl.hxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #pragma once |
21 | | |
22 | | #include <sal/config.h> |
23 | | |
24 | | #include <map> |
25 | | #include <list> |
26 | | #include <unordered_map> |
27 | | #include <unordered_set> |
28 | | #include <memory> |
29 | | #include <string_view> |
30 | | #include <vector> |
31 | | #include <stack> |
32 | | #include <variant> |
33 | | |
34 | | #include <pdf/ResourceDict.hxx> |
35 | | #include <pdf/BitmapID.hxx> |
36 | | #include <pdf/Matrix3.hxx> |
37 | | |
38 | | #include <com/sun/star/lang/Locale.hpp> |
39 | | #include <com/sun/star/util/XURLTransformer.hpp> |
40 | | #include <osl/file.hxx> |
41 | | #include <rtl/strbuf.hxx> |
42 | | #include <rtl/ustring.hxx> |
43 | | #include <tools/gen.hxx> |
44 | | #include <vcl/alpha.hxx> |
45 | | #include <vcl/bitmap.hxx> |
46 | | #include <vcl/gradient.hxx> |
47 | | #include <vcl/graphictools.hxx> |
48 | | #include <vcl/hatch.hxx> |
49 | | #include <vcl/virdev.hxx> |
50 | | #include <vcl/pdfwriter.hxx> |
51 | | #include <vcl/wall.hxx> |
52 | | #include <o3tl/safeint.hxx> |
53 | | #include <o3tl/typed_flags_set.hxx> |
54 | | #include <o3tl/lru_map.hxx> |
55 | | #include <comphelper/hash.hxx> |
56 | | #include <tools/stream.hxx> |
57 | | #include <vcl/BinaryDataContainer.hxx> |
58 | | #include <vcl/pdf/PDFNote.hxx> |
59 | | |
60 | | #include <vcl/filter/pdfobjectcontainer.hxx> |
61 | | #include <vcl/settings.hxx> |
62 | | #include <pdf/ExternalPDFStreams.hxx> |
63 | | #include <pdf/pdfbuildin_fonts.hxx> |
64 | | #include <salgdi.hxx> |
65 | | |
66 | | class FontSubsetInfo; |
67 | | class ZCodec; |
68 | | |
69 | | namespace vcl::pdf |
70 | | { |
71 | | |
72 | | enum class GraphicsStateUpdateFlags { |
73 | | Font = 0x0001, |
74 | | MapMode = 0x0002, |
75 | | LineColor = 0x0004, |
76 | | FillColor = 0x0008, |
77 | | ClipRegion = 0x0040, |
78 | | LayoutMode = 0x0100, |
79 | | TransparentPercent = 0x0200, |
80 | | DigitLanguage = 0x0400, |
81 | | All = 0x077f |
82 | | }; |
83 | | |
84 | | } // end vcl::pdf |
85 | | |
86 | | namespace o3tl { |
87 | | template<> struct typed_flags<vcl::pdf::GraphicsStateUpdateFlags> : is_typed_flags<vcl::pdf::GraphicsStateUpdateFlags, 0x077f> {}; |
88 | | } |
89 | | |
90 | | namespace vcl |
91 | | { |
92 | | |
93 | | using namespace vcl::pdf; |
94 | | |
95 | | namespace filter |
96 | | { |
97 | | class PDFObjectElement; |
98 | | } |
99 | | |
100 | | namespace pdf |
101 | | { |
102 | | struct PDFPage |
103 | | { |
104 | | VclPtr<PDFWriterImpl> m_pWriter; |
105 | | double m_nPageWidth; // in inch/72 |
106 | | double m_nPageHeight; // in inch/72 |
107 | | /** |
108 | | * A positive number that gives the size of default user space units, in multiples of points. |
109 | | * Typically 1, larger if page size is > 508 cm. |
110 | | */ |
111 | | sal_Int32 m_nUserUnit; |
112 | | PDFWriter::Orientation m_eOrientation; |
113 | | sal_Int32 m_nPageObject; |
114 | | std::vector<sal_Int32> m_aStreamObjects; |
115 | | sal_Int32 m_nStreamLengthObject; |
116 | | sal_uInt64 m_nBeginStreamPos; |
117 | | std::vector<sal_Int32> m_aAnnotations; |
118 | | std::vector<sal_Int32> m_aMCIDParents; |
119 | | PDFWriter::PageTransition m_eTransition; |
120 | | sal_uInt32 m_nTransTime; |
121 | | |
122 | | PDFPage( PDFWriterImpl* pWriter, double nPageWidth, double nPageHeight, PDFWriter::Orientation eOrientation ); |
123 | | |
124 | | void beginStream(); |
125 | | void endStream(); |
126 | | bool emit( sal_Int32 nParentPage ); |
127 | | |
128 | | // converts point from ref device coordinates to |
129 | | // page coordinates and appends the point to the buffer |
130 | | // if pOutPoint is set it will be updated to the emitted point |
131 | | // (in PDF map mode, that is 10th of point) |
132 | | void appendPoint( const Point& rPoint, OStringBuffer& rBuffer ) const; |
133 | | // appends a B2DPoint without further transformation |
134 | | void appendPixelPoint( const basegfx::B2DPoint& rPoint, OStringBuffer& rBuffer ) const; |
135 | | // appends a rectangle |
136 | | void appendRect( const tools::Rectangle& rRect, OStringBuffer& rBuffer ) const; |
137 | | // converts a rectangle to 10th points page space |
138 | | void convertRect( tools::Rectangle& rRect ) const; |
139 | | // appends a polygon optionally closing it |
140 | | void appendPolygon( const tools::Polygon& rPoly, OStringBuffer& rBuffer, bool bClose = true ) const; |
141 | | // appends a polygon optionally closing it |
142 | | void appendPolygon( const basegfx::B2DPolygon& rPoly, OStringBuffer& rBuffer ) const; |
143 | | // appends a polypolygon optionally closing the subpaths |
144 | | void appendPolyPolygon( const tools::PolyPolygon& rPolyPoly, OStringBuffer& rBuffer ) const; |
145 | | // appends a polypolygon optionally closing the subpaths |
146 | | void appendPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly, OStringBuffer& rBuffer ) const; |
147 | | // converts a length (either vertical or horizontal; this |
148 | | // can be important if the source MapMode is not |
149 | | // symmetrical) to page length and appends it to the buffer |
150 | | // if pOutLength is set it will be updated to the emitted length |
151 | | // (in PDF map mode, that is 10th of point) |
152 | | void appendMappedLength( sal_Int32 nLength, OStringBuffer& rBuffer, bool bVertical = true, sal_Int32* pOutLength = nullptr ) const; |
153 | | // the same for double values |
154 | | void appendMappedLength( double fLength, OStringBuffer& rBuffer, bool bVertical = true, sal_Int32 nPrecision = 5 ) const; |
155 | | // appends LineInfo |
156 | | // returns false if too many dash array entry were created for |
157 | | // the implementation limits of some PDF readers |
158 | | bool appendLineInfo( const LineInfo& rInfo, OStringBuffer& rBuffer ) const; |
159 | | // appends a horizontal waveline with vertical offset (helper for drawWaveLine) |
160 | | void appendWaveLine( sal_Int32 nLength, sal_Int32 nYOffset, sal_Int32 nDelta, OStringBuffer& rBuffer ) const; |
161 | | |
162 | | void appendMatrix3(Matrix3 const & rMatrix, OStringBuffer& rBuffer); |
163 | | |
164 | | double getHeight() const; |
165 | | }; |
166 | | |
167 | | /// Contains information to emit a reference XObject. |
168 | | struct ReferenceXObjectEmit |
169 | | { |
170 | | /// ID of the Form XObject, if any. |
171 | | sal_Int32 m_nFormObject; |
172 | | /// ID of the vector/embedded object, if m_nFormObject is used. |
173 | | sal_Int32 m_nEmbeddedObject; |
174 | | /// ID of the bitmap object, if m_nFormObject is used. |
175 | | sal_Int32 m_nBitmapObject; |
176 | | /// Size of the bitmap replacement, in pixels. |
177 | | Size m_aPixelSize; |
178 | | /// PDF data from the graphic object, if not writing a reference XObject. |
179 | | sal_Int32 m_nExternalPDFDataIndex; |
180 | | sal_Int32 m_nExternalPDFPageIndex; |
181 | | |
182 | | ReferenceXObjectEmit() |
183 | 0 | : m_nFormObject(0) |
184 | 0 | , m_nEmbeddedObject(0) |
185 | 0 | , m_nBitmapObject(0) |
186 | 0 | , m_nExternalPDFDataIndex(-1) |
187 | 0 | , m_nExternalPDFPageIndex(-1) |
188 | 0 | { |
189 | 0 | } |
190 | | |
191 | | /// Returns the ID one should use when referring to this bitmap. |
192 | | sal_Int32 getObject() const; |
193 | | |
194 | | bool hasExternalPDFData() const |
195 | 0 | { |
196 | 0 | return m_nExternalPDFDataIndex >= 0; |
197 | 0 | } |
198 | | }; |
199 | | |
200 | | struct BitmapEmit |
201 | | { |
202 | | BitmapID m_aID; |
203 | | Bitmap m_aBitmap; |
204 | | sal_Int32 m_nObject; |
205 | | ReferenceXObjectEmit m_aReferenceXObject; |
206 | | |
207 | | BitmapEmit() |
208 | 0 | : m_nObject(0) |
209 | 0 | { |
210 | 0 | } |
211 | | }; |
212 | | |
213 | | struct JPGEmit |
214 | | { |
215 | | BitmapID m_aID; |
216 | | std::unique_ptr<SvMemoryStream> |
217 | | m_pStream; |
218 | | AlphaMask m_aAlphaMask; |
219 | | sal_Int32 m_nObject; |
220 | | bool m_bTrueColor; |
221 | | ReferenceXObjectEmit m_aReferenceXObject; |
222 | | |
223 | | JPGEmit() |
224 | 0 | : m_nObject(0) |
225 | 0 | , m_bTrueColor(false) |
226 | 0 | { |
227 | 0 | } |
228 | | }; |
229 | | |
230 | | struct GradientEmit |
231 | | { |
232 | | Gradient m_aGradient; |
233 | | Size m_aSize; |
234 | | sal_Int32 m_nObject; |
235 | | }; |
236 | | |
237 | | // for tilings (drawWallpaper, begin/endPattern) |
238 | | struct TilingEmit |
239 | | { |
240 | | sal_Int32 m_nObject; |
241 | | tools::Rectangle m_aRectangle; |
242 | | Size m_aCellSize; |
243 | | SvtGraphicFill::Transform m_aTransform; |
244 | | ResourceDict m_aResources; |
245 | | std::unique_ptr<SvMemoryStream> m_pTilingStream; |
246 | | |
247 | | TilingEmit() |
248 | 0 | : m_nObject( 0 ) |
249 | 0 | {} |
250 | | }; |
251 | | |
252 | | // for transparency group XObjects |
253 | | struct TransparencyEmit |
254 | | { |
255 | | sal_Int32 m_nObject; |
256 | | sal_Int32 m_nExtGStateObject; |
257 | | double m_fAlpha; |
258 | | tools::Rectangle m_aBoundRect; |
259 | | std::unique_ptr<SvMemoryStream> m_pContentStream; |
260 | | |
261 | | TransparencyEmit() |
262 | 8 | : m_nObject( 0 ), |
263 | 8 | m_nExtGStateObject( -1 ), |
264 | 8 | m_fAlpha( 0.0 ) |
265 | 8 | {} |
266 | | }; |
267 | | |
268 | | // font subsets |
269 | | |
270 | | struct ColorLayer |
271 | | { |
272 | | sal_Int32 m_nFontID; |
273 | | sal_uInt8 m_nSubsetGlyphID; |
274 | | uint32_t m_nColorIndex; |
275 | | }; |
276 | | |
277 | | class GlyphEmit |
278 | | { |
279 | | // performance: actually this should probably a vector; |
280 | | std::vector<sal_Ucs> m_CodeUnits; |
281 | | sal_uInt8 m_nSubsetGlyphID; |
282 | | sal_Int32 m_nGlyphWidth; |
283 | | std::vector<ColorLayer> m_aColorLayers; |
284 | | font::RawFontData m_aColorBitmap; |
285 | | tools::Rectangle m_aRect; |
286 | | basegfx::B2DPolyPolygon m_aOutline; |
287 | | |
288 | | public: |
289 | 210k | GlyphEmit() : m_nSubsetGlyphID(0), m_nGlyphWidth(0) |
290 | 210k | { |
291 | 210k | } |
292 | | |
293 | 210k | void setGlyphId( sal_uInt8 i_nId ) { m_nSubsetGlyphID = i_nId; } |
294 | 210k | sal_uInt8 getGlyphId() const { return m_nSubsetGlyphID; } |
295 | | |
296 | 210k | void setGlyphWidth( sal_Int32 nWidth ) { m_nGlyphWidth = nWidth; } |
297 | 210k | sal_Int32 getGlyphWidth() const { return m_nGlyphWidth; } |
298 | | |
299 | 0 | void addColorLayer(ColorLayer aLayer) { m_aColorLayers.push_back(aLayer); } |
300 | 0 | const std::vector<ColorLayer>& getColorLayers() const { return m_aColorLayers; } |
301 | | |
302 | | void setColorBitmap(font::RawFontData aData, tools::Rectangle aRect) |
303 | 0 | { |
304 | 0 | m_aColorBitmap = aData; |
305 | 0 | m_aRect = aRect; |
306 | 0 | } |
307 | | const font::RawFontData& getColorBitmap(tools::Rectangle& rRect) const |
308 | 0 | { |
309 | 0 | rRect = m_aRect; |
310 | 0 | return m_aColorBitmap; |
311 | 0 | } |
312 | | |
313 | 0 | void setOutline(const basegfx::B2DPolyPolygon& rOutline) { m_aOutline = rOutline; } |
314 | 0 | const basegfx::B2DPolyPolygon& getOutline() const { return m_aOutline; } |
315 | | |
316 | | void addCode( sal_Ucs i_cCode ) |
317 | 210k | { |
318 | 210k | m_CodeUnits.push_back(i_cCode); |
319 | 210k | } |
320 | 210k | sal_Int32 countCodes() const { return m_CodeUnits.size(); } |
321 | 11.0M | const std::vector<sal_Ucs>& codes() const { return m_CodeUnits; } |
322 | | sal_Ucs getCode( sal_Int32 i_nIndex ) const |
323 | 421k | { |
324 | 421k | sal_Ucs nRet = 0; |
325 | 421k | if (o3tl::make_unsigned(i_nIndex) < m_CodeUnits.size()) |
326 | 421k | nRet = m_CodeUnits[i_nIndex]; |
327 | 421k | return nRet; |
328 | 421k | } |
329 | | }; |
330 | | |
331 | | struct FontEmit |
332 | | { |
333 | | sal_Int32 m_nFontID; |
334 | | std::map<sal_GlyphId, GlyphEmit> m_aMapping; |
335 | | |
336 | 6.81k | explicit FontEmit( sal_Int32 nID ) : m_nFontID( nID ) {} |
337 | | }; |
338 | | |
339 | | struct Glyph |
340 | | { |
341 | | sal_Int32 m_nFontID; |
342 | | sal_uInt8 m_nSubsetGlyphID; |
343 | | }; |
344 | | |
345 | | struct FontSubset |
346 | | { |
347 | | std::vector< FontEmit > m_aSubsets; |
348 | | std::map<sal_GlyphId, Glyph> m_aMapping; |
349 | | }; |
350 | | |
351 | | struct FontSubsetKey |
352 | | { |
353 | | const vcl::font::PhysicalFontFace* m_pFace; |
354 | | const std::vector<vcl::font::Variation>& m_rVariations; |
355 | | size_t m_nHash; |
356 | | |
357 | | FontSubsetKey(const vcl::font::PhysicalFontFace* pFace, const LogicalFontInstance* pFont) |
358 | 22.5M | : m_pFace(pFace) |
359 | 22.5M | , m_rVariations(pFont->GetVariations()) |
360 | 22.5M | , m_nHash(0) |
361 | 22.5M | { |
362 | 22.5M | o3tl::hash_combine(m_nHash, m_rVariations.size()); |
363 | 22.5M | for (const auto& rVar : m_rVariations) |
364 | 22.5M | { |
365 | 22.5M | o3tl::hash_combine(m_nHash, rVar.nTag); |
366 | 22.5M | o3tl::hash_combine(m_nHash, rVar.fValue); |
367 | 22.5M | } |
368 | 22.5M | } |
369 | | |
370 | | bool operator<(const FontSubsetKey& rOther) const |
371 | 74.3M | { |
372 | 74.3M | if (m_pFace != rOther.m_pFace) |
373 | 1.12M | return m_pFace < rOther.m_pFace; |
374 | 73.2M | return m_nHash < rOther.m_nHash; |
375 | 74.3M | } |
376 | | }; |
377 | | |
378 | | struct EmbedFont |
379 | | { |
380 | | sal_Int32 m_nNormalFontID; |
381 | | LogicalFontInstance* m_pFontInstance; |
382 | | |
383 | | EmbedFont() |
384 | 0 | : m_nNormalFontID(0) |
385 | 0 | , m_pFontInstance(nullptr) {} |
386 | | }; |
387 | | |
388 | | struct PDFDest |
389 | | { |
390 | | sal_Int32 m_nPage; |
391 | | PDFWriter::DestAreaType m_eType; |
392 | | tools::Rectangle m_aRect; |
393 | | }; |
394 | | |
395 | | //--->i56629 |
396 | | struct PDFNamedDest |
397 | | { |
398 | | OUString m_aDestName; |
399 | | sal_Int32 m_nPage; |
400 | | PDFWriter::DestAreaType m_eType; |
401 | | tools::Rectangle m_aRect; |
402 | | }; |
403 | | |
404 | | struct PDFOutlineEntry |
405 | | { |
406 | | sal_Int32 m_nObject; |
407 | | sal_Int32 m_nParentObject; |
408 | | sal_Int32 m_nNextObject; |
409 | | sal_Int32 m_nPrevObject; |
410 | | std::vector< sal_Int32 > m_aChildren; |
411 | | OUString m_aTitle; |
412 | | sal_Int32 m_nDestID; |
413 | | |
414 | | PDFOutlineEntry() |
415 | 4.90k | : m_nObject( 0 ), |
416 | 4.90k | m_nParentObject( 0 ), |
417 | 4.90k | m_nNextObject( 0 ), |
418 | 4.90k | m_nPrevObject( 0 ), |
419 | 4.90k | m_nDestID( -1 ) |
420 | 4.90k | {} |
421 | | }; |
422 | | |
423 | | struct PDFAnnotation |
424 | | { |
425 | | sal_Int32 m_nObject; |
426 | | tools::Rectangle m_aRect; |
427 | | sal_Int32 m_nPage; |
428 | | |
429 | | PDFAnnotation() |
430 | 1.77k | : m_nObject( -1 ), |
431 | 1.77k | m_nPage( -1 ) |
432 | 1.77k | {} |
433 | | }; |
434 | | |
435 | | struct PDFLink : public PDFAnnotation |
436 | | { |
437 | | sal_Int32 m_nDest; // set to -1 for URL, to a dest else |
438 | | OUString m_aURL; |
439 | | sal_Int32 m_nStructParent; // struct parent entry |
440 | | OUString m_AltText; |
441 | | |
442 | | PDFLink(OUString const& rAltText) |
443 | 1.71k | : m_nDest( -1 ), |
444 | 1.71k | m_nStructParent( -1 ) |
445 | 1.71k | , m_AltText(rAltText) |
446 | 1.71k | {} |
447 | | }; |
448 | | |
449 | | /// A PDF embedded file. |
450 | | struct PDFEmbeddedFile |
451 | | { |
452 | | /// ID of the file. |
453 | | sal_Int32 m_nObject; |
454 | | OUString m_aSubType; |
455 | | /// Contents of the file. |
456 | | BinaryDataContainer m_aDataContainer; |
457 | | std::unique_ptr<PDFOutputStream> m_pStream; |
458 | | |
459 | | PDFEmbeddedFile() |
460 | 0 | : m_nObject(0) |
461 | 0 | { |
462 | 0 | } |
463 | | }; |
464 | | |
465 | | struct PDFPopupAnnotation : public PDFAnnotation |
466 | | { |
467 | | /// ID of the parent object. |
468 | | sal_Int32 m_nParentObject; |
469 | | }; |
470 | | |
471 | | struct PDFNoteEntry : public PDFAnnotation |
472 | | { |
473 | | vcl::pdf::PDFNote m_aContents; |
474 | | |
475 | | PDFPopupAnnotation m_aPopUpAnnotation; |
476 | | |
477 | | sal_Int32 m_nStructParent; |
478 | | |
479 | | PDFNoteEntry() |
480 | 26 | : m_nStructParent(-1) |
481 | 26 | {} |
482 | | }; |
483 | | |
484 | | /// A PDF Screen annotation. |
485 | | struct PDFScreen : public PDFAnnotation |
486 | | { |
487 | | /// Linked video. |
488 | | OUString m_aURL; |
489 | | /// Embedded video. |
490 | | OUString m_aTempFileURL; |
491 | | /// ID of the EmbeddedFile object. |
492 | | sal_Int32 m_nTempFileObject; |
493 | | /// alternative text description |
494 | | OUString m_AltText; |
495 | | sal_Int32 m_nStructParent; |
496 | | OUString m_MimeType; |
497 | | |
498 | | PDFScreen(OUString const& rAltText, OUString const& rMimeType) |
499 | 0 | : m_nTempFileObject(0) |
500 | 0 | , m_AltText(rAltText) |
501 | 0 | , m_nStructParent(-1) |
502 | 0 | , m_MimeType(rMimeType) |
503 | 0 | { |
504 | 0 | } |
505 | | }; |
506 | | |
507 | | struct PDFWidgetCopy |
508 | | { |
509 | | sal_Int32 m_nObject = -1; |
510 | | }; |
511 | | |
512 | | struct PDFWidget : public PDFAnnotation |
513 | | { |
514 | | PDFWriter::WidgetType m_eType; |
515 | | OString m_aName; |
516 | | OUString m_aDescription; |
517 | | OUString m_aText; |
518 | | DrawTextFlags m_nTextStyle; |
519 | | OUString m_aValue; |
520 | | OString m_aDAString; |
521 | | OString m_aDRDict; |
522 | | OString m_aMKDict; |
523 | | OString m_aMKDictCAString; // i12626, added to be able to encrypt the /CA text string |
524 | | // since the object number is not known at the moment |
525 | | // of filling m_aMKDict, the string will be encrypted when emitted. |
526 | | // the /CA string MUST BE the last added to m_aMKDict |
527 | | // see code for details |
528 | | sal_Int32 m_nFlags; |
529 | | sal_Int32 m_nParent; // if not 0, parent's object number |
530 | | std::vector<sal_Int32> m_aKids; // widget children, contains object numbers |
531 | | std::vector<sal_Int32> m_aKidsIndex; // widget children, contains index to m_aWidgets |
532 | | OUString m_aOnValue; |
533 | | OUString m_aOffValue; |
534 | | sal_Int32 m_nTabOrder; // lowest number gets first in tab order |
535 | | sal_Int32 m_nRadioGroup; |
536 | | sal_Int32 m_nMaxLen; |
537 | | PDFWriter::FormatType m_nFormat; |
538 | | OUString m_aCurrencySymbol; |
539 | | sal_Int32 m_nDecimalAccuracy; |
540 | | bool m_bPrependCurrencySymbol; |
541 | | OUString m_aTimeFormat; |
542 | | OUString m_aDateFormat; |
543 | | bool m_bSubmit; |
544 | | bool m_bSubmitGet; |
545 | | sal_Int32 m_nDest; |
546 | | std::vector<OUString> m_aListEntries; |
547 | | std::vector<sal_Int32> m_aSelectedEntries; |
548 | | typedef std::unordered_map<OString, SvMemoryStream*> PDFAppearanceStreams; |
549 | | std::unordered_map<OString, PDFAppearanceStreams> m_aAppearances; |
550 | | sal_Int32 m_nStructParent = -1; |
551 | | |
552 | | PDFWidget() |
553 | 0 | : m_eType( PDFWriter::PushButton ), |
554 | 0 | m_nTextStyle( DrawTextFlags::NONE ), |
555 | 0 | m_nFlags( 0 ), |
556 | 0 | m_nParent( 0 ), |
557 | 0 | m_nTabOrder( 0 ), |
558 | 0 | m_nRadioGroup( -1 ), |
559 | 0 | m_nMaxLen( 0 ), |
560 | 0 | m_nFormat( PDFWriter::FormatType::Text ), |
561 | 0 | m_nDecimalAccuracy ( 0 ), |
562 | 0 | m_bPrependCurrencySymbol( false ), |
563 | 0 | m_bSubmit( false ), |
564 | 0 | m_bSubmitGet( false ), |
565 | 0 | m_nDest( -1 ) |
566 | 0 | {} |
567 | | }; |
568 | | |
569 | | struct PDFStructureAttribute |
570 | | { |
571 | | PDFWriter::StructAttributeValue eValue; |
572 | | sal_Int32 nValue; |
573 | | |
574 | | PDFStructureAttribute() |
575 | 0 | : eValue( PDFWriter::Invalid ), |
576 | 0 | nValue( 0 ) |
577 | 0 | {} |
578 | | |
579 | | explicit PDFStructureAttribute( PDFWriter::StructAttributeValue eVal ) |
580 | 0 | : eValue( eVal ), |
581 | 0 | nValue( 0 ) |
582 | 0 | {} |
583 | | |
584 | | explicit PDFStructureAttribute( sal_Int32 nVal ) |
585 | 0 | : eValue( PDFWriter::Invalid ), |
586 | 0 | nValue( nVal ) |
587 | 0 | {} |
588 | | }; |
589 | | |
590 | | struct ObjReference { sal_Int32 const nObject; }; |
591 | | struct ObjReferenceObj { sal_Int32 const nObject; }; |
592 | | struct MCIDReference { sal_Int32 const nPageObj; sal_Int32 const nMCID; }; |
593 | | typedef ::std::variant<ObjReference, ObjReferenceObj, MCIDReference> PDFStructureElementKid; |
594 | | |
595 | | struct PDFStructureElement |
596 | | { |
597 | | sal_Int32 m_nObject; |
598 | | std::optional<vcl::pdf::StructElement> m_oType; |
599 | | OString m_aAlias; |
600 | | sal_Int32 m_nOwnElement; // index into structure vector |
601 | | sal_Int32 m_nParentElement; // index into structure vector |
602 | | sal_Int32 m_nFirstPageObject; |
603 | | bool m_bOpenMCSeq; |
604 | | std::vector< sal_Int32 > m_aChildren; // indexes into structure vector |
605 | | std::list< PDFStructureElementKid > m_aKids; |
606 | | std::map<PDFWriter::StructAttribute, PDFStructureAttribute > |
607 | | m_aAttributes; |
608 | | ::std::vector<sal_Int32> m_AnnotIds; |
609 | | tools::Rectangle m_aBBox; |
610 | | OUString m_aActualText; |
611 | | OUString m_aAltText; |
612 | | css::lang::Locale m_aLocale; |
613 | | |
614 | | // m_aContents contains the element's marked content sequence |
615 | | // as pairs of (page nr, MCID) |
616 | | |
617 | | PDFStructureElement() |
618 | 4.16k | : m_nObject( 0 ), |
619 | 4.16k | m_nOwnElement( -1 ), |
620 | 4.16k | m_nParentElement( -1 ), |
621 | 4.16k | m_nFirstPageObject( 0 ), |
622 | 4.16k | m_bOpenMCSeq( false ) |
623 | 4.16k | { |
624 | 4.16k | } |
625 | | |
626 | | PDFStructureElement(sal_Int32 nOwnElement, sal_Int32 nParentElement, sal_Int32 nFirstPageObject) |
627 | 0 | : m_nObject(0) |
628 | 0 | , m_nOwnElement(nOwnElement) |
629 | 0 | , m_nParentElement(nParentElement) |
630 | 0 | , m_nFirstPageObject(nFirstPageObject) |
631 | 0 | , m_bOpenMCSeq(false ) |
632 | 0 | { |
633 | 0 | } |
634 | | }; |
635 | | |
636 | | // helper structure for drawLayout and friends |
637 | | struct PDFGlyph |
638 | | { |
639 | | basegfx::B2DPoint const m_aPos; |
640 | | const GlyphItem* m_pGlyph; |
641 | | const LogicalFontInstance* m_pFont; |
642 | | sal_Int32 const m_nNativeWidth; |
643 | | sal_Int32 const m_nMappedFontId; |
644 | | sal_uInt8 const m_nMappedGlyphId; |
645 | | int const m_nCharPos; |
646 | | |
647 | | PDFGlyph( const basegfx::B2DPoint& rPos, |
648 | | const GlyphItem* pGlyph, |
649 | | const LogicalFontInstance* pFont, |
650 | | sal_Int32 nNativeWidth, |
651 | | sal_Int32 nFontId, |
652 | | sal_uInt8 nMappedGlyphId, |
653 | | int nCharPos ) |
654 | 11.2M | : m_aPos( rPos ), m_pGlyph(pGlyph), m_pFont(pFont), m_nNativeWidth( nNativeWidth ), |
655 | 11.2M | m_nMappedFontId( nFontId ), m_nMappedGlyphId( nMappedGlyphId ), |
656 | 11.2M | m_nCharPos(nCharPos) |
657 | 11.2M | {} |
658 | | }; |
659 | | |
660 | | struct StreamRedirect |
661 | | { |
662 | | SvStream* m_pStream; |
663 | | MapMode m_aMapMode; |
664 | | tools::Rectangle m_aTargetRect; |
665 | | ResourceDict m_aResourceDict; |
666 | | }; |
667 | | |
668 | | // graphics state |
669 | | struct GraphicsState |
670 | | { |
671 | | vcl::Font m_aFont; |
672 | | MapMode m_aMapMode; |
673 | | Color m_aLineColor; |
674 | | Color m_aFillColor; |
675 | | Color m_aTextLineColor; |
676 | | Color m_aOverlineColor; |
677 | | basegfx::B2DPolyPolygon m_aClipRegion; |
678 | | bool m_bClipRegion; |
679 | | vcl::text::ComplexTextLayoutFlags m_nLayoutMode; |
680 | | LanguageType m_aDigitLanguage; |
681 | | PushFlags m_nFlags; |
682 | | GraphicsStateUpdateFlags m_nUpdateFlags; |
683 | | |
684 | | GraphicsState() : |
685 | 128k | m_aLineColor( COL_TRANSPARENT ), |
686 | 128k | m_aFillColor( COL_TRANSPARENT ), |
687 | 128k | m_aTextLineColor( COL_TRANSPARENT ), |
688 | 128k | m_aOverlineColor( COL_TRANSPARENT ), |
689 | 128k | m_bClipRegion( false ), |
690 | 128k | m_nLayoutMode( vcl::text::ComplexTextLayoutFlags::Default ), |
691 | 128k | m_aDigitLanguage( 0 ), |
692 | 128k | m_nFlags( PushFlags::ALL ), |
693 | 128k | m_nUpdateFlags( GraphicsStateUpdateFlags::All ) |
694 | 128k | {} |
695 | | }; |
696 | | |
697 | | enum class Mode { DEFAULT, NOWRITE }; |
698 | | |
699 | | struct PDFDocumentAttachedFile |
700 | | { |
701 | | OUString maFilename; |
702 | | OUString maMimeType; |
703 | | OUString maDescription; |
704 | | sal_Int32 mnEmbeddedFileObjectId; |
705 | | sal_Int32 mnObjectId; |
706 | | }; |
707 | | |
708 | | class IPDFEncryptor; |
709 | | |
710 | | } // end pdf namespace |
711 | | |
712 | | class PDFWriterImpl final : public VirtualDevice, public PDFObjectContainer |
713 | | { |
714 | | friend class PDFStreamIf; |
715 | | |
716 | | public: |
717 | | friend struct vcl::pdf::PDFPage; |
718 | | |
719 | | const char* getStructureTag(vcl::pdf::StructElement eElement); |
720 | | static const char* getAttributeTag(PDFWriter::StructAttribute eAtr ); |
721 | | static const char* getAttributeValueTag( PDFWriter::StructAttributeValue eVal ); |
722 | | |
723 | | // returns true if compression was done |
724 | | // else false |
725 | | static bool compressStream( SvMemoryStream* ); |
726 | | |
727 | | static void convertLineInfoToExtLineInfo( const LineInfo& rIn, PDFWriter::ExtLineInfo& rOut ); |
728 | | |
729 | | private: |
730 | | bool ImplNewFont() const override; |
731 | | void ImplClearFontData(bool bNewFontLists) override; |
732 | | void ImplRefreshFontData(bool bNewFontLists) override; |
733 | | vcl::Region ClipToDeviceBounds(vcl::Region aRegion) const override; |
734 | | void DrawHatchLine_DrawLine(const Point& rStartPoint, const Point& rEndPoint) override; |
735 | | |
736 | | MapMode m_aMapMode; // PDFWriterImpl scaled units |
737 | | StyleSettings m_aWidgetStyleSettings; |
738 | | std::vector< PDFPage > m_aPages; |
739 | | /* maps object numbers to file offsets (needed for xref) */ |
740 | | std::vector< sal_uInt64 > m_aObjects; |
741 | | /* contains Bitmaps until they are written to the |
742 | | * file stream as XObjects*/ |
743 | | std::list< BitmapEmit > m_aBitmaps; |
744 | | /* contains JPG streams until written to file */ |
745 | | std::vector<JPGEmit> m_aJPGs; |
746 | | /*--->i56629 contains all named destinations ever set during the PDF creation, |
747 | | destination id is always the destination's position in this vector |
748 | | */ |
749 | | std::vector<PDFNamedDest> m_aNamedDests; |
750 | | /* contains all dests ever set during the PDF creation, |
751 | | dest id is always the dest's position in this vector |
752 | | */ |
753 | | std::vector<PDFDest> m_aDests; |
754 | | /** contains destinations accessible via a public Id, instead of being linked to by an ordinary link |
755 | | */ |
756 | | ::std::map< sal_Int32, sal_Int32 > m_aDestinationIdTranslation; |
757 | | /* contains all links ever set during PDF creation, |
758 | | link id is always the link's position in this vector |
759 | | */ |
760 | | std::vector<PDFLink> m_aLinks; |
761 | | /// Contains all screen annotations. |
762 | | std::vector<PDFScreen> m_aScreens; |
763 | | /// Contains embedded files. |
764 | | std::vector<PDFEmbeddedFile> m_aEmbeddedFiles; |
765 | | |
766 | | std::vector<PDFDocumentAttachedFile> m_aDocumentAttachedFiles; |
767 | | |
768 | | /* makes correctly encoded for export to PDF URLS |
769 | | */ |
770 | | css::uno::Reference< css::util::XURLTransformer > m_xTrans; |
771 | | /* maps arbitrary link ids for structure attributes to real link ids |
772 | | (for setLinkPropertyId) |
773 | | */ |
774 | | std::map<sal_Int32, sal_Int32> m_aLinkPropertyMap; |
775 | | /* contains all outline items, |
776 | | object 0 is the outline root |
777 | | */ |
778 | | std::vector<PDFOutlineEntry> m_aOutline; |
779 | | /* contains all notes set during PDF creation |
780 | | */ |
781 | | std::vector<PDFNoteEntry> m_aNotes; |
782 | | /* the root of the structure tree |
783 | | */ |
784 | | std::vector<PDFStructureElement> m_aStructure; |
785 | | /* current object in the structure hierarchy |
786 | | */ |
787 | | sal_Int32 m_nCurrentStructElement; |
788 | | std::stack<sal_Int32> m_StructElementStack; |
789 | | /* structure parent tree */ |
790 | | std::vector< OString > m_aStructParentTree; |
791 | | /* emit structure marks currently (aka. NonStructElement or not) |
792 | | */ |
793 | | bool m_bEmitStructure; |
794 | | /* role map of struct tree root */ |
795 | | std::unordered_map< OString, OString > |
796 | | m_aRoleMap; |
797 | | /* structure elements (object ids) that should have ID */ |
798 | | std::unordered_set<sal_Int32> m_StructElemObjsWithID; |
799 | | |
800 | | /* contains all widgets used in the PDF */ |
801 | | std::vector<PDFWidget> m_aWidgets; |
802 | | std::vector<PDFWidgetCopy> m_aCopiedWidgets; |
803 | | |
804 | | /* maps radio group id to index of radio group control in m_aWidgets */ |
805 | | std::map< sal_Int32, sal_Int32 > m_aRadioGroupWidgets; |
806 | | /* unordered_map for field names, used to ensure unique field names */ |
807 | | std::unordered_map< OString, sal_Int32 > m_aFieldNameMap; |
808 | | |
809 | | /* contains Bitmaps for gradient functions until they are written |
810 | | * to the file stream */ |
811 | | std::list< GradientEmit > m_aGradients; |
812 | | /* contains bitmap tiling patterns */ |
813 | | std::vector< TilingEmit > m_aTilings; |
814 | | std::vector< TransparencyEmit > m_aTransparentObjects; |
815 | | /* contains all font subsets in use */ |
816 | | std::map<FontSubsetKey, FontSubset> m_aSubsets; |
817 | | std::map<const vcl::font::PhysicalFontFace*, EmbedFont> m_aSystemFonts; |
818 | | std::map<const vcl::font::PhysicalFontFace*, FontSubset> m_aType3Fonts; |
819 | | sal_Int32 m_nNextFID; |
820 | | |
821 | | /// Cache some most recent bitmaps we've exported, in case we encounter them again.. |
822 | | o3tl::lru_map<BitmapChecksum, |
823 | | std::shared_ptr<SvMemoryStream>> m_aPDFBmpCache; |
824 | | |
825 | | sal_Int32 m_nCurrentPage; |
826 | | |
827 | | sal_Int32 m_nCatalogObject; |
828 | | // object number of the main signature dictionary |
829 | | sal_Int32 m_nSignatureObject; |
830 | | sal_Int64 m_nSignatureContentOffset; |
831 | | sal_Int64 m_nSignatureLastByteRangeNoOffset; |
832 | | sal_Int32 m_nResourceDict; |
833 | | ResourceDict m_aGlobalResourceDict; |
834 | | sal_Int32 m_nFontDictObject; |
835 | | std::map< sal_Int32, sal_Int32 > m_aBuildinFontToObjectMap; |
836 | | |
837 | | PDFWriter::PDFWriterContext m_aContext; |
838 | | osl::File m_aFile; |
839 | | bool m_bOpen; |
840 | | |
841 | | ExternalPDFStreams m_aExternalPDFStreams; |
842 | | |
843 | | std::shared_ptr<IPDFEncryptor> m_pPDFEncryptor; |
844 | | |
845 | | /* output redirection; e.g. to accumulate content streams for |
846 | | XObjects |
847 | | */ |
848 | | std::list< StreamRedirect > m_aOutputStreams; |
849 | | |
850 | | std::list< GraphicsState > m_aGraphicsStack; |
851 | | GraphicsState m_aCurrentPDFState; |
852 | | |
853 | | std::unique_ptr<ZCodec> m_pCodec; |
854 | | std::unique_ptr<SvMemoryStream> m_pMemStream; |
855 | | |
856 | | std::set< PDFWriter::ErrorCode > m_aErrors; |
857 | | |
858 | | ::comphelper::Hash m_DocDigest; |
859 | | |
860 | | std::unordered_map<std::string_view, sal_Int32> m_aNamespacesMap; |
861 | | |
862 | | // reduce repeated allocations |
863 | | OStringBuffer updateGraphicsStateLine{256}; |
864 | | OStringBuffer drawBitmapLine{80}; |
865 | | |
866 | | sal_uInt64 getCurrentFilePosition() |
867 | 0 | { |
868 | 0 | sal_uInt64 nPosition{}; |
869 | 0 | if (osl::File::E_None != m_aFile.getPos(nPosition)) |
870 | 0 | { |
871 | 0 | m_aFile.close(); |
872 | 0 | m_bOpen = false; |
873 | 0 | } |
874 | 0 | return nPosition; |
875 | 0 | } |
876 | | |
877 | | /* string to hold the PDF creation date */ |
878 | | OString m_aCreationDateString; |
879 | | /* string to hold the PDF creation date, for PDF/A metadata */ |
880 | | OString m_aCreationMetaDateString; |
881 | | /* the buffer where the data are encrypted, dynamically allocated */ |
882 | | std::vector<sal_uInt8> m_vEncryptionBuffer; |
883 | | |
884 | | void addRoleMap(const OString& aAlias, vcl::pdf::StructElement eType); |
885 | | |
886 | | void checkAndEnableStreamEncryption( sal_Int32 nObject ) override; |
887 | | |
888 | | void disableStreamEncryption() override; |
889 | | |
890 | | /* */ |
891 | | void enableStringEncryption( sal_Int32 nObject ); |
892 | | |
893 | | private: |
894 | | /* creates fonts and subsets that will be emitted later */ |
895 | | void registerGlyph(const sal_GlyphId, const vcl::font::PhysicalFontFace*, const LogicalFontInstance* pFont, const std::vector<sal_Ucs>&, sal_Int32, sal_uInt8&, sal_Int32&); |
896 | | void registerSimpleGlyph(const sal_GlyphId, const vcl::font::PhysicalFontFace*, const LogicalFontInstance*, const std::vector<sal_Ucs>&, sal_Int32, sal_uInt8&, sal_Int32&); |
897 | | |
898 | | /* emits a text object according to the passed layout */ |
899 | | /* TODO: remove rText as soon as SalLayout will change so that rText is not necessary anymore */ |
900 | | void drawVerticalGlyphs( const std::vector<PDFGlyph>& rGlyphs, OStringBuffer& rLine, const Point& rAlignOffset, const Matrix3& rRotScale, double fAngle, double fXScale, sal_Int32 nFontHeight ); |
901 | | void drawHorizontalGlyphs( const std::vector<PDFGlyph>& rGlyphs, OStringBuffer& rLine, const Point& rAlignOffset, bool bFirst, double fAngle, double fXScale, sal_Int32 nFontHeight, sal_Int32 nPixelFontHeight ); |
902 | | void drawLayout( SalLayout& rLayout, const OUString& rText, bool bTextLines ); |
903 | | void drawRelief( SalLayout& rLayout, const OUString& rText, bool bTextLines ); |
904 | | void drawShadow( SalLayout& rLayout, const OUString& rText, bool bTextLines ); |
905 | | |
906 | | /* writes differences between graphics stack and current real PDF |
907 | | * state to the file |
908 | | */ |
909 | | void updateGraphicsState(Mode mode = Mode::DEFAULT); |
910 | | |
911 | | /* writes a transparency group object */ |
912 | | void writeTransparentObject( TransparencyEmit& rObject ); |
913 | | |
914 | | /* writes an XObject of type image, may create |
915 | | a second for the mask |
916 | | */ |
917 | | bool writeBitmapObject( const BitmapEmit& rObject ); |
918 | | /* writes an XObject of type mask image |
919 | | */ |
920 | | bool writeBitmapMaskObject( sal_Int32 nMaskObject, const AlphaMask& rAlphaMask ); |
921 | | |
922 | | void writeJPG( const JPGEmit& rEmit ); |
923 | | /// Writes the form XObject proxy for the image. |
924 | | void writeReferenceXObject(const ReferenceXObjectEmit& rEmit); |
925 | | |
926 | | void mergeAnnotationsFromExternalPage(filter::PDFObjectElement* pPage, std::map<sal_Int32, sal_Int32>& rCopiedResourcesMap); |
927 | | |
928 | | /* tries to find the bitmap by its id and returns its emit data if exists, |
929 | | else creates a new emit data block */ |
930 | | const BitmapEmit& createBitmapEmit( const Bitmap& rBitmap, const Graphic& rGraphic, std::list<BitmapEmit>& rBitmaps, ResourceDict& rResourceDict, std::list<StreamRedirect>& rOutputStreams ); |
931 | | const BitmapEmit& createBitmapEmit( const Bitmap& rBitmap, const Graphic& rGraphic ); |
932 | | |
933 | | /* writes the Do operation inside the content stream */ |
934 | | void drawBitmap( const Point& rDestPt, const Size& rDestSize, const BitmapEmit& rBitmap, const Color& rFillColor ); |
935 | | /* write the function object for a Gradient */ |
936 | | bool writeGradientFunction( GradientEmit const & rObject ); |
937 | | /* creates a GradientEmit and returns its object number */ |
938 | | sal_Int32 createGradient( const Gradient& rGradient, const Size& rSize ); |
939 | | |
940 | | /* writes all tilings */ |
941 | | bool emitTilings(); |
942 | | /* writes all gradient patterns */ |
943 | | bool emitGradients(); |
944 | | /* writes a builtin font object and returns its objectid (or 0 in case of failure ) */ |
945 | | sal_Int32 emitBuildinFont( const pdf::BuildinFontFace*, sal_Int32 nObject ); |
946 | | /* writes a type1 system font object and returns its mapping from font ids to object ids (or 0 in case of failure ) */ |
947 | | std::map< sal_Int32, sal_Int32 > emitSystemFont(const vcl::font::PhysicalFontFace*, EmbedFont const &); |
948 | | /* writes a type3 font object and appends it to the font id mapping, or returns false in case of failure */ |
949 | | bool emitType3Font(const vcl::font::PhysicalFontFace*, const FontSubset&, std::map<sal_Int32, sal_Int32>&); |
950 | | /* writes a font descriptor and returns its object id (or 0) */ |
951 | | sal_Int32 emitFontDescriptor(const vcl::font::PhysicalFontFace*, FontSubsetInfo const &, sal_Int32 nSubsetID, sal_Int32 nStream); |
952 | | /* writes a ToUnicode cmap, returns the corresponding stream object */ |
953 | | sal_Int32 createToUnicodeCMap( sal_uInt8 const * pEncoding, const std::vector<sal_Ucs>& CodeUnits, const sal_Int32* pCodeUnitsPerGlyph, |
954 | | const sal_Int32* pEncToUnicodeIndex, uint32_t nGlyphs ); |
955 | | |
956 | | /* get resource dict object number */ |
957 | | sal_Int32 getResourceDictObj() |
958 | 68.4k | { |
959 | 68.4k | if( m_nResourceDict <= 0 ) |
960 | 4.16k | m_nResourceDict = createObject(); |
961 | 68.4k | return m_nResourceDict; |
962 | 68.4k | } |
963 | | /* get the font dict object */ |
964 | | sal_Int32 getFontDictObject() |
965 | 12.4k | { |
966 | 12.4k | if( m_nFontDictObject <= 0 ) |
967 | 4.16k | m_nFontDictObject = createObject(); |
968 | 12.4k | return m_nFontDictObject; |
969 | 12.4k | } |
970 | | /* push resource into current (redirected) resource dict */ |
971 | | static void pushResource( ResourceKind eKind, const OString& rResource, sal_Int32 nObject, ResourceDict& rResourceDict, std::list<StreamRedirect>& rOutputStreams ); |
972 | | void pushResource( ResourceKind eKind, const OString& rResource, sal_Int32 nObject ); |
973 | | |
974 | | void appendBuildinFontsToDict( OStringBuffer& rDict ) const; |
975 | | /* writes the font dictionary and emits all font objects |
976 | | * returns object id of font directory (or 0 on error) |
977 | | */ |
978 | | bool emitFonts(); |
979 | | /* writes the Resource dictionary; |
980 | | * returns dict object id (or 0 on error) |
981 | | */ |
982 | | sal_Int32 emitResources(); |
983 | | // appends a dest |
984 | | bool appendDest( sal_Int32 nDestID, OStringBuffer& rBuffer ); |
985 | | // write all links |
986 | | bool emitLinkAnnotations(); |
987 | | // Write all screen annotations. |
988 | | bool emitScreenAnnotations(); |
989 | | |
990 | | void emitTextAnnotationLine(OStringBuffer & aLine, PDFNoteEntry const & rNote); |
991 | | static void emitPopupAnnotationLine(OStringBuffer & aLine, PDFPopupAnnotation const & rPopUp); |
992 | | // write all notes |
993 | | bool emitNoteAnnotations(); |
994 | | |
995 | | // write the appearance streams of a widget |
996 | | bool emitAppearances( PDFWidget& rWidget, OStringBuffer& rAnnotDict ); |
997 | | // clean up radio button "On" values |
998 | | void ensureUniqueRadioOnValues(); |
999 | | // write all widgets |
1000 | | bool emitWidgetAnnotations(); |
1001 | | // writes all annotation objects |
1002 | | bool emitAnnotations(); |
1003 | | /// Writes embedded files. |
1004 | | bool emitEmbeddedFiles(); |
1005 | | //write the named destination stuff |
1006 | | sal_Int32 emitNamedDestinations();//i56629 |
1007 | | // writes outline dict and tree |
1008 | | sal_Int32 emitOutline(); |
1009 | | template<typename T> void AppendAnnotKid(PDFStructureElement& i_rEle, T & rAnnot); |
1010 | | // puts the attribute objects of a structure element into the returned string, |
1011 | | // helper for emitStructure |
1012 | | OString emitStructureAttributes( PDFStructureElement& rEle ); |
1013 | | //--->i94258 |
1014 | | // the maximum array elements allowed for PDF array object |
1015 | | static const sal_uInt32 ncMaxPDFArraySize = 8191; |
1016 | | //check if internal dummy container are needed in the structure elements |
1017 | | void addInternalStructureContainer( PDFStructureElement& rEle ); |
1018 | | //<---i94258 |
1019 | | // writes namespaces |
1020 | | void emitNamespaces(); |
1021 | | // writes document structure |
1022 | | sal_Int32 emitStructure( PDFStructureElement& rEle ); |
1023 | | // writes structure parent tree |
1024 | | sal_Int32 emitStructParentTree( sal_Int32 nTreeObject ); |
1025 | | // writes structure IDTree |
1026 | | sal_Int32 emitStructIDTree(sal_Int32 nTreeObject); |
1027 | | // writes page tree and catalog |
1028 | | bool emitCatalog(); |
1029 | | // writes signature dictionary object |
1030 | | bool emitSignature(); |
1031 | | // creates a PKCS7 object using the ByteRange and overwrite /Contents |
1032 | | // of the signature dictionary |
1033 | | bool finalizeSignature(); |
1034 | | //writes encrypt |
1035 | | sal_Int32 emitEncrypt(); |
1036 | | // writes xref and trailer |
1037 | | bool emitTrailer(); |
1038 | | // emits info dict (if applicable) |
1039 | | sal_Int32 emitInfoDict( ); |
1040 | | |
1041 | | // acrobat reader 5 and 6 use the order of the annotations |
1042 | | // as their tab order; since PDF1.5 one can make the |
1043 | | // tab order explicit by using the structure tree |
1044 | | void sortWidgets(); |
1045 | | |
1046 | | // updates the count numbers of outline items |
1047 | | sal_Int32 updateOutlineItemCount( std::vector< sal_Int32 >& rCounts, |
1048 | | sal_Int32 nItemLevel, |
1049 | | sal_Int32 nCurrentItemId ); |
1050 | | // default appearances for widgets |
1051 | | sal_Int32 findRadioGroupWidget( const PDFWriter::RadioButtonWidget& rRadio ); |
1052 | | Font replaceFont( const Font& rControlFont, const Font& rAppSetFont ); |
1053 | | sal_Int32 getBestBuildinFont( const Font& rFont ); |
1054 | | sal_Int32 getSystemFont( const Font& i_rFont ); |
1055 | | |
1056 | | // used for edit and listbox |
1057 | | Font drawFieldBorder( PDFWidget&, const PDFWriter::AnyWidget&, const StyleSettings& ); |
1058 | | |
1059 | | void createDefaultPushButtonAppearance( PDFWidget&, const PDFWriter::PushButtonWidget& rWidget ); |
1060 | | void createDefaultCheckBoxAppearance( PDFWidget&, const PDFWriter::CheckBoxWidget& rWidget ); |
1061 | | void createDefaultRadioButtonAppearance( PDFWidget&, const PDFWriter::RadioButtonWidget& rWidget ); |
1062 | | void createDefaultEditAppearance( PDFWidget&, const PDFWriter::EditWidget& rWidget ); |
1063 | | void createDefaultListBoxAppearance( PDFWidget&, const PDFWriter::ListBoxWidget& rWidget ); |
1064 | | |
1065 | | /* ensure proper escapement and uniqueness of field names */ |
1066 | | void createWidgetFieldName( sal_Int32 i_nWidgetsIndex, const PDFWriter::AnyWidget& i_rInWidget ); |
1067 | | /// See vcl::PDFObjectContainer::createObject(). |
1068 | | sal_Int32 createObject() override; |
1069 | | /// See vcl::PDFObjectContainer::updateObject(). |
1070 | | bool updateObject( sal_Int32 n ) override; |
1071 | | |
1072 | | /// See vcl::PDFObjectContainer::writeBuffer(). |
1073 | | bool writeBufferBytes( const void* pBuffer, sal_uInt64 nBytes ) override; |
1074 | | void beginCompression(); |
1075 | | void endCompression(); |
1076 | | void beginRedirect( SvStream* pStream, const tools::Rectangle& ); |
1077 | | SvStream* endRedirect(); |
1078 | | |
1079 | | void endPage(); |
1080 | | |
1081 | | void beginStructureElementMCSeq(); |
1082 | | enum class EndMode { Default, OnlyStruct }; |
1083 | | void endStructureElementMCSeq(EndMode = EndMode::Default); |
1084 | | /** checks whether a non struct element lies in the ancestor hierarchy |
1085 | | of the current structure element |
1086 | | |
1087 | | @returns |
1088 | | true if no NonStructElement was found in ancestor path and tagged |
1089 | | PDF output is enabled |
1090 | | false else |
1091 | | */ |
1092 | | bool checkEmitStructure(); |
1093 | | |
1094 | | /* draws an emphasis mark */ |
1095 | | void drawEmphasisMark( tools::Long nX, tools::Long nY, const tools::PolyPolygon& rPolyPoly, bool bPolyLine, const tools::Rectangle& rRect1, const tools::Rectangle& rRect2 ); |
1096 | | |
1097 | | /* true if PDF/A-1a or PDF/A-1b is output */ |
1098 | | bool m_bIsPDF_A1 = false; |
1099 | | /* true if PDF/A-2a is output */ |
1100 | | bool m_bIsPDF_A2 = false; |
1101 | | /* true if PDF/A-3 is output */ |
1102 | | bool m_bIsPDF_A3 = false; |
1103 | | /* true if PDF/A-4 is output */ |
1104 | | bool m_bIsPDF_A4 = false; |
1105 | | |
1106 | | sal_Int32 m_nPDFA_Version = 0; |
1107 | | |
1108 | | /* PDF/UA support enabled */ |
1109 | | bool m_bIsPDF_UA = false; |
1110 | | |
1111 | | PDFWriter& m_rOuterFace; |
1112 | | |
1113 | | /* |
1114 | | i12626 |
1115 | | methods for PDF security |
1116 | | |
1117 | | pad a password according algorithm 3.2, step 1 */ |
1118 | | void setupDocInfo(); |
1119 | | |
1120 | | // helper for playMetafile |
1121 | | void implWriteGradient( const tools::PolyPolygon& rPolyPoly, const Gradient& rGradient, |
1122 | | VirtualDevice* pDummyVDev, const vcl::PDFWriter::PlayMetafileContext& ); |
1123 | | void implWriteBitmapEx( const Point& rPoint, const Size& rSize, const Bitmap& rBitmap, const Graphic& i_pGraphic, |
1124 | | VirtualDevice const * pDummyVDev, const vcl::PDFWriter::PlayMetafileContext& ); |
1125 | | |
1126 | | // color helper functions |
1127 | | void appendStrokingColor( const Color& rColor, OStringBuffer& rBuffer ); |
1128 | | void appendNonStrokingColor( const Color& rColor, OStringBuffer& rBuffer ); |
1129 | | public: |
1130 | | PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext, const css::uno::Reference< css::beans::XMaterialHolder >&, PDFWriter& ); |
1131 | | ~PDFWriterImpl() override; |
1132 | | void dispose() override; |
1133 | | |
1134 | | /* document structure */ |
1135 | | void newPage( double nPageWidth , double nPageHeight, PDFWriter::Orientation eOrientation ); |
1136 | | bool emit(); |
1137 | 4.16k | const std::set< PDFWriter::ErrorCode > & getErrors() const { return m_aErrors;} |
1138 | 0 | void insertError( PDFWriter::ErrorCode eErr ) { m_aErrors.insert( eErr ); } |
1139 | | void playMetafile( const GDIMetaFile&, vcl::PDFExtOutDevData*, const vcl::PDFWriter::PlayMetafileContext&, VirtualDevice* pDummyDev = nullptr ); |
1140 | | |
1141 | | Size getCurPageSize() const |
1142 | 0 | { |
1143 | 0 | Size aSize; |
1144 | 0 | if( m_nCurrentPage >= 0 && o3tl::make_unsigned(m_nCurrentPage) < m_aPages.size() ) |
1145 | 0 | aSize = Size( m_aPages[ m_nCurrentPage ].m_nPageWidth, m_aPages[ m_nCurrentPage ].m_nPageHeight ); |
1146 | 0 | return aSize; |
1147 | 0 | } |
1148 | | |
1149 | | void setDocumentLocale( const css::lang::Locale& rLoc ) |
1150 | 4.16k | { m_aContext.DocumentLocale = rLoc; } |
1151 | | |
1152 | | /* graphics state */ |
1153 | | void push( PushFlags nFlags ); |
1154 | | void pop(); |
1155 | | |
1156 | | void setFont( const Font& rFont ); |
1157 | | |
1158 | | void setMapMode( const MapMode& rMapMode ); |
1159 | | |
1160 | 0 | const MapMode& getMapMode() { return m_aGraphicsStack.front().m_aMapMode; } |
1161 | | |
1162 | | void setLineColor( const Color& rColor ) |
1163 | 455k | { |
1164 | 455k | m_aGraphicsStack.front().m_aLineColor = rColor.IsTransparent() ? COL_TRANSPARENT : rColor; |
1165 | 455k | m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::LineColor; |
1166 | 455k | } |
1167 | | |
1168 | | void setFillColor( const Color& rColor ) |
1169 | 456k | { |
1170 | 456k | m_aGraphicsStack.front().m_aFillColor = rColor.IsTransparent() ? COL_TRANSPARENT : rColor; |
1171 | 456k | m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::FillColor; |
1172 | 456k | } |
1173 | | |
1174 | | void setTextLineColor() |
1175 | 0 | { |
1176 | 0 | m_aGraphicsStack.front().m_aTextLineColor = COL_TRANSPARENT; |
1177 | 0 | } |
1178 | | |
1179 | | void setTextLineColor( const Color& rColor ) |
1180 | 454k | { |
1181 | 454k | m_aGraphicsStack.front().m_aTextLineColor = rColor; |
1182 | 454k | } |
1183 | | |
1184 | | void setOverlineColor() |
1185 | 0 | { |
1186 | 0 | m_aGraphicsStack.front().m_aOverlineColor = COL_TRANSPARENT; |
1187 | 0 | } |
1188 | | |
1189 | | void setOverlineColor( const Color& rColor ) |
1190 | 454k | { |
1191 | 454k | m_aGraphicsStack.front().m_aOverlineColor = rColor; |
1192 | 454k | } |
1193 | | |
1194 | | void setTextFillColor( const Color& rColor ) |
1195 | 454k | { |
1196 | 454k | m_aGraphicsStack.front().m_aFont.SetFillColor( rColor ); |
1197 | 454k | m_aGraphicsStack.front().m_aFont.SetTransparent( rColor.IsTransparent() ); |
1198 | 454k | m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::Font; |
1199 | 454k | } |
1200 | | void setTextFillColor() |
1201 | 905k | { |
1202 | 905k | m_aGraphicsStack.front().m_aFont.SetFillColor( COL_TRANSPARENT ); |
1203 | 905k | m_aGraphicsStack.front().m_aFont.SetTransparent( true ); |
1204 | 905k | m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::Font; |
1205 | 905k | } |
1206 | | void setTextColor( const Color& rColor ) |
1207 | 840k | { |
1208 | 840k | m_aGraphicsStack.front().m_aFont.SetColor( rColor ); |
1209 | 840k | m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::Font; |
1210 | 840k | } |
1211 | | |
1212 | | void clearClipRegion() |
1213 | 671 | { |
1214 | 671 | m_aGraphicsStack.front().m_aClipRegion.clear(); |
1215 | 671 | m_aGraphicsStack.front().m_bClipRegion = false; |
1216 | 671 | m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::ClipRegion; |
1217 | 671 | } |
1218 | | |
1219 | | void setClipRegion( const basegfx::B2DPolyPolygon& rRegion ); |
1220 | | |
1221 | | void moveClipRegion( sal_Int32 nX, sal_Int32 nY ); |
1222 | | |
1223 | | void intersectClipRegion( const tools::Rectangle& rRect ); |
1224 | | |
1225 | | void intersectClipRegion( const basegfx::B2DPolyPolygon& rRegion ); |
1226 | | |
1227 | | void setLayoutMode( vcl::text::ComplexTextLayoutFlags nLayoutMode ) |
1228 | 1.40M | { |
1229 | 1.40M | m_aGraphicsStack.front().m_nLayoutMode = nLayoutMode; |
1230 | 1.40M | m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::LayoutMode; |
1231 | 1.40M | } |
1232 | | |
1233 | | void setDigitLanguage( LanguageType eLang ) |
1234 | 838k | { |
1235 | 838k | m_aGraphicsStack.front().m_aDigitLanguage = eLang; |
1236 | 838k | m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::DigitLanguage; |
1237 | 838k | } |
1238 | | |
1239 | | void setTextAlign( TextAlign eAlign ) |
1240 | 1.35M | { |
1241 | 1.35M | m_aGraphicsStack.front().m_aFont.SetAlignment( eAlign ); |
1242 | 1.35M | m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::Font; |
1243 | 1.35M | } |
1244 | | |
1245 | | /* actual drawing functions */ |
1246 | | void drawText( const Point& rPos, const OUString& rText, sal_Int32 nIndex, sal_Int32 nLen, bool bTextLines = true ); |
1247 | | void drawTextArray(const Point& rPos, const OUString& rText, KernArraySpan pDXArray, |
1248 | | std::span<const sal_Bool> pKashidaArray, sal_Int32 nIndex, sal_Int32 nLen, |
1249 | | sal_Int32 nLayoutContextIndex, sal_Int32 nLayoutContextLen); |
1250 | | void drawStretchText( const Point& rPos, sal_Int32 nWidth, const OUString& rText, |
1251 | | sal_Int32 nIndex, sal_Int32 nLen ); |
1252 | | void drawText( const tools::Rectangle& rRect, const OUString& rOrigStr, DrawTextFlags nStyle ); |
1253 | | void drawTextLine( const Point& rPos, tools::Long nWidth, FontStrikeout eStrikeout, FontLineStyle eUnderline, FontLineStyle eOverline, bool bUnderlineAbove ); |
1254 | | void drawWaveTextLine( OStringBuffer& aLine, tools::Long nWidth, FontLineStyle eTextLine, Color aColor, bool bIsAbove ); |
1255 | | void drawStraightTextLine( OStringBuffer& aLine, tools::Long nWidth, FontLineStyle eTextLine, Color aColor, bool bIsAbove ); |
1256 | | void drawStrikeoutLine( OStringBuffer& aLine, tools::Long nWidth, FontStrikeout eStrikeout, Color aColor ); |
1257 | | void drawStrikeoutChar( const Point& rPos, tools::Long nWidth, FontStrikeout eStrikeout ); |
1258 | | |
1259 | | void drawLine( const Point& rStart, const Point& rStop ); |
1260 | | void drawLine( const Point& rStart, const Point& rStop, const LineInfo& rInfo ); |
1261 | | void drawPolygon( const tools::Polygon& rPoly ); |
1262 | | void drawPolyPolygon( const tools::PolyPolygon& rPolyPoly ); |
1263 | | void drawPolyLine( const tools::Polygon& rPoly ); |
1264 | | void drawPolyLine( const tools::Polygon& rPoly, const LineInfo& rInfo ); |
1265 | | void drawPolyLine( const tools::Polygon& rPoly, const PDFWriter::ExtLineInfo& rInfo ); |
1266 | | |
1267 | | void drawPixel( const Point& rPt, const Color& rColor ); |
1268 | | |
1269 | | void drawRectangle( const tools::Rectangle& rRect ); |
1270 | | void drawRectangle( const tools::Rectangle& rRect, sal_uInt32 nHorzRound, sal_uInt32 nVertRound ); |
1271 | | void drawEllipse( const tools::Rectangle& rRect ); |
1272 | | void drawArc( const tools::Rectangle& rRect, const Point& rStart, const Point& rStop, bool bWithPie, bool bWidthChord ); |
1273 | | |
1274 | | void drawBitmap( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap, const Graphic& rGraphic ); |
1275 | | void drawBitmap( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap ); |
1276 | | void drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const Size& rSizePixel, const tools::Rectangle& rTargetArea, const AlphaMask& rAlphaMask, const Graphic& rGraphic ); |
1277 | | /// Stores the original PDF data from rGraphic as an embedded file. |
1278 | | void createEmbeddedFile(const Graphic& rGraphic, ReferenceXObjectEmit& rEmit, sal_Int32 nBitmapObject); |
1279 | | |
1280 | | void drawGradient( const tools::Rectangle& rRect, const Gradient& rGradient ); |
1281 | | void drawHatch( const tools::PolyPolygon& rPolyPoly, const Hatch& rHatch ); |
1282 | | void drawWallpaper( const tools::Rectangle& rRect, const Wallpaper& rWall ); |
1283 | | void drawTransparent( const tools::PolyPolygon& rPolyPoly, sal_uInt32 nTransparentPercent ); |
1284 | | void beginTransparencyGroup(); |
1285 | | void endTransparencyGroup( const tools::Rectangle& rBoundingBox, sal_uInt32 nTransparentPercent ); |
1286 | | |
1287 | | void emitComment( const char* pComment ); |
1288 | | |
1289 | | //--->i56629 named destinations |
1290 | | sal_Int32 createNamedDest( const OUString& sDestName, const tools::Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType ); |
1291 | | |
1292 | | //--->i59651 |
1293 | | //emits output intent |
1294 | | sal_Int32 emitOutputIntent(); |
1295 | | |
1296 | | //emits the document metadata |
1297 | | sal_Int32 emitDocumentMetadata(); |
1298 | | |
1299 | | // links |
1300 | | sal_Int32 createLink(const tools::Rectangle& rRect, sal_Int32 nPageNr, OUString const& rAltText); |
1301 | | sal_Int32 createDest( const tools::Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType ); |
1302 | | sal_Int32 registerDestReference( sal_Int32 nDestId, const tools::Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType ); |
1303 | | void setLinkDest( sal_Int32 nLinkId, sal_Int32 nDestId ); |
1304 | | void setLinkURL( sal_Int32 nLinkId, const OUString& rURL ); |
1305 | | void setLinkPropertyId( sal_Int32 nLinkId, sal_Int32 nPropertyId ); |
1306 | | |
1307 | | // screens |
1308 | | sal_Int32 createScreen(const tools::Rectangle& rRect, sal_Int32 nPageNr, OUString const& rAltText, OUString const& rMimeType); |
1309 | | void setScreenURL(sal_Int32 nScreenId, const OUString& rURL); |
1310 | | void setScreenStream(sal_Int32 nScreenId, const OUString& rURL); |
1311 | | |
1312 | | // outline |
1313 | | sal_Int32 createOutlineItem( sal_Int32 nParent, std::u16string_view rText, sal_Int32 nDestID ); |
1314 | | void setOutlineItemParent( sal_Int32 nItem, sal_Int32 nNewParent ); |
1315 | | void setOutlineItemText( sal_Int32 nItem, std::u16string_view rText ); |
1316 | | void setOutlineItemDest( sal_Int32 nItem, sal_Int32 nDestID ); |
1317 | | |
1318 | | // notes |
1319 | | sal_Int32 createNote(const tools::Rectangle& rRect, const tools::Rectangle& rPopupRect, const PDFNote& rNote, sal_Int32 nPageNr); |
1320 | | // structure elements |
1321 | | sal_Int32 ensureStructureElement(); |
1322 | | void initStructureElement(sal_Int32 id, vcl::pdf::StructElement eType, std::u16string_view rAlias); |
1323 | | void beginStructureElement(sal_Int32 id); |
1324 | | void endStructureElement(); |
1325 | | bool setCurrentStructureElement( sal_Int32 nElement ); |
1326 | | bool setStructureAttribute( enum PDFWriter::StructAttribute eAttr, enum PDFWriter::StructAttributeValue eVal ); |
1327 | | bool setStructureAttributeNumerical( enum PDFWriter::StructAttribute eAttr, sal_Int32 nValue ); |
1328 | | void setStructureBoundingBox( const tools::Rectangle& rRect ); |
1329 | | void setStructureAnnotIds(::std::vector<sal_Int32> const& rAnnotIds); |
1330 | | void setActualText( const OUString& rText ); |
1331 | | void setAlternateText( const OUString& rText ); |
1332 | | |
1333 | | // transitional effects |
1334 | | void setPageTransition( PDFWriter::PageTransition eType, sal_uInt32 nMilliSec, sal_Int32 nPageNr ); |
1335 | | |
1336 | | // controls |
1337 | | sal_Int32 createControl( const PDFWriter::AnyWidget& rControl, sal_Int32 nPageNr = -1 ); |
1338 | | |
1339 | | // attached file |
1340 | | void addDocumentAttachedFile(OUString const& rFileName, OUString const& rMimeType, OUString const& rDescription, std::unique_ptr<PDFOutputStream> rStream); |
1341 | | |
1342 | | sal_Int32 addEmbeddedFile(BinaryDataContainer const & rDataContainer); |
1343 | | sal_Int32 addEmbeddedFile(std::unique_ptr<PDFOutputStream> rStream, OUString const& rMimeType); |
1344 | | |
1345 | | // helper: eventually begin marked content sequence and |
1346 | | // emit a comment in debug case |
1347 | | void MARK( const char* pString ); |
1348 | | }; |
1349 | | |
1350 | | } // namespace vcl |
1351 | | |
1352 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |