Commit f37d399d825fc70155a3634c26463a24a2e17035
1 parent
6a7d53ad
Add newline-before-endstream option (fixes #103)
Showing
6 changed files
with
41 additions
and
2 deletions
ChangeLog
| 1 | 2017-07-29 Jay Berkenbilt <ejb@ql.org> | 1 | 2017-07-29 Jay Berkenbilt <ejb@ql.org> |
| 2 | 2 | ||
| 3 | + * Add --newline-before-endstream command-line option and | ||
| 4 | + setNewlineBeforeEndstream method to QPDFWriter. This forces qpdf | ||
| 5 | + to always add a newline before the endstream keyword. It is a | ||
| 6 | + necessary but not sufficient condition for PDF/A compliance. Fixes | ||
| 7 | + #103. | ||
| 8 | + | ||
| 3 | * Handle zlib data errors when decoding streams. Fixes #106. | 9 | * Handle zlib data errors when decoding streams. Fixes #106. |
| 4 | 10 | ||
| 5 | * Improve handling of files where the "stream" keyword is not | 11 | * Improve handling of files where the "stream" keyword is not |
include/qpdf/QPDFWriter.hh
| @@ -161,6 +161,11 @@ class QPDFWriter | @@ -161,6 +161,11 @@ class QPDFWriter | ||
| 161 | QPDF_DLL | 161 | QPDF_DLL |
| 162 | void setPreserveUnreferencedObjects(bool); | 162 | void setPreserveUnreferencedObjects(bool); |
| 163 | 163 | ||
| 164 | + // Always write a newline before the endstream keyword. This helps | ||
| 165 | + // with PDF/A compliance, though it is not sufficient for it. | ||
| 166 | + QPDF_DLL | ||
| 167 | + void setNewlineBeforeEndstream(bool); | ||
| 168 | + | ||
| 164 | // Set the minimum PDF version. If the PDF version of the input | 169 | // Set the minimum PDF version. If the PDF version of the input |
| 165 | // file (or previously set minimum version) is less than the | 170 | // file (or previously set minimum version) is less than the |
| 166 | // version passed to this method, the PDF version of the output | 171 | // version passed to this method, the PDF version of the output |
| @@ -434,6 +439,7 @@ class QPDFWriter | @@ -434,6 +439,7 @@ class QPDFWriter | ||
| 434 | bool qdf_mode; | 439 | bool qdf_mode; |
| 435 | bool precheck_streams; | 440 | bool precheck_streams; |
| 436 | bool preserve_unreferenced_objects; | 441 | bool preserve_unreferenced_objects; |
| 442 | + bool newline_before_endstream; | ||
| 437 | bool static_id; | 443 | bool static_id; |
| 438 | bool suppress_original_object_ids; | 444 | bool suppress_original_object_ids; |
| 439 | bool direct_stream_lengths; | 445 | bool direct_stream_lengths; |
libqpdf/QPDFWriter.cc
| @@ -59,6 +59,7 @@ QPDFWriter::init() | @@ -59,6 +59,7 @@ QPDFWriter::init() | ||
| 59 | qdf_mode = false; | 59 | qdf_mode = false; |
| 60 | precheck_streams = false; | 60 | precheck_streams = false; |
| 61 | preserve_unreferenced_objects = false; | 61 | preserve_unreferenced_objects = false; |
| 62 | + newline_before_endstream = false; | ||
| 62 | static_id = false; | 63 | static_id = false; |
| 63 | suppress_original_object_ids = false; | 64 | suppress_original_object_ids = false; |
| 64 | direct_stream_lengths = true; | 65 | direct_stream_lengths = true; |
| @@ -191,6 +192,12 @@ QPDFWriter::setPreserveUnreferencedObjects(bool val) | @@ -191,6 +192,12 @@ QPDFWriter::setPreserveUnreferencedObjects(bool val) | ||
| 191 | } | 192 | } |
| 192 | 193 | ||
| 193 | void | 194 | void |
| 195 | +QPDFWriter::setNewlineBeforeEndstream(bool val) | ||
| 196 | +{ | ||
| 197 | + this->newline_before_endstream = val; | ||
| 198 | +} | ||
| 199 | + | ||
| 200 | +void | ||
| 194 | QPDFWriter::setMinimumPDFVersion(std::string const& version) | 201 | QPDFWriter::setMinimumPDFVersion(std::string const& version) |
| 195 | { | 202 | { |
| 196 | setMinimumPDFVersion(version, 0); | 203 | setMinimumPDFVersion(version, 0); |
| @@ -1580,7 +1587,7 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level, | @@ -1580,7 +1587,7 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level, | ||
| 1580 | char last_char = this->pipeline->getLastChar(); | 1587 | char last_char = this->pipeline->getLastChar(); |
| 1581 | popPipelineStack(); | 1588 | popPipelineStack(); |
| 1582 | 1589 | ||
| 1583 | - if (this->qdf_mode) | 1590 | + if (this->qdf_mode || this->newline_before_endstream) |
| 1584 | { | 1591 | { |
| 1585 | if (last_char != '\n') | 1592 | if (last_char != '\n') |
| 1586 | { | 1593 | { |
qpdf/qpdf.cc
| @@ -204,6 +204,7 @@ familiar with the PDF file format or who are PDF developers.\n\ | @@ -204,6 +204,7 @@ familiar with the PDF file format or who are PDF developers.\n\ | ||
| 204 | --ignore-xref-streams tells qpdf to ignore any cross-reference streams\n\ | 204 | --ignore-xref-streams tells qpdf to ignore any cross-reference streams\n\ |
| 205 | --precheck-streams precheck ability to decode streams\n\ | 205 | --precheck-streams precheck ability to decode streams\n\ |
| 206 | --preserve-unreferenced preserve unreferenced objects\n\ | 206 | --preserve-unreferenced preserve unreferenced objects\n\ |
| 207 | +--newline-before-endstream always put a newline before endstream\n\ | ||
| 207 | --qdf turns on \"QDF mode\" (below)\n\ | 208 | --qdf turns on \"QDF mode\" (below)\n\ |
| 208 | --min-version=version sets the minimum PDF version of the output file\n\ | 209 | --min-version=version sets the minimum PDF version of the output file\n\ |
| 209 | --force-version=version forces this to be the PDF version of the output file\n\ | 210 | --force-version=version forces this to be the PDF version of the output file\n\ |
| @@ -1032,6 +1033,7 @@ int main(int argc, char* argv[]) | @@ -1032,6 +1033,7 @@ int main(int argc, char* argv[]) | ||
| 1032 | bool qdf_mode = false; | 1033 | bool qdf_mode = false; |
| 1033 | bool precheck_streams = false; | 1034 | bool precheck_streams = false; |
| 1034 | bool preserve_unreferenced_objects = false; | 1035 | bool preserve_unreferenced_objects = false; |
| 1036 | + bool newline_before_endstream = false; | ||
| 1035 | std::string min_version; | 1037 | std::string min_version; |
| 1036 | std::string force_version; | 1038 | std::string force_version; |
| 1037 | 1039 | ||
| @@ -1225,6 +1227,10 @@ int main(int argc, char* argv[]) | @@ -1225,6 +1227,10 @@ int main(int argc, char* argv[]) | ||
| 1225 | { | 1227 | { |
| 1226 | preserve_unreferenced_objects = true; | 1228 | preserve_unreferenced_objects = true; |
| 1227 | } | 1229 | } |
| 1230 | + else if (strcmp(arg, "newline-before-endstream") == 0) | ||
| 1231 | + { | ||
| 1232 | + newline_before_endstream = true; | ||
| 1233 | + } | ||
| 1228 | else if (strcmp(arg, "min-version") == 0) | 1234 | else if (strcmp(arg, "min-version") == 0) |
| 1229 | { | 1235 | { |
| 1230 | if (parameter == 0) | 1236 | if (parameter == 0) |
| @@ -1724,6 +1730,10 @@ int main(int argc, char* argv[]) | @@ -1724,6 +1730,10 @@ int main(int argc, char* argv[]) | ||
| 1724 | { | 1730 | { |
| 1725 | w.setPreserveUnreferencedObjects(true); | 1731 | w.setPreserveUnreferencedObjects(true); |
| 1726 | } | 1732 | } |
| 1733 | + if (newline_before_endstream) | ||
| 1734 | + { | ||
| 1735 | + w.setNewlineBeforeEndstream(true); | ||
| 1736 | + } | ||
| 1727 | if (normalize_set) | 1737 | if (normalize_set) |
| 1728 | { | 1738 | { |
| 1729 | w.setContentNormalization(normalize); | 1739 | w.setContentNormalization(normalize); |
qpdf/qtest/qpdf.test
| @@ -206,7 +206,7 @@ $td->runtest("remove page we don't have", | @@ -206,7 +206,7 @@ $td->runtest("remove page we don't have", | ||
| 206 | show_ntests(); | 206 | show_ntests(); |
| 207 | # ---------- | 207 | # ---------- |
| 208 | $td->notify("--- Miscellaneous Tests ---"); | 208 | $td->notify("--- Miscellaneous Tests ---"); |
| 209 | -$n_tests += 89; | 209 | +$n_tests += 91; |
| 210 | 210 | ||
| 211 | $td->runtest("qpdf version", | 211 | $td->runtest("qpdf version", |
| 212 | {$td->COMMAND => "qpdf --version"}, | 212 | {$td->COMMAND => "qpdf --version"}, |
| @@ -618,6 +618,16 @@ $td->runtest("split content stream errors", | @@ -618,6 +618,16 @@ $td->runtest("split content stream errors", | ||
| 618 | $td->EXIT_STATUS => 3}, | 618 | $td->EXIT_STATUS => 3}, |
| 619 | $td->NORMALIZE_NEWLINES); | 619 | $td->NORMALIZE_NEWLINES); |
| 620 | 620 | ||
| 621 | +$td->runtest("newline before endstream", | ||
| 622 | + {$td->COMMAND => | ||
| 623 | + "qpdf --static-id --newline-before-endstream" . | ||
| 624 | + " minimal.pdf a.pdf"}, | ||
| 625 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | ||
| 626 | + $td->NORMALIZE_NEWLINES); | ||
| 627 | +$td->runtest("check output", | ||
| 628 | + {$td->FILE => "a.pdf"}, | ||
| 629 | + {$td->FILE => "newline-before-endstream.pdf"}); | ||
| 630 | + | ||
| 621 | 631 | ||
| 622 | show_ntests(); | 632 | show_ntests(); |
| 623 | # ---------- | 633 | # ---------- |
qpdf/qtest/qpdf/newline-before-endstream.pdf
0 → 100644
No preview for this file type