Commit 4cded10821e3bd523cf96eb628d7364820a07b84
1 parent
078cf9bf
Add QPDFObjectHandle::Rectangle type
Provide a convenient way of accessing rectangles.
Showing
4 changed files
with
127 additions
and
2 deletions
ChangeLog
| 1 | +2018-06-19 Jay Berkenbilt <ejb@ql.org> | ||
| 2 | + | ||
| 3 | + * New QPDFObject::Rectangle class will convert to and from arrays | ||
| 4 | + of four numerical values. Rectangles are used in various places | ||
| 5 | + within the PDF file format and are called out as a specific data | ||
| 6 | + type in the PDF specification. | ||
| 7 | + | ||
| 1 | 2018-05-12 Jay Berkenbilt <ejb@ql.org> | 8 | 2018-05-12 Jay Berkenbilt <ejb@ql.org> |
| 2 | 9 | ||
| 3 | * In newline before endstream mode, an extra newline was not | 10 | * In newline before endstream mode, an extra newline was not |
include/qpdf/QPDFObjectHandle.hh
| @@ -172,6 +172,31 @@ class QPDFObjectHandle | @@ -172,6 +172,31 @@ class QPDFObjectHandle | ||
| 172 | void terminateParsing(); | 172 | void terminateParsing(); |
| 173 | }; | 173 | }; |
| 174 | 174 | ||
| 175 | + // Convenience object for rectangles | ||
| 176 | + class Rectangle | ||
| 177 | + { | ||
| 178 | + public: | ||
| 179 | + Rectangle() : | ||
| 180 | + llx(0.0), | ||
| 181 | + lly(0.0), | ||
| 182 | + urx(0.0), | ||
| 183 | + ury(0.0) | ||
| 184 | + { | ||
| 185 | + } | ||
| 186 | + Rectangle(double llx, double lly, | ||
| 187 | + double urx, double ury) : | ||
| 188 | + llx(llx), | ||
| 189 | + lly(lly), | ||
| 190 | + urx(urx), | ||
| 191 | + ury(ury) | ||
| 192 | + { | ||
| 193 | + } | ||
| 194 | + | ||
| 195 | + double llx; | ||
| 196 | + double lly; | ||
| 197 | + double urx; | ||
| 198 | + double ury; | ||
| 199 | + }; | ||
| 175 | 200 | ||
| 176 | QPDF_DLL | 201 | QPDF_DLL |
| 177 | QPDFObjectHandle(); | 202 | QPDFObjectHandle(); |
| @@ -344,11 +369,18 @@ class QPDFObjectHandle | @@ -344,11 +369,18 @@ class QPDFObjectHandle | ||
| 344 | static QPDFObjectHandle newArray( | 369 | static QPDFObjectHandle newArray( |
| 345 | std::vector<QPDFObjectHandle> const& items); | 370 | std::vector<QPDFObjectHandle> const& items); |
| 346 | QPDF_DLL | 371 | QPDF_DLL |
| 372 | + static QPDFObjectHandle newArray(Rectangle const&); | ||
| 373 | + QPDF_DLL | ||
| 347 | static QPDFObjectHandle newDictionary(); | 374 | static QPDFObjectHandle newDictionary(); |
| 348 | QPDF_DLL | 375 | QPDF_DLL |
| 349 | static QPDFObjectHandle newDictionary( | 376 | static QPDFObjectHandle newDictionary( |
| 350 | std::map<std::string, QPDFObjectHandle> const& items); | 377 | std::map<std::string, QPDFObjectHandle> const& items); |
| 351 | 378 | ||
| 379 | + // Create an array from a rectangle. Equivalent to the rectangle | ||
| 380 | + // form of newArray. | ||
| 381 | + QPDF_DLL | ||
| 382 | + static QPDFObjectHandle newFromRectangle(Rectangle const&); | ||
| 383 | + | ||
| 352 | // Create a new stream and associate it with the given qpdf | 384 | // Create a new stream and associate it with the given qpdf |
| 353 | // object. A subsequent call must be made to replaceStreamData() | 385 | // object. A subsequent call must be made to replaceStreamData() |
| 354 | // to provide data for the stream. The stream's dictionary may be | 386 | // to provide data for the stream. The stream's dictionary may be |
| @@ -465,6 +497,12 @@ class QPDFObjectHandle | @@ -465,6 +497,12 @@ class QPDFObjectHandle | ||
| 465 | QPDFObjectHandle getArrayItem(int n); | 497 | QPDFObjectHandle getArrayItem(int n); |
| 466 | QPDF_DLL | 498 | QPDF_DLL |
| 467 | std::vector<QPDFObjectHandle> getArrayAsVector(); | 499 | std::vector<QPDFObjectHandle> getArrayAsVector(); |
| 500 | + QPDF_DLL | ||
| 501 | + bool isRectangle(); | ||
| 502 | + // If the array an array of four numeric values, return as a | ||
| 503 | + // rectangle. Otherwise, return the rectangle [0, 0, 0, 0] | ||
| 504 | + QPDF_DLL | ||
| 505 | + Rectangle getArrayAsRectangle(); | ||
| 468 | 506 | ||
| 469 | // Methods for dictionary objects | 507 | // Methods for dictionary objects |
| 470 | QPDF_DLL | 508 | QPDF_DLL |
| @@ -739,6 +777,15 @@ class QPDFObjectHandle | @@ -739,6 +777,15 @@ class QPDFObjectHandle | ||
| 739 | QPDF_DLL | 777 | QPDF_DLL |
| 740 | void coalesceContentStreams(); | 778 | void coalesceContentStreams(); |
| 741 | 779 | ||
| 780 | + // Issue a warning about this object if possible. If the object | ||
| 781 | + // has a description, a warning will be issued. Otherwise, if | ||
| 782 | + // throw_if_no_description is true, throw an exception. Otherwise | ||
| 783 | + // do nothing. Objects read normally from the file have | ||
| 784 | + // descriptions. See comments on setObjectDescription for | ||
| 785 | + // additional details. | ||
| 786 | + void warnIfPossible(std::string const& warning, | ||
| 787 | + bool throw_if_no_description = false); | ||
| 788 | + | ||
| 742 | // Initializers for objects. This Factory class gives the QPDF | 789 | // Initializers for objects. This Factory class gives the QPDF |
| 743 | // class specific permission to call factory methods without | 790 | // class specific permission to call factory methods without |
| 744 | // making it a friend of the whole QPDFObjectHandle class. | 791 | // making it a friend of the whole QPDFObjectHandle class. |
libqpdf/QPDFObjectHandle.cc
| @@ -554,6 +554,42 @@ QPDFObjectHandle::getArrayItem(int n) | @@ -554,6 +554,42 @@ QPDFObjectHandle::getArrayItem(int n) | ||
| 554 | return result; | 554 | return result; |
| 555 | } | 555 | } |
| 556 | 556 | ||
| 557 | +bool | ||
| 558 | +QPDFObjectHandle::isRectangle() | ||
| 559 | +{ | ||
| 560 | + if (! isArray()) | ||
| 561 | + { | ||
| 562 | + return false; | ||
| 563 | + } | ||
| 564 | + if (getArrayNItems() != 4) | ||
| 565 | + { | ||
| 566 | + return false; | ||
| 567 | + } | ||
| 568 | + for (size_t i = 0; i < 4; ++i) | ||
| 569 | + { | ||
| 570 | + if (! getArrayItem(i).isNumber()) | ||
| 571 | + { | ||
| 572 | + return false; | ||
| 573 | + } | ||
| 574 | + } | ||
| 575 | + return true; | ||
| 576 | +} | ||
| 577 | + | ||
| 578 | + | ||
| 579 | +QPDFObjectHandle::Rectangle | ||
| 580 | +QPDFObjectHandle::getArrayAsRectangle() | ||
| 581 | +{ | ||
| 582 | + Rectangle result; | ||
| 583 | + if (isRectangle()) | ||
| 584 | + { | ||
| 585 | + result = Rectangle(getArrayItem(0).getNumericValue(), | ||
| 586 | + getArrayItem(1).getNumericValue(), | ||
| 587 | + getArrayItem(2).getNumericValue(), | ||
| 588 | + getArrayItem(3).getNumericValue()); | ||
| 589 | + } | ||
| 590 | + return result; | ||
| 591 | +} | ||
| 592 | + | ||
| 557 | std::vector<QPDFObjectHandle> | 593 | std::vector<QPDFObjectHandle> |
| 558 | QPDFObjectHandle::getArrayAsVector() | 594 | QPDFObjectHandle::getArrayAsVector() |
| 559 | { | 595 | { |
| @@ -1834,6 +1870,23 @@ QPDFObjectHandle::newArray(std::vector<QPDFObjectHandle> const& items) | @@ -1834,6 +1870,23 @@ QPDFObjectHandle::newArray(std::vector<QPDFObjectHandle> const& items) | ||
| 1834 | } | 1870 | } |
| 1835 | 1871 | ||
| 1836 | QPDFObjectHandle | 1872 | QPDFObjectHandle |
| 1873 | +QPDFObjectHandle::newArray(Rectangle const& rect) | ||
| 1874 | +{ | ||
| 1875 | + std::vector<QPDFObjectHandle> items; | ||
| 1876 | + items.push_back(newReal(rect.llx)); | ||
| 1877 | + items.push_back(newReal(rect.lly)); | ||
| 1878 | + items.push_back(newReal(rect.urx)); | ||
| 1879 | + items.push_back(newReal(rect.ury)); | ||
| 1880 | + return newArray(items); | ||
| 1881 | +} | ||
| 1882 | + | ||
| 1883 | +QPDFObjectHandle | ||
| 1884 | +QPDFObjectHandle::newFromRectangle(Rectangle const& rect) | ||
| 1885 | +{ | ||
| 1886 | + return newArray(rect); | ||
| 1887 | +} | ||
| 1888 | + | ||
| 1889 | +QPDFObjectHandle | ||
| 1837 | QPDFObjectHandle::newDictionary() | 1890 | QPDFObjectHandle::newDictionary() |
| 1838 | { | 1891 | { |
| 1839 | return newDictionary(std::map<std::string, QPDFObjectHandle>()); | 1892 | return newDictionary(std::map<std::string, QPDFObjectHandle>()); |
| @@ -2103,7 +2156,8 @@ QPDFObjectHandle::typeWarning(char const* expected_type, | @@ -2103,7 +2156,8 @@ QPDFObjectHandle::typeWarning(char const* expected_type, | ||
| 2103 | } | 2156 | } |
| 2104 | 2157 | ||
| 2105 | void | 2158 | void |
| 2106 | -QPDFObjectHandle::objectWarning(std::string const& warning) | 2159 | +QPDFObjectHandle::warnIfPossible(std::string const& warning, |
| 2160 | + bool throw_if_no_description) | ||
| 2107 | { | 2161 | { |
| 2108 | QPDF* context = 0; | 2162 | QPDF* context = 0; |
| 2109 | std::string description; | 2163 | std::string description; |
| @@ -2115,13 +2169,19 @@ QPDFObjectHandle::objectWarning(std::string const& warning) | @@ -2115,13 +2169,19 @@ QPDFObjectHandle::objectWarning(std::string const& warning) | ||
| 2115 | "", description, 0, | 2169 | "", description, 0, |
| 2116 | warning)); | 2170 | warning)); |
| 2117 | } | 2171 | } |
| 2118 | - else | 2172 | + else if (throw_if_no_description) |
| 2119 | { | 2173 | { |
| 2120 | throw std::logic_error(warning); | 2174 | throw std::logic_error(warning); |
| 2121 | } | 2175 | } |
| 2122 | } | 2176 | } |
| 2123 | 2177 | ||
| 2124 | void | 2178 | void |
| 2179 | +QPDFObjectHandle::objectWarning(std::string const& warning) | ||
| 2180 | +{ | ||
| 2181 | + warnIfPossible(warning, true); | ||
| 2182 | +} | ||
| 2183 | + | ||
| 2184 | +void | ||
| 2125 | QPDFObjectHandle::assertType(char const* type_name, bool istype) | 2185 | QPDFObjectHandle::assertType(char const* type_name, bool istype) |
| 2126 | { | 2186 | { |
| 2127 | if (! istype) | 2187 | if (! istype) |
qpdf/test_driver.cc
| @@ -1449,6 +1449,17 @@ void runtest(int n, char const* filename1, char const* arg2) | @@ -1449,6 +1449,17 @@ void runtest(int n, char const* filename1, char const* arg2) | ||
| 1449 | QPDFObjectHandle page = pdf.getAllPages()[0]; | 1449 | QPDFObjectHandle page = pdf.getAllPages()[0]; |
| 1450 | assert("/QPDFFakeName" == | 1450 | assert("/QPDFFakeName" == |
| 1451 | page.getKey("/Contents").getDict().getKey("/Potato").getName()); | 1451 | page.getKey("/Contents").getDict().getKey("/Potato").getName()); |
| 1452 | + // Rectangles | ||
| 1453 | + QPDFObjectHandle::Rectangle r0 = integer.getArrayAsRectangle(); | ||
| 1454 | + assert((r0.llx == 0) && (r0.lly == 0) && | ||
| 1455 | + (r0.urx == 0) && (r0.ury == 0)); | ||
| 1456 | + QPDFObjectHandle rect = QPDFObjectHandle::newFromRectangle( | ||
| 1457 | + QPDFObjectHandle::Rectangle(1.2, 3.4, 5.6, 7.8)); | ||
| 1458 | + QPDFObjectHandle::Rectangle r1 = rect.getArrayAsRectangle(); | ||
| 1459 | + assert((r1.llx > 1.19) && (r1.llx < 1.21) && | ||
| 1460 | + (r1.lly > 3.39) && (r1.lly < 3.41) && | ||
| 1461 | + (r1.urx > 5.59) && (r1.urx < 5.61) && | ||
| 1462 | + (r1.ury > 7.79) && (r1.ury < 7.81)); | ||
| 1452 | } | 1463 | } |
| 1453 | else | 1464 | else |
| 1454 | { | 1465 | { |