1
#include "qpdf_xobject.h"
2
//#include <qpdf/Types.h>
3
#include <qpdf/QPDF.hh>
4
#include <qpdf/Pl_Discard.hh>
5
#include <qpdf/Pl_Count.hh>
6
#include <qpdf/Pl_Concatenate.hh>
7
#include "qpdf_tools.h"
8
#include "qpdf_pdftopdf.h"
10
// TODO: need to remove Struct Parent stuff (or fix)
12
// NOTE: use /TrimBox to position content inside Nup cell, /BleedBox to clip against
14
class CombineFromContents_Provider : public QPDFObjectHandle::StreamDataProvider {
16
CombineFromContents_Provider(const std::vector<QPDFObjectHandle> &contents);
18
void provideStreamData(int objid, int generation, Pipeline* pipeline);
20
std::vector<QPDFObjectHandle> contents;
23
CombineFromContents_Provider::CombineFromContents_Provider(const std::vector<QPDFObjectHandle> &contents)
28
void CombineFromContents_Provider::provideStreamData(int objid, int generation, Pipeline* pipeline)
30
Pl_Concatenate concat("concat", pipeline);
31
const int clen=contents.size();
32
for (int iA=0;iA<clen;iA++) {
33
contents[iA].pipeStreamData(&concat, true, false, false);
35
concat.manualFinish();
39
To convert a page to an XObject there are several keys to consider:
41
/Type /Page -> /Type /XObject (/Type optional for XObject)
43
-> [/FormType 1] (optional)
44
/Parent ? ? R -> remove
45
/Resources dict -> copy
46
/MediaBox rect [/CropBox /BleedBox /TrimBox /ArtBox]
47
-> /BBox (use TrimBox [+ Bleed consideration?], with fallback to /MediaBox)
48
note that /BBox is in *Form Space*, see /Matrix!
49
[/BoxColorInfo dict] (used for guidelines that may be shown by viewer)
51
[/Contents asfd] -> concatenate into stream data of the XObject (page is a dict, XObject a stream)
53
[/Rotate 90] ... must be handled (either use CTM where XObject is /used/ -- or set /Matrix)
54
[/UserUnit] (PDF 1.6) -> to /Matrix ? -- it MUST be handled.
57
[/Thumb stream] -> remove, not needed any more / would have to be regenerated (combined)
58
[/B] article beads -- ignore for now
59
[/Dur] -> remove (transition duration)
60
[/Trans] -> remove (transitions)
61
[/AA] -> remove (additional-actions)
63
[/Metadata] what shall we do?? (kill: we can't combine XML)
64
[/PieceInfo] -> remove, we can't combine private app data (?)
65
[/LastModified date] (opt except /PieceInfo) -> see there
67
[/PZ] -> remove, can't combine/keep (preferred zoom level)
68
[/SeparationInfo] -> remove, no way to keep this (needed for separation)
70
[/ID] related to web capture -- ignore/kill?
71
[/StructParents] (opt except pdf contains "structural content items")
72
-> copy (is this correct?)
74
[/Annots] annotations -- ignore for now
75
[/Tabs] tab order for annotations (/R row, /C column, /S structure order) -- see /Annots
77
[/TemplateInstantiated] (reqd, if page was created from named page obj, 1.5) -- ? just ignore?
78
[/PresSteps] -> remove (sub-page navigation for presentations) [no subpage navigation for printing / nup]
79
[/VP] viewport rects -- ignore/drop or recalculate into new page
82
QPDFObjectHandle makeXObject(QPDF *pdf,QPDFObjectHandle page)
84
page.assertPageObject();
86
QPDFObjectHandle ret=QPDFObjectHandle::newStream(pdf);
87
QPDFObjectHandle dict=ret.getDict();
89
dict.replaceKey("/Type",QPDFObjectHandle::newName("/XObject")); // optional
90
dict.replaceKey("/Subtype",QPDFObjectHandle::newName("/Form")); // required
91
// dict.replaceKey("/FormType",QPDFObjectHandle::newInteger(1)); // optional
93
QPDFObjectHandle box=getTrimBox(page); // already in "form space"
94
dict.replaceKey("/BBox",box); // reqd
96
// [/Matrix .] ... default is [1 0 0 1 0 0]; we incorporate /UserUnit and /Rotate here
98
if (page.hasKey("/UserUnit")) {
99
mtx.scale(page.getKey("/UserUnit").getNumericValue());
102
// transform, so that bbox is [0 0 w h] (in outer space, but after UserUnit)
103
Rotation rot=getRotate(page);
105
// calculate rotation effect on [0 0 w h]
106
PageRect bbox=getBoxAsRect(box),tmp;
111
tmp.rotate_move(rot,bbox.width,bbox.height);
112
// tmp.rotate_move moves the bbox; we must achieve this move with the matrix.
113
mtx.translate(tmp.left,tmp.bottom); // 1. move origin to end up at left,bottom after rotation
115
mtx.rotate(rot); // 2. rotate coordinates according to /Rotate
116
mtx.translate(-bbox.left,-bbox.bottom); // 3. move origin from 0,0 to "form space"
118
dict.replaceKey("/Matrix",mtx.get());
120
dict.replaceKey("/Resources",page.getKey("/Resources"));
121
if (page.hasKey("/Group")) {
122
dict.replaceKey("/Group",page.getKey("/Group")); // (transparency); opt, copy if there
125
// ?? /StructParents ... can basically copy from page, but would need fixup in Structure Tree
126
// FIXME: remove (globally) Tagged spec (/MarkInfo), and Structure Tree
128
// Note: [/Name] (reqd. only in 1.0 -- but there we even can't use our normal img/patter procedures)
131
// QPDFObjectHandle filter=QPDFObjectHandle::newArray();
132
// QPDFObjectHandle decode_parms=QPDFObjectHandle::newArray();
133
// null leads to use of "default filters" from qpdf's settings
134
QPDFObjectHandle filter=QPDFObjectHandle::newNull();
135
QPDFObjectHandle decode_parms=QPDFObjectHandle::newNull();
137
std::vector<QPDFObjectHandle> contents=page.getPageContents(); // (will assertPageObject)
139
auto ph=PointerHolder<QPDFObjectHandle::StreamDataProvider>(new CombineFromContents_Provider(contents));
140
ret.replaceStreamData(ph,filter,decode_parms);
146
we will have to fix up the structure tree (e.g. /K in element), when copying /StructParents;
147
(there is /Pg, which has to point to the containing page, /Stm when it's not part of the page's content stream
148
i.e. when it is in our XObject!; then there is /StmOwn ...)
149
when not copying, we have to remove the structure tree completely (also /MarkInfo dict)
150
Still this might not be sufficient(?), as there are probably BDC and EMC operators in the stream.
153
/* /XObject /Form has
157
/BBox rect from crop box, or recalculate
158
[/Matrix .] ... default is [1 0 0 1 0 0] --- we have to incorporate /UserUnit here?!
159
[/Resources dict] from page.
160
[/Group dict] used for transparency -- can copy from page
161
[/Ref dict] not needed; for external reference
162
[/Metadata] not, as long we can not combine.
163
[/PieceInfo] can copy, but not combine
164
[/LastModified date] copy if /PieceInfo there
165
[/StructParent] . don't want to be one ... have to read more spec
166
[/StructParents] . copy from page!
167
[/OPI] no opi version. don't set
168
[/OC] is this optional content? NO! not needed.
169
[/Name] (only reqd. in 1.0 -- but there we even can't use our normal img/patter procedures)