//======================================================================== // // Page.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== //======================================================================== // // Modified under the Poppler project - http://poppler.freedesktop.org // // All changes made under the Poppler project to this file are licensed // under GPL version 2 or later // // Copyright (C) 2005 Kristian Høgsberg // Copyright (C) 2005 Jeff Muizelaar // Copyright (C) 2006 Pino Toscano // Copyright (C) 2006, 2011 Carlos Garcia Campos // Copyright (C) 2007 Julien Rebetez // Copyright (C) 2008 Iñigo Martínez // Copyright (C) 2012 Fabio D'Urso // Copyright (C) 2012, 2017, 2018, 2020 Albert Astals Cid // Copyright (C) 2013 Thomas Freitag // Copyright (C) 2013, 2017 Adrian Johnson // Copyright (C) 2018 Adam Reichold // Copyright (C) 2020 Oliver Sander // Copyright (C) 2020 Nelson Benítez León // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git // //======================================================================== #ifndef PAGE_H #define PAGE_H #include #include #include "poppler-config.h" #include "Object.h" class Dict; class PDFDoc; class XRef; class OutputDev; class Links; class LinkAction; class Annots; class Annot; class Gfx; class FormPageWidgets; class Form; class FormField; //------------------------------------------------------------------------ class PDFRectangle { public: double x1, y1, x2, y2; PDFRectangle() { x1 = y1 = x2 = y2 = 0; } PDFRectangle(double x1A, double y1A, double x2A, double y2A) { x1 = x1A; y1 = y1A; x2 = x2A; y2 = y2A; } bool isValid() const { return x1 != 0 || y1 != 0 || x2 != 0 || y2 != 0; } bool contains(double x, double y) const { return x1 <= x && x <= x2 && y1 <= y && y <= y2; } void clipTo(PDFRectangle *rect); bool operator==(const PDFRectangle &rect) const { return x1 == rect.x1 && y1 == rect.y1 && x2 == rect.x2 && y2 == rect.y2; } }; //------------------------------------------------------------------------ // PageAttrs //------------------------------------------------------------------------ class PageAttrs { public: // Construct a new PageAttrs object by merging a dictionary // (of type Pages or Page) into another PageAttrs object. If // is nullptr, uses defaults. PageAttrs(PageAttrs *attrs, Dict *dict); // Destructor. ~PageAttrs(); // Accessors. const PDFRectangle *getMediaBox() const { return &mediaBox; } const PDFRectangle *getCropBox() const { return &cropBox; } bool isCropped() const { return haveCropBox; } const PDFRectangle *getBleedBox() const { return &bleedBox; } const PDFRectangle *getTrimBox() const { return &trimBox; } const PDFRectangle *getArtBox() const { return &artBox; } int getRotate() const { return rotate; } const GooString *getLastModified() const { return lastModified.isString() ? lastModified.getString() : nullptr; } Dict *getBoxColorInfo() { return boxColorInfo.isDict() ? boxColorInfo.getDict() : nullptr; } Dict *getGroup() { return group.isDict() ? group.getDict() : nullptr; } Stream *getMetadata() { return metadata.isStream() ? metadata.getStream() : nullptr; } Dict *getPieceInfo() { return pieceInfo.isDict() ? pieceInfo.getDict() : nullptr; } Dict *getSeparationInfo() { return separationInfo.isDict() ? separationInfo.getDict() : nullptr; } Dict *getResourceDict() { return resources.isDict() ? resources.getDict() : nullptr; } Object *getResourceDictObject() { return &resources; } void replaceResource(Object &&obj1) { resources = std::move(obj1); } // Clip all other boxes to the MediaBox. void clipBoxes(); private: bool readBox(Dict *dict, const char *key, PDFRectangle *box); PDFRectangle mediaBox; PDFRectangle cropBox; bool haveCropBox; PDFRectangle bleedBox; PDFRectangle trimBox; PDFRectangle artBox; int rotate; Object lastModified; Object boxColorInfo; Object group; Object metadata; Object pieceInfo; Object separationInfo; Object resources; }; //------------------------------------------------------------------------ // Page //------------------------------------------------------------------------ class Page { public: // Constructor. Page(PDFDoc *docA, int numA, Object &&pageDict, Ref pageRefA, PageAttrs *attrsA, Form *form); // Destructor. ~Page(); Page(const Page &) = delete; Page &operator=(const Page &) = delete; // Is page valid? bool isOk() const { return ok; } // Get page parameters. int getNum() const { return num; } const PDFRectangle *getMediaBox() const { return attrs->getMediaBox(); } const PDFRectangle *getCropBox() const { return attrs->getCropBox(); } bool isCropped() const { return attrs->isCropped(); } double getMediaWidth() const { return attrs->getMediaBox()->x2 - attrs->getMediaBox()->x1; } double getMediaHeight() const { return attrs->getMediaBox()->y2 - attrs->getMediaBox()->y1; } double getCropWidth() const { return attrs->getCropBox()->x2 - attrs->getCropBox()->x1; } double getCropHeight() const { return attrs->getCropBox()->y2 - attrs->getCropBox()->y1; } const PDFRectangle *getBleedBox() const { return attrs->getBleedBox(); } const PDFRectangle *getTrimBox() const { return attrs->getTrimBox(); } const PDFRectangle *getArtBox() const { return attrs->getArtBox(); } int getRotate() const { return attrs->getRotate(); } const GooString *getLastModified() const { return attrs->getLastModified(); } Dict *getBoxColorInfo() { return attrs->getBoxColorInfo(); } Dict *getGroup() { return attrs->getGroup(); } Stream *getMetadata() { return attrs->getMetadata(); } Dict *getPieceInfo() { return attrs->getPieceInfo(); } Dict *getSeparationInfo() { return attrs->getSeparationInfo(); } PDFDoc *getDoc() { return doc; } Ref getRef() { return pageRef; } // Get resource dictionary. Dict *getResourceDict(); Object *getResourceDictObject(); Dict *getResourceDictCopy(XRef *xrefA); // Get annotations array. Object getAnnotsObject(XRef *xrefA = nullptr) { return annotsObj.fetch(xrefA ? xrefA : xref); } // Add a new annotation to the page void addAnnot(Annot *annot); // Remove an existing annotation from the page void removeAnnot(Annot *annot); // Return a list of links. Links *getLinks(); // Return a list of annots. It will be valid until the page is destroyed Annots *getAnnots(XRef *xrefA = nullptr); // Get contents. Object getContents() { return contents.fetch(xref); } // Get thumb. Object getThumb() { return thumb.fetch(xref); } bool loadThumb(unsigned char **data, int *width, int *height, int *rowstride); // Get transition. Object getTrans() { return trans.fetch(xref); } // Get form. FormPageWidgets *getFormWidgets(); // Get duration, the maximum length of time, in seconds, // that the page is displayed before the presentation automatically // advances to the next page double getDuration() { return duration; } // Get actions Object getActions() { return actions.fetch(xref); } enum PageAdditionalActionsType { actionOpenPage, ///< Performed when opening the page actionClosePage, ///< Performed when closing the page }; std::unique_ptr getAdditionalAction(PageAdditionalActionsType type); Gfx *createGfx(OutputDev *out, double hDPI, double vDPI, int rotate, bool useMediaBox, bool crop, int sliceX, int sliceY, int sliceW, int sliceH, bool printing, bool (*abortCheckCbk)(void *data), void *abortCheckCbkData, XRef *xrefA = nullptr); // Display a page. void display(OutputDev *out, double hDPI, double vDPI, int rotate, bool useMediaBox, bool crop, bool printing, bool (*abortCheckCbk)(void *data) = nullptr, void *abortCheckCbkData = nullptr, bool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = nullptr, void *annotDisplayDecideCbkData = nullptr, bool copyXRef = false); // Display part of a page. void displaySlice(OutputDev *out, double hDPI, double vDPI, int rotate, bool useMediaBox, bool crop, int sliceX, int sliceY, int sliceW, int sliceH, bool printing, bool (*abortCheckCbk)(void *data) = nullptr, void *abortCheckCbkData = nullptr, bool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = nullptr, void *annotDisplayDecideCbkData = nullptr, bool copyXRef = false); void display(Gfx *gfx); void makeBox(double hDPI, double vDPI, int rotate, bool useMediaBox, bool upsideDown, double sliceX, double sliceY, double sliceW, double sliceH, PDFRectangle *box, bool *crop); void processLinks(OutputDev *out); // Get the page's default CTM. void getDefaultCTM(double *ctm, double hDPI, double vDPI, int rotate, bool useMediaBox, bool upsideDown); private: // replace xref void replaceXRef(XRef *xrefA); PDFDoc *doc; XRef *xref; // the xref table for this PDF file Object pageObj; // page dictionary Ref pageRef; // page reference int num; // page number PageAttrs *attrs; // page attributes Annots *annots; // annotations Object annotsObj; // annotations array Object contents; // page contents Object thumb; // page thumbnail Object trans; // page transition Object actions; // page additional actions double duration; // page duration bool ok; // true if page is valid mutable std::recursive_mutex mutex; // standalone widgets are special FormWidget's inside a Page that *are not* // referenced from the Catalog's Field array. That means they are standlone, // i.e. the PDF document does not have a FormField associated with them. We // create standalone FormFields to contain those special FormWidgets, as // they are 'de facto' being used to implement tooltips. See #34 std::vector standaloneFields; void loadStandaloneFields(Annots *annotations, Form *form); }; #endif