aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--manual/qpdf-manual.xml38
-rw-r--r--qpdf/qpdf.cc52
-rw-r--r--qpdf/qpdf.testcov1
-rw-r--r--qpdf/qtest/qpdf.test29
-rw-r--r--qpdf/qtest/qpdf/11-pages-with-labels.pdfbin0 -> 4215 bytes
-rw-r--r--qpdf/qtest/qpdf/labels-split-01-06.pdf324
-rw-r--r--qpdf/qtest/qpdf/labels-split-07-11.pdf280
-rw-r--r--qpdf/qtest/qpdf/merge-implicit-ranges.pdf220
-rw-r--r--qpdf/qtest/qpdf/merge-multiple-labels.pdfbin0 -> 3452 bytes
-rw-r--r--qpdf/qtest/qpdf/merge-three-files-1.pdfbin8495 -> 8396 bytes
-rw-r--r--qpdf/qtest/qpdf/merge-three-files-2.pdfbin6036 -> 6196 bytes
12 files changed, 806 insertions, 144 deletions
diff --git a/ChangeLog b/ChangeLog
index 75fad549..5f44bb05 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
2018-12-18 Jay Berkenbilt <ejb@ql.org>
+ * Preserve page labels when merging and splitting files. Prior
+ versions of qpdf simply preserved the page label information from
+ the first file, which usually wouldn't make any sense in the
+ merged file. Now any page that had a page number in any original
+ file will have the same page number after merging or splitting.
+
* Add QPDFPageLabelDocumentHelper class. This is a document helper
class that provides useful methods for dealing with page labels.
It abstracts the fact that they are stored as number trees and
diff --git a/manual/qpdf-manual.xml b/manual/qpdf-manual.xml
index 8185b848..e327eb95 100644
--- a/manual/qpdf-manual.xml
+++ b/manual/qpdf-manual.xml
@@ -911,23 +911,23 @@ make
</itemizedlist>
</para>
<para>
- Note that qpdf doesn't presently do anything special about other
- constructs in a PDF file that may know about pages, so semantics
- of splitting and merging vary across features. For example, the
- document's outlines (bookmarks) point to actual page objects, so
- if you select some pages and not others, bookmarks that point to
- pages that are in the output file will work, and remaining
- bookmarks will not work. On the other hand, page labels (page
- numbers specified in the file) are just sequential, so page labels
- will be messed up in the output file. A future version of
- <command>qpdf</command> may do a better job at handling these
- issues. (Note that the qpdf library already contains all of the
- APIs required in order to implement this in your own application
- if you need it.) In the mean time, you can always use
- <option>--empty</option> as the primary input file to avoid
- copying all of that from the first file. For example, to take
- pages 1 through 5 from a <filename>infile.pdf</filename> while
- preserving all metadata associated with that file, you could use
+ Starting in qpdf version 8.3, when you split and merge files, any
+ page labels (page numbers) are preserved in the final file. It is
+ expected that more document features will be preserved by
+ splitting and merging. In the mean time, semantics of splitting
+ and merging vary across features. For example, the document's
+ outlines (bookmarks) point to actual page objects, so if you
+ select some pages and not others, bookmarks that point to pages
+ that are in the output file will work, and remaining bookmarks
+ will not work. A future version of <command>qpdf</command> may do
+ a better job at handling these issues. (Note that the qpdf library
+ already contains all of the APIs required in order to implement
+ this in your own application if you need it.) In the mean time,
+ you can always use <option>--empty</option> as the primary input
+ file to avoid copying all of that from the first file. For
+ example, to take pages 1 through 5 from a
+ <filename>infile.pdf</filename> while preserving all metadata
+ associated with that file, you could use
<programlisting><command>qpdf</command> <option>infile.pdf --pages infile.pdf 1-5 -- outfile.pdf</option>
</programlisting>
@@ -946,8 +946,8 @@ make
If, for some reason, you wanted to take the first page of an
encrypted file called <filename>encrypted.pdf</filename> with
password <literal>pass</literal> and repeat it twice in an output
- file, and if you wanted to drop metadata (like page numbers and
- outlines) but preserve encryption, you would use
+ file, and if you wanted to drop document-level metadata but
+ preserve encryption, you would use
<programlisting><command>qpdf</command> <option>--empty --copy-encryption=encrypted.pdf --encryption-file-password=pass
--pages encrypted.pdf --password=pass 1 ./encrypted.pdf --password=pass 1 --
diff --git a/qpdf/qpdf.cc b/qpdf/qpdf.cc
index 19d46acc..b6762aab 100644
--- a/qpdf/qpdf.cc
+++ b/qpdf/qpdf.cc
@@ -16,6 +16,7 @@
#include <qpdf/QPDF.hh>
#include <qpdf/QPDFPageDocumentHelper.hh>
#include <qpdf/QPDFPageObjectHelper.hh>
+#include <qpdf/QPDFPageLabelDocumentHelper.hh>
#include <qpdf/QPDFExc.hh>
#include <qpdf/QPDFWriter.hh>
@@ -2296,11 +2297,25 @@ static void handle_page_specs(QPDF& pdf, Options& o,
// Keep track of any pages from the original file that we are
// selecting.
std::set<int> selected_from_orig;
+ std::vector<QPDFObjectHandle> new_labels;
+ bool any_page_labels = false;
+ int out_pageno = 0;
for (std::vector<QPDFPageData>::iterator iter =
parsed_specs.begin();
iter != parsed_specs.end(); ++iter)
{
QPDFPageData& page_data = *iter;
+ ClosedFileInputSource* cis = 0;
+ if (page_spec_cfis.count(page_data.filename))
+ {
+ cis = page_spec_cfis[page_data.filename];
+ cis->stayOpen(true);
+ }
+ QPDFPageLabelDocumentHelper pldh(*page_data.qpdf);
+ if (pldh.hasPageLabels())
+ {
+ any_page_labels = true;
+ }
if (o.verbose)
{
std::cout << whoami << ": adding pages from "
@@ -2309,22 +2324,14 @@ static void handle_page_specs(QPDF& pdf, Options& o,
for (std::vector<int>::iterator pageno_iter =
page_data.selected_pages.begin();
pageno_iter != page_data.selected_pages.end();
- ++pageno_iter)
+ ++pageno_iter, ++out_pageno)
{
// Pages are specified from 1 but numbered from 0 in the
// vector
int pageno = *pageno_iter - 1;
- ClosedFileInputSource* cis = 0;
- if (page_spec_cfis.count(page_data.filename))
- {
- cis = page_spec_cfis[page_data.filename];
- cis->stayOpen(true);
- }
+ pldh.getLabelsForPageRange(pageno, pageno, out_pageno,
+ new_labels);
dh.addPage(page_data.orig_pages.at(pageno), false);
- if (cis)
- {
- cis->stayOpen(false);
- }
if (page_data.qpdf == &pdf)
{
// This is a page from the original file. Keep track
@@ -2332,6 +2339,18 @@ static void handle_page_specs(QPDF& pdf, Options& o,
selected_from_orig.insert(pageno);
}
}
+ if (cis)
+ {
+ cis->stayOpen(false);
+ }
+ }
+ if (any_page_labels)
+ {
+ QPDFObjectHandle page_labels =
+ QPDFObjectHandle::newDictionary();
+ page_labels.replaceKey(
+ "/Nums", QPDFObjectHandle::newArray(new_labels));
+ pdf.getRoot().replaceKey("/PageLabels", page_labels);
}
// Delete page objects for unused page in primary. This prevents
@@ -2574,6 +2593,7 @@ static void write_outfile(QPDF& pdf, Options& o)
dh.pushInheritedAttributesToPage();
dh.removeUnreferencedResources();
}
+ QPDFPageLabelDocumentHelper pldh(pdf);
std::vector<QPDFObjectHandle> const& pages = pdf.getAllPages();
int pageno_len = QUtil::int_to_string(pages.size()).length();
unsigned int num_pages = pages.size();
@@ -2592,6 +2612,16 @@ static void write_outfile(QPDF& pdf, Options& o)
QPDFObjectHandle page = pages.at(pageno - 1);
outpdf.addPage(page, false);
}
+ if (pldh.hasPageLabels())
+ {
+ std::vector<QPDFObjectHandle> labels;
+ pldh.getLabelsForPageRange(first - 1, last - 1, 0, labels);
+ QPDFObjectHandle page_labels =
+ QPDFObjectHandle::newDictionary();
+ page_labels.replaceKey(
+ "/Nums", QPDFObjectHandle::newArray(labels));
+ outpdf.getRoot().replaceKey("/PageLabels", page_labels);
+ }
std::string page_range = QUtil::int_to_string(first, pageno_len);
if (o.split_pages > 1)
{
diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov
index 6f06ab05..71858eec 100644
--- a/qpdf/qpdf.testcov
+++ b/qpdf/qpdf.testcov
@@ -360,3 +360,4 @@ qpdf disable keep files open 0
qpdf keep files open n 0
qpdf keep files open y 0
qpdf don't disable keep files open 0
+QPDFPageLabelDocumentHelper skip first 0
diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test
index aba78938..cf5b2ab5 100644
--- a/qpdf/qtest/qpdf.test
+++ b/qpdf/qtest/qpdf.test
@@ -1137,7 +1137,7 @@ my @sp_cases = (
[11, 'pdf extension', '', 'split-out.Pdf'],
[4, 'fallback', '--pages 11-pages.pdf 1-3 minimal.pdf --', 'split-out'],
);
-$n_tests += 9;
+$n_tests += 12;
for (@sp_cases)
{
$n_tests += 1 + $_->[0];
@@ -1171,6 +1171,17 @@ foreach my $i (qw(01-04 05-08 09-10))
{$td->FILE => "shared-split-$i.pdf"});
}
+$td->runtest("split page with labels",
+ {$td->COMMAND => "qpdf --qdf --static-id --split-pages=6".
+ " 11-pages-with-labels.pdf split-out-labels.pdf"},
+ {$td->STRING => "", $td->EXIT_STATUS => 0});
+foreach my $i (qw(01-06 07-11))
+{
+ $td->runtest("check output ($i)",
+ {$td->FILE => "split-out-labels-$i.pdf"},
+ {$td->FILE => "labels-split-$i.pdf"});
+}
+
foreach my $d (@sp_cases)
{
my ($n, $description, $xargs, $out) = @$d;
@@ -1335,7 +1346,7 @@ foreach my $d (@nrange_tests)
show_ntests();
# ----------
$td->notify("--- Merging and Splitting ---");
-$n_tests += 16;
+$n_tests += 18;
# Select pages from the same file multiple times including selecting
# twice from an encrypted file and specifying the password only the
@@ -1368,8 +1379,7 @@ $td->runtest("merge three files",
" $pages_options --static-id"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
# Manually verified about this file: it has the same pages but does
-# not contain outlines, page labels, or other things from the original
-# file.
+# not contain outlines or other things from the original file.
$td->runtest("check output",
{$td->FILE => "a.pdf"},
{$td->FILE => "merge-three-files-2.pdf"});
@@ -1392,6 +1402,17 @@ $td->runtest("merge with implicit ranges",
$td->runtest("check output",
{$td->FILE => "a.pdf"},
{$td->FILE => "merge-implicit-ranges.pdf"});
+$td->runtest("merge with multiple labels",
+ {$td->COMMAND =>
+ "qpdf --empty a.pdf" .
+ " --pages 11-pages-with-labels.pdf 8-11" .
+ " minimal.pdf " .
+ " page-labels-and-outlines.pdf 17-19 --" .
+ " --static-id"},
+ {$td->STRING => "", $td->EXIT_STATUS => 0});
+$td->runtest("check output",
+ {$td->FILE => "a.pdf"},
+ {$td->FILE => "merge-multiple-labels.pdf"});
$td->runtest("split with shared resources",
{$td->COMMAND =>
diff --git a/qpdf/qtest/qpdf/11-pages-with-labels.pdf b/qpdf/qtest/qpdf/11-pages-with-labels.pdf
new file mode 100644
index 00000000..962b1b0e
--- /dev/null
+++ b/qpdf/qtest/qpdf/11-pages-with-labels.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/labels-split-01-06.pdf b/qpdf/qtest/qpdf/labels-split-01-06.pdf
new file mode 100644
index 00000000..1058eba1
--- /dev/null
+++ b/qpdf/qtest/qpdf/labels-split-01-06.pdf
@@ -0,0 +1,324 @@
+%PDF-1.3
+%¿÷¢þ
+%QDF-1.0
+
+%% Original object ID: 1 0
+1 0 obj
+<<
+ /PageLabels <<
+ /Nums [
+ 0
+ <<
+ /P (pre-)
+ /St 1
+ >>
+ 4
+ <<
+ /S /r
+ /St 4
+ >>
+ ]
+ >>
+ /Pages 2 0 R
+ /Type /Catalog
+>>
+endobj
+
+%% Original object ID: 2 0
+2 0 obj
+<<
+ /Count 6
+ /Kids [
+ 3 0 R
+ 4 0 R
+ 5 0 R
+ 6 0 R
+ 7 0 R
+ 8 0 R
+ ]
+ /Type /Pages
+>>
+endobj
+
+%% Page 1
+%% Original object ID: 3 0
+3 0 obj
+<<
+ /Contents 9 0 R
+ /MediaBox [
+ 0
+ 0
+ 612
+ 792
+ ]
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 11 0 R
+ >>
+ /ProcSet [
+ /PDF
+ /Text
+ ]
+ >>
+ /Type /Page
+>>
+endobj
+
+%% Page 2
+%% Original object ID: 6 0
+4 0 obj
+<<
+ /Contents 12 0 R
+ /MediaBox [
+ 0
+ 0
+ 612
+ 792
+ ]
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 11 0 R
+ >>
+ /ProcSet [
+ /PDF
+ /Text
+ ]
+ >>
+ /Type /Page
+>>
+endobj
+
+%% Page 3
+%% Original object ID: 8 0
+5 0 obj
+<<
+ /Contents 14 0 R
+ /MediaBox [
+ 0
+ 0
+ 612
+ 792
+ ]
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 11 0 R
+ >>
+ /ProcSet [
+ /PDF
+ /Text
+ ]
+ >>
+ /Type /Page
+>>
+endobj
+
+%% Page 4
+%% Original object ID: 10 0
+6 0 obj
+<<
+ /Contents 16 0 R
+ /MediaBox [
+ 0
+ 0
+ 612
+ 792
+ ]
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 11 0 R
+ >>
+ /ProcSet [
+ /PDF
+ /Text
+ ]
+ >>
+ /Type /Page
+>>
+endobj
+
+%% Page 5
+%% Original object ID: 12 0
+7 0 obj
+<<
+ /Contents 18 0 R
+ /MediaBox [
+ 0
+ 0
+ 612
+ 792
+ ]
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 11 0 R
+ >>
+ /ProcSet [
+ /PDF
+ /Text
+ ]
+ >>
+ /Type /Page
+>>
+endobj
+
+%% Page 6
+%% Original object ID: 14 0
+8 0 obj
+<<
+ /Contents 20 0 R
+ /MediaBox [
+ 0
+ 0
+ 612
+ 792
+ ]
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 11 0 R
+ >>
+ /ProcSet [
+ /PDF
+ /Text
+ ]
+ >>
+ /Type /Page
+>>
+endobj
+
+%% Contents for page 1
+%% Original object ID: 4 0
+9 0 obj
+<<
+ /Length 10 0 R
+>>
+stream
+BT /F1 15 Tf 72 720 Td (Original page 1) Tj ET
+endstream
+endobj
+
+10 0 obj
+47
+endobj
+
+%% Original object ID: 5 0
+11 0 obj
+<<
+ /BaseFont /Times-Roman
+ /Encoding /WinAnsiEncoding
+ /Subtype /Type1
+ /Type /Font
+>>
+endobj
+
+%% Contents for page 2
+%% Original object ID: 7 0
+12 0 obj
+<<
+ /Length 13 0 R
+>>
+stream
+BT /F1 15 Tf 72 720 Td (Original page 2) Tj ET
+endstream
+endobj
+
+13 0 obj
+47
+endobj
+
+%% Contents for page 3
+%% Original object ID: 9 0
+14 0 obj
+<<
+ /Length 15 0 R
+>>
+stream
+BT /F1 15 Tf 72 720 Td (Original page 3) Tj ET
+endstream
+endobj
+
+15 0 obj
+47
+endobj
+
+%% Contents for page 4
+%% Original object ID: 11 0
+16 0 obj
+<<
+ /Length 17 0 R
+>>
+stream
+BT /F1 15 Tf 72 720 Td (Original page 4) Tj ET
+endstream
+endobj
+
+17 0 obj
+47
+endobj
+
+%% Contents for page 5
+%% Original object ID: 13 0
+18 0 obj
+<<
+ /Length 19 0 R
+>>
+stream
+BT /F1 15 Tf 72 720 Td (Original page 5) Tj ET
+endstream
+endobj
+
+19 0 obj
+47
+endobj
+
+%% Contents for page 6
+%% Original object ID: 15 0
+20 0 obj
+<<
+ /Length 21 0 R
+>>
+stream
+BT /F1 15 Tf 72 720 Td (Original page 6) Tj ET
+endstream
+endobj
+
+21 0 obj
+47
+endobj
+
+xref
+0 22
+0000000000 65535 f
+0000000052 00000 n
+0000000285 00000 n
+0000000444 00000 n
+0000000699 00000 n
+0000000955 00000 n
+0000001212 00000 n
+0000001469 00000 n
+0000001726 00000 n
+0000001995 00000 n
+0000002098 00000 n
+0000002145 00000 n
+0000002304 00000 n
+0000002408 00000 n
+0000002478 00000 n
+0000002582 00000 n
+0000002653 00000 n
+0000002757 00000 n
+0000002828 00000 n
+0000002932 00000 n
+0000003003 00000 n
+0000003107 00000 n
+trailer <<
+ /Root 1 0 R
+ /Size 22
+ /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
+>>
+startxref
+3127
+%%EOF
diff --git a/qpdf/qtest/qpdf/labels-split-07-11.pdf b/qpdf/qtest/qpdf/labels-split-07-11.pdf
new file mode 100644
index 00000000..42120fed
--- /dev/null
+++ b/qpdf/qtest/qpdf/labels-split-07-11.pdf
@@ -0,0 +1,280 @@
+%PDF-1.3
+%¿÷¢þ
+%QDF-1.0
+
+%% Original object ID: 1 0
+1 0 obj
+<<
+ /PageLabels <<
+ /Nums [
+ 0
+ <<
+ /S /r
+ /St 6
+ >>
+ 2
+ <<
+ /S /a
+ /St 16
+ >>
+ ]
+ >>
+ /Pages 2 0 R
+ /Type /Catalog
+>>
+endobj
+
+%% Original object ID: 2 0
+2 0 obj
+<<
+ /Count 5
+ /Kids [
+ 3 0 R
+ 4 0 R
+ 5 0 R
+ 6 0 R
+ 7 0 R
+ ]
+ /Type /Pages
+>>
+endobj
+
+%% Page 1
+%% Original object ID: 3 0
+3 0 obj
+<<
+ /Contents 8 0 R
+ /MediaBox [
+ 0
+ 0
+ 612
+ 792
+ ]
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 10 0 R
+ >>
+ /ProcSet [
+ /PDF
+ /Text
+ ]
+ >>
+ /Type /Page
+>>
+endobj
+
+%% Page 2
+%% Original object ID: 6 0
+4 0 obj
+<<
+ /Contents 11 0 R
+ /MediaBox [
+ 0
+ 0
+ 612
+ 792
+ ]
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 10 0 R
+ >>
+ /ProcSet [
+ /PDF
+ /Text
+ ]
+ >>
+ /Type /Page
+>>
+endobj
+
+%% Page 3
+%% Original object ID: 8 0
+5 0 obj
+<<
+ /Contents 13 0 R
+ /MediaBox [
+ 0
+ 0
+ 612
+ 792
+ ]
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 10 0 R
+ >>
+ /ProcSet [
+ /PDF
+ /Text
+ ]
+ >>
+ /Type /Page
+>>
+endobj
+
+%% Page 4
+%% Original object ID: 10 0
+6 0 obj
+<<
+ /Contents 15 0 R
+ /MediaBox [
+ 0
+ 0
+ 612
+ 792
+ ]
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 10 0 R
+ >>
+ /ProcSet [
+ /PDF
+ /Text
+ ]
+ >>
+ /Type /Page
+>>
+endobj
+
+%% Page 5
+%% Original object ID: 12 0
+7 0 obj
+<<
+ /Contents 17 0 R
+ /MediaBox [
+ 0
+ 0
+ 612
+ 792
+ ]
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 10 0 R
+ >>
+ /ProcSet [
+ /PDF
+ /Text
+ ]
+ >>
+ /Type /Page
+>>
+endobj
+
+%% Contents for page 1
+%% Original object ID: 4 0
+8 0 obj
+<<
+ /Length 9 0 R
+>>
+stream
+BT /F1 15 Tf 72 720 Td (Original page 7) Tj ET
+endstream
+endobj
+
+9 0 obj
+47
+endobj
+
+%% Original object ID: 5 0
+10 0 obj
+<<
+ /BaseFont /Times-Roman
+ /Encoding /WinAnsiEncoding
+ /Subtype /Type1
+ /Type /Font
+>>
+endobj
+
+%% Contents for page 2
+%% Original object ID: 7 0
+11 0 obj
+<<
+ /Length 12 0 R
+>>
+stream
+BT /F1 15 Tf 72 720 Td (Original page 8) Tj ET
+endstream
+endobj
+
+12 0 obj
+47
+endobj
+
+%% Contents for page 3
+%% Original object ID: 9 0
+13 0 obj
+<<
+ /Length 14 0 R
+>>
+stream
+BT /F1 15 Tf 72 720 Td (Original page 9) Tj ET
+endstream
+endobj
+
+14 0 obj
+47
+endobj
+
+%% Contents for page 4
+%% Original object ID: 11 0
+15 0 obj
+<<
+ /Length 16 0 R
+>>
+stream
+BT /F1 15 Tf 72 720 Td (Original page 10) Tj ET
+endstream
+endobj
+
+16 0 obj
+48
+endobj
+
+%% Contents for page 5
+%% Original object ID: 13 0
+17 0 obj
+<<
+ /Length 18 0 R
+>>
+stream
+BT /F1 15 Tf 72 720 Td (Original page 11) Tj ET
+endstream
+endobj
+
+18 0 obj
+48
+endobj
+
+xref
+0 19
+0000000000 65535 f
+0000000052 00000 n
+0000000282 00000 n
+0000000431 00000 n
+0000000686 00000 n
+0000000942 00000 n
+0000001199 00000 n
+0000001456 00000 n
+0000001725 00000 n
+0000001827 00000 n
+0000001873 00000 n
+0000002032 00000 n
+0000002136 00000 n
+0000002206 00000 n
+0000002310 00000 n
+0000002381 00000 n
+0000002486 00000 n
+0000002557 00000 n
+0000002662 00000 n
+trailer <<
+ /Root 1 0 R
+ /Size 19
+ /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
+>>
+startxref
+2682
+%%EOF
diff --git a/qpdf/qtest/qpdf/merge-implicit-ranges.pdf b/qpdf/qtest/qpdf/merge-implicit-ranges.pdf
index da523cad..be17bf46 100644
--- a/qpdf/qtest/qpdf/merge-implicit-ranges.pdf
+++ b/qpdf/qtest/qpdf/merge-implicit-ranges.pdf
@@ -1,7 +1,7 @@
%PDF-1.3
%¿÷¢þ
1 0 obj
-<< /Pages 2 0 R /Type /Catalog >>
+<< /PageLabels << /Nums [ 0 << /St 1 >> 21 << /P () /St 1 >> 23 << /S /r /St 1 >> 28 << /P () /St 1 >> 30 << /S /r /St 6 >> 32 << /P () /St 1 >> 33 << /S /D /St 2 >> 36 << /S /D /St 6 >> 40 << /P () /St 1 >> 41 << /S /D /St 12 >> 43 << /S /D /St 16059 >> 44 << /S /r /St 50 >> 50 << /S /r /St 54 >> ] >> /Pages 2 0 R /Type /Catalog >>
endobj
2 0 obj
<< /Count 51 /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 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 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R 29 0 R 30 0 R 31 0 R 32 0 R 33 0 R 34 0 R 35 0 R 36 0 R 37 0 R 38 0 R 39 0 R 40 0 R 41 0 R 42 0 R 43 0 R 44 0 R 45 0 R 46 0 R 47 0 R 48 0 R 49 0 R 50 0 R 51 0 R 52 0 R 53 0 R ] /Type /Pages >>
@@ -514,115 +514,115 @@ xref
0 110
0000000000 65535 f
0000000015 00000 n
-0000000064 00000 n
-0000000468 00000 n
-0000000614 00000 n
-0000000768 00000 n
-0000000922 00000 n
-0000001076 00000 n
-0000001230 00000 n
-0000001384 00000 n
-0000001538 00000 n
-0000001693 00000 n
-0000001848 00000 n
-0000002003 00000 n
-0000002158 00000 n
-0000002313 00000 n
-0000002468 00000 n
-0000002623 00000 n
-0000002778 00000 n
-0000002933 00000 n
-0000003088 00000 n
-0000003243 00000 n
-0000003398 00000 n
-0000003553 00000 n
-0000003708 00000 n
-0000003855 00000 n
-0000004002 00000 n
-0000004149 00000 n
-0000004296 00000 n
-0000004443 00000 n
-0000004590 00000 n
-0000004737 00000 n
-0000004884 00000 n
-0000005031 00000 n
-0000005178 00000 n
-0000005325 00000 n
-0000005472 00000 n
-0000005619 00000 n
-0000005766 00000 n
-0000005913 00000 n
-0000006060 00000 n
-0000006207 00000 n
-0000006354 00000 n
-0000006501 00000 n
-0000006648 00000 n
-0000006796 00000 n
-0000006944 00000 n
-0000007092 00000 n
-0000007240 00000 n
-0000007388 00000 n
-0000007536 00000 n
-0000007684 00000 n
-0000007832 00000 n
-0000007980 00000 n
-0000008128 00000 n
-0000008247 00000 n
-0000008355 00000 n
-0000008386 00000 n
-0000008510 00000 n
-0000008610 00000 n
-0000008734 00000 n
-0000008858 00000 n
-0000008982 00000 n
-0000009106 00000 n
-0000009230 00000 n
-0000009354 00000 n
-0000009478 00000 n
-0000009602 00000 n
-0000009726 00000 n
-0000009851 00000 n
-0000009976 00000 n
-0000010101 00000 n
-0000010226 00000 n
-0000010351 00000 n
-0000010475 00000 n
-0000010600 00000 n
-0000010725 00000 n
-0000010850 00000 n
-0000010975 00000 n
-0000011096 00000 n
-0000011204 00000 n
-0000011235 00000 n
-0000011356 00000 n
-0000011477 00000 n
-0000011598 00000 n
-0000011719 00000 n
-0000011840 00000 n
-0000011961 00000 n
-0000012082 00000 n
-0000012203 00000 n
-0000012324 00000 n
-0000012446 00000 n
-0000012568 00000 n
-0000012690 00000 n
-0000012812 00000 n
-0000012934 00000 n
-0000013056 00000 n
-0000013178 00000 n
-0000013300 00000 n
-0000013422 00000 n
-0000013544 00000 n
-0000013667 00000 n
-0000013790 00000 n
-0000013913 00000 n
-0000014036 00000 n
-0000014158 00000 n
-0000014281 00000 n
-0000014404 00000 n
-0000014527 00000 n
-0000014650 00000 n
+0000000365 00000 n
+0000000769 00000 n
+0000000915 00000 n
+0000001069 00000 n
+0000001223 00000 n
+0000001377 00000 n
+0000001531 00000 n
+0000001685 00000 n
+0000001839 00000 n
+0000001994 00000 n
+0000002149 00000 n
+0000002304 00000 n
+0000002459 00000 n
+0000002614 00000 n
+0000002769 00000 n
+0000002924 00000 n
+0000003079 00000 n
+0000003234 00000 n
+0000003389 00000 n
+0000003544 00000 n
+0000003699 00000 n
+0000003854 00000 n
+0000004009 00000 n
+0000004156 00000 n
+0000004303 00000 n
+0000004450 00000 n
+0000004597 00000 n
+0000004744 00000 n
+0000004891 00000 n
+0000005038 00000 n
+0000005185 00000 n
+0000005332 00000 n
+0000005479 00000 n
+0000005626 00000 n
+0000005773 00000 n
+0000005920 00000 n
+0000006067 00000 n
+0000006214 00000 n
+0000006361 00000 n
+0000006508 00000 n
+0000006655 00000 n
+0000006802 00000 n
+0000006949 00000 n
+0000007097 00000 n
+0000007245 00000 n
+0000007393 00000 n
+0000007541 00000 n
+0000007689 00000 n
+0000007837 00000 n
+0000007985 00000 n
+0000008133 00000 n
+0000008281 00000 n
+0000008429 00000 n
+0000008548 00000 n
+0000008656 00000 n
+0000008687 00000 n
+0000008811 00000 n
+0000008911 00000 n
+0000009035 00000 n
+0000009159 00000 n
+0000009283 00000 n
+0000009407 00000 n
+0000009531 00000 n
+0000009655 00000 n
+0000009779 00000 n
+0000009903 00000 n
+0000010027 00000 n
+0000010152 00000 n
+0000010277 00000 n
+0000010402 00000 n
+0000010527 00000 n
+0000010652 00000 n
+0000010776 00000 n
+0000010901 00000 n
+0000011026 00000 n
+0000011151 00000 n
+0000011276 00000 n
+0000011397 00000 n
+0000011505 00000 n
+0000011536 00000 n
+0000011657 00000 n
+0000011778 00000 n
+0000011899 00000 n
+0000012020 00000 n
+0000012141 00000 n
+0000012262 00000 n
+0000012383 00000 n
+0000012504 00000 n
+0000012625 00000 n
+0000012747 00000 n
+0000012869 00000 n
+0000012991 00000 n
+0000013113 00000 n
+0000013235 00000 n
+0000013357 00000 n
+0000013479 00000 n
+0000013601 00000 n
+0000013723 00000 n
+0000013845 00000 n
+0000013968 00000 n
+0000014091 00000 n
+0000014214 00000 n
+0000014337 00000 n
+0000014459 00000 n
+0000014582 00000 n
+0000014705 00000 n
+0000014828 00000 n
+0000014951 00000 n
trailer << /Root 1 0 R /Size 110 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] >>
startxref
-14773
+15074
%%EOF
diff --git a/qpdf/qtest/qpdf/merge-multiple-labels.pdf b/qpdf/qtest/qpdf/merge-multiple-labels.pdf
new file mode 100644
index 00000000..d767e760
--- /dev/null
+++ b/qpdf/qtest/qpdf/merge-multiple-labels.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/merge-three-files-1.pdf b/qpdf/qtest/qpdf/merge-three-files-1.pdf
index 709f21ed..d90b97d7 100644
--- a/qpdf/qtest/qpdf/merge-three-files-1.pdf
+++ b/qpdf/qtest/qpdf/merge-three-files-1.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/merge-three-files-2.pdf b/qpdf/qtest/qpdf/merge-three-files-2.pdf
index c8b717e6..2d472ac6 100644
--- a/qpdf/qtest/qpdf/merge-three-files-2.pdf
+++ b/qpdf/qtest/qpdf/merge-three-files-2.pdf
Binary files differ