044_第三代软件开发-保存PDF-LMLPHP

第三代软件开发-保存PDF


关键字: QtQmlpdfpainter打印

项目介绍

重要说明☝

☀该专栏在第三代软开发更新完将涨价

保存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)
        }

    }


044_第三代软件开发-保存PDF-LMLPHP
11-05 13:48