Commit 7fb22740e131d997fb68bc113b8d9b4472e2c908
1 parent
b48a0ff0
Add operator ""_qpdf for creating QPDFObjectHandle literals
Showing
14 changed files
with
57 additions
and
48 deletions
ChangeLog
| 1 | 1 | 2022-02-05 Jay Berkenbilt <ejb@ql.org> |
| 2 | 2 | |
| 3 | + * Add a global user-defined string literal "_qpdf" as a shorthand | |
| 4 | + for QPDFObjectHandle::parse, allowing you to create | |
| 5 | + QPDFObjectHandle objects with | |
| 6 | + | |
| 7 | + QPDFObjectHandle oh = "<</Some (PDF)>>"_qpdf; | |
| 8 | + | |
| 3 | 9 | * Expose QPDF::emptyPDF to the C API as qpdf_empty_pdf() |
| 4 | 10 | |
| 5 | 11 | * Add comments letting people know that the version string | ... | ... |
TODO
| ... | ... | @@ -11,9 +11,6 @@ |
| 11 | 11 | |
| 12 | 12 | * QPDFObjectHandle: getValueAsX methods, getKeyIfDict. Plus C API. |
| 13 | 13 | |
| 14 | -* Add user-defined initializer `QPDFObjectHandle operator ""_qpdf` to | |
| 15 | - be like QPDFObjectHandle::parse: `auto oh = "<< /a (b) >>"_qpdf;` | |
| 16 | - | |
| 17 | 14 | * See if this has been done or is trivial with C++11 local static |
| 18 | 15 | initializers: Secure random number generation could be made more |
| 19 | 16 | efficient by using a local static to ensure a single random device | ... | ... |
examples/pdf-attach-file.cc
| ... | ... | @@ -36,16 +36,16 @@ static void process(char const* infilename, char const* password, |
| 36 | 36 | QPDF q; |
| 37 | 37 | q.processFile(infilename, password); |
| 38 | 38 | |
| 39 | - // Create an indirect object for the built-in Helvetica font. | |
| 39 | + // Create an indirect object for the built-in Helvetica font. This | |
| 40 | + // uses the qpdf literal syntax introduced in qpdf 10.6. | |
| 40 | 41 | auto f1 = q.makeIndirectObject( |
| 41 | - QPDFObjectHandle::parse( | |
| 42 | - "<<" | |
| 43 | - " /Type /Font" | |
| 44 | - " /Subtype /Type1" | |
| 45 | - " /Name /F1" | |
| 46 | - " /BaseFont /Helvetica" | |
| 47 | - " /Encoding /WinAnsiEncoding" | |
| 48 | - ">>")); | |
| 42 | + "<<" | |
| 43 | + " /Type /Font" | |
| 44 | + " /Subtype /Type1" | |
| 45 | + " /Name /F1" | |
| 46 | + " /BaseFont /Helvetica" | |
| 47 | + " /Encoding /WinAnsiEncoding" | |
| 48 | + ">>"_qpdf); | |
| 49 | 49 | |
| 50 | 50 | // Create a resources dictionary with fonts. This uses the new |
| 51 | 51 | // 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, |
| 93 | 93 | apdict.replaceKey("/Resources", QPDFObjectHandle::newDictionary()); |
| 94 | 94 | apdict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject")); |
| 95 | 95 | apdict.replaceKey("/Subtype", QPDFObjectHandle::newName("/Form")); |
| 96 | - apdict.replaceKey("/BBox", QPDFObjectHandle::parse("[ 0 0 20 20 ]")); | |
| 96 | + apdict.replaceKey("/BBox", "[ 0 0 20 20 ]"_qpdf); | |
| 97 | 97 | auto annot = q.makeIndirectObject( |
| 98 | 98 | QPDFObjectHandle::parse( |
| 99 | 99 | &q, | ... | ... |
examples/pdf-create.cc
| ... | ... | @@ -182,12 +182,11 @@ void add_page(QPDFPageDocumentHelper& dh, QPDFObjectHandle font, |
| 182 | 182 | size_t width = p->getWidth(); |
| 183 | 183 | size_t height = p->getHeight(); |
| 184 | 184 | QPDFObjectHandle image = QPDFObjectHandle::newStream(&pdf); |
| 185 | - image.replaceDict(QPDFObjectHandle::parse( | |
| 186 | - "<<" | |
| 187 | - " /Type /XObject" | |
| 188 | - " /Subtype /Image" | |
| 189 | - " /BitsPerComponent 8" | |
| 190 | - ">>")); | |
| 185 | + image.replaceDict("<<" | |
| 186 | + " /Type /XObject" | |
| 187 | + " /Subtype /Image" | |
| 188 | + " /BitsPerComponent 8" | |
| 189 | + ">>"_qpdf); | |
| 191 | 190 | QPDFObjectHandle image_dict = image.getDict(); |
| 192 | 191 | image_dict.replaceKey("/ColorSpace", newName(color_space)); |
| 193 | 192 | image_dict.replaceKey("/Width", newInteger(width)); |
| ... | ... | @@ -199,8 +198,7 @@ void add_page(QPDFPageDocumentHelper& dh, QPDFObjectHandle font, |
| 199 | 198 | QPDFObjectHandle::newNull()); |
| 200 | 199 | |
| 201 | 200 | // Create direct objects as needed by the page dictionary. |
| 202 | - QPDFObjectHandle procset = QPDFObjectHandle::parse( | |
| 203 | - "[/PDF /Text /ImageC]"); | |
| 201 | + QPDFObjectHandle procset = "[/PDF /Text /ImageC]"_qpdf; | |
| 204 | 202 | |
| 205 | 203 | QPDFObjectHandle rfont = QPDFObjectHandle::newDictionary(); |
| 206 | 204 | rfont.replaceKey("/F1", font); |
| ... | ... | @@ -384,14 +382,13 @@ static void create_pdf(char const* filename) |
| 384 | 382 | // Add an indirect object to contain a font descriptor for the |
| 385 | 383 | // built-in Helvetica font. |
| 386 | 384 | QPDFObjectHandle font = pdf.makeIndirectObject( |
| 387 | - QPDFObjectHandle::parse( | |
| 388 | - "<<" | |
| 389 | - " /Type /Font" | |
| 390 | - " /Subtype /Type1" | |
| 391 | - " /Name /F1" | |
| 392 | - " /BaseFont /Helvetica" | |
| 393 | - " /Encoding /WinAnsiEncoding" | |
| 394 | - ">>")); | |
| 385 | + "<<" | |
| 386 | + " /Type /Font" | |
| 387 | + " /Subtype /Type1" | |
| 388 | + " /Name /F1" | |
| 389 | + " /BaseFont /Helvetica" | |
| 390 | + " /Encoding /WinAnsiEncoding" | |
| 391 | + ">>"_qpdf); | |
| 395 | 392 | |
| 396 | 393 | std::vector<std::string> color_spaces; |
| 397 | 394 | color_spaces.push_back("/DeviceCMYK"); | ... | ... |
examples/pdf-overlay-page.cc
| ... | ... | @@ -65,8 +65,7 @@ static void stamp_page(char const* infile, |
| 65 | 65 | // Append the content to the page's content. Surround the |
| 66 | 66 | // original content with q...Q to the new content from the |
| 67 | 67 | // page's original content. |
| 68 | - resources.mergeResources( | |
| 69 | - QPDFObjectHandle::parse("<< /XObject << >> >>")); | |
| 68 | + resources.mergeResources("<< /XObject << >> >>"_qpdf); | |
| 70 | 69 | resources.getKey("/XObject").replaceKey(name, stamp_fo); |
| 71 | 70 | ph.addPageContents( |
| 72 | 71 | QPDFObjectHandle::newStream(&inpdf, "q\n"), true); | ... | ... |
include/qpdf/QPDFObjectHandle.hh
| ... | ... | @@ -395,7 +395,7 @@ class QPDFObjectHandle |
| 395 | 395 | // object syntax (obj gen R) will cause a logic_error exception to |
| 396 | 396 | // be thrown. If object_description is provided, it will appear |
| 397 | 397 | // in the message of any QPDFExc exception thrown for invalid |
| 398 | - // syntax. | |
| 398 | + // syntax. See also the global `operator ""_qpdf` defined below. | |
| 399 | 399 | QPDF_DLL |
| 400 | 400 | static QPDFObjectHandle parse(std::string const& object_str, |
| 401 | 401 | std::string const& object_description = ""); |
| ... | ... | @@ -1450,6 +1450,17 @@ class QPDFObjectHandle |
| 1450 | 1450 | bool reserved; |
| 1451 | 1451 | }; |
| 1452 | 1452 | |
| 1453 | +#ifndef QPDF_NO_QPDF_STRING | |
| 1454 | +// This is short for QPDFObjectHandle::parse, so you can do | |
| 1455 | + | |
| 1456 | +// auto oh = "<< /Key (value) >>"_qpdf; | |
| 1457 | + | |
| 1458 | +// If this is causing problems in your code, define | |
| 1459 | +// QPDF_NO_QPDF_STRING to prevent the declaration from being here. | |
| 1460 | +QPDF_DLL | |
| 1461 | +QPDFObjectHandle operator ""_qpdf(char const* v, size_t len); | |
| 1462 | +#endif // QPDF_NO_QPDF_STRING | |
| 1463 | + | |
| 1453 | 1464 | class QPDFObjectHandle::QPDFDictItems |
| 1454 | 1465 | { |
| 1455 | 1466 | // This class allows C++-style iteration, including range-for | ... | ... |
libqpdf/QPDFFormFieldObjectHelper.cc
| ... | ... | @@ -981,8 +981,7 @@ QPDFFormFieldObjectHelper::generateTextAppearance( |
| 981 | 981 | AS.getDict().replaceKey("/Resources", resources); |
| 982 | 982 | } |
| 983 | 983 | // Use mergeResources to force /Font to be local |
| 984 | - resources.mergeResources( | |
| 985 | - QPDFObjectHandle::parse("<< /Font << >> >>")); | |
| 984 | + resources.mergeResources("<< /Font << >> >>"_qpdf); | |
| 986 | 985 | resources.getKey("/Font").replaceKey(font_name, font); |
| 987 | 986 | } |
| 988 | 987 | ... | ... |
libqpdf/QPDFJob.cc
| ... | ... | @@ -2281,8 +2281,7 @@ QPDFJob::doUnderOverlayForPage( |
| 2281 | 2281 | from_page, cm, dest_afdh, make_afdh(from_page)); |
| 2282 | 2282 | if (! new_content.empty()) |
| 2283 | 2283 | { |
| 2284 | - resources.mergeResources( | |
| 2285 | - QPDFObjectHandle::parse("<< /XObject << >> >>")); | |
| 2284 | + resources.mergeResources("<< /XObject << >> >>"_qpdf); | |
| 2286 | 2285 | auto xobject = resources.getKey("/XObject"); |
| 2287 | 2286 | if (xobject.isDictionary()) |
| 2288 | 2287 | { | ... | ... |
libqpdf/QPDFNameTreeObjectHelper.cc
| ... | ... | @@ -61,8 +61,7 @@ QPDFNameTreeObjectHelper |
| 61 | 61 | QPDFNameTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair) |
| 62 | 62 | { |
| 63 | 63 | return QPDFNameTreeObjectHelper( |
| 64 | - qpdf.makeIndirectObject( | |
| 65 | - QPDFObjectHandle::parse("<< /Names [] >>")), qpdf, auto_repair); | |
| 64 | + qpdf.makeIndirectObject("<< /Names [] >>"_qpdf), qpdf, auto_repair); | |
| 66 | 65 | } |
| 67 | 66 | |
| 68 | 67 | QPDFNameTreeObjectHelper::iterator::iterator( | ... | ... |
libqpdf/QPDFNumberTreeObjectHelper.cc
| ... | ... | @@ -58,8 +58,7 @@ QPDFNumberTreeObjectHelper |
| 58 | 58 | QPDFNumberTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair) |
| 59 | 59 | { |
| 60 | 60 | return QPDFNumberTreeObjectHelper( |
| 61 | - qpdf.makeIndirectObject( | |
| 62 | - QPDFObjectHandle::parse("<< /Nums [] >>")), qpdf, auto_repair); | |
| 61 | + qpdf.makeIndirectObject("<< /Nums [] >>"_qpdf), qpdf, auto_repair); | |
| 63 | 62 | } |
| 64 | 63 | |
| 65 | 64 | QPDFNumberTreeObjectHelper::iterator::iterator( | ... | ... |
libqpdf/QPDFObjectHandle.cc
| ... | ... | @@ -3666,3 +3666,10 @@ QPDFObjectHandle::QPDFArrayItems::end() |
| 3666 | 3666 | { |
| 3667 | 3667 | return iterator(oh, false); |
| 3668 | 3668 | } |
| 3669 | + | |
| 3670 | +QPDFObjectHandle | |
| 3671 | +operator ""_qpdf(char const* v, size_t len) | |
| 3672 | +{ | |
| 3673 | + return QPDFObjectHandle::parse( | |
| 3674 | + std::string(v, len), "QPDFObjectHandle literal"); | |
| 3675 | +} | ... | ... |
libqpdf/QPDFPageDocumentHelper.cc
| ... | ... | @@ -161,8 +161,7 @@ QPDFPageDocumentHelper::flattenAnnotationsForPage( |
| 161 | 161 | name, rotate, required_flags, forbidden_flags); |
| 162 | 162 | if (! content.empty()) |
| 163 | 163 | { |
| 164 | - resources.mergeResources( | |
| 165 | - QPDFObjectHandle::parse("<< /XObject << >> >>")); | |
| 164 | + resources.mergeResources("<< /XObject << >> >>"_qpdf); | |
| 166 | 165 | resources.getKey("/XObject").replaceKey(name, as); |
| 167 | 166 | ++next_fx; |
| 168 | 167 | } | ... | ... |
libqpdf/QPDFPageObjectHelper.cc
| ... | ... | @@ -500,8 +500,7 @@ QPDFPageObjectHelper::externalizeInlineImages(size_t min_size, bool shallow) |
| 500 | 500 | QPDFObjectHandle resources = getAttribute("/Resources", true); |
| 501 | 501 | // Calling mergeResources also ensures that /XObject becomes |
| 502 | 502 | // direct and is not shared with other pages. |
| 503 | - resources.mergeResources( | |
| 504 | - QPDFObjectHandle::parse("<< /XObject << >> >>")); | |
| 503 | + resources.mergeResources("<< /XObject << >> >>"_qpdf); | |
| 505 | 504 | InlineImageTracker iit(this->oh.getOwningQPDF(), min_size, resources); |
| 506 | 505 | Pl_Buffer b("new page content"); |
| 507 | 506 | bool filtered = false; | ... | ... |
qpdf/test_driver.cc
| ... | ... | @@ -1255,10 +1255,8 @@ static void test_31(QPDF& pdf, char const* arg2) |
| 1255 | 1255 | { |
| 1256 | 1256 | // Test object parsing from a string. The input file is not used. |
| 1257 | 1257 | |
| 1258 | - QPDFObjectHandle o1 = | |
| 1259 | - QPDFObjectHandle::parse( | |
| 1260 | - "[/name 16059 3.14159 false\n" | |
| 1261 | - " << /key true /other [ (string1) (string2) ] >> null]"); | |
| 1258 | + auto o1 = "[/name 16059 3.14159 false\n" | |
| 1259 | + " << /key true /other [ (string1) (string2) ] >> null]"_qpdf; | |
| 1262 | 1260 | std::cout << o1.unparse() << std::endl; |
| 1263 | 1261 | QPDFObjectHandle o2 = QPDFObjectHandle::parse(" 12345 \f "); |
| 1264 | 1262 | assert(o2.isInteger() && (o2.getIntValue() == 12345)); | ... | ... |