自学内容网 自学内容网

如何在C++中使用Poppler库读取PDF文件(二)

PDF目录

书籍一般都有目录,电子书也不例外。使用Poppler::Document加载PDF文件以后,就可以通过outline()方法,取得PDF文件的目录。

outline()方法的定义如下:

QVector<OutlineItem> outline() const;

我们看到,Poppler的目录是一个目录项(Poppler::OutlineItem)的列表(QVector)。

Popper::OutlineItem的默认构造函数会初始化一个空的目录项,其中不含任何跟PDF文件相关的信息。

Poppler::OutlineItem支持如下方法:

判断是否为空。上文提到,默认构造以后就是空的。

bool isNull() const;

目录项名称,即显示出来的目录项名字。

QString name() const;

目录项是否是展开状态。

bool isOpen() const;

目录项指向的页数等信息,是一个智能指针,根据这个指针,就可以取得目录具体指向什么位置。

QSharedPointer destination() const;

目录项指向的外部文件。

QString externalFileName() const;

目录项指向的URI。

QString uri() const;

目录项是否含有子项。

bool hasChildren() const;

目录项的子项列表。

QVector children() const;

所以综上,根据Poppler::Document的outline()方法,可以取得目录项的列表,再根据列表中每个目录项是否有子项,就可以完成一个目录项的遍历。

PDF链接目标

PDF文件中,除了目录以外,在正文中也会有超链接。无论是链接的视频、音频还是其它外部网址,这些都是通过LinkDestination表示的。

LinkDestination的定义为:

class POPPLER_QT6_EXPORT LinkDestination
{
public:
    /**
     * The possible kind of "viewport destination".
     */
    enum Kind
    {
        /**
         * The new viewport is specified in terms of:
         * - possible new left coordinate (see isChangeLeft() )
         * - possible new top coordinate (see isChangeTop() )
         * - possible new zoom level (see isChangeZoom() )
         */
        destXYZ = 1,
        destFit = 2,
        destFitH = 3,
        destFitV = 4,
        destFitR = 5,
        destFitB = 6,
        destFitBH = 7,
        destFitBV = 8
    };

    /// \cond PRIVATE
    explicit LinkDestination(const LinkDestinationData &data);
    explicit LinkDestination(const QString &description);
    /// \endcond
    /**
     * Copy constructor.
     */
    LinkDestination(const LinkDestination &other);
    /**
     * Destructor.
     */
    ~LinkDestination();

    // Accessors.
    /**
     * The kind of destination.
     */
    Kind kind() const;
    /**
     * Which page is the target of this destination.
     *
     * \note this number is 1-based, so for a 5 pages document the
     *       valid page numbers go from 1 to 5 (both included).
     */
    int pageNumber() const;
    /**
     * The new left for the viewport of the target page, in case
     * it is specified to be changed (see isChangeLeft() )
     */
    double left() const;
    double bottom() const;
    double right() const;
    /**
     * The new top for the viewport of the target page, in case
     * it is specified to be changed (see isChangeTop() )
     */
    double top() const;
    double zoom() const;
    /**
     * Whether the left of the viewport on the target page should
     * be changed.
     *
     * \see left()
     */
    bool isChangeLeft() const;
    /**
     * Whether the top of the viewport on the target page should
     * be changed.
     *
     * \see top()
     */
    bool isChangeTop() const;
    /**
     * Whether the zoom level should be changed.
     *
     * \see zoom()
     */
    bool isChangeZoom() const;

    /**
     * Return a string repesentation of this destination.
     */
    QString toString() const;

    /**
     * Return the name of this destination.
     */
    QString destinationName() const;

    /**
     * Assignment operator.
     */
    LinkDestination &operator=(const LinkDestination &other);

private:
    QSharedDataPointer<LinkDestinationPrivate> d;
};

其中,pageNumber()方法,返回的是目标所在的页码数。

既然有链接目标,当然就会有链接。在Poppler里面,链接的类是Poppler::Link,是一个基类,它派生了LinkGoto、LinkExecute、LinkBrowse、LinkAction、LinkSound、LinkMovie等各种具体的子类。

在Poppler::Document中取得一个Link以后,可以通过Link的

virtual LinkType linkType() const;
来取得具体类型。

LinkType是一个enum:

  enum LinkType  
   {  
       None, ///< Unknown link  
       Goto, ///< A "Go To" link  
       Execute, ///< A command to be executed  
       Browse, ///< An URL to be browsed (eg "http://poppler.freedesktop.org")  
       Action, ///< A "standard" action to be executed in the viewer  
       Sound, ///< A link representing a sound to be played  
       Movie, ///< An action to be executed on a movie  
       Rendition, ///< A rendition link  
       JavaScript, ///< A JavaScript code to be interpreted  
       OCGState, ///< An Optional Content Group state change  
       Hide, 
   };

对应相应的子类实现。

比如,如果Link是一个LinkExecute,就可以通过它的fileName()、parameters()方法,分别取得可执行文件的路径以及执行参数。

PDF批注

如果要对PDF文件进行批注,可以使用Annotation类。

这个类也是一个基类,它的子类有TextAnnotation、LineAnnotation、GeomAnnotation、HighlightAnnotation等等。

Annotation基类中有一个

virtual SubType subType() const = 0;
纯虚函数,可以返回子类的类型。

SubType也是一个enum:

   enum SubType  
   {    
       AText = 1, ///< TextAnnotation  
       ALine = 2, ///< LineAnnotation  
       AGeom = 3, ///< GeomAnnotation  
       AHighlight = 4, ///< HighlightAnnotation  
       AStamp = 5, ///< StampAnnotation  
       AInk = 6, ///< InkAnnotation  
       ALink = 7, ///< LinkAnnotation  
       ACaret = 8, ///< CaretAnnotation  
       AFileAttachment = 9, ///< FileAttachmentAnnotation  
       ASound = 10, ///< SoundAnnotation  
       AMovie = 11, ///< MovieAnnotation  
       AScreen = 12, ///< ScreenAnnotation  
       AWidget = 13, ///< WidgetAnnotation  
       ARichMedia = 14 ///< RichMediaAnnotation  
   };

所以,Annotation的使用,与Link很相似。我们可以举一反三,很快地掌握Annotation的使用方法。

比如,如下代码就可以给一个文档的指定位置,加一行下划线:

void  
annot_line (unique_ptr<Document> doc, int pn, double x1, double y1, double x2,  double y2)  
{  
  auto page = doc->page(pn);  
  auto annot = new LineAnnotation (LineAnnotation::LineType::Polyline);  
  annot->setLinePoints({{x1, y1}, {x2, y2}});  
  page->addAnnotation(annot);  
}

或者,给PDF文件中加一行注释:

void  
annot_text (unique_ptr<Document> doc, int pn, double x1, double y1, double x2,  
            double y2, string_view text)  
{  
  auto page = doc->page (pn);  
  auto annot = new TextAnnotation (TextAnnotation::TextType::Linked);  
  annot->setBoundary ({ x1, y1, x2, y2 });  
  annot->setContents (QString::fromLocal8Bit (text));  
  page->addAnnotation (annot);  
}

原文地址:https://blog.csdn.net/cuxqblt/article/details/142595037

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!