Commit c1627d04385a02045e7a1a5462f2a632fc529a2e
1 parent
fc4c82a9
Add QPDFWriter::setExtraHeaderText
Showing
11 changed files
with
102 additions
and
2 deletions
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& 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->runtest("remove page we don't have", |
| 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->runtest("EOF reading token", |
| 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
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 ") + | ... | ... |