批量图片合并生成PDF文档
为解决大量图片合并为pdf文档而写,离线操作,保证数据安全,支持图片左键拖拽或右键菜单添加、调整顺序,图片预览、纸张大小设置、排版方向、边距设置、奇偶页打印边距、图片自动缩放、等常用功能。(文末有封装好的单文件版下载)
开发环境:windows10 LTSC Qt5.9 C++
运行环境:x86 Winows


mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QDebug>
#include <QMenu>
#include <QPoint>
#include <QListWidget>
#include <QCheckBox>
#include <QPixmap>
#include <QDebug>
#include <QDropEvent>
#include <QMimeData>
#include <QPainter>
#include <QPdfWriter>
#include <QProgressBar>
#include <QDesktopServices>
#include <QMessageBox>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->imgListWidget->setDragDropMode(QAbstractItemView::InternalMove);
ui->imgListWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
QObject::connect(ui->addImgBtn,SIGNAL(clicked(bool)),this,SLOT(onAddImg()));
QObject::connect(ui->allImgChk,SIGNAL(stateChanged(int)),this,SLOT(onSelectAll()));
QObject::connect(ui->delImgBtn,SIGNAL(clicked(bool)),this, SLOT(onDelItem()));
QObject::connect(ui->imgListWidget,SIGNAL(customContextMenuRequested(const QPoint &)),this,SLOT(onCustomContextMenuRequested(const QPoint &)));
QObject::connect(ui->imgListWidget,SIGNAL(itemSelectionChanged()),this,SLOT(itemSelectedCount()));
QObject::connect(ui->imgListWidget,SIGNAL(itemSelectionChanged()),this,SLOT(viewImg()));
QObject::connect(ui->imgListWidget,SIGNAL(itemClicked(QListWidgetItem*)),this,SLOT(viewImg()));
QObject::connect(ui->selPdfBtn,SIGNAL(clicked(bool)),this,SLOT(pdfFileName()));
QObject::connect(ui->creatPdfBtn,SIGNAL(clicked(bool)),this,SLOT(creatPdf()));
QObject::connect(ui->aboutBtn,SIGNAL(clicked(bool)),this,SLOT(openAbout()));
this->setAcceptDrops(true); //必须设置,不然无法接收拖放事件
ui->imgListWidget->setContextMenuPolicy(Qt::CustomContextMenu);
ui->outputTxt->setFocusPolicy(Qt::NoFocus);
ui->imgInforLabel->setVisible(false);
ui->hideLabel->setVisible(false);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::onAddImg()
{
QStringList FileNames = QFileDialog::getOpenFileNames(this, QStringLiteral("选择图片文件!"), QStandardPaths::writableLocation(QStandardPaths::PicturesLocation),QStringLiteral("图片文件(*.png *.jpg *.bmp)"));
int index=0,count=0;
count = FileNames.count();
for(index=0;index<=count-1;index++)
{
QListWidgetItem *item = new QListWidgetItem;
item->setSizeHint(QSize(0,24));
item->setText(QFileInfo(FileNames.at(index)).fileName());
QString suf = QFileInfo(FileNames.at(index)).suffix();
if(suf == "jpg" || suf == "JPG")
{
item->setIcon(QIcon(":/icon/jpg.png"));
}
if(suf == "png" || suf == "PNG")
{
item->setIcon(QIcon(":/icon/png.png"));
}
if(suf == "bmp" || suf == "BMP")
{
item->setIcon(QIcon(":/icon/bmp.png"));
}
ui->imgListWidget->addItem(item);
item->setData(Qt::UserRole,QFileInfo(FileNames.at(index)).absoluteFilePath());
}
int itemCount = ui->imgListWidget->count();
ui->countLabel->setText("图片数量:" + QString::number(itemCount));
if(itemCount ==0){
ui->imgInforLabel->setVisible(false);
}
}
void MainWindow::onSelectAll()
{
if(ui->allImgChk->isChecked())
{
ui->imgListWidget->selectAll();
}
else{
ui->imgListWidget->clearSelection();
}
}
//图片项右键
void MainWindow::onCustomContextMenuRequested(const QPoint &pos)
{
QListWidgetItem* curItem = ui->imgListWidget->itemAt(pos);
if( curItem == NULL )
return;
QIcon icon1 = QIcon(":/icon/up.png");
QIcon icon2 = QIcon(":/icon/down.png");
QIcon icon3 = QIcon(":/icon/delete.png");
QMenu *popMenu = new QMenu(ui->imgListWidget);
QAction *Menu1 = new QAction(icon1,"上移");
QAction *Menu2 = new QAction(icon2,"下移");
QAction *Menu3 = new QAction(icon3,"删除");
popMenu->addAction(Menu1);
popMenu->addAction(Menu2);
popMenu->addAction(Menu3);
connect(Menu1, SIGNAL(triggered(bool)), this, SLOT(itemUp()));
connect(Menu2, SIGNAL(triggered(bool)), this, SLOT(itemDown()));
connect(Menu3, SIGNAL(triggered(bool)), this, SLOT(onDelItem()));
popMenu->exec( QCursor::pos());
}
//删除选中
void MainWindow::onDelItem()
{
QList<QListWidgetItem*> list = ui->imgListWidget->selectedItems();
if(list.size() == 0)
return;
for(int i=0;i<list.count();i++){
QListWidgetItem *sel = list[i];
if(sel){
if(ui->hideLabel->text() == sel->data(Qt::UserRole).toString()){
ui->showImgLabel->clear();
ui->imgInforLabel->setText("");
ui->imgInforLabel->setVisible(false);
}
ui->imgListWidget->removeItemWidget(sel);
delete sel;
}
}
int itemCount = ui->imgListWidget->count();
ui->countLabel->setText("图片数量:" + QString::number(itemCount));
if(itemCount ==0){
ui->imgInforLabel->setVisible(false);
}
}
void MainWindow::itemUp()
{
QList<QListWidgetItem*> list = ui->imgListWidget->selectedItems();
if(list.size() == 0)
return;
for(int i=0;i<list.count();i++){
QListWidgetItem *sel = list[i];
if (sel)
{
ui->imgListWidget->setCurrentItem(sel);
int currentRow = ui->imgListWidget->currentRow();
if (currentRow == -1)
return;
int arriveRow = currentRow - 1 < 0 ? 0 : currentRow - 1;
ui->imgListWidget->insertItem(std::min(currentRow, arriveRow), ui->imgListWidget->takeItem(std::max(currentRow, arriveRow)));
ui->imgListWidget->setCurrentRow(arriveRow);
}
}
ui->imgListWidget->setCurrentItem(NULL);
}
void MainWindow::itemDown()
{
QList<QListWidgetItem*> list = ui->imgListWidget->selectedItems();
if(list.size() == 0)
return;
for(int i=0;i<list.count();i++){
QListWidgetItem *sel = list[i];
if (sel)
{
ui->imgListWidget->setCurrentItem(sel);
int currentRow = ui->imgListWidget->currentRow();
if (currentRow == -1)
return;
int arriveRow = currentRow + 1 >= ui->imgListWidget->count() ? ui->imgListWidget->count() - 1 : currentRow + 1;
ui->imgListWidget->insertItem(std::min(currentRow, arriveRow), ui->imgListWidget->takeItem(std::max(currentRow, arriveRow)));
ui->imgListWidget->setCurrentRow(arriveRow);
}
}
ui->imgListWidget->setCurrentItem(NULL);
}
//当图片被全选后设置全选复选框的状态
void MainWindow::itemSelectedCount()
{
QList<QListWidgetItem*> list = ui->imgListWidget->selectedItems();
int itemCount = ui->imgListWidget->count();
if(list.size() == itemCount){
ui->allImgChk->setChecked(true);
}
else{
ui->allImgChk->setChecked(false);
}
}
//拖动文件到窗口,触发
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
if(event->mimeData()->hasUrls())
{
event->acceptProposedAction(); //事件数据中存在路径,方向事件
}
else
{
event->ignore();
}
}
//拖动文件到窗口释放文件,触发
void MainWindow::dropEvent(QDropEvent *event)
{
const QMimeData *mimeData = event->mimeData();
if(mimeData->hasUrls())
{
QList<QUrl> urls = mimeData->urls();
for(int i=0;i<urls.count();i++)
{
QListWidgetItem *item = new QListWidgetItem;
item->setSizeHint(QSize(0,24));
QString fileName = urls.at(i).toLocalFile();
QFileInfo fileinfo = QFileInfo(fileName);
item->setText(fileinfo.fileName());
QString suf = fileinfo.suffix();
if(suf == "jpg" || suf == "JPG")
{
item->setIcon(QIcon(":/icon/jpg.png"));
ui->imgListWidget->addItem(item);
item->setData(Qt::UserRole,fileName);
}
if(suf == "png" || suf == "PNG")
{
item->setIcon(QIcon(":/icon/png.png"));
ui->imgListWidget->addItem(item);
item->setData(Qt::UserRole,fileName);
}
if(suf == "bmp" || suf=="BMP")
{
item->setIcon(QIcon(":/icon/bmp.png"));
ui->imgListWidget->addItem(item);
item->setData(Qt::UserRole,fileName);
}
}
}
int itemCount = ui->imgListWidget->count();
ui->countLabel->setText("图片数量:" + QString::number(itemCount));
if(itemCount ==0){
ui->imgInforLabel->setVisible(false);
}
}
//图片预览
void MainWindow::viewImg()
{
ui->showImgLabel->clear();
ui->imgInforLabel->setText("");
ui->imgInforLabel->setVisible(false);
QList<QListWidgetItem*> list = ui->imgListWidget->selectedItems();
int selectCount = list.size();
int itemCount = ui->imgListWidget->count();
if(selectCount == 0 || itemCount == 0)
return;
QListWidgetItem *currentItem = list[0];
QString imgFullName = currentItem->data(Qt::UserRole).toString();
QImage *img = new QImage();
if(!img->load(imgFullName)){
ui->showImgLabel->setText("预览失败");
}
ui->imgInforLabel->setVisible(true);
QString imgInfor = "水平:"+QString::number(img->width())+"像素,宽度:"+QString::number(img->widthMM()/10)+"cm 垂直:"+QString::number(img->height())+"像素,高度: "+QString::number(img->heightMM()/10)+"cm" ;
ui->imgInforLabel->setText(imgInfor);
ui->hideLabel->setText(imgFullName);
float sw = 420.0/img->width();
float sh = 390.0/img->height();
float scal =(sw>=1 && sh>=1)?1.0:sw>sh?sh:sw;
QImage* imgScaled = new QImage;
*imgScaled = img->scaled(img->width()*scal,img->height()*scal,Qt::KeepAspectRatio,Qt::SmoothTransformation);
ui->showImgLabel->setPixmap(QPixmap::fromImage(*imgScaled));
delete img;
delete imgScaled;
}
void MainWindow::pdfFileName()
{
QString fileName = QFileDialog::getSaveFileName(this,QStringLiteral("文件保存为"),QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation),QStringLiteral("*.pdf"));
ui->outputTxt->setText(fileName);
}
void MainWindow::creatPdf()
{
//纸张选择
int paperIndex = ui->paperSizeCbox->currentIndex();
//是否纸张横向
bool isPaperLayout = ui->paperLayoutChk->isChecked();
//是否双面
bool isDoublePrint = ui->doublePrintChk->isChecked();
//内容是否水平居中
bool isHorizonCenter = ui->horizonChk->isChecked();
//内容是否垂直居中
bool isVerticalCenter = ui->verticalChk->isChecked();
//图片自动缩放
bool isAutoScal = ui->autoScalChk->isChecked();
//上边距
float topMargin = ui->topSpinBox->value()*10;
//下边距
float bottomMargin = ui->bottomSpinBox->value()*10;
//左边距
float leftMargin = ui->leftSpinBox->value()*10;
//右边距
float rightMargin = ui->rightSpinBox->value()*10;
//pdf输出路径
QString pdfpath = ui->outputTxt->text();
//生成后是否打开,默认为true
bool isView = ui->viewPdfChk->isChecked();
QFile pdfFile(pdfpath);
pdfFile.open(QIODevice::WriteOnly);
QPdfWriter *pWriter = new QPdfWriter(&pdfFile);
pWriter->setResolution(300);
pWriter->setPageMargins(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin),QPageLayout::Millimeter);
//定义纸张大小,像素
int pageSizeWidth = 0;
int pageSizeHeight = 0;
//定义图像大小,像素
int imgSizeWidth = 0;
int imgSizeHeight = 0;
//定义图像可用区域大小
int areaWidht = 0;
int areaHeight = 0;
//纸张大小
switch(paperIndex)
{
case 0:
pWriter->setPageSize(QPagedPaintDevice::Custom);
pageSizeWidth = isPaperLayout?3508:2479;
pageSizeHeight = isPaperLayout?2479:3508;
break;
case 1:
pWriter->setPageSize(QPagedPaintDevice::Custom);
pageSizeWidth = isPaperLayout?3071:2185;
pageSizeHeight = isPaperLayout?2185:3071;
break;
}
//是否横向
if(isPaperLayout){
pWriter->setPageOrientation(QPageLayout::Landscape);
}
else{
pWriter->setPageOrientation(QPageLayout::Portrait);
}
//可用图像区域大小
areaWidht = pageSizeWidth - (leftMargin+rightMargin)/25.4*300;
areaHeight = pageSizeHeight - (topMargin+bottomMargin)/25.4*300;
QMessageBox msgBox;
msgBox.setWindowTitle("操作提示");
//判断图像数量是否为0
int itemCount = ui->imgListWidget->count();
if(itemCount == 0){
msgBox.setInformativeText("请添加用于生成PDF文件的图像!");
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.setButtonText(QMessageBox::Ok, QStringLiteral("确定"));
msgBox.setButtonText(QMessageBox::Cancel, QStringLiteral("取消"));
int reply = msgBox.exec();
if(reply == QMessageBox::Ok){
this->onAddImg();
return;
}
return;
}
//判断文件保存路径是否为空
if(ui->outputTxt->text().isEmpty()){
msgBox.setInformativeText("请设置PDF文件保存路径!");
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.setButtonText(QMessageBox::Ok, QStringLiteral("确定"));
msgBox.setButtonText(QMessageBox::Cancel, QStringLiteral("取消"));
int reply = msgBox.exec();
if(reply == QMessageBox::Ok)
{
this->pdfFileName();
return;
}
}
QPainter *pPainter = new QPainter(pWriter);
QProgressBar *pProgressBar = new QProgressBar(this);
pProgressBar->setOrientation(Qt::Horizontal); // 水平方向
pProgressBar->setMinimum(1); // 最小值
pProgressBar->setMaximum(100); // 最大值
pProgressBar->setMaximumHeight(15);
pProgressBar->setMinimumWidth(60);
pProgressBar->setVisible(true);
ui->statusbar->addPermanentWidget(pProgressBar,1);
for(int i = 0; i<itemCount;i++)
{
if(i>0){
if(isDoublePrint){
float tmp;
tmp = leftMargin;
leftMargin = rightMargin;
rightMargin = tmp;
}
pWriter->setPageMargins(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin),QPageLayout::Millimeter);
pWriter->newPage();
}
QString imgFullName = ui->imgListWidget->item(i)->data(Qt::UserRole).toString();
QImage *image = new QImage;
image->load(imgFullName);
imgSizeWidth = image->width(); //获取图片宽度,像素
imgSizeHeight = image->height(); //获取图片高度,像素
////////////////////////////////////////////////////////////////////////////////////////
if(isAutoScal && imgSizeWidth < areaWidht && imgSizeHeight < areaHeight){
float sW = (float)areaWidht/imgSizeWidth;
float sH = (float)areaHeight/imgSizeHeight;
float scal = (sW < sH) ? sW : sH;
*image = image->scaled((int)(imgSizeWidth*scal),(int)(imgSizeHeight*scal),Qt::KeepAspectRatio,Qt::SmoothTransformation);
imgSizeWidth = image->width(); //获取图片宽度,像素
imgSizeHeight = image->height(); //获取图片高度,像素
}
//////////////////////////////////////////////////////////////////////////////////////////
if(imgSizeWidth > areaWidht || imgSizeHeight > areaHeight){
float sw = (float)areaWidht/imgSizeWidth;
float sh = (float)areaHeight/imgSizeHeight;
float scal =(sw>=1.0 && sh>=1.0)?1.0:sw>sh?sh:sw;
*image = image->scaled((int)(imgSizeWidth*scal),(int)(imgSizeHeight*scal),Qt::KeepAspectRatio,Qt::SmoothTransformation);
imgSizeWidth = image->width(); //获取图片宽度,像素
imgSizeHeight = image->height(); //获取图片高度,像素
}
int top = 0;
int left = 0;
if(isHorizonCenter && imgSizeWidth<areaWidht){
left = (int)(areaWidht-imgSizeWidth)/2;
}
if(isVerticalCenter && imgSizeHeight<areaHeight){
top = (areaHeight-imgSizeHeight)/2;
}
pPainter->drawImage(QRect(left, top, image->width(), image->height()),*image);
pProgressBar->setValue(i);
delete image;
}
pProgressBar->setVisible(false);
pPainter->end();
delete pProgressBar;
delete pPainter;
delete pWriter;
pdfFile.close();
if(isView){
QDesktopServices::openUrl(QUrl::fromLocalFile(pdfpath));
}
}
void MainWindow::openAbout()
{
about *a = new about(this);
a->setModal(false);
a->show();
}mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "about.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void dragEnterEvent(QDragEnterEvent*event) Q_DECL_OVERRIDE;
void dropEvent(QDropEvent *event) Q_DECL_OVERRIDE;
private slots:
void onAddImg();
void onSelectAll();
void onCustomContextMenuRequested(const QPoint &);
void onDelItem();
void itemUp();
void itemDown();
void itemSelectedCount();
void viewImg();
void pdfFileName();
void creatPdf();
void openAbout();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H目录 返回
首页