第三代软件开发-保存PDF
文章目录
- 第三代软件开发-保存PDF
- 项目介绍
- 保存PDF
- 头文件
- 源文件
- 使用
关键字:
Qt
、
Qml
、
pdf
、
painter
、
打印
项目介绍
欢迎来到我们的 QML & C++ 项目!这个项目结合了 QML(Qt Meta-Object Language)和 C++ 的强大功能,旨在开发出色的用户界面和高性能的后端逻辑。
在项目中,我们利用 QML 的声明式语法和可视化设计能力创建出现代化的用户界面。通过直观的编码和可重用的组件,我们能够迅速开发出丰富多样的界面效果和动画效果。同时,我们利用 QML 强大的集成能力,轻松将 C++ 的底层逻辑和数据模型集成到前端界面中。
在后端方面,我们使用 C++ 编写高性能的算法、数据处理和计算逻辑。C++ 是一种强大的编程语言,能够提供卓越的性能和可扩展性。我们的团队致力于优化代码,减少资源消耗,以确保我们的项目在各种平台和设备上都能够高效运行。
无论您是对 QML 和 C++ 开发感兴趣,还是需要我们为您构建复杂的用户界面和后端逻辑,我们都随时准备为您提供支持。请随时联系我们,让我们一同打造现代化、高性能的 QML & C++ 项目!
重要说明☝
☀该专栏在第三代软开发更新完将涨价
保存PDF
这个其实如果是QWidget开发,那就很简单了,直接有现成的打印模块,但是QML下是没有的,这里就需要重新写一下,首先,还是需要我们使用Qt的打印模块,
QT += printsupport
这里需要说明一下,这个文件不是原创,是在GitHub上找到另一个,完了做了修改。
头文件
#ifndef XXXX_PRINT_H
#define XXXX_PRINT_H
#include <QObject>
#ifndef QT_NO_PRINTER
#include <QPrinter>
#include <QPrintDialog>
#endif
#include <QQuickItem>
#include <QJSValue>
#include <QDir>
class XXXX_Print : public QQuickItem
{
Q_OBJECT
// QML_ELEMENT
Q_DISABLE_COPY(XXXX_Print)
public:
typedef enum { Print, PrintToFile, GrabOnly } GrabMode;
Q_ENUMS(GrabMode);
private:
QSharedPointer<QQuickItemGrabResult> m_result;
// 打印的qml组件
QQuickItem *m_item;
#ifndef QT_NO_PRINTER
QPrintDialog *m_printDialogue;
QPrinter *m_printer;
bool m_pagePrinted;
bool m_sessionOpen;
// 指定调用“print()”将产生多少份副本
int m_copyCount;
QPainter *m_painter;
// 启用或禁用抗锯齿
bool m_antialias;
// 启用或禁用单色打印(例如,热敏打印机)
bool m_monochrome;
// 选择“打印到文件”时要打印到的文件路径(在某些平台上)
QString m_filepath;
QRectF m_margins;
#endif
GrabMode m_mode;
QString m_fileDest;
QString m_fileType;
int m_fileQuality;
QJSValue m_callback;
Q_PROPERTY(QQuickItem* item READ getItem WRITE setItem NOTIFY itemChanged)
#ifndef QT_NO_PRINTER
Q_PROPERTY(QString filepath READ getFilePath WRITE setFilePath NOTIFY filePathChanged)
Q_PROPERTY(QString fileDest READ fileDest WRITE setFileDest NOTIFY fileDestChanged)
Q_PROPERTY(bool antialias READ getAntialias WRITE setAntialias NOTIFY antialiasChanged)
Q_PROPERTY(bool monochrome READ getMonochrome WRITE setMonochrome NOTIFY monochromeChanged)
// 打印的 dpi 整数分辨率
Q_PROPERTY(int resolution READ getResolution WRITE setResolution NOTIFY resolutionChanged)
Q_PROPERTY(int copyCount READ getCopyCount WRITE setCopyCount NOTIFY copyCountChanged)
// QRectF 对象,表示以设备像素为单位的页面尺寸
Q_PROPERTY(QRectF pageRect READ getPageRect NOTIFY sizeChanged)
Q_PROPERTY(QRectF paperRect READ getPaperRect NOTIFY sizeChanged)
Q_PROPERTY(QStringList paperSizes READ getPaperSizes)
Q_PROPERTY(QString printerName READ getPrinterName WRITE setPrinterName NOTIFY printerNameChanged)
Q_PROPERTY(Status status READ getStatus)
#endif
public:
XXXX_Print(QQuickItem *parent = 0);
~XXXX_Print();
#ifndef QT_NO_PRINTER
typedef enum {
Millimeter = QPageSize::Millimeter,
Point = QPageSize::Point,
Inch = QPageSize::Inch,
Pica = QPageSize::Pica,
Didot = QPageSize::Didot,
Cicero = QPageSize::Cicero,
DevicePixel
} Unit;
Q_ENUMS(Unit)
typedef enum {
Idle = QPrinter::Idle,
Active = QPrinter::Active,
Aborted = QPrinter::Aborted,
Error = QPrinter::Error,
Unknown
} Status;
Q_ENUMS(Status)
#endif
public slots:
#ifndef QT_NO_PRINTER
bool print(QJSValue callback=QJSValue());
bool setup(bool bDialogue = false);
bool open();
bool close();
bool newPage() const;
bool abort();
#endif
bool grabImage(const QString &fileFormat, int quality=100, QJSValue callback=QJSValue());
bool saveImage(const QString &fileName, const QString &fileFormat, int quality, QJSValue callback=QJSValue());
// Property Hooks:
void setItem( QQuickItem *item );
#ifndef QT_NO_PRINTER
void setFilePath(const QString &filepath);
void setFileDest(const QString &newFileDest);
void setMonochrome(bool toggle);
void setAntialias(bool toggle);
void setMargins(double top, double right, double bottom, double left);
bool setPageSize( qreal width, qreal height, Unit unit );
bool setPageSize( const QString &paperSize );
void setPrinterName(const QString &printerName);
void setResolution(int dpi);
void setCopyCount(int count);
#endif
QQuickItem *getItem() const { return m_item; }
#ifndef QT_NO_PRINTER
QString getFilePath() const { return m_filepath; }
const QString fileDest() const { return m_fileDest; };
bool getMonochrome() const { return m_monochrome; }
bool getAntialias() const { return m_antialias; }
QRectF getMargins() const { return m_margins; }
QRectF getPageRect(Unit unit=DevicePixel) const;
QRectF getPaperRect(Unit unit=DevicePixel) const;
QStringList getPaperSizes() const;
QString getPrinterName() const;
int getResolution() const { return m_printer->resolution(); }
int getCopyCount() const { return m_printer->copyCount(); }
Status getStatus() const;
#endif
private slots:
bool grab();
void grabbed();
private:
bool printGrab(const QImage &img);
bool isDirExist(QString fullPath);
signals:
void itemChanged();
void frameGrabbed(const QByteArray &imageData);
void sizeChanged();
void printComplete();
void printError();
#ifndef QT_NO_PRINTER
void filePathChanged();
void monochromeChanged();
void antialiasChanged();
void marginsChanged();
void printerNameChanged();
void resolutionChanged();
void copyCountChanged();
#endif
void fileDestChanged();
void strTestChanged();
};
#endif // XXXX_PRINT_H
源文件
#include "XXXX_print.h"
#include <QBuffer>
#include <QFileInfo>
#include <QPainter>
#ifndef QT_NO_PRINTER
# include <QPrintEngine>
#endif
#include <QQuickItemGrabResult>
// Just for converting QByteArray:
#include <QQmlEngine>
void XXXX_Print::setFileDest(const QString &newFileDest)
{
if (m_fileDest == newFileDest)
return;
m_fileDest = newFileDest;
emit fileDestChanged();
}
XXXX_Print::XXXX_Print(QQuickItem *parent):
QQuickItem(parent)
{
#ifndef QT_NO_PRINTER
m_printDialogue = nullptr;
m_printer = new QPrinter(QPrinter::ScreenResolution);
m_pagePrinted = false;
m_sessionOpen = false;
m_copyCount = 1;
m_painter = nullptr;
m_antialias = true;
m_monochrome = false;
m_margins = QRectF(0, 0, 0, 0);
m_filepath.clear();
#endif
m_mode = XXXX_Print::GrabOnly;
m_item = NULL;
m_fileDest.clear();
m_fileType.clear();
m_fileQuality = 0;
}
XXXX_Print::~XXXX_Print()
{
#ifndef QT_NO_PRINTER
delete m_printer;
#endif
}
#ifndef QT_NO_PRINTER
/**
* @brief XXXX_Print::print 打印/保存PDF(打印 setup至true)
* @param callback
* @return
*/
bool XXXX_Print::print(QJSValue callback)
{
m_mode = XXXX_Print::Print;
m_callback = callback;
return grab();
}
#endif
/**
* @brief XXXX_Print::grabImage 图片以QByteArray存储
* @param fileFormat
* @param quality
* @param callback
* @return
*/
bool XXXX_Print::grabImage(const QString &fileFormat, int quality, QJSValue callback)
{
m_mode = XXXX_Print::GrabOnly;
m_callback = callback;
m_fileType = fileFormat;
m_fileQuality = quality;
return grab();
}
/**
* @brief XXXX_Print::saveImage 保存图片,不用打开
* @param fileName 图片名称
* @param fileFormat 图片类型
* @param quality 图片像素-1 0-100
* @param callback
* @return
*/
bool XXXX_Print::saveImage(const QString &fileName, const QString &fileFormat, int quality, QJSValue callback)
{
m_mode = XXXX_Print::PrintToFile;
m_callback = callback;
m_fileDest = fileName;
m_fileType = fileFormat;
m_fileQuality = quality;
return grab();
}
#ifndef QT_NO_PRINTER
/**
* @brief XXXX_Print::setup 初始化打印机(true)/存储PDF(false)
* @param bDialogue
* @return
*/
bool XXXX_Print::setup(bool bDialogue)
{
m_printer->setOutputFormat(QPrinter::NativeFormat);
QMarginsF margins( 0.0, 0.0, 0.0, 0.0);
if( !m_printer->setPageMargins( margins, QPageLayout::Millimeter ) )
{
qWarning() << tr("Printer: Failed to set page margin (in mm) as configured.");
return false;
}
QString strFilePath = QCoreApplication::applicationDirPath();
m_printer->setOutputFileName(m_filepath + m_fileDest); //设置输出路径
if(bDialogue)
{
m_printDialogue = new QPrintDialog(m_printer);
if( m_printDialogue->exec() == QDialog::Accepted )
{
m_printDialogue->deleteLater();
return true;
}
qWarning() << "打印机初始化失败";
delete m_printDialogue;
}
else
{
// HP LaserJet Pro M428f-M429f [453773]
m_printer->setOutputFormat(QPrinter::PdfFormat); //设置输出格式为pdf
return true;
}
return false;
}
/**
* @brief XXXX_Print::open 打开打印机/存储
* @return
*/
bool XXXX_Print::open()
{
if( m_sessionOpen )
{
qCritical() << tr("Printer::open called while already in a multipage session. (Call 'close' first.)");
return false;
}
m_painter = new QPainter();
if( !m_painter )
{
qCritical() << tr("Printer::open failed to instantiate new QPainter. (Are you out of memory?)");
return false;
}
if(!m_painter->begin(m_printer))
{
qCritical() << tr("Failed to initialise QPainter to QPrintDevice.");
return false;
}
m_painter->setRenderHint(QPainter::Antialiasing, m_antialias);
m_painter->setRenderHint(QPainter::TextAntialiasing, m_antialias);
m_painter->setRenderHint(QPainter::SmoothPixmapTransform, m_antialias);
m_sessionOpen = true;
return true;
}
/**
* @brief XXXX_Print::close 关闭打印机/存储
* @return
*/
bool XXXX_Print::close()
{
if( !m_sessionOpen )
{
qCritical() << tr("Printer::close called while not in multipage session.");
return false;
}
delete m_painter;
m_painter = nullptr;
m_sessionOpen = false;
return true;
}
/**
* @brief XXXX_Print::newPage 下一页
* @return
*/
bool XXXX_Print::newPage() const
{
if( !m_sessionOpen )
{
qCritical() << tr("Printer::newPage called while not in a multipage session. (Call Printer::open first.)");
return false;
}
return m_printer->newPage();
}
/**
* @brief XXXX_Print::abort 中止打印机
* @return
*/
bool XXXX_Print::abort()
{
if( m_sessionOpen )
close();
return m_printer->abort();
}
void XXXX_Print::setMonochrome(bool toggle)
{
if( m_monochrome == toggle )
return;
m_monochrome = toggle;
emit monochromeChanged();
}
void XXXX_Print::setAntialias(bool toggle)
{
if( m_antialias == toggle )
return;
m_antialias = toggle;
emit antialiasChanged();
}
void XXXX_Print::setFilePath(const QString &filepath)
{
if( m_filepath == filepath )
return;
isDirExist(filepath);
m_filepath = filepath;
emit filePathChanged();
}
#endif
void XXXX_Print::setItem(QQuickItem *item)
{
if( m_item == item )
return;
m_item = item;
emit itemChanged();
}
#ifndef QT_NO_PRINTER
void XXXX_Print::setMargins(double top, double right, double bottom, double left)
{
QRectF m( left, top, right-left, bottom-top );
if( m_margins == m )
return;
m_margins = m;
emit marginsChanged();
}
bool XXXX_Print::setPageSize( const QString &paperSize )
{
QPageSize size;
// Run through each..
for( int x=0; x < QPageSize::LastPageSize; x++ )
{
size = QPageSize((QPageSize::PageSizeId)x);
if( size.name() == paperSize )
{
bool result = m_printer->setPageSize( size );
emit sizeChanged();
return result;
}
}
qWarning() << tr("Unknown paper size: ") << paperSize << tr(" (Refer to 'paperSizes()' for valid options.)");
return false;
}
bool XXXX_Print::setPageSize( qreal width, qreal height, Unit unit )
{
QSizeF szf(width, height);
QPageSize size;
switch( unit )
{
case DevicePixel:
// Fanagle from DPI:
szf /= m_printer->resolution();
size = QPageSize(szf, QPageSize::Inch);
break;
default:
size = QPageSize(szf, (QPageSize::Unit)unit);
break;
}
bool result = m_printer->setPageSize(size);
emit sizeChanged();
return result;
}
void XXXX_Print::setPrinterName(const QString &printerName)
{
if( m_printer->printerName() == printerName )
return;
m_printer->setPrinterName( printerName );
emit printerNameChanged();
}
void XXXX_Print::setResolution(int dpi)
{
if( m_printer->resolution() == dpi )
return;
m_printer->setResolution( dpi );
emit resolutionChanged();
}
void XXXX_Print::setCopyCount(int count)
{
if( m_printer->copyCount() == count )
return;
m_printer->setCopyCount( count );
emit copyCountChanged();
}
QRectF XXXX_Print::getPageRect(Unit unit) const
{
return m_printer->pageRect( (QPrinter::Unit)unit );
}
QRectF XXXX_Print::getPaperRect(Unit unit) const
{
return m_printer->paperRect( (QPrinter::Unit)unit );
}
QStringList XXXX_Print::getPaperSizes() const
{
QStringList results;
QPageSize size;
// Run through each..
for( int x=0; x < QPageSize::LastPageSize; x++ )
{
size = QPageSize((QPageSize::PageSizeId)x);
results.append( size.name() );
}
return results;
}
XXXX_Print::Status XXXX_Print::getStatus() const
{
QPrinter::PrinterState state = m_printer->printEngine()->printerState();
return (XXXX_Print::Status)state;
}
#endif
bool XXXX_Print::grab()
{
if( !m_item )
{
qWarning() << tr("Printer::grab: No item source specified. (Set it with the 'item' property.)");
return false;
}
QSharedPointer<QQuickItemGrabResult> res = m_item->grabToImage();
if( !res )
{
qWarning() << tr("Printer::grab: Grab failed for some reason. (Is the item loaded and rendered?)");
return false;
}
connect( res.data(), SIGNAL(ready()), this, SLOT(grabbed()) );
m_result = res;
return true;
}
#ifndef QT_NO_PRINTER
bool XXXX_Print::printGrab(const QImage &img)
{
if( !m_sessionOpen )
{
qCritical() << tr("Printer: Attempt to print without first calling Printer::open(). (This behaviour changed in 1.2)");;
return false;
}
if( m_monochrome )
m_painter->drawImage( m_printer->paperRect(QPrinter::DevicePixel), img.convertToFormat(QImage::Format_Mono, Qt::MonoOnly | Qt::ThresholdDither) );
else
m_painter->drawImage( m_printer->paperRect(QPrinter::DevicePixel), img );
return true;
}
/**
* @brief XXXX_Print::isDirExist 判断文件夹是否存在,不存在则创建
* @param fullPath
* @return
*/
bool XXXX_Print::isDirExist(QString fullPath)
{
// QString strFilePath = QCoreApplication::applicationDirPath();
QDir dir(fullPath);
if(dir.exists())
{
return true;
}
else
{
return dir.mkdir(fullPath);
}
}
#endif
void XXXX_Print::grabbed()
{
const QImage img = m_result.data()->image();
m_result.clear();
QQmlEngine *jse = qmlEngine(this);
jse->collectGarbage();
bool ret = true;
if( m_mode == XXXX_Print::PrintToFile )
{
ret = img.save(m_fileDest, m_fileType.toStdString().c_str(), m_fileQuality);
if( m_callback.isCallable() )
{
QJSValueList args;
args << ret;
m_callback.call(args);
}
}
#ifndef QT_NO_PRINTER
else if( m_mode == XXXX_Print::Print )
{
ret = printGrab(img);
if( m_callback.isCallable() )
{
QJSValueList args;
args << ret;
m_callback.call(args);
}
}
#endif
else if( m_callback.isCallable() )
{
QImage image;
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
// 此函数将 QImage 写入给定设备
ret = img.save(&buffer, m_fileType.toStdString().c_str(), m_fileQuality);
buffer.close();
if( ret )
{
QJSValueList args;
args << jse->toScriptValue<QByteArray>(ba);
m_callback.call( args );
}
}
// m_callback = QJSValue();
if( ret )
emit printComplete();
else
emit printError();
}
#ifndef QT_NO_PRINTER
QString XXXX_Print::getPrinterName() const
{
return m_printer->printerName();
}
#endif
使用
XXX_Print {
id: printPDF
filepath: pdfFilePath
fileDest: "/" + UserProfile.userName + dateString +".pdf"
antialias: false
monochrome: false
onPrintComplete: console.log("Print complete.");
onPrintError: console.log("Print error!");
Component.onCompleted: scanPaperSizes();
function scanPaperSizes()
{
printPDF.setPageSize( 'A4' );
printPDF.setMargins(0,0,0,0)
}
}