diff --git a/ChangeLog b/ChangeLog index 6add548a..5484137e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2010-09-05 Jay Berkenbilt + + * libqpdf/QPDF_Stream.cc (filterable): Handle inline image filter + abbreviations as stream filter abbreviations. Although this is + not technically allowed by the PDF specification, table H.1 in the + pre-ISO spec indicates that Adobe's readers accept them. Thanks + to Jian Ma for bringing this to my + attention. + 2010-08-14 Jay Berkenbilt * 2.2.0: release diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc index 2985118a..68fd62f5 100644 --- a/libqpdf/QPDFWriter.cc +++ b/libqpdf/QPDFWriter.cc @@ -993,7 +993,9 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level, // compressed with a lossy compression scheme, but we // don't support any of those right now. QPDFObjectHandle filter_obj = stream_dict.getKey("/Filter"); - if (filter_obj.isName() && (filter_obj.getName() == "/FlateDecode")) + if (filter_obj.isName() && + ((filter_obj.getName() == "/FlateDecode") || + (filter_obj.getName() == "/Fl"))) { QTC::TC("qpdf", "QPDFWriter not recompressing /FlateDecode"); filter = false; diff --git a/libqpdf/QPDF_Stream.cc b/libqpdf/QPDF_Stream.cc index 72be2e32..db6cfb58 100644 --- a/libqpdf/QPDF_Stream.cc +++ b/libqpdf/QPDF_Stream.cc @@ -18,6 +18,8 @@ #include +std::map QPDF_Stream::filter_abbreviations; + QPDF_Stream::QPDF_Stream(QPDF* qpdf, int objid, int generation, QPDFObjectHandle stream_dict, off_t offset, int length) : @@ -93,6 +95,21 @@ QPDF_Stream::filterable(std::vector& filters, int& predictor, int& columns, bool& early_code_change) { + if (filter_abbreviations.empty()) + { + // The PDF specification provides these filter abbreviations + // for use in inline images, but according to table H.1 in the + // pre-ISO versions of the PDF specification, Adobe Reader + // also accepts them for stream filters. + filter_abbreviations["/AHx"] = "/ASCIIHexDecode"; + filter_abbreviations["/A85"] = "/ASCII85Decode"; + filter_abbreviations["/LZW"] = "/LZWDecode"; + filter_abbreviations["/Fl"] = "/FlateDecode"; + filter_abbreviations["/RL"] = "/RunLengthDecode"; + filter_abbreviations["/CCF"] = "/CCITTFaxDecode"; + filter_abbreviations["/DCT"] = "/DCTDecode"; + } + // Initialize values to their defaults as per the PDF spec predictor = 1; columns = 0; @@ -243,7 +260,14 @@ QPDF_Stream::filterable(std::vector& filters, for (std::vector::iterator iter = filters.begin(); iter != filters.end(); ++iter) { - std::string const& filter = *iter; + std::string& filter = *iter; + + if (filter_abbreviations.count(filter)) + { + QTC::TC("qpdf", "QPDF_Stream expand filter abbreviation"); + filter = filter_abbreviations[filter]; + } + if (! ((filter == "/Crypt") || (filter == "/FlateDecode") || (filter == "/LZWDecode") || diff --git a/libqpdf/qpdf/QPDF_Stream.hh b/libqpdf/qpdf/QPDF_Stream.hh index ed70ae8f..144a9274 100644 --- a/libqpdf/qpdf/QPDF_Stream.hh +++ b/libqpdf/qpdf/QPDF_Stream.hh @@ -38,6 +38,8 @@ class QPDF_Stream: public QPDFObject void setObjGen(int objid, int generation); private: + static std::map filter_abbreviations; + void replaceFilterData(QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length); diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index f4354891..85455a68 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -185,3 +185,4 @@ QPDFObjectHandle prepend page contents 0 QPDFObjectHandle append page contents 0 QPDF_Stream getRawStreamData 0 QPDF_Stream getStreamData 0 +QPDF_Stream expand filter abbreviation 0 diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index 35b2be51..c6040bf8 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -111,7 +111,7 @@ $td->runtest("new stream", show_ntests(); # ---------- $td->notify("--- Miscellaneous Tests ---"); -$n_tests += 23; +$n_tests += 25; $td->runtest("qpdf version", {$td->COMMAND => "qpdf --version"}, @@ -229,6 +229,16 @@ $td->runtest("C check version 2", $td->EXIT_STATUS => 0}, $td->NORMALIZE_NEWLINES); +# Stream filter abbreviations from table H.1 +$td->runtest("stream filter abbreviations", + {$td->COMMAND => "qpdf --static-id filter-abbreviation.pdf a.pdf"}, + {$td->STRING => "", + $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +$td->runtest("check output", + {$td->FILE => "a.pdf"}, + {$td->FILE => "filter-abbreviation.out"}); + show_ntests(); # ---------- $td->notify("--- Error Condition Tests ---"); diff --git a/qpdf/qtest/qpdf/filter-abbreviation.out b/qpdf/qtest/qpdf/filter-abbreviation.out new file mode 100644 index 00000000..aa9bf28e Binary files /dev/null and b/qpdf/qtest/qpdf/filter-abbreviation.out differ diff --git a/qpdf/qtest/qpdf/filter-abbreviation.pdf b/qpdf/qtest/qpdf/filter-abbreviation.pdf new file mode 100644 index 00000000..cdf39ac9 Binary files /dev/null and b/qpdf/qtest/qpdf/filter-abbreviation.pdf differ