Commit c1627d04385a02045e7a1a5462f2a632fc529a2e

Authored by Jay Berkenbilt
1 parent fc4c82a9

Add QPDFWriter::setExtraHeaderText

ChangeLog
1 1 2012-09-06 Jay Berkenbilt <ejb@ql.org>
2 2  
  3 + * Add new method QPDFWriter::setExtraHeaderText to add extra text,
  4 + such as application-specific comments, to near the beginning of a
  5 + PDF file. For linearized files, this appears after the
  6 + linearization parameter dictionary. For non-linearized files, it
  7 + appears right after the PDF header and non-ASCII comment.
  8 +
3 9 * Make it possible to write the same QPDF object with two
4 10 different QPDFWriter objects that have both called
5 11 setLinearization(true) by making private method
... ...
include/qpdf/QPDFWriter.hh
... ... @@ -163,6 +163,18 @@ class QPDFWriter
163 163 QPDF_DLL
164 164 void forcePDFVersion(std::string const&);
165 165  
  166 + // Provide additional text to insert in the PDF file somewhere
  167 + // near the beginning of the file. This can be used to add
  168 + // comments to the beginning of a PDF file, for example, if those
  169 + // comments are to be consumed by some other application. No
  170 + // checks are performed to ensure that the text inserted here is
  171 + // valid PDF. If you want to insert multiline comments, you will
  172 + // need to include \n in the string yourself and start each line
  173 + // with %. An extra newline will be appended if one is not
  174 + // already present at the end of your text.
  175 + QPDF_DLL
  176 + void setExtraHeaderText(std::string const&);
  177 +
166 178 // Cause a static /ID value to be generated. Use only in test
167 179 // suites.
168 180 QPDF_DLL
... ... @@ -354,6 +366,7 @@ class QPDFWriter
354 366 std::string id2; // trailer dictionary
355 367 std::string min_pdf_version;
356 368 std::string forced_pdf_version;
  369 + std::string extra_header_text;
357 370 int encryption_dict_objid;
358 371 std::string cur_data_key;
359 372 std::list<PointerHolder<Pipeline> > to_delete;
... ...
libqpdf/QPDFWriter.cc
... ... @@ -196,6 +196,22 @@ QPDFWriter::forcePDFVersion(std::string const&amp; version)
196 196 }
197 197  
198 198 void
  199 +QPDFWriter::setExtraHeaderText(std::string const& text)
  200 +{
  201 + this->extra_header_text = text;
  202 + if ((this->extra_header_text.length() > 0) &&
  203 + (*(this->extra_header_text.rbegin()) != '\n'))
  204 + {
  205 + QTC::TC("qpdf", "QPDFWriter extra header text add newline");
  206 + this->extra_header_text += "\n";
  207 + }
  208 + else
  209 + {
  210 + QTC::TC("qpdf", "QPDFWriter extra header text no newline");
  211 + }
  212 +}
  213 +
  214 +void
199 215 QPDFWriter::setStaticID(bool val)
200 216 {
201 217 this->static_id = val;
... ... @@ -1832,6 +1848,12 @@ QPDFWriter::writeHeader()
1832 1848 // it really should be treated as binary.
1833 1849 writeString("\n%\xbf\xf7\xa2\xfe\n");
1834 1850 writeStringQDF("%QDF-1.0\n\n");
  1851 +
  1852 + // Note: do not write extra header text here. Linearized PDFs
  1853 + // must include the entire linearization parameter dictionary
  1854 + // within the first 1024 characters of the PDF file, so for
  1855 + // linearized files, we have to write extra header text after the
  1856 + // linearization parameter dictionary.
1835 1857 }
1836 1858  
1837 1859 void
... ... @@ -2189,7 +2211,9 @@ QPDFWriter::writeLinearized()
2189 2211 // space to write real dictionary. 200 characters is enough
2190 2212 // space if all numerical values in the parameter dictionary
2191 2213 // that contain offsets are 20 digits long plus a few extra
2192   - // characters for safety.
  2214 + // characters for safety. The entire linearization parameter
  2215 + // dictionary must appear within the first 1024 characters of
  2216 + // the file.
2193 2217  
2194 2218 qpdf_offset_t pos = this->pipeline->getCount();
2195 2219 openObject(lindict_id);
... ... @@ -2225,6 +2249,10 @@ QPDFWriter::writeLinearized()
2225 2249 writePad(spaces);
2226 2250 writeString("\n");
2227 2251  
  2252 + // If the user supplied any additional header text, write it
  2253 + // here after the linearization parameter dictionary.
  2254 + writeString(this->extra_header_text);
  2255 +
2228 2256 // Part 3: first page cross reference table and trailer.
2229 2257  
2230 2258 qpdf_offset_t first_xref_offset = this->pipeline->getCount();
... ... @@ -2396,6 +2424,7 @@ QPDFWriter::writeStandard()
2396 2424 // Start writing
2397 2425  
2398 2426 writeHeader();
  2427 + writeString(this->extra_header_text);
2399 2428  
2400 2429 // Put root first on queue.
2401 2430 QPDFObjectHandle trailer = pdf.getTrailer();
... ...
qpdf/qpdf.testcov
... ... @@ -240,3 +240,5 @@ QPDFObjectHandle trailing data in parse 0
240 240 qpdf pages encryption password 0
241 241 QPDF_Tokenizer EOF reading token 0
242 242 QPDF_Tokenizer EOF reading appendable token 0
  243 +QPDFWriter extra header text no newline 0
  244 +QPDFWriter extra header text add newline 0
... ...
qpdf/qtest/qpdf.test
... ... @@ -149,7 +149,7 @@ $td-&gt;runtest(&quot;remove page we don&#39;t have&quot;,
149 149 $td->NORMALIZE_NEWLINES);
150 150 # ----------
151 151 $td->notify("--- Miscellaneous Tests ---");
152   -$n_tests += 48;
  152 +$n_tests += 53;
153 153  
154 154 $td->runtest("qpdf version",
155 155 {$td->COMMAND => "qpdf --version"},
... ... @@ -387,6 +387,22 @@ $td-&gt;runtest(&quot;EOF reading token&quot;,
387 387 {$td->COMMAND => "qpdf --check eof-reading-token.pdf"},
388 388 {$td->FILE => "eof-reading-token.out", $td->EXIT_STATUS => 0},
389 389 $td->NORMALIZE_NEWLINES);
  390 +$td->runtest("extra header text",
  391 + {$td->COMMAND => "test_driver 32 minimal.pdf"},
  392 + {$td->FILE => "test-32.out", $td->EXIT_STATUS => 0},
  393 + $td->NORMALIZE_NEWLINES);
  394 +$td->runtest("check output",
  395 + {$td->FILE => "a.pdf"},
  396 + {$td->FILE => "extra-header-no-newline.pdf"});
  397 +$td->runtest("check output",
  398 + {$td->FILE => "b.pdf"},
  399 + {$td->FILE => "extra-header-lin-no-newline.pdf"});
  400 +$td->runtest("check output",
  401 + {$td->FILE => "c.pdf"},
  402 + {$td->FILE => "extra-header-newline.pdf"});
  403 +$td->runtest("check output",
  404 + {$td->FILE => "d.pdf"},
  405 + {$td->FILE => "extra-header-lin-newline.pdf"});
390 406  
391 407 show_ntests();
392 408 # ----------
... ...
qpdf/qtest/qpdf/extra-header-lin-newline.pdf 0 → 100644
No preview for this file type
qpdf/qtest/qpdf/extra-header-lin-no-newline.pdf 0 → 100644
No preview for this file type
qpdf/qtest/qpdf/extra-header-newline.pdf 0 → 100644
No preview for this file type
qpdf/qtest/qpdf/extra-header-no-newline.pdf 0 → 100644
No preview for this file type
qpdf/qtest/qpdf/test-32.out 0 → 100644
  1 +file: a.pdf
  2 +linearized: no
  3 +newline: no
  4 +file: b.pdf
  5 +linearized: yes
  6 +newline: no
  7 +file: c.pdf
  8 +linearized: no
  9 +newline: yes
  10 +file: d.pdf
  11 +linearized: yes
  12 +newline: yes
  13 +test 32 done
... ...
qpdf/test_driver.cc
... ... @@ -1091,6 +1091,27 @@ void runtest(int n, char const* filename1, char const* filename2)
1091 1091 << std::endl;
1092 1092 }
1093 1093 }
  1094 + else if (n == 32)
  1095 + {
  1096 + // Extra header text
  1097 + char const* filenames[] = {"a.pdf", "b.pdf", "c.pdf", "d.pdf"};
  1098 + for (int i = 0; i < 4; ++i)
  1099 + {
  1100 + bool linearized = ((i & 1) != 0);
  1101 + bool newline = ((i & 2) != 0);
  1102 + QPDFWriter w(pdf, filenames[i]);
  1103 + w.setStaticID(true);
  1104 + std::cout
  1105 + << "file: " << filenames[i] << std::endl
  1106 + << "linearized: " << (linearized ? "yes" : "no") << std::endl
  1107 + << "newline: " << (newline ? "yes" : "no") << std::endl;
  1108 + w.setLinearization(linearized);
  1109 + w.setExtraHeaderText(newline
  1110 + ? "%% Comment with newline\n"
  1111 + : "%% Comment\n% No newline");
  1112 + w.write();
  1113 + }
  1114 + }
1094 1115 else
1095 1116 {
1096 1117 throw std::runtime_error(std::string("invalid test ") +
... ...