C++中将Pdf转换成图片,可以使用Xpdf或者Poppler。本文介绍的是Poppler。

需要注意的是Poppler的开源协议是GPL。

编译

如果仅仅是在C++中使用,可以直接使用vcpkg进行安装。

1
$ vcpkg install poppler

手动编译poppler

下面介绍如何在Windows上进行手动编译。

验证环境:Windows 10, Visual Studio 2019, CMake 3.23

  1. 安装vcpkg。是为了更方便安装一些第三方依赖。

  2. 下载Poppler

    1
    $ git clone git@github.com:freedesktop/poppler.git
  3. Poppler依赖了freetype和pkgconf,先通过vcpkg安装它们

    1
    2
    $ vcpkg install freetype
    $ vcpkg install pkgconf
  4. 修改poppler/CMakeLists.txt,使CMake可以找到vcpkg安装的包。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    cmake_minimum_required(VERSION 3.10.0 FATAL_ERROR)

    project(poppler)

    set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)

    include(D:/vcpkg/scripts/buildsystems/vcpkg.cmake)

    include(PopplerDefaults)
    include(PopplerMacros)

    像上面那样,加上include(D:/vcpkg/scripts/buildsystems/vcpkg.cmake),这是我的环境上的vcpkg.cmake位置,请根据你的环境同步修改。

  5. 编译debug版本

    1
    2
    3
    4
    $ cd poppler
    $ cmake -G "Visual Studio 16 2019" -A Win32 -S . -B "build_win32_debug" -DCMAKE_BUILD_TYPE=debug
    $ cmake --build build_win32_debug
    $ cmake --install build_win32_debug --config debug --prefix dist/debug

    在poppler/dist/debug目录下便是编译好的debug版本

  6. 用同样的方式编译release版本

    1
    2
    3
    $ cmake -G "Visual Studio 16 2019" -A Win32 -S . -B "build_win32_release" -DCMAKE_BUILD_TYPE=release
    $ cmake --build build_win32_release --config Release
    $ cmake --install build_win32_release --config Release --prefix dist/release

    在poppler/dist/release目录下便是编译好的release版本

手动编译poppler-qt5

如果你要在Qt5中使用poppler,可以编译poppler-qt5以获得更好的支持。

验证环境:Windows 10, Visual Studio 2019, CMake 3.23, Qt 5.15.2

在CMake编译增加参数即可:

1
2
3
$ cmake -G "Visual Studio 16 2019" -A Win32 -S . -B "build_win32_release" -DCMAKE_BUILD_TYPE=release -DCMAKE_PREFIX_PATH=C:\Qt\5.15.2\msvc2019\lib\cmake
$ cmake --build build_win32_release --config Release
$ cmake --install build_win32_release --config Release --prefix dist/release

C++

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
bool pdf2images(const std::string &pdfFileName, const std::string &imageDir, std::string *err)
{
std::unique_ptr<poppler::document> doc(poppler::document::load_from_file(pdfFileName));
if (!doc.get()) {
if (err != nullptr) *err = "loading error";
return false;
}
if (doc->is_locked()) {
if (err != nullptr) *err = "encrypted document";
return false;
}
int count = doc->pages();
for (int i = 0; i < count; ++i) {
std::unique_ptr<poppler::page> p(doc->create_page(i));
if (!p.get()) {
if (err != nullptr) *err = "NULL page";
return false;
}
poppler::page_renderer pr;
pr.set_render_hint(poppler::page_renderer::antialiasing, true);
pr.set_render_hint(poppler::page_renderer::text_antialiasing, true);
poppler::image img = pr.render_page(p.get());
if (!img.is_valid()) {
if (err != nullptr) *err = "rendering failed";
return false;
}
if (!img.save(imageDir + "/" + std::to_string(i) + ".png", "png")) {
if (err != nullptr) *err = "saving to file failed";
return false;
}
}
return true;
}

如果需要指定dpi,修改render_page的参数,例如:

1
poppler::image img = pr.render_page(p.get(), 96, 96);

Qt5

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

bool pdf2images(const QString &pdfFileName, const QString &imageDir, QString *err)
{
QScopedPointer<Poppler::Document> doc(Poppler::Document::load(pdfFileName));
if (!doc.get()) {
if (err != nullptr) *err = "loading error";
return false;
}
if (doc->isLocked()) {
if (err != nullptr) *err = "encrypted document";
return false;
}
doc->setRenderHint(Poppler::Document::Antialiasing);
doc->setRenderHint(Poppler::Document::TextAntialiasing);
int count = doc->numPages();
for (int i = 0; i < count; ++i) {
QScopedPointer<Poppler::Page> p(doc->page(i));
if (!p.get()) {
if (err != nullptr) *err = "NULL page";
return false;
}
QImage img = p->renderToImage();
if (img.isNull()) {
if (err != nullptr) *err = "rendering failed";
return false;
}
if (!img.save(imageDir + "/" + QString::number(i) + ".png", "png")) {
if (err != nullptr) *err = "saving to file failed";
return false;
}
}
return true;
}

完整的示例代码在这里

Reference