1 #include "qpdf_cm.h"
2 #include <stdio.h>
3 #include <assert.h>
4
5 #include <stdexcept>
6
7 // TODO? instead use qpdf's StreamDataProvider, FileInputSource, Buffer etc.
load_file(const char * filename)8 static std::string load_file(const char *filename) // {{{
9 {
10 if (!filename) {
11 throw std::invalid_argument("NULL filename not allowed");
12 }
13
14 FILE *f=fopen(filename,"r");
15 if (!f) {
16 throw std::runtime_error(std::string("file ") + filename + " could not be opened");
17 }
18
19 const int bsize=2048;
20 int pos=0;
21
22 std::string ret;
23 while (!feof(f)) {
24 ret.resize(pos+bsize);
25 int res=fread(&ret[pos],1,bsize,f);
26 pos+=res;
27 if (res<bsize) {
28 ret.resize(pos);
29 break;
30 }
31 }
32
33 fclose(f);
34 return ret;
35 }
36 // }}}
37
38
39 // TODO?
40 // TODO? test
hasOutputIntent(QPDF & pdf)41 bool hasOutputIntent(QPDF &pdf) // {{{
42 {
43 auto catalog=pdf.getRoot();
44 if (!catalog.hasKey("/OutputIntents")) {
45 return false;
46 }
47 return true; // TODO?
48 }
49 // }}}
50
51 // TODO: test
52 // TODO? find existing , replace and return (?)
addOutputIntent(QPDF & pdf,const char * filename)53 void addOutputIntent(QPDF &pdf,const char *filename) // {{{
54 {
55 std::string icc=load_file(filename);
56 // TODO: check icc fitness
57 // ICC data, subject to "version limitations" per pdf version...
58
59 QPDFObjectHandle outicc=QPDFObjectHandle::newStream(&pdf,icc);
60
61 auto sdict=outicc.getDict();
62 sdict.replaceKey("/N",QPDFObjectHandle::newInteger(4)); // must match ICC
63 // /Range ? // must match ICC, default [0.0 1.0 ...]
64 // /Alternate ? (/DeviceCMYK for N=4)
65
66 auto intent=QPDFObjectHandle::parse(
67 "<<"
68 " /Type /OutputIntent" // Must be so (the standard requires).
69 " /S /GTS_PDFX" // Must be so (the standard requires).
70 " /OutputCondition (Commercial and specialty printing)" // TODO: Customize [optional(?)]
71 " /Info (none)" // TODO: Customize
72 " /OutputConditionIdentifier (CGATS TR001)" // TODO: FIXME: Customize
73 " /RegistryName (http://www.color.org)" // Must be so (the standard requires).
74 " /DestOutputProfile null "
75 ">>");
76 intent.replaceKey("/DestOutputProfile",outicc);
77
78 auto catalog=pdf.getRoot();
79 if (!catalog.hasKey("/OutputIntents")) {
80 catalog.replaceKey("/OutputIntents",QPDFObjectHandle::newArray());
81 }
82 catalog.getKey("/OutputIntents").appendItem(intent);
83 }
84 // }}}
85
86
87 /* for color management:
88 Use /DefaultGray, /DefaultRGB, /DefaultCMYK ... from *current* resource dictionary ...
89 i.e. set
90 /Resources <<
91 /ColorSpace << --- can use just one indirect ref for this (probably)
92 /DefaultRGB [/ICCBased 5 0 R] ... sensible use is sRGB for DefaultRGB, etc.
93 >>
94 >>
95 for every page (what with form /XObjects?) and most importantly RGB (leave CMYK, Gray for now, as this is already printer native(?))
96
97 ? also every form XObject, pattern, type3 font, annotation appearance stream(=form xobject +X)
98
99 ? what if page already defines /Default? -- probably keep!
100
101 ? maybe we need to set /ColorSpace in /Images ? [gs idea is to just add the /Default-key and then reprocess...]
102
103 */
104
105 // TODO? test
addDefaultRGB(QPDF & pdf,QPDFObjectHandle srcicc)106 void addDefaultRGB(QPDF &pdf,QPDFObjectHandle srcicc) // {{{
107 {
108 srcicc.assertStream();
109
110 auto pages=pdf.getAllPages();
111 for (auto it=pages.begin(),end=pages.end();it!=end;++it) {
112 if (!it->hasKey("/Resources")) {
113 it->replaceKey("/Resources",QPDFObjectHandle::newDictionary());
114 }
115 auto rdict=it->getKey("/Resources");
116
117 if (!rdict.hasKey("/ColorSpace")) {
118 rdict.replaceKey("/ColorSpace",QPDFObjectHandle::newDictionary());
119 }
120 auto cdict=rdict.getKey("/ColorSpace");
121
122 if (!cdict.hasKey("/DefaultRGB")) {
123 cdict.replaceKey("/DefaultRGB",QPDFObjectHandle::parse("[/ICCBased ]"));
124 cdict.getKey("/DefaultRGB").appendItem(srcicc);
125 }
126 }
127 }
128 // }}}
129
130 // TODO? test
131 // TODO: find existing , replace and return (?)
132 // TODO: check icc fitness
setDefaultICC(QPDF & pdf,const char * filename)133 QPDFObjectHandle setDefaultICC(QPDF &pdf,const char *filename) // {{{
134 {
135 // TODO: find existing , replace and return (?)
136
137 std::string icc=load_file(filename);
138 // TODO: check icc fitness
139 // ICC data, subject to "version limitations" per pdf version...
140
141 QPDFObjectHandle ret=QPDFObjectHandle::newStream(&pdf,icc);
142
143 auto sdict=ret.getDict();
144 sdict.replaceKey("/N",QPDFObjectHandle::newInteger(3)); // must match ICC
145 // /Range ? // must match ICC, default [0.0 1.0 ...]
146 // /Alternate ? (/DeviceRGB for N=3)
147
148 return ret;
149 }
150 // }}}
151
152