当前位置: 首页 > news >正文

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

如果只是读取、渲染pdf文件,除了mupdf以外,在Linux系统中还可以使用Poppler库。Poppler的历史非常古老,X窗口系统中的pdf查看工具xpdf,使用的就是poppler。

Poppler在Linux各发行版,以及BSD族系统之中,都有现成的二进制安装包。

而且,Poppler还提供了glib、Qt5、Qt6等多种上层库的支持。本文中的示例,就采用Qt6的接口。

开发环境

Poppler按照上层接口的不同,需要不同的头文件与库文件。

原生API

比如,如果使用原生的C++接口,就需要使用poppler-devel安装包,包含Poppler底层的头文件,头文件目录是/usr/include/poppler,连接/usr/lib64/libpoppler.so动态库。

为了简化这一操作,可以使用pkg-config文件。

如:

~/$ pkg-config --cflags --libs poppler  
-I/usr/include/poppler -lpoppler

GLIB API

如果在glib程序中使用Poppler,就可以使用Poppler的glib绑定。

还是使用pkg-config:

~/$ pkg-config --cflags --libs poppler-glib  
-I/usr/include/poppler/glib -I/usr/include/cairo -I/usr/include/freetype2 -I/usr/include/glib-2.0 -I/usr/li  
b64/glib-2.0/include -I/usr/include/libxml2 -I/usr/include/libpng16 -DWITH_GZFILEOP -I/usr/include/harfbuzz  
-I/usr/include/sysprof-6 -pthread -I/usr/include/pixman-1 -I/usr/include/poppler -lpoppler-glib -lgobject-  
2.0 -lglib-2.0 -lcairo

我们可以看到,头文件目录是/usr/include/poppler/glib,而连接的库也大量使用了glib的底层动态库。

如果我们真的使用Poppler的glib绑定,就会发现把PDF的页面导出成图片的时候,是使用的GdkPixbuf。

Qt API

如果使用Qt的绑定,就根据Qt的版本,还有不同的二进制库。对于Qt5、Qt6的分别是poppler-qt5-devel与poppler-qt6-devel。

我们后文全都使用poppler-qt6-devel举例。

还是使用pkg-config看一下:

~/$ pkg-config --cflags --libs poppler-qt6  
-I/usr/include/poppler/qt6 -I/usr/include/poppler -lpoppler-qt6

如果使用CMake构建,就可以使用CMake的PkgConfig来获取相应的变量,不再赘述。

打开PDF

使用poppler-qt6的时候,PDF相关的类位于Poppler名字空间,PDF文档的类是Document,即我们需要把PDF文档解析成Poppler::Document。

这个解析过程是load()静态方法。

需要注意的是,Poppler的Qt绑定,大量使用了智能指针来方便内存的管理。

比如上文提到的Poppler::Document::load()方法,返回的就是一个unique_ptrPoppler::Document。

所以,我们需要使用unique_ptrPoppler::Document来保存加载的PDF文件,在智能指针的作用域超出以后,Poppler::Document被自动释放。

另外,load函数的第一个参数,是一个QString。如果我们是C++的std::string,需要使用QString::fromLocal8Bit来转化成QString。

比如我们定义一个PDF类:

using namespace Poppler;class PDF {
public:// 加载bool load(const std::string &filename);// 总页数int pageCount();// 页面大小QSizeF pageSizeF(int pagenum);// 搜索QList<QRectF> pageSearch (int pagenum, const string &str);// 渲染QImage pageRender (int pagenum, int ix, int iy, double zoom, int degree);private:// 智能指针unique_ptr<Document> m_doc;
};

加载方法:

bool PDF::load(const std::string &filename)
{m_doc = Document::load (QString::fromLocal8Bit (filename));  if (m_doc == nullptr)  {      // 如果加载失败,尝试使用密码解锁auto text = QInputDialog::getText (nullptr, "password", "input password");  auto pass = QByteArray::fromStdString (text.toStdString ());  m_doc = Document::load (QString::fromStdString (filename), pass, pass);}if (m_doc)return true;elsereturn false;

上面的过程,返回的doc就是一个unique_ptrPoppler::Document。

取得页面信息

通过unique_ptrPoppler::Document的numPages()方法,可以取得总页数。

int  
PDF::pageCount ()  
{  return m_doc->numPages ();  
}  

另外通过page(int pagenum)方法,可以取得一个unique_ptrPoppler::Page,这个Page支持的方法比较多,可以做各种操作。

比如,可以通过Poppler::Page的pageSizeF()方法,取得页面的大小。

QSizeF  
PDF::pageSize (int pagenum)  
{  auto page = m_doc->page (pn);  auto size = page->pageSizeF ();  return size;
}  

再比如,可以通过Poppler::Page的search()方法,搜索页面的文本:

QList<QRectF> 
PDF::pageSearch (int pn, const string &str)  
{  auto page = mDoc->page (pn);  auto results = page->search (QString::fromLocal8Bit(str));  return results;
}

返回的是一个模板类QList<QRectF>,每一个QRectF都是一个矩形。

渲染PDF

还可以通过Poppler::Page的renderToImage()方法,把一个页面渲染成一个图片。

但是renderToImage()方法,比前面介绍的稍微复杂一点儿。

它的原型是:

 QImage renderToImage(double xres = 72.0, double yres = 72.0, int x = -1, int y = -1, int w = -1, int h  
= -1, Rotation rotate = Rotate0) const;
  • 其中,xres、yres分别是横竖两个方向的字符大小。默认都是72.0。如果我们要缩放页面,就需要根据缩放比例调整这个值。
  • 而x、y是页面的左上角坐标,w是页面宽度,h是页面高度。如果我们要渲染页面的一部分,就可以灵活调整这4个数值。
  • 而Rotation是控制渲染的方向,默认是原始方向,即Rotate0,还可以是Rotate90、Rotate180、Rotate270,可以通过字面意思猜出来,这是页面旋转的角度。

所以,以下代码可以根据输出页面大小、缩放以及方向来渲染一个PDF页面为一个QImage。

QImage
ApvlvPDF::pageRender (int pagenum, int ix, int iy, double zoom, int degree)  
{  auto xres = 72.0, yres = 72.0;  xres *= zoom;  yres *= zoom;auto width = zoom * ix, height = zoom * iy;  auto prot = Poppler::Page::Rotate0;  if (degree == 90)  prot = Poppler::Page::Rotate90;  if (degree == 180)  prot = Poppler::Page::Rotate180;  if (degree == 270)  prot = Poppler::Page::Rotate270;  auto page = mDoc->page (pagenum);  auto image = page->renderToImage (xres, yres, 0, 0, width, height, prot);  return image;  
}  

http://www.mrgr.cn/news/31277.html

相关文章:

  • Web开发:ABP框架3——入门级别的接口增删改查实现原理
  • MapReduce基本原理
  • 【Python报错已解决】python setup.py bdist_wheel did not run successfully.
  • 动态线程池(四)
  • jdk版本更换以及遇到的问题略谈(以jdk1.8和jdk11为例)
  • 如何来写一份开题报告?
  • OpenCV特征检测(6)对初步检测到的角点位置进行亚像素级别的精炼函数cornerSubPix()的使用
  • Live800:从心出发,以情动人:构建深度客户服务文化
  • (c++)线程的创建、互斥锁的使用、线程数组
  • 网络编程练习:UDP聊天室
  • 虚拟机安装nginx需要注意的一些事项
  • Linux 进程3
  • 5G技术对IT行业的影响及未来发展
  • 操作系统 | 学习笔记 | | 王道 | 5.2 设备独立软件
  • OpenAi assistant run always fails when called from PHP
  • 基于嵌入式的智能物流柜( 触摸屏/0.96寸oled屏)
  • pytorch快速入门(一)—— 基本工具及平台介绍
  • Bigemap GIS Office 2024注册机 全能版地图下载软件
  • nginx常用配置及调优
  • 力扣题解(统计特殊整数)