Extend PDF engine to allow the generation of PDFs with huge pages
Qt's PDF engine previously supported only the PDF v1.4 standard, which only allows pages of up to 200x200in (about 5x5m). This patch optionally enables the generation of PDF v1.6-compliant files that allow the redefinition of user space units, so that pages of up to 381x381km are now possible. By default, generated files are compliant to v1.4 spec. v1.6 compliance must be enabled by, e.g., calling QPrinter::setPdfVersion() with QPrinter::PdfVersion_1_6. PDF v1.6-compliant files require Adobe Reader 7.0 or newer (also worked with the built-in viewers in current versions of Chrome, Firefox and Edge). Task-number: QTBUG-69386 Change-Id: I21708e0d465d5d7d9e46ff06dd04acfe1dfb0858 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> Reviewed-by: Andy Shaw <andy.shaw@qt.io> Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
This commit is contained in:
parent
a87f85dbf9
commit
1bb8627f8f
@ -290,7 +290,8 @@ QPagedPaintDevicePrivate *QPagedPaintDevice::dd()
|
||||
|
||||
\value PdfVersion_A1b A PDF/A-1b compatible document is produced.
|
||||
|
||||
\since 5.10
|
||||
\value PdfVersion_1_6 A PDF 1.6 compatible document is produced.
|
||||
This value was added in Qt 5.12.
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
@ -213,7 +213,7 @@ public:
|
||||
Envelope10 = Comm10E
|
||||
};
|
||||
|
||||
enum PdfVersion { PdfVersion_1_4, PdfVersion_A1b };
|
||||
enum PdfVersion { PdfVersion_1_4, PdfVersion_A1b, PdfVersion_1_6 };
|
||||
|
||||
// ### Qt6 Make these virtual
|
||||
bool setPageLayout(const QPageLayout &pageLayout);
|
||||
|
@ -1547,7 +1547,14 @@ void QPdfEnginePrivate::writeHeader()
|
||||
{
|
||||
addXrefEntry(0,false);
|
||||
|
||||
xprintf("%%PDF-1.4\n");
|
||||
static const QHash<QPdfEngine::PdfVersion, const char *> mapping {
|
||||
{QPdfEngine::Version_1_4, "1.4"},
|
||||
{QPdfEngine::Version_A1b, "1.4"},
|
||||
{QPdfEngine::Version_1_6, "1.6"}
|
||||
};
|
||||
const char *verStr = mapping.value(pdfVersion, "1.4");
|
||||
|
||||
xprintf("%%PDF-%s\n", verStr);
|
||||
xprintf("%%\303\242\303\243\n");
|
||||
|
||||
writeInfo();
|
||||
@ -1880,6 +1887,19 @@ void QPdfEnginePrivate::embedFont(QFontSubset *font)
|
||||
}
|
||||
}
|
||||
|
||||
qreal QPdfEnginePrivate::calcUserUnit() const
|
||||
{
|
||||
// PDF standards < 1.6 support max 200x200in pages (no UserUnit)
|
||||
if (pdfVersion < QPdfEngine::Version_1_6)
|
||||
return 1.0;
|
||||
|
||||
const int maxLen = qMax(currentPage->pageSize.width(), currentPage->pageSize.height());
|
||||
if (maxLen <= 14400)
|
||||
return 1.0; // for pages up to 200x200in (14400x14400 units) use default scaling
|
||||
|
||||
// for larger pages, rescale units so we can have up to 381x381km
|
||||
return qMin(maxLen / 14400.0, 75000.0);
|
||||
}
|
||||
|
||||
void QPdfEnginePrivate::writeFonts()
|
||||
{
|
||||
@ -1902,6 +1922,8 @@ void QPdfEnginePrivate::writePage()
|
||||
uint resources = requestObject();
|
||||
uint annots = requestObject();
|
||||
|
||||
qreal userUnit = calcUserUnit();
|
||||
|
||||
addXrefEntry(pages.constLast());
|
||||
xprintf("<<\n"
|
||||
"/Type /Page\n"
|
||||
@ -1909,12 +1931,16 @@ void QPdfEnginePrivate::writePage()
|
||||
"/Contents %d 0 R\n"
|
||||
"/Resources %d 0 R\n"
|
||||
"/Annots %d 0 R\n"
|
||||
"/MediaBox [0 0 %d %d]\n"
|
||||
">>\n"
|
||||
"endobj\n",
|
||||
"/MediaBox [0 0 %f %f]\n",
|
||||
pageRoot, pageStream, resources, annots,
|
||||
// make sure we use the pagesize from when we started the page, since the user may have changed it
|
||||
currentPage->pageSize.width(), currentPage->pageSize.height());
|
||||
currentPage->pageSize.width() / userUnit, currentPage->pageSize.height() / userUnit);
|
||||
|
||||
if (pdfVersion >= QPdfEngine::Version_1_6)
|
||||
xprintf("/UserUnit %f\n", userUnit);
|
||||
|
||||
xprintf(">>\n"
|
||||
"endobj\n");
|
||||
|
||||
addXrefEntry(resources);
|
||||
xprintf("<<\n"
|
||||
@ -2983,8 +3009,9 @@ void QPdfEnginePrivate::drawTextItem(const QPointF &p, const QTextItemInt &ti)
|
||||
|
||||
QTransform QPdfEnginePrivate::pageMatrix() const
|
||||
{
|
||||
qreal scale = 72./resolution;
|
||||
QTransform tmp(scale, 0.0, 0.0, -scale, 0.0, m_pageLayout.fullRectPoints().height());
|
||||
qreal userUnit = calcUserUnit();
|
||||
qreal scale = 72. / userUnit / resolution;
|
||||
QTransform tmp(scale, 0.0, 0.0, -scale, 0.0, m_pageLayout.fullRectPoints().height() / userUnit);
|
||||
if (m_pageLayout.mode() != QPageLayout::FullPageMode) {
|
||||
QRect r = m_pageLayout.paintRectPixels(resolution);
|
||||
tmp.translate(r.left(), r.top());
|
||||
|
@ -171,7 +171,8 @@ public:
|
||||
enum PdfVersion
|
||||
{
|
||||
Version_1_4,
|
||||
Version_A1b
|
||||
Version_A1b,
|
||||
Version_1_6
|
||||
};
|
||||
|
||||
QPdfEngine();
|
||||
@ -300,6 +301,7 @@ private:
|
||||
void writePageRoot();
|
||||
void writeFonts();
|
||||
void embedFont(QFontSubset *font);
|
||||
qreal calcUserUnit() const;
|
||||
|
||||
QVector<int> xrefPositions;
|
||||
QDataStream* stream;
|
||||
|
@ -170,11 +170,17 @@ void QPdfWriter::setPdfVersion(PdfVersion version)
|
||||
{
|
||||
Q_D(QPdfWriter);
|
||||
|
||||
static const QHash<QPdfWriter::PdfVersion, QPdfEngine::PdfVersion> engineMapping {
|
||||
{QPdfWriter::PdfVersion_1_4, QPdfEngine::Version_1_4},
|
||||
{QPdfWriter::PdfVersion_A1b, QPdfEngine::Version_A1b},
|
||||
{QPdfWriter::PdfVersion_1_6, QPdfEngine::Version_1_6}
|
||||
};
|
||||
|
||||
if (d->pdfVersion == version)
|
||||
return;
|
||||
|
||||
d->pdfVersion = version;
|
||||
d->engine->setPdfVersion(d->pdfVersion == QPdfWriter::PdfVersion_1_4 ? QPdfEngine::Version_1_4 : QPdfEngine::Version_A1b);
|
||||
d->engine->setPdfVersion(engineMapping.value(version, QPdfEngine::Version_1_4));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -149,7 +149,12 @@ void QPrinterPrivate::initEngines(QPrinter::OutputFormat format, const QPrinterI
|
||||
printEngine = ps->createNativePrintEngine(printerMode, printerName);
|
||||
paintEngine = ps->createPaintEngine(printEngine, printerMode);
|
||||
} else {
|
||||
const auto pdfEngineVersion = (pdfVersion == QPrinter::PdfVersion_1_4 ? QPdfEngine::Version_1_4 : QPdfEngine::Version_A1b);
|
||||
static const QHash<QPrinter::PdfVersion, QPdfEngine::PdfVersion> engineMapping {
|
||||
{QPrinter::PdfVersion_1_4, QPdfEngine::Version_1_4},
|
||||
{QPrinter::PdfVersion_A1b, QPdfEngine::Version_A1b},
|
||||
{QPrinter::PdfVersion_1_6, QPdfEngine::Version_1_6}
|
||||
};
|
||||
const auto pdfEngineVersion = engineMapping.value(pdfVersion, QPdfEngine::Version_1_4);
|
||||
QPdfPrintEngine *pdfEngine = new QPdfPrintEngine(printerMode, pdfEngineVersion);
|
||||
paintEngine = pdfEngine;
|
||||
printEngine = pdfEngine;
|
||||
|
Loading…
x
Reference in New Issue
Block a user