summaryrefslogtreecommitdiffstats
path: root/src/gui/painting/qpdf.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/painting/qpdf.cpp')
-rw-r--r--src/gui/painting/qpdf.cpp104
1 files changed, 82 insertions, 22 deletions
diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp
index 4fd0d3c8fe..25d488961c 100644
--- a/src/gui/painting/qpdf.cpp
+++ b/src/gui/painting/qpdf.cpp
@@ -71,6 +71,11 @@ static const bool do_compress = true;
// Can't use it though, as gs generates completely wrong images if this is true.
static const bool interpolateImages = false;
+static void initResources()
+{
+ Q_INIT_RESOURCE(qpdf);
+}
+
QT_BEGIN_NAMESPACE
inline QPaintEngine::PaintEngineFeatures qt_pdf_decide_features()
@@ -851,7 +856,6 @@ void QPdfEngine::drawRects (const QRectF *rects, int rectCount)
if (!d->hasPen && !d->hasBrush)
return;
- QBrush penBrush = d->pen.brush();
if (d->simplePen || !d->hasPen) {
// draw strokes natively in this case for better output
if(!d->simplePen && !d->stroker.matrix.isIdentity())
@@ -944,11 +948,23 @@ void QPdfEngine::drawPixmap (const QRectF &rectangle, const QPixmap &pixmap, con
QPixmap pm = sourceRect != pixmap.rect() ? pixmap.copy(sourceRect) : pixmap;
QImage image = pm.toImage();
bool bitmap = true;
- const int object = d->addImage(image, &bitmap, pm.cacheKey());
+ const bool lossless = painter()->testRenderHint(QPainter::LosslessImageRendering);
+ const int object = d->addImage(image, &bitmap, lossless, pm.cacheKey());
if (object < 0)
return;
- *d->currentPage << "q\n/GSa gs\n";
+ *d->currentPage << "q\n";
+
+ if ((d->pdfVersion != QPdfEngine::Version_A1b) && (d->opacity != 1.0)) {
+ int stateObject = d->addConstantAlphaObject(qRound(255 * d->opacity), qRound(255 * d->opacity));
+ if (stateObject)
+ *d->currentPage << "/GState" << stateObject << "gs\n";
+ else
+ *d->currentPage << "/GSa gs\n";
+ } else {
+ *d->currentPage << "/GSa gs\n";
+ }
+
*d->currentPage
<< QPdf::generateMatrix(QTransform(rectangle.width() / sr.width(), 0, 0, rectangle.height() / sr.height(),
rectangle.x(), rectangle.y()) * (d->simplePen ? QTransform() : d->stroker.matrix));
@@ -972,11 +988,23 @@ void QPdfEngine::drawImage(const QRectF &rectangle, const QImage &image, const Q
QRect sourceRect = sr.toRect();
QImage im = sourceRect != image.rect() ? image.copy(sourceRect) : image;
bool bitmap = true;
- const int object = d->addImage(im, &bitmap, im.cacheKey());
+ const bool lossless = painter()->testRenderHint(QPainter::LosslessImageRendering);
+ const int object = d->addImage(im, &bitmap, lossless, im.cacheKey());
if (object < 0)
return;
- *d->currentPage << "q\n/GSa gs\n";
+ *d->currentPage << "q\n";
+
+ if ((d->pdfVersion != QPdfEngine::Version_A1b) && (d->opacity != 1.0)) {
+ int stateObject = d->addConstantAlphaObject(qRound(255 * d->opacity), qRound(255 * d->opacity));
+ if (stateObject)
+ *d->currentPage << "/GState" << stateObject << "gs\n";
+ else
+ *d->currentPage << "/GSa gs\n";
+ } else {
+ *d->currentPage << "/GSa gs\n";
+ }
+
*d->currentPage
<< QPdf::generateMatrix(QTransform(rectangle.width() / sr.width(), 0, 0, rectangle.height() / sr.height(),
rectangle.x(), rectangle.y()) * (d->simplePen ? QTransform() : d->stroker.matrix));
@@ -1446,6 +1474,7 @@ QPdfEnginePrivate::QPdfEnginePrivate()
grayscale(false),
m_pageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(10, 10, 10, 10))
{
+ initResources();
resolution = 1200;
currentObject = 1;
currentPage = 0;
@@ -1513,7 +1542,7 @@ bool QPdfEngine::end()
Q_D(QPdfEngine);
d->writeTail();
- d->stream->unsetDevice();
+ d->stream->setDevice(nullptr);
qDeleteAll(d->fonts);
d->fonts.clear();
@@ -1541,7 +1570,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();
@@ -1635,19 +1671,19 @@ int QPdfEnginePrivate::writeXmpMetaData()
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 QString timeStr =
+ QString::asprintf("%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);
+ tzStr = QString::asprintf("-%02d:%02d", -hours, -mins);
else if (offset > 0)
- tzStr.sprintf("+%02d:%02d", hours , mins);
+ tzStr = QString::asprintf("+%02d:%02d", hours , mins);
else
tzStr = QLatin1String("Z");
@@ -1874,6 +1910,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()
{
@@ -1896,6 +1945,8 @@ void QPdfEnginePrivate::writePage()
uint resources = requestObject();
uint annots = requestObject();
+ qreal userUnit = calcUserUnit();
+
addXrefEntry(pages.constLast());
xprintf("<<\n"
"/Type /Page\n"
@@ -1903,12 +1954,17 @@ 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 %s %s]\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());
+ QByteArray::number(currentPage->pageSize.width() / userUnit, 'f').constData(),
+ QByteArray::number(currentPage->pageSize.height() / userUnit, 'f').constData());
+
+ if (pdfVersion >= QPdfEngine::Version_1_6)
+ xprintf("/UserUnit %s\n", QByteArray::number(userUnit, 'f').constData());
+
+ xprintf(">>\n"
+ "endobj\n");
addXrefEntry(resources);
xprintf("<<\n"
@@ -2578,6 +2634,8 @@ int QPdfEnginePrivate::addConstantAlphaObject(int brushAlpha, int penAlpha)
int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor, int *gStateObject)
{
+ Q_Q(QPdfEngine);
+
int paintType = 2; // Uncolored tiling
int w = 8;
int h = 8;
@@ -2607,7 +2665,8 @@ int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor,
return 0;
QImage image = brush.textureImage();
bool bitmap = true;
- imageObject = addImage(image, &bitmap, image.cacheKey());
+ const bool lossless = q->painter()->testRenderHint(QPainter::LosslessImageRendering);
+ imageObject = addImage(image, &bitmap, lossless, image.cacheKey());
if (imageObject != -1) {
QImage::Format f = image.format();
if (f != QImage::Format_MonoLSB && f != QImage::Format_Mono) {
@@ -2669,7 +2728,7 @@ static inline bool is_monochrome(const QVector<QRgb> &colorTable)
/*!
* Adds an image to the pdf and return the pdf-object id. Returns -1 if adding the image failed.
*/
-int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, qint64 serial_no)
+int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, bool lossless, qint64 serial_no)
{
if (img.isNull())
return -1;
@@ -2730,7 +2789,7 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, qint64 serial_n
bool hasAlpha = false;
bool hasMask = false;
- if (QImageWriter::supportedImageFormats().contains("jpeg") && !grayscale) {
+ if (QImageWriter::supportedImageFormats().contains("jpeg") && !grayscale && !lossless) {
QBuffer buffer(&imageData);
QImageWriter writer(&buffer, "jpeg");
writer.setQuality(94);
@@ -2977,8 +3036,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());