第三代软件开发-保存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_ELEMENTQ_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_PRINTERQPrintDialog *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;
#endifGrabMode 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_PRINTERQ_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)
#endifpublic:XXXX_Print(QQuickItem *parent = 0);~XXXX_Print();#ifndef QT_NO_PRINTERtypedef 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)
#endifpublic slots:
#ifndef QT_NO_PRINTERbool print(QJSValue callback=QJSValue());bool setup(bool bDialogue = false);bool open();bool close();bool newPage() const;bool abort();
#endifbool 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_PRINTERvoid 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);
#endifQQuickItem *getItem() const { return m_item; }
#ifndef QT_NO_PRINTERQString 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;
#endifprivate 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_PRINTERvoid filePathChanged();void monochromeChanged();void antialiasChanged();void marginsChanged();void printerNameChanged();void resolutionChanged();void copyCountChanged();
#endifvoid 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_PRINTERm_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();
#endifm_mode = XXXX_Print::GrabOnly;m_item = NULL;m_fileDest.clear();m_fileType.clear();m_fileQuality = 0;
}XXXX_Print::~XXXX_Print()
{
#ifndef QT_NO_PRINTERdelete 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); //设置输出格式为pdfreturn 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();
}
#endifvoid 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;
}
#endifbool 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) );elsem_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);}
}
#endifvoid 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_PRINTERelse if( m_mode == XXXX_Print::Print ){ret = printGrab(img);if( m_callback.isCallable() ){QJSValueList args;args << ret;m_callback.call(args);}}
#endifelse 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();elseemit printError();
}#ifndef QT_NO_PRINTER
QString XXXX_Print::getPrinterName() const
{return m_printer->printerName();
}
#endif
使用
XXX_Print {id: printPDFfilepath: pdfFilePathfileDest: "/" + UserProfile.userName + dateString +".pdf"antialias: falsemonochrome: falseonPrintComplete: console.log("Print complete.");onPrintError: console.log("Print error!");Component.onCompleted: scanPaperSizes();function scanPaperSizes(){printPDF.setPageSize( 'A4' );printPDF.setMargins(0,0,0,0)}}