diff options
author | Jay Berkenbilt <ejb@ql.org> | 2022-09-07 01:00:40 +0200 |
---|---|---|
committer | Jay Berkenbilt <ejb@ql.org> | 2022-09-07 01:00:40 +0200 |
commit | 76cd7ea67aee7edd1004a68a28e63a00a38239dd (patch) | |
tree | 66d131387939bc7bf88e802a9f11221aba5eda2e /qpdf | |
parent | c1def4ead4c578862ad6fcda35a9ca65be407893 (diff) | |
download | qpdf-76cd7ea67aee7edd1004a68a28e63a00a38239dd.tar.zst |
Clarify and improve QPDFPageObjectHelper::get*Box methods
Add copy_if_fallback and explain how it differs from copy_if_shared.
Diffstat (limited to 'qpdf')
-rw-r--r-- | qpdf/qpdf.testcov | 2 | ||||
-rw-r--r-- | qpdf/qtest/page-api.test | 9 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/boxes2.pdf | 491 | ||||
-rw-r--r-- | qpdf/test_driver.cc | 104 |
4 files changed, 602 insertions, 4 deletions
diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index c3ab0a07..e89f63a0 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -676,3 +676,5 @@ QPDF_json missing json version 0 QPDF_json bad json version 0 QPDF_json bad calledgetallpages 0 QPDF_json bad pushedinheritedpageresources 0 +QPDFPageObjectHelper copied fallback 0 +QPDFPageObjectHelper used fallback without copying 0 diff --git a/qpdf/qtest/page-api.test b/qpdf/qtest/page-api.test index 0bfff47d..c976a6e6 100644 --- a/qpdf/qtest/page-api.test +++ b/qpdf/qtest/page-api.test @@ -14,8 +14,6 @@ cleanup(); my $td = new TestDriver('page-api'); -my $n_tests = 11; - $td->runtest("basic page API", {$td->COMMAND => "test_driver 15 page_api_1.pdf"}, {$td->STRING => "test 15 done\n", $td->EXIT_STATUS => 0}, @@ -58,5 +56,10 @@ $td->runtest("flatten rotation", $td->runtest("check output", {$td->FILE => "a.pdf"}, {$td->FILE => "boxes-flattened.pdf"}); +$td->runtest("get box methods", + {$td->COMMAND => "test_driver 94 boxes2.pdf"}, + {$td->STRING => "test 94 done\n", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); + cleanup(); -$td->report($n_tests); +$td->report(12); diff --git a/qpdf/qtest/qpdf/boxes2.pdf b/qpdf/qtest/qpdf/boxes2.pdf new file mode 100644 index 00000000..71a95670 --- /dev/null +++ b/qpdf/qtest/qpdf/boxes2.pdf @@ -0,0 +1,491 @@ +%PDF-1.3 +%¿÷¢þ +%QDF-1.0 + +1 0 obj +<< + /Pages 2 0 R + /Type /Catalog +>> +endobj + +2 0 obj +<< + /Count 5 + /Kids [ + 3 0 R + 4 0 R + 5 0 R + 6 0 R + 7 0 R + ] + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Type /Pages +>> +endobj + +%% Page 1 +3 0 obj +<< + /Contents 8 0 R + /Parent 2 0 R + /Resources << + /Font << + /F1 10 0 R + >> + /ProcSet 11 0 R + /XObject << + /Fx1 12 0 R + >> + >> + /Type /Page +>> +endobj + +%% Page 2 +4 0 obj +<< + /Contents 14 0 R + /CropBox [ + 10 + 20 + 582 + 752 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 16 0 R + >> + /ProcSet 17 0 R + /XObject << + /Fx1 12 0 R + >> + >> + /Type /Page +>> +endobj + +%% Page 3 +5 0 obj +<< + /Contents 18 0 R + /CropBox [ + 10 + 20 + 582 + 752 + ] + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 20 0 R + >> + /ProcSet 21 0 R + /XObject << + /Fx1 12 0 R + >> + >> + /Type /Page +>> +endobj + +%% Page 4 +6 0 obj +<< + /BleedBox [ + 20 + 40 + 552 + 712 + ] + /Contents 22 0 R + /CropBox 24 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 25 0 R + >> + /ProcSet 26 0 R + /XObject << + /Fx1 12 0 R + >> + >> + /TrimBox [ + 30 + 60 + 522 + 672 + ] + /Type /Page +>> +endobj + +%% Page 5 +7 0 obj +<< + /ArtBox [ + 25 + 50 + 527 + 722 + ] + /Contents 27 0 R + /Parent 2 0 R + /Resources << + /Font << + /F1 29 0 R + >> + /ProcSet 30 0 R + /XObject << + /Fx1 12 0 R + >> + >> + /TrimBox [ + 30 + 60 + 522 + 672 + ] + /Type /Page +>> +endobj + +%% Contents for page 1 +8 0 obj +<< + /Length 9 0 R +>> +stream +q +BT + /F1 12 Tf + 144 470 Td + (Media inherited) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +9 0 obj +121 +endobj + +10 0 obj +<< + /BaseFont /Helvetica + /Encoding /WinAnsiEncoding + /Name /F1 + /Subtype /Type1 + /Type /Font +>> +endobj + +11 0 obj +[ + /PDF + /Text +] +endobj + +12 0 obj +<< + /BBox [ + 0 + 0 + 612 + 792 + ] + /Resources << + /Font << + /F1 10 0 R + >> + /ProcSet 31 0 R + >> + /Subtype /Form + /Type /XObject + /Length 13 0 R +>> +stream +BT + /F1 12 Tf + 144 600 Td + 1 0 0 rg + (red rectangle at media [0 0 612 792]) Tj + 0 -15 Td + 0 1 0 rg + (green at crop [10 20 582 752]) Tj + 0 -15 Td + 0 0 1 rg + (blue at bleed [20 40 552 712]) Tj + 0 -15 Td + 1 .5 0 rg + (orange at trim [30 60 522 672]) Tj + 0 -15 Td + 1 0 1 rg + (purple at art [40 80 452 552]) Tj + 0 -15 Td + 0 0 0 rg + (if crop is present, page is cropped) Tj +ET +5 w +1 0 0 RG +0 0 612 792 re s +0 1 0 RG +10 20 572 732 re s +0 0 1 RG +20 40 532 672 re s +1 .5 0 RG +30 60 492 612 re s +1 0 1 RG +40 80 452 552 re s +endstream +endobj + +13 0 obj +532 +endobj + +%% Contents for page 2 +14 0 obj +<< + /Length 15 0 R +>> +stream +q +BT + /F1 12 Tf + 144 470 Td + (Media inherited, Crop present) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +15 0 obj +135 +endobj + +16 0 obj +<< + /BaseFont /Helvetica + /Encoding /WinAnsiEncoding + /Name /F1 + /Subtype /Type1 + /Type /Font +>> +endobj + +17 0 obj +[ + /PDF + /Text +] +endobj + +%% Contents for page 3 +18 0 obj +<< + /Length 19 0 R +>> +stream +q +BT + /F1 12 Tf + 144 470 Td + (Media, Crop present) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +19 0 obj +125 +endobj + +20 0 obj +<< + /BaseFont /Helvetica + /Encoding /WinAnsiEncoding + /Name /F1 + /Subtype /Type1 + /Type /Font +>> +endobj + +21 0 obj +[ + /PDF + /Text +] +endobj + +%% Contents for page 4 +22 0 obj +<< + /Length 23 0 R +>> +stream +q +BT + /F1 12 Tf + 144 470 Td + (Media, Trim, Bleed present, Crop indirect) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +23 0 obj +147 +endobj + +24 0 obj +[ + 10 + 20 + 582 + 752 +] +endobj + +25 0 obj +<< + /BaseFont /Helvetica + /Encoding /WinAnsiEncoding + /Name /F1 + /Subtype /Type1 + /Type /Font +>> +endobj + +26 0 obj +[ + /PDF + /Text +] +endobj + +%% Contents for page 5 +27 0 obj +<< + /Length 28 0 R +>> +stream +q +BT + /F1 12 Tf + 144 470 Td + (Media inherited, Trim, Art present) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +28 0 obj +140 +endobj + +29 0 obj +<< + /BaseFont /Helvetica + /Encoding /WinAnsiEncoding + /Name /F1 + /Subtype /Type1 + /Type /Font +>> +endobj + +30 0 obj +[ + /PDF + /Text +] +endobj + +31 0 obj +[ + /PDF + /Text +] +endobj + +xref +0 32 +0000000000 65535 f +0000000025 00000 n +0000000079 00000 n +0000000247 00000 n +0000000446 00000 n +0000000693 00000 n +0000000986 00000 n +0000001345 00000 n +0000001651 00000 n +0000001827 00000 n +0000001847 00000 n +0000001966 00000 n +0000002002 00000 n +0000002745 00000 n +0000002789 00000 n +0000002981 00000 n +0000003002 00000 n +0000003121 00000 n +0000003180 00000 n +0000003362 00000 n +0000003383 00000 n +0000003502 00000 n +0000003561 00000 n +0000003765 00000 n +0000003786 00000 n +0000003829 00000 n +0000003948 00000 n +0000004007 00000 n +0000004204 00000 n +0000004225 00000 n +0000004344 00000 n +0000004380 00000 n +trailer << + /Root 1 0 R + /Size 32 + /ID [<42ed290ee4e4c51171853f92a1a7642d><4529bd7e2686f4deaa59ab2fa8e0338d>] +>> +startxref +4416 +%%EOF diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc index 812d6c07..30e7d677 100644 --- a/qpdf/test_driver.cc +++ b/qpdf/test_driver.cc @@ -3302,6 +3302,108 @@ test_93(QPDF& pdf, char const* arg2) assert(trailer.getKey("/Potato") == oh2); } +static void +test_94(QPDF& pdf, char const* arg2) +{ + // Exercise methods to get page boxes. This test is built for + // boxes2.pdf. + + // /MediaBox is present in the pages tree root. + // Each page has the following boxes present directly: + // 1. none + // 2. crop + // 3. media, crop + // 4. media, crop, trim, bleed; crop is indirect + // 5. trim, art + + auto pages_root = pdf.getRoot().getKey("/Pages"); + auto root_media = pages_root.getKey("/MediaBox"); + auto root_media_unparse = root_media.unparse(); + auto pages = QPDFPageDocumentHelper(pdf).getAllPages(); + assert(pages.size() == 5); + auto& p1 = pages[0]; + auto& p2 = pages[1]; + auto& p3 = pages[2]; + auto& p4 = pages[3]; + auto& p5 = pages[4]; + + assert(p1.getObjectHandle().getKey("/MediaBox").isNull()); + // MediaBox not present, so get inherited one + assert(p1.getMediaBox(false) == root_media); + // Other boxesBox not present, so fall back to MediaBox + assert(p1.getCropBox(false, false) == root_media); + assert(p1.getBleedBox(false, false) == root_media); + assert(p1.getTrimBox(false, false) == root_media); + assert(p1.getArtBox(false, false) == root_media); + // Make copy of artbox + auto p1_new_art = p1.getArtBox(false, true); + assert(p1_new_art.unparse() == root_media_unparse); + assert(p1_new_art != root_media); + // This also copied cropbox + auto p1_new_crop = p1.getCropBox(false, false); + assert(p1_new_crop != root_media); + assert(p1_new_crop != p1_new_art); + assert(p1_new_crop.unparse() == root_media_unparse); + // But it didn't copy Media + assert(p1.getMediaBox(false) == root_media); + // Now fall back to new crop + assert(p1.getTrimBox(false, false) == p1_new_crop); + // Request copy. The value returned has the same structure but is + // a different object. + auto p1_effective_media = p1.getMediaBox(true); + assert(p1_effective_media.unparse() == root_media_unparse); + assert(p1_effective_media != root_media); + + // copy_on_fallback didn't have to copy media to crop + assert(p2.getMediaBox(false) == root_media); + auto p2_crop = p2.getCropBox(false, false); + auto p2_new_trim = p2.getTrimBox(false, true); + assert(p2_new_trim.unparse() == p2_crop.unparse()); + assert(p2_new_trim != p2_crop); + assert(p2.getMediaBox(false) == root_media); + + // We didn't need to copy anything + auto p3_media = p3.getMediaBox(false); + auto p3_crop = p3.getCropBox(false, false); + assert(p3.getMediaBox(true) == p3_media); + assert(p3.getCropBox(true, true) == p3_crop); + + // We didn't have to copy for bleed but we did for art + auto p4_orig_crop = p4.getObjectHandle().getKey("/CropBox"); + auto p4_crop = p4.getCropBox(false, false); + assert(p4_orig_crop == p4_crop); + auto p4_bleed1 = p4.getBleedBox(false, false); + auto p4_bleed2 = p4.getBleedBox(false, true); + assert(p4_bleed1 != p4_crop); + assert(p4_bleed1 == p4_bleed2); + auto p4_art1 = p4.getArtBox(false, false); + assert(p4_art1 == p4_crop); + auto p4_art2 = p4.getArtBox(false, true); + assert(p4_art2 != p4_crop); + auto p4_new_crop = p4.getCropBox(true, false); + assert(p4_new_crop != p4_orig_crop); + assert(p4_orig_crop.isIndirect()); + assert(!p4_new_crop.isIndirect()); + assert(p4_new_crop.unparse() == p4_orig_crop.unparseResolved()); + + // Exercise copying for inheritence and fallback + assert(p5.getMediaBox(false) == root_media); + assert(p5.getCropBox(false, false) == root_media); + assert(p5.getBleedBox(false, false) == root_media); + auto p5_new_bleed = p5.getBleedBox(true, true); + auto p5_new_media = p5.getMediaBox(false); + auto p5_new_crop = p5.getCropBox(false, false); + assert(p5_new_media != root_media); + assert(p5_new_crop != root_media); + assert(p5_new_crop != p5_new_media); + assert(p5_new_bleed != root_media); + assert(p5_new_bleed != p5_new_media); + assert(p5_new_bleed != p5_new_crop); + assert(p5_new_media.unparse() == root_media_unparse); + assert(p5_new_crop.unparse() == root_media_unparse); + assert(p5_new_bleed.unparse() == root_media_unparse); +} + void runtest(int n, char const* filename1, char const* arg2) { @@ -3411,7 +3513,7 @@ runtest(int n, char const* filename1, char const* arg2) {80, test_80}, {81, test_81}, {82, test_82}, {83, test_83}, {84, test_84}, {85, test_85}, {86, test_86}, {87, test_87}, {88, test_88}, {89, test_89}, {90, test_90}, {91, test_91}, - {92, test_92}, {93, test_93}}; + {92, test_92}, {93, test_93}, {94, test_94}}; auto fn = test_functions.find(n); if (fn == test_functions.end()) { |