Add operator ""_qpdf for creating QPDFObjectHandle literals

This commit is contained in:
Jay Berkenbilt 2022-02-05 09:18:58 -05:00
parent b48a0ff0e8
commit 7fb22740e1
14 changed files with 57 additions and 48 deletions

View File

@ -1,5 +1,11 @@
2022-02-05 Jay Berkenbilt <ejb@ql.org>
* Add a global user-defined string literal "_qpdf" as a shorthand
for QPDFObjectHandle::parse, allowing you to create
QPDFObjectHandle objects with
QPDFObjectHandle oh = "<</Some (PDF)>>"_qpdf;
* Expose QPDF::emptyPDF to the C API as qpdf_empty_pdf()
* Add comments letting people know that the version string

3
TODO
View File

@ -11,9 +11,6 @@
* QPDFObjectHandle: getValueAsX methods, getKeyIfDict. Plus C API.
* Add user-defined initializer `QPDFObjectHandle operator ""_qpdf` to
be like QPDFObjectHandle::parse: `auto oh = "<< /a (b) >>"_qpdf;`
* See if this has been done or is trivial with C++11 local static
initializers: Secure random number generation could be made more
efficient by using a local static to ensure a single random device

View File

@ -36,16 +36,16 @@ static void process(char const* infilename, char const* password,
QPDF q;
q.processFile(infilename, password);
// Create an indirect object for the built-in Helvetica font.
// Create an indirect object for the built-in Helvetica font. This
// uses the qpdf literal syntax introduced in qpdf 10.6.
auto f1 = q.makeIndirectObject(
QPDFObjectHandle::parse(
"<<"
" /Type /Font"
" /Subtype /Type1"
" /Name /F1"
" /BaseFont /Helvetica"
" /Encoding /WinAnsiEncoding"
">>"));
"<<"
" /Type /Font"
" /Subtype /Type1"
" /Name /F1"
" /BaseFont /Helvetica"
" /Encoding /WinAnsiEncoding"
">>"_qpdf);
// Create a resources dictionary with fonts. This uses the new
// parse introduced in qpdf 10.2 that takes a QPDF* and allows
@ -93,7 +93,7 @@ static void process(char const* infilename, char const* password,
apdict.replaceKey("/Resources", QPDFObjectHandle::newDictionary());
apdict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject"));
apdict.replaceKey("/Subtype", QPDFObjectHandle::newName("/Form"));
apdict.replaceKey("/BBox", QPDFObjectHandle::parse("[ 0 0 20 20 ]"));
apdict.replaceKey("/BBox", "[ 0 0 20 20 ]"_qpdf);
auto annot = q.makeIndirectObject(
QPDFObjectHandle::parse(
&q,

View File

@ -182,12 +182,11 @@ void add_page(QPDFPageDocumentHelper& dh, QPDFObjectHandle font,
size_t width = p->getWidth();
size_t height = p->getHeight();
QPDFObjectHandle image = QPDFObjectHandle::newStream(&pdf);
image.replaceDict(QPDFObjectHandle::parse(
"<<"
" /Type /XObject"
" /Subtype /Image"
" /BitsPerComponent 8"
">>"));
image.replaceDict("<<"
" /Type /XObject"
" /Subtype /Image"
" /BitsPerComponent 8"
">>"_qpdf);
QPDFObjectHandle image_dict = image.getDict();
image_dict.replaceKey("/ColorSpace", newName(color_space));
image_dict.replaceKey("/Width", newInteger(width));
@ -199,8 +198,7 @@ void add_page(QPDFPageDocumentHelper& dh, QPDFObjectHandle font,
QPDFObjectHandle::newNull());
// Create direct objects as needed by the page dictionary.
QPDFObjectHandle procset = QPDFObjectHandle::parse(
"[/PDF /Text /ImageC]");
QPDFObjectHandle procset = "[/PDF /Text /ImageC]"_qpdf;
QPDFObjectHandle rfont = QPDFObjectHandle::newDictionary();
rfont.replaceKey("/F1", font);
@ -384,14 +382,13 @@ static void create_pdf(char const* filename)
// Add an indirect object to contain a font descriptor for the
// built-in Helvetica font.
QPDFObjectHandle font = pdf.makeIndirectObject(
QPDFObjectHandle::parse(
"<<"
" /Type /Font"
" /Subtype /Type1"
" /Name /F1"
" /BaseFont /Helvetica"
" /Encoding /WinAnsiEncoding"
">>"));
"<<"
" /Type /Font"
" /Subtype /Type1"
" /Name /F1"
" /BaseFont /Helvetica"
" /Encoding /WinAnsiEncoding"
">>"_qpdf);
std::vector<std::string> color_spaces;
color_spaces.push_back("/DeviceCMYK");

View File

@ -65,8 +65,7 @@ static void stamp_page(char const* infile,
// Append the content to the page's content. Surround the
// original content with q...Q to the new content from the
// page's original content.
resources.mergeResources(
QPDFObjectHandle::parse("<< /XObject << >> >>"));
resources.mergeResources("<< /XObject << >> >>"_qpdf);
resources.getKey("/XObject").replaceKey(name, stamp_fo);
ph.addPageContents(
QPDFObjectHandle::newStream(&inpdf, "q\n"), true);

View File

@ -395,7 +395,7 @@ class QPDFObjectHandle
// object syntax (obj gen R) will cause a logic_error exception to
// be thrown. If object_description is provided, it will appear
// in the message of any QPDFExc exception thrown for invalid
// syntax.
// syntax. See also the global `operator ""_qpdf` defined below.
QPDF_DLL
static QPDFObjectHandle parse(std::string const& object_str,
std::string const& object_description = "");
@ -1450,6 +1450,17 @@ class QPDFObjectHandle
bool reserved;
};
#ifndef QPDF_NO_QPDF_STRING
// This is short for QPDFObjectHandle::parse, so you can do
// auto oh = "<< /Key (value) >>"_qpdf;
// If this is causing problems in your code, define
// QPDF_NO_QPDF_STRING to prevent the declaration from being here.
QPDF_DLL
QPDFObjectHandle operator ""_qpdf(char const* v, size_t len);
#endif // QPDF_NO_QPDF_STRING
class QPDFObjectHandle::QPDFDictItems
{
// This class allows C++-style iteration, including range-for

View File

@ -981,8 +981,7 @@ QPDFFormFieldObjectHelper::generateTextAppearance(
AS.getDict().replaceKey("/Resources", resources);
}
// Use mergeResources to force /Font to be local
resources.mergeResources(
QPDFObjectHandle::parse("<< /Font << >> >>"));
resources.mergeResources("<< /Font << >> >>"_qpdf);
resources.getKey("/Font").replaceKey(font_name, font);
}

View File

@ -2281,8 +2281,7 @@ QPDFJob::doUnderOverlayForPage(
from_page, cm, dest_afdh, make_afdh(from_page));
if (! new_content.empty())
{
resources.mergeResources(
QPDFObjectHandle::parse("<< /XObject << >> >>"));
resources.mergeResources("<< /XObject << >> >>"_qpdf);
auto xobject = resources.getKey("/XObject");
if (xobject.isDictionary())
{

View File

@ -61,8 +61,7 @@ QPDFNameTreeObjectHelper
QPDFNameTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair)
{
return QPDFNameTreeObjectHelper(
qpdf.makeIndirectObject(
QPDFObjectHandle::parse("<< /Names [] >>")), qpdf, auto_repair);
qpdf.makeIndirectObject("<< /Names [] >>"_qpdf), qpdf, auto_repair);
}
QPDFNameTreeObjectHelper::iterator::iterator(

View File

@ -58,8 +58,7 @@ QPDFNumberTreeObjectHelper
QPDFNumberTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair)
{
return QPDFNumberTreeObjectHelper(
qpdf.makeIndirectObject(
QPDFObjectHandle::parse("<< /Nums [] >>")), qpdf, auto_repair);
qpdf.makeIndirectObject("<< /Nums [] >>"_qpdf), qpdf, auto_repair);
}
QPDFNumberTreeObjectHelper::iterator::iterator(

View File

@ -3666,3 +3666,10 @@ QPDFObjectHandle::QPDFArrayItems::end()
{
return iterator(oh, false);
}
QPDFObjectHandle
operator ""_qpdf(char const* v, size_t len)
{
return QPDFObjectHandle::parse(
std::string(v, len), "QPDFObjectHandle literal");
}

View File

@ -161,8 +161,7 @@ QPDFPageDocumentHelper::flattenAnnotationsForPage(
name, rotate, required_flags, forbidden_flags);
if (! content.empty())
{
resources.mergeResources(
QPDFObjectHandle::parse("<< /XObject << >> >>"));
resources.mergeResources("<< /XObject << >> >>"_qpdf);
resources.getKey("/XObject").replaceKey(name, as);
++next_fx;
}

View File

@ -500,8 +500,7 @@ QPDFPageObjectHelper::externalizeInlineImages(size_t min_size, bool shallow)
QPDFObjectHandle resources = getAttribute("/Resources", true);
// Calling mergeResources also ensures that /XObject becomes
// direct and is not shared with other pages.
resources.mergeResources(
QPDFObjectHandle::parse("<< /XObject << >> >>"));
resources.mergeResources("<< /XObject << >> >>"_qpdf);
InlineImageTracker iit(this->oh.getOwningQPDF(), min_size, resources);
Pl_Buffer b("new page content");
bool filtered = false;

View File

@ -1255,10 +1255,8 @@ static void test_31(QPDF& pdf, char const* arg2)
{
// Test object parsing from a string. The input file is not used.
QPDFObjectHandle o1 =
QPDFObjectHandle::parse(
"[/name 16059 3.14159 false\n"
" << /key true /other [ (string1) (string2) ] >> null]");
auto o1 = "[/name 16059 3.14159 false\n"
" << /key true /other [ (string1) (string2) ] >> null]"_qpdf;
std::cout << o1.unparse() << std::endl;
QPDFObjectHandle o2 = QPDFObjectHandle::parse(" 12345 \f ");
assert(o2.isInteger() && (o2.getIntValue() == 12345));