• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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