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.
|
\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
|
Envelope10 = Comm10E
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PdfVersion { PdfVersion_1_4, PdfVersion_A1b };
|
enum PdfVersion { PdfVersion_1_4, PdfVersion_A1b, PdfVersion_1_6 };
|
||||||
|
|
||||||
// ### Qt6 Make these virtual
|
// ### Qt6 Make these virtual
|
||||||
bool setPageLayout(const QPageLayout &pageLayout);
|
bool setPageLayout(const QPageLayout &pageLayout);
|
||||||
|
@ -1547,7 +1547,14 @@ void QPdfEnginePrivate::writeHeader()
|
|||||||
{
|
{
|
||||||
addXrefEntry(0,false);
|
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");
|
xprintf("%%\303\242\303\243\n");
|
||||||
|
|
||||||
writeInfo();
|
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()
|
void QPdfEnginePrivate::writeFonts()
|
||||||
{
|
{
|
||||||
@ -1902,6 +1922,8 @@ void QPdfEnginePrivate::writePage()
|
|||||||
uint resources = requestObject();
|
uint resources = requestObject();
|
||||||
uint annots = requestObject();
|
uint annots = requestObject();
|
||||||
|
|
||||||
|
qreal userUnit = calcUserUnit();
|
||||||
|
|
||||||
addXrefEntry(pages.constLast());
|
addXrefEntry(pages.constLast());
|
||||||
xprintf("<<\n"
|
xprintf("<<\n"
|
||||||
"/Type /Page\n"
|
"/Type /Page\n"
|
||||||
@ -1909,12 +1931,16 @@ void QPdfEnginePrivate::writePage()
|
|||||||
"/Contents %d 0 R\n"
|
"/Contents %d 0 R\n"
|
||||||
"/Resources %d 0 R\n"
|
"/Resources %d 0 R\n"
|
||||||
"/Annots %d 0 R\n"
|
"/Annots %d 0 R\n"
|
||||||
"/MediaBox [0 0 %d %d]\n"
|
"/MediaBox [0 0 %f %f]\n",
|
||||||
">>\n"
|
|
||||||
"endobj\n",
|
|
||||||
pageRoot, pageStream, resources, annots,
|
pageRoot, pageStream, resources, annots,
|
||||||
// make sure we use the pagesize from when we started the page, since the user may have changed it
|
// 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);
|
addXrefEntry(resources);
|
||||||
xprintf("<<\n"
|
xprintf("<<\n"
|
||||||
@ -2983,8 +3009,9 @@ void QPdfEnginePrivate::drawTextItem(const QPointF &p, const QTextItemInt &ti)
|
|||||||
|
|
||||||
QTransform QPdfEnginePrivate::pageMatrix() const
|
QTransform QPdfEnginePrivate::pageMatrix() const
|
||||||
{
|
{
|
||||||
qreal scale = 72./resolution;
|
qreal userUnit = calcUserUnit();
|
||||||
QTransform tmp(scale, 0.0, 0.0, -scale, 0.0, m_pageLayout.fullRectPoints().height());
|
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) {
|
if (m_pageLayout.mode() != QPageLayout::FullPageMode) {
|
||||||
QRect r = m_pageLayout.paintRectPixels(resolution);
|
QRect r = m_pageLayout.paintRectPixels(resolution);
|
||||||
tmp.translate(r.left(), r.top());
|
tmp.translate(r.left(), r.top());
|
||||||
|
@ -171,7 +171,8 @@ public:
|
|||||||
enum PdfVersion
|
enum PdfVersion
|
||||||
{
|
{
|
||||||
Version_1_4,
|
Version_1_4,
|
||||||
Version_A1b
|
Version_A1b,
|
||||||
|
Version_1_6
|
||||||
};
|
};
|
||||||
|
|
||||||
QPdfEngine();
|
QPdfEngine();
|
||||||
@ -300,6 +301,7 @@ private:
|
|||||||
void writePageRoot();
|
void writePageRoot();
|
||||||
void writeFonts();
|
void writeFonts();
|
||||||
void embedFont(QFontSubset *font);
|
void embedFont(QFontSubset *font);
|
||||||
|
qreal calcUserUnit() const;
|
||||||
|
|
||||||
QVector<int> xrefPositions;
|
QVector<int> xrefPositions;
|
||||||
QDataStream* stream;
|
QDataStream* stream;
|
||||||
|
@ -170,11 +170,17 @@ void QPdfWriter::setPdfVersion(PdfVersion version)
|
|||||||
{
|
{
|
||||||
Q_D(QPdfWriter);
|
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)
|
if (d->pdfVersion == version)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
d->pdfVersion = version;
|
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);
|
printEngine = ps->createNativePrintEngine(printerMode, printerName);
|
||||||
paintEngine = ps->createPaintEngine(printEngine, printerMode);
|
paintEngine = ps->createPaintEngine(printEngine, printerMode);
|
||||||
} else {
|
} 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);
|
QPdfPrintEngine *pdfEngine = new QPdfPrintEngine(printerMode, pdfEngineVersion);
|
||||||
paintEngine = pdfEngine;
|
paintEngine = pdfEngine;
|
||||||
printEngine = pdfEngine;
|
printEngine = pdfEngine;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user