diff options
Diffstat (limited to 'libqpdf/QPDFPageObjectHelper.cc')
-rw-r--r-- | libqpdf/QPDFPageObjectHelper.cc | 719 |
1 files changed, 275 insertions, 444 deletions
diff --git a/libqpdf/QPDFPageObjectHelper.cc b/libqpdf/QPDFPageObjectHelper.cc index 6d06364a..988068f3 100644 --- a/libqpdf/QPDFPageObjectHelper.cc +++ b/libqpdf/QPDFPageObjectHelper.cc @@ -1,14 +1,14 @@ #include <qpdf/QPDFPageObjectHelper.hh> -#include <qpdf/QTC.hh> -#include <qpdf/QPDF.hh> -#include <qpdf/Pl_Concatenate.hh> #include <qpdf/Pl_Buffer.hh> -#include <qpdf/QUtil.hh> -#include <qpdf/QPDFExc.hh> -#include <qpdf/QPDFMatrix.hh> +#include <qpdf/Pl_Concatenate.hh> #include <qpdf/QIntC.hh> +#include <qpdf/QPDF.hh> #include <qpdf/QPDFAcroFormDocumentHelper.hh> +#include <qpdf/QPDFExc.hh> +#include <qpdf/QPDFMatrix.hh> +#include <qpdf/QTC.hh> +#include <qpdf/QUtil.hh> #include <qpdf/ResourceFinder.hh> class ContentProvider: public QPDFObjectHandle::StreamDataProvider @@ -21,8 +21,8 @@ class ContentProvider: public QPDFObjectHandle::StreamDataProvider virtual ~ContentProvider() { } - virtual void provideStreamData(int objid, int generation, - Pipeline* pipeline); + virtual void + provideStreamData(int objid, int generation, Pipeline* pipeline); private: QPDFObjectHandle from_page; @@ -36,8 +36,8 @@ ContentProvider::provideStreamData(int, int, Pipeline* p) QUtil::int_to_string(from_page.getObjectID()) + " " + QUtil::int_to_string(from_page.getGeneration()); std::string all_description; - from_page.getKey("/Contents").pipeContentStreams( - &concat, description, all_description); + from_page.getKey("/Contents") + .pipeContentStreams(&concat, description, all_description); concat.manualFinish(); } @@ -61,8 +61,8 @@ class InlineImageTracker: public QPDFObjectHandle::TokenFilter enum { st_top, st_bi } state; }; -InlineImageTracker::InlineImageTracker(QPDF* qpdf, size_t min_size, - QPDFObjectHandle resources) : +InlineImageTracker::InlineImageTracker( + QPDF* qpdf, size_t min_size, QPDFObjectHandle resources) : qpdf(qpdf), min_size(min_size), resources(resources), @@ -79,154 +79,96 @@ InlineImageTracker::convertIIDict(QPDFObjectHandle odict) dict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject")); dict.replaceKey("/Subtype", QPDFObjectHandle::newName("/Image")); std::set<std::string> keys = odict.getKeys(); - for (auto key: keys) - { + for (auto key : keys) { QPDFObjectHandle value = odict.getKey(key); - if (key == "/BPC") - { + if (key == "/BPC") { key = "/BitsPerComponent"; - } - else if (key == "/CS") - { + } else if (key == "/CS") { key = "/ColorSpace"; - } - else if (key == "/D") - { + } else if (key == "/D") { key = "/Decode"; - } - else if (key == "/DP") - { + } else if (key == "/DP") { key = "/DecodeParms"; - } - else if (key == "/F") - { + } else if (key == "/F") { key = "/Filter"; - } - else if (key == "/H") - { + } else if (key == "/H") { key = "/Height"; - } - else if (key == "/IM") - { + } else if (key == "/IM") { key = "/ImageMask"; - } - else if (key == "/I") - { + } else if (key == "/I") { key = "/Interpolate"; - } - else if (key == "/W") - { + } else if (key == "/W") { key = "/Width"; } - if (key == "/ColorSpace") - { - if (value.isName()) - { + if (key == "/ColorSpace") { + if (value.isName()) { std::string name = value.getName(); - if (name == "/G") - { + if (name == "/G") { name = "/DeviceGray"; - } - else if (name == "/RGB") - { + } else if (name == "/RGB") { name = "/DeviceRGB"; - } - else if (name == "/CMYK") - { + } else if (name == "/CMYK") { name = "/DeviceCMYK"; - } - else if (name == "/I") - { + } else if (name == "/I") { name = "/Indexed"; - } - else - { + } else { // This is a key in the page's /Resources -> // /ColorSpace dictionary. We need to look it up // and use its value as the color space for the // image. QPDFObjectHandle colorspace = resources.getKey("/ColorSpace"); - if (colorspace.isDictionary() && colorspace.hasKey(name)) - { - QTC::TC("qpdf", "QPDFPageObjectHelper colorspace lookup"); + if (colorspace.isDictionary() && colorspace.hasKey(name)) { + QTC::TC( + "qpdf", "QPDFPageObjectHelper colorspace lookup"); value = colorspace.getKey(name); - } - else - { + } else { resources.warnIfPossible( "unable to resolve colorspace " + name); } name.clear(); } - if (! name.empty()) - { + if (!name.empty()) { value = QPDFObjectHandle::newName(name); } } - } - else if (key == "/Filter") - { + } else if (key == "/Filter") { std::vector<QPDFObjectHandle> filters; - if (value.isName()) - { + if (value.isName()) { filters.push_back(value); - } - else if (value.isArray()) - { + } else if (value.isArray()) { filters = value.getArrayAsVector(); } - for (auto& iter: filters) - { + for (auto& iter : filters) { std::string name; - if (iter.isName()) - { + if (iter.isName()) { name = iter.getName(); } - if (name == "/AHx") - { + if (name == "/AHx") { name = "/ASCIIHexDecode"; - } - else if (name == "/A85") - { + } else if (name == "/A85") { name = "/ASCII85Decode"; - } - else if (name == "/LZW") - { + } else if (name == "/LZW") { name = "/LZWDecode"; - } - else if (name == "/Fl") - { + } else if (name == "/Fl") { name = "/FlateDecode"; - } - else if (name == "/RL") - { + } else if (name == "/RL") { name = "/RunLengthDecode"; - } - else if (name == "/CCF") - { + } else if (name == "/CCF") { name = "/CCITTFaxDecode"; - } - else if (name == "/DCT") - { + } else if (name == "/DCT") { name = "/DCTDecode"; - } - else - { + } else { name.clear(); } - if (! name.empty()) - { + if (!name.empty()) { iter = QPDFObjectHandle::newName(name); } } - if (value.isName() && (filters.size() == 1)) - { + if (value.isName() && (filters.size() == 1)) { value = filters.at(0); - } - else if (value.isArray()) - { + } else if (value.isArray()) { value = QPDFObjectHandle::newArray(filters); } } @@ -238,15 +180,13 @@ InlineImageTracker::convertIIDict(QPDFObjectHandle odict) void InlineImageTracker::handleToken(QPDFTokenizer::Token const& token) { - if (state == st_bi) - { - if (token.getType() == QPDFTokenizer::tt_inline_image) - { + if (state == st_bi) { + if (token.getType() == QPDFTokenizer::tt_inline_image) { std::string image_data(token.getValue()); size_t len = image_data.length(); - if (len >= this->min_size) - { - QTC::TC("qpdf", "QPDFPageObjectHelper externalize inline image"); + if (len >= this->min_size) { + QTC::TC( + "qpdf", "QPDFPageObjectHelper externalize inline image"); Pl_Buffer b("image_data"); b.write(QUtil::unsigned_char_pointer(image_data), len); b.finish(); @@ -255,8 +195,8 @@ InlineImageTracker::handleToken(QPDFTokenizer::Token const& token) dict.replaceKey( "/Length", QPDFObjectHandle::newInteger(QIntC::to_longlong(len))); - std::string name = resources.getUniqueResourceName( - "/IIm", this->min_suffix); + std::string name = + resources.getUniqueResourceName("/IIm", this->min_suffix); QPDFObjectHandle image = QPDFObjectHandle::newStream( this->qpdf, b.getBufferSharedPointer()); image.replaceDict(dict); @@ -264,38 +204,28 @@ InlineImageTracker::handleToken(QPDFTokenizer::Token const& token) write(name); write(" Do\n"); any_images = true; - } - else - { + } else { QTC::TC("qpdf", "QPDFPageObjectHelper keep inline image"); write(bi_str); writeToken(token); state = st_top; } - } - else if (token == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "ID")) - { + } else if ( + token == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "ID")) { bi_str += token.getValue(); dict_str += " >>"; - } - else if (token == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "EI")) - { + } else if ( + token == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "EI")) { state = st_top; - } - else - { + } else { bi_str += token.getRawValue(); dict_str += token.getRawValue(); } - } - else if (token == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "BI")) - { + } else if (token == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "BI")) { bi_str = token.getValue(); dict_str = "<< "; state = st_bi; - } - else - { + } else { writeToken(token); } } @@ -314,47 +244,42 @@ QPDFPageObjectHelper::QPDFPageObjectHelper(QPDFObjectHandle oh) : } QPDFObjectHandle -QPDFPageObjectHelper::getAttribute(std::string const& name, - bool copy_if_shared) +QPDFPageObjectHelper::getAttribute(std::string const& name, bool copy_if_shared) { QPDFObjectHandle result; QPDFObjectHandle dict; bool is_form_xobject = this->oh.isFormXObject(); bool inherited = false; - if (is_form_xobject) - { + if (is_form_xobject) { dict = this->oh.getDict(); result = dict.getKey(name); - } - else - { + } else { dict = this->oh; - bool inheritable = ((name == "/MediaBox") || (name == "/CropBox") || - (name == "/Resources") || (name == "/Rotate")); + bool inheritable = + ((name == "/MediaBox") || (name == "/CropBox") || + (name == "/Resources") || (name == "/Rotate")); QPDFObjectHandle node = dict; result = node.getKey(name); std::set<QPDFObjGen> seen; - while (inheritable && result.isNull() && node.hasKey("/Parent")) - { + while (inheritable && result.isNull() && node.hasKey("/Parent")) { seen.insert(node.getObjGen()); node = node.getKey("/Parent"); - if (seen.count(node.getObjGen())) - { + if (seen.count(node.getObjGen())) { break; } result = node.getKey(name); - if (! result.isNull()) - { + if (!result.isNull()) { QTC::TC("qpdf", "QPDFPageObjectHelper non-trivial inheritance"); inherited = true; } } } - if (copy_if_shared && (inherited || result.isIndirect())) - { - QTC::TC("qpdf", "QPDFPageObjectHelper copy shared attribute", - is_form_xobject ? 0 : 1); + if (copy_if_shared && (inherited || result.isIndirect())) { + QTC::TC( + "qpdf", + "QPDFPageObjectHelper copy shared attribute", + is_form_xobject ? 0 : 1); result = result.shallowCopy(); dict.replaceKey(name, result); } @@ -365,8 +290,7 @@ QPDFObjectHandle QPDFPageObjectHelper::getTrimBox(bool copy_if_shared) { QPDFObjectHandle result = getAttribute("/TrimBox", copy_if_shared); - if (result.isNull()) - { + if (result.isNull()) { result = getCropBox(copy_if_shared); } return result; @@ -376,8 +300,7 @@ QPDFObjectHandle QPDFPageObjectHelper::getCropBox(bool copy_if_shared) { QPDFObjectHandle result = getAttribute("/CropBox", copy_if_shared); - if (result.isNull()) - { + if (result.isNull()) { result = getMediaBox(); } return result; @@ -392,41 +315,37 @@ QPDFPageObjectHelper::getMediaBox(bool copy_if_shared) void QPDFPageObjectHelper::forEachXObject( bool recursive, - std::function<void(QPDFObjectHandle& obj, - QPDFObjectHandle& xobj_dict, - std::string const& key)> action, + std::function<void( + QPDFObjectHandle& obj, + QPDFObjectHandle& xobj_dict, + std::string const& key)> action, std::function<bool(QPDFObjectHandle)> selector) { - QTC::TC("qpdf", "QPDFPageObjectHelper::forEachXObject", - recursive - ? (this->oh.isFormXObject() ? 0 : 1) - : (this->oh.isFormXObject() ? 2 : 3)); + QTC::TC( + "qpdf", + "QPDFPageObjectHelper::forEachXObject", + recursive ? (this->oh.isFormXObject() ? 0 : 1) + : (this->oh.isFormXObject() ? 2 : 3)); std::set<QPDFObjGen> seen; std::list<QPDFPageObjectHelper> queue; queue.push_back(*this); - while (! queue.empty()) - { + while (!queue.empty()) { QPDFPageObjectHelper ph = queue.front(); queue.pop_front(); QPDFObjGen og = ph.oh.getObjGen(); - if (seen.count(og)) - { + if (seen.count(og)) { continue; } seen.insert(og); QPDFObjectHandle resources = ph.getAttribute("/Resources", false); - if (resources.isDictionary() && resources.hasKey("/XObject")) - { + if (resources.isDictionary() && resources.hasKey("/XObject")) { QPDFObjectHandle xobj_dict = resources.getKey("/XObject"); - for (auto const& key: xobj_dict.getKeys()) - { + for (auto const& key : xobj_dict.getKeys()) { QPDFObjectHandle obj = xobj_dict.getKey(key); - if ((! selector) || selector(obj)) - { + if ((!selector) || selector(obj)) { action(obj, xobj_dict, key); } - if (recursive && obj.isFormXObject()) - { + if (recursive && obj.isFormXObject()) { queue.push_back(QPDFPageObjectHelper(obj)); } } @@ -437,23 +356,26 @@ QPDFPageObjectHelper::forEachXObject( void QPDFPageObjectHelper::forEachImage( bool recursive, - std::function<void(QPDFObjectHandle& obj, - QPDFObjectHandle& xobj_dict, - std::string const& key)> action) + std::function<void( + QPDFObjectHandle& obj, + QPDFObjectHandle& xobj_dict, + std::string const& key)> action) { - forEachXObject(recursive, action, - [](QPDFObjectHandle obj) { return obj.isImage(); }); + forEachXObject( + recursive, action, [](QPDFObjectHandle obj) { return obj.isImage(); }); } void QPDFPageObjectHelper::forEachFormXObject( bool recursive, - std::function<void(QPDFObjectHandle& obj, - QPDFObjectHandle& xobj_dict, - std::string const& key)> action) + std::function<void( + QPDFObjectHandle& obj, + QPDFObjectHandle& xobj_dict, + std::string const& key)> action) { - forEachXObject(recursive, action, - [](QPDFObjectHandle obj) { return obj.isFormXObject(); }); + forEachXObject(recursive, action, [](QPDFObjectHandle obj) { + return obj.isFormXObject(); + }); } std::map<std::string, QPDFObjectHandle> @@ -466,11 +388,12 @@ std::map<std::string, QPDFObjectHandle> QPDFPageObjectHelper::getImages() { std::map<std::string, QPDFObjectHandle> result; - forEachImage(false, [&result](QPDFObjectHandle& obj, - QPDFObjectHandle&, - std::string const& key) { - result[key] = obj; - }); + forEachImage( + false, + [&result]( + QPDFObjectHandle& obj, QPDFObjectHandle&, std::string const& key) { + result[key] = obj; + }); return result; } @@ -478,11 +401,12 @@ std::map<std::string, QPDFObjectHandle> QPDFPageObjectHelper::getFormXObjects() { std::map<std::string, QPDFObjectHandle> result; - forEachFormXObject(false, [&result](QPDFObjectHandle& obj, - QPDFObjectHandle&, - std::string const& key) { - result[key] = obj; - }); + forEachFormXObject( + false, + [&result]( + QPDFObjectHandle& obj, QPDFObjectHandle&, std::string const& key) { + result[key] = obj; + }); return result; } @@ -495,8 +419,7 @@ QPDFPageObjectHelper::externalizeInlineImages(size_t min_size) void QPDFPageObjectHelper::externalizeInlineImages(size_t min_size, bool shallow) { - if (shallow) - { + if (shallow) { QPDFObjectHandle resources = getAttribute("/Resources", true); // Calling mergeResources also ensures that /XObject becomes // direct and is not shared with other pages. @@ -504,44 +427,34 @@ QPDFPageObjectHelper::externalizeInlineImages(size_t min_size, bool shallow) InlineImageTracker iit(this->oh.getOwningQPDF(), min_size, resources); Pl_Buffer b("new page content"); bool filtered = false; - try - { + try { filterContents(&iit, &b); filtered = true; - } - catch (std::exception& e) - { + } catch (std::exception& e) { this->oh.warnIfPossible( std::string("Unable to filter content stream: ") + e.what() + "; not attempting to externalize inline images" " from this stream"); } - if (filtered && iit.any_images) - { - if (this->oh.isFormXObject()) - { + if (filtered && iit.any_images) { + if (this->oh.isFormXObject()) { this->oh.replaceStreamData( b.getBufferSharedPointer(), QPDFObjectHandle::newNull(), QPDFObjectHandle::newNull()); - } - else - { + } else { this->oh.replaceKey( "/Contents", QPDFObjectHandle::newStream( - this->oh.getOwningQPDF(), - b.getBufferSharedPointer())); + this->oh.getOwningQPDF(), b.getBufferSharedPointer())); } } - } - else - { + } else { externalizeInlineImages(min_size, true); forEachFormXObject( true, - [min_size](QPDFObjectHandle& obj, - QPDFObjectHandle&, std::string const&) { + [min_size]( + QPDFObjectHandle& obj, QPDFObjectHandle&, std::string const&) { QPDFPageObjectHelper(obj).externalizeInlineImages( min_size, true); }); @@ -553,14 +466,11 @@ QPDFPageObjectHelper::getAnnotations(std::string const& only_subtype) { std::vector<QPDFAnnotationObjectHelper> result; QPDFObjectHandle annots = this->oh.getKey("/Annots"); - if (annots.isArray()) - { + if (annots.isArray()) { int nannots = annots.getArrayNItems(); - for (int i = 0; i < nannots; ++i) - { + for (int i = 0; i < nannots; ++i) { QPDFObjectHandle annot = annots.getArrayItem(i); - if (annot.isDictionaryOfType("", only_subtype)) - { + if (annot.isDictionaryOfType("", only_subtype)) { result.push_back(QPDFAnnotationObjectHelper(annot)); } } @@ -603,35 +513,27 @@ void QPDFPageObjectHelper::parseContents( QPDFObjectHandle::ParserCallbacks* callbacks) { - if (this->oh.isFormXObject()) - { + if (this->oh.isFormXObject()) { this->oh.parseAsContents(callbacks); - } - else - { + } else { this->oh.parsePageContents(callbacks); } } void QPDFPageObjectHelper::filterPageContents( - QPDFObjectHandle::TokenFilter* filter, - Pipeline* next) + QPDFObjectHandle::TokenFilter* filter, Pipeline* next) { return filterContents(filter, next); } void QPDFPageObjectHelper::filterContents( - QPDFObjectHandle::TokenFilter* filter, - Pipeline* next) + QPDFObjectHandle::TokenFilter* filter, Pipeline* next) { - if (this->oh.isFormXObject()) - { + if (this->oh.isFormXObject()) { this->oh.filterAsContents(filter, next); - } - else - { + } else { this->oh.filterPageContents(filter, next); } } @@ -645,12 +547,9 @@ QPDFPageObjectHelper::pipePageContents(Pipeline* p) void QPDFPageObjectHelper::pipeContents(Pipeline* p) { - if (this->oh.isFormXObject()) - { + if (this->oh.isFormXObject()) { this->oh.pipeStreamData(p, 0, qpdf_dl_specialized); - } - else - { + } else { this->oh.pipePageContents(p); } } @@ -659,12 +558,9 @@ void QPDFPageObjectHelper::addContentTokenFilter( PointerHolder<QPDFObjectHandle::TokenFilter> token_filter) { - if (this->oh.isFormXObject()) - { + if (this->oh.isFormXObject()) { this->oh.addTokenFilter(token_filter); - } - else - { + } else { this->oh.addContentTokenFilter(token_filter); } } @@ -673,30 +569,25 @@ bool QPDFPageObjectHelper::removeUnreferencedResourcesHelper( QPDFPageObjectHelper ph, std::set<std::string>& unresolved) { - bool is_page = (! ph.oh.isFormXObject()); - if (! is_page) - { + bool is_page = (!ph.oh.isFormXObject()); + if (!is_page) { QTC::TC("qpdf", "QPDFPageObjectHelper filter form xobject"); } ResourceFinder rf; - try - { + try { auto q = ph.oh.getOwningQPDF(); size_t before_nw = (q ? q->numWarnings() : 0); ph.parseContents(&rf); size_t after_nw = (q ? q->numWarnings() : 0); - if (after_nw > before_nw) - { + if (after_nw > before_nw) { ph.oh.warnIfPossible( "Bad token found while scanning content stream; " "not attempting to remove unreferenced objects from" " this object"); return false; } - } - catch (std::exception& e) - { + } catch (std::exception& e) { QTC::TC("qpdf", "QPDFPageObjectHelper bad token finding names"); ph.oh.warnIfPossible( std::string("Unable to parse content stream: ") + e.what() + @@ -714,13 +605,10 @@ QPDFPageObjectHelper::removeUnreferencedResourcesHelper( std::vector<QPDFObjectHandle> rdicts; std::set<std::string> known_names; std::vector<std::string> to_filter = {"/Font", "/XObject"}; - if (resources.isDictionary()) - { - for (auto const& iter: to_filter) - { + if (resources.isDictionary()) { + for (auto const& iter : to_filter) { QPDFObjectHandle dict = resources.getKey(iter); - if (dict.isDictionary()) - { + if (dict.isDictionary()) { dict = dict.shallowCopy(); resources.replaceKey(iter, dict); rdicts.push_back(dict); @@ -732,13 +620,10 @@ QPDFPageObjectHelper::removeUnreferencedResourcesHelper( std::set<std::string> local_unresolved; auto names_by_rtype = rf.getNamesByResourceType(); - for (auto const& i1: to_filter) - { - for (auto const& n_iter: names_by_rtype[i1]) - { + for (auto const& i1 : to_filter) { + for (auto const& n_iter : names_by_rtype[i1]) { std::string const& name = n_iter.first; - if (! known_names.count(name)) - { + if (!known_names.count(name)) { unresolved.insert(name); local_unresolved.insert(name); } @@ -759,8 +644,7 @@ QPDFPageObjectHelper::removeUnreferencedResourcesHelper( // unresolved names, and for page objects, we avoid removing any // such names found in nested form XObjects. - if ((! local_unresolved.empty()) && resources.isDictionary()) - { + if ((!local_unresolved.empty()) && resources.isDictionary()) { // It's not worth issuing a warning for this case. From qpdf // 10.3, we are hopefully only looking at names that are // referencing fonts and XObjects, but until we're certain @@ -776,18 +660,13 @@ QPDFPageObjectHelper::removeUnreferencedResourcesHelper( return false; } - for (auto& dict: rdicts) - { - for (auto const& key: dict.getKeys()) - { - if (is_page && unresolved.count(key)) - { + for (auto& dict : rdicts) { + for (auto const& key : dict.getKeys()) { + if (is_page && unresolved.count(key)) { // This name is referenced by some nested form // xobject, so don't remove it. QTC::TC("qpdf", "QPDFPageObjectHelper resolving unresolved"); - } - else if (! rf.getNames().count(key)) - { + } else if (!rf.getNames().count(key)) { dict.removeKey(key); } } @@ -805,16 +684,13 @@ QPDFPageObjectHelper::removeUnreferencedResources() forEachFormXObject( true, [&any_failures, &unresolved]( - QPDFObjectHandle& obj, QPDFObjectHandle&, std::string const&) - { - if (! removeUnreferencedResourcesHelper( - QPDFPageObjectHelper(obj), unresolved)) - { + QPDFObjectHandle& obj, QPDFObjectHandle&, std::string const&) { + if (!removeUnreferencedResourcesHelper( + QPDFPageObjectHelper(obj), unresolved)) { any_failures = true; } }); - if (this->oh.isFormXObject() || (! any_failures)) - { + if (this->oh.isFormXObject() || (!any_failures)) { removeUnreferencedResourcesHelper(*this, unresolved); } } @@ -823,11 +699,9 @@ QPDFPageObjectHelper QPDFPageObjectHelper::shallowCopyPage() { QPDF* qpdf = this->oh.getOwningQPDF(); - if (! qpdf) - { - throw std::runtime_error( - "QPDFPageObjectHelper::shallowCopyPage" - " called with a direct object"); + if (!qpdf) { + throw std::runtime_error("QPDFPageObjectHelper::shallowCopyPage" + " called with a direct object"); } QPDFObjectHandle new_page = this->oh.shallowCopy(); return QPDFPageObjectHelper(qpdf->makeIndirectObject(new_page)); @@ -838,27 +712,21 @@ QPDFPageObjectHelper::getMatrixForTransformations(bool invert) { QPDFObjectHandle::Matrix matrix(1, 0, 0, 1, 0, 0); QPDFObjectHandle bbox = getTrimBox(false); - if (! bbox.isRectangle()) - { + if (!bbox.isRectangle()) { return matrix; } QPDFObjectHandle rotate_obj = getAttribute("/Rotate", false); QPDFObjectHandle scale_obj = getAttribute("/UserUnit", false); - if (! (rotate_obj.isNull() && scale_obj.isNull())) - { + if (!(rotate_obj.isNull() && scale_obj.isNull())) { QPDFObjectHandle::Rectangle rect = bbox.getArrayAsRectangle(); double width = rect.urx - rect.llx; double height = rect.ury - rect.lly; - double scale = (scale_obj.isNumber() - ? scale_obj.getNumericValue() - : 1.0); - int rotate = (rotate_obj.isInteger() - ? rotate_obj.getIntValueAsInt() - : 0); - if (invert) - { - if (scale == 0.0) - { + double scale = + (scale_obj.isNumber() ? scale_obj.getNumericValue() : 1.0); + int rotate = + (rotate_obj.isInteger() ? rotate_obj.getIntValueAsInt() : 0); + if (invert) { + if (scale == 0.0) { return matrix; } scale = 1.0 / scale; @@ -866,23 +734,21 @@ QPDFPageObjectHelper::getMatrixForTransformations(bool invert) } // Ignore invalid rotation angle - switch (rotate) - { - case 90: - matrix = QPDFObjectHandle::Matrix( - 0, -scale, scale, 0, 0, width * scale); + switch (rotate) { + case 90: + matrix = + QPDFObjectHandle::Matrix(0, -scale, scale, 0, 0, width * scale); break; - case 180: + case 180: matrix = QPDFObjectHandle::Matrix( -scale, 0, 0, -scale, width * scale, height * scale); break; - case 270: + case 270: matrix = QPDFObjectHandle::Matrix( 0, scale, -scale, 0, height * scale, 0); break; - default: - matrix = QPDFObjectHandle::Matrix( - scale, 0, 0, scale, 0, 0); + default: + matrix = QPDFObjectHandle::Matrix(scale, 0, 0, scale, 0, 0); break; } } @@ -893,26 +759,21 @@ QPDFObjectHandle QPDFPageObjectHelper::getFormXObjectForPage(bool handle_transformations) { QPDF* qpdf = this->oh.getOwningQPDF(); - if (! qpdf) - { - throw std::runtime_error( - "QPDFPageObjectHelper::getFormXObjectForPage" - " called with a direct object"); + if (!qpdf) { + throw std::runtime_error("QPDFPageObjectHelper::getFormXObjectForPage" + " called with a direct object"); } QPDFObjectHandle result = QPDFObjectHandle::newStream(qpdf); QPDFObjectHandle newdict = result.getDict(); newdict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject")); newdict.replaceKey("/Subtype", QPDFObjectHandle::newName("/Form")); - newdict.replaceKey("/Resources", - getAttribute("/Resources", false).shallowCopy()); - newdict.replaceKey("/Group", - getAttribute("/Group", false).shallowCopy()); + newdict.replaceKey( + "/Resources", getAttribute("/Resources", false).shallowCopy()); + newdict.replaceKey("/Group", getAttribute("/Group", false).shallowCopy()); QPDFObjectHandle bbox = getTrimBox(false).shallowCopy(); - if (! bbox.isRectangle()) - { - this->oh.warnIfPossible( - "bounding box is invalid; form" - " XObject created from page will not work"); + if (!bbox.isRectangle()) { + this->oh.warnIfPossible("bounding box is invalid; form" + " XObject created from page will not work"); } newdict.replaceKey("/BBox", bbox); auto provider = PointerHolder<QPDFObjectHandle::StreamDataProvider>( @@ -922,11 +783,10 @@ QPDFPageObjectHelper::getFormXObjectForPage(bool handle_transformations) QPDFObjectHandle rotate_obj = getAttribute("/Rotate", false); QPDFObjectHandle scale_obj = getAttribute("/UserUnit", false); if (handle_transformations && - (! (rotate_obj.isNull() && scale_obj.isNull()))) - { - newdict.replaceKey("/Matrix", - QPDFObjectHandle::newArray( - getMatrixForTransformations())); + (!(rotate_obj.isNull() && scale_obj.isNull()))) { + newdict.replaceKey( + "/Matrix", + QPDFObjectHandle::newArray(getMatrixForTransformations())); } return result; @@ -934,9 +794,11 @@ QPDFPageObjectHelper::getFormXObjectForPage(bool handle_transformations) QPDFMatrix QPDFPageObjectHelper::getMatrixForFormXObjectPlacement( - QPDFObjectHandle fo, QPDFObjectHandle::Rectangle rect, + QPDFObjectHandle fo, + QPDFObjectHandle::Rectangle rect, bool invert_transformations, - bool allow_shrink, bool allow_expand) + bool allow_shrink, + bool allow_expand) { // Calculate the transformation matrix that will place the given // form XObject fully inside the given rectangle, center and @@ -953,16 +815,14 @@ QPDFPageObjectHelper::getMatrixForFormXObjectPlacement( QPDFObjectHandle fdict = fo.getDict(); QPDFObjectHandle bbox_obj = fdict.getKey("/BBox"); - if (! bbox_obj.isRectangle()) - { + if (!bbox_obj.isRectangle()) { return QPDFMatrix(); } - QPDFMatrix wmatrix; // work matrix - QPDFMatrix tmatrix; // "to" matrix - QPDFMatrix fmatrix; // "from" matrix - if (invert_transformations) - { + QPDFMatrix wmatrix; // work matrix + QPDFMatrix tmatrix; // "to" matrix + QPDFMatrix fmatrix; // "from" matrix + if (invert_transformations) { // tmatrix inverts scaling and rotation of the destination // page. Applying this matrix allows the overlaid form // XObject's to be absolute rather than relative to properties @@ -971,8 +831,7 @@ QPDFPageObjectHelper::getMatrixForFormXObjectPlacement( tmatrix = QPDFMatrix(getMatrixForTransformations(true)); wmatrix.concat(tmatrix); } - if (fdict.getKey("/Matrix").isMatrix()) - { + if (fdict.getKey("/Matrix").isMatrix()) { // fmatrix is the transformation matrix that is applied to the // form XObject itself. We need this for calculations, but we // don't explicitly use it in the final result because the PDF @@ -995,8 +854,7 @@ QPDFPageObjectHelper::getMatrixForFormXObjectPlacement( // Calculate a scale factor, if needed. Shrink or expand if needed // and allowed. - if ((T.urx == T.llx) || (T.ury == T.lly)) - { + if ((T.urx == T.llx) || (T.ury == T.lly)) { // avoid division by zero return QPDFMatrix(); } @@ -1007,17 +865,12 @@ QPDFPageObjectHelper::getMatrixForFormXObjectPlacement( double xscale = rect_w / t_w; double yscale = rect_h / t_h; double scale = (xscale < yscale ? xscale : yscale); - if (scale > 1.0) - { - if (! allow_expand) - { + if (scale > 1.0) { + if (!allow_expand) { scale = 1.0; } - } - else if (scale < 1.0) - { - if (! allow_shrink) - { + } else if (scale < 1.0) { + if (!allow_shrink) { scale = 1.0; } } @@ -1049,20 +902,22 @@ QPDFPageObjectHelper::getMatrixForFormXObjectPlacement( std::string QPDFPageObjectHelper::placeFormXObject( - QPDFObjectHandle fo, std::string const& name, + QPDFObjectHandle fo, + std::string const& name, QPDFObjectHandle::Rectangle rect, bool invert_transformations, - bool allow_shrink, bool allow_expand) + bool allow_shrink, + bool allow_expand) { QPDFMatrix cm; return placeFormXObject( - fo, name, rect, cm, invert_transformations, - allow_shrink, allow_expand); + fo, name, rect, cm, invert_transformations, allow_shrink, allow_expand); } std::string QPDFPageObjectHelper::placeFormXObject( - QPDFObjectHandle fo, std::string const& name, + QPDFObjectHandle fo, + std::string const& name, QPDFObjectHandle::Rectangle rect, QPDFMatrix& cm, bool invert_transformations, @@ -1071,11 +926,7 @@ QPDFPageObjectHelper::placeFormXObject( { cm = getMatrixForFormXObjectPlacement( fo, rect, invert_transformations, allow_shrink, allow_expand); - return ( - "q\n" + - cm.unparse() + " cm\n" + - name + " Do\n" + - "Q\n"); + return ("q\n" + cm.unparse() + " cm\n" + name + " Do\n" + "Q\n"); } void @@ -1088,38 +939,35 @@ void QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) { QPDF* qpdf = this->oh.getOwningQPDF(); - if (! qpdf) - { - throw std::runtime_error( - "QPDFPageObjectHelper::flattenRotation" - " called with a direct object"); + if (!qpdf) { + throw std::runtime_error("QPDFPageObjectHelper::flattenRotation" + " called with a direct object"); } auto rotate_oh = this->oh.getKey("/Rotate"); int rotate = 0; - if (rotate_oh.isInteger()) - { + if (rotate_oh.isInteger()) { rotate = rotate_oh.getIntValueAsInt(); } - if (! ((rotate == 90) || (rotate == 180) || (rotate == 270))) - { + if (!((rotate == 90) || (rotate == 180) || (rotate == 270))) { return; } auto mediabox = this->oh.getKey("/MediaBox"); - if (! mediabox.isRectangle()) - { + if (!mediabox.isRectangle()) { return; } auto media_rect = mediabox.getArrayAsRectangle(); std::vector<std::string> boxes = { - "/MediaBox", "/CropBox", "/BleedBox", "/TrimBox", "/ArtBox", + "/MediaBox", + "/CropBox", + "/BleedBox", + "/TrimBox", + "/ArtBox", }; - for (auto const& boxkey: boxes) - { + for (auto const& boxkey : boxes) { auto box = this->oh.getKey(boxkey); - if (! box.isRectangle()) - { + if (!box.isRectangle()) { continue; } auto rect = box.getArrayAsRectangle(); @@ -1127,40 +975,39 @@ QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) // How far are the edges of our rectangle from the edges // of the media box? - auto left_x = rect.llx - media_rect.llx; - auto right_x = media_rect.urx - rect.urx; + auto left_x = rect.llx - media_rect.llx; + auto right_x = media_rect.urx - rect.urx; auto bottom_y = rect.lly - media_rect.lly; - auto top_y = media_rect.ury - rect.ury; + auto top_y = media_rect.ury - rect.ury; // Rotating the page 180 degrees does not change // /MediaBox. Rotating 90 or 270 degrees reverses llx and // lly and also reverse urx and ury. For all the other // boxes, we want the corners to be the correct distance // away from the corners of the mediabox. - switch (rotate) - { - case 90: + switch (rotate) { + case 90: new_rect.llx = media_rect.lly + bottom_y; new_rect.urx = media_rect.ury - top_y; new_rect.lly = media_rect.llx + right_x; new_rect.ury = media_rect.urx - left_x; break; - case 180: + case 180: new_rect.llx = media_rect.llx + right_x; new_rect.urx = media_rect.urx - left_x; new_rect.lly = media_rect.lly + top_y; new_rect.ury = media_rect.ury - bottom_y; break; - case 270: + case 270: new_rect.llx = media_rect.lly + top_y; new_rect.urx = media_rect.ury - bottom_y; new_rect.lly = media_rect.llx + left_x; new_rect.ury = media_rect.urx - right_x; break; - default: + default: // ignore break; } @@ -1175,61 +1022,53 @@ QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) // These calculations have been verified empirically with various // PDF readers. QPDFMatrix cm(0, 0, 0, 0, 0, 0); - switch (rotate) - { - case 90: + switch (rotate) { + case 90: cm.b = -1; cm.c = 1; cm.f = media_rect.urx + media_rect.llx; break; - case 180: + case 180: cm.a = -1; cm.d = -1; cm.e = media_rect.urx + media_rect.llx; cm.f = media_rect.ury + media_rect.lly; break; - case 270: + case 270: cm.b = 1; cm.c = -1; cm.e = media_rect.ury + media_rect.lly; break; - default: + default: break; } - std::string cm_str = - std::string("q\n") + cm.unparse() + " cm\n"; - this->oh.addPageContents( - QPDFObjectHandle::newStream(qpdf, cm_str), true); - this->oh.addPageContents( - QPDFObjectHandle::newStream(qpdf, "\nQ\n"), false); + std::string cm_str = std::string("q\n") + cm.unparse() + " cm\n"; + this->oh.addPageContents(QPDFObjectHandle::newStream(qpdf, cm_str), true); + this->oh.addPageContents(QPDFObjectHandle::newStream(qpdf, "\nQ\n"), false); this->oh.removeKey("/Rotate"); QPDFObjectHandle rotate_obj = getAttribute("/Rotate", false); - if (! rotate_obj.isNull()) - { + if (!rotate_obj.isNull()) { QTC::TC("qpdf", "QPDFPageObjectHelper flatten inherit rotate"); this->oh.replaceKey("/Rotate", QPDFObjectHandle::newInteger(0)); } QPDFObjectHandle annots = this->oh.getKey("/Annots"); - if (annots.isArray()) - { + if (annots.isArray()) { std::vector<QPDFObjectHandle> new_annots; std::vector<QPDFObjectHandle> new_fields; std::set<QPDFObjGen> old_fields; PointerHolder<QPDFAcroFormDocumentHelper> afdhph; - if (! afdh) - { + if (!afdh) { afdhph = make_pointer_holder<QPDFAcroFormDocumentHelper>(*qpdf); afdh = afdhph.get(); } afdh->transformAnnotations( annots, new_annots, new_fields, old_fields, cm); afdh->removeFormFields(old_fields); - for (auto const& f: new_fields) - { + for (auto const& f : new_fields) { afdh->addFormField(QPDFFormFieldObjectHelper(f)); } this->oh.replaceKey("/Annots", QPDFObjectHandle::newArray(new_annots)); @@ -1238,29 +1077,25 @@ QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) void QPDFPageObjectHelper::copyAnnotations( - QPDFPageObjectHelper from_page, QPDFMatrix const& cm, + QPDFPageObjectHelper from_page, + QPDFMatrix const& cm, QPDFAcroFormDocumentHelper* afdh, QPDFAcroFormDocumentHelper* from_afdh) { auto old_annots = from_page.getObjectHandle().getKey("/Annots"); - if (! old_annots.isArray()) - { + if (!old_annots.isArray()) { return; } QPDF* from_qpdf = from_page.getObjectHandle().getOwningQPDF(); - if (! from_qpdf) - { - throw std::runtime_error( - "QPDFPageObjectHelper::copyAnnotations:" - " from page is a direct object"); + if (!from_qpdf) { + throw std::runtime_error("QPDFPageObjectHelper::copyAnnotations:" + " from page is a direct object"); } QPDF* this_qpdf = this->oh.getOwningQPDF(); - if (! this_qpdf) - { - throw std::runtime_error( - "QPDFPageObjectHelper::copyAnnotations:" - " this page is a direct object"); + if (!this_qpdf) { + throw std::runtime_error("QPDFPageObjectHelper::copyAnnotations:" + " this page is a direct object"); } std::vector<QPDFObjectHandle> new_annots; @@ -1268,43 +1103,39 @@ QPDFPageObjectHelper::copyAnnotations( std::set<QPDFObjGen> old_fields; PointerHolder<QPDFAcroFormDocumentHelper> afdhph; PointerHolder<QPDFAcroFormDocumentHelper> from_afdhph; - if (! afdh) - { + if (!afdh) { afdhph = make_pointer_holder<QPDFAcroFormDocumentHelper>(*this_qpdf); afdh = afdhph.get(); } - if (this_qpdf == from_qpdf) - { + if (this_qpdf == from_qpdf) { from_afdh = afdh; - } - else if (from_afdh) - { - if (from_afdh->getQPDF().getUniqueId() != from_qpdf->getUniqueId()) - { + } else if (from_afdh) { + if (from_afdh->getQPDF().getUniqueId() != from_qpdf->getUniqueId()) { throw std::logic_error( "QPDFAcroFormDocumentHelper::copyAnnotations: from_afdh" " is not from the same QPDF as from_page"); } - } - else - { + } else { from_afdhph = make_pointer_holder<QPDFAcroFormDocumentHelper>(*from_qpdf); from_afdh = from_afdhph.get(); } afdh->transformAnnotations( - old_annots, new_annots, new_fields, old_fields, cm, - from_qpdf, from_afdh); + old_annots, + new_annots, + new_fields, + old_fields, + cm, + from_qpdf, + from_afdh); afdh->addAndRenameFormFields(new_fields); auto annots = this->oh.getKey("/Annots"); - if (! annots.isArray()) - { + if (!annots.isArray()) { annots = QPDFObjectHandle::newArray(); this->oh.replaceKey("/Annots", annots); } - for (auto const& annot: new_annots) - { + for (auto const& annot : new_annots) { annots.appendItem(annot); } } |