From 35dd11f3560f820d01da9acb6c5425afcdeaea93 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sat, 20 Feb 2021 16:28:58 -0500 Subject: [PATCH] Allow --rotate=0 --- ChangeLog | 4 + libqpdf/QPDFObjectHandle.cc | 2 + manual/qpdf-manual.xml | 8 +- qpdf/qpdf.cc | 9 +- qpdf/qtest/qpdf.test | 10 +- qpdf/qtest/qpdf/unrotated.pdf | 925 ++++++++++++++++++++++++++++++++++ 6 files changed, 952 insertions(+), 6 deletions(-) create mode 100644 qpdf/qtest/qpdf/unrotated.pdf diff --git a/ChangeLog b/ChangeLog index baf568c4..c3b6629e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2021-02-20 Jay Berkenbilt + + * Allow --rotate=0 to clear rotation from a page. + 2021-02-18 Jay Berkenbilt * Add QPDFAcroFormDocumentHelper::addFormField, which adds a new diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index 8f7399f2..b0ae75f1 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -1579,6 +1579,8 @@ QPDFObjectHandle::rotatePage(int angle, bool relative) new_angle += old_angle; } new_angle = (new_angle + 360) % 360; + // Make this explicit even with new_angle == 0 since /Rotate can + // be inherited. replaceKey("/Rotate", QPDFObjectHandle::newInteger(new_angle)); } diff --git a/manual/qpdf-manual.xml b/manual/qpdf-manual.xml index dd03f8d8..bffd52cb 100644 --- a/manual/qpdf-manual.xml +++ b/manual/qpdf-manual.xml @@ -1008,7 +1008,7 @@ make linkend="ref.page-selection"/>. If the page range is omitted, the rotation is applied to all pages. The portion of the parameter may be either - 90, 180, or 270. If preceded by or + 0, 90, 180, or 270. If preceded by or , the angle is added to or subtracted from the specified pages' original rotations. This is almost always what you want. Otherwise the pages' rotations are set to the @@ -5175,6 +5175,12 @@ print "\n"; from the given files. + + + It is now valid to provide to + clear rotation from a page. + + diff --git a/qpdf/qpdf.cc b/qpdf/qpdf.cc index 0c0b344f..2f910f22 100644 --- a/qpdf/qpdf.cc +++ b/qpdf/qpdf.cc @@ -1374,8 +1374,8 @@ ArgParser::argHelp() << " 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" + << " rotate each specified page 0, 90, 180, or 270\n" + << " degrees; rotate all pages if no page range is given\n" << "--split-pages=[n] write each output page to a separate file\n" << "--overlay options -- overlay pages from another file\n" << "--underlay options -- underlay pages from another file\n" @@ -1399,7 +1399,7 @@ ArgParser::argHelp() << "or investigatory purposes. See manual for further discussion.\n" << "\n" << "The --rotate flag can be used to specify pages to rotate pages either\n" - << "90, 180, or 270 degrees. The page range is specified in the same\n" + << "0, 90, 180, or 270 degrees. The page range is specified in the same\n" << "format as with the --pages option, described below. Repeat the option\n" << "to rotate multiple groups of pages. If the angle is preceded by + or -,\n" << "it is added to or subtracted from the original rotation. Otherwise, the\n" @@ -3448,7 +3448,8 @@ ArgParser::parseRotationParameter(std::string const& parameter) // ignore } if (range_valid && - ((angle_str == "90") || (angle_str == "180") || (angle_str == "270"))) + ((angle_str == "0") ||(angle_str == "90") || + (angle_str == "180") || (angle_str == "270"))) { int angle = QUtil::string_to_int(angle_str.c_str()); if (relative == -1) diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index 4ed3ac33..90e7730f 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -2241,7 +2241,7 @@ $td->runtest("explicit keep files open = n", show_ntests(); # ---------- $td->notify("--- Rotate Pages ---"); -$n_tests += 4; +$n_tests += 6; # Do absolute, positive, and negative on ranges that include # inherited and non-inherited. # Pages 11-15 inherit /Rotate 90 @@ -2258,6 +2258,14 @@ $td->runtest("check output", {$td->FILE => "a.pdf"}, {$td->FILE => "rotated.pdf"}); +$td->runtest("remove rotation", + {$td->COMMAND => "qpdf --static-id rotated.pdf a.pdf" . + " --qdf --no-original-object-ids --rotate=0"}, + {$td->STRING => "", $td->EXIT_STATUS => 0}); +$td->runtest("check output", + {$td->FILE => "a.pdf"}, + {$td->FILE => "unrotated.pdf"}); + $td->runtest("rotate all pages", {$td->COMMAND => "qpdf --static-id --rotate=180 minimal.pdf a.pdf"}, diff --git a/qpdf/qtest/qpdf/unrotated.pdf b/qpdf/qtest/qpdf/unrotated.pdf new file mode 100644 index 00000000..6341f29c --- /dev/null +++ b/qpdf/qtest/qpdf/unrotated.pdf @@ -0,0 +1,925 @@ +%PDF-1.4 +%¿÷¢þ +%QDF-1.0 + +1 0 obj +<< + /Pages 3 0 R + /Type /Catalog +>> +endobj + +2 0 obj +<< + /CreationDate (D:20120721200217) + /Producer (Apex PDFWriter) +>> +endobj + +3 0 obj +<< + /Count 20 + /Kids [ + 4 0 R + 5 0 R + 6 0 R + 7 0 R + 8 0 R + 9 0 R + 10 0 R + 11 0 R + 12 0 R + 13 0 R + 14 0 R + 15 0 R + 16 0 R + 17 0 R + 18 0 R + 19 0 R + ] + /Type /Pages +>> +endobj + +%% Page 1 +4 0 obj +<< + /Contents 20 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Page 2 +5 0 obj +<< + /Contents 23 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Page 3 +6 0 obj +<< + /Contents 25 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Page 4 +7 0 obj +<< + /Contents 27 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Page 5 +8 0 obj +<< + /Contents 29 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Page 6 +9 0 obj +<< + /Contents 31 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Page 7 +10 0 obj +<< + /Contents 33 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Page 8 +11 0 obj +<< + /Contents 35 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Page 9 +12 0 obj +<< + /Contents 37 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Page 10 +13 0 obj +<< + /Contents 39 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +14 0 obj +<< + /Count 5 + /Kids [ + 41 0 R + 42 0 R + 43 0 R + 44 0 R + 45 0 R + ] + /Parent 3 0 R + /Rotate 90 + /Type /Pages +>> +endobj + +%% Page 16 +15 0 obj +<< + /Contents 46 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Page 17 +16 0 obj +<< + /Contents 48 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Page 18 +17 0 obj +<< + /Contents 50 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Page 19 +18 0 obj +<< + /Contents 52 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Page 20 +19 0 obj +<< + /Contents 54 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Contents for page 1 +20 0 obj +<< + /Length 21 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 1) Tj ET +endstream +endobj + +21 0 obj +47 +endobj + +22 0 obj +<< + /BaseFont /Times-Roman + /Encoding /WinAnsiEncoding + /Subtype /Type1 + /Type /Font +>> +endobj + +%% Contents for page 2 +23 0 obj +<< + /Length 24 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 2) Tj ET +endstream +endobj + +24 0 obj +47 +endobj + +%% Contents for page 3 +25 0 obj +<< + /Length 26 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 3) Tj ET +endstream +endobj + +26 0 obj +47 +endobj + +%% Contents for page 4 +27 0 obj +<< + /Length 28 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 4) Tj ET +endstream +endobj + +28 0 obj +47 +endobj + +%% Contents for page 5 +29 0 obj +<< + /Length 30 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 5) Tj ET +endstream +endobj + +30 0 obj +47 +endobj + +%% Contents for page 6 +31 0 obj +<< + /Length 32 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 6) Tj ET +endstream +endobj + +32 0 obj +47 +endobj + +%% Contents for page 7 +33 0 obj +<< + /Length 34 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 7) Tj ET +endstream +endobj + +34 0 obj +47 +endobj + +%% Contents for page 8 +35 0 obj +<< + /Length 36 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 8) Tj ET +endstream +endobj + +36 0 obj +47 +endobj + +%% Contents for page 9 +37 0 obj +<< + /Length 38 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 9) Tj ET +endstream +endobj + +38 0 obj +47 +endobj + +%% Contents for page 10 +39 0 obj +<< + /Length 40 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 10) Tj ET +endstream +endobj + +40 0 obj +48 +endobj + +%% Page 11 +41 0 obj +<< + /Contents 56 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 14 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Page 12 +42 0 obj +<< + /Contents 58 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 14 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Page 13 +43 0 obj +<< + /Contents 60 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 14 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Page 14 +44 0 obj +<< + /Contents 62 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 14 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Page 15 +45 0 obj +<< + /Contents 64 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 14 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Rotate 0 + /Type /Page +>> +endobj + +%% Contents for page 16 +46 0 obj +<< + /Length 47 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 16) Tj ET +endstream +endobj + +47 0 obj +48 +endobj + +%% Contents for page 17 +48 0 obj +<< + /Length 49 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 17) Tj ET +endstream +endobj + +49 0 obj +48 +endobj + +%% Contents for page 18 +50 0 obj +<< + /Length 51 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 18) Tj ET +endstream +endobj + +51 0 obj +48 +endobj + +%% Contents for page 19 +52 0 obj +<< + /Length 53 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 19) Tj ET +endstream +endobj + +53 0 obj +48 +endobj + +%% Contents for page 20 +54 0 obj +<< + /Length 55 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 20) Tj ET +endstream +endobj + +55 0 obj +48 +endobj + +%% Contents for page 11 +56 0 obj +<< + /Length 57 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 11) Tj ET +endstream +endobj + +57 0 obj +48 +endobj + +%% Contents for page 12 +58 0 obj +<< + /Length 59 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 12) Tj ET +endstream +endobj + +59 0 obj +48 +endobj + +%% Contents for page 13 +60 0 obj +<< + /Length 61 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 13) Tj ET +endstream +endobj + +61 0 obj +48 +endobj + +%% Contents for page 14 +62 0 obj +<< + /Length 63 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 14) Tj ET +endstream +endobj + +63 0 obj +48 +endobj + +%% Contents for page 15 +64 0 obj +<< + /Length 65 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 15) Tj ET +endstream +endobj + +65 0 obj +48 +endobj + +xref +0 66 +0000000000 65535 f +0000000025 00000 n +0000000079 00000 n +0000000165 00000 n +0000000408 00000 n +0000000649 00000 n +0000000890 00000 n +0000001131 00000 n +0000001372 00000 n +0000001613 00000 n +0000001854 00000 n +0000002096 00000 n +0000002338 00000 n +0000002581 00000 n +0000002813 00000 n +0000002971 00000 n +0000003214 00000 n +0000003457 00000 n +0000003700 00000 n +0000003943 00000 n +0000004198 00000 n +0000004302 00000 n +0000004322 00000 n +0000004454 00000 n +0000004558 00000 n +0000004601 00000 n +0000004705 00000 n +0000004748 00000 n +0000004852 00000 n +0000004895 00000 n +0000004999 00000 n +0000005042 00000 n +0000005146 00000 n +0000005189 00000 n +0000005293 00000 n +0000005336 00000 n +0000005440 00000 n +0000005483 00000 n +0000005587 00000 n +0000005631 00000 n +0000005736 00000 n +0000005767 00000 n +0000006011 00000 n +0000006255 00000 n +0000006499 00000 n +0000006743 00000 n +0000007000 00000 n +0000007105 00000 n +0000007149 00000 n +0000007254 00000 n +0000007298 00000 n +0000007403 00000 n +0000007447 00000 n +0000007552 00000 n +0000007596 00000 n +0000007701 00000 n +0000007745 00000 n +0000007850 00000 n +0000007894 00000 n +0000007999 00000 n +0000008043 00000 n +0000008148 00000 n +0000008192 00000 n +0000008297 00000 n +0000008341 00000 n +0000008446 00000 n +trailer << + /Info 2 0 R + /Root 1 0 R + /Size 66 + /ID [<31415926535897932384626433832795>] +>> +startxref +8466 +%%EOF