aboutsummaryrefslogtreecommitdiffstats
path: root/qpdf
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2022-09-07 01:00:40 +0200
committerJay Berkenbilt <ejb@ql.org>2022-09-07 01:00:40 +0200
commit76cd7ea67aee7edd1004a68a28e63a00a38239dd (patch)
tree66d131387939bc7bf88e802a9f11221aba5eda2e /qpdf
parentc1def4ead4c578862ad6fcda35a9ca65be407893 (diff)
downloadqpdf-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.testcov2
-rw-r--r--qpdf/qtest/page-api.test9
-rw-r--r--qpdf/qtest/qpdf/boxes2.pdf491
-rw-r--r--qpdf/test_driver.cc104
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()) {