Commit 352ce9b22ba32fa50e22258f7d61557ae0d53cc5

Authored by Jay Berkenbilt
1 parent 6ef9e312

Preserve page labels (numbers) when splitting and merging

ChangeLog
1 1 2018-12-18 Jay Berkenbilt <ejb@ql.org>
2 2  
  3 + * Preserve page labels when merging and splitting files. Prior
  4 + versions of qpdf simply preserved the page label information from
  5 + the first file, which usually wouldn't make any sense in the
  6 + merged file. Now any page that had a page number in any original
  7 + file will have the same page number after merging or splitting.
  8 +
3 9 * Add QPDFPageLabelDocumentHelper class. This is a document helper
4 10 class that provides useful methods for dealing with page labels.
5 11 It abstracts the fact that they are stored as number trees and
... ...
manual/qpdf-manual.xml
... ... @@ -911,23 +911,23 @@ make
911 911 </itemizedlist>
912 912 </para>
913 913 <para>
914   - Note that qpdf doesn't presently do anything special about other
915   - constructs in a PDF file that may know about pages, so semantics
916   - of splitting and merging vary across features. For example, the
917   - document's outlines (bookmarks) point to actual page objects, so
918   - if you select some pages and not others, bookmarks that point to
919   - pages that are in the output file will work, and remaining
920   - bookmarks will not work. On the other hand, page labels (page
921   - numbers specified in the file) are just sequential, so page labels
922   - will be messed up in the output file. A future version of
923   - <command>qpdf</command> may do a better job at handling these
924   - issues. (Note that the qpdf library already contains all of the
925   - APIs required in order to implement this in your own application
926   - if you need it.) In the mean time, you can always use
927   - <option>--empty</option> as the primary input file to avoid
928   - copying all of that from the first file. For example, to take
929   - pages 1 through 5 from a <filename>infile.pdf</filename> while
930   - preserving all metadata associated with that file, you could use
  914 + Starting in qpdf version 8.3, when you split and merge files, any
  915 + page labels (page numbers) are preserved in the final file. It is
  916 + expected that more document features will be preserved by
  917 + splitting and merging. In the mean time, semantics of splitting
  918 + and merging vary across features. For example, the document's
  919 + outlines (bookmarks) point to actual page objects, so if you
  920 + select some pages and not others, bookmarks that point to pages
  921 + that are in the output file will work, and remaining bookmarks
  922 + will not work. A future version of <command>qpdf</command> may do
  923 + a better job at handling these issues. (Note that the qpdf library
  924 + already contains all of the APIs required in order to implement
  925 + this in your own application if you need it.) In the mean time,
  926 + you can always use <option>--empty</option> as the primary input
  927 + file to avoid copying all of that from the first file. For
  928 + example, to take pages 1 through 5 from a
  929 + <filename>infile.pdf</filename> while preserving all metadata
  930 + associated with that file, you could use
931 931  
932 932 <programlisting><command>qpdf</command> <option>infile.pdf --pages infile.pdf 1-5 -- outfile.pdf</option>
933 933 </programlisting>
... ... @@ -946,8 +946,8 @@ make
946 946 If, for some reason, you wanted to take the first page of an
947 947 encrypted file called <filename>encrypted.pdf</filename> with
948 948 password <literal>pass</literal> and repeat it twice in an output
949   - file, and if you wanted to drop metadata (like page numbers and
950   - outlines) but preserve encryption, you would use
  949 + file, and if you wanted to drop document-level metadata but
  950 + preserve encryption, you would use
951 951  
952 952 <programlisting><command>qpdf</command> <option>--empty --copy-encryption=encrypted.pdf --encryption-file-password=pass
953 953 --pages encrypted.pdf --password=pass 1 ./encrypted.pdf --password=pass 1 --
... ...
qpdf/qpdf.cc
... ... @@ -16,6 +16,7 @@
16 16 #include <qpdf/QPDF.hh>
17 17 #include <qpdf/QPDFPageDocumentHelper.hh>
18 18 #include <qpdf/QPDFPageObjectHelper.hh>
  19 +#include <qpdf/QPDFPageLabelDocumentHelper.hh>
19 20 #include <qpdf/QPDFExc.hh>
20 21  
21 22 #include <qpdf/QPDFWriter.hh>
... ... @@ -2296,11 +2297,25 @@ static void handle_page_specs(QPDF&amp; pdf, Options&amp; o,
2296 2297 // Keep track of any pages from the original file that we are
2297 2298 // selecting.
2298 2299 std::set<int> selected_from_orig;
  2300 + std::vector<QPDFObjectHandle> new_labels;
  2301 + bool any_page_labels = false;
  2302 + int out_pageno = 0;
2299 2303 for (std::vector<QPDFPageData>::iterator iter =
2300 2304 parsed_specs.begin();
2301 2305 iter != parsed_specs.end(); ++iter)
2302 2306 {
2303 2307 QPDFPageData& page_data = *iter;
  2308 + ClosedFileInputSource* cis = 0;
  2309 + if (page_spec_cfis.count(page_data.filename))
  2310 + {
  2311 + cis = page_spec_cfis[page_data.filename];
  2312 + cis->stayOpen(true);
  2313 + }
  2314 + QPDFPageLabelDocumentHelper pldh(*page_data.qpdf);
  2315 + if (pldh.hasPageLabels())
  2316 + {
  2317 + any_page_labels = true;
  2318 + }
2304 2319 if (o.verbose)
2305 2320 {
2306 2321 std::cout << whoami << ": adding pages from "
... ... @@ -2309,22 +2324,14 @@ static void handle_page_specs(QPDF&amp; pdf, Options&amp; o,
2309 2324 for (std::vector<int>::iterator pageno_iter =
2310 2325 page_data.selected_pages.begin();
2311 2326 pageno_iter != page_data.selected_pages.end();
2312   - ++pageno_iter)
  2327 + ++pageno_iter, ++out_pageno)
2313 2328 {
2314 2329 // Pages are specified from 1 but numbered from 0 in the
2315 2330 // vector
2316 2331 int pageno = *pageno_iter - 1;
2317   - ClosedFileInputSource* cis = 0;
2318   - if (page_spec_cfis.count(page_data.filename))
2319   - {
2320   - cis = page_spec_cfis[page_data.filename];
2321   - cis->stayOpen(true);
2322   - }
  2332 + pldh.getLabelsForPageRange(pageno, pageno, out_pageno,
  2333 + new_labels);
2323 2334 dh.addPage(page_data.orig_pages.at(pageno), false);
2324   - if (cis)
2325   - {
2326   - cis->stayOpen(false);
2327   - }
2328 2335 if (page_data.qpdf == &pdf)
2329 2336 {
2330 2337 // This is a page from the original file. Keep track
... ... @@ -2332,6 +2339,18 @@ static void handle_page_specs(QPDF&amp; pdf, Options&amp; o,
2332 2339 selected_from_orig.insert(pageno);
2333 2340 }
2334 2341 }
  2342 + if (cis)
  2343 + {
  2344 + cis->stayOpen(false);
  2345 + }
  2346 + }
  2347 + if (any_page_labels)
  2348 + {
  2349 + QPDFObjectHandle page_labels =
  2350 + QPDFObjectHandle::newDictionary();
  2351 + page_labels.replaceKey(
  2352 + "/Nums", QPDFObjectHandle::newArray(new_labels));
  2353 + pdf.getRoot().replaceKey("/PageLabels", page_labels);
2335 2354 }
2336 2355  
2337 2356 // Delete page objects for unused page in primary. This prevents
... ... @@ -2574,6 +2593,7 @@ static void write_outfile(QPDF&amp; pdf, Options&amp; o)
2574 2593 dh.pushInheritedAttributesToPage();
2575 2594 dh.removeUnreferencedResources();
2576 2595 }
  2596 + QPDFPageLabelDocumentHelper pldh(pdf);
2577 2597 std::vector<QPDFObjectHandle> const& pages = pdf.getAllPages();
2578 2598 int pageno_len = QUtil::int_to_string(pages.size()).length();
2579 2599 unsigned int num_pages = pages.size();
... ... @@ -2592,6 +2612,16 @@ static void write_outfile(QPDF&amp; pdf, Options&amp; o)
2592 2612 QPDFObjectHandle page = pages.at(pageno - 1);
2593 2613 outpdf.addPage(page, false);
2594 2614 }
  2615 + if (pldh.hasPageLabels())
  2616 + {
  2617 + std::vector<QPDFObjectHandle> labels;
  2618 + pldh.getLabelsForPageRange(first - 1, last - 1, 0, labels);
  2619 + QPDFObjectHandle page_labels =
  2620 + QPDFObjectHandle::newDictionary();
  2621 + page_labels.replaceKey(
  2622 + "/Nums", QPDFObjectHandle::newArray(labels));
  2623 + outpdf.getRoot().replaceKey("/PageLabels", page_labels);
  2624 + }
2595 2625 std::string page_range = QUtil::int_to_string(first, pageno_len);
2596 2626 if (o.split_pages > 1)
2597 2627 {
... ...
qpdf/qpdf.testcov
... ... @@ -360,3 +360,4 @@ qpdf disable keep files open 0
360 360 qpdf keep files open n 0
361 361 qpdf keep files open y 0
362 362 qpdf don't disable keep files open 0
  363 +QPDFPageLabelDocumentHelper skip first 0
... ...
qpdf/qtest/qpdf.test
... ... @@ -1137,7 +1137,7 @@ my @sp_cases = (
1137 1137 [11, 'pdf extension', '', 'split-out.Pdf'],
1138 1138 [4, 'fallback', '--pages 11-pages.pdf 1-3 minimal.pdf --', 'split-out'],
1139 1139 );
1140   -$n_tests += 9;
  1140 +$n_tests += 12;
1141 1141 for (@sp_cases)
1142 1142 {
1143 1143 $n_tests += 1 + $_->[0];
... ... @@ -1171,6 +1171,17 @@ foreach my $i (qw(01-04 05-08 09-10))
1171 1171 {$td->FILE => "shared-split-$i.pdf"});
1172 1172 }
1173 1173  
  1174 +$td->runtest("split page with labels",
  1175 + {$td->COMMAND => "qpdf --qdf --static-id --split-pages=6".
  1176 + " 11-pages-with-labels.pdf split-out-labels.pdf"},
  1177 + {$td->STRING => "", $td->EXIT_STATUS => 0});
  1178 +foreach my $i (qw(01-06 07-11))
  1179 +{
  1180 + $td->runtest("check output ($i)",
  1181 + {$td->FILE => "split-out-labels-$i.pdf"},
  1182 + {$td->FILE => "labels-split-$i.pdf"});
  1183 +}
  1184 +
1174 1185 foreach my $d (@sp_cases)
1175 1186 {
1176 1187 my ($n, $description, $xargs, $out) = @$d;
... ... @@ -1335,7 +1346,7 @@ foreach my $d (@nrange_tests)
1335 1346 show_ntests();
1336 1347 # ----------
1337 1348 $td->notify("--- Merging and Splitting ---");
1338   -$n_tests += 16;
  1349 +$n_tests += 18;
1339 1350  
1340 1351 # Select pages from the same file multiple times including selecting
1341 1352 # twice from an encrypted file and specifying the password only the
... ... @@ -1368,8 +1379,7 @@ $td-&gt;runtest(&quot;merge three files&quot;,
1368 1379 " $pages_options --static-id"},
1369 1380 {$td->STRING => "", $td->EXIT_STATUS => 0});
1370 1381 # Manually verified about this file: it has the same pages but does
1371   -# not contain outlines, page labels, or other things from the original
1372   -# file.
  1382 +# not contain outlines or other things from the original file.
1373 1383 $td->runtest("check output",
1374 1384 {$td->FILE => "a.pdf"},
1375 1385 {$td->FILE => "merge-three-files-2.pdf"});
... ... @@ -1392,6 +1402,17 @@ $td-&gt;runtest(&quot;merge with implicit ranges&quot;,
1392 1402 $td->runtest("check output",
1393 1403 {$td->FILE => "a.pdf"},
1394 1404 {$td->FILE => "merge-implicit-ranges.pdf"});
  1405 +$td->runtest("merge with multiple labels",
  1406 + {$td->COMMAND =>
  1407 + "qpdf --empty a.pdf" .
  1408 + " --pages 11-pages-with-labels.pdf 8-11" .
  1409 + " minimal.pdf " .
  1410 + " page-labels-and-outlines.pdf 17-19 --" .
  1411 + " --static-id"},
  1412 + {$td->STRING => "", $td->EXIT_STATUS => 0});
  1413 +$td->runtest("check output",
  1414 + {$td->FILE => "a.pdf"},
  1415 + {$td->FILE => "merge-multiple-labels.pdf"});
1395 1416  
1396 1417 $td->runtest("split with shared resources",
1397 1418 {$td->COMMAND =>
... ...
qpdf/qtest/qpdf/11-pages-with-labels.pdf 0 → 100644
No preview for this file type
qpdf/qtest/qpdf/labels-split-01-06.pdf 0 → 100644
  1 +%PDF-1.3
  2 +%¿÷¢þ
  3 +%QDF-1.0
  4 +
  5 +%% Original object ID: 1 0
  6 +1 0 obj
  7 +<<
  8 + /PageLabels <<
  9 + /Nums [
  10 + 0
  11 + <<
  12 + /P (pre-)
  13 + /St 1
  14 + >>
  15 + 4
  16 + <<
  17 + /S /r
  18 + /St 4
  19 + >>
  20 + ]
  21 + >>
  22 + /Pages 2 0 R
  23 + /Type /Catalog
  24 +>>
  25 +endobj
  26 +
  27 +%% Original object ID: 2 0
  28 +2 0 obj
  29 +<<
  30 + /Count 6
  31 + /Kids [
  32 + 3 0 R
  33 + 4 0 R
  34 + 5 0 R
  35 + 6 0 R
  36 + 7 0 R
  37 + 8 0 R
  38 + ]
  39 + /Type /Pages
  40 +>>
  41 +endobj
  42 +
  43 +%% Page 1
  44 +%% Original object ID: 3 0
  45 +3 0 obj
  46 +<<
  47 + /Contents 9 0 R
  48 + /MediaBox [
  49 + 0
  50 + 0
  51 + 612
  52 + 792
  53 + ]
  54 + /Parent 2 0 R
  55 + /Resources <<
  56 + /Font <<
  57 + /F1 11 0 R
  58 + >>
  59 + /ProcSet [
  60 + /PDF
  61 + /Text
  62 + ]
  63 + >>
  64 + /Type /Page
  65 +>>
  66 +endobj
  67 +
  68 +%% Page 2
  69 +%% Original object ID: 6 0
  70 +4 0 obj
  71 +<<
  72 + /Contents 12 0 R
  73 + /MediaBox [
  74 + 0
  75 + 0
  76 + 612
  77 + 792
  78 + ]
  79 + /Parent 2 0 R
  80 + /Resources <<
  81 + /Font <<
  82 + /F1 11 0 R
  83 + >>
  84 + /ProcSet [
  85 + /PDF
  86 + /Text
  87 + ]
  88 + >>
  89 + /Type /Page
  90 +>>
  91 +endobj
  92 +
  93 +%% Page 3
  94 +%% Original object ID: 8 0
  95 +5 0 obj
  96 +<<
  97 + /Contents 14 0 R
  98 + /MediaBox [
  99 + 0
  100 + 0
  101 + 612
  102 + 792
  103 + ]
  104 + /Parent 2 0 R
  105 + /Resources <<
  106 + /Font <<
  107 + /F1 11 0 R
  108 + >>
  109 + /ProcSet [
  110 + /PDF
  111 + /Text
  112 + ]
  113 + >>
  114 + /Type /Page
  115 +>>
  116 +endobj
  117 +
  118 +%% Page 4
  119 +%% Original object ID: 10 0
  120 +6 0 obj
  121 +<<
  122 + /Contents 16 0 R
  123 + /MediaBox [
  124 + 0
  125 + 0
  126 + 612
  127 + 792
  128 + ]
  129 + /Parent 2 0 R
  130 + /Resources <<
  131 + /Font <<
  132 + /F1 11 0 R
  133 + >>
  134 + /ProcSet [
  135 + /PDF
  136 + /Text
  137 + ]
  138 + >>
  139 + /Type /Page
  140 +>>
  141 +endobj
  142 +
  143 +%% Page 5
  144 +%% Original object ID: 12 0
  145 +7 0 obj
  146 +<<
  147 + /Contents 18 0 R
  148 + /MediaBox [
  149 + 0
  150 + 0
  151 + 612
  152 + 792
  153 + ]
  154 + /Parent 2 0 R
  155 + /Resources <<
  156 + /Font <<
  157 + /F1 11 0 R
  158 + >>
  159 + /ProcSet [
  160 + /PDF
  161 + /Text
  162 + ]
  163 + >>
  164 + /Type /Page
  165 +>>
  166 +endobj
  167 +
  168 +%% Page 6
  169 +%% Original object ID: 14 0
  170 +8 0 obj
  171 +<<
  172 + /Contents 20 0 R
  173 + /MediaBox [
  174 + 0
  175 + 0
  176 + 612
  177 + 792
  178 + ]
  179 + /Parent 2 0 R
  180 + /Resources <<
  181 + /Font <<
  182 + /F1 11 0 R
  183 + >>
  184 + /ProcSet [
  185 + /PDF
  186 + /Text
  187 + ]
  188 + >>
  189 + /Type /Page
  190 +>>
  191 +endobj
  192 +
  193 +%% Contents for page 1
  194 +%% Original object ID: 4 0
  195 +9 0 obj
  196 +<<
  197 + /Length 10 0 R
  198 +>>
  199 +stream
  200 +BT /F1 15 Tf 72 720 Td (Original page 1) Tj ET
  201 +endstream
  202 +endobj
  203 +
  204 +10 0 obj
  205 +47
  206 +endobj
  207 +
  208 +%% Original object ID: 5 0
  209 +11 0 obj
  210 +<<
  211 + /BaseFont /Times-Roman
  212 + /Encoding /WinAnsiEncoding
  213 + /Subtype /Type1
  214 + /Type /Font
  215 +>>
  216 +endobj
  217 +
  218 +%% Contents for page 2
  219 +%% Original object ID: 7 0
  220 +12 0 obj
  221 +<<
  222 + /Length 13 0 R
  223 +>>
  224 +stream
  225 +BT /F1 15 Tf 72 720 Td (Original page 2) Tj ET
  226 +endstream
  227 +endobj
  228 +
  229 +13 0 obj
  230 +47
  231 +endobj
  232 +
  233 +%% Contents for page 3
  234 +%% Original object ID: 9 0
  235 +14 0 obj
  236 +<<
  237 + /Length 15 0 R
  238 +>>
  239 +stream
  240 +BT /F1 15 Tf 72 720 Td (Original page 3) Tj ET
  241 +endstream
  242 +endobj
  243 +
  244 +15 0 obj
  245 +47
  246 +endobj
  247 +
  248 +%% Contents for page 4
  249 +%% Original object ID: 11 0
  250 +16 0 obj
  251 +<<
  252 + /Length 17 0 R
  253 +>>
  254 +stream
  255 +BT /F1 15 Tf 72 720 Td (Original page 4) Tj ET
  256 +endstream
  257 +endobj
  258 +
  259 +17 0 obj
  260 +47
  261 +endobj
  262 +
  263 +%% Contents for page 5
  264 +%% Original object ID: 13 0
  265 +18 0 obj
  266 +<<
  267 + /Length 19 0 R
  268 +>>
  269 +stream
  270 +BT /F1 15 Tf 72 720 Td (Original page 5) Tj ET
  271 +endstream
  272 +endobj
  273 +
  274 +19 0 obj
  275 +47
  276 +endobj
  277 +
  278 +%% Contents for page 6
  279 +%% Original object ID: 15 0
  280 +20 0 obj
  281 +<<
  282 + /Length 21 0 R
  283 +>>
  284 +stream
  285 +BT /F1 15 Tf 72 720 Td (Original page 6) Tj ET
  286 +endstream
  287 +endobj
  288 +
  289 +21 0 obj
  290 +47
  291 +endobj
  292 +
  293 +xref
  294 +0 22
  295 +0000000000 65535 f
  296 +0000000052 00000 n
  297 +0000000285 00000 n
  298 +0000000444 00000 n
  299 +0000000699 00000 n
  300 +0000000955 00000 n
  301 +0000001212 00000 n
  302 +0000001469 00000 n
  303 +0000001726 00000 n
  304 +0000001995 00000 n
  305 +0000002098 00000 n
  306 +0000002145 00000 n
  307 +0000002304 00000 n
  308 +0000002408 00000 n
  309 +0000002478 00000 n
  310 +0000002582 00000 n
  311 +0000002653 00000 n
  312 +0000002757 00000 n
  313 +0000002828 00000 n
  314 +0000002932 00000 n
  315 +0000003003 00000 n
  316 +0000003107 00000 n
  317 +trailer <<
  318 + /Root 1 0 R
  319 + /Size 22
  320 + /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
  321 +>>
  322 +startxref
  323 +3127
  324 +%%EOF
... ...
qpdf/qtest/qpdf/labels-split-07-11.pdf 0 → 100644
  1 +%PDF-1.3
  2 +%¿÷¢þ
  3 +%QDF-1.0
  4 +
  5 +%% Original object ID: 1 0
  6 +1 0 obj
  7 +<<
  8 + /PageLabels <<
  9 + /Nums [
  10 + 0
  11 + <<
  12 + /S /r
  13 + /St 6
  14 + >>
  15 + 2
  16 + <<
  17 + /S /a
  18 + /St 16
  19 + >>
  20 + ]
  21 + >>
  22 + /Pages 2 0 R
  23 + /Type /Catalog
  24 +>>
  25 +endobj
  26 +
  27 +%% Original object ID: 2 0
  28 +2 0 obj
  29 +<<
  30 + /Count 5
  31 + /Kids [
  32 + 3 0 R
  33 + 4 0 R
  34 + 5 0 R
  35 + 6 0 R
  36 + 7 0 R
  37 + ]
  38 + /Type /Pages
  39 +>>
  40 +endobj
  41 +
  42 +%% Page 1
  43 +%% Original object ID: 3 0
  44 +3 0 obj
  45 +<<
  46 + /Contents 8 0 R
  47 + /MediaBox [
  48 + 0
  49 + 0
  50 + 612
  51 + 792
  52 + ]
  53 + /Parent 2 0 R
  54 + /Resources <<
  55 + /Font <<
  56 + /F1 10 0 R
  57 + >>
  58 + /ProcSet [
  59 + /PDF
  60 + /Text
  61 + ]
  62 + >>
  63 + /Type /Page
  64 +>>
  65 +endobj
  66 +
  67 +%% Page 2
  68 +%% Original object ID: 6 0
  69 +4 0 obj
  70 +<<
  71 + /Contents 11 0 R
  72 + /MediaBox [
  73 + 0
  74 + 0
  75 + 612
  76 + 792
  77 + ]
  78 + /Parent 2 0 R
  79 + /Resources <<
  80 + /Font <<
  81 + /F1 10 0 R
  82 + >>
  83 + /ProcSet [
  84 + /PDF
  85 + /Text
  86 + ]
  87 + >>
  88 + /Type /Page
  89 +>>
  90 +endobj
  91 +
  92 +%% Page 3
  93 +%% Original object ID: 8 0
  94 +5 0 obj
  95 +<<
  96 + /Contents 13 0 R
  97 + /MediaBox [
  98 + 0
  99 + 0
  100 + 612
  101 + 792
  102 + ]
  103 + /Parent 2 0 R
  104 + /Resources <<
  105 + /Font <<
  106 + /F1 10 0 R
  107 + >>
  108 + /ProcSet [
  109 + /PDF
  110 + /Text
  111 + ]
  112 + >>
  113 + /Type /Page
  114 +>>
  115 +endobj
  116 +
  117 +%% Page 4
  118 +%% Original object ID: 10 0
  119 +6 0 obj
  120 +<<
  121 + /Contents 15 0 R
  122 + /MediaBox [
  123 + 0
  124 + 0
  125 + 612
  126 + 792
  127 + ]
  128 + /Parent 2 0 R
  129 + /Resources <<
  130 + /Font <<
  131 + /F1 10 0 R
  132 + >>
  133 + /ProcSet [
  134 + /PDF
  135 + /Text
  136 + ]
  137 + >>
  138 + /Type /Page
  139 +>>
  140 +endobj
  141 +
  142 +%% Page 5
  143 +%% Original object ID: 12 0
  144 +7 0 obj
  145 +<<
  146 + /Contents 17 0 R
  147 + /MediaBox [
  148 + 0
  149 + 0
  150 + 612
  151 + 792
  152 + ]
  153 + /Parent 2 0 R
  154 + /Resources <<
  155 + /Font <<
  156 + /F1 10 0 R
  157 + >>
  158 + /ProcSet [
  159 + /PDF
  160 + /Text
  161 + ]
  162 + >>
  163 + /Type /Page
  164 +>>
  165 +endobj
  166 +
  167 +%% Contents for page 1
  168 +%% Original object ID: 4 0
  169 +8 0 obj
  170 +<<
  171 + /Length 9 0 R
  172 +>>
  173 +stream
  174 +BT /F1 15 Tf 72 720 Td (Original page 7) Tj ET
  175 +endstream
  176 +endobj
  177 +
  178 +9 0 obj
  179 +47
  180 +endobj
  181 +
  182 +%% Original object ID: 5 0
  183 +10 0 obj
  184 +<<
  185 + /BaseFont /Times-Roman
  186 + /Encoding /WinAnsiEncoding
  187 + /Subtype /Type1
  188 + /Type /Font
  189 +>>
  190 +endobj
  191 +
  192 +%% Contents for page 2
  193 +%% Original object ID: 7 0
  194 +11 0 obj
  195 +<<
  196 + /Length 12 0 R
  197 +>>
  198 +stream
  199 +BT /F1 15 Tf 72 720 Td (Original page 8) Tj ET
  200 +endstream
  201 +endobj
  202 +
  203 +12 0 obj
  204 +47
  205 +endobj
  206 +
  207 +%% Contents for page 3
  208 +%% Original object ID: 9 0
  209 +13 0 obj
  210 +<<
  211 + /Length 14 0 R
  212 +>>
  213 +stream
  214 +BT /F1 15 Tf 72 720 Td (Original page 9) Tj ET
  215 +endstream
  216 +endobj
  217 +
  218 +14 0 obj
  219 +47
  220 +endobj
  221 +
  222 +%% Contents for page 4
  223 +%% Original object ID: 11 0
  224 +15 0 obj
  225 +<<
  226 + /Length 16 0 R
  227 +>>
  228 +stream
  229 +BT /F1 15 Tf 72 720 Td (Original page 10) Tj ET
  230 +endstream
  231 +endobj
  232 +
  233 +16 0 obj
  234 +48
  235 +endobj
  236 +
  237 +%% Contents for page 5
  238 +%% Original object ID: 13 0
  239 +17 0 obj
  240 +<<
  241 + /Length 18 0 R
  242 +>>
  243 +stream
  244 +BT /F1 15 Tf 72 720 Td (Original page 11) Tj ET
  245 +endstream
  246 +endobj
  247 +
  248 +18 0 obj
  249 +48
  250 +endobj
  251 +
  252 +xref
  253 +0 19
  254 +0000000000 65535 f
  255 +0000000052 00000 n
  256 +0000000282 00000 n
  257 +0000000431 00000 n
  258 +0000000686 00000 n
  259 +0000000942 00000 n
  260 +0000001199 00000 n
  261 +0000001456 00000 n
  262 +0000001725 00000 n
  263 +0000001827 00000 n
  264 +0000001873 00000 n
  265 +0000002032 00000 n
  266 +0000002136 00000 n
  267 +0000002206 00000 n
  268 +0000002310 00000 n
  269 +0000002381 00000 n
  270 +0000002486 00000 n
  271 +0000002557 00000 n
  272 +0000002662 00000 n
  273 +trailer <<
  274 + /Root 1 0 R
  275 + /Size 19
  276 + /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
  277 +>>
  278 +startxref
  279 +2682
  280 +%%EOF
... ...
qpdf/qtest/qpdf/merge-implicit-ranges.pdf
No preview for this file type
qpdf/qtest/qpdf/merge-multiple-labels.pdf 0 → 100644
No preview for this file type
qpdf/qtest/qpdf/merge-three-files-1.pdf
No preview for this file type
qpdf/qtest/qpdf/merge-three-files-2.pdf
No preview for this file type