diff --git a/ChangeLog b/ChangeLog index 6fc963f3..9703de5f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2020-12-30 Jay Berkenbilt + + * Add QPDFPageObjectHelper::flattenRotation and --flatten-rotation + option to the qpdf CLI. The flattenRotation method removes any + /Rotate key from a page dictionary and implements the same + rotation by modifying the page's contents such that the various + page boxes are altered and the page renders identically. This can + be used to work around buggy PDF applications that don't properly + handle page rotation. The --flatten-rotation option to the qpdf + CLI calls flattenRotation for every page. + 2020-12-26 Jay Berkenbilt * Add QPDFObjectHandle::setFilterOnWrite, which can be used to diff --git a/TODO b/TODO index 444535f3..a07c93d3 100644 --- a/TODO +++ b/TODO @@ -39,10 +39,6 @@ Candidates for upcoming release * big page even with --remove-unreferenced-resources=yes, even with --empty * optimize image failure because of colorspace -* Take flattenRotation code from pdf-split and do something with it, - maybe adding it to the library. Once there, call it from pdf-split - and bump up the required version of qpdf. - * Externalize inline images doesn't walk into form XObjects. In general: diff --git a/include/qpdf/QPDFPageObjectHelper.hh b/include/qpdf/QPDFPageObjectHelper.hh index a197ece7..42d67088 100644 --- a/include/qpdf/QPDFPageObjectHelper.hh +++ b/include/qpdf/QPDFPageObjectHelper.hh @@ -242,6 +242,16 @@ class QPDFPageObjectHelper: public QPDFObjectHelper bool allow_shrink = true, bool allow_expand = false); + // If a page is rotated using /Rotate in the page's dictionary, + // instead rotate the page by the same amount by altering the + // contents and removing the /Rotate key. This method adjusts the + // various page bounding boxes (/MediaBox, etc.) so that the page + // will have the same semantics. This can be useful to work around + // problems with PDF applications that can't properly handle + // rotated pages. + QPDF_DLL + void flattenRotation(); + private: static void removeUnreferencedResourcesHelper( diff --git a/libqpdf/QPDFPageObjectHelper.cc b/libqpdf/QPDFPageObjectHelper.cc index b7da816e..58747814 100644 --- a/libqpdf/QPDFPageObjectHelper.cc +++ b/libqpdf/QPDFPageObjectHelper.cc @@ -835,3 +835,135 @@ QPDFPageObjectHelper::placeFormXObject( name + " Do\n" + "Q\n"); } + +void +QPDFPageObjectHelper::flattenRotation() +{ + QPDF* qpdf = this->oh.getOwningQPDF(); + if (! qpdf) + { + throw std::runtime_error( + "QPDFPageObjectHelper::flattenRotation" + " called with a direct object"); + } + + auto rotate_oh = this->oh.getKey("/Rotate"); + int rotate = 0; + if (rotate_oh.isInteger()) + { + rotate = rotate_oh.getIntValueAsInt(); + } + if (! ((rotate == 90) || (rotate == 180) || (rotate == 270))) + { + return; + } + auto mediabox = this->oh.getKey("/MediaBox"); + if (! mediabox.isRectangle()) + { + return; + } + auto media_rect = mediabox.getArrayAsRectangle(); + + std::vector boxes = { + "/MediaBox", "/CropBox", "/BleedBox", "/TrimBox", "/ArtBox", + }; + for (auto const& boxkey: boxes) + { + auto box = this->oh.getKey(boxkey); + if (! box.isRectangle()) + { + continue; + } + auto rect = box.getArrayAsRectangle(); + decltype(rect) new_rect; + + // How far are the edges of our rectangle from the edges + // of the media box? + auto left_x = rect.llx - media_rect.llx; + auto right_x = media_rect.urx - rect.urx; + auto bottom_y = rect.lly - media_rect.lly; + auto top_y = media_rect.ury - rect.ury; + + // Rotating the page 180 degrees does not change + // /MediaBox. Rotating 90 or 270 degrees reverses llx and + // lly and also reverse urx and ury. For all the other + // boxes, we want the corners to be the correct distance + // away from the corners of the mediabox. + switch (rotate) + { + case 90: + new_rect.llx = media_rect.lly + bottom_y; + new_rect.urx = media_rect.ury - top_y; + new_rect.lly = media_rect.llx + right_x; + new_rect.ury = media_rect.urx - left_x; + break; + + case 180: + new_rect.llx = media_rect.llx + right_x; + new_rect.urx = media_rect.urx - left_x; + new_rect.lly = media_rect.lly + top_y; + new_rect.ury = media_rect.ury - bottom_y; + break; + + case 270: + new_rect.llx = media_rect.lly + top_y; + new_rect.urx = media_rect.ury - bottom_y; + new_rect.lly = media_rect.llx + left_x; + new_rect.ury = media_rect.urx - right_x; + break; + + default: + // ignore + break; + } + + this->oh.replaceKey( + boxkey, QPDFObjectHandle::newFromRectangle(new_rect)); + } + + // When we rotate the page, pivot about the point 0, 0 and then + // translate so the page is visible with the origin point being + // the same offset from the lower left corner of the media box. + // These calculations have been verified emperically with various + // PDF readers. + QPDFObjectHandle::Matrix cm; + cm.e = 0.0; + cm.f = 0.0; + switch (rotate) + { + case 90: + cm.b = -1; + cm.c = 1; + cm.f = media_rect.urx + media_rect.llx; + break; + + case 180: + cm.a = -1; + cm.d = -1; + cm.e = media_rect.urx + media_rect.llx; + cm.f = media_rect.ury + media_rect.lly; + break; + + case 270: + cm.b = 1; + cm.c = -1; + cm.e = media_rect.ury + media_rect.lly; + break; + + default: + break; + } + std::string cm_str = + std::string("q\n") + + QUtil::double_to_string(cm.a, 2) + " " + + QUtil::double_to_string(cm.b, 2) + " " + + QUtil::double_to_string(cm.c, 2) + " " + + QUtil::double_to_string(cm.d, 2) + " " + + QUtil::double_to_string(cm.e, 2) + " " + + QUtil::double_to_string(cm.f, 2) + " cm\n"; + this->oh.addPageContents( + QPDFObjectHandle::newStream(qpdf, cm_str), true); + this->oh.addPageContents( + QPDFObjectHandle::newStream(qpdf, "\nQ\n"), false); + this->oh.removeKey("/Rotate"); +} diff --git a/manual/qpdf-manual.xml b/manual/qpdf-manual.xml index 10a165d3..8caab104 100644 --- a/manual/qpdf-manual.xml +++ b/manual/qpdf-manual.xml @@ -1062,6 +1062,19 @@ make + + + + + For each page that is rotated using the + /Rotate key in the page's dictionary, + remove the /Rotate key and implement the + identical rotation semantics by modifying the page's contents. + This option can be useful to prepare files for buggy PDF + applications that don't properly handle rotated pages. + + + diff --git a/qpdf/qpdf.cc b/qpdf/qpdf.cc index 83670596..19d7b0c4 100644 --- a/qpdf/qpdf.cc +++ b/qpdf/qpdf.cc @@ -174,6 +174,7 @@ struct Options show_pages(false), show_page_images(false), collate(false), + flatten_rotation(false), json(false), check(false), optimize_images(false), @@ -276,6 +277,7 @@ struct Options bool show_pages; bool show_page_images; bool collate; + bool flatten_rotation; bool json; std::set json_keys; std::set json_objects; @@ -747,6 +749,7 @@ class ArgParser void argOverlay(); void argRotate(char* parameter); void argCollate(); + void argFlattenRotation(); void argStreamData(char* parameter); void argCompressStreams(char* parameter); void argRecompressFlate(); @@ -968,6 +971,7 @@ ArgParser::initOptionTable() char const* stream_data_choices[] = {"compress", "preserve", "uncompress", 0}; (*t)["collate"] = oe_bare(&ArgParser::argCollate); + (*t)["flatten-rotation"] = oe_bare(&ArgParser::argFlattenRotation); (*t)["stream-data"] = oe_requiredChoices( &ArgParser::argStreamData, stream_data_choices); (*t)["compress-streams"] = oe_requiredChoices( @@ -1250,6 +1254,7 @@ ArgParser::argHelp() << "--pages options -- select specific pages from one or more files\n" << "--collate causes files specified in --pages to be collated\n" << " rather than concatenated\n" + << "--flatten-rotation move page rotation from /Rotate key to content\n" << "--rotate=[+|-]angle[:page-range]\n" << " rotate each specified page 90, 180, or 270 degrees;\n" << " rotate all pages if no page range is given\n" @@ -1879,6 +1884,12 @@ ArgParser::argRotate(char* parameter) parseRotationParameter(parameter); } +void +ArgParser::argFlattenRotation() +{ + o.flatten_rotation = true; +} + void ArgParser::argStreamData(char* parameter) { @@ -4818,6 +4829,13 @@ static void handle_transformations(QPDF& pdf, Options& o) (*iter).coalesceContentStreams(); } } + if (o.flatten_rotation) + { + for (auto& page: dh.getAllPages()) + { + page.flattenRotation(); + } + } if (o.remove_page_labels) { pdf.getRoot().removeKey("/PageLabels"); diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index b166db84..1fdc5f09 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -671,7 +671,7 @@ foreach my $d (@json_files) show_ntests(); # ---------- $td->notify("--- Page API Tests ---"); -$n_tests += 9; +$n_tests += 11; $td->runtest("basic page API", {$td->COMMAND => "test_driver 15 page_api_1.pdf"}, @@ -706,6 +706,15 @@ $td->runtest("remove page we don't have", {$td->COMMAND => "test_driver 22 page_api_1.pdf"}, {$td->FILE => "page_api_1.out2", $td->EXIT_STATUS => 2}, $td->NORMALIZE_NEWLINES); +$td->runtest("flatten rotation", + {$td->COMMAND => "qpdf --static-id --qdf". + " --no-original-object-ids" . + " --flatten-rotation boxes.pdf a.pdf"}, + {$td->STRING => "", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +$td->runtest("check output", + {$td->FILE => "a.pdf"}, + {$td->FILE => "boxes-flattened.pdf"}); show_ntests(); # ---------- $td->notify("--- Files for specific bugs ---"); diff --git a/qpdf/qtest/qpdf/boxes-flattened.pdf b/qpdf/qtest/qpdf/boxes-flattened.pdf new file mode 100644 index 00000000..97effcef --- /dev/null +++ b/qpdf/qtest/qpdf/boxes-flattened.pdf @@ -0,0 +1,907 @@ +%PDF-1.3 +%¿÷¢þ +%QDF-1.0 + +1 0 obj +<< + /Pages 2 0 R + /Type /Catalog +>> +endobj + +2 0 obj +<< + /Count 8 + /Kids [ + 3 0 R + 4 0 R + 5 0 R + 6 0 R + 7 0 R + 8 0 R + 9 0 R + 10 0 R + ] + /Type /Pages +>> +endobj + +%% Page 1 +3 0 obj +<< + /BleedBox [ + 20 + 40 + 552 + 712 + ] + /Contents 11 0 R + /CropBox [ + 10 + 20 + 582 + 752 + ] + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 14 0 R + /XObject << + /Fx1 15 0 R + >> + >> + /TrimBox [ + 30 + 60 + 522 + 672 + ] + /Type /Page +>> +endobj + +%% Page 2 +4 0 obj +<< + /BleedBox [ + 40.000000 + 60.000000 + 712.000000 + 592.000000 + ] + /Contents [ + 17 0 R + 19 0 R + 21 0 R + ] + /CropBox [ + 20.000000 + 30.000000 + 752.000000 + 602.000000 + ] + /MediaBox [ + 0.000000 + 0.000000 + 792.000000 + 612.000000 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 14 0 R + /XObject << + /Fx1 15 0 R + >> + >> + /TrimBox [ + 60.000000 + 90.000000 + 672.000000 + 582.000000 + ] + /Type /Page +>> +endobj + +%% Page 3 +5 0 obj +<< + /BleedBox [ + 60.000000 + 80.000000 + 592.000000 + 752.000000 + ] + /Contents [ + 23 0 R + 25 0 R + 27 0 R + ] + /CropBox [ + 30.000000 + 40.000000 + 602.000000 + 772.000000 + ] + /MediaBox [ + 0.000000 + 0.000000 + 612.000000 + 792.000000 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 14 0 R + /XObject << + /Fx1 15 0 R + >> + >> + /TrimBox [ + 90.000000 + 120.000000 + 582.000000 + 732.000000 + ] + /Type /Page +>> +endobj + +%% Page 4 +6 0 obj +<< + /BleedBox [ + 80.000000 + 20.000000 + 752.000000 + 552.000000 + ] + /Contents [ + 29 0 R + 31 0 R + 33 0 R + ] + /CropBox [ + 40.000000 + 10.000000 + 772.000000 + 582.000000 + ] + /MediaBox [ + 0.000000 + 0.000000 + 792.000000 + 612.000000 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 14 0 R + /XObject << + /Fx1 15 0 R + >> + >> + /TrimBox [ + 120.000000 + 30.000000 + 732.000000 + 522.000000 + ] + /Type /Page +>> +endobj + +%% Page 5 +7 0 obj +<< + /BleedBox [ + 20 + 40 + 552 + 712 + ] + /Contents 35 0 R + /CropBox [ + 10 + 20 + 582 + 752 + ] + /MediaBox [ + -10 + -20 + 642 + 832 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 14 0 R + /XObject << + /Fx1 15 0 R + >> + >> + /TrimBox [ + 30 + 60 + 522 + 672 + ] + /Type /Page +>> +endobj + +%% Page 6 +8 0 obj +<< + /BleedBox [ + 40.000000 + 80.000000 + 712.000000 + 612.000000 + ] + /Contents [ + 37 0 R + 39 0 R + 41 0 R + ] + /CropBox [ + 20.000000 + 50.000000 + 752.000000 + 622.000000 + ] + /MediaBox [ + -20.000000 + -10.000000 + 832.000000 + 642.000000 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 14 0 R + /XObject << + /Fx1 15 0 R + >> + >> + /TrimBox [ + 60.000000 + 110.000000 + 672.000000 + 602.000000 + ] + /Type /Page +>> +endobj + +%% Page 7 +9 0 obj +<< + /BleedBox [ + 80.000000 + 100.000000 + 612.000000 + 772.000000 + ] + /Contents [ + 43 0 R + 45 0 R + 47 0 R + ] + /CropBox [ + 50.000000 + 60.000000 + 622.000000 + 792.000000 + ] + /MediaBox [ + -10.000000 + -20.000000 + 642.000000 + 832.000000 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 14 0 R + /XObject << + /Fx1 15 0 R + >> + >> + /TrimBox [ + 110.000000 + 140.000000 + 602.000000 + 752.000000 + ] + /Type /Page +>> +endobj + +%% Page 8 +10 0 obj +<< + /BleedBox [ + 100.000000 + 20.000000 + 772.000000 + 552.000000 + ] + /Contents [ + 49 0 R + 51 0 R + 53 0 R + ] + /CropBox [ + 60.000000 + 10.000000 + 792.000000 + 582.000000 + ] + /MediaBox [ + -20.000000 + -10.000000 + 832.000000 + 642.000000 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 14 0 R + /XObject << + /Fx1 15 0 R + >> + >> + /TrimBox [ + 140.000000 + 30.000000 + 752.000000 + 522.000000 + ] + /Type /Page +>> +endobj + +%% Contents for page 1 +11 0 obj +<< + /Length 12 0 R +>> +stream +q +BT + /F1 12 Tf + 144 500 Td + (Rotate: 0) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +12 0 obj +115 +endobj + +13 0 obj +<< + /BaseFont /Helvetica + /Encoding /WinAnsiEncoding + /Name /F1 + /Subtype /Type1 + /Type /Font +>> +endobj + +14 0 obj +[ + /PDF + /Text +] +endobj + +15 0 obj +<< + /BBox [ + 0 + 0 + 612 + 792 + ] + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 55 0 R + >> + /Subtype /Form + /Type /XObject + /Length 16 0 R +>> +stream +BT + /F1 12 Tf + 144 620 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 + 0 0 0 rg + (page is cropped at crop) Tj + 0 -15 Td + 0 0 0 rg + (red media rectangle is not visible) 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 +0 0 0 rg +1 .5 0 RG +30 60 492 612 re s +endstream +endobj + +16 0 obj +506 +endobj + +%% Contents for page 2 +17 0 obj +<< + /Length 18 0 R +>> +stream +q +0.00 -1.00 1.00 0.00 0.00 612.00 cm +endstream +endobj + +18 0 obj +38 +endobj + +%% Contents for page 2 +19 0 obj +<< + /Length 20 0 R +>> +stream +q +BT + /F1 12 Tf + 144 500 Td + (Rotate: 90) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +20 0 obj +116 +endobj + +%% Contents for page 2 +21 0 obj +<< + /Length 22 0 R +>> +stream + +Q +endstream +endobj + +22 0 obj +3 +endobj + +%% Contents for page 3 +23 0 obj +<< + /Length 24 0 R +>> +stream +q +-1.00 0.00 0.00 -1.00 612.00 792.00 cm +endstream +endobj + +24 0 obj +41 +endobj + +%% Contents for page 3 +25 0 obj +<< + /Length 26 0 R +>> +stream +q +BT + /F1 12 Tf + 144 500 Td + (Rotate: 180) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +26 0 obj +117 +endobj + +%% Contents for page 3 +27 0 obj +<< + /Length 28 0 R +>> +stream + +Q +endstream +endobj + +28 0 obj +3 +endobj + +%% Contents for page 4 +29 0 obj +<< + /Length 30 0 R +>> +stream +q +0.00 1.00 -1.00 0.00 792.00 0.00 cm +endstream +endobj + +30 0 obj +38 +endobj + +%% Contents for page 4 +31 0 obj +<< + /Length 32 0 R +>> +stream +q +BT + /F1 12 Tf + 144 500 Td + (Rotate: 270) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +32 0 obj +117 +endobj + +%% Contents for page 4 +33 0 obj +<< + /Length 34 0 R +>> +stream + +Q +endstream +endobj + +34 0 obj +3 +endobj + +%% Contents for page 5 +35 0 obj +<< + /Length 36 0 R +>> +stream +q +BT + /F1 12 Tf + 144 500 Td + (Rotate: 0, extended MediaBox) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +36 0 obj +134 +endobj + +%% Contents for page 6 +37 0 obj +<< + /Length 38 0 R +>> +stream +q +0.00 -1.00 1.00 0.00 0.00 632.00 cm +endstream +endobj + +38 0 obj +38 +endobj + +%% Contents for page 6 +39 0 obj +<< + /Length 40 0 R +>> +stream +q +BT + /F1 12 Tf + 144 500 Td + (Rotate: 90, extended MediaBox) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +40 0 obj +135 +endobj + +%% Contents for page 6 +41 0 obj +<< + /Length 42 0 R +>> +stream + +Q +endstream +endobj + +42 0 obj +3 +endobj + +%% Contents for page 7 +43 0 obj +<< + /Length 44 0 R +>> +stream +q +-1.00 0.00 0.00 -1.00 632.00 812.00 cm +endstream +endobj + +44 0 obj +41 +endobj + +%% Contents for page 7 +45 0 obj +<< + /Length 46 0 R +>> +stream +q +BT + /F1 12 Tf + 144 500 Td + (Rotate: 180, extended MediaBox) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +46 0 obj +136 +endobj + +%% Contents for page 7 +47 0 obj +<< + /Length 48 0 R +>> +stream + +Q +endstream +endobj + +48 0 obj +3 +endobj + +%% Contents for page 8 +49 0 obj +<< + /Length 50 0 R +>> +stream +q +0.00 1.00 -1.00 0.00 812.00 0.00 cm +endstream +endobj + +50 0 obj +38 +endobj + +%% Contents for page 8 +51 0 obj +<< + /Length 52 0 R +>> +stream +q +BT + /F1 12 Tf + 144 500 Td + (Rotate: 270, extended MediaBox) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +52 0 obj +136 +endobj + +%% Contents for page 8 +53 0 obj +<< + /Length 54 0 R +>> +stream + +Q +endstream +endobj + +54 0 obj +3 +endobj + +55 0 obj +[ + /PDF + /Text +] +endobj + +xref +0 56 +0000000000 65535 f +0000000025 00000 n +0000000079 00000 n +0000000232 00000 n +0000000620 00000 n +0000001152 00000 n +0000001685 00000 n +0000002218 00000 n +0000002610 00000 n +0000003147 00000 n +0000003686 00000 n +0000004238 00000 n +0000004410 00000 n +0000004431 00000 n +0000004550 00000 n +0000004586 00000 n +0000005303 00000 n +0000005347 00000 n +0000005442 00000 n +0000005485 00000 n +0000005658 00000 n +0000005702 00000 n +0000005762 00000 n +0000005804 00000 n +0000005902 00000 n +0000005945 00000 n +0000006119 00000 n +0000006163 00000 n +0000006223 00000 n +0000006265 00000 n +0000006360 00000 n +0000006403 00000 n +0000006577 00000 n +0000006621 00000 n +0000006681 00000 n +0000006723 00000 n +0000006914 00000 n +0000006958 00000 n +0000007053 00000 n +0000007096 00000 n +0000007288 00000 n +0000007332 00000 n +0000007392 00000 n +0000007434 00000 n +0000007532 00000 n +0000007575 00000 n +0000007768 00000 n +0000007812 00000 n +0000007872 00000 n +0000007914 00000 n +0000008009 00000 n +0000008052 00000 n +0000008245 00000 n +0000008289 00000 n +0000008349 00000 n +0000008368 00000 n +trailer << + /Root 1 0 R + /Size 56 + /ID [<42ed290ee4e4c51171853f92a1a7642d><31415926535897932384626433832795>] +>> +startxref +8404 +%%EOF diff --git a/qpdf/qtest/qpdf/boxes.pdf b/qpdf/qtest/qpdf/boxes.pdf new file mode 100644 index 00000000..fba1b969 --- /dev/null +++ b/qpdf/qtest/qpdf/boxes.pdf @@ -0,0 +1,685 @@ +%PDF-1.3 +%¿÷¢þ +%QDF-1.0 + +1 0 obj +<< + /Pages 2 0 R + /Type /Catalog +>> +endobj + +2 0 obj +<< + /Count 8 + /Kids [ + 3 0 R + 4 0 R + 5 0 R + 6 0 R + 7 0 R + 8 0 R + 9 0 R + 10 0 R + ] + /Type /Pages +>> +endobj + +%% Page 1 +3 0 obj +<< + /BleedBox [ + 20 + 40 + 552 + 712 + ] + /Contents 11 0 R + /CropBox [ + 10 + 20 + 582 + 752 + ] + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 14 0 R + /XObject << + /Fx1 15 0 R + >> + >> + /TrimBox [ + 30 + 60 + 522 + 672 + ] + /Type /Page +>> +endobj + +%% Page 2 +4 0 obj +<< + /BleedBox [ + 20 + 40 + 552 + 712 + ] + /Contents 17 0 R + /CropBox [ + 10 + 20 + 582 + 752 + ] + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 14 0 R + /XObject << + /Fx1 15 0 R + >> + >> + /Rotate 90 + /TrimBox [ + 30 + 60 + 522 + 672 + ] + /Type /Page +>> +endobj + +%% Page 3 +5 0 obj +<< + /BleedBox [ + 20 + 40 + 552 + 712 + ] + /Contents 19 0 R + /CropBox [ + 10 + 20 + 582 + 752 + ] + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 14 0 R + /XObject << + /Fx1 15 0 R + >> + >> + /Rotate 180 + /TrimBox [ + 30 + 60 + 522 + 672 + ] + /Type /Page +>> +endobj + +%% Page 4 +6 0 obj +<< + /BleedBox [ + 20 + 40 + 552 + 712 + ] + /Contents 21 0 R + /CropBox [ + 10 + 20 + 582 + 752 + ] + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 14 0 R + /XObject << + /Fx1 15 0 R + >> + >> + /Rotate 270 + /TrimBox [ + 30 + 60 + 522 + 672 + ] + /Type /Page +>> +endobj + +%% Page 5 +7 0 obj +<< + /BleedBox [ + 20 + 40 + 552 + 712 + ] + /Contents 23 0 R + /CropBox [ + 10 + 20 + 582 + 752 + ] + /MediaBox [ + -10 + -20 + 642 + 832 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 14 0 R + /XObject << + /Fx1 15 0 R + >> + >> + /TrimBox [ + 30 + 60 + 522 + 672 + ] + /Type /Page +>> +endobj + +%% Page 6 +8 0 obj +<< + /BleedBox [ + 20 + 40 + 552 + 712 + ] + /Contents 25 0 R + /CropBox [ + 10 + 20 + 582 + 752 + ] + /MediaBox [ + -10 + -20 + 642 + 832 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 14 0 R + /XObject << + /Fx1 15 0 R + >> + >> + /Rotate 90 + /TrimBox [ + 30 + 60 + 522 + 672 + ] + /Type /Page +>> +endobj + +%% Page 7 +9 0 obj +<< + /BleedBox [ + 20 + 40 + 552 + 712 + ] + /Contents 27 0 R + /CropBox [ + 10 + 20 + 582 + 752 + ] + /MediaBox [ + -10 + -20 + 642 + 832 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 14 0 R + /XObject << + /Fx1 15 0 R + >> + >> + /Rotate 180 + /TrimBox [ + 30 + 60 + 522 + 672 + ] + /Type /Page +>> +endobj + +%% Page 8 +10 0 obj +<< + /BleedBox [ + 20 + 40 + 552 + 712 + ] + /Contents 29 0 R + /CropBox [ + 10 + 20 + 582 + 752 + ] + /MediaBox [ + -10 + -20 + 642 + 832 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 14 0 R + /XObject << + /Fx1 15 0 R + >> + >> + /Rotate 270 + /TrimBox [ + 30 + 60 + 522 + 672 + ] + /Type /Page +>> +endobj + +%% Contents for page 1 +11 0 obj +<< + /Length 12 0 R +>> +stream +q +BT + /F1 12 Tf + 144 500 Td + (Rotate: 0) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +12 0 obj +115 +endobj + +13 0 obj +<< + /BaseFont /Helvetica + /Encoding /WinAnsiEncoding + /Name /F1 + /Subtype /Type1 + /Type /Font +>> +endobj + +14 0 obj +[ + /PDF + /Text +] +endobj + +15 0 obj +<< + /BBox [ + 0 + 0 + 612 + 792 + ] + /Resources << + /Font << + /F1 13 0 R + >> + /ProcSet 31 0 R + >> + /Subtype /Form + /Type /XObject + /Length 16 0 R +>> +stream +BT + /F1 12 Tf + 144 620 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 + 0 0 0 rg + (page is cropped at crop) Tj + 0 -15 Td + 0 0 0 rg + (red media rectangle is not visible) 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 +0 0 0 rg +1 .5 0 RG +30 60 492 612 re s +endstream +endobj + +16 0 obj +506 +endobj + +%% Contents for page 2 +17 0 obj +<< + /Length 18 0 R +>> +stream +q +BT + /F1 12 Tf + 144 500 Td + (Rotate: 90) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +18 0 obj +116 +endobj + +%% Contents for page 3 +19 0 obj +<< + /Length 20 0 R +>> +stream +q +BT + /F1 12 Tf + 144 500 Td + (Rotate: 180) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +20 0 obj +117 +endobj + +%% Contents for page 4 +21 0 obj +<< + /Length 22 0 R +>> +stream +q +BT + /F1 12 Tf + 144 500 Td + (Rotate: 270) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +22 0 obj +117 +endobj + +%% Contents for page 5 +23 0 obj +<< + /Length 24 0 R +>> +stream +q +BT + /F1 12 Tf + 144 500 Td + (Rotate: 0, extended MediaBox) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +24 0 obj +134 +endobj + +%% Contents for page 6 +25 0 obj +<< + /Length 26 0 R +>> +stream +q +BT + /F1 12 Tf + 144 500 Td + (Rotate: 90, extended MediaBox) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +26 0 obj +135 +endobj + +%% Contents for page 7 +27 0 obj +<< + /Length 28 0 R +>> +stream +q +BT + /F1 12 Tf + 144 500 Td + (Rotate: 180, extended MediaBox) 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 +136 +endobj + +%% Contents for page 8 +29 0 obj +<< + /Length 30 0 R +>> +stream +q +BT + /F1 12 Tf + 144 500 Td + (Rotate: 270, extended MediaBox) Tj +ET +Q +q +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm +/Fx1 Do +Q +endstream +endobj + +30 0 obj +136 +endobj + +31 0 obj +[ + /PDF + /Text +] +endobj + +xref +0 32 +0000000000 65535 f +0000000025 00000 n +0000000079 00000 n +0000000232 00000 n +0000000620 00000 n +0000001021 00000 n +0000001423 00000 n +0000001825 00000 n +0000002217 00000 n +0000002622 00000 n +0000003028 00000 n +0000003448 00000 n +0000003620 00000 n +0000003641 00000 n +0000003760 00000 n +0000003796 00000 n +0000004513 00000 n +0000004557 00000 n +0000004730 00000 n +0000004774 00000 n +0000004948 00000 n +0000004992 00000 n +0000005166 00000 n +0000005210 00000 n +0000005401 00000 n +0000005445 00000 n +0000005637 00000 n +0000005681 00000 n +0000005874 00000 n +0000005918 00000 n +0000006111 00000 n +0000006132 00000 n +trailer << + /Root 1 0 R + /Size 32 + /ID [<42ed290ee4e4c51171853f92a1a7642d>] +>> +startxref +6168 +%%EOF