一、编译Poppler库
#交叉编译Poppler-22.02.0
mkdir build && cd build
cmake .. \
-DCMAKE_C_COMPILER=/usr/bin/aarch64-linux-gnu-gcc \
-DCMAKE_CXX_COMPILER=/usr/bin/aarch64-linux-gnu-g++ \
-DCMAKE_SYSTEM_NAME=Linux \
-DCMAKE_SYSTEM_PROCESSOR=aarch64 \
-DCMAKE_SYSROOT=/home/cc/nvidia/35.3/Linux_for_Tegra/rootfs \
-DCMAKE_FIND_ROOT_PATH=/home/cc/nvidia/35.3/Linux_for_Tegra/rootfs \
-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \
-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \
-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \
-DENABLE_QT5=ON \
-DENABLE_GLIB=OFF \
-DENABLE_GTK_DOC=OFF \
-DENABLE_LIBOPENJPEG=none \
-DWITH_Fontconfig=ON \
-DENABLE_BOOST=OFF \
-DCMAKE_PREFIX_PATH=/home/cc/qt_source/Qt-5.15.2-arm \
-DCMAKE_INSTALL_PREFIX=~/poppler-qt5-arm-install
#可选
-DPKG_CONFIG_EXECUTABLE=/usr/bin/pkg-config \
pkg-config 精准找到 rootfs 里的库配置,建议你在运行 CMake 时,再加一个环境变量(或者在 CMake 命令前加上):
export PKG_CONFIG_SYSROOT_DIR=/home/cc/nvidia/35.3/Linux_for_Tegra/rootfs
编译
make -j$(nproc)
安装
make install
验证,bin目录下生成一些pdf工具。比如:pdfinfo等。
pdfinfo ./test.pdf
打印信息如下:
itle:
Subject:
Keywords:
Author: xuxua
Creator: WPS 文字
Producer:
CreationDate: Mon Aug 3 02:13:36 2026 PDT
ModDate: Mon Aug 3 02:13:36 2026 PDT
Tagged: no
UserProperties: no
Suspects: no
Form: none
JavaScript: no
Pages: 14
Encrypted: no
Page size: 595.3 x 841.9 pts (A4)
Page rot: 0
File size: 2205329 bytes
Optimized: no
PDF version: 1.7
二、编译Poppler-QML-plugin插件
1、获取代码
git clone https://github.com/dept2/Poppler-QML-plugin.git
cd Poppler-QML-plugin
2、编译并安装
方法一:使用qmake 进行构建。
qmake
make
sudo make install
执行 sudo make install 后,插件会被自动安装到系统的 QML 导入路径中,例如 /usr/lib/aarch64-linux-gnu/qt5/qml/org/docviewer/poppler/
TARGET = popplerPlugin
QT += qml quick
CONFIG += qt plugin
TEMPLATE = lib
LIBS += -lpoppler-qt5
# Input
SOURCES += \
plugin.cpp \
pdfModel.cpp \
pageImageProvider.cpp
HEADERS += \
plugin.h \
pdfModel.h \
pageImageProvider.h
OTHER_FILES += ../README.md
qmlFiles.files = \
qmldir \
popplerPlugin.qmltypes \
PDFView.qml
# Add 'make qmltypes' command to generate popplerPlugin.qmltypes
load(resolve_target)
qmltypes.target = qmltypes
qmltypes.commands = $$[QT_INSTALL_BINS]/qmlplugindump org.docviewer.poppler 1.0 $$QMAKE_RESOLVED_TARGET > $$PWD/popplerPlugin.qmltypes
qmltypes.depends = $$QMAKE_RESOLVED_TARGET
QMAKE_EXTRA_TARGETS += qmltypes
installPath = $$[QT_INSTALL_QML]/org/docviewer/poppler/
qmlFiles.path = $$installPath
target.path = $$installPath
INSTALLS += target qmlFiles
win32:CONFIG(release, debug|release): LIBS += -L/home/cc/poppler-qt5-arm-install/lib/ -lpoppler-qt5
else:win32:CONFIG(debug, debug|release): LIBS += -L/home/cc/poppler-qt5-arm-install/lib/ -lpoppler-qt5
else:unix: LIBS += -L/home/cc/poppler-qt5-arm-install/lib/ -lpoppler-qt5
INCLUDEPATH += /home/cc/poppler-qt5-arm-install/include
DEPENDPATH += /home/cc/poppler-qt5-arm-install/include
方法二:通过qt编译器打开插件对应的plugin.pro工程。添加lib库路径,编译。手工按照插件(切换到libpopplerPlugin.so生成目录下,执行make install)
make install
/home/cc/qt_source/Qt-5.15.2-arm/bin/qmake -install qinstall -exe libpopplerPlugin.so /home/cc/qt_source/Qt-5.15.2-arm/qml/org/docviewer/poppler/libpopplerPlugin.so
/usr/bin/aarch64-linux-gnu-strip --strip-unneeded /home/cc/qt_source/Qt-5.15.2-arm/qml/org/docviewer/poppler/libpopplerPlugin.so
/home/cc/qt_source/Qt-5.15.2-arm/bin/qmake -install qinstall /home/cc/Poppler-QML-plugin/Poppler-QML-plugin/src/qmldir /home/cc/qt_source/Qt-5.15.2-arm/qml/org/docviewer/poppler/qmldir
/home/cc/qt_source/Qt-5.15.2-arm/bin/qmake -install qinstall /home/cc/Poppler-QML-plugin/Poppler-QML-plugin/src/popplerPlugin.qmltypes /home/cc/qt_source/Qt-5.15.2-arm/qml/org/docviewer/poppler/popplerPlugin.qmltypes
/home/cc/qt_source/Qt-5.15.2-arm/bin/qmake -install qinstall /home/cc/Poppler-QML-plugin/Poppler-QML-plugin/src/PDFView.qml /home/cc/qt_source/Qt-5.15.2-arm/qml/org/docviewer/poppler/PDFView.qml
验证:执行example
1、在非嵌入式系统中执行运行example ./file:///home/cc/help.pdf
2、在嵌入式系统中执行运行example ./file:///home/cc/help.pdf
选择pdf文件后,崩溃。如下信息:
EGLFS: OpenGL windows cannot be mixed with others.
Aborted
解决方案(按推荐顺序)
- 切换到 XCB(如果 Jetson 有 X11 桌面)
在终端运行以下命令检查是否支持 X11:
bash
echo $DISPLAY
如果输出(如 :0),则说明 X11 可用。此时用以下命令运行程序:
bash
./example -platform xcb file:///home/cc/help-cn.pdf
这是最简单有效的方案,XCB 不会限制 OpenGL 窗口数量。
三、qml插件部署
QML 引擎会按顺序在以下几个默认路径中查找:
-
应用程序可执行文件所在的目录。
-
QML2_IMPORT_PATH环境变量指定的路径(在 Qt 5 中使用)。 -
Qt 库内置的导入路径 (
Qml2ImportsPath),通常是 Qt 安装目录下的qml文件夹。
几种方法来添加自己的路径:
添加到Qt安装目录中:将插件放到qml目录中。比如:/home/cc/qt_source/Qt-5.15.2-arm/qml。
示例:
/home/cc/qt_source/Qt-5.15.2-arm/qml//org/docviewer/poppler
├── libpopplerPlugin.so
└── qmldir
在 C++ 代码中:使用 QQmlEngine::addImportPath() 方法。
cpp
QQmlEngine engine;
engine.addImportPath("/home/cc/qt_source/Qt-5.15.2-arm/qml"); // 添加文件系统路径
或者
使用相对路径
QQmlEngine engine;
// 如果可执行文件在某个位置,可以使用相对路径
engine.addImportPath("./qml_modules"); // 假设 qml_modules 包含 org 目录
通过环境变量:设置 QML_IMPORT_PATH 环境变量。
使用示例
#include <QQmlEngine>
#include <QQmlComponent>
#include <QQuickView>
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QQmlEngine engine;
// 添加导入路径(指向包含 org 目录的父目录)
engine.addImportPath("/home/cc/qt_source/Qt-5.15.2-arm/qml");
// 可选:设置插件路径(如果需要)
engine.addPluginPath("/home/cc/qt_source/Qt-5.15.2-arm/qml/org/docviewer/poppler");
// 创建 QML 组件
QQmlComponent component(&engine);
component.setData(R"(
import org.docviewer.poppler 1.0
// 使用您的插件中的类型
// ...
)", QUrl());
// 或者加载 QML 文件
// QQmlComponent component(&engine, QUrl::fromLocalFile("main.qml"));
QQuickView view;
view.setEngine(&engine);
view.setSource(QUrl::fromLocalFile("main.qml"));
view.show();
return app.exec();
}
验证插件是否加载成功。
import QtQuick 2.15
import org.docviewer.poppler 1.0
Rectangle {
width: 400
height: 300
Component.onCompleted: {
console.log("Poppler plugin loaded successfully!");
// 这里使用您的插件类型
}
}
注意事项
-
路径必须指向包含
qmldir文件的目录的父目录,而不是qmldir本身所在的目录 -
确保
libpopplerPlugin.so有正确的执行权限:chmod +x libpopplerPlugin.so -
确保库依赖项(如 poppler 库)在系统路径中可用
-
qmldir文件内容应该类似:text
module org.docviewer.poppler plugin libpopplerPlugin
如果您仍然遇到加载问题,请检查:
-
LD_LIBRARY_PATH 是否包含插件目录
-
qmldir 文件中的 module 声明是否与目录结构匹配
-
插件的依赖库是否都已安装
四、qml示例
pdfSee.qml
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.15
import Qt.labs.platform 1.1
//import QtQuick.Dialogs 1.3
import QtQuick.Pdf 5.15 // 导入PDF模块
import QtWebEngine 1.10
import QtQuick.Controls.Material 2.4
import org.docviewer.poppler 1.0
Rectangle{
id:pdfSeeDialog
width: parent.width
height: parent.height
anchors.fill: parent
color: "#FFFACD" /*"transparent"*/
visible: true
FileDialog {
id: fileDialog
title: "选择 PDF"
nameFilters: ["PDF (*.pdf)"]
folder: StandardPaths.writableLocation(StandardPaths.DocumentsLocation)
onFileChanged: pdfView.forceActiveFocus()
/*
onAccepted: {
console.log("系统返回的 URL:", fileDialog.fileUrl)
var url = fileDialog.fileUrl.toString()
var fileName = url.substring(url.lastIndexOf("/") + 1)
console.log("文件名:", fileName)
labelFileNameValue.text = fileName
webView.url = fileDialog.fileUrl.toString()
console.log("加载 PDF:", fileDialog.fileUrl)
}
*/
onRejected: {
console.log("取消选择")
}
}
ColumnLayout{
width: parent.width
height:parent.height
spacing: 5
Item{
height: 3
}
RowLayout {
width: parent.width
Layout.preferredHeight: 50
height:50
spacing: 5
//anchors.centerIn: parent
Label {
id: labelFileName
Layout.preferredWidth: 160
Layout.preferredHeight: 50
verticalAlignment: Text.AlignVCenter
text: qsTr("文件名:")
font.pixelSize: 20
// 设置内边距
padding: 3
}
Label {
id: labelFileNameValue
Layout.fillWidth: true
Layout.preferredHeight: 50
verticalAlignment: Text.AlignVCenter
text: ""
// 设置背景
background: Rectangle {
color: "#4A4A77" // 背景颜色
radius: 0 // 圆角半径
}
color: "#F5F5F5"
font.pixelSize: 20
// 设置内边距
padding: 3
}
Slider {
id: zoomSlider
Layout.preferredWidth: 140
Layout.preferredHeight: 50
from: 0.5
to: 2
stepSize: .1
value: 1
onValueChanged: pdfView.zoom = value
}
Button {
id: buttonSelectPdfFile
Layout.preferredWidth: 140
Layout.preferredHeight: 50
text: qsTr("选择PDF文件")
// 文字大小
font.pixelSize: fontDefaultSize
font.bold: true
// 移除默认背景
background: Rectangle {
color: buttonSelectPdfFile.down ? "#0083B5" :
buttonSelectPdfFile.hovered ? "#0083B5" : "#2d5d8c"
//radius: 8
border.color: "#0083B5"//background: #0083B5;
border.width: 1
}
// 自定义文字样式
contentItem: Text {
text: buttonSelectPdfFile.text
font: buttonSelectPdfFile.font
color: "#F5F5F5"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
//font.pixelSize: 30
//font.bold: true
}
// 设置内边距
padding: 3
onClicked: {
//事件处理
fileDialog.open()
}
}
Button {
id: buttonClose
Layout.preferredWidth: 140
Layout.preferredHeight: 50
Layout.alignment: Qt.AlignRight
Layout.rightMargin: 5
text: qsTr("关闭")
// 文字大小
font.pixelSize: 20
font.bold: true
// 移除默认背景
background: Rectangle {
color: buttonClose.down ? "#0083B5" :
buttonClose.hovered ? "#0083B5" : "#2d5d8c"
//radius: 8
border.color: "#0083B5"//background: #0083B5;
border.width: 1
}
// 自定义文字样式
contentItem: Text {
text: buttonClose.text
font: buttonClose.font
color: "#F5F5F5"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
//font.pixelSize: 30
//font.bold: true
}
// 设置内边距
padding: 3
onClicked: {
//事件处理
pageLoader.source = ""
}
}
}
PDFView {
id: pdfView
Layout.fillWidth: true
Layout.fillHeight: true
focus: true
clip: true
path: fileDialog.file.toString().substring(6)
ScrollBar.vertical: ScrollBar {
minimumSize: 0.04
}
Keys.onPressed: {
if (event.modifiers === Qt.ControlModifier) {
if (event.key === Qt.Key_Minus) {
zoomSlider.decrease()
event.accepted = true
} else if (event.key === Qt.Key_Plus) {
zoomSlider.increase()
event.accepted = true
} else if (event.key === Qt.Key_0) {
zoomSlider.value = 1
event.accepted = true
} else if (event.key === Qt.Key_F) {
searchField.forceActiveFocus()
}
} else if (event.modifiers === Qt.NoModifier) {
if (event.key === Qt.Key_Home) {
pagesView.positionViewAtBeginning()
event.accepted = true
} else if (event.key === Qt.Key_End) {
pagesView.positionViewAtEnd()
event.accepted = true
}
}
}
}
}
}
help.qml
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.15
Item {
width: parent.width
height: 1200-80
property int fontDefaultSize: 30
//帮助 title
Rectangle {
y:20
id: rectHelpSetByContent
width: parent.width
height: 40
color: "#383838"
//border.color:"blue"
Text {
anchors.centerIn: parent
id: labelHelpSetByContent
text: qsTr("帮助")
color: "#F5F5F5"
font.pixelSize: fontDefaultSize
}
}
ColumnLayout{
y:90
width:parent.width
height: 80
spacing: 0
//用户手册
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 80
color: "#4A4A4A" // 背景色
border{
color: "#FFFFFF"
width: 1
}
Layout.alignment: Qt.AlignTop
RowLayout {
width: parent.width
spacing: 10
anchors.centerIn: parent
Label {
id: labelUserManualByContent
Layout.fillWidth: true
text: qsTr("用户手册")
color: "#F5F5F5"
font.pixelSize: fontDefaultSize
Layout.leftMargin: 30
}
Label {
text: qsTr("详情")
color: "#F5F5F5"
font.pixelSize: fontDefaultSize
Layout.alignment:Qt.AlignRight
}
Label {
text: qsTr(">")
color: "#F5F5F5"
font.pixelSize: fontDefaultSize
Layout.alignment:Qt.AlignRight
Layout.rightMargin: 30
MouseArea{
anchors.fill:parent
onClicked: {
console.log("--详情触发")
pageLoader.source = "pdfSee.qml"
}
}
}
}
}
}
Loader {
id: pageLoader
y:90
width:parent.width
height:1080 - 170
source: "" // 默认空
}
}