Add QPDFObjectHandle::Rectangle type

Provide a convenient way of accessing rectangles.
This commit is contained in:
Jay Berkenbilt 2018-06-19 11:00:15 -04:00
parent 078cf9bf90
commit 4cded10821
4 changed files with 127 additions and 2 deletions

View File

@ -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

View File

@ -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.

View File

@ -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()
{
@ -1833,6 +1869,23 @@ QPDFObjectHandle::newArray(std::vector<QPDFObjectHandle> const& items)
return QPDFObjectHandle(new QPDF_Array(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()
{
@ -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,12 +2169,18 @@ 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)
{

View File

@ -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
{