diff --git a/include/qpdf/QPDFPageDocumentHelper.hh b/include/qpdf/QPDFPageDocumentHelper.hh index 3714258..2820b93 100644 --- a/include/qpdf/QPDFPageDocumentHelper.hh +++ b/include/qpdf/QPDFPageDocumentHelper.hh @@ -120,13 +120,6 @@ class QPDFPageDocumentHelper: public QPDFDocumentHelper void flattenAnnotations(int required_flags = 0, int forbidden_flags = an_invisible | an_hidden); private: - void flattenAnnotationsForPage( - QPDFPageObjectHelper& page, - QPDFObjectHandle& resources, - QPDFAcroFormDocumentHelper& afdh, - int required_flags, - int forbidden_flags); - class Members; std::shared_ptr m; diff --git a/libqpdf/QPDF_pages.cc b/libqpdf/QPDF_pages.cc index 95cfa95..7b3b9c8 100644 --- a/libqpdf/QPDF_pages.cc +++ b/libqpdf/QPDF_pages.cc @@ -631,6 +631,12 @@ QPDFPageDocumentHelper::removePage(QPDFPageObjectHelper page) void QPDFPageDocumentHelper::flattenAnnotations(int required_flags, int forbidden_flags) { + qpdf.doc().pages().flatten_annotations(required_flags, forbidden_flags); +} + +void +Pages::flatten_annotations(int required_flags, int forbidden_flags) +{ auto& afdh = qpdf.doc().acroform(); if (afdh.getNeedAppearances()) { qpdf.getRoot() @@ -639,14 +645,13 @@ QPDFPageDocumentHelper::flattenAnnotations(int required_flags, int forbidden_fla "document does not have updated appearance streams, so form fields " "will not be flattened"); } - for (auto& ph: getAllPages()) { + for (QPDFPageObjectHelper ph: all()) { QPDFObjectHandle resources = ph.getAttribute("/Resources", true); if (!resources.isDictionary()) { // As of #1521, this should be impossible unless a user inserted an invalid page. - resources = ph.getObjectHandle().replaceKeyAndGetNew( - "/Resources", QPDFObjectHandle::newDictionary()); + resources = ph.getObjectHandle().replaceKeyAndGetNew("/Resources", Dictionary::empty()); } - flattenAnnotationsForPage(ph, resources, afdh, required_flags, forbidden_flags); + flatten_annotations_for_page(ph, resources, afdh, required_flags, forbidden_flags); } if (!afdh.getNeedAppearances()) { qpdf.getRoot().removeKey("/AcroForm"); @@ -654,7 +659,7 @@ QPDFPageDocumentHelper::flattenAnnotations(int required_flags, int forbidden_fla } void -QPDFPageDocumentHelper::flattenAnnotationsForPage( +Pages::flatten_annotations_for_page( QPDFPageObjectHelper& page, QPDFObjectHandle& resources, QPDFAcroFormDocumentHelper& afdh, @@ -676,16 +681,14 @@ QPDFPageDocumentHelper::flattenAnnotationsForPage( bool is_widget = (aoh.getSubtype() == "/Widget"); bool process = true; if (need_appearances && is_widget) { - QTC::TC("qpdf", "QPDFPageDocumentHelper skip widget need appearances"); process = false; } if (process && as.isStream()) { if (is_widget) { - QTC::TC("qpdf", "QPDFPageDocumentHelper merge DR"); QPDFFormFieldObjectHelper ff = afdh.getFieldForAnnotation(aoh); QPDFObjectHandle as_resources = as.getDict().getKey("/Resources"); if (as_resources.isIndirect()) { - QTC::TC("qpdf", "QPDFPageDocumentHelper indirect as resources"); + ; as.getDict().replaceKey("/Resources", as_resources.shallowCopy()); as_resources = as.getDict().getKey("/Resources"); } @@ -708,7 +711,6 @@ QPDFPageDocumentHelper::flattenAnnotationsForPage( // associated with comments that aren't visible, and other types of annotations that // aren't visible. Annotations that have no appearance streams at all, such as Link, // Popup, and Projection, should be preserved. - QTC::TC("qpdf", "QPDFPageDocumentHelper ignore annotation with no appearance"); } else { new_annots.push_back(aoh.getObjectHandle()); } @@ -716,16 +718,13 @@ QPDFPageDocumentHelper::flattenAnnotationsForPage( if (new_annots.size() != annots.size()) { QPDFObjectHandle page_oh = page.getObjectHandle(); if (new_annots.empty()) { - QTC::TC("qpdf", "QPDFPageDocumentHelper remove annots"); page_oh.removeKey("/Annots"); } else { QPDFObjectHandle old_annots = page_oh.getKey("/Annots"); QPDFObjectHandle new_annots_oh = QPDFObjectHandle::newArray(new_annots); if (old_annots.isIndirect()) { - QTC::TC("qpdf", "QPDFPageDocumentHelper replace indirect annots"); qpdf.replaceObject(old_annots.getObjGen(), new_annots_oh); } else { - QTC::TC("qpdf", "QPDFPageDocumentHelper replace direct annots"); page_oh.replaceKey("/Annots", new_annots_oh); } } diff --git a/libqpdf/qpdf/QPDF_private.hh b/libqpdf/qpdf/QPDF_private.hh index c4cf664..9523674 100644 --- a/libqpdf/qpdf/QPDF_private.hh +++ b/libqpdf/qpdf/QPDF_private.hh @@ -900,6 +900,7 @@ class QPDF::Doc::Pages: Common int find(QPDFObjGen og); void erase(QPDFObjectHandle& page); void update_cache(); + void flatten_annotations(int required_flags, int forbidden_flags); bool ever_pushed_inherited_attributes_to_pages() const @@ -931,6 +932,12 @@ class QPDF::Doc::Pages: Common QPDFObjGen::set& seen, bool media_box, bool resources); + void flatten_annotations_for_page( + QPDFPageObjectHelper& page, + QPDFObjectHandle& resources, + QPDFAcroFormDocumentHelper& afdh, + int required_flags, + int forbidden_flags); std::vector all_pages; std::map pageobj_to_pages_pos; diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index d6f5e83..dfbc25c 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -224,14 +224,8 @@ QPDFAnnotationObjectHelper default matrix 0 QPDFAnnotationObjectHelper rotate 90 0 QPDFAnnotationObjectHelper rotate 180 0 QPDFAnnotationObjectHelper rotate 270 0 -QPDFPageDocumentHelper skip widget need appearances 0 -QPDFPageDocumentHelper merge DR 0 QPDFPageDocumentHelper non-widget annotation 0 -QPDFPageDocumentHelper remove annots 0 -QPDFPageDocumentHelper replace indirect annots 0 -QPDFPageDocumentHelper replace direct annots 0 QPDFObjectHandle replace with copy 0 -QPDFPageDocumentHelper indirect as resources 0 QPDFAnnotationObjectHelper forbidden flags 0 QPDFAnnotationObjectHelper missing required flags 0 QPDFFormFieldObjectHelper checkbox kid widget 0 @@ -255,7 +249,6 @@ QPDFJob auto-encode password 0 QPDFJob bytes fallback warning 0 QPDFJob invalid utf-8 in auto 0 QPDFJob input password hex-bytes 0 -QPDFPageDocumentHelper ignore annotation with no appearance 0 QPDFFormFieldObjectHelper replaced BMC at EOF 0 QPDFFormFieldObjectHelper fallback Tf 0 QPDFPageObjectHelper copy shared attribute 1