aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--include/qpdf/QPDFObjectHandle.hh47
-rw-r--r--libqpdf/QPDFObjectHandle.cc64
-rw-r--r--qpdf/test_driver.cc11
4 files changed, 127 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index a0838606..a2f84f00 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2018-06-19 Jay Berkenbilt <ejb@ql.org>
+
+ * New QPDFObject::Rectangle class will convert to and from arrays
+ of four numerical values. Rectangles are used in various places
+ within the PDF file format and are called out as a specific data
+ type in the PDF specification.
+
2018-05-12 Jay Berkenbilt <ejb@ql.org>
* In newline before endstream mode, an extra newline was not
diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh
index 6f78e9a9..4f5cde37 100644
--- a/include/qpdf/QPDFObjectHandle.hh
+++ b/include/qpdf/QPDFObjectHandle.hh
@@ -172,6 +172,31 @@ class QPDFObjectHandle
void terminateParsing();
};
+ // Convenience object for rectangles
+ class Rectangle
+ {
+ public:
+ Rectangle() :
+ llx(0.0),
+ lly(0.0),
+ urx(0.0),
+ ury(0.0)
+ {
+ }
+ Rectangle(double llx, double lly,
+ double urx, double ury) :
+ llx(llx),
+ lly(lly),
+ urx(urx),
+ ury(ury)
+ {
+ }
+
+ double llx;
+ double lly;
+ double urx;
+ double ury;
+ };
QPDF_DLL
QPDFObjectHandle();
@@ -344,11 +369,18 @@ class QPDFObjectHandle
static QPDFObjectHandle newArray(
std::vector<QPDFObjectHandle> const& items);
QPDF_DLL
+ static QPDFObjectHandle newArray(Rectangle const&);
+ QPDF_DLL
static QPDFObjectHandle newDictionary();
QPDF_DLL
static QPDFObjectHandle newDictionary(
std::map<std::string, QPDFObjectHandle> const& items);
+ // Create an array from a rectangle. Equivalent to the rectangle
+ // form of newArray.
+ QPDF_DLL
+ static QPDFObjectHandle newFromRectangle(Rectangle const&);
+
// Create a new stream and associate it with the given qpdf
// object. A subsequent call must be made to replaceStreamData()
// to provide data for the stream. The stream's dictionary may be
@@ -465,6 +497,12 @@ class QPDFObjectHandle
QPDFObjectHandle getArrayItem(int n);
QPDF_DLL
std::vector<QPDFObjectHandle> getArrayAsVector();
+ QPDF_DLL
+ bool isRectangle();
+ // If the array an array of four numeric values, return as a
+ // rectangle. Otherwise, return the rectangle [0, 0, 0, 0]
+ QPDF_DLL
+ Rectangle getArrayAsRectangle();
// Methods for dictionary objects
QPDF_DLL
@@ -739,6 +777,15 @@ class QPDFObjectHandle
QPDF_DLL
void coalesceContentStreams();
+ // Issue a warning about this object if possible. If the object
+ // has a description, a warning will be issued. Otherwise, if
+ // throw_if_no_description is true, throw an exception. Otherwise
+ // do nothing. Objects read normally from the file have
+ // descriptions. See comments on setObjectDescription for
+ // additional details.
+ void warnIfPossible(std::string const& warning,
+ bool throw_if_no_description = false);
+
// Initializers for objects. This Factory class gives the QPDF
// class specific permission to call factory methods without
// making it a friend of the whole QPDFObjectHandle class.
diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc
index 149668eb..5c111cc8 100644
--- a/libqpdf/QPDFObjectHandle.cc
+++ b/libqpdf/QPDFObjectHandle.cc
@@ -554,6 +554,42 @@ QPDFObjectHandle::getArrayItem(int n)
return result;
}
+bool
+QPDFObjectHandle::isRectangle()
+{
+ if (! isArray())
+ {
+ return false;
+ }
+ if (getArrayNItems() != 4)
+ {
+ return false;
+ }
+ for (size_t i = 0; i < 4; ++i)
+ {
+ if (! getArrayItem(i).isNumber())
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+QPDFObjectHandle::Rectangle
+QPDFObjectHandle::getArrayAsRectangle()
+{
+ Rectangle result;
+ if (isRectangle())
+ {
+ result = Rectangle(getArrayItem(0).getNumericValue(),
+ getArrayItem(1).getNumericValue(),
+ getArrayItem(2).getNumericValue(),
+ getArrayItem(3).getNumericValue());
+ }
+ return result;
+}
+
std::vector<QPDFObjectHandle>
QPDFObjectHandle::getArrayAsVector()
{
@@ -1834,6 +1870,23 @@ QPDFObjectHandle::newArray(std::vector<QPDFObjectHandle> const& items)
}
QPDFObjectHandle
+QPDFObjectHandle::newArray(Rectangle const& rect)
+{
+ std::vector<QPDFObjectHandle> items;
+ items.push_back(newReal(rect.llx));
+ items.push_back(newReal(rect.lly));
+ items.push_back(newReal(rect.urx));
+ items.push_back(newReal(rect.ury));
+ return newArray(items);
+}
+
+QPDFObjectHandle
+QPDFObjectHandle::newFromRectangle(Rectangle const& rect)
+{
+ return newArray(rect);
+}
+
+QPDFObjectHandle
QPDFObjectHandle::newDictionary()
{
return newDictionary(std::map<std::string, QPDFObjectHandle>());
@@ -2103,7 +2156,8 @@ QPDFObjectHandle::typeWarning(char const* expected_type,
}
void
-QPDFObjectHandle::objectWarning(std::string const& warning)
+QPDFObjectHandle::warnIfPossible(std::string const& warning,
+ bool throw_if_no_description)
{
QPDF* context = 0;
std::string description;
@@ -2115,13 +2169,19 @@ QPDFObjectHandle::objectWarning(std::string const& warning)
"", description, 0,
warning));
}
- else
+ else if (throw_if_no_description)
{
throw std::logic_error(warning);
}
}
void
+QPDFObjectHandle::objectWarning(std::string const& warning)
+{
+ warnIfPossible(warning, true);
+}
+
+void
QPDFObjectHandle::assertType(char const* type_name, bool istype)
{
if (! istype)
diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc
index 3ec20dd8..7dd6c595 100644
--- a/qpdf/test_driver.cc
+++ b/qpdf/test_driver.cc
@@ -1449,6 +1449,17 @@ void runtest(int n, char const* filename1, char const* arg2)
QPDFObjectHandle page = pdf.getAllPages()[0];
assert("/QPDFFakeName" ==
page.getKey("/Contents").getDict().getKey("/Potato").getName());
+ // Rectangles
+ QPDFObjectHandle::Rectangle r0 = integer.getArrayAsRectangle();
+ assert((r0.llx == 0) && (r0.lly == 0) &&
+ (r0.urx == 0) && (r0.ury == 0));
+ QPDFObjectHandle rect = QPDFObjectHandle::newFromRectangle(
+ QPDFObjectHandle::Rectangle(1.2, 3.4, 5.6, 7.8));
+ QPDFObjectHandle::Rectangle r1 = rect.getArrayAsRectangle();
+ assert((r1.llx > 1.19) && (r1.llx < 1.21) &&
+ (r1.lly > 3.39) && (r1.lly < 3.41) &&
+ (r1.urx > 5.59) && (r1.urx < 5.61) &&
+ (r1.ury > 7.79) && (r1.ury < 7.81));
}
else
{