2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-12-22 10:58:58 +00:00

Back out fluent QPDFObjectHandle methods. Keep the andGet methods.

I decided these were confusing and inconsistent with how JSON works.
They muddle the API rather than improving it.
This commit is contained in:
Jay Berkenbilt 2022-05-17 18:28:50 -04:00
parent 7e7a9c4379
commit 56f1b411fe
16 changed files with 149 additions and 164 deletions

View File

@ -86,15 +86,12 @@
2022-04-29 Jay Berkenbilt <ejb@ql.org>
* QPDFObjectHandle: for the methods insertItem, appendItem,
eraseItem, replaceKey, and removeKey, have the methods return a
reference to the original object, making a fluent interface to
initializing or modifying QPDFObjectHandle possible. Also, for
each one, add a corresponding "AndGet" method (insertItemAndGet,
appendItemAndGet, eraseItemAndGet, replaceKeyAndGet, and
removeKeyAndGet) that returns the newly inserted, replaced, or
removed item. This makes it possible to create a new object, add
it to an array or dictionary, and get a handle to it all in one
line.
eraseItem, replaceKey, and removeKey, add a corresponding "AndGet"
method (insertItemAndGet, appendItemAndGet, eraseItemAndGet,
replaceKeyAndGet, and removeKeyAndGet) that returns the newly
inserted, replaced, or removed item. This makes it possible to
create a new object, add it to an array or dictionary, and get a
handle to it all in one line.
2022-04-24 Jay Berkenbilt <ejb@ql.org>

View File

@ -106,10 +106,10 @@ process(
// apdict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject"));
// apdict.replaceKey("/Subtype", QPDFObjectHandle::newName("/Form"));
// apdict.replaceKey("/BBox", QPDFObjectHandle::parse("[ 0 0 20 20 ]"));
apdict.replaceKey("/Resources", "<< >>"_qpdf)
.replaceKey("/Type", "/XObject"_qpdf)
.replaceKey("/Subtype", "/Form"_qpdf)
.replaceKey("/BBox", "[ 0 0 20 20 ]"_qpdf);
apdict.replaceKey("/Resources", "<< >>"_qpdf);
apdict.replaceKey("/Type", "/XObject"_qpdf);
apdict.replaceKey("/Subtype", "/Form"_qpdf);
apdict.replaceKey("/BBox", "[ 0 0 20 20 ]"_qpdf);
auto annot = q.makeIndirectObject(QPDFObjectHandle::parse(
&q,
("<<"

View File

@ -181,9 +181,9 @@ add_page(
" /Subtype /Image"
" /BitsPerComponent 8"
">>"_qpdf;
image_dict.replaceKey("/ColorSpace", newName(color_space))
.replaceKey("/Width", newInteger(width))
.replaceKey("/Height", newInteger(height));
image_dict.replaceKey("/ColorSpace", newName(color_space));
image_dict.replaceKey("/Width", newInteger(width));
image_dict.replaceKey("/Height", newInteger(height));
image.replaceDict(image_dict);
// Provide the stream data.
@ -200,9 +200,9 @@ add_page(
xobject.replaceKey("/Im1", image);
QPDFObjectHandle resources = QPDFObjectHandle::newDictionary();
resources.replaceKey("/ProcSet", procset)
.replaceKey("/Font", rfont)
.replaceKey("/XObject", xobject);
resources.replaceKey("/ProcSet", procset);
resources.replaceKey("/Font", rfont);
resources.replaceKey("/XObject", xobject);
// Create the page content stream
QPDFObjectHandle contents =
@ -213,7 +213,8 @@ add_page(
" /Type /Page"
" /MediaBox [0 0 612 392]"
">>"_qpdf);
page.replaceKey("/Contents", contents).replaceKey("/Resources", resources);
page.replaceKey("/Contents", contents);
page.replaceKey("/Resources", resources);
// Add the page to the PDF file
dh.addPage(page, false);

View File

@ -1024,25 +1024,22 @@ class QPDFObjectHandle
void setArrayFromVector(std::vector<QPDFObjectHandle> const& items);
// Insert an item before the item at the given position ("at") so
// that it has that position after insertion. If "at" is equal to
// the size of the array, insert the item at the end. Return a
// reference to the array (not the new item).
// the size of the array, insert the item at the end.
QPDF_DLL
QPDFObjectHandle& insertItem(int at, QPDFObjectHandle const& item);
void insertItem(int at, QPDFObjectHandle const& item);
// Like insertItem but return the item that was inserted.
QPDF_DLL
QPDFObjectHandle insertItemAndGet(int at, QPDFObjectHandle const& item);
// Append an item, and return a reference to the original array
// (not the new item).
// Append an item to an array.
QPDF_DLL
QPDFObjectHandle& appendItem(QPDFObjectHandle const& item);
void appendItem(QPDFObjectHandle const& item);
// Append an item, and return the newly added item.
QPDF_DLL
QPDFObjectHandle appendItemAndGet(QPDFObjectHandle const& item);
// Remove the item at that position, reducing the size of the
// array by one. Return a reference the original array (not the
// item that was removed).
// array by one.
QPDF_DLL
QPDFObjectHandle& eraseItem(int at);
void eraseItem(int at);
// Erase and item and return the item that was removed.
QPDF_DLL
QPDFObjectHandle eraseItemAndGet(int at);
@ -1050,19 +1047,16 @@ class QPDFObjectHandle
// Mutator methods for dictionary objects
// Replace value of key, adding it if it does not exist. If value
// is null, remove the key. Return a reference to the original
// dictionary (not the new item).
// is null, remove the key.
QPDF_DLL
QPDFObjectHandle&
replaceKey(std::string const& key, QPDFObjectHandle const& value);
void replaceKey(std::string const& key, QPDFObjectHandle const& value);
// Replace value of key and return the value.
QPDF_DLL
QPDFObjectHandle
replaceKeyAndGet(std::string const& key, QPDFObjectHandle const& value);
// Remove key, doing nothing if key does not exist. Return the
// original dictionary (not the removed item).
// Remove key, doing nothing if key does not exist.
QPDF_DLL
QPDFObjectHandle& removeKey(std::string const& key);
void removeKey(std::string const& key);
// Remove key and return the old value. If the old value didn't
// exist, return a null object.
QPDF_DLL

View File

@ -208,8 +208,9 @@ NNTreeIterator::resetLimits(
}
}
if (first.isInitialized() && last.isInitialized()) {
auto limits =
QPDFObjectHandle::newArray().appendItem(first).appendItem(last);
auto limits = QPDFObjectHandle::newArray();
limits.appendItem(first);
limits.appendItem(last);
auto olimits = node.getKey("/Limits");
if (olimits.isArray() && (olimits.getArrayNItems() == 2)) {
auto ofirst = olimits.getArrayItem(0);
@ -340,10 +341,9 @@ NNTreeIterator::split(
first_node.replaceKey(key, first_half);
QPDFObjectHandle new_kids = QPDFObjectHandle::newArray();
new_kids.appendItem(first_node);
to_split
.removeKey("/Limits") // already shouldn't be there for root
.removeKey(impl.details.itemsKey())
.replaceKey("/Kids", new_kids);
to_split.removeKey("/Limits"); // already shouldn't be there for root
to_split.removeKey(impl.details.itemsKey());
to_split.replaceKey("/Kids", new_kids);
if (is_leaf) {
QTC::TC("qpdf", "NNTree split root + leaf");
this->node = first_node;
@ -884,8 +884,9 @@ NNTreeImpl::repair()
for (auto const& i: *this) {
repl.insert(i.first, i.second);
}
this->oh.replaceKey("/Kids", new_node.getKey("/Kids"))
.replaceKey(details.itemsKey(), new_node.getKey(details.itemsKey()));
this->oh.replaceKey("/Kids", new_node.getKey("/Kids"));
this->oh.replaceKey(
details.itemsKey(), new_node.getKey(details.itemsKey()));
}
NNTreeImpl::iterator

View File

@ -733,7 +733,8 @@ QPDFAcroFormDocumentHelper::adjustAppearanceStream(
auto existing_old = subdict.getKey(old_key);
if (!existing_old.isNull()) {
QTC::TC("qpdf", "QPDFAcroFormDocumentHelper ap rename");
subdict.replaceKey(new_key, existing_old).removeKey(old_key);
subdict.replaceKey(new_key, existing_old);
subdict.removeKey(old_key);
}
}
}

View File

@ -103,8 +103,8 @@ QPDFFileSpecObjectHelper::createFileSpec(
QPDFFileSpecObjectHelper result(oh);
result.setFilename(filename);
auto ef = QPDFObjectHandle::newDictionary();
ef.replaceKey("/F", efsoh.getObjectHandle())
.replaceKey("/UF", efsoh.getObjectHandle());
ef.replaceKey("/F", efsoh.getObjectHandle());
ef.replaceKey("/UF", efsoh.getObjectHandle());
oh.replaceKey("/EF", ef);
return result;
}

View File

@ -959,7 +959,7 @@ QPDFObjectHandle::setArrayFromVector(std::vector<QPDFObjectHandle> const& items)
}
}
QPDFObjectHandle&
void
QPDFObjectHandle::insertItem(int at, QPDFObjectHandle const& item)
{
if (isArray()) {
@ -968,7 +968,6 @@ QPDFObjectHandle::insertItem(int at, QPDFObjectHandle const& item)
typeWarning("array", "ignoring attempt to insert item");
QTC::TC("qpdf", "QPDFObjectHandle array ignoring insert item");
}
return *this;
}
QPDFObjectHandle
@ -978,7 +977,7 @@ QPDFObjectHandle::insertItemAndGet(int at, QPDFObjectHandle const& item)
return item;
}
QPDFObjectHandle&
void
QPDFObjectHandle::appendItem(QPDFObjectHandle const& item)
{
if (isArray()) {
@ -988,7 +987,6 @@ QPDFObjectHandle::appendItem(QPDFObjectHandle const& item)
typeWarning("array", "ignoring attempt to append item");
QTC::TC("qpdf", "QPDFObjectHandle array ignoring append item");
}
return *this;
}
QPDFObjectHandle
@ -998,7 +996,7 @@ QPDFObjectHandle::appendItemAndGet(QPDFObjectHandle const& item)
return item;
}
QPDFObjectHandle&
void
QPDFObjectHandle::eraseItem(int at)
{
if (isArray() && (at < getArrayNItems()) && (at >= 0)) {
@ -1012,7 +1010,6 @@ QPDFObjectHandle::eraseItem(int at)
QTC::TC("qpdf", "QPDFObjectHandle array ignoring erase item");
}
}
return *this;
}
QPDFObjectHandle
@ -1289,7 +1286,7 @@ QPDFObjectHandle::getOwningQPDF()
// Dictionary mutators
QPDFObjectHandle&
void
QPDFObjectHandle::replaceKey(
std::string const& key, QPDFObjectHandle const& value)
{
@ -1300,7 +1297,6 @@ QPDFObjectHandle::replaceKey(
typeWarning("dictionary", "ignoring key replacement request");
QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring replaceKey");
}
return *this;
}
QPDFObjectHandle
@ -1311,7 +1307,7 @@ QPDFObjectHandle::replaceKeyAndGet(
return value;
}
QPDFObjectHandle&
void
QPDFObjectHandle::removeKey(std::string const& key)
{
if (isDictionary()) {
@ -1320,7 +1316,6 @@ QPDFObjectHandle::removeKey(std::string const& key)
typeWarning("dictionary", "ignoring key removal request");
QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring removeKey");
}
return *this;
}
QPDFObjectHandle

View File

@ -44,8 +44,9 @@ QPDFPageLabelDocumentHelper::getLabelForPage(long long page_idx)
QIntC::range_check(start, offset);
start += offset;
result = QPDFObjectHandle::newDictionary();
result.replaceKey("/S", S).replaceKey("/P", P).replaceKey(
"/St", QPDFObjectHandle::newInteger(start));
result.replaceKey("/S", S);
result.replaceKey("/P", P);
result.replaceKey("/St", QPDFObjectHandle::newInteger(start));
return result;
}

View File

@ -78,8 +78,8 @@ QPDFObjectHandle
InlineImageTracker::convertIIDict(QPDFObjectHandle odict)
{
QPDFObjectHandle dict = QPDFObjectHandle::newDictionary();
dict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject"))
.replaceKey("/Subtype", QPDFObjectHandle::newName("/Image"));
dict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject"));
dict.replaceKey("/Subtype", QPDFObjectHandle::newName("/Image"));
std::set<std::string> keys = odict.getKeys();
for (auto key: keys) {
QPDFObjectHandle value = odict.getKey(key);
@ -752,11 +752,11 @@ QPDFPageObjectHelper::getFormXObjectForPage(bool handle_transformations)
}
QPDFObjectHandle result = QPDFObjectHandle::newStream(qpdf);
QPDFObjectHandle newdict = result.getDict();
newdict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject"))
.replaceKey("/Subtype", QPDFObjectHandle::newName("/Form"))
.replaceKey(
"/Resources", getAttribute("/Resources", false).shallowCopy())
.replaceKey("/Group", getAttribute("/Group", false).shallowCopy());
newdict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject"));
newdict.replaceKey("/Subtype", QPDFObjectHandle::newName("/Form"));
newdict.replaceKey(
"/Resources", getAttribute("/Resources", false).shallowCopy());
newdict.replaceKey("/Group", getAttribute("/Group", false).shallowCopy());
QPDFObjectHandle bbox = getTrimBox(false).shallowCopy();
if (!bbox.isRectangle()) {
this->oh.warnIfPossible("bounding box is invalid; form"

View File

@ -725,8 +725,8 @@ QPDF_Stream::replaceFilterData(
QPDFObjectHandle const& decode_parms,
size_t length)
{
this->stream_dict.replaceKey("/Filter", filter)
.replaceKey("/DecodeParms", decode_parms);
this->stream_dict.replaceKey("/Filter", filter);
this->stream_dict.replaceKey("/DecodeParms", decode_parms);
if (length == 0) {
QTC::TC("qpdf", "QPDF_Stream unknown stream length");
this->stream_dict.removeKey("/Length");

View File

@ -62,15 +62,16 @@ test_bsearch()
auto mk = [&q](std::vector<int> const& v) {
auto nums = QPDFObjectHandle::newArray();
for (auto i: v) {
nums.appendItem(QPDFObjectHandle::newInteger(i))
.appendItem(QPDFObjectHandle::newString(
nums.appendItem(QPDFObjectHandle::newInteger(i));
nums.appendItem(QPDFObjectHandle::newString(
"-" + QUtil::int_to_string(i) + "-"));
}
auto limits = QPDFObjectHandle::newArray();
limits.appendItem(QPDFObjectHandle::newInteger(v.at(0)))
.appendItem(QPDFObjectHandle::newInteger(v.at(v.size() - 1)));
limits.appendItem(QPDFObjectHandle::newInteger(v.at(0)));
limits.appendItem(QPDFObjectHandle::newInteger(v.at(v.size() - 1)));
auto node = q.makeIndirectObject(QPDFObjectHandle::newDictionary());
node.replaceKey("/Nums", nums).replaceKey("/Limits", limits);
node.replaceKey("/Nums", nums);
node.replaceKey("/Limits", limits);
return node;
};
@ -168,8 +169,8 @@ test_depth()
int val =
(((((i1 * NITEMS) + i2) * NITEMS) + i3) * NITEMS) + i4;
std::string str = QUtil::int_to_string(10 * val, 6);
items.appendItem(QPDFObjectHandle::newString(str))
.appendItem(QPDFObjectHandle::newString("val " + str));
items.appendItem(QPDFObjectHandle::newString(str));
items.appendItem(QPDFObjectHandle::newString("val " + str));
if (i4 == 0) {
first = str;
} else if (i4 == NITEMS - 1) {
@ -178,22 +179,20 @@ test_depth()
}
auto limits = QPDFObjectHandle::newArray();
n3.replaceKey("/Limits", limits);
limits.appendItem(QPDFObjectHandle::newString(first))
.appendItem(QPDFObjectHandle::newString(last));
limits.appendItem(QPDFObjectHandle::newString(first));
limits.appendItem(QPDFObjectHandle::newString(last));
}
auto limits = QPDFObjectHandle::newArray();
n2.replaceKey("/Limits", limits);
limits
.appendItem(
k2.getArrayItem(0).getKey("/Limits").getArrayItem(0))
.appendItem(k2.getArrayItem(NITEMS - 1)
.getKey("/Limits")
.getArrayItem(1));
limits.appendItem(
k2.getArrayItem(0).getKey("/Limits").getArrayItem(0));
limits.appendItem(
k2.getArrayItem(NITEMS - 1).getKey("/Limits").getArrayItem(1));
}
auto limits = QPDFObjectHandle::newArray();
n1.replaceKey("/Limits", limits);
limits.appendItem(k1.getArrayItem(0).getKey("/Limits").getArrayItem(0))
.appendItem(
limits.appendItem(k1.getArrayItem(0).getKey("/Limits").getArrayItem(0));
limits.appendItem(
k1.getArrayItem(NITEMS - 1).getKey("/Limits").getArrayItem(1));
}

View File

@ -98,12 +98,9 @@ For a detailed list of changes, please see the file
- Library Enhancements
- Support for more fluent programming with ``QPDFObjectHandle``.
The methods ``insertItem``, ``appendItem``, ``eraseItem``,
``replaceKey``, and ``removeKey`` all return a reference to the
object being modified. New methods ``insertItemAndGet``,
``appendItemAndGet``, ``eraseItemAndGet``, ``replaceKeyAndGet``,
and ``removeKeyAndGet`` return the newly added or removed object.
- New methods ``insertItemAndGet``, ``appendItemAndGet``,
``eraseItemAndGet``, ``replaceKeyAndGet``, and
``removeKeyAndGet`` return the newly added or removed object.
- Add new ``Pipeline`` methods to reduce the amount of casting that is
needed:

View File

@ -60,14 +60,15 @@ runtest(int n)
rfont.replaceKey("/F1", font);
QPDFObjectHandle resources = QPDFObjectHandle::newDictionary();
resources.replaceKey("/ProcSet", procset).replaceKey("/Font", rfont);
resources.replaceKey("/ProcSet", procset);
resources.replaceKey("/Font", rfont);
QPDFObjectHandle page =
pdf.makeIndirectObject(QPDFObjectHandle::newDictionary());
page.replaceKey("/Type", newName("/Page"))
.replaceKey("/MediaBox", mediabox)
.replaceKey("/Contents", contents)
.replaceKey("/Resources", resources);
page.replaceKey("/Type", newName("/Page"));
page.replaceKey("/MediaBox", mediabox);
page.replaceKey("/Contents", contents);
page.replaceKey("/Resources", resources);
QPDFPageDocumentHelper(pdf).addPage(page, true);

View File

@ -525,7 +525,8 @@ test_9(QPDF& pdf, char const* arg2)
"data for other stream\n",
QPDFObjectHandle::newNull(),
QPDFObjectHandle::newNull());
root.replaceKey("/QStream", qstream).replaceKey("/RStream", rstream);
root.replaceKey("/QStream", qstream);
root.replaceKey("/RStream", rstream);
QPDFWriter w(pdf, "a.pdf");
w.setStaticID(true);
w.setStreamDataMode(qpdf_s_preserve);
@ -895,12 +896,15 @@ test_24(QPDF& pdf, char const* arg2)
QPDFObjectHandle res1 = QPDFObjectHandle::newReserved(&pdf);
QPDFObjectHandle res2 = QPDFObjectHandle::newReserved(&pdf);
QPDFObjectHandle trailer = pdf.getTrailer();
trailer.replaceKey("Array1", res1).replaceKey("Array2", res2);
trailer.replaceKey("Array1", res1);
trailer.replaceKey("Array2", res2);
QPDFObjectHandle array1 = QPDFObjectHandle::newArray();
QPDFObjectHandle array2 = QPDFObjectHandle::newArray();
array1.appendItem(res2).appendItem(QPDFObjectHandle::newInteger(1));
array2.appendItem(res1).appendItem(QPDFObjectHandle::newInteger(2));
array1.appendItem(res2);
array1.appendItem(QPDFObjectHandle::newInteger(1));
array2.appendItem(res1);
array2.appendItem(QPDFObjectHandle::newInteger(2));
// Make sure trying to ask questions about a reserved object
// doesn't break it.
if (res1.isArray()) {
@ -1065,14 +1069,13 @@ test_27(QPDF& pdf, char const* arg2)
dh.addPage(O3.getKey("/OtherPage"), false);
dh.addPage(O3, false);
QPDFObjectHandle s2 = QPDFObjectHandle::newStream(&oldpdf, "potato\n");
pdf.getTrailer()
.replaceKey("/QTest", pdf.copyForeignObject(qtest))
.replaceKey("/QTest2", QPDFObjectHandle::newArray());
pdf.getTrailer()
.getKey("/QTest2")
.appendItem(pdf.copyForeignObject(s1))
.appendItem(pdf.copyForeignObject(s2))
.appendItem(pdf.copyForeignObject(s3));
auto trailer = pdf.getTrailer();
trailer.replaceKey("/QTest", pdf.copyForeignObject(qtest));
auto qtest2 =
trailer.replaceKeyAndGet("/QTest2", QPDFObjectHandle::newArray());
qtest2.appendItem(pdf.copyForeignObject(s1));
qtest2.appendItem(pdf.copyForeignObject(s2));
qtest2.appendItem(pdf.copyForeignObject(s3));
}
QPDFWriter w(pdf, "a.pdf");
@ -2035,12 +2038,6 @@ test_55(QPDF& pdf, char const* arg2)
QPDFPageDocumentHelper(pdf).getAllPages();
QPDFObjectHandle qtest = QPDFObjectHandle::newArray();
for (auto& ph: pages) {
// Note: using fluent appendItem causes a test failure with
// MSVC 19.31.31107, which appears to evaluate the argument to
// the second appendItem before the first. Since these
// arguments have the side effect of creating objects, the
// object numbers end up being different even though the
// resulting file is semantically correct.
qtest.appendItem(ph.getFormXObjectForPage());
qtest.appendItem(ph.getFormXObjectForPage(false));
}
@ -2196,10 +2193,10 @@ test_60(QPDF& pdf, char const* arg2)
// The only differences between /QTest and /QTest3 should be
// the direct objects merged from r2.
pdf.getTrailer()
.replaceKey("/QTest1", r1)
.replaceKey("/QTest2", r2)
.replaceKey("/QTest3", r3);
auto trailer = pdf.getTrailer();
trailer.replaceKey("/QTest1", r1);
trailer.replaceKey("/QTest2", r2);
trailer.replaceKey("/QTest3", r3);
QPDFWriter w(pdf, "a.pdf");
w.setQDFMode(true);
w.setStaticID(true);
@ -2259,9 +2256,9 @@ test_62(QPDF& pdf, char const* arg2)
long long q2 = QIntC::to_longlong(q2_l);
unsigned int q3_i = UINT_MAX;
long long q3 = QIntC::to_longlong(q3_i);
t.replaceKey("/Q1", QPDFObjectHandle::newInteger(q1))
.replaceKey("/Q2", QPDFObjectHandle::newInteger(q2))
.replaceKey("/Q3", QPDFObjectHandle::newInteger(q3));
t.replaceKey("/Q1", QPDFObjectHandle::newInteger(q1));
t.replaceKey("/Q2", QPDFObjectHandle::newInteger(q2));
t.replaceKey("/Q3", QPDFObjectHandle::newInteger(q3));
assert_compare_numbers(q1, t.getKey("/Q1").getIntValue());
assert_compare_numbers(q1_l, t.getKey("/Q1").getUIntValue());
assert_compare_numbers(INT_MAX, t.getKey("/Q1").getIntValueAsInt());
@ -3120,17 +3117,16 @@ test_87(QPDF& pdf, char const* arg2)
static void
test_88(QPDF& pdf, char const* arg2)
{
// Exercise fluent QPDFObjectHandle mutators and similar methods
// added for qpdf 11.
auto dict = QPDFObjectHandle::newDictionary()
.replaceKey("/One", QPDFObjectHandle::newInteger(1))
.replaceKey("/Two", QPDFObjectHandle::newInteger(2));
dict.replaceKeyAndGet("/Three", QPDFObjectHandle::newArray())
.appendItem("(a)"_qpdf)
.appendItem("(b)"_qpdf)
.appendItemAndGet(QPDFObjectHandle::newDictionary())
.replaceKey("/Z", "/Y"_qpdf)
.replaceKey("/X", "/W"_qpdf);
// Exercise mutate and get methods added for qpdf 11.
auto dict = QPDFObjectHandle::newDictionary();
dict.replaceKey("/One", QPDFObjectHandle::newInteger(1));
dict.replaceKey("/Two", QPDFObjectHandle::newInteger(2));
auto three = dict.replaceKeyAndGet("/Three", QPDFObjectHandle::newArray());
three.appendItem("(a)"_qpdf);
three.appendItem("(b)"_qpdf);
auto newdict = three.appendItemAndGet(QPDFObjectHandle::newDictionary());
newdict.replaceKey("/Z", "/Y"_qpdf);
newdict.replaceKey("/X", "/W"_qpdf);
assert(dict.unparse() == R"(
<<
/One 1
@ -3138,14 +3134,15 @@ test_88(QPDF& pdf, char const* arg2)
/Three [ (a) (b) << /Z /Y /X /W >> ]
>>
)"_qpdf.unparse());
auto arr = dict.getKey("/Three")
.insertItem(0, QPDFObjectHandle::newString("0"))
.insertItem(0, QPDFObjectHandle::newString("00"));
auto arr = dict.getKey("/Three");
arr.insertItem(0, QPDFObjectHandle::newString("0"));
arr.insertItem(0, QPDFObjectHandle::newString("00"));
assert(
arr.unparse() ==
"[ (00) (0) (a) (b) << /Z /Y /X /W >> ]"_qpdf.unparse());
auto new_dict = arr.insertItemAndGet(1, "<< /P /Q /R /S >>"_qpdf);
arr.eraseItem(2).eraseItem(0);
arr.eraseItem(2);
arr.eraseItem(0);
assert(
arr.unparse() ==
"[ << /P /Q /R /S >> (a) (b) << /Z /Y /X /W >> ]"_qpdf.unparse());
@ -3154,7 +3151,8 @@ test_88(QPDF& pdf, char const* arg2)
// always been this way, and there is code that relies on this
// behavior. Maybe it would be different if I could start over
// again...
new_dict.removeKey("/R").replaceKey("/T", "/U"_qpdf);
new_dict.removeKey("/R");
new_dict.replaceKey("/T", "/U"_qpdf);
assert(
arr.unparse() ==
"[ << /P /Q /T /U >> (a) (b) << /Z /Y /X /W >> ]"_qpdf.unparse());

View File

@ -187,37 +187,37 @@ create_pdf(char const* filename)
QPDFObjectHandle font =
pdf.makeIndirectObject(QPDFObjectHandle::newDictionary());
font.replaceKey("/Type", newName("/Font"))
.replaceKey("/Subtype", newName("/Type1"))
.replaceKey("/Name", newName("/F1"))
.replaceKey("/BaseFont", newName("/Helvetica"))
.replaceKey("/Encoding", newName("/WinAnsiEncoding"));
font.replaceKey("/Type", newName("/Font"));
font.replaceKey("/Subtype", newName("/Type1"));
font.replaceKey("/Name", newName("/F1"));
font.replaceKey("/BaseFont", newName("/Helvetica"));
font.replaceKey("/Encoding", newName("/WinAnsiEncoding"));
QPDFObjectHandle procset =
pdf.makeIndirectObject(QPDFObjectHandle::newArray());
procset.appendItem(newName("/PDF"))
.appendItem(newName("/Text"))
.appendItem(newName("/ImageC"));
procset.appendItem(newName("/PDF"));
procset.appendItem(newName("/Text"));
procset.appendItem(newName("/ImageC"));
QPDFObjectHandle rfont = QPDFObjectHandle::newDictionary();
rfont.replaceKey("/F1", font);
QPDFObjectHandle mediabox = QPDFObjectHandle::newArray();
mediabox.appendItem(newInteger(0))
.appendItem(newInteger(0))
.appendItem(newInteger(612))
.appendItem(newInteger(792));
mediabox.appendItem(newInteger(0));
mediabox.appendItem(newInteger(0));
mediabox.appendItem(newInteger(612));
mediabox.appendItem(newInteger(792));
QPDFPageDocumentHelper dh(pdf);
for (size_t pageno = 1; pageno <= npages; ++pageno) {
QPDFObjectHandle image = QPDFObjectHandle::newStream(&pdf);
QPDFObjectHandle image_dict = image.getDict();
image_dict.replaceKey("/Type", newName("/XObject"))
.replaceKey("/Subtype", newName("/Image"))
.replaceKey("/ColorSpace", newName("/DeviceGray"))
.replaceKey("/BitsPerComponent", newInteger(8))
.replaceKey("/Width", newInteger(width))
.replaceKey("/Height", newInteger(height));
image_dict.replaceKey("/Type", newName("/XObject"));
image_dict.replaceKey("/Subtype", newName("/Image"));
image_dict.replaceKey("/ColorSpace", newName("/DeviceGray"));
image_dict.replaceKey("/BitsPerComponent", newInteger(8));
image_dict.replaceKey("/Width", newInteger(width));
image_dict.replaceKey("/Height", newInteger(height));
ImageProvider* p = new ImageProvider(pageno);
std::shared_ptr<QPDFObjectHandle::StreamDataProvider> provider(p);
image.replaceStreamData(
@ -227,18 +227,18 @@ create_pdf(char const* filename)
xobject.replaceKey("/Im1", image);
QPDFObjectHandle resources = QPDFObjectHandle::newDictionary();
resources.replaceKey("/ProcSet", procset)
.replaceKey("/Font", rfont)
.replaceKey("/XObject", xobject);
resources.replaceKey("/ProcSet", procset);
resources.replaceKey("/Font", rfont);
resources.replaceKey("/XObject", xobject);
QPDFObjectHandle contents = create_page_contents(pdf, pageno);
QPDFObjectHandle page =
pdf.makeIndirectObject(QPDFObjectHandle::newDictionary());
page.replaceKey("/Type", newName("/Page"))
.replaceKey("/MediaBox", mediabox)
.replaceKey("/Contents", contents)
.replaceKey("/Resources", resources);
page.replaceKey("/Type", newName("/Page"));
page.replaceKey("/MediaBox", mediabox);
page.replaceKey("/Contents", contents);
page.replaceKey("/Resources", resources);
dh.addPage(page, false);
}