Commit 4cded10821e3bd523cf96eb628d7364820a07b84

Authored by Jay Berkenbilt
1 parent 078cf9bf

Add QPDFObjectHandle::Rectangle type

Provide a convenient way of accessing rectangles.
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 8 2018-05-12 Jay Berkenbilt <ejb@ql.org>
2 9  
3 10 * In newline before endstream mode, an extra newline was not
... ...
include/qpdf/QPDFObjectHandle.hh
... ... @@ -172,6 +172,31 @@ class QPDFObjectHandle
172 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 201 QPDF_DLL
177 202 QPDFObjectHandle();
... ... @@ -344,11 +369,18 @@ class QPDFObjectHandle
344 369 static QPDFObjectHandle newArray(
345 370 std::vector<QPDFObjectHandle> const& items);
346 371 QPDF_DLL
  372 + static QPDFObjectHandle newArray(Rectangle const&);
  373 + QPDF_DLL
347 374 static QPDFObjectHandle newDictionary();
348 375 QPDF_DLL
349 376 static QPDFObjectHandle newDictionary(
350 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 384 // Create a new stream and associate it with the given qpdf
353 385 // object. A subsequent call must be made to replaceStreamData()
354 386 // to provide data for the stream. The stream's dictionary may be
... ... @@ -465,6 +497,12 @@ class QPDFObjectHandle
465 497 QPDFObjectHandle getArrayItem(int n);
466 498 QPDF_DLL
467 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 507 // Methods for dictionary objects
470 508 QPDF_DLL
... ... @@ -739,6 +777,15 @@ class QPDFObjectHandle
739 777 QPDF_DLL
740 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 789 // Initializers for objects. This Factory class gives the QPDF
743 790 // class specific permission to call factory methods without
744 791 // making it a friend of the whole QPDFObjectHandle class.
... ...
libqpdf/QPDFObjectHandle.cc
... ... @@ -554,6 +554,42 @@ QPDFObjectHandle::getArrayItem(int n)
554 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 593 std::vector<QPDFObjectHandle>
558 594 QPDFObjectHandle::getArrayAsVector()
559 595 {
... ... @@ -1834,6 +1870,23 @@ QPDFObjectHandle::newArray(std::vector&lt;QPDFObjectHandle&gt; const&amp; items)
1834 1870 }
1835 1871  
1836 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 1890 QPDFObjectHandle::newDictionary()
1838 1891 {
1839 1892 return newDictionary(std::map<std::string, QPDFObjectHandle>());
... ... @@ -2103,7 +2156,8 @@ QPDFObjectHandle::typeWarning(char const* expected_type,
2103 2156 }
2104 2157  
2105 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 2162 QPDF* context = 0;
2109 2163 std::string description;
... ... @@ -2115,13 +2169,19 @@ QPDFObjectHandle::objectWarning(std::string const&amp; warning)
2115 2169 "", description, 0,
2116 2170 warning));
2117 2171 }
2118   - else
  2172 + else if (throw_if_no_description)
2119 2173 {
2120 2174 throw std::logic_error(warning);
2121 2175 }
2122 2176 }
2123 2177  
2124 2178 void
  2179 +QPDFObjectHandle::objectWarning(std::string const& warning)
  2180 +{
  2181 + warnIfPossible(warning, true);
  2182 +}
  2183 +
  2184 +void
2125 2185 QPDFObjectHandle::assertType(char const* type_name, bool istype)
2126 2186 {
2127 2187 if (! istype)
... ...
qpdf/test_driver.cc
... ... @@ -1449,6 +1449,17 @@ void runtest(int n, char const* filename1, char const* arg2)
1449 1449 QPDFObjectHandle page = pdf.getAllPages()[0];
1450 1450 assert("/QPDFFakeName" ==
1451 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 1464 else
1454 1465 {
... ...