Commit 0a470d2daf8ec8a1ba0abfea053af4b4d0955ff6
1 parent
eb49e07c
Don't optimize non-8-bit images
Also add test cases for additional coverage on image optimization.
Showing
9 changed files
with
80 additions
and
5 deletions
ChangeLog
| 1 | 2019-01-31 Jay Berkenbilt <ejb@ql.org> | 1 | 2019-01-31 Jay Berkenbilt <ejb@ql.org> |
| 2 | 2 | ||
| 3 | + * Bug fix: do better pre-checks on images before optimizing; | ||
| 4 | + refuse to optimize images that can't be converted to JPEG because | ||
| 5 | + of colorspace or depth. | ||
| 6 | + | ||
| 3 | * Add new options --externalize-inline-images, which converts | 7 | * Add new options --externalize-inline-images, which converts |
| 4 | inline images larger than a specified size to regular images, and | 8 | inline images larger than a specified size to regular images, and |
| 5 | --ii-min-bytes, which tweaks that size. | 9 | --ii-min-bytes, which tweaks that size. |
TODO
manual/qpdf-manual.xml
| @@ -4456,6 +4456,13 @@ print "\n"; | @@ -4456,6 +4456,13 @@ print "\n"; | ||
| 4456 | </listitem> | 4456 | </listitem> |
| 4457 | <listitem> | 4457 | <listitem> |
| 4458 | <para> | 4458 | <para> |
| 4459 | + When optimizing images, detect and refuse to optimize | ||
| 4460 | + images that can't be converted to JPEG because of bit depth | ||
| 4461 | + or color space. | ||
| 4462 | + </para> | ||
| 4463 | + </listitem> | ||
| 4464 | + <listitem> | ||
| 4465 | + <para> | ||
| 4459 | Linearization and page manipulation APIs now detect and | 4466 | Linearization and page manipulation APIs now detect and |
| 4460 | recover from files that have duplicate Page objects in the | 4467 | recover from files that have duplicate Page objects in the |
| 4461 | pages tree. | 4468 | pages tree. |
qpdf/qpdf.cc
| @@ -3816,6 +3816,18 @@ ImageOptimizer::makePipeline(std::string const& description, Pipeline* next) | @@ -3816,6 +3816,18 @@ ImageOptimizer::makePipeline(std::string const& description, Pipeline* next) | ||
| 3816 | } | 3816 | } |
| 3817 | return result; | 3817 | return result; |
| 3818 | } | 3818 | } |
| 3819 | + QPDFObjectHandle components_obj = dict.getKey("/BitsPerComponent"); | ||
| 3820 | + if (! (components_obj.isInteger() && (components_obj.getIntValue() == 8))) | ||
| 3821 | + { | ||
| 3822 | + QTC::TC("qpdf", "qpdf image optimize bits per component"); | ||
| 3823 | + if (o.verbose && (! description.empty())) | ||
| 3824 | + { | ||
| 3825 | + std::cout << whoami << ": " << description | ||
| 3826 | + << ": not optimizing because image has other than" | ||
| 3827 | + << " 8 bits per component" << std::endl; | ||
| 3828 | + } | ||
| 3829 | + return result; | ||
| 3830 | + } | ||
| 3819 | // Files have been seen in the wild whose width and height are | 3831 | // Files have been seen in the wild whose width and height are |
| 3820 | // floating point, which is goofy, but we can deal with it. | 3832 | // floating point, which is goofy, but we can deal with it. |
| 3821 | JDIMENSION w = static_cast<JDIMENSION>( | 3833 | JDIMENSION w = static_cast<JDIMENSION>( |
| @@ -3844,6 +3856,7 @@ ImageOptimizer::makePipeline(std::string const& description, Pipeline* next) | @@ -3844,6 +3856,7 @@ ImageOptimizer::makePipeline(std::string const& description, Pipeline* next) | ||
| 3844 | } | 3856 | } |
| 3845 | else | 3857 | else |
| 3846 | { | 3858 | { |
| 3859 | + QTC::TC("qpdf", "qpdf image optimize colorspace"); | ||
| 3847 | if (o.verbose && (! description.empty())) | 3860 | if (o.verbose && (! description.empty())) |
| 3848 | { | 3861 | { |
| 3849 | std::cout << whoami << ": " << description | 3862 | std::cout << whoami << ": " << description |
qpdf/qpdf.testcov
| @@ -437,3 +437,5 @@ QPDFTokenizer inline image at EOF the old way 0 | @@ -437,3 +437,5 @@ QPDFTokenizer inline image at EOF the old way 0 | ||
| 437 | QPDFTokenizer found EI after more than one try 0 | 437 | QPDFTokenizer found EI after more than one try 0 |
| 438 | QPDFPageObjectHelper externalize inline image 0 | 438 | QPDFPageObjectHelper externalize inline image 0 |
| 439 | QPDFPageObjectHelper keep inline image 0 | 439 | QPDFPageObjectHelper keep inline image 0 |
| 440 | +qpdf image optimize colorspace 0 | ||
| 441 | +qpdf image optimize bits per component 0 |
qpdf/qtest/qpdf.test
| @@ -2088,6 +2088,8 @@ my @image_opt = ( | @@ -2088,6 +2088,8 @@ my @image_opt = ( | ||
| 2088 | '--oi-min-width=0 --oi-min-height=0 --oi-min-area=0 --ii-min-bytes=0'], | 2088 | '--oi-min-width=0 --oi-min-height=0 --oi-min-area=0 --ii-min-bytes=0'], |
| 2089 | ['large-inline-image', 'inline-images-keep-some', ''], | 2089 | ['large-inline-image', 'inline-images-keep-some', ''], |
| 2090 | ['large-inline-image', 'inline-images-keep-all', '--keep-inline-images'], | 2090 | ['large-inline-image', 'inline-images-keep-all', '--keep-inline-images'], |
| 2091 | + ['unsupported-optimization', 'unsupported', | ||
| 2092 | + '--oi-min-width=0 --oi-min-height=0 --oi-min-area=0'], | ||
| 2091 | ); | 2093 | ); |
| 2092 | 2094 | ||
| 2093 | $n_tests += 2 * scalar(@image_opt); | 2095 | $n_tests += 2 * scalar(@image_opt); |
qpdf/qtest/qpdf/optimize-images-unsupported-json.out
0 โ 100644
| 1 | +{ | ||
| 2 | + "pages": [ | ||
| 3 | + { | ||
| 4 | + "contents": [ | ||
| 5 | + "4 0 R" | ||
| 6 | + ], | ||
| 7 | + "images": [ | ||
| 8 | + { | ||
| 9 | + "bitspercomponent": 1, | ||
| 10 | + "colorspace": "/DeviceGray", | ||
| 11 | + "decodeparms": [ | ||
| 12 | + null | ||
| 13 | + ], | ||
| 14 | + "filter": [ | ||
| 15 | + "/FlateDecode" | ||
| 16 | + ], | ||
| 17 | + "filterable": true, | ||
| 18 | + "height": 200, | ||
| 19 | + "name": "/Im1", | ||
| 20 | + "object": "6 0 R", | ||
| 21 | + "width": 100 | ||
| 22 | + }, | ||
| 23 | + { | ||
| 24 | + "bitspercomponent": 8, | ||
| 25 | + "colorspace": "/XeviceGray", | ||
| 26 | + "decodeparms": [ | ||
| 27 | + null | ||
| 28 | + ], | ||
| 29 | + "filter": [ | ||
| 30 | + "/FlateDecode" | ||
| 31 | + ], | ||
| 32 | + "filterable": true, | ||
| 33 | + "height": 200, | ||
| 34 | + "name": "/Im2", | ||
| 35 | + "object": "7 0 R", | ||
| 36 | + "width": 200 | ||
| 37 | + } | ||
| 38 | + ], | ||
| 39 | + "label": null, | ||
| 40 | + "object": "3 0 R", | ||
| 41 | + "outlines": [], | ||
| 42 | + "pageposfrom1": 1 | ||
| 43 | + } | ||
| 44 | + ], | ||
| 45 | + "parameters": { | ||
| 46 | + "decodelevel": "generalized" | ||
| 47 | + }, | ||
| 48 | + "version": 1 | ||
| 49 | +} |
qpdf/qtest/qpdf/optimize-images-unsupported.out
0 โ 100644
qpdf/qtest/qpdf/unsupported-optimization.pdf
0 โ 100644
No preview for this file type