mirror of https://github.com/qpdf/qpdf.git
Add transformAnnotations and fix flattenRotations to use it
This commit is contained in:
parent
a76decd2d5
commit
a9ae8cadc6
|
@ -1,5 +1,11 @@
|
|||
2021-02-21 Jay Berkenbilt <ejb@ql.org>
|
||||
|
||||
* Bug fix: --flatten-rotation now applies the required
|
||||
transformation to annotations on the page.
|
||||
|
||||
* Add QPDFAcroFormDocumentHelper::transformAnnotations to apply a
|
||||
transformation to a group of annotations.
|
||||
|
||||
* Add QPDFObjGen::unparse()
|
||||
|
||||
* Add QPDFObjectHandle::copyStream() for making a copy of a stream
|
||||
|
|
|
@ -113,6 +113,10 @@ class QPDFAcroFormDocumentHelper: public QPDFDocumentHelper
|
|||
QPDF_DLL
|
||||
void addFormField(QPDFFormFieldObjectHelper);
|
||||
|
||||
// Remove fields from the fields array
|
||||
QPDF_DLL
|
||||
void removeFormFields(std::set<QPDFObjGen> const&);
|
||||
|
||||
// Return a vector of all terminal fields in a document. Terminal
|
||||
// fields are fields that have no children that are also fields.
|
||||
// Terminal fields may still have children that are annotations.
|
||||
|
@ -174,6 +178,32 @@ class QPDFAcroFormDocumentHelper: public QPDFDocumentHelper
|
|||
QPDF_DLL
|
||||
void generateAppearancesIfNeeded();
|
||||
|
||||
// Note: this method works on all annotations, not just ones with
|
||||
// associated fields. For each annotation in old_annots, apply the
|
||||
// given transformation matrix to create a new annotation. New
|
||||
// annotations are appended to new_annots. If the annotation is
|
||||
// associated with a form field, a new form field is created that
|
||||
// points to the new annotation and is appended to new_fields, and
|
||||
// the old field is added to old_fields.
|
||||
//
|
||||
// old_annots may belong to a different QPDF object. In that case,
|
||||
// you should pass in from_qpdf, and copyForeignObject will be
|
||||
// called automatically. If this is the case, for efficiency, you
|
||||
// may pass in a QPDFAcroFormDocumentHelper for the other file to
|
||||
// avoid the expensive process of creating one for each call to
|
||||
// transformAnnotations. New fields and annotations are not added
|
||||
// to the document or pages. You have to do that yourself after
|
||||
// calling transformAnnotations.
|
||||
QPDF_DLL
|
||||
void transformAnnotations(
|
||||
QPDFObjectHandle old_annots,
|
||||
std::vector<QPDFObjectHandle>& new_annots,
|
||||
std::vector<QPDFObjectHandle>& new_fields,
|
||||
std::set<QPDFObjGen>& old_fields,
|
||||
QPDFMatrix const& cm,
|
||||
QPDF* from_qpdf = nullptr,
|
||||
QPDFAcroFormDocumentHelper* from_afdh = nullptr);
|
||||
|
||||
private:
|
||||
void analyze();
|
||||
void traverseField(QPDFObjectHandle field,
|
||||
|
|
|
@ -40,6 +40,13 @@ class QPDFAnnotationObjectHelper: public QPDFObjectHelper
|
|||
// This class provides helper methods for annotations. More
|
||||
// functionality will likely be added in the future.
|
||||
|
||||
// Some functionality for annotations is also implemented in
|
||||
// QPDFAcroFormDocumentHelper and QPDFFormFieldObjectHelper. In
|
||||
// some cases, functions defined there work for other annotations
|
||||
// besides widget annotations, but they are implemented with form
|
||||
// fields so that they can properly handle form fields when
|
||||
// needed.
|
||||
|
||||
// Return the subtype of the annotation as a string (e.g.
|
||||
// "/Widget"). Returns the empty string if the subtype (which is
|
||||
// required by the spec) is missing.
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include <qpdf/QPDFObjectHandle.hh>
|
||||
#include <functional>
|
||||
|
||||
class QPDFAcroFormDocumentHelper;
|
||||
|
||||
class QPDFPageObjectHelper: public QPDFObjectHelper
|
||||
{
|
||||
// This is a helper class for page objects, but as of qpdf 10.1,
|
||||
|
@ -323,9 +325,15 @@ class QPDFPageObjectHelper: public QPDFObjectHelper
|
|||
// various page bounding boxes (/MediaBox, etc.) so that the page
|
||||
// will have the same semantics. This can be useful to work around
|
||||
// problems with PDF applications that can't properly handle
|
||||
// rotated pages.
|
||||
// rotated pages. If a QPDFAcroFormDocumentHelper is provided, it
|
||||
// will be used for resolving any form fields that have to be
|
||||
// rotated. If not, one will be created inside the function, which
|
||||
// is less efficient.
|
||||
QPDF_DLL
|
||||
void flattenRotation();
|
||||
// ABI: merge versions and make afdh default to nullptr
|
||||
QPDF_DLL
|
||||
void flattenRotation(QPDFAcroFormDocumentHelper* afdh);
|
||||
|
||||
private:
|
||||
static bool
|
||||
|
|
|
@ -54,6 +54,50 @@ QPDFAcroFormDocumentHelper::addFormField(QPDFFormFieldObjectHelper ff)
|
|||
ff.getObjectHandle(), QPDFObjectHandle::newNull(), 0, visited);
|
||||
}
|
||||
|
||||
void
|
||||
QPDFAcroFormDocumentHelper::removeFormFields(
|
||||
std::set<QPDFObjGen> const& to_remove)
|
||||
{
|
||||
auto acroform = this->qpdf.getRoot().getKey("/AcroForm");
|
||||
if (! acroform.isDictionary())
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto fields = acroform.getKey("/Fields");
|
||||
if (! fields.isArray())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto const& og: to_remove)
|
||||
{
|
||||
auto annotations = this->m->field_to_annotations.find(og);
|
||||
if (annotations != this->m->field_to_annotations.end())
|
||||
{
|
||||
for (auto aoh: annotations->second)
|
||||
{
|
||||
this->m->annotation_to_field.erase(
|
||||
aoh.getObjectHandle().getObjGen());
|
||||
}
|
||||
this->m->field_to_annotations.erase(og);
|
||||
}
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while (i < fields.getArrayNItems())
|
||||
{
|
||||
auto field = fields.getArrayItem(i);
|
||||
if (to_remove.count(field.getObjGen()))
|
||||
{
|
||||
fields.eraseItem(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<QPDFFormFieldObjectHelper>
|
||||
QPDFAcroFormDocumentHelper::getFormFields()
|
||||
{
|
||||
|
@ -350,3 +394,273 @@ QPDFAcroFormDocumentHelper::generateAppearancesIfNeeded()
|
|||
}
|
||||
setNeedAppearances(false);
|
||||
}
|
||||
|
||||
void
|
||||
QPDFAcroFormDocumentHelper::transformAnnotations(
|
||||
QPDFObjectHandle old_annots,
|
||||
std::vector<QPDFObjectHandle>& new_annots,
|
||||
std::vector<QPDFObjectHandle>& new_fields,
|
||||
std::set<QPDFObjGen>& old_fields,
|
||||
QPDFMatrix const& cm,
|
||||
QPDF* from_qpdf,
|
||||
QPDFAcroFormDocumentHelper* from_afdh)
|
||||
{
|
||||
PointerHolder<QPDFAcroFormDocumentHelper> afdhph;
|
||||
if (! from_qpdf)
|
||||
{
|
||||
// Assume these are from the same QPDF.
|
||||
from_qpdf = &this->qpdf;
|
||||
from_afdh = this;
|
||||
}
|
||||
else if ((from_qpdf != &this->qpdf) && (! from_afdh))
|
||||
{
|
||||
afdhph = new QPDFAcroFormDocumentHelper(*from_qpdf);
|
||||
from_afdh = afdhph.getPointer();
|
||||
}
|
||||
bool foreign = (from_qpdf != &this->qpdf);
|
||||
|
||||
std::set<QPDFObjGen> added_new_fields;
|
||||
|
||||
// This helper prevents us from copying the same object
|
||||
// multiple times.
|
||||
std::map<QPDFObjGen, QPDFObjectHandle> copied_objects;
|
||||
auto maybe_copy_object = [&](QPDFObjectHandle& to_copy) {
|
||||
auto og = to_copy.getObjGen();
|
||||
if (copied_objects.count(og))
|
||||
{
|
||||
to_copy = copied_objects[og];
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
to_copy = this->qpdf.makeIndirectObject(to_copy.shallowCopy());
|
||||
copied_objects[og] = to_copy;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
for (auto annot: QPDFArrayItems(old_annots))
|
||||
{
|
||||
if (annot.isStream())
|
||||
{
|
||||
annot.warnIfPossible("ignoring annotation that's a stream");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make copies of annotations and fields down to the
|
||||
// appearance streams, preserving all internal referential
|
||||
// integrity. When the incoming annotations are from a
|
||||
// different file, we first copy them locally. Then, whether
|
||||
// local or foreign, we copy them again so that if we bring
|
||||
// the same annotation in multiple times (e.g. overlaying a
|
||||
// foreign page onto multiple local pages or a local page onto
|
||||
// multiple other local pages), we don't create annotations
|
||||
// that are referenced in more than one place. If we did that,
|
||||
// the effect of applying transformations would be cumulative,
|
||||
// which is definitely not what we want. Besides, annotations
|
||||
// and fields are not intended to be referenced in multiple
|
||||
// places.
|
||||
|
||||
// Determine if this annotation is attached to a form field.
|
||||
// If so, the annotation may be the same object as the form
|
||||
// field, or the form field may have the annotation as a kid.
|
||||
// In either case, we have to walk up the field structure to
|
||||
// find the top-level field. Within one iteration through a
|
||||
// set of annotations, we don't want to copy the same item
|
||||
// more than once. For example, suppose we have field A with
|
||||
// kids B, C, and D, each of which has annotations BA, CA, and
|
||||
// DA. When we get to BA, we will find that BA is a kid of B
|
||||
// which is under A. When we do a copyForeignObject of A, it
|
||||
// will also copy everything else because of the indirect
|
||||
// references. When we clone BA, we will want to clone A and
|
||||
// then update A's clone's kid to point B's clone and B's
|
||||
// clone's parent to point to A's clone. The same thing holds
|
||||
// for annotatons. Next, when we get to CA, we will again
|
||||
// discover that A is the top, but we don't want to re-copy A.
|
||||
// We want CA's clone to be linked to the same clone as BA's.
|
||||
// Failure to do this will break up things like radio button
|
||||
// groups, which all have to kids of the same parent.
|
||||
|
||||
auto ffield = from_afdh->getFieldForAnnotation(annot);
|
||||
auto ffield_oh = ffield.getObjectHandle();
|
||||
QPDFObjectHandle top_field;
|
||||
bool have_field = false;
|
||||
bool have_parent = false;
|
||||
if (ffield_oh.isStream())
|
||||
{
|
||||
ffield_oh.warnIfPossible("ignoring form field that's a stream");
|
||||
}
|
||||
else if ((! ffield_oh.isNull()) && (! ffield_oh.isIndirect()))
|
||||
{
|
||||
ffield_oh.warnIfPossible("ignoring form field not indirect");
|
||||
}
|
||||
else if (! ffield_oh.isNull())
|
||||
{
|
||||
// A field and its associated annotation can be the same
|
||||
// object. This matters because we don't want to clone the
|
||||
// annotation and field separately in this case.
|
||||
have_field = true;
|
||||
// Find the top-level field. It may be the field itself.
|
||||
top_field = ffield_oh;
|
||||
std::set<QPDFObjGen> seen;
|
||||
while (! top_field.getKey("/Parent").isNull())
|
||||
{
|
||||
top_field = top_field.getKey("/Parent");
|
||||
have_parent = true;
|
||||
auto og = top_field.getObjGen();
|
||||
if (seen.count(og))
|
||||
{
|
||||
break;
|
||||
}
|
||||
seen.insert(og);
|
||||
}
|
||||
if (foreign)
|
||||
{
|
||||
// copyForeignObject returns the same value if called
|
||||
// multiple times with the same field. Create/retrieve
|
||||
// the local copy of the original field. This pulls
|
||||
// over everything the field references including
|
||||
// annotations and appearance streams, but it's
|
||||
// harmless to call copyForeignObject on them too.
|
||||
// They will already be copied, so we'll get the right
|
||||
// object back.
|
||||
|
||||
top_field = this->qpdf.copyForeignObject(top_field);
|
||||
ffield_oh = this->qpdf.copyForeignObject(ffield_oh);
|
||||
}
|
||||
old_fields.insert(top_field.getObjGen());
|
||||
|
||||
// Traverse the field, copying kids, and preserving
|
||||
// integrity.
|
||||
std::list<QPDFObjectHandle> queue;
|
||||
if (maybe_copy_object(top_field))
|
||||
{
|
||||
queue.push_back(top_field);
|
||||
}
|
||||
seen.clear();
|
||||
while (! queue.empty())
|
||||
{
|
||||
QPDFObjectHandle obj = queue.front();
|
||||
queue.pop_front();
|
||||
auto orig_og = obj.getObjGen();
|
||||
if (seen.count(orig_og))
|
||||
{
|
||||
// loop
|
||||
break;
|
||||
}
|
||||
seen.insert(orig_og);
|
||||
auto parent = obj.getKey("/Parent");
|
||||
if (parent.isIndirect())
|
||||
{
|
||||
auto parent_og = parent.getObjGen();
|
||||
if (copied_objects.count(parent_og))
|
||||
{
|
||||
obj.replaceKey("/Parent", copied_objects[parent_og]);
|
||||
}
|
||||
else
|
||||
{
|
||||
parent.warnIfPossible(
|
||||
"while traversing field " +
|
||||
obj.getObjGen().unparse() +
|
||||
", found parent (" + parent_og.unparse() +
|
||||
") that had not been seen, indicating likely"
|
||||
" invalid field structure");
|
||||
}
|
||||
}
|
||||
auto kids = obj.getKey("/Kids");
|
||||
if (kids.isArray())
|
||||
{
|
||||
for (int i = 0; i < kids.getArrayNItems(); ++i)
|
||||
{
|
||||
auto kid = kids.getArrayItem(i);
|
||||
if (maybe_copy_object(kid))
|
||||
{
|
||||
kids.setArrayItem(i, kid);
|
||||
queue.push_back(kid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now switch to copies. We already switched for top_field
|
||||
maybe_copy_object(ffield_oh);
|
||||
ffield = QPDFFormFieldObjectHelper(ffield_oh);
|
||||
}
|
||||
|
||||
QTC::TC("qpdf", "QPDFAcroFormDocumentHelper copy annotation",
|
||||
(have_field ? 1 : 0) | (foreign ? 2 : 0));
|
||||
if (have_field)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDFAcroFormDocumentHelper field with parent",
|
||||
(have_parent ? 1 : 0) | (foreign ? 2 : 0));
|
||||
}
|
||||
if (foreign)
|
||||
{
|
||||
annot = this->qpdf.copyForeignObject(annot);
|
||||
}
|
||||
maybe_copy_object(annot);
|
||||
|
||||
// Now we have copies, so we can safely mutate.
|
||||
if (have_field && ! added_new_fields.count(top_field.getObjGen()))
|
||||
{
|
||||
new_fields.push_back(top_field);
|
||||
added_new_fields.insert(top_field.getObjGen());
|
||||
}
|
||||
new_annots.push_back(annot);
|
||||
|
||||
// Identify and copy any appearance streams
|
||||
|
||||
auto ah = QPDFAnnotationObjectHelper(annot);
|
||||
auto apdict = ah.getAppearanceDictionary();
|
||||
std::vector<QPDFObjectHandle> streams;
|
||||
auto replace_stream = [](auto& dict, auto& key, auto& old) {
|
||||
auto new_stream = old.copyStream();
|
||||
dict.replaceKey(key, new_stream);
|
||||
return new_stream;
|
||||
};
|
||||
if (apdict.isDictionary())
|
||||
{
|
||||
for (auto& ap: QPDFDictItems(apdict))
|
||||
{
|
||||
if (ap.second.isStream())
|
||||
{
|
||||
streams.push_back(
|
||||
replace_stream(apdict, ap.first, ap.second));
|
||||
}
|
||||
else if (ap.second.isDictionary())
|
||||
{
|
||||
for (auto& ap2: QPDFDictItems(ap.second))
|
||||
{
|
||||
if (ap2.second.isStream())
|
||||
{
|
||||
streams.push_back(
|
||||
replace_stream(
|
||||
ap.second, ap2.first, ap2.second));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now we can safely mutate the annotation and its appearance
|
||||
// streams.
|
||||
for (auto& stream: streams)
|
||||
{
|
||||
auto omatrix = stream.getDict().getKey("/Matrix");
|
||||
QPDFMatrix apcm;
|
||||
if (omatrix.isArray())
|
||||
{
|
||||
QTC::TC("qpdf", "QPDFAcroFormDocumentHelper modify ap matrix");
|
||||
auto m1 = omatrix.getArrayAsMatrix();
|
||||
apcm = QPDFMatrix(m1);
|
||||
}
|
||||
apcm.concat(cm);
|
||||
auto new_matrix = QPDFObjectHandle::newFromMatrix(apcm);
|
||||
stream.getDict().replaceKey("/Matrix", new_matrix);
|
||||
}
|
||||
auto rect = cm.transformRectangle(
|
||||
annot.getKey("/Rect").getArrayAsRectangle());
|
||||
annot.replaceKey(
|
||||
"/Rect", QPDFObjectHandle::newFromRectangle(rect));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <qpdf/QPDFExc.hh>
|
||||
#include <qpdf/QPDFMatrix.hh>
|
||||
#include <qpdf/QIntC.hh>
|
||||
#include <qpdf/QPDFAcroFormDocumentHelper.hh>
|
||||
|
||||
class ContentProvider: public QPDFObjectHandle::StreamDataProvider
|
||||
{
|
||||
|
@ -1080,6 +1081,12 @@ QPDFPageObjectHelper::placeFormXObject(
|
|||
|
||||
void
|
||||
QPDFPageObjectHelper::flattenRotation()
|
||||
{
|
||||
flattenRotation(nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh)
|
||||
{
|
||||
QPDF* qpdf = this->oh.getOwningQPDF();
|
||||
if (! qpdf)
|
||||
|
@ -1206,4 +1213,26 @@ QPDFPageObjectHelper::flattenRotation()
|
|||
QTC::TC("qpdf", "QPDFPageObjectHelper flatten inherit rotate");
|
||||
this->oh.replaceKey("/Rotate", QPDFObjectHandle::newInteger(0));
|
||||
}
|
||||
|
||||
QPDFObjectHandle annots = this->oh.getKey("/Annots");
|
||||
if (annots.isArray())
|
||||
{
|
||||
std::vector<QPDFObjectHandle> new_annots;
|
||||
std::vector<QPDFObjectHandle> new_fields;
|
||||
std::set<QPDFObjGen> old_fields;
|
||||
PointerHolder<QPDFAcroFormDocumentHelper> afdhph;
|
||||
if (! afdh)
|
||||
{
|
||||
afdhph = new QPDFAcroFormDocumentHelper(*qpdf);
|
||||
afdh = afdhph.getPointer();
|
||||
}
|
||||
afdh->transformAnnotations(
|
||||
annots, new_annots, new_fields, old_fields, cm);
|
||||
afdh->removeFormFields(old_fields);
|
||||
for (auto const& f: new_fields)
|
||||
{
|
||||
afdh->addFormField(QPDFFormFieldObjectHelper(f));
|
||||
}
|
||||
this->oh.replaceKey("/Annots", QPDFObjectHandle::newArray(new_annots));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5313,6 +5313,13 @@ print "\n";
|
|||
dictionary if needed.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Add method
|
||||
<function>QPDFAcroFormDocumentHelper::transformAnnotations</function>,
|
||||
which applies a transformation to each annotation on a page.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Add <function>QUtil::path_basename</function> to return the
|
||||
|
@ -5341,6 +5348,12 @@ print "\n";
|
|||
Bug Fixes
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
The <option>--flatten-rotations</option> option applies
|
||||
transformations to any annotations that may be on the page.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
If a form XObject lacks a resources dictionary, consider any
|
||||
|
|
14
qpdf/qpdf.cc
14
qpdf/qpdf.cc
|
@ -5362,6 +5362,13 @@ static void copy_attachments(QPDF& pdf, Options& o, int& exit_code)
|
|||
static void handle_transformations(QPDF& pdf, Options& o, int& exit_code)
|
||||
{
|
||||
QPDFPageDocumentHelper dh(pdf);
|
||||
PointerHolder<QPDFAcroFormDocumentHelper> afdh;
|
||||
auto make_afdh = [&]() {
|
||||
if (! afdh.getPointer())
|
||||
{
|
||||
afdh = new QPDFAcroFormDocumentHelper(pdf);
|
||||
}
|
||||
};
|
||||
if (o.externalize_inline_images)
|
||||
{
|
||||
std::vector<QPDFPageObjectHelper> pages = dh.getAllPages();
|
||||
|
@ -5408,8 +5415,8 @@ static void handle_transformations(QPDF& pdf, Options& o, int& exit_code)
|
|||
}
|
||||
if (o.generate_appearances)
|
||||
{
|
||||
QPDFAcroFormDocumentHelper afdh(pdf);
|
||||
afdh.generateAppearancesIfNeeded();
|
||||
make_afdh();
|
||||
afdh->generateAppearancesIfNeeded();
|
||||
}
|
||||
if (o.flatten_annotations)
|
||||
{
|
||||
|
@ -5427,9 +5434,10 @@ static void handle_transformations(QPDF& pdf, Options& o, int& exit_code)
|
|||
}
|
||||
if (o.flatten_rotation)
|
||||
{
|
||||
make_afdh();
|
||||
for (auto& page: dh.getAllPages())
|
||||
{
|
||||
page.flattenRotation();
|
||||
page.flattenRotation(afdh.getPointer());
|
||||
}
|
||||
}
|
||||
if (o.remove_page_labels)
|
||||
|
|
|
@ -572,3 +572,6 @@ qpdf password file 0
|
|||
QPDFFileSpecObjectHelper empty compat_name 0
|
||||
QPDFFileSpecObjectHelper non-empty compat_name 0
|
||||
QPDFPageObjectHelper flatten inherit rotate 0
|
||||
QPDFAcroFormDocumentHelper copy annotation 1
|
||||
QPDFAcroFormDocumentHelper field with parent 1
|
||||
QPDFAcroFormDocumentHelper modify ap matrix 0
|
||||
|
|
|
@ -2248,7 +2248,7 @@ $td->runtest("explicit keep files open = n",
|
|||
show_ntests();
|
||||
# ----------
|
||||
$td->notify("--- Rotate Pages ---");
|
||||
$n_tests += 8;
|
||||
$n_tests += 18;
|
||||
# Do absolute, positive, and negative on ranges that include
|
||||
# inherited and non-inherited.
|
||||
# Pages 11-15 inherit /Rotate 90
|
||||
|
@ -2290,6 +2290,49 @@ $td->runtest("check output",
|
|||
{$td->FILE => "a.pdf"},
|
||||
{$td->FILE => "inherited-flattened.pdf"});
|
||||
|
||||
foreach my $angle (qw(90 180 270))
|
||||
{
|
||||
$td->runtest("rotate annotations",
|
||||
{$td->COMMAND =>
|
||||
"qpdf --static-id --qdf --rotate=$angle" .
|
||||
" --flatten-rotation --no-original-object-ids" .
|
||||
" form-fields-and-annotations.pdf a.pdf"},
|
||||
{$td->STRING => "", $td->EXIT_STATUS => 0});
|
||||
$td->runtest("check output (flatten $angle)",
|
||||
{$td->FILE => "a.pdf"},
|
||||
{$td->FILE => "annotations-rotated-$angle.pdf"});
|
||||
}
|
||||
|
||||
# The file form-fields-and-annotations-shared.pdf contains some
|
||||
# annotations that appear in multiple pages /Annots, some non-shared
|
||||
# things that share appearance streams, some form fields appear on
|
||||
# multiple pages, and an indirect /Annotations array. It is out of
|
||||
# spec in several ways but still works in most viewers. These test
|
||||
# make sure we don't make anything worse and also end up exercising
|
||||
# some cases of things being copied more than once, though we also
|
||||
# exercise that with legitimate test cases using overlay.
|
||||
|
||||
$td->runtest("shared annotations 1 page",
|
||||
{$td->COMMAND =>
|
||||
"qpdf --qdf --no-original-object-ids --static-id" .
|
||||
" --rotate=90:1 form-fields-and-annotations-shared.pdf" .
|
||||
" a.pdf --flatten-rotation"},
|
||||
{$td->STRING => "", $td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
$td->runtest("check output",
|
||||
{$td->FILE => "a.pdf"},
|
||||
{$td->FILE => "rotated-shared-annotations-1.pdf"});
|
||||
$td->runtest("shared annotations 2 pages",
|
||||
{$td->COMMAND =>
|
||||
"qpdf --qdf --no-original-object-ids --static-id" .
|
||||
" --rotate=90:1,2 form-fields-and-annotations-shared.pdf" .
|
||||
" a.pdf --flatten-rotation"},
|
||||
{$td->STRING => "", $td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
$td->runtest("check output",
|
||||
{$td->FILE => "a.pdf"},
|
||||
{$td->FILE => "rotated-shared-annotations-2.pdf"});
|
||||
|
||||
show_ntests();
|
||||
# ----------
|
||||
$td->notify("--- Flatten Form/Annotations ---");
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,942 @@
|
|||
%PDF-1.6
|
||||
%¿÷¢þ
|
||||
%QDF-1.0
|
||||
|
||||
1 0 obj
|
||||
<<
|
||||
/AcroForm <<
|
||||
/DR 2 0 R
|
||||
/Fields [
|
||||
3 0 R
|
||||
4 0 R
|
||||
5 0 R
|
||||
]
|
||||
>>
|
||||
/Names <<
|
||||
/EmbeddedFiles 6 0 R
|
||||
>>
|
||||
/Pages 7 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<<
|
||||
/Font <<
|
||||
/F1 8 0 R
|
||||
>>
|
||||
>>
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
<<
|
||||
/AP <<
|
||||
/N 9 0 R
|
||||
>>
|
||||
/DA (0 0.4 0 rg /F1 18 Tf)
|
||||
/DR 2 0 R
|
||||
/DV ()
|
||||
/FT /Tx
|
||||
/Ff 0
|
||||
/Rect [
|
||||
72
|
||||
470.774
|
||||
190.8
|
||||
484.922
|
||||
]
|
||||
/Subtype /Widget
|
||||
/T (Text Box 1)
|
||||
/Type /Annot
|
||||
/V (Formy field)
|
||||
>>
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<<
|
||||
/AP <<
|
||||
/N 11 0 R
|
||||
>>
|
||||
/DA (0 0.4 0 rg /F1 18 Tf)
|
||||
/DR 2 0 R
|
||||
/DV ()
|
||||
/FT /Tx
|
||||
/Ff 0
|
||||
/Rect [
|
||||
372
|
||||
330.774
|
||||
386.148
|
||||
470.374
|
||||
]
|
||||
/Subtype /Widget
|
||||
/T (Text Box 1)
|
||||
/Type /Annot
|
||||
/V (Rot-ccw field)
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<<
|
||||
/DV /1
|
||||
/FT /Btn
|
||||
/Ff 49152
|
||||
/Kids [
|
||||
13 0 R
|
||||
14 0 R
|
||||
15 0 R
|
||||
]
|
||||
/T (r1)
|
||||
/V /2
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<<
|
||||
/Names [
|
||||
(attachment1.txt)
|
||||
16 0 R
|
||||
]
|
||||
>>
|
||||
endobj
|
||||
|
||||
7 0 obj
|
||||
<<
|
||||
/Count 1
|
||||
/Kids [
|
||||
17 0 R
|
||||
]
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
8 0 obj
|
||||
<<
|
||||
/BaseFont /Courier
|
||||
/Encoding /WinAnsiEncoding
|
||||
/Subtype /Type1
|
||||
/Type /Font
|
||||
>>
|
||||
endobj
|
||||
|
||||
9 0 obj
|
||||
<<
|
||||
/BBox [
|
||||
0
|
||||
-2.826
|
||||
118.8
|
||||
11.322
|
||||
]
|
||||
/Resources 2 0 R
|
||||
/Subtype /Form
|
||||
/Type /XObject
|
||||
/Length 10 0 R
|
||||
>>
|
||||
stream
|
||||
/Tx BMC
|
||||
q
|
||||
BT
|
||||
/F1 18 Tf
|
||||
(Formy field) Tj
|
||||
ET
|
||||
Q
|
||||
EMC
|
||||
endstream
|
||||
endobj
|
||||
|
||||
10 0 obj
|
||||
53
|
||||
endobj
|
||||
|
||||
11 0 obj
|
||||
<<
|
||||
/BBox [
|
||||
0
|
||||
-2.826
|
||||
140.4
|
||||
11.322
|
||||
]
|
||||
/Matrix [
|
||||
0
|
||||
1
|
||||
-1
|
||||
0
|
||||
0
|
||||
0
|
||||
]
|
||||
/Resources 2 0 R
|
||||
/Subtype /Form
|
||||
/Type /XObject
|
||||
/Length 12 0 R
|
||||
>>
|
||||
stream
|
||||
/Tx BMC
|
||||
q
|
||||
BT
|
||||
/F1 18 Tf
|
||||
(Rot-ccw field) Tj
|
||||
ET
|
||||
Q
|
||||
EMC
|
||||
endstream
|
||||
endobj
|
||||
|
||||
12 0 obj
|
||||
55
|
||||
endobj
|
||||
|
||||
13 0 obj
|
||||
<<
|
||||
/AP <<
|
||||
/N <<
|
||||
/1 18 0 R
|
||||
/Off 20 0 R
|
||||
>>
|
||||
>>
|
||||
/AS /1
|
||||
/DA (0.18039 0.20392 0.21176 rg /ZaDi 0 Tf)
|
||||
/DR <<
|
||||
/Font <<
|
||||
/ZaDi 22 0 R
|
||||
>>
|
||||
>>
|
||||
/F 4
|
||||
/FT /Btn
|
||||
/MK <<
|
||||
/CA (l)
|
||||
>>
|
||||
/Parent 5 0 R
|
||||
/Rect [
|
||||
152.749
|
||||
648.501
|
||||
164.801
|
||||
660.549
|
||||
]
|
||||
/Subtype /Widget
|
||||
/Type /Annot
|
||||
>>
|
||||
endobj
|
||||
|
||||
14 0 obj
|
||||
<<
|
||||
/AP <<
|
||||
/N <<
|
||||
/2 23 0 R
|
||||
/Off 25 0 R
|
||||
>>
|
||||
>>
|
||||
/AS /2
|
||||
/DA (0.18039 0.20392 0.21176 rg /ZaDi 0 Tf)
|
||||
/DR <<
|
||||
/Font <<
|
||||
/ZaDi 22 0 R
|
||||
>>
|
||||
>>
|
||||
/F 4
|
||||
/FT /Btn
|
||||
/MK <<
|
||||
/CA (l)
|
||||
>>
|
||||
/Parent 5 0 R
|
||||
/Rect [
|
||||
152.749
|
||||
627.301
|
||||
164.801
|
||||
639.349
|
||||
]
|
||||
/Subtype /Widget
|
||||
/Type /Annot
|
||||
>>
|
||||
endobj
|
||||
|
||||
15 0 obj
|
||||
<<
|
||||
/AP <<
|
||||
/N <<
|
||||
/3 27 0 R
|
||||
/Off 29 0 R
|
||||
>>
|
||||
>>
|
||||
/AS /3
|
||||
/DA (0.18039 0.20392 0.21176 rg /ZaDi 0 Tf)
|
||||
/DR <<
|
||||
/Font <<
|
||||
/ZaDi 22 0 R
|
||||
>>
|
||||
>>
|
||||
/F 4
|
||||
/FT /Btn
|
||||
/MK <<
|
||||
/CA (l)
|
||||
>>
|
||||
/Parent 5 0 R
|
||||
/Rect [
|
||||
151.399
|
||||
606.501
|
||||
163.451
|
||||
618.549
|
||||
]
|
||||
/Subtype /Widget
|
||||
/Type /Annot
|
||||
>>
|
||||
endobj
|
||||
|
||||
16 0 obj
|
||||
<<
|
||||
/EF <<
|
||||
/F 31 0 R
|
||||
/UF 31 0 R
|
||||
>>
|
||||
/F (attachment1.txt)
|
||||
/Type /Filespec
|
||||
/UF (attachment1.txt)
|
||||
>>
|
||||
endobj
|
||||
|
||||
%% Page 1
|
||||
17 0 obj
|
||||
<<
|
||||
/Annots [
|
||||
33 0 R
|
||||
3 0 R
|
||||
34 0 R
|
||||
4 0 R
|
||||
35 0 R
|
||||
36 0 R
|
||||
37 0 R
|
||||
38 0 R
|
||||
13 0 R
|
||||
14 0 R
|
||||
15 0 R
|
||||
]
|
||||
/Contents 39 0 R
|
||||
/MediaBox [
|
||||
0
|
||||
0
|
||||
612
|
||||
792
|
||||
]
|
||||
/Parent 7 0 R
|
||||
/Resources 2 0 R
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
|
||||
18 0 obj
|
||||
<<
|
||||
/BBox [
|
||||
0
|
||||
0
|
||||
12.05
|
||||
12.05
|
||||
]
|
||||
/Resources 41 0 R
|
||||
/Subtype /Form
|
||||
/Type /XObject
|
||||
/Length 19 0 R
|
||||
>>
|
||||
stream
|
||||
/Tx BMC
|
||||
q BT
|
||||
0.18039 0.20392 0.21176 rg /ZaDi 12.05 Tf
|
||||
0 0 Td
|
||||
ET
|
||||
Q
|
||||
1 0 0 rg
|
||||
6 8.4 m 7.35 8.4 8.45 7.35 8.45 6 c
|
||||
8.45 4.65 7.35 3.55 6 3.55 c
|
||||
4.65 3.55 3.6 4.65 3.6 6 c
|
||||
3.6 7.35 4.65 8.4 6 8.4 c f*
|
||||
|
||||
EMC
|
||||
endstream
|
||||
endobj
|
||||
|
||||
19 0 obj
|
||||
202
|
||||
endobj
|
||||
|
||||
20 0 obj
|
||||
<<
|
||||
/BBox [
|
||||
0
|
||||
0
|
||||
12.05
|
||||
12.05
|
||||
]
|
||||
/Resources 41 0 R
|
||||
/Subtype /Form
|
||||
/Type /XObject
|
||||
/Length 21 0 R
|
||||
>>
|
||||
stream
|
||||
/Tx BMC
|
||||
EMC
|
||||
endstream
|
||||
endobj
|
||||
|
||||
21 0 obj
|
||||
12
|
||||
endobj
|
||||
|
||||
22 0 obj
|
||||
<<
|
||||
/BaseFont /ZapfDingbats
|
||||
/Subtype /Type1
|
||||
/Type /Font
|
||||
>>
|
||||
endobj
|
||||
|
||||
23 0 obj
|
||||
<<
|
||||
/BBox [
|
||||
0
|
||||
0
|
||||
12.05
|
||||
12.05
|
||||
]
|
||||
/Resources 41 0 R
|
||||
/Subtype /Form
|
||||
/Type /XObject
|
||||
/Length 24 0 R
|
||||
>>
|
||||
stream
|
||||
/Tx BMC
|
||||
q BT
|
||||
0.18039 0.20392 0.21176 rg /ZaDi 12.05 Tf
|
||||
0 0 Td
|
||||
ET
|
||||
Q
|
||||
0 1 0 rg
|
||||
6 8.4 m 7.35 8.4 8.45 7.35 8.45 6 c
|
||||
8.45 4.65 7.35 3.55 6 3.55 c
|
||||
4.65 3.55 3.6 4.65 3.6 6 c
|
||||
3.6 7.35 4.65 8.4 6 8.4 c f*
|
||||
|
||||
EMC
|
||||
endstream
|
||||
endobj
|
||||
|
||||
24 0 obj
|
||||
202
|
||||
endobj
|
||||
|
||||
25 0 obj
|
||||
<<
|
||||
/BBox [
|
||||
0
|
||||
0
|
||||
12.05
|
||||
12.05
|
||||
]
|
||||
/Resources 41 0 R
|
||||
/Subtype /Form
|
||||
/Type /XObject
|
||||
/Length 26 0 R
|
||||
>>
|
||||
stream
|
||||
/Tx BMC
|
||||
EMC
|
||||
endstream
|
||||
endobj
|
||||
|
||||
26 0 obj
|
||||
12
|
||||
endobj
|
||||
|
||||
27 0 obj
|
||||
<<
|
||||
/BBox [
|
||||
0
|
||||
0
|
||||
12.05
|
||||
12.05
|
||||
]
|
||||
/Resources 41 0 R
|
||||
/Subtype /Form
|
||||
/Type /XObject
|
||||
/Length 28 0 R
|
||||
>>
|
||||
stream
|
||||
/Tx BMC
|
||||
q BT
|
||||
0.18039 0.20392 0.21176 rg /ZaDi 12.05 Tf
|
||||
0 0 Td
|
||||
ET
|
||||
Q
|
||||
0 0 1 rg
|
||||
6 8.4 m 7.35 8.4 8.45 7.35 8.45 6 c
|
||||
8.45 4.65 7.35 3.55 6 3.55 c
|
||||
4.65 3.55 3.6 4.65 3.6 6 c
|
||||
3.6 7.35 4.65 8.4 6 8.4 c f*
|
||||
|
||||
EMC
|
||||
endstream
|
||||
endobj
|
||||
|
||||
28 0 obj
|
||||
202
|
||||
endobj
|
||||
|
||||
29 0 obj
|
||||
<<
|
||||
/BBox [
|
||||
0
|
||||
0
|
||||
12.05
|
||||
12.05
|
||||
]
|
||||
/Resources 41 0 R
|
||||
/Subtype /Form
|
||||
/Type /XObject
|
||||
/Length 30 0 R
|
||||
>>
|
||||
stream
|
||||
/Tx BMC
|
||||
EMC
|
||||
endstream
|
||||
endobj
|
||||
|
||||
30 0 obj
|
||||
12
|
||||
endobj
|
||||
|
||||
31 0 obj
|
||||
<<
|
||||
/Params <<
|
||||
/CheckSum <80a33fc110b5a7b8b4d58b8d57e814bc>
|
||||
/Size 22
|
||||
/Subtype /text#2fplain
|
||||
>>
|
||||
/Type /EmbeddedFile
|
||||
/Length 32 0 R
|
||||
>>
|
||||
stream
|
||||
content of attachment
|
||||
endstream
|
||||
endobj
|
||||
|
||||
32 0 obj
|
||||
22
|
||||
endobj
|
||||
|
||||
33 0 obj
|
||||
<<
|
||||
/A <<
|
||||
/S /URI
|
||||
/URI (https://www.qbilt.org/)
|
||||
>>
|
||||
/Border [
|
||||
0
|
||||
0
|
||||
.4
|
||||
]
|
||||
/C [
|
||||
.8
|
||||
.6
|
||||
.6
|
||||
]
|
||||
/H /I
|
||||
/Rect [
|
||||
72
|
||||
501.832
|
||||
374.4
|
||||
520.696
|
||||
]
|
||||
/Subtype /Link
|
||||
/Type /Annot
|
||||
>>
|
||||
endobj
|
||||
|
||||
34 0 obj
|
||||
<<
|
||||
/AP <<
|
||||
/N 42 0 R
|
||||
>>
|
||||
/Contents (attachment1.txt)
|
||||
/FS 16 0 R
|
||||
/NM (attachment1.txt)
|
||||
/Rect [
|
||||
72
|
||||
400
|
||||
92
|
||||
420
|
||||
]
|
||||
/Subtype /FileAttachment
|
||||
/Type /Annot
|
||||
>>
|
||||
endobj
|
||||
|
||||
35 0 obj
|
||||
<<
|
||||
/AP <<
|
||||
/N 44 0 R
|
||||
>>
|
||||
/DA ()
|
||||
/Rect [
|
||||
72
|
||||
350
|
||||
92
|
||||
360
|
||||
]
|
||||
/Subtype /FreeText
|
||||
/Type /Annot
|
||||
>>
|
||||
endobj
|
||||
|
||||
36 0 obj
|
||||
<<
|
||||
/AP <<
|
||||
/N 46 0 R
|
||||
>>
|
||||
/DA ()
|
||||
/Rect [
|
||||
102
|
||||
350
|
||||
112
|
||||
370
|
||||
]
|
||||
/Subtype /FreeText
|
||||
/Type /Annot
|
||||
>>
|
||||
endobj
|
||||
|
||||
37 0 obj
|
||||
<<
|
||||
/AP <<
|
||||
/N 48 0 R
|
||||
>>
|
||||
/DA ()
|
||||
/Rect [
|
||||
122
|
||||
350
|
||||
142
|
||||
360
|
||||
]
|
||||
/Subtype /FreeText
|
||||
/Type /Annot
|
||||
>>
|
||||
endobj
|
||||
|
||||
38 0 obj
|
||||
<<
|
||||
/AP <<
|
||||
/N 50 0 R
|
||||
>>
|
||||
/DA ()
|
||||
/Rect [
|
||||
152
|
||||
350
|
||||
162
|
||||
370
|
||||
]
|
||||
/Subtype /FreeText
|
||||
/Type /Annot
|
||||
>>
|
||||
endobj
|
||||
|
||||
%% Contents for page 1
|
||||
39 0 obj
|
||||
<<
|
||||
/Length 40 0 R
|
||||
>>
|
||||
stream
|
||||
q
|
||||
1 1 .7 rg
|
||||
.5 .5 0 RG
|
||||
72 470.77 118.8 14.15 re
|
||||
B
|
||||
Q
|
||||
q
|
||||
0 .5 .5 RG
|
||||
0 1 1 rg
|
||||
372 330.77 14.15 139.4 re
|
||||
B
|
||||
Q
|
||||
q
|
||||
1 0 0 RG
|
||||
72 310 20 10 re
|
||||
72 310 5 10 re
|
||||
S
|
||||
0 1 0 RG
|
||||
102 310 10 20 re
|
||||
102 310 10 5 re
|
||||
S
|
||||
0 0 1 RG
|
||||
122 310 20 10 re
|
||||
137 310 5 10 re
|
||||
S
|
||||
0.5 0 1 RG
|
||||
152 310 10 20 re
|
||||
152 325 10 5 re
|
||||
S
|
||||
10 w
|
||||
0.14 .33 .18 RG
|
||||
5 5 602 782 re
|
||||
S
|
||||
Q
|
||||
BT
|
||||
/F1 16 Tf
|
||||
20.6 TL
|
||||
170 650 Td
|
||||
(radio button 1) Tj
|
||||
(radio button 2) '
|
||||
(radio button 3) '
|
||||
1 0 0 1 72 546 Tm
|
||||
/F1 20 Tf
|
||||
(Thick green border surrounds page.) Tj
|
||||
0 -40 Td
|
||||
/F1 24 Tf
|
||||
0 0 1 rg
|
||||
(https://www.qbilt.org) Tj
|
||||
/F1 12 Tf
|
||||
1 0 0 1 202 474 Tm
|
||||
(<- Formy field in yellow) Tj
|
||||
1 0 0 1 392 410 Tm
|
||||
14.4 TL
|
||||
(<- Rot-ccw field) Tj
|
||||
(with "Rot" at bottom) '
|
||||
(and text going up) '
|
||||
0 g
|
||||
1 0 0 1 102 405 Tm
|
||||
(Arrow to the left points down.) Tj
|
||||
1 0 0 1 182 310 Tm
|
||||
(<- Drawn rectangles appear below annotations.) Tj
|
||||
ET
|
||||
endstream
|
||||
endobj
|
||||
|
||||
40 0 obj
|
||||
874
|
||||
endobj
|
||||
|
||||
41 0 obj
|
||||
<<
|
||||
/Font 52 0 R
|
||||
/ProcSet [
|
||||
/PDF
|
||||
/Text
|
||||
]
|
||||
>>
|
||||
endobj
|
||||
|
||||
42 0 obj
|
||||
<<
|
||||
/BBox [
|
||||
0
|
||||
0
|
||||
20
|
||||
20
|
||||
]
|
||||
/Resources <<
|
||||
>>
|
||||
/Subtype /Form
|
||||
/Type /XObject
|
||||
/Length 43 0 R
|
||||
>>
|
||||
stream
|
||||
0 10 m
|
||||
10 0 l
|
||||
20 10 l
|
||||
10 0 m
|
||||
10 20 l
|
||||
0 0 20 20 re
|
||||
S
|
||||
endstream
|
||||
endobj
|
||||
|
||||
43 0 obj
|
||||
52
|
||||
endobj
|
||||
|
||||
44 0 obj
|
||||
<<
|
||||
/BBox [
|
||||
0
|
||||
0
|
||||
20
|
||||
10
|
||||
]
|
||||
/Resources 2 0 R
|
||||
/Subtype /Form
|
||||
/Type /XObject
|
||||
/Length 45 0 R
|
||||
>>
|
||||
stream
|
||||
1 0 0 RG
|
||||
0 0 20 10 re
|
||||
0 0 5 10 re
|
||||
S
|
||||
endstream
|
||||
endobj
|
||||
|
||||
45 0 obj
|
||||
36
|
||||
endobj
|
||||
|
||||
46 0 obj
|
||||
<<
|
||||
/BBox [
|
||||
0
|
||||
0
|
||||
20
|
||||
10
|
||||
]
|
||||
/Matrix [
|
||||
0
|
||||
1
|
||||
-1
|
||||
0
|
||||
0
|
||||
0
|
||||
]
|
||||
/Resources 2 0 R
|
||||
/Subtype /Form
|
||||
/Type /XObject
|
||||
/Length 47 0 R
|
||||
>>
|
||||
stream
|
||||
0 1 0 RG
|
||||
0 0 20 10 re
|
||||
0 0 5 10 re
|
||||
S
|
||||
endstream
|
||||
endobj
|
||||
|
||||
47 0 obj
|
||||
36
|
||||
endobj
|
||||
|
||||
48 0 obj
|
||||
<<
|
||||
/BBox [
|
||||
0
|
||||
0
|
||||
20
|
||||
10
|
||||
]
|
||||
/Matrix [
|
||||
-1
|
||||
0
|
||||
0
|
||||
-1
|
||||
0
|
||||
0
|
||||
]
|
||||
/Resources 2 0 R
|
||||
/Subtype /Form
|
||||
/Type /XObject
|
||||
/Length 49 0 R
|
||||
>>
|
||||
stream
|
||||
0 0 1 RG
|
||||
0 0 20 10 re
|
||||
0 0 5 10 re
|
||||
S
|
||||
endstream
|
||||
endobj
|
||||
|
||||
49 0 obj
|
||||
36
|
||||
endobj
|
||||
|
||||
50 0 obj
|
||||
<<
|
||||
/BBox [
|
||||
0
|
||||
0
|
||||
20
|
||||
10
|
||||
]
|
||||
/Matrix [
|
||||
0
|
||||
-1
|
||||
1
|
||||
0
|
||||
0
|
||||
0
|
||||
]
|
||||
/Resources 2 0 R
|
||||
/Subtype /Form
|
||||
/Type /XObject
|
||||
/Length 51 0 R
|
||||
>>
|
||||
stream
|
||||
0.5 0 1 RG
|
||||
0 0 20 10 re
|
||||
0 0 5 10 re
|
||||
S
|
||||
endstream
|
||||
endobj
|
||||
|
||||
51 0 obj
|
||||
38
|
||||
endobj
|
||||
|
||||
52 0 obj
|
||||
<<
|
||||
/ZaDi 22 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 53
|
||||
0000000000 65535 f
|
||||
0000000025 00000 n
|
||||
0000000211 00000 n
|
||||
0000000263 00000 n
|
||||
0000000506 00000 n
|
||||
0000000755 00000 n
|
||||
0000000874 00000 n
|
||||
0000000944 00000 n
|
||||
0000001017 00000 n
|
||||
0000001121 00000 n
|
||||
0000001335 00000 n
|
||||
0000001355 00000 n
|
||||
0000001625 00000 n
|
||||
0000001645 00000 n
|
||||
0000001997 00000 n
|
||||
0000002349 00000 n
|
||||
0000002701 00000 n
|
||||
0000002842 00000 n
|
||||
0000003114 00000 n
|
||||
0000003473 00000 n
|
||||
0000003494 00000 n
|
||||
0000003663 00000 n
|
||||
0000003683 00000 n
|
||||
0000003764 00000 n
|
||||
0000004123 00000 n
|
||||
0000004144 00000 n
|
||||
0000004313 00000 n
|
||||
0000004333 00000 n
|
||||
0000004692 00000 n
|
||||
0000004713 00000 n
|
||||
0000004882 00000 n
|
||||
0000004902 00000 n
|
||||
0000005110 00000 n
|
||||
0000005130 00000 n
|
||||
0000005374 00000 n
|
||||
0000005578 00000 n
|
||||
0000005718 00000 n
|
||||
0000005860 00000 n
|
||||
0000006002 00000 n
|
||||
0000006167 00000 n
|
||||
0000007098 00000 n
|
||||
0000007119 00000 n
|
||||
0000007193 00000 n
|
||||
0000007397 00000 n
|
||||
0000007417 00000 n
|
||||
0000007603 00000 n
|
||||
0000007623 00000 n
|
||||
0000007862 00000 n
|
||||
0000007882 00000 n
|
||||
0000008122 00000 n
|
||||
0000008142 00000 n
|
||||
0000008383 00000 n
|
||||
0000008403 00000 n
|
||||
trailer <<
|
||||
/Root 1 0 R
|
||||
/Size 53
|
||||
/ID [<a2f146daeb6d814a742556489dab9882><7b639c67bfc16b5e891fa5468aac3a14>]
|
||||
>>
|
||||
startxref
|
||||
8441
|
||||
%%EOF
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue