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

Qt pdf分割成png格式

记录下最近在Qt5.6.3 32位QtCreator环境下,使用MuPDF库将pdf分割成png。下面贴下相关文件内容

库目录

先在“..\PDFSplit\3rdparty\mupdf\platform\win32”目录下编译mupdf.sln生成“libmupdf.lib”,

下面是pro文件内容

QT       += core gui printsupport

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

FORMS += \
    mainwindow.ui
UI_DIR=temp
MOC_DIR=temp
OBJECTS_DIR=temp
RCC_DIR=temp

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target



win32: LIBS += -L$$PWD/3rdparty/lib/ -llibmupdf

INCLUDEPATH += $$PWD/3rdparty/include
DEPENDPATH += $$PWD/3rdparty/include

下面是mainWindow.cpp内容

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QThreadPool>
#include <QDebug>
#include <QFileInfo>


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    ,ui(new Ui::MainWindow)
    ,m_pdfPageToPngTask(nullptr)
{
    ui->setupUi(this);
    this->setWindowTitle(QStringLiteral("PDF拆分成png"));
    m_pdfPageToPngTask=new PdfPageToPngTask;
    connect(m_pdfPageToPngTask,&PdfPageToPngTask::fileSaved,this,&MainWindow::onFileSaved,Qt::BlockingQueuedConnection);
    connect(m_pdfPageToPngTask,&PdfPageToPngTask::sigFinished,this,[=](){
        QMessageBox::information(this,QStringLiteral("提示"),QStringLiteral("拆分完成!!!"));
    },Qt::BlockingQueuedConnection);
}
void MainWindow::onFileSaved(QString fileName)
{
    ui->listWidget->addItem(fileName);
}

void MainWindow::on_pushButtonLoad_clicked()
{
    auto temp = QFileDialog::getOpenFileName(this, "", qApp->applicationDirPath(), "*.pdf");
    if(temp.isEmpty())
    {
        return;
    }
    m_pdfPath=temp;
    ui->listWidget->addItem(m_pdfPath);
}

void MainWindow::on_pushButtonCreatPng_clicked()
{
    if (m_pdfPath.isEmpty())
        return;
    // 弹出文件夹选择对话框,获取用于保存图片的文件夹路径
    auto dir = QFileDialog::getExistingDirectory(this, "", qApp->applicationDirPath());
    if (dir.isEmpty())
        return;
    if(m_pdfPageToPngTask->isRunning())
    {
        m_pdfPageToPngTask->m_lock.lock();
        m_pdfPageToPngTask->m_isStop=true;
        m_pdfPageToPngTask->m_pdfPath.clear();
        m_pdfPageToPngTask->m_lock.unlock();
        m_pdfPageToPngTask->quit();
        m_pdfPageToPngTask->wait();
    }
    m_pdfPageToPngTask->m_pdfPath=m_pdfPath;
    m_pdfPageToPngTask->m_saveDir=dir;
    m_pdfPageToPngTask->start();
}

MainWindow::~MainWindow()
{
    if(m_pdfPageToPngTask!=nullptr)
    {
        if(m_pdfPageToPngTask->isRunning())
        {
            m_pdfPageToPngTask->m_lock.lock();
            m_pdfPageToPngTask->m_isStop=true;
            m_pdfPageToPngTask->m_lock.unlock();
            m_pdfPageToPngTask->quit();
            m_pdfPageToPngTask->wait();
        }
        delete m_pdfPageToPngTask;
        m_pdfPageToPngTask=nullptr;
    }
    delete ui;
}

void MainWindow::on_listWidget_itemSelectionChanged()
{
    auto item=ui->listWidget->currentItem();
    auto path = item->text();
    if(path.isEmpty())return;
    QImage *image=new QImage;
    image->load(path);
    ui->label->setPixmap(QPixmap::fromImage(*image));
    ui->label->setAlignment(Qt::AlignCenter);
    QFileInfo fileInfo(path);
    ui->groupBox->setTitle(QStringLiteral("预览-")+fileInfo.baseName());
}


void MainWindow::on_pushButtonLoadPNG_clicked()
{
    auto temp = QFileDialog::getOpenFileNames(this, "", qApp->applicationDirPath(), "*.png");
    if(temp.isEmpty())
    {
        return;
    }
    for(const QString& filePath:temp)
    {
        QFileInfo fileInfo(filePath);
        if(fileInfo.suffix()!="png")continue;
        ui->listWidgetPNG->addItem(fileInfo.filePath());
    }

}

void MainWindow::on_pushButtonCreatPDF_clicked()
{
    auto temp = QFileDialog::getSaveFileName(this, "", qApp->applicationDirPath(), "*.pdf");
    if(temp.isEmpty())
    {
        return;
    }
    QPrinter *printer = new QPrinter;
    QPainter *painter = new QPainter;
    QString  PdfName = temp;

    printer->setPageSize(QPrinter::A4);
    printer->setOutputFormat(QPrinter::PdfFormat);
    printer->setOutputFileName(PdfName);
    painter->begin(printer);

    if(printer == NULL)
        return;

    // A4纸尺寸相关参数(单位:像素,这里假设了一定的分辨率来转换,可根据实际情况调整)
    const int a4Width = 2480;  // 示例宽度,对应常见的分辨率转换后的宽度,可按需改
    const int a4Height = 3508;  // 示例高度,对应常见的分辨率转换后的高度,可按需改

    for(int i = 0; i < ui->listWidgetPNG->count(); ++i)
    {
        QFileInfo fileInfo(ui->listWidgetPNG->item(i)->text());
        qDebug() << fileInfo.suffix();
        if(fileInfo.suffix()!= "png")
            continue;
        QImage *image = new QImage;
        image->load(fileInfo.filePath());//读取图片

        // 调整图片大小以适应A4纸尺寸(这里简单按照等比例缩放,可根据需求完善比如拉伸等处理)
        if (image->width()!= a4Width || image->height()!= a4Height)
        {
            image = new QImage(image->scaled(a4Width, a4Height, Qt::KeepAspectRatio));
        }

        // 绘制图片到PDF页面,左上角坐标(0, 0)开始绘制,铺满整个页面
        painter->drawImage(0, 0, *image);

        // 每绘制完一张图片,开启新的页面用于放置下一张图片
        printer->newPage();
    }
    painter->end();
    QMessageBox::information(this, QStringLiteral("提示"), QStringLiteral("合成pdf完成!!!"));
}

下面是mainWindow.h内容

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QListWidgetItem>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

#include <QRunnable>
#include <QObject>
#include <QDebug>
#include <QFileInfo>
#include <QThread>
#include "mupdf/fitz.h"
#include <QMessageBox>
#include <QPainter>
#include <QPrinter>

class PdfPageToPngTask : public QThread
{
    Q_OBJECT
public:

    // 重写run函数,该函数内定义了具体要在线程中执行的任务逻辑
    void run() override
    {
        while (true)
        {
            if(m_isStop)
            {
                break;
            }
            if(m_pdfPath.isEmpty())
            {
                QThread::msleep(10);
            }
            else
            {
                // MuPDF库的上下文结构体指针,用于管理整个文档处理的相关资源和状态
                fz_context *context;
                // MuPDF库的文档结构体指针,用于表示打开的PDF文档
                fz_document *document;
                // MuPDF库的矩阵结构体,用于定义页面的变换(如缩放、旋转等)
                fz_matrix matrix;
                // 用于存储页面缩放比例,初始化为100,表示100%缩放
                float zoom = 100;
                // 用于存储旋转角度,初始化为0
                float rotate = 0;

                // 创建一个新的MuPDF上下文,参数NULL表示使用默认的内存分配器等设置,FZ_STORE_UNLIMITED表示内存使用无限制(通常用于测试等场景)
                context = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
                if (!context)
                {
                    qDebug() << QString::asprintf("cannot create mupdf context\n");
                    continue;
                }

                // 尝试在创建的上下文中注册文档处理相关的各种处理器(例如不同类型PDF的解析等相关处理)
                fz_try(context)
                        fz_register_document_handlers(context);
                // 如果在上述尝试过程中出现错误(例如内存不足等原因导致注册失败)
                fz_catch(context)
                {
                    qDebug() << QString::asprintf("cannot register document handlers: %s\n", fz_caught_message(context));
                    fz_drop_context(context);
                    continue;
                }

                // 尝试使用之前创建的上下文打开指定的PDF文档(通过pdfPath路径指定)
                fz_try(context)
                        document = fz_open_document(context, m_pdfPath.toLocal8Bit().data());
                // 如果打开文档过程中出现错误
                fz_catch(context)
                {
                    // 在标准错误输出打印错误信息,提示无法打开文档以及具体的错误消息
                    qDebug() << QString::asprintf("cannot open document: %s\n", fz_caught_message(context));
                    // 释放之前创建的上下文资源
                    fz_drop_context(context);
                    continue;
                }

                // 获取打开的PDF文档的总页数
                int page_count = fz_count_pages(context, document);
                // 如果获取总页数过程中出现错误
                if (page_count < 0)
                {
                    qDebug() << QString::asprintf("cannot count number of pages: %s\n", fz_caught_message(context));
                    fz_drop_document(context, document);
                    fz_drop_context(context);
                    continue;
                }

                // 根据指定的缩放比例创建一个缩放矩阵,将缩放比例转换为适合MuPDF库内部使用的格式(例如100%缩放在这里就是1.0的比例)
                matrix = fz_scale(zoom / 100, zoom / 100);
                // 根据指定的旋转角度对之前创建的矩阵进行旋转操作,得到最终用于页面渲染的变换矩阵
                matrix = fz_pre_rotate(matrix, rotate);

                for (int page_number = 0; page_number < page_count; ++page_number)
                {
                    if(m_isStop)break;
                    fz_pixmap *pix;
                    // 尝试根据指定的页码、变换矩阵等参数从打开的PDF文档中渲染出对应页面的像素图(以RGB颜色模式,参数0可能表示一些默认的渲染选项等)
                    fz_try(context)
                            pix = fz_new_pixmap_from_page_number(context, document, page_number, matrix, fz_device_rgb(context), 0);
                    // 如果渲染页面过程中出现错误
                    fz_catch(context)
                    {
                        // 在标准错误输出打印错误信息,提示无法渲染页面以及具体的错误消息
                        fprintf(stderr, "cannot render page %d: %s\n", page_number, fz_caught_message(context));
                        continue;
                    }
                    QFileInfo fileInfo(m_pdfPath);
                    // 构建保存当前页面的PNG文件路径,这里简单地在原文件名基础上添加页码信息,可根据实际需求调整更合理的命名方式
                    QString saveFileName = QString("%1/%2_page_%3.png").arg(m_saveDir).arg(fileInfo.baseName()).arg(page_number + 1);

                    // 将渲染得到的像素图保存为PNG图片
                    fz_save_pixmap_as_png(context, pix, saveFileName.toLocal8Bit().data());

                    // 在主线程中更新UI,将生成的图片文件名添加到QListWidget中显示(通过信号槽机制)
                    emit fileSaved(saveFileName);

                    // 释放渲染得到的像素图资源
                    fz_drop_pixmap(context, pix);
                }
                // 释放打开的文档资源
                fz_drop_document(context, document);
                // 释放创建的上下文资源
                fz_drop_context(context);
                m_isStop=true;
                emit sigFinished();
                break;
            }

        }
    }

signals:
    // 自定义信号,用于通知主线程有文件保存成功,传递文件名参数
    void fileSaved(QString fileName);
    void sigFinished();
public:
    QString m_pdfPath;
    QString m_saveDir;
    QMutex m_lock;
    bool m_isStop=false;
};

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void onFileSaved(QString fileName);
    void on_pushButtonLoad_clicked();

    void on_pushButtonCreatPng_clicked();

    void on_listWidget_itemSelectionChanged();

    void on_pushButtonLoadPNG_clicked();

    void on_pushButtonCreatPDF_clicked();

private:
    Ui::MainWindow *ui;
    QString m_pdfPath;
    PdfPageToPngTask *m_pdfPageToPngTask;
};
#endif // MAINWINDOW_H

效果展示


http://www.kler.cn/a/470970.html

相关文章:

  • 设计模式(1)——面向对象和面向过程,封装、继承和多态
  • ECharts系列:echart中折线图折线设置不平滑显示
  • 如何删除 Docker 中的悬虚镜像?
  • 嵌入式硬件设计的基本流程
  • 【Python运维】使用Python与Docker进行高效的容器化应用管理
  • MySQL入门学习笔记
  • 5.zookeeper可视化工具ZooInspector
  • QT自定义工具条渐变背景颜色一例
  • 基于YOLOV5的车辆跟踪与目标检测
  • 【C++数据结构——内排序】希尔排序(头歌实践教学平台习题)【合集】
  • 【FlutterDart】 listView例子一(13 /100)
  • 高效工作流:用Mermaid绘制你的专属流程图;如何在Vue3中导入mermaid绘制流程图
  • 抖音a_bogus,mstoken全参数爬虫逆向补环境2024-06-15最新版
  • 可缩放大屏布局方式
  • K8S中的Pod生命周期之容器探测
  • 理解 maven-jar-plugin:如何使用 Add-Opens 配置解决 Java 模块访问问题
  • 亚远景-ASPICE评估:提升汽车软件开发过程的质量与效率
  • QT中如何通过QFile正确读写、覆盖、追加写入内容?
  • docker的基本操作示例
  • sqli-labs靶场环境搭建
  • package.json解决依赖冲突
  • WebSocket 客户端开发:浏览器实战
  • vue3中el-table实现多表头并表格合并行或列
  • 【数据挖掘】深度高斯过程
  • 小米智能哑铃上市,代理 IP 视角下的智能健身新篇
  • 【EI会议征稿】2025图像处理和深度学习国际学术会议(IPDL 2025)