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

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> 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() * Expose QPDF::emptyPDF to the C API as qpdf_empty_pdf()
* Add comments letting people know that the version string * Add comments letting people know that the version string

3
TODO
View File

@ -11,9 +11,6 @@
* QPDFObjectHandle: getValueAsX methods, getKeyIfDict. Plus C API. * 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 * See if this has been done or is trivial with C++11 local static
initializers: Secure random number generation could be made more initializers: Secure random number generation could be made more
efficient by using a local static to ensure a single random device 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; QPDF q;
q.processFile(infilename, password); 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( auto f1 = q.makeIndirectObject(
QPDFObjectHandle::parse( "<<"
"<<" " /Type /Font"
" /Type /Font" " /Subtype /Type1"
" /Subtype /Type1" " /Name /F1"
" /Name /F1" " /BaseFont /Helvetica"
" /BaseFont /Helvetica" " /Encoding /WinAnsiEncoding"
" /Encoding /WinAnsiEncoding" ">>"_qpdf);
">>"));
// Create a resources dictionary with fonts. This uses the new // Create a resources dictionary with fonts. This uses the new
// parse introduced in qpdf 10.2 that takes a QPDF* and allows // 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("/Resources", QPDFObjectHandle::newDictionary());
apdict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject")); apdict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject"));
apdict.replaceKey("/Subtype", QPDFObjectHandle::newName("/Form")); 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( auto annot = q.makeIndirectObject(
QPDFObjectHandle::parse( QPDFObjectHandle::parse(
&q, &q,

View File

@ -182,12 +182,11 @@ void add_page(QPDFPageDocumentHelper& dh, QPDFObjectHandle font,
size_t width = p->getWidth(); size_t width = p->getWidth();
size_t height = p->getHeight(); size_t height = p->getHeight();
QPDFObjectHandle image = QPDFObjectHandle::newStream(&pdf); QPDFObjectHandle image = QPDFObjectHandle::newStream(&pdf);
image.replaceDict(QPDFObjectHandle::parse( image.replaceDict("<<"
"<<" " /Type /XObject"
" /Type /XObject" " /Subtype /Image"
" /Subtype /Image" " /BitsPerComponent 8"
" /BitsPerComponent 8" ">>"_qpdf);
">>"));
QPDFObjectHandle image_dict = image.getDict(); QPDFObjectHandle image_dict = image.getDict();
image_dict.replaceKey("/ColorSpace", newName(color_space)); image_dict.replaceKey("/ColorSpace", newName(color_space));
image_dict.replaceKey("/Width", newInteger(width)); image_dict.replaceKey("/Width", newInteger(width));
@ -199,8 +198,7 @@ void add_page(QPDFPageDocumentHelper& dh, QPDFObjectHandle font,
QPDFObjectHandle::newNull()); QPDFObjectHandle::newNull());
// Create direct objects as needed by the page dictionary. // Create direct objects as needed by the page dictionary.
QPDFObjectHandle procset = QPDFObjectHandle::parse( QPDFObjectHandle procset = "[/PDF /Text /ImageC]"_qpdf;
"[/PDF /Text /ImageC]");
QPDFObjectHandle rfont = QPDFObjectHandle::newDictionary(); QPDFObjectHandle rfont = QPDFObjectHandle::newDictionary();
rfont.replaceKey("/F1", font); 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 // Add an indirect object to contain a font descriptor for the
// built-in Helvetica font. // built-in Helvetica font.
QPDFObjectHandle font = pdf.makeIndirectObject( QPDFObjectHandle font = pdf.makeIndirectObject(
QPDFObjectHandle::parse( "<<"
"<<" " /Type /Font"
" /Type /Font" " /Subtype /Type1"
" /Subtype /Type1" " /Name /F1"
" /Name /F1" " /BaseFont /Helvetica"
" /BaseFont /Helvetica" " /Encoding /WinAnsiEncoding"
" /Encoding /WinAnsiEncoding" ">>"_qpdf);
">>"));
std::vector<std::string> color_spaces; std::vector<std::string> color_spaces;
color_spaces.push_back("/DeviceCMYK"); 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 // Append the content to the page's content. Surround the
// original content with q...Q to the new content from the // original content with q...Q to the new content from the
// page's original content. // page's original content.
resources.mergeResources( resources.mergeResources("<< /XObject << >> >>"_qpdf);
QPDFObjectHandle::parse("<< /XObject << >> >>"));
resources.getKey("/XObject").replaceKey(name, stamp_fo); resources.getKey("/XObject").replaceKey(name, stamp_fo);
ph.addPageContents( ph.addPageContents(
QPDFObjectHandle::newStream(&inpdf, "q\n"), true); 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 // object syntax (obj gen R) will cause a logic_error exception to
// be thrown. If object_description is provided, it will appear // be thrown. If object_description is provided, it will appear
// in the message of any QPDFExc exception thrown for invalid // in the message of any QPDFExc exception thrown for invalid
// syntax. // syntax. See also the global `operator ""_qpdf` defined below.
QPDF_DLL QPDF_DLL
static QPDFObjectHandle parse(std::string const& object_str, static QPDFObjectHandle parse(std::string const& object_str,
std::string const& object_description = ""); std::string const& object_description = "");
@ -1450,6 +1450,17 @@ class QPDFObjectHandle
bool reserved; 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 class QPDFObjectHandle::QPDFDictItems
{ {
// This class allows C++-style iteration, including range-for // This class allows C++-style iteration, including range-for

View File

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

View File

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

View File

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

View File

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

View File

@ -3666,3 +3666,10 @@ QPDFObjectHandle::QPDFArrayItems::end()
{ {
return iterator(oh, false); 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); name, rotate, required_flags, forbidden_flags);
if (! content.empty()) if (! content.empty())
{ {
resources.mergeResources( resources.mergeResources("<< /XObject << >> >>"_qpdf);
QPDFObjectHandle::parse("<< /XObject << >> >>"));
resources.getKey("/XObject").replaceKey(name, as); resources.getKey("/XObject").replaceKey(name, as);
++next_fx; ++next_fx;
} }

View File

@ -500,8 +500,7 @@ QPDFPageObjectHelper::externalizeInlineImages(size_t min_size, bool shallow)
QPDFObjectHandle resources = getAttribute("/Resources", true); QPDFObjectHandle resources = getAttribute("/Resources", true);
// Calling mergeResources also ensures that /XObject becomes // Calling mergeResources also ensures that /XObject becomes
// direct and is not shared with other pages. // direct and is not shared with other pages.
resources.mergeResources( resources.mergeResources("<< /XObject << >> >>"_qpdf);
QPDFObjectHandle::parse("<< /XObject << >> >>"));
InlineImageTracker iit(this->oh.getOwningQPDF(), min_size, resources); InlineImageTracker iit(this->oh.getOwningQPDF(), min_size, resources);
Pl_Buffer b("new page content"); Pl_Buffer b("new page content");
bool filtered = false; 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. // Test object parsing from a string. The input file is not used.
QPDFObjectHandle o1 = auto o1 = "[/name 16059 3.14159 false\n"
QPDFObjectHandle::parse( " << /key true /other [ (string1) (string2) ] >> null]"_qpdf;
"[/name 16059 3.14159 false\n"
" << /key true /other [ (string1) (string2) ] >> null]");
std::cout << o1.unparse() << std::endl; std::cout << o1.unparse() << std::endl;
QPDFObjectHandle o2 = QPDFObjectHandle::parse(" 12345 \f "); QPDFObjectHandle o2 = QPDFObjectHandle::parse(" 12345 \f ");
assert(o2.isInteger() && (o2.getIntValue() == 12345)); assert(o2.isInteger() && (o2.getIntValue() == 12345));