Commit fe36ef141c7d77548175666eb952cd185f2d9fa6

Authored by Jay Berkenbilt
Committed by GitHub
2 parents 1e53da74 f6b13fcc

Merge pull request #924 from cdosborn/main

Improve --optimize-images to find images nested within XObjects
libqpdf/QPDFJob.cc
@@ -2363,31 +2363,30 @@ QPDFJob::handleTransformations(QPDF& pdf) @@ -2363,31 +2363,30 @@ QPDFJob::handleTransformations(QPDF& pdf)
2363 int pageno = 0; 2363 int pageno = 0;
2364 for (auto& ph: dh.getAllPages()) { 2364 for (auto& ph: dh.getAllPages()) {
2365 ++pageno; 2365 ++pageno;
2366 - QPDFObjectHandle page = ph.getObjectHandle();  
2367 - for (auto& iter2: ph.getImages()) {  
2368 - std::string name = iter2.first;  
2369 - QPDFObjectHandle& image = iter2.second;  
2370 - ImageOptimizer* io = new ImageOptimizer(  
2371 - *this,  
2372 - m->oi_min_width,  
2373 - m->oi_min_height,  
2374 - m->oi_min_area,  
2375 - image);  
2376 - std::shared_ptr<QPDFObjectHandle::StreamDataProvider> sdp(io);  
2377 - if (io->evaluate(  
2378 - "image " + name + " on page " +  
2379 - std::to_string(pageno))) {  
2380 - QPDFObjectHandle new_image = pdf.newStream();  
2381 - new_image.replaceDict(image.getDict().shallowCopy());  
2382 - new_image.replaceStreamData(  
2383 - sdp,  
2384 - QPDFObjectHandle::newName("/DCTDecode"),  
2385 - QPDFObjectHandle::newNull());  
2386 - ph.getAttribute("/Resources", true)  
2387 - .getKey("/XObject")  
2388 - .replaceKey(name, new_image);  
2389 - }  
2390 - } 2366 + ph.forEachImage(
  2367 + true,
  2368 + [this, pageno, &pdf](
  2369 + QPDFObjectHandle& obj,
  2370 + QPDFObjectHandle& xobj_dict,
  2371 + std::string const& key) {
  2372 + auto io = std::make_unique<ImageOptimizer>(
  2373 + *this,
  2374 + m->oi_min_width,
  2375 + m->oi_min_height,
  2376 + m->oi_min_area,
  2377 + obj);
  2378 + if (io->evaluate(
  2379 + "image " + key + " on page " +
  2380 + std::to_string(pageno))) {
  2381 + QPDFObjectHandle new_image = pdf.newStream();
  2382 + new_image.replaceDict(obj.getDict().shallowCopy());
  2383 + new_image.replaceStreamData(
  2384 + std::move(io),
  2385 + QPDFObjectHandle::newName("/DCTDecode"),
  2386 + QPDFObjectHandle::newNull());
  2387 + xobj_dict.replaceKey(key, new_image);
  2388 + }
  2389 + });
2391 } 2390 }
2392 } 2391 }
2393 if (m->generate_appearances) { 2392 if (m->generate_appearances) {
qpdf/qtest/image-optimization.test
@@ -33,6 +33,8 @@ my @image_opt = ( @@ -33,6 +33,8 @@ my @image_opt = (
33 ['large-inline-image', 'inline-images-keep-all', '--keep-inline-images'], 33 ['large-inline-image', 'inline-images-keep-all', '--keep-inline-images'],
34 ['unsupported-optimization', 'unsupported', 34 ['unsupported-optimization', 'unsupported',
35 '--oi-min-width=0 --oi-min-height=0 --oi-min-area=0'], 35 '--oi-min-width=0 --oi-min-height=0 --oi-min-area=0'],
  36 + ['nested-images', 'nested-images',
  37 + '--oi-min-width=0 --oi-min-height=0 --oi-min-area=0']
36 ); 38 );
37 39
38 my $n_tests = 2 * scalar(@image_opt); 40 my $n_tests = 2 * scalar(@image_opt);
qpdf/qtest/qpdf/nested-images.pdf 0 โ†’ 100644
No preview for this file type
qpdf/qtest/qpdf/optimize-images-nested-images-json.out 0 โ†’ 100644
  1 +{
  2 + "version": 2,
  3 + "parameters": {
  4 + "decodelevel": "generalized"
  5 + },
  6 + "pages": [
  7 + {
  8 + "contents": [
  9 + "4 0 R"
  10 + ],
  11 + "images": [],
  12 + "label": null,
  13 + "object": "3 0 R",
  14 + "outlines": [],
  15 + "pageposfrom1": 1
  16 + }
  17 + ]
  18 +}
qpdf/qtest/qpdf/optimize-images-nested-images.out 0 โ†’ 100644
  1 +qpdf: image /X1 on page 1: optimizing image reduces size from 2628 to ...
  2 +qpdf: wrote file a.pdf