jeston平台交叉编译Poppler库与预览pdf文件

一、编译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/

src.pro

复制代码
     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

解决方案(按推荐顺序)

  1. 切换到 XCB(如果 Jetson 有 X11 桌面)

在终端运行以下命令检查是否支持 X11:

bash

echo $DISPLAY

如果输出(如 :0),则说明 X11 可用。此时用以下命令运行程序:

bash

./example -platform xcb file:///home/cc/help-cn.pdf

这是最简单有效的方案,XCB 不会限制 OpenGL 窗口数量。

三、qml插件部署

QML 引擎会按顺序在以下几个默认路径中查找:

  1. 应用程序可执行文件所在的目录

  2. QML2_IMPORT_PATH 环境变量指定的路径(在 Qt 5 中使用)。

  3. 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!");
        // 这里使用您的插件类型
    }
}

注意事项

  1. 路径必须指向包含 qmldir 文件的目录的父目录,而不是 qmldir 本身所在的目录

  2. 确保 libpopplerPlugin.so 有正确的执行权限:chmod +x libpopplerPlugin.so

  3. 确保库依赖项(如 poppler 库)在系统路径中可用

  4. 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: ""   // 默认空
    }
}
相关推荐
SilicoCode1 小时前
江科大STM32入门:FLASH闪存详解——从结构原理到读写保护
数据库·mongodb
一个有温度的技术博主2 小时前
DeepSeek Harness 深度解析:与 LangChain / LangGraph 的本质区别
数据库·oracle·langchain·harness
Wang's Blog2 小时前
PostgreSQL笔记4: 市场地位、生态全景与行业应用实践
数据库·笔记·postgresql
隔窗听雨眠3 小时前
Oracle误Truncate操作恢复:从原理到实战的完整指南
数据库·oracle
Lethehong4 小时前
MySQL迁移如何做到零改造?四层兼容方案详解
数据库·mysql·adb
Json____4 小时前
五金制品行业-企业官网源码
java·大数据·数据库·企业站·wwwoop.com
深念Y6 小时前
Opencode Event 表写入优化方案
数据库·人工智能·ai·node.js·bug·优化·opencode
竹枝溪6 小时前
MySQL进阶:约束、多表设计、多表查询与事务
java·数据库·mysql·事务·子查询·acid·多表查询
weixin_431600446 小时前
NestJS 入门(9):连上数据库,SQL 写在哪?
数据库·后端·sql·学习·nest.js