From 6c32927f8cf226b8158dd25f4b92a6853dadb8b6 Mon Sep 17 00:00:00 2001 From: Tobias Koenig Date: Tue, 14 Feb 2017 10:11:19 +0100 Subject: Improve PDF/A-1b support in QPdfWriter Add new enum QPrinter::PdfVersion to switch QPdfWriter into PDF/A-1b mode. In that mode - meta data are embedded in XMP format - a color profile for sRGB is embedded and an OutputIntent defined - the ID key is added to the document trailer dictionary - a CIDSet entry is added to the font descriptor - transparency is removed from pens, brushes and images Change-Id: Ia8a24d83609b239e716aefc1ba05f07320dbd290 Reviewed-by: Lars Knoll --- src/3rdparty/icc/LICENSE.txt | 10 + src/3rdparty/icc/qt_attribution.json | 15 ++ src/3rdparty/icc/sRGB2014.icc | Bin 0 -> 3024 bytes src/gui/painting/painting.pri | 3 + src/gui/painting/qpagedpaintdevice.cpp | 12 ++ src/gui/painting/qpagedpaintdevice.h | 2 + src/gui/painting/qpdf.cpp | 288 ++++++++++++++++++++++++--- src/gui/painting/qpdf.qrc | 7 + src/gui/painting/qpdf_p.h | 11 + src/gui/painting/qpdfa_metadata.xml | 16 ++ src/gui/painting/qpdfwriter.cpp | 31 +++ src/gui/painting/qpdfwriter.h | 3 + src/printsupport/kernel/qprintengine_pdf.cpp | 4 +- src/printsupport/kernel/qprintengine_pdf_p.h | 2 +- src/printsupport/kernel/qprinter.cpp | 33 ++- src/printsupport/kernel/qprinter.h | 3 + src/printsupport/kernel/qprinter_p.h | 4 +- 17 files changed, 414 insertions(+), 30 deletions(-) create mode 100644 src/3rdparty/icc/LICENSE.txt create mode 100644 src/3rdparty/icc/qt_attribution.json create mode 100644 src/3rdparty/icc/sRGB2014.icc create mode 100644 src/gui/painting/qpdf.qrc create mode 100644 src/gui/painting/qpdfa_metadata.xml diff --git a/src/3rdparty/icc/LICENSE.txt b/src/3rdparty/icc/LICENSE.txt new file mode 100644 index 0000000000..e25b1d39f1 --- /dev/null +++ b/src/3rdparty/icc/LICENSE.txt @@ -0,0 +1,10 @@ +For the file sRGB2014.icc: + +Copyright International Color Consortium, 2015 + +This profile is made available by the International Color Consortium, and may be copied, +distributed, embedded, made, used, and sold without restriction. Altered versions of this +profile shall have the original identification and copyright information removed and +shall not be misrepresented as the original profile. + +(original source location: http://www.color.org/srgbprofiles.xalter) diff --git a/src/3rdparty/icc/qt_attribution.json b/src/3rdparty/icc/qt_attribution.json new file mode 100644 index 0000000000..7a1c813522 --- /dev/null +++ b/src/3rdparty/icc/qt_attribution.json @@ -0,0 +1,15 @@ +[ + { + "Id": "icc-sRGB-color-profile", + "Name": "sRGB color profile icc file", + "QDocModule": "qtgui", + "QtUsage": "Used in Qt Gui (Embedded into PDF/A-1b files generated by QPrinter/QPdfWriter).", + "Files": "sRGB2014.icc", + + "Description": "An ICC color profile for PDF/A-1b compatible PDF files.", + "LicenseId": "ICC License", + "License": "International Color Consortium License", + "LicenseFile": "LICENSE.txt", + "Copyright": "Copyright International Color Consortium, 2015" + } +] diff --git a/src/3rdparty/icc/sRGB2014.icc b/src/3rdparty/icc/sRGB2014.icc new file mode 100644 index 0000000000..49afbfef10 Binary files /dev/null and b/src/3rdparty/icc/sRGB2014.icc differ diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 63e345545c..9ff0b5f5e5 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -99,6 +99,9 @@ SOURCES += \ painting/qplatformbackingstore.cpp \ painting/qpathsimplifier.cpp +RESOURCES += \ + painting/qpdf.qrc + darwin { HEADERS += painting/qcoregraphics_p.h SOURCES += painting/qcoregraphics.mm diff --git a/src/gui/painting/qpagedpaintdevice.cpp b/src/gui/painting/qpagedpaintdevice.cpp index 22ec981134..372b9524ee 100644 --- a/src/gui/painting/qpagedpaintdevice.cpp +++ b/src/gui/painting/qpagedpaintdevice.cpp @@ -243,6 +243,18 @@ QPagedPaintDevicePrivate *QPagedPaintDevice::dd() Starts a new page. Returns \c true on success. */ +/*! + \enum QPagedPaintDevice::PdfVersion + + The PdfVersion enum describes the version of the PDF file that + is produced by QPrinter or QPdfWriter. + + \value PdfFormat_1_4 A PDF 1.4 compatible document is produced. + + \value PdfFormat_A1b A PDF/A-1b compatible document is produced. + + \since 5.10 +*/ /*! Sets the size of the a page to \a size. diff --git a/src/gui/painting/qpagedpaintdevice.h b/src/gui/painting/qpagedpaintdevice.h index c516f6a963..66dd6fa8cf 100644 --- a/src/gui/painting/qpagedpaintdevice.h +++ b/src/gui/painting/qpagedpaintdevice.h @@ -213,6 +213,8 @@ public: Envelope10 = Comm10E }; + enum PdfVersion { PdfVersion_1_4, PdfVersion_A1b }; + // ### Qt6 Make these virtual bool setPageLayout(const QPageLayout &pageLayout); bool setPageSize(const QPageSize &pageSize); diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index bac9740892..fdbc803174 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -42,16 +42,20 @@ #ifndef QT_NO_PDF #include "qplatformdefs.h" -#include -#include -#include + +#include #include #include -#include -#include "private/qfont_p.h" + +#include +#include +#include +#include +#include #include -#include "qbuffer.h" -#include "QtCore/qdatetime.h" +#include +#include +#include #ifndef QT_NO_COMPRESS #include @@ -79,6 +83,45 @@ inline QPaintEngine::PaintEngineFeatures qt_pdf_decide_features() return f; } +extern bool qt_isExtendedRadialGradient(const QBrush &brush); + +// helper function to remove transparency from brush in PDF/A-1b mode +static void removeTransparencyFromBrush(QBrush &brush) +{ + if (brush.style() == Qt::SolidPattern) { + QColor color = brush.color(); + if (color.alpha() != 255) { + color.setAlpha(255); + brush.setColor(color); + } + + return; + } + + if (qt_isExtendedRadialGradient(brush)) { + brush = QBrush(Qt::black); // the safest we can do so far... + return; + } + + if (brush.style() == Qt::LinearGradientPattern + || brush.style() == Qt::RadialGradientPattern + || brush.style() == Qt::ConicalGradientPattern) { + + QGradientStops stops = brush.gradient()->stops(); + for (int i = 0; i < stops.size(); ++i) { + if (stops[i].second.alpha() != 255) + stops[i].second.setAlpha(255); + } + + const_cast(brush.gradient())->setStops(stops); + return; + } + + if (brush.style() == Qt::TexturePattern) { + // handled inside QPdfEnginePrivate::addImage() already + return; + } +} /* also adds a space at the end of the number */ @@ -1042,7 +1085,22 @@ void QPdfEngine::updateState(const QPaintEngineState &state) d->stroker.matrix = state.transform(); if (flags & DirtyPen) { - d->pen = state.pen(); + if (d->pdfVersion == QPdfEngine::Version_A1b) { + QPen pen = state.pen(); + + QColor penColor = pen.color(); + if (penColor.alpha() != 255) + penColor.setAlpha(255); + pen.setColor(penColor); + + QBrush penBrush = pen.brush(); + removeTransparencyFromBrush(penBrush); + pen.setBrush(penBrush); + + d->pen = pen; + } else { + d->pen = state.pen(); + } d->hasPen = d->pen.style() != Qt::NoPen; d->stroker.setPen(d->pen, state.renderHints()); QBrush penBrush = d->pen.brush(); @@ -1054,7 +1112,13 @@ void QPdfEngine::updateState(const QPaintEngineState &state) d->stroker.setPen(d->pen, state.renderHints()); } if (flags & DirtyBrush) { - d->brush = state.brush(); + if (d->pdfVersion == QPdfEngine::Version_A1b) { + QBrush brush = state.brush(); + removeTransparencyFromBrush(brush); + d->brush = brush; + } else { + d->brush = state.brush(); + } if (d->brush.color().alpha() == 0 && d->brush.style() == Qt::SolidPattern) d->brush.setStyle(Qt::NoBrush); d->hasBrush = d->brush.style() != Qt::NoBrush; @@ -1286,6 +1350,12 @@ int QPdfEngine::resolution() const return d->resolution; } +void QPdfEngine::setPdfVersion(PdfVersion version) +{ + Q_D(QPdfEngine); + d->pdfVersion = version; +} + void QPdfEngine::setPageLayout(const QPageLayout &pageLayout) { Q_D(QPdfEngine); @@ -1364,6 +1434,7 @@ int QPdfEngine::metric(QPaintDevice::PaintDeviceMetric metricType) const QPdfEnginePrivate::QPdfEnginePrivate() : clipEnabled(false), allClipped(false), hasPen(true), hasBrush(false), simplePen(false), + pdfVersion(QPdfEngine::Version_1_4), outDevice(0), ownsDevice(false), embedFonts(true), grayscale(false), @@ -1469,13 +1540,34 @@ void QPdfEnginePrivate::writeHeader() writeInfo(); + int metaDataObj = -1; + int outputIntentObj = -1; + if (pdfVersion == QPdfEngine::Version_A1b) { + metaDataObj = writeXmpMetaData(); + outputIntentObj = writeOutputIntent(); + } + catalog = addXrefEntry(-1); pageRoot = requestObject(); - xprintf("<<\n" - "/Type /Catalog\n" - "/Pages %d 0 R\n" - ">>\n" - "endobj\n", pageRoot); + + // catalog + { + QByteArray catalog; + QPdf::ByteStream s(&catalog); + s << "<<\n" + << "/Type /Catalog\n" + << "/Pages " << pageRoot << "0 R\n"; + + if (pdfVersion == QPdfEngine::Version_A1b) { + s << "/OutputIntents [" << outputIntentObj << "0 R]\n"; + s << "/Metadata " << metaDataObj << "0 R\n"; + } + + s << ">>\n" + << "endobj\n"; + + write(catalog); + } // graphics state graphicsState = addXrefEntry(-1); @@ -1528,6 +1620,95 @@ void QPdfEnginePrivate::writeInfo() "endobj\n"); } +int QPdfEnginePrivate::writeXmpMetaData() +{ + const int metaDataObj = addXrefEntry(-1); + + const QString producer(QString::fromLatin1("Qt " QT_VERSION_STR)); + + const QDateTime now = QDateTime::currentDateTime(); + const QDate date = now.date(); + const QTime time = now.time(); + + QString timeStr; + timeStr.sprintf("%d-%02d-%02dT%02d:%02d:%02d", date.year(), date.month(), date.day(), + time.hour(), time.minute(), time.second()); + + const int offset = now.offsetFromUtc(); + const int hours = (offset / 60) / 60; + const int mins = (offset / 60) % 60; + QString tzStr; + if (offset < 0) + tzStr.sprintf("-%02d:%02d", -hours, -mins); + else if (offset > 0) + tzStr.sprintf("+%02d:%02d", hours , mins); + else + tzStr = QLatin1String("Z"); + + const QString metaDataDate = timeStr + tzStr; + + QFile metaDataFile(QLatin1String(":/qpdf/qpdfa_metadata.xml")); + metaDataFile.open(QIODevice::ReadOnly); + const QByteArray metaDataContent = QString::fromUtf8(metaDataFile.readAll()).arg(producer.toHtmlEscaped(), + title.toHtmlEscaped(), + creator.toHtmlEscaped(), + metaDataDate).toUtf8(); + xprintf("<<\n" + "/Type /Metadata /Subtype /XML\n" + "/Length %d\n" + ">>\n" + "stream\n", metaDataContent.size()); + write(metaDataContent); + xprintf("\nendstream\n" + "endobj\n"); + + return metaDataObj; +} + +int QPdfEnginePrivate::writeOutputIntent() +{ + const int colorProfile = addXrefEntry(-1); + { + QFile colorProfileFile(QLatin1String(":/qpdf/sRGB2014.icc")); + colorProfileFile.open(QIODevice::ReadOnly); + const QByteArray colorProfileData = colorProfileFile.readAll(); + + QByteArray data; + QPdf::ByteStream s(&data); + int length_object = requestObject(); + + s << "<<\n"; + s << "/N 3\n"; + s << "/Alternate /DeviceRGB\n"; + s << "/Length " << length_object << "0 R\n"; + s << "/Filter /FlateDecode\n"; + s << ">>\n"; + s << "stream\n"; + write(data); + const int len = writeCompressed(colorProfileData); + write("\nendstream\n" + "endobj\n"); + addXrefEntry(length_object); + xprintf("%d\n" + "endobj\n", len); + } + + const int outputIntent = addXrefEntry(-1); + { + xprintf("<<\n"); + xprintf("/Type /OutputIntent\n"); + xprintf("/S/GTS_PDFA1\n"); + xprintf("/OutputConditionIdentifier (sRGB_IEC61966-2-1_black_scaled)\n"); + xprintf("/DestOutputProfile %d 0 R\n", colorProfile); + xprintf("/Info(sRGB IEC61966 v2.1 with black scaling)\n"); + xprintf("/RegistryName(http://www.color.org)\n"); + xprintf(">>\n"); + xprintf("endobj\n"); + } + + return outputIntent; +} + void QPdfEnginePrivate::writePageRoot() { addXrefEntry(pageRoot); @@ -1569,6 +1750,7 @@ void QPdfEnginePrivate::embedFont(QFontSubset *font) int fontstream = requestObject(); int cidfont = requestObject(); int toUnicode = requestObject(); + int cidset = requestObject(); QFontEngine::Properties properties = font->fontEngine->properties(); QByteArray postscriptName = properties.postscriptName.replace(' ', '_'); @@ -1598,6 +1780,7 @@ void QPdfEnginePrivate::embedFont(QFontSubset *font) "/CapHeight " << properties.capHeight.toReal()*scale << "\n" "/StemV " << properties.lineWidth.toReal()*scale << "\n" "/FontFile2 " << fontstream << "0 R\n" + "/CIDSet " << cidset << "0 R\n" ">>\nendobj\n"; write(descriptor); } @@ -1660,6 +1843,29 @@ void QPdfEnginePrivate::embedFont(QFontSubset *font) "endobj\n"; write(font); } + { + QByteArray cidSetStream(font->nGlyphs() / 8 + 1, 0); + int byteCounter = 0; + int bitCounter = 0; + for (int i = 0; i < font->nGlyphs(); ++i) { + cidSetStream.data()[byteCounter] |= (1 << (7 - bitCounter)); + + bitCounter++; + if (bitCounter == 8) { + bitCounter = 0; + byteCounter++; + } + } + + addXrefEntry(cidset); + xprintf("<<\n"); + xprintf("/Length %d\n", cidSetStream.size()); + xprintf(">>\n"); + xprintf("stream\n"); + write(cidSetStream); + xprintf("\nendstream\n"); + xprintf("endobj\n"); + } } @@ -1769,15 +1975,28 @@ void QPdfEnginePrivate::writeTail() for (int i = 1; i < xrefPositions.size()-1; ++i) xprintf("%010d 00000 n \n", xrefPositions[i]); - xprintf("trailer\n" - "<<\n" - "/Size %d\n" - "/Info %d 0 R\n" - "/Root %d 0 R\n" - ">>\n" - "startxref\n%d\n" - "%%%%EOF\n", - xrefPositions.size()-1, info, catalog, xrefPositions.constLast()); + { + QByteArray trailer; + QPdf::ByteStream s(&trailer); + + s << "trailer\n" + << "<<\n" + << "/Size " << xrefPositions.size() - 1 << "\n" + << "/Info " << info << "0 R\n" + << "/Root " << catalog << "0 R\n"; + + if (pdfVersion == QPdfEngine::Version_A1b) { + const QString uniqueId = QUuid::createUuid().toString(); + const QByteArray fileIdentifier = QCryptographicHash::hash(uniqueId.toLatin1(), QCryptographicHash::Md5).toHex(); + s << "/ID [ <" << fileIdentifier << "> <" << fileIdentifier << "> ]\n"; + } + + s << ">>\n" + << "startxref\n" << xrefPositions.constLast() << "\n" + << "%%EOF\n"; + + write(trailer); + } } int QPdfEnginePrivate::addXrefEntry(int object, bool printostr) @@ -1983,7 +2202,7 @@ int QPdfEnginePrivate::writeImage(const QByteArray &data, int width, int height, xprintf(">>\nstream\n"); len = writeCompressed(data); } - xprintf("endstream\n" + xprintf("\nendstream\n" "endobj\n"); addXrefEntry(lenobj); xprintf("%d\n" @@ -2309,7 +2528,7 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QTransform &matrix, ">>\n" "stream\n" << content - << "endstream\n" + << "\nendstream\n" "endobj\n"; int softMaskFormObject = addXrefEntry(-1); @@ -2418,7 +2637,7 @@ int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor, ">>\n" "stream\n" << pattern - << "endstream\n" + << "\nendstream\n" "endobj\n"; int patternObj = addXrefEntry(-1); @@ -2449,6 +2668,23 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, qint64 serial_n QImage image = img; QImage::Format format = image.format(); + + if (pdfVersion == QPdfEngine::Version_A1b) { + if (image.hasAlphaChannel()) { + // transparent images are not allowed in PDF/A-1b, so we convert it to + // a format without alpha channel first + + QImage alphaLessImage(image.width(), image.height(), QImage::Format_RGB32); + alphaLessImage.fill(Qt::white); + + QPainter p(&alphaLessImage); + p.drawImage(0, 0, image); + + image = alphaLessImage; + format = image.format(); + } + } + if (image.depth() == 1 && *bitmap && is_monochrome(img.colorTable())) { if (format == QImage::Format_MonoLSB) image = image.convertToFormat(QImage::Format_Mono); diff --git a/src/gui/painting/qpdf.qrc b/src/gui/painting/qpdf.qrc new file mode 100644 index 0000000000..56359c775b --- /dev/null +++ b/src/gui/painting/qpdf.qrc @@ -0,0 +1,7 @@ + + + + qpdfa_metadata.xml + ../../3rdparty/icc/sRGB2014.icc + + diff --git a/src/gui/painting/qpdf_p.h b/src/gui/painting/qpdf_p.h index a6aa2940c8..f5bb4e17a8 100644 --- a/src/gui/painting/qpdf_p.h +++ b/src/gui/painting/qpdf_p.h @@ -168,6 +168,12 @@ class Q_GUI_EXPORT QPdfEngine : public QPaintEngine Q_DECLARE_PRIVATE(QPdfEngine) friend class QPdfWriter; public: + enum PdfVersion + { + Version_1_4, + Version_A1b + }; + QPdfEngine(); QPdfEngine(QPdfEnginePrivate &d); ~QPdfEngine() {} @@ -177,6 +183,8 @@ public: void setResolution(int resolution); int resolution() const; + void setPdfVersion(PdfVersion version); + // reimplementations QPaintEngine bool begin(QPaintDevice *pdev) Q_DECL_OVERRIDE; bool end() Q_DECL_OVERRIDE; @@ -258,6 +266,7 @@ public: bool hasBrush; bool simplePen; qreal opacity; + QPdfEngine::PdfVersion pdfVersion; QHash fonts; @@ -286,6 +295,8 @@ private: int createShadingFunction(const QGradient *gradient, int from, int to, bool reflect, bool alpha); void writeInfo(); + int writeXmpMetaData(); + int writeOutputIntent(); void writePageRoot(); void writeFonts(); void embedFont(QFontSubset *font); diff --git a/src/gui/painting/qpdfa_metadata.xml b/src/gui/painting/qpdfa_metadata.xml new file mode 100644 index 0000000000..5e5c57f1c6 --- /dev/null +++ b/src/gui/painting/qpdfa_metadata.xml @@ -0,0 +1,16 @@ + + + + + + + %2 + + + + + + + + + diff --git a/src/gui/painting/qpdfwriter.cpp b/src/gui/painting/qpdfwriter.cpp index edf2950a67..5af465edeb 100644 --- a/src/gui/painting/qpdfwriter.cpp +++ b/src/gui/painting/qpdfwriter.cpp @@ -56,6 +56,7 @@ public: { engine = new QPdfEngine(); output = 0; + pdfVersion = QPdfWriter::PdfVersion_1_4; } ~QPdfWriterPrivate() { @@ -65,6 +66,7 @@ public: QPdfEngine *engine; QFile *output; + QPdfWriter::PdfVersion pdfVersion; }; class QPdfPagedPaintDevicePrivate : public QPagedPaintDevicePrivate @@ -176,6 +178,35 @@ QPdfWriter::~QPdfWriter() } +/*! + \since 5.10 + + Sets the PDF version for this writer to \a version. + + If \a version is the same value as currently set then no change will be made. +*/ +void QPdfWriter::setPdfVersion(PdfVersion version) +{ + Q_D(QPdfWriter); + + if (d->pdfVersion == version) + return; + + d->pdfVersion = version; + d->engine->setPdfVersion(d->pdfVersion == QPdfWriter::PdfVersion_1_4 ? QPdfEngine::Version_1_4 : QPdfEngine::Version_A1b); +} + +/*! + \since 5.10 + + Returns the PDF version for this writer. The default is \c PdfVersion_1_4. +*/ +QPdfWriter::PdfVersion QPdfWriter::pdfVersion() const +{ + Q_D(const QPdfWriter); + return d->pdfVersion; +} + /*! Returns the title of the document. */ diff --git a/src/gui/painting/qpdfwriter.h b/src/gui/painting/qpdfwriter.h index 17c73dd480..b260805b2b 100644 --- a/src/gui/painting/qpdfwriter.h +++ b/src/gui/painting/qpdfwriter.h @@ -61,6 +61,9 @@ public: explicit QPdfWriter(QIODevice *device); ~QPdfWriter(); + void setPdfVersion(PdfVersion version); + PdfVersion pdfVersion() const; + QString title() const; void setTitle(const QString &title); diff --git a/src/printsupport/kernel/qprintengine_pdf.cpp b/src/printsupport/kernel/qprintengine_pdf.cpp index 278bb044e1..080ff7ccf4 100644 --- a/src/printsupport/kernel/qprintengine_pdf.cpp +++ b/src/printsupport/kernel/qprintengine_pdf.cpp @@ -58,10 +58,12 @@ QT_BEGIN_NAMESPACE -QPdfPrintEngine::QPdfPrintEngine(QPrinter::PrinterMode m) +QPdfPrintEngine::QPdfPrintEngine(QPrinter::PrinterMode m, QPdfEngine::PdfVersion version) : QPdfEngine(*new QPdfPrintEnginePrivate(m)) { state = QPrinter::Idle; + + setPdfVersion(version); } QPdfPrintEngine::QPdfPrintEngine(QPdfPrintEnginePrivate &p) diff --git a/src/printsupport/kernel/qprintengine_pdf_p.h b/src/printsupport/kernel/qprintengine_pdf_p.h index b964885bbf..e9e81bdf68 100644 --- a/src/printsupport/kernel/qprintengine_pdf_p.h +++ b/src/printsupport/kernel/qprintengine_pdf_p.h @@ -83,7 +83,7 @@ class Q_PRINTSUPPORT_EXPORT QPdfPrintEngine : public QPdfEngine, public QPrintEn { Q_DECLARE_PRIVATE(QPdfPrintEngine) public: - QPdfPrintEngine(QPrinter::PrinterMode m); + QPdfPrintEngine(QPrinter::PrinterMode m, QPdfEngine::PdfVersion version = QPdfEngine::Version_1_4); virtual ~QPdfPrintEngine(); // reimplementations QPaintEngine diff --git a/src/printsupport/kernel/qprinter.cpp b/src/printsupport/kernel/qprinter.cpp index 53bed87dfc..638187c614 100644 --- a/src/printsupport/kernel/qprinter.cpp +++ b/src/printsupport/kernel/qprinter.cpp @@ -147,7 +147,8 @@ void QPrinterPrivate::initEngines(QPrinter::OutputFormat format, const QPrinterI printEngine = ps->createNativePrintEngine(printerMode); paintEngine = ps->createPaintEngine(printEngine, printerMode); } else { - QPdfPrintEngine *pdfEngine = new QPdfPrintEngine(printerMode); + const auto pdfEngineVersion = (pdfVersion == QPrinter::PdfVersion_1_4 ? QPdfEngine::Version_1_4 : QPdfEngine::Version_A1b); + QPdfPrintEngine *pdfEngine = new QPdfPrintEngine(printerMode, pdfEngineVersion); paintEngine = pdfEngine; printEngine = pdfEngine; } @@ -685,7 +686,37 @@ QPrinter::OutputFormat QPrinter::outputFormat() const return d->outputFormat; } +/*! + \since 5.10 + + Sets the PDF version for this printer to \a version. + + If \a version is the same value as currently set then no change will be made. +*/ +void QPrinter::setPdfVersion(PdfVersion version) +{ + Q_D(QPrinter); + + if (d->pdfVersion == version) + return; + + d->pdfVersion = version; + if (d->outputFormat == QPrinter::PdfFormat) { + d->changeEngines(d->outputFormat, QPrinterInfo()); + } +} + +/*! + \since 5.10 + + Returns the PDF version for this printer. The default is \c PdfVersion_1_4. +*/ +QPrinter::PdfVersion QPrinter::pdfVersion() const +{ + Q_D(const QPrinter); + return d->pdfVersion; +} /*! \internal */ diff --git a/src/printsupport/kernel/qprinter.h b/src/printsupport/kernel/qprinter.h index 33a2d4dbc8..bfe2d346ae 100644 --- a/src/printsupport/kernel/qprinter.h +++ b/src/printsupport/kernel/qprinter.h @@ -134,6 +134,9 @@ public: void setOutputFormat(OutputFormat format); OutputFormat outputFormat() const; + void setPdfVersion(PdfVersion version); + PdfVersion pdfVersion() const; + void setPrinterName(const QString &); QString printerName() const; diff --git a/src/printsupport/kernel/qprinter_p.h b/src/printsupport/kernel/qprinter_p.h index 18dfad926c..8f962ea051 100644 --- a/src/printsupport/kernel/qprinter_p.h +++ b/src/printsupport/kernel/qprinter_p.h @@ -75,7 +75,8 @@ class Q_PRINTSUPPORT_EXPORT QPrinterPrivate Q_DECLARE_PUBLIC(QPrinter) public: QPrinterPrivate(QPrinter *printer) - : printEngine(0), + : pdfVersion(QPrinter::PdfVersion_1_4), + printEngine(0), paintEngine(0), realPrintEngine(0), realPaintEngine(0), @@ -107,6 +108,7 @@ public: QPrinter::PrinterMode printerMode; QPrinter::OutputFormat outputFormat; + QPrinter::PdfVersion pdfVersion; QPrintEngine *printEngine; QPaintEngine *paintEngine; -- cgit v1.2.3