Commit 352ce9b22ba32fa50e22258f7d61557ae0d53cc5

Authored by Jay Berkenbilt
1 parent 6ef9e312

Preserve page labels (numbers) when splitting and merging

ChangeLog
1 2018-12-18 Jay Berkenbilt <ejb@ql.org> 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 * Add QPDFPageLabelDocumentHelper class. This is a document helper 9 * Add QPDFPageLabelDocumentHelper class. This is a document helper
4 class that provides useful methods for dealing with page labels. 10 class that provides useful methods for dealing with page labels.
5 It abstracts the fact that they are stored as number trees and 11 It abstracts the fact that they are stored as number trees and
manual/qpdf-manual.xml
@@ -911,23 +911,23 @@ make @@ -911,23 +911,23 @@ make
911 </itemizedlist> 911 </itemizedlist>
912 </para> 912 </para>
913 <para> 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 <programlisting><command>qpdf</command> <option>infile.pdf --pages infile.pdf 1-5 -- outfile.pdf</option> 932 <programlisting><command>qpdf</command> <option>infile.pdf --pages infile.pdf 1-5 -- outfile.pdf</option>
933 </programlisting> 933 </programlisting>
@@ -946,8 +946,8 @@ make @@ -946,8 +946,8 @@ make
946 If, for some reason, you wanted to take the first page of an 946 If, for some reason, you wanted to take the first page of an
947 encrypted file called <filename>encrypted.pdf</filename> with 947 encrypted file called <filename>encrypted.pdf</filename> with
948 password <literal>pass</literal> and repeat it twice in an output 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 <programlisting><command>qpdf</command> <option>--empty --copy-encryption=encrypted.pdf --encryption-file-password=pass 952 <programlisting><command>qpdf</command> <option>--empty --copy-encryption=encrypted.pdf --encryption-file-password=pass
953 --pages encrypted.pdf --password=pass 1 ./encrypted.pdf --password=pass 1 -- 953 --pages encrypted.pdf --password=pass 1 ./encrypted.pdf --password=pass 1 --
qpdf/qpdf.cc
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 #include <qpdf/QPDF.hh> 16 #include <qpdf/QPDF.hh>
17 #include <qpdf/QPDFPageDocumentHelper.hh> 17 #include <qpdf/QPDFPageDocumentHelper.hh>
18 #include <qpdf/QPDFPageObjectHelper.hh> 18 #include <qpdf/QPDFPageObjectHelper.hh>
  19 +#include <qpdf/QPDFPageLabelDocumentHelper.hh>
19 #include <qpdf/QPDFExc.hh> 20 #include <qpdf/QPDFExc.hh>
20 21
21 #include <qpdf/QPDFWriter.hh> 22 #include <qpdf/QPDFWriter.hh>
@@ -2296,11 +2297,25 @@ static void handle_page_specs(QPDF&amp; pdf, Options&amp; o, @@ -2296,11 +2297,25 @@ static void handle_page_specs(QPDF&amp; pdf, Options&amp; o,
2296 // Keep track of any pages from the original file that we are 2297 // Keep track of any pages from the original file that we are
2297 // selecting. 2298 // selecting.
2298 std::set<int> selected_from_orig; 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 for (std::vector<QPDFPageData>::iterator iter = 2303 for (std::vector<QPDFPageData>::iterator iter =
2300 parsed_specs.begin(); 2304 parsed_specs.begin();
2301 iter != parsed_specs.end(); ++iter) 2305 iter != parsed_specs.end(); ++iter)
2302 { 2306 {
2303 QPDFPageData& page_data = *iter; 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 if (o.verbose) 2319 if (o.verbose)
2305 { 2320 {
2306 std::cout << whoami << ": adding pages from " 2321 std::cout << whoami << ": adding pages from "
@@ -2309,22 +2324,14 @@ static void handle_page_specs(QPDF&amp; pdf, Options&amp; o, @@ -2309,22 +2324,14 @@ static void handle_page_specs(QPDF&amp; pdf, Options&amp; o,
2309 for (std::vector<int>::iterator pageno_iter = 2324 for (std::vector<int>::iterator pageno_iter =
2310 page_data.selected_pages.begin(); 2325 page_data.selected_pages.begin();
2311 pageno_iter != page_data.selected_pages.end(); 2326 pageno_iter != page_data.selected_pages.end();
2312 - ++pageno_iter) 2327 + ++pageno_iter, ++out_pageno)
2313 { 2328 {
2314 // Pages are specified from 1 but numbered from 0 in the 2329 // Pages are specified from 1 but numbered from 0 in the
2315 // vector 2330 // vector
2316 int pageno = *pageno_iter - 1; 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 dh.addPage(page_data.orig_pages.at(pageno), false); 2334 dh.addPage(page_data.orig_pages.at(pageno), false);
2324 - if (cis)  
2325 - {  
2326 - cis->stayOpen(false);  
2327 - }  
2328 if (page_data.qpdf == &pdf) 2335 if (page_data.qpdf == &pdf)
2329 { 2336 {
2330 // This is a page from the original file. Keep track 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,6 +2339,18 @@ static void handle_page_specs(QPDF&amp; pdf, Options&amp; o,
2332 selected_from_orig.insert(pageno); 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 // Delete page objects for unused page in primary. This prevents 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,6 +2593,7 @@ static void write_outfile(QPDF&amp; pdf, Options&amp; o)
2574 dh.pushInheritedAttributesToPage(); 2593 dh.pushInheritedAttributesToPage();
2575 dh.removeUnreferencedResources(); 2594 dh.removeUnreferencedResources();
2576 } 2595 }
  2596 + QPDFPageLabelDocumentHelper pldh(pdf);
2577 std::vector<QPDFObjectHandle> const& pages = pdf.getAllPages(); 2597 std::vector<QPDFObjectHandle> const& pages = pdf.getAllPages();
2578 int pageno_len = QUtil::int_to_string(pages.size()).length(); 2598 int pageno_len = QUtil::int_to_string(pages.size()).length();
2579 unsigned int num_pages = pages.size(); 2599 unsigned int num_pages = pages.size();
@@ -2592,6 +2612,16 @@ static void write_outfile(QPDF&amp; pdf, Options&amp; o) @@ -2592,6 +2612,16 @@ static void write_outfile(QPDF&amp; pdf, Options&amp; o)
2592 QPDFObjectHandle page = pages.at(pageno - 1); 2612 QPDFObjectHandle page = pages.at(pageno - 1);
2593 outpdf.addPage(page, false); 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 std::string page_range = QUtil::int_to_string(first, pageno_len); 2625 std::string page_range = QUtil::int_to_string(first, pageno_len);
2596 if (o.split_pages > 1) 2626 if (o.split_pages > 1)
2597 { 2627 {
qpdf/qpdf.testcov
@@ -360,3 +360,4 @@ qpdf disable keep files open 0 @@ -360,3 +360,4 @@ qpdf disable keep files open 0
360 qpdf keep files open n 0 360 qpdf keep files open n 0
361 qpdf keep files open y 0 361 qpdf keep files open y 0
362 qpdf don't disable keep files open 0 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,7 +1137,7 @@ my @sp_cases = (
1137 [11, 'pdf extension', '', 'split-out.Pdf'], 1137 [11, 'pdf extension', '', 'split-out.Pdf'],
1138 [4, 'fallback', '--pages 11-pages.pdf 1-3 minimal.pdf --', 'split-out'], 1138 [4, 'fallback', '--pages 11-pages.pdf 1-3 minimal.pdf --', 'split-out'],
1139 ); 1139 );
1140 -$n_tests += 9; 1140 +$n_tests += 12;
1141 for (@sp_cases) 1141 for (@sp_cases)
1142 { 1142 {
1143 $n_tests += 1 + $_->[0]; 1143 $n_tests += 1 + $_->[0];
@@ -1171,6 +1171,17 @@ foreach my $i (qw(01-04 05-08 09-10)) @@ -1171,6 +1171,17 @@ foreach my $i (qw(01-04 05-08 09-10))
1171 {$td->FILE => "shared-split-$i.pdf"}); 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 foreach my $d (@sp_cases) 1185 foreach my $d (@sp_cases)
1175 { 1186 {
1176 my ($n, $description, $xargs, $out) = @$d; 1187 my ($n, $description, $xargs, $out) = @$d;
@@ -1335,7 +1346,7 @@ foreach my $d (@nrange_tests) @@ -1335,7 +1346,7 @@ foreach my $d (@nrange_tests)
1335 show_ntests(); 1346 show_ntests();
1336 # ---------- 1347 # ----------
1337 $td->notify("--- Merging and Splitting ---"); 1348 $td->notify("--- Merging and Splitting ---");
1338 -$n_tests += 16; 1349 +$n_tests += 18;
1339 1350
1340 # Select pages from the same file multiple times including selecting 1351 # Select pages from the same file multiple times including selecting
1341 # twice from an encrypted file and specifying the password only the 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,8 +1379,7 @@ $td-&gt;runtest(&quot;merge three files&quot;,
1368 " $pages_options --static-id"}, 1379 " $pages_options --static-id"},
1369 {$td->STRING => "", $td->EXIT_STATUS => 0}); 1380 {$td->STRING => "", $td->EXIT_STATUS => 0});
1370 # Manually verified about this file: it has the same pages but does 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 $td->runtest("check output", 1383 $td->runtest("check output",
1374 {$td->FILE => "a.pdf"}, 1384 {$td->FILE => "a.pdf"},
1375 {$td->FILE => "merge-three-files-2.pdf"}); 1385 {$td->FILE => "merge-three-files-2.pdf"});
@@ -1392,6 +1402,17 @@ $td-&gt;runtest(&quot;merge with implicit ranges&quot;, @@ -1392,6 +1402,17 @@ $td-&gt;runtest(&quot;merge with implicit ranges&quot;,
1392 $td->runtest("check output", 1402 $td->runtest("check output",
1393 {$td->FILE => "a.pdf"}, 1403 {$td->FILE => "a.pdf"},
1394 {$td->FILE => "merge-implicit-ranges.pdf"}); 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 $td->runtest("split with shared resources", 1417 $td->runtest("split with shared resources",
1397 {$td->COMMAND => 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