aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--include/qpdf/QPDFPageObjectHelper.hh4
-rw-r--r--libqpdf/QPDFPageObjectHelper.cc83
-rw-r--r--manual/qpdf-manual.xml10
-rw-r--r--qpdf/qpdf.testcov2
-rw-r--r--qpdf/qtest/qpdf.test36
-rw-r--r--qpdf/qtest/qpdf/form-xobjects-no-resources-out.pdfbin0 -> 2664 bytes
-rw-r--r--qpdf/qtest/qpdf/form-xobjects-no-resources.pdf325
-rw-r--r--qpdf/qtest/qpdf/form-xobjects-some-resources1-out.pdfbin0 -> 2775 bytes
-rw-r--r--qpdf/qtest/qpdf/form-xobjects-some-resources1.out2
-rw-r--r--qpdf/qtest/qpdf/form-xobjects-some-resources1.pdf331
-rw-r--r--qpdf/qtest/qpdf/form-xobjects-some-resources2-out.pdfbin0 -> 2819 bytes
-rw-r--r--qpdf/qtest/qpdf/form-xobjects-some-resources2.out3
-rw-r--r--qpdf/qtest/qpdf/form-xobjects-some-resources2.pdf336
-rw-r--r--qpdf/qtest/qpdf/shared-images-errors-2.out2
-rw-r--r--qpdf/qtest/qpdf/split-tokens-split.out2
16 files changed, 1128 insertions, 17 deletions
diff --git a/ChangeLog b/ChangeLog
index 243e4929..2670dd07 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2021-02-02 Jay Berkenbilt <ejb@ql.org>
+
+ * Bug fix: if a form XObject lacks a resources dictionary,
+ consider any names in that form XObject to be referenced from the
+ containing page. This is compliant with older PDF versions. Also
+ detect if any form XObjects have any unresolved names and, if so,
+ don't remove unreferenced resources from them or from the page
+ that contains them. Fixes #494.
+
2021-01-31 Jay Berkenbilt <ejb@ql.org>
* Bug fix: properly handle strings if they appear in inline image
diff --git a/include/qpdf/QPDFPageObjectHelper.hh b/include/qpdf/QPDFPageObjectHelper.hh
index c948c5c2..73344caf 100644
--- a/include/qpdf/QPDFPageObjectHelper.hh
+++ b/include/qpdf/QPDFPageObjectHelper.hh
@@ -317,9 +317,9 @@ class QPDFPageObjectHelper: public QPDFObjectHelper
void flattenRotation();
private:
- static void
+ static bool
removeUnreferencedResourcesHelper(
- QPDFPageObjectHelper ph);
+ QPDFPageObjectHelper ph, std::set<std::string>& unresolved);
class Members
{
diff --git a/libqpdf/QPDFPageObjectHelper.cc b/libqpdf/QPDFPageObjectHelper.cc
index 28b76561..da8b3919 100644
--- a/libqpdf/QPDFPageObjectHelper.cc
+++ b/libqpdf/QPDFPageObjectHelper.cc
@@ -701,10 +701,16 @@ NameWatcher::handleToken(QPDFTokenizer::Token const& token)
writeToken(token);
}
-void
+bool
QPDFPageObjectHelper::removeUnreferencedResourcesHelper(
- QPDFPageObjectHelper ph)
+ QPDFPageObjectHelper ph, std::set<std::string>& unresolved)
{
+ bool is_page = (! ph.oh.isFormXObject());
+ if (! is_page)
+ {
+ QTC::TC("qpdf", "QPDFPageObjectHelper filter form xobject");
+ }
+
NameWatcher nw;
try
{
@@ -714,16 +720,17 @@ QPDFPageObjectHelper::removeUnreferencedResourcesHelper(
{
ph.oh.warnIfPossible(
std::string("Unable to parse content stream: ") + e.what() +
- "; not attempting to remove unreferenced objects from this page");
- return;
+ "; not attempting to remove unreferenced objects"
+ " from this object");
+ return false;
}
if (nw.saw_bad)
{
QTC::TC("qpdf", "QPDFPageObjectHelper bad token finding names");
ph.oh.warnIfPossible(
"Bad token found while scanning content stream; "
- "not attempting to remove unreferenced objects from this page");
- return;
+ "not attempting to remove unreferenced objects from this object");
+ return false;
}
// We will walk through /Font and /XObject dictionaries, removing
@@ -733,6 +740,7 @@ QPDFPageObjectHelper::removeUnreferencedResourcesHelper(
// of mutating the one it was copied from.
QPDFObjectHandle resources = ph.getAttribute("/Resources", true);
std::vector<QPDFObjectHandle> rdicts;
+ std::set<std::string> known_names;
if (resources.isDictionary())
{
std::vector<std::string> to_filter = {"/Font", "/XObject"};
@@ -744,33 +752,86 @@ QPDFPageObjectHelper::removeUnreferencedResourcesHelper(
dict = dict.shallowCopy();
resources.replaceKey(iter, dict);
rdicts.push_back(dict);
+ auto keys = dict.getKeys();
+ known_names.insert(keys.begin(), keys.end());
}
}
}
+
+ std::set<std::string> local_unresolved;
+ for (auto const& name: nw.names)
+ {
+ if (! known_names.count(name))
+ {
+ unresolved.insert(name);
+ local_unresolved.insert(name);
+ }
+ }
+ // Older versions of the PDF spec allowed form XObjects to omit
+ // their resources dictionaries, in which case names were resolved
+ // from the containing page. This behavior seems to be widely
+ // supported by viewers. If a form XObjects has a resources
+ // dictionary and has some unresolved names, some viewers fail to
+ // resolve them, and others allow them to be inherited from the
+ // page or from another form XObjects that contains them. Since
+ // this behavior is inconsistent across viewers, we consider an
+ // unresolved name when a resources dictionary is present to be
+ // reason not to remove unreferenced resources. An unresolved name
+ // in the absence of a resource dictionary is not considered a
+ // problem. For form XObjects, we just accumulate a list of
+ // unresolved names, and for page objects, we avoid removing any
+ // such names found in nested form XObjects.
+
+ if ((! local_unresolved.empty()) && resources.isDictionary())
+ {
+ QTC::TC("qpdf", "QPDFPageObjectHelper unresolved names");
+ ph.oh.warnIfPossible(
+ "Unresolved names found while scanning content stream; "
+ "not attempting to remove unreferenced objects from this object");
+ return false;
+ }
+
for (auto& dict: rdicts)
{
for (auto const& key: dict.getKeys())
{
- if (! nw.names.count(key))
+ if (is_page && unresolved.count(key))
+ {
+ // This name is referenced by some nested form
+ // xobject, so don't remove it.
+ QTC::TC("qpdf", "QPDFPageObjectHelper resolving unresolved");
+ }
+ else if (! nw.names.count(key))
{
dict.removeKey(key);
}
}
}
+ return true;
}
void
QPDFPageObjectHelper::removeUnreferencedResources()
{
+ // Accumulate a list of unresolved names across all nested form
+ // XObjects.
+ std::set<std::string> unresolved;
+ bool any_failures = false;
forEachFormXObject(
true,
- [](
+ [&any_failures, &unresolved](
QPDFObjectHandle& obj, QPDFObjectHandle&, std::string const&)
{
- QTC::TC("qpdf", "QPDFPageObjectHelper filter form xobject");
- removeUnreferencedResourcesHelper(QPDFPageObjectHelper(obj));
+ if (! removeUnreferencedResourcesHelper(
+ QPDFPageObjectHelper(obj), unresolved))
+ {
+ any_failures = true;
+ }
});
- removeUnreferencedResourcesHelper(*this);
+ if (this->oh.isFormXObject() || (! any_failures))
+ {
+ removeUnreferencedResourcesHelper(*this, unresolved);
+ }
}
QPDFPageObjectHelper
diff --git a/manual/qpdf-manual.xml b/manual/qpdf-manual.xml
index 66819d99..fda9c1fd 100644
--- a/manual/qpdf-manual.xml
+++ b/manual/qpdf-manual.xml
@@ -4889,6 +4889,16 @@ print "\n";
<itemizedlist>
<listitem>
<para>
+ If a form XObject lacks a resources dictionary, consider any
+ names in that form XObject to be referenced from the
+ containing page. This is compliant with older PDF versions.
+ Also detect if any form XObjects have any unresolved names
+ and, if so, don't remove unreferenced resources from them or
+ from the page that contains them.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
Properly handle strings if they appear in inline image
dictionaries while externalizing inline images.
</para>
diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov
index 7aa84d8d..520cc84b 100644
--- a/qpdf/qpdf.testcov
+++ b/qpdf/qpdf.testcov
@@ -566,3 +566,5 @@ NNTree non-flat tree is empty after remove 0
NNTree remove walking up tree 0
NNTree erased last item in tree 0
NNTree remove limits from root 0
+QPDFPageObjectHelper unresolved names 0
+QPDFPageObjectHelper resolving unresolved 0
diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test
index 62eebcd7..0ec1b834 100644
--- a/qpdf/qtest/qpdf.test
+++ b/qpdf/qtest/qpdf.test
@@ -1783,8 +1783,8 @@ my @sp_cases = (
[1, 'broken data', '--pages broken-lzw.pdf --', 'split-out.pdf',
{$td->FILE => "broken-lzw.out", $td->EXIT_STATUS => 3}],
);
-$n_tests += 36;
-$n_compare_pdfs += 1;
+$n_tests += 43;
+$n_compare_pdfs += 2;
for (@sp_cases)
{
$n_tests += 1 + $_->[0];
@@ -1943,6 +1943,38 @@ foreach my $i (qw(1 2))
{$td->FILE => "shared-form-xobject-split-$i.pdf"});
}
+my @fo_resources = (['form-xobjects-no-resources', 0],
+ ['form-xobjects-some-resources1', 3],
+ ['form-xobjects-some-resources2', 3]);
+foreach my $d (@fo_resources)
+{
+ my ($f, $status) = @$d;
+ my $expout = ($status == 0 ?
+ {$td->STRING => ""} :
+ {$td->FILE => "$f.out"});
+ $expout->{$td->EXIT_STATUS} = $status;
+ $td->runtest("split $f",
+ {$td->COMMAND =>
+ "qpdf --empty --static-id --pages $f.pdf 1 --" .
+ " --remove-unreferenced-resources=yes a.pdf"},
+ $expout, $td->NORMALIZE_NEWLINES);
+ $td->runtest("check output ($f)",
+ {$td->FILE => "a.pdf"},
+ {$td->FILE => "$f-out.pdf"});
+ if ($status == 0)
+ {
+ compare_pdfs("$f.pdf", "a.pdf");
+ }
+}
+
+$td->runtest("no warn with pages warnings",
+ {$td->COMMAND =>
+ "qpdf --no-warn --empty --static-id".
+ " --pages form-xobjects-some-resources1.pdf 1 --" .
+ " --remove-unreferenced-resources=yes a.pdf"},
+ {$td->STRING => "", $td->EXIT_STATUS => 3},
+ $td->NORMALIZE_NEWLINES);
+
show_ntests();
# ----------
$td->notify("--- Keep Files Open ---");
diff --git a/qpdf/qtest/qpdf/form-xobjects-no-resources-out.pdf b/qpdf/qtest/qpdf/form-xobjects-no-resources-out.pdf
new file mode 100644
index 00000000..ac9f92eb
--- /dev/null
+++ b/qpdf/qtest/qpdf/form-xobjects-no-resources-out.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/form-xobjects-no-resources.pdf b/qpdf/qtest/qpdf/form-xobjects-no-resources.pdf
new file mode 100644
index 00000000..64898fe4
--- /dev/null
+++ b/qpdf/qtest/qpdf/form-xobjects-no-resources.pdf
@@ -0,0 +1,325 @@
+%PDF-1.3
+%¿÷¢þ
+%QDF-1.0
+
+1 0 obj
+<<
+ /Pages 2 0 R
+ /Type /Catalog
+>>
+endobj
+
+2 0 obj
+<<
+ /Count 1
+ /Kids [
+ 3 0 R
+ ]
+ /Resources <<
+ /Font <<
+ /F1 4 0 R
+ >>
+ /ProcSet 5 0 R
+ /XObject <<
+ /Fx1 6 0 R
+ /Fx2 8 0 R
+ /Im1 10 0 R
+ /Im2 12 0 R
+ /Im3 14 0 R
+ /Im4 16 0 R
+ /Im5 18 0 R
+ /Im6 20 0 R
+ /ImX 20 0 R
+ >>
+ >>
+ /Type /Pages
+>>
+endobj
+
+%% Page 1
+3 0 obj
+<<
+ /Contents 22 0 R
+ /MediaBox [
+ 0
+ 0
+ 612
+ 792
+ ]
+ /Parent 2 0 R
+ /Type /Page
+>>
+endobj
+
+4 0 obj
+<<
+ /BaseFont /Helvetica
+ /Encoding /WinAnsiEncoding
+ /Name /F1
+ /Subtype /Type1
+ /Type /Font
+>>
+endobj
+
+5 0 obj
+[
+ /PDF
+ /Text
+ /ImageC
+]
+endobj
+
+6 0 obj
+<<
+ /BBox [
+ 0
+ 0
+ 300
+ 500
+ ]
+ /Subtype /Form
+ /Type /XObject
+ /Length 7 0 R
+>>
+stream
+BT
+ /F1 24 Tf
+ 0 320 Td
+ (FX1) Tj
+ET
+q
+100 0 0 100 000 200 cm
+/Im3 Do
+Q
+q
+100 0 0 100 120 200 cm
+/Im4 Do
+Q
+q
+1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm
+/Fx2 Do
+Q
+endstream
+endobj
+
+7 0 obj
+173
+endobj
+
+8 0 obj
+<<
+ /BBox [
+ 0
+ 0
+ 300
+ 200
+ ]
+ /Subtype /Form
+ /Type /XObject
+ /Length 9 0 R
+>>
+stream
+BT
+ /F1 24 Tf
+ 0 120 Td
+ (FX2) Tj
+ET
+q
+100 0 0 100 0 0 cm
+/Im5 Do
+Q
+q
+100 0 0 100 120 0 cm
+/Im6 Do
+Q
+endstream
+endobj
+
+9 0 obj
+104
+endobj
+
+10 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 11 0 R
+>>
+stream
+`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+11 0 obj
+225
+endobj
+
+12 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 13 0 R
+>>
+stream
+@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+13 0 obj
+225
+endobj
+
+14 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 15 0 R
+>>
+stream
+@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+15 0 obj
+225
+endobj
+
+16 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 17 0 R
+>>
+stream
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+17 0 obj
+225
+endobj
+
+18 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 19 0 R
+>>
+stream
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+19 0 obj
+225
+endobj
+
+20 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 21 0 R
+>>
+stream
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+21 0 obj
+225
+endobj
+
+%% Contents for page 1
+22 0 obj
+<<
+ /Length 23 0 R
+>>
+stream
+BT
+ /F1 24 Tf
+ 72 720 Td
+ (Page) Tj
+ET
+q
+100 0 0 100 72 600 cm
+/Im1 Do
+Q
+q
+100 0 0 100 192 600 cm
+/Im2 Do
+Q
+q
+1.00000 0.00000 0.00000 1.00000 72.00000 200.00000 cm
+/Fx1 Do
+Q
+endstream
+endobj
+
+23 0 obj
+177
+endobj
+
+xref
+0 24
+0000000000 65535 f
+0000000025 00000 n
+0000000079 00000 n
+0000000420 00000 n
+0000000537 00000 n
+0000000655 00000 n
+0000000700 00000 n
+0000001004 00000 n
+0000001024 00000 n
+0000001259 00000 n
+0000001279 00000 n
+0000001691 00000 n
+0000001712 00000 n
+0000002124 00000 n
+0000002145 00000 n
+0000002557 00000 n
+0000002578 00000 n
+0000002990 00000 n
+0000003011 00000 n
+0000003423 00000 n
+0000003444 00000 n
+0000003856 00000 n
+0000003900 00000 n
+0000004134 00000 n
+trailer <<
+ /Root 1 0 R
+ /Size 24
+ /ID [<55269d37282af9edc76855e4cb859987><5044e8073c04a0be007e587c761cce26>]
+>>
+startxref
+4155
+%%EOF
diff --git a/qpdf/qtest/qpdf/form-xobjects-some-resources1-out.pdf b/qpdf/qtest/qpdf/form-xobjects-some-resources1-out.pdf
new file mode 100644
index 00000000..7cb072a8
--- /dev/null
+++ b/qpdf/qtest/qpdf/form-xobjects-some-resources1-out.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/form-xobjects-some-resources1.out b/qpdf/qtest/qpdf/form-xobjects-some-resources1.out
new file mode 100644
index 00000000..17d6c7f2
--- /dev/null
+++ b/qpdf/qtest/qpdf/form-xobjects-some-resources1.out
@@ -0,0 +1,2 @@
+WARNING: form-xobjects-some-resources1.pdf, stream object 8 0: Unresolved names found while scanning content stream; not attempting to remove unreferenced objects from this object
+qpdf: operation succeeded with warnings; resulting file may have some problems
diff --git a/qpdf/qtest/qpdf/form-xobjects-some-resources1.pdf b/qpdf/qtest/qpdf/form-xobjects-some-resources1.pdf
new file mode 100644
index 00000000..0c914ad5
--- /dev/null
+++ b/qpdf/qtest/qpdf/form-xobjects-some-resources1.pdf
@@ -0,0 +1,331 @@
+%PDF-1.3
+%¿÷¢þ
+%QDF-1.0
+
+1 0 obj
+<<
+ /Pages 2 0 R
+ /Type /Catalog
+>>
+endobj
+
+2 0 obj
+<<
+ /Count 1
+ /Kids [
+ 3 0 R
+ ]
+ /Resources <<
+ /Font <<
+ /F1 4 0 R
+ >>
+ /ProcSet 5 0 R
+ /XObject <<
+ /Fx1 6 0 R
+ /Fx2 8 0 R
+ /Im1 10 0 R
+ /Im2 12 0 R
+ /Im3 14 0 R
+ /Im4 16 0 R
+ /Im5 18 0 R
+ /Im6 20 0 R
+ /ImX 20 0 R
+ >>
+ >>
+ /Type /Pages
+>>
+endobj
+
+%% Page 1
+3 0 obj
+<<
+ /Contents 22 0 R
+ /MediaBox [
+ 0
+ 0
+ 612
+ 792
+ ]
+ /Parent 2 0 R
+ /Type /Page
+>>
+endobj
+
+4 0 obj
+<<
+ /BaseFont /Helvetica
+ /Encoding /WinAnsiEncoding
+ /Name /F1
+ /Subtype /Type1
+ /Type /Font
+>>
+endobj
+
+5 0 obj
+[
+ /PDF
+ /Text
+ /ImageC
+]
+endobj
+
+6 0 obj
+<<
+ /BBox [
+ 0
+ 0
+ 300
+ 500
+ ]
+ /Subtype /Form
+ /Type /XObject
+ /Length 7 0 R
+>>
+stream
+BT
+ /F1 24 Tf
+ 0 320 Td
+ (FX1) Tj
+ET
+q
+100 0 0 100 000 200 cm
+/Im3 Do
+Q
+q
+100 0 0 100 120 200 cm
+/Im4 Do
+Q
+q
+1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm
+/Fx2 Do
+Q
+endstream
+endobj
+
+7 0 obj
+173
+endobj
+
+8 0 obj
+<<
+ /BBox [
+ 0
+ 0
+ 300
+ 200
+ ]
+ /Subtype /Form
+ /Type /XObject
+ /Length 9 0 R
+ /Resources <<
+ /XObject <<
+ /Im1 20 0 R
+ /ImY 20 0 R
+ >>
+ >>
+>>
+stream
+BT
+ /F1 24 Tf
+ 0 120 Td
+ (FX2) Tj
+ET
+q
+100 0 0 100 0 0 cm
+/Im5 Do
+Q
+q
+100 0 0 100 120 0 cm
+/Im1 Do
+Q
+endstream
+endobj
+
+9 0 obj
+104
+endobj
+
+10 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 11 0 R
+>>
+stream
+`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+11 0 obj
+225
+endobj
+
+12 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 13 0 R
+>>
+stream
+@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+13 0 obj
+225
+endobj
+
+14 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 15 0 R
+>>
+stream
+@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+15 0 obj
+225
+endobj
+
+16 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 17 0 R
+>>
+stream
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+17 0 obj
+225
+endobj
+
+18 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 19 0 R
+>>
+stream
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+19 0 obj
+225
+endobj
+
+20 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 21 0 R
+>>
+stream
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+21 0 obj
+225
+endobj
+
+%% Contents for page 1
+22 0 obj
+<<
+ /Length 23 0 R
+>>
+stream
+BT
+ /F1 24 Tf
+ 72 720 Td
+ (Page) Tj
+ET
+q
+100 0 0 100 72 600 cm
+/Im1 Do
+Q
+q
+100 0 0 100 192 600 cm
+/Im2 Do
+Q
+q
+1.00000 0.00000 0.00000 1.00000 72.00000 200.00000 cm
+/Fx1 Do
+Q
+endstream
+endobj
+
+23 0 obj
+177
+endobj
+
+xref
+0 24
+0000000000 65535 f
+0000000025 00000 n
+0000000079 00000 n
+0000000420 00000 n
+0000000537 00000 n
+0000000655 00000 n
+0000000700 00000 n
+0000001004 00000 n
+0000001024 00000 n
+0000001339 00000 n
+0000001359 00000 n
+0000001771 00000 n
+0000001792 00000 n
+0000002204 00000 n
+0000002225 00000 n
+0000002637 00000 n
+0000002658 00000 n
+0000003070 00000 n
+0000003091 00000 n
+0000003503 00000 n
+0000003524 00000 n
+0000003936 00000 n
+0000003980 00000 n
+0000004214 00000 n
+trailer <<
+ /Root 1 0 R
+ /Size 24
+ /ID [<55269d37282af9edc76855e4cb859987><5044e8073c04a0be007e587c761cce26>]
+>>
+startxref
+4235
+%%EOF
diff --git a/qpdf/qtest/qpdf/form-xobjects-some-resources2-out.pdf b/qpdf/qtest/qpdf/form-xobjects-some-resources2-out.pdf
new file mode 100644
index 00000000..2b54914b
--- /dev/null
+++ b/qpdf/qtest/qpdf/form-xobjects-some-resources2-out.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/form-xobjects-some-resources2.out b/qpdf/qtest/qpdf/form-xobjects-some-resources2.out
new file mode 100644
index 00000000..a21ab495
--- /dev/null
+++ b/qpdf/qtest/qpdf/form-xobjects-some-resources2.out
@@ -0,0 +1,3 @@
+WARNING: form-xobjects-some-resources2.pdf, stream object 6 0: Unresolved names found while scanning content stream; not attempting to remove unreferenced objects from this object
+WARNING: form-xobjects-some-resources2.pdf, stream object 8 0: Unresolved names found while scanning content stream; not attempting to remove unreferenced objects from this object
+qpdf: operation succeeded with warnings; resulting file may have some problems
diff --git a/qpdf/qtest/qpdf/form-xobjects-some-resources2.pdf b/qpdf/qtest/qpdf/form-xobjects-some-resources2.pdf
new file mode 100644
index 00000000..7f722877
--- /dev/null
+++ b/qpdf/qtest/qpdf/form-xobjects-some-resources2.pdf
@@ -0,0 +1,336 @@
+%PDF-1.3
+%¿÷¢þ
+%QDF-1.0
+
+1 0 obj
+<<
+ /Pages 2 0 R
+ /Type /Catalog
+>>
+endobj
+
+2 0 obj
+<<
+ /Count 1
+ /Kids [
+ 3 0 R
+ ]
+ /Resources <<
+ /Font <<
+ /F1 4 0 R
+ >>
+ /ProcSet 5 0 R
+ /XObject <<
+ /Fx1 6 0 R
+ /Fx2 8 0 R
+ /Im1 10 0 R
+ /Im2 12 0 R
+ /Im3 14 0 R
+ /Im4 16 0 R
+ /Im6 20 0 R
+ /ImX 20 0 R
+ >>
+ >>
+ /Type /Pages
+>>
+endobj
+
+%% Page 1
+3 0 obj
+<<
+ /Contents 22 0 R
+ /MediaBox [
+ 0
+ 0
+ 612
+ 792
+ ]
+ /Parent 2 0 R
+ /Type /Page
+>>
+endobj
+
+4 0 obj
+<<
+ /BaseFont /Helvetica
+ /Encoding /WinAnsiEncoding
+ /Name /F1
+ /Subtype /Type1
+ /Type /Font
+>>
+endobj
+
+5 0 obj
+[
+ /PDF
+ /Text
+ /ImageC
+]
+endobj
+
+6 0 obj
+<<
+ /BBox [
+ 0
+ 0
+ 300
+ 500
+ ]
+ /Subtype /Form
+ /Type /XObject
+ /Length 7 0 R
+ /Resources <<
+ /XObject <<
+ /Im5 18 0 R
+ /ImY 20 0 R
+ >>
+ >>
+>>
+stream
+BT
+ /F1 24 Tf
+ 0 320 Td
+ (FX1) Tj
+ET
+q
+100 0 0 100 000 200 cm
+/Im3 Do
+Q
+q
+100 0 0 100 120 200 cm
+/Im4 Do
+Q
+q
+1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm
+/Fx2 Do
+Q
+endstream
+endobj
+
+7 0 obj
+173
+endobj
+
+8 0 obj
+<<
+ /BBox [
+ 0
+ 0
+ 300
+ 200
+ ]
+ /Subtype /Form
+ /Type /XObject
+ /Length 9 0 R
+ /Resources <<
+ /XObject <<
+ /Im1 20 0 R
+ /ImZ 20 0 R
+ >>
+ >>
+>>
+stream
+BT
+ /F1 24 Tf
+ 0 120 Td
+ (FX2) Tj
+ET
+q
+100 0 0 100 0 0 cm
+/Im5 Do
+Q
+q
+100 0 0 100 120 0 cm
+/Im1 Do
+Q
+endstream
+endobj
+
+9 0 obj
+104
+endobj
+
+10 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 11 0 R
+>>
+stream
+`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+11 0 obj
+225
+endobj
+
+12 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 13 0 R
+>>
+stream
+@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+13 0 obj
+225
+endobj
+
+14 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 15 0 R
+>>
+stream
+@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+15 0 obj
+225
+endobj
+
+16 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 17 0 R
+>>
+stream
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+17 0 obj
+225
+endobj
+
+18 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 19 0 R
+>>
+stream
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+19 0 obj
+225
+endobj
+
+20 0 obj
+<<
+ /BitsPerComponent 8
+ /ColorSpace /DeviceGray
+ /Height 15
+ /Subtype /Image
+ /Type /XObject
+ /Width 15
+ /Length 21 0 R
+>>
+stream
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@`````@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+endstream
+endobj
+
+%QDF: ignore_newline
+21 0 obj
+225
+endobj
+
+%% Contents for page 1
+22 0 obj
+<<
+ /Length 23 0 R
+>>
+stream
+BT
+ /F1 24 Tf
+ 72 720 Td
+ (Page) Tj
+ET
+q
+100 0 0 100 72 600 cm
+/Im1 Do
+Q
+q
+100 0 0 100 192 600 cm
+/Im2 Do
+Q
+q
+1.00000 0.00000 0.00000 1.00000 72.00000 200.00000 cm
+/Fx1 Do
+Q
+endstream
+endobj
+
+23 0 obj
+177
+endobj
+
+xref
+0 24
+0000000000 65535 f
+0000000025 00000 n
+0000000079 00000 n
+0000000402 00000 n
+0000000519 00000 n
+0000000637 00000 n
+0000000682 00000 n
+0000001066 00000 n
+0000001086 00000 n
+0000001401 00000 n
+0000001421 00000 n
+0000001833 00000 n
+0000001854 00000 n
+0000002266 00000 n
+0000002287 00000 n
+0000002699 00000 n
+0000002720 00000 n
+0000003132 00000 n
+0000003153 00000 n
+0000003565 00000 n
+0000003586 00000 n
+0000003998 00000 n
+0000004042 00000 n
+0000004276 00000 n
+trailer <<
+ /Root 1 0 R
+ /Size 24
+ /ID [<55269d37282af9edc76855e4cb859987><5044e8073c04a0be007e587c761cce26>]
+>>
+startxref
+4297
+%%EOF
diff --git a/qpdf/qtest/qpdf/shared-images-errors-2.out b/qpdf/qtest/qpdf/shared-images-errors-2.out
index eda5851a..5e00a7a7 100644
--- a/qpdf/qtest/qpdf/shared-images-errors-2.out
+++ b/qpdf/qtest/qpdf/shared-images-errors-2.out
@@ -1,5 +1,5 @@
WARNING: shared-images-errors.pdf (offset 4933): error decoding stream data for object 19 0: stream inflate: inflate: data: incorrect header check
-WARNING: shared-images-errors.pdf, object 4 0 at offset 676: Unable to parse content stream: content stream (content stream object 19 0): errors while decoding content stream; not attempting to remove unreferenced objects from this page
+WARNING: shared-images-errors.pdf, object 4 0 at offset 676: Unable to parse content stream: content stream (content stream object 19 0): errors while decoding content stream; not attempting to remove unreferenced objects from this object
WARNING: shared-images-errors.pdf (offset 4933): error decoding stream data for object 19 0: stream inflate: inflate: data: incorrect header check
WARNING: shared-images-errors.pdf (offset 4933): stream will be re-processed without filtering to avoid data loss
qpdf: operation succeeded with warnings; resulting file may have some problems
diff --git a/qpdf/qtest/qpdf/split-tokens-split.out b/qpdf/qtest/qpdf/split-tokens-split.out
index 7b940622..ab9f3b7a 100644
--- a/qpdf/qtest/qpdf/split-tokens-split.out
+++ b/qpdf/qtest/qpdf/split-tokens-split.out
@@ -1,4 +1,4 @@
-WARNING: split-tokens.pdf, object 3 0 at offset 181: Bad token found while scanning content stream; not attempting to remove unreferenced objects from this page
+WARNING: split-tokens.pdf, object 3 0 at offset 181: Bad token found while scanning content stream; not attempting to remove unreferenced objects from this object
WARNING: empty PDF: content normalization encountered bad tokens
WARNING: empty PDF: normalized content ended with a bad token; you may be able to resolve this by coalescing content streams in combination with normalizing content. From the command line, specify --coalesce-contents
WARNING: empty PDF: Resulting stream data may be corrupted but is may still useful for manual inspection. For more information on this warning, search for content normalization in the manual.