summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2011-08-12 14:20:08 +0200
committerLars Knoll <lars.knoll@nokia.com>2011-08-19 09:15:28 +0200
commitb91d30eae1d4f75aa9e05c2c4fa204e24e953f6d (patch)
treeaf043c317097555783537bbb49dc1659f22f6db3
parent8f47da7b8f8d83bd79cde05dee6046b14a292ba9 (diff)
Move the PDF related functionality into QPdf
Goal is to have all functionality related to PDF generation in QPdf, and then separate out the parts related to interfacing with the printing system into the pdf printengine. Change-Id: I8c30cb65365c503945fc270fad5cbcaabe59495d Reviewed-on: http://codereview.qt.nokia.com/3201 Reviewed-by: Gunnar Sletta <gunnar.sletta@nokia.com>
-rw-r--r--src/gui/painting/qpdf.cpp1666
-rw-r--r--src/gui/painting/qpdf_p.h85
-rw-r--r--src/gui/painting/qprintengine_pdf.cpp1522
-rw-r--r--src/gui/painting/qprintengine_pdf_p.h82
4 files changed, 1674 insertions, 1681 deletions
diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp
index 958e49907b..da87653ae7 100644
--- a/src/gui/painting/qpdf.cpp
+++ b/src/gui/painting/qpdf.cpp
@@ -44,18 +44,27 @@
#include <qfile.h>
#include <qtemporaryfile.h>
#include <private/qmath_p.h>
-#include "private/qcups_p.h"
-#include "qprinterinfo.h"
#include <qnumeric.h>
#include "private/qfont_p.h"
+#include <qimagewriter.h>
+#include "qbuffer.h"
+#include "QtCore/qdatetime.h"
-#ifdef Q_OS_UNIX
-#include "private/qcore_unix_p.h" // overrides QT_OPEN
+#ifndef QT_NO_COMPRESS
+#include <zlib.h>
#endif
-QT_BEGIN_NAMESPACE
+#ifdef QT_NO_COMPRESS
+static const bool do_compress = false;
+#else
+static const bool do_compress = true;
+#endif
+
+// might be helpful for smooth transforms of images
+// Can't use it though, as gs generates completely wrong images if this is true.
+static const bool interpolateImages = false;
-#ifndef QT_NO_PRINTER
+QT_BEGIN_NAMESPACE
extern QSizeF qt_paperSizeToQSizeF(QPrinter::PaperSize size);
@@ -914,36 +923,22 @@ const char *QPdf::paperSizeToString(QPrinter::PaperSize paperSize)
return psToStr[paperSize];
}
-// -------------------------- base engine, shared code between PS and PDF -----------------------
+QPdfPage::QPdfPage()
+ : QPdf::ByteStream(true) // Enable file backing
+{
+}
+
+void QPdfPage::streamImage(int w, int h, int object)
+{
+ *this << w << "0 0 " << -h << "0 " << h << "cm /Im" << object << " Do\n";
+ if (!images.contains(object))
+ images.append(object);
+}
+
QPdfBaseEngine::QPdfBaseEngine(QPdfBaseEnginePrivate &dd, PaintEngineFeatures f)
: QAlphaPaintEngine(dd, f)
{
- Q_D(QPdfBaseEngine);
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
- if (QCUPSSupport::isAvailable()) {
- QCUPSSupport cups;
- const cups_dest_t* printers = cups.availablePrinters();
- int prnCount = cups.availablePrintersCount();
-
- for (int i = 0; i < prnCount; ++i) {
- if (printers[i].is_default) {
- d->printerName = QString::fromLocal8Bit(printers[i].name);
- break;
- }
- }
-
- } else
-#endif
- {
- d->printerName = QString::fromLocal8Bit(qgetenv("PRINTER"));
- if (d->printerName.isEmpty())
- d->printerName = QString::fromLocal8Bit(qgetenv("LPDEST"));
- if (d->printerName.isEmpty())
- d->printerName = QString::fromLocal8Bit(qgetenv("NPRINTER"));
- if (d->printerName.isEmpty())
- d->printerName = QString::fromLocal8Bit(qgetenv("NGPRINTER"));
- }
}
void QPdfBaseEngine::drawPoints (const QPointF *points, int pointCount)
@@ -1091,6 +1086,89 @@ void QPdfBaseEngine::drawPath (const QPainterPath &p)
}
}
+void QPdfBaseEngine::drawPixmap (const QRectF &rectangle, const QPixmap &pixmap, const QRectF &sr)
+{
+ if (sr.isEmpty() || rectangle.isEmpty() || pixmap.isNull())
+ return;
+ Q_D(QPdfBaseEngine);
+
+ QBrush b = d->brush;
+
+ QRect sourceRect = sr.toRect();
+ 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());
+ if (object < 0)
+ return;
+
+ *d->currentPage << "q\n/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));
+ if (bitmap) {
+ // set current pen as d->brush
+ d->brush = d->pen.brush();
+ }
+ setBrush();
+ d->currentPage->streamImage(image.width(), image.height(), object);
+ *d->currentPage << "Q\n";
+
+ d->brush = b;
+}
+
+void QPdfBaseEngine::drawImage(const QRectF &rectangle, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags)
+{
+ if (sr.isEmpty() || rectangle.isEmpty() || image.isNull())
+ return;
+ Q_D(QPdfBaseEngine);
+
+ 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());
+ if (object < 0)
+ return;
+
+ *d->currentPage << "q\n/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));
+ setBrush();
+ d->currentPage->streamImage(im.width(), im.height(), object);
+ *d->currentPage << "Q\n";
+}
+
+void QPdfBaseEngine::drawTiledPixmap (const QRectF &rectangle, const QPixmap &pixmap, const QPointF &point)
+{
+ Q_D(QPdfBaseEngine);
+
+ bool bitmap = (pixmap.depth() == 1);
+ QBrush b = d->brush;
+ QPointF bo = d->brushOrigin;
+ bool hp = d->hasPen;
+ d->hasPen = false;
+ bool hb = d->hasBrush;
+ d->hasBrush = true;
+
+ d->brush = QBrush(pixmap);
+ if (bitmap)
+ // #### fix bitmap case where we have a brush pen
+ d->brush.setColor(d->pen.color());
+
+ d->brushOrigin = -point;
+ *d->currentPage << "q\n";
+ setBrush();
+
+ drawRects(&rectangle, 1);
+ *d->currentPage << "Q\n";
+
+ d->hasPen = hp;
+ d->hasBrush = hb;
+ d->brush = b;
+ d->brushOrigin = bo;
+}
+
void QPdfBaseEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
{
Q_D(QPdfBaseEngine);
@@ -1337,9 +1415,48 @@ void QPdfBaseEngine::setPen()
*d->currentPage << QPdf::generateDashes(d->pen) << " 0 d\n";
}
+
+void QPdfBaseEngine::setBrush()
+{
+ Q_D(QPdfBaseEngine);
+ Qt::BrushStyle style = d->brush.style();
+ if (style == Qt::NoBrush)
+ return;
+
+ bool specifyColor;
+ int gStateObject = 0;
+ int patternObject = d->addBrushPattern(d->stroker.matrix, &specifyColor, &gStateObject);
+
+ *d->currentPage << (patternObject ? "/PCSp cs " : "/CSp cs ");
+ if (specifyColor) {
+ QColor rgba = d->brush.color();
+ if (d->colorMode == QPrinter::GrayScale) {
+ qreal gray = qGray(rgba.rgba())/255.;
+ *d->currentPage << gray << gray << gray;
+ } else {
+ *d->currentPage << rgba.redF()
+ << rgba.greenF()
+ << rgba.blueF();
+ }
+ }
+ if (patternObject)
+ *d->currentPage << "/Pat" << patternObject;
+ *d->currentPage << "scn\n";
+
+ if (gStateObject)
+ *d->currentPage << "/GState" << gStateObject << "gs\n";
+ else
+ *d->currentPage << "/GSa gs\n";
+}
+
+
bool QPdfBaseEngine::newPage()
{
Q_D(QPdfBaseEngine);
+ if (!isActive())
+ return false;
+ d->newPage();
+
setupGraphicsState(DirtyBrush|DirtyPen|DirtyClipPath);
QFile *outfile = qobject_cast<QFile*> (d->outDevice);
if (outfile && outfile->error() != QFile::NoError)
@@ -1347,6 +1464,12 @@ bool QPdfBaseEngine::newPage()
return true;
}
+QPaintEngine::Type QPdfBaseEngine::type() const
+{
+ return QPaintEngine::Pdf;
+}
+
+
int QPdfBaseEngine::metric(QPaintDevice::PaintDeviceMetric metricType) const
{
@@ -1387,210 +1510,6 @@ int QPdfBaseEngine::metric(QPaintDevice::PaintDeviceMetric metricType) const
return val;
}
-void QPdfBaseEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value)
-{
- Q_D(QPdfBaseEngine);
- switch (int(key)) {
- case PPK_CollateCopies:
- d->collate = value.toBool();
- break;
- case PPK_ColorMode:
- d->colorMode = QPrinter::ColorMode(value.toInt());
- break;
- case PPK_Creator:
- d->creator = value.toString();
- break;
- case PPK_DocumentName:
- d->title = value.toString();
- break;
- case PPK_FullPage:
- d->fullPage = value.toBool();
- break;
- case PPK_CopyCount: // fallthrough
- case PPK_NumberOfCopies:
- d->copies = value.toInt();
- break;
- case PPK_Orientation:
- d->orientation = QPrinter::Orientation(value.toInt());
- break;
- case PPK_OutputFileName:
- d->outputFileName = value.toString();
- break;
- case PPK_PageOrder:
- d->pageOrder = QPrinter::PageOrder(value.toInt());
- break;
- case PPK_PaperSize:
- d->paperSize = QPrinter::PaperSize(value.toInt());
- break;
- case PPK_PaperSource:
- d->paperSource = QPrinter::PaperSource(value.toInt());
- break;
- case PPK_PrinterName:
- d->printerName = value.toString();
- break;
- case PPK_PrinterProgram:
- d->printProgram = value.toString();
- break;
- case PPK_Resolution:
- d->resolution = value.toInt();
- break;
- case PPK_SelectionOption:
- d->selectionOption = value.toString();
- break;
- case PPK_FontEmbedding:
- d->embedFonts = value.toBool();
- break;
- case PPK_Duplex:
- d->duplex = static_cast<QPrinter::DuplexMode> (value.toInt());
- break;
- case PPK_CupsPageRect:
- d->cupsPageRect = value.toRect();
- break;
- case PPK_CupsPaperRect:
- d->cupsPaperRect = value.toRect();
- break;
- case PPK_CupsOptions:
- d->cupsOptions = value.toStringList();
- break;
- case PPK_CupsStringPageSize:
- d->cupsStringPageSize = value.toString();
- break;
- case PPK_CustomPaperSize:
- d->paperSize = QPrinter::Custom;
- d->customPaperSize = value.toSizeF();
- break;
- case PPK_PageMargins:
- {
- QList<QVariant> margins(value.toList());
- Q_ASSERT(margins.size() == 4);
- d->leftMargin = margins.at(0).toReal();
- d->topMargin = margins.at(1).toReal();
- d->rightMargin = margins.at(2).toReal();
- d->bottomMargin = margins.at(3).toReal();
- d->hasCustomPageMargins = true;
- break;
- }
- default:
- break;
- }
-}
-
-QVariant QPdfBaseEngine::property(PrintEnginePropertyKey key) const
-{
- Q_D(const QPdfBaseEngine);
-
- QVariant ret;
- switch (int(key)) {
- case PPK_CollateCopies:
- ret = d->collate;
- break;
- case PPK_ColorMode:
- ret = d->colorMode;
- break;
- case PPK_Creator:
- ret = d->creator;
- break;
- case PPK_DocumentName:
- ret = d->title;
- break;
- case PPK_FullPage:
- ret = d->fullPage;
- break;
- case PPK_CopyCount:
- ret = d->copies;
- break;
- case PPK_SupportsMultipleCopies:
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
- if (QCUPSSupport::isAvailable())
- ret = true;
- else
-#endif
- ret = false;
- break;
- case PPK_NumberOfCopies:
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
- if (QCUPSSupport::isAvailable())
- ret = 1;
- else
-#endif
- ret = d->copies;
- break;
- case PPK_Orientation:
- ret = d->orientation;
- break;
- case PPK_OutputFileName:
- ret = d->outputFileName;
- break;
- case PPK_PageOrder:
- ret = d->pageOrder;
- break;
- case PPK_PaperSize:
- ret = d->paperSize;
- break;
- case PPK_PaperSource:
- ret = d->paperSource;
- break;
- case PPK_PrinterName:
- ret = d->printerName;
- break;
- case PPK_PrinterProgram:
- ret = d->printProgram;
- break;
- case PPK_Resolution:
- ret = d->resolution;
- break;
- case PPK_SupportedResolutions:
- ret = QList<QVariant>() << 72;
- break;
- case PPK_PaperRect:
- ret = d->paperRect();
- break;
- case PPK_PageRect:
- ret = d->pageRect();
- break;
- case PPK_SelectionOption:
- ret = d->selectionOption;
- break;
- case PPK_FontEmbedding:
- ret = d->embedFonts;
- break;
- case PPK_Duplex:
- ret = d->duplex;
- break;
- case PPK_CupsPageRect:
- ret = d->cupsPageRect;
- break;
- case PPK_CupsPaperRect:
- ret = d->cupsPaperRect;
- break;
- case PPK_CupsOptions:
- ret = d->cupsOptions;
- break;
- case PPK_CupsStringPageSize:
- ret = d->cupsStringPageSize;
- break;
- case PPK_CustomPaperSize:
- ret = d->customPaperSize;
- break;
- case PPK_PageMargins:
- {
- QList<QVariant> margins;
- if (d->hasCustomPageMargins) {
- margins << d->leftMargin << d->topMargin
- << d->rightMargin << d->bottomMargin;
- } else {
- const qreal defaultMargin = 10; // ~3.5 mm
- margins << defaultMargin << defaultMargin
- << defaultMargin << defaultMargin;
- }
- ret = margins;
- break;
- }
- default:
- break;
- }
- return ret;
-}
QPdfBaseEnginePrivate::QPdfBaseEnginePrivate(QPrinter::PrinterMode m)
: clipEnabled(false), allClipped(false), hasPen(true), hasBrush(false), simplePen(false),
@@ -1612,6 +1531,13 @@ QPdfBaseEnginePrivate::QPdfBaseEnginePrivate(QPrinter::PrinterMode m)
currentObject = 1;
currentPage = 0;
stroker.stream = 0;
+
+ streampos = 0;
+
+ stream = new QDataStream;
+ pageOrder = QPrinter::FirstPageFirst;
+ orientation = QPrinter::Portrait;
+ fullPage = false;
}
bool QPdfBaseEngine::begin(QPaintDevice *pdev)
@@ -1626,289 +1552,1021 @@ bool QPdfBaseEngine::begin(QPaintDevice *pdev)
d->stroker.stream = d->currentPage;
d->opacity = 1.0;
- return d->openPrintDevice();
+ d->stream->setDevice(d->outDevice);
+
+ d->streampos = 0;
+ d->hasPen = true;
+ d->hasBrush = false;
+ d->clipEnabled = false;
+ d->allClipped = false;
+
+ d->xrefPositions.clear();
+ d->pageRoot = 0;
+ d->catalog = 0;
+ d->info = 0;
+ d->graphicsState = 0;
+ d->patternColorSpace = 0;
+
+ d->pages.clear();
+ d->imageCache.clear();
+
+ setActive(true);
+ d->writeHeader();
+ newPage();
+
+ return true;
}
bool QPdfBaseEngine::end()
{
Q_D(QPdfBaseEngine);
+ d->writeTail();
+
+ d->stream->unsetDevice();
+
qDeleteAll(d->fonts);
d->fonts.clear();
delete d->currentPage;
d->currentPage = 0;
- d->closePrintDevice();
+ setActive(false);
return true;
}
-#ifndef QT_NO_LPR
-static void closeAllOpenFds()
+QPdfBaseEnginePrivate::~QPdfBaseEnginePrivate()
{
- // hack time... getting the maximum number of open
- // files, if possible. if not we assume it's the
- // larger of 256 and the fd we got
- int i;
-#if defined(_SC_OPEN_MAX)
- i = (int)sysconf(_SC_OPEN_MAX);
-#elif defined(_POSIX_OPEN_MAX)
- i = (int)_POSIX_OPEN_MAX;
-#elif defined(OPEN_MAX)
- i = (int)OPEN_MAX;
-#else
- i = 256;
-#endif
- // leave stdin/out/err untouched
- while(--i > 2)
- QT_CLOSE(i);
+ qDeleteAll(fonts);
+ delete currentPage;
+ delete stream;
}
-#endif
-bool QPdfBaseEnginePrivate::openPrintDevice()
+QRect QPdfBaseEnginePrivate::paperRect() const
{
- if(outDevice)
- return false;
-
- if (!outputFileName.isEmpty()) {
- QFile *file = new QFile(outputFileName);
- if (! file->open(QFile::WriteOnly|QFile::Truncate)) {
- delete file;
- return false;
+ int w;
+ int h;
+ if (paperSize == QPrinter::Custom) {
+ w = qRound(customPaperSize.width()*resolution/72.);
+ h = qRound(customPaperSize.height()*resolution/72.);
+ } else {
+ if (!cupsPaperRect.isNull()) {
+ QRect r = cupsPaperRect;
+ w = r.width();
+ h = r.height();
+ } else{
+ QPdf::PaperSize s = QPdf::paperSize(paperSize);
+ w = s.width;
+ h = s.height;
}
- outDevice = file;
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
- } else if (QCUPSSupport::isAvailable()) {
- QCUPSSupport cups;
- QPair<int, QString> ret = cups.tempFd();
- if (ret.first < 0) {
- qWarning("QPdfPrinter: Could not open temporary file to print");
- return false;
+ w = qRound(w*resolution/72.);
+ h = qRound(h*resolution/72.);
+ }
+ if (orientation == QPrinter::Portrait)
+ return QRect(0, 0, w, h);
+ else
+ return QRect(0, 0, h, w);
+}
+
+QRect QPdfBaseEnginePrivate::pageRect() const
+{
+ if(fullPage)
+ return paperRect();
+
+ QRect r;
+
+ if (!hasCustomPageMargins && !cupsPageRect.isNull()) {
+ r = cupsPageRect;
+ if (r == cupsPaperRect) {
+ // if cups doesn't define any margins, give it at least approx 3.5 mm
+ r = QRect(10, 10, r.width() - 20, r.height() - 20);
}
- cupsTempFile = ret.second;
- outDevice = new QFile();
- static_cast<QFile *>(outDevice)->open(ret.first, QIODevice::WriteOnly);
-#endif
-#ifndef QT_NO_LPR
} else {
- QString pr;
- if (!printerName.isEmpty())
- pr = printerName;
- int fds[2];
- if (qt_safe_pipe(fds) != 0) {
- qWarning("QPdfPrinter: Could not open pipe to print");
- return false;
+ QPdf::PaperSize s;
+ if (paperSize == QPrinter::Custom) {
+ s.width = qRound(customPaperSize.width());
+ s.height = qRound(customPaperSize.height());
+ } else {
+ s = QPdf::paperSize(paperSize);
}
+ if (hasCustomPageMargins)
+ r = QRect(0, 0, s.width, s.height);
+ else
+ r = QRect(72/3, 72/3, s.width - 2*72/3, s.height - 2*72/3);
+ }
- pid_t pid = fork();
- if (pid == 0) { // child process
- // if possible, exit quickly, so the actual lp/lpr
- // becomes a child of init, and ::waitpid() is
- // guaranteed not to wait.
- if (fork() > 0) {
- closeAllOpenFds();
-
- // try to replace this process with "true" - this prevents
- // global destructors from being called (that could possibly
- // do wrong things to the parent process)
- (void)execlp("true", "true", (char *)0);
- (void)execl("/bin/true", "true", (char *)0);
- (void)execl("/usr/bin/true", "true", (char *)0);
- ::_exit(0);
- }
- qt_safe_dup2(fds[0], 0, 0);
+ int x = qRound(r.left()*resolution/72.);
+ int y = qRound(r.top()*resolution/72.);
+ int w = qRound(r.width()*resolution/72.);
+ int h = qRound(r.height()*resolution/72.);
+ if (orientation == QPrinter::Portrait)
+ r = QRect(x, y, w, h);
+ else
+ r = QRect(y, x, h, w);
+
+ if (hasCustomPageMargins) {
+ r.adjust(qRound(leftMargin*(resolution/72.)),
+ qRound(topMargin*(resolution/72.)),
+ -qRound(rightMargin*(resolution/72.)),
+ -qRound(bottomMargin*(resolution/72.)));
+ }
+ return r;
+}
- closeAllOpenFds();
- if (!printProgram.isEmpty()) {
- if (!selectionOption.isEmpty())
- pr.prepend(selectionOption);
- else
- pr.prepend(QLatin1String("-P"));
- (void)execlp(printProgram.toLocal8Bit().data(), printProgram.toLocal8Bit().data(),
- pr.toLocal8Bit().data(), (char *)0);
- } else {
- // if no print program has been specified, be smart
- // about the option string too.
- QList<QByteArray> lprhack;
- QList<QByteArray> lphack;
- QByteArray media;
- if (!pr.isEmpty() || !selectionOption.isEmpty()) {
- if (!selectionOption.isEmpty()) {
- QStringList list = selectionOption.split(QLatin1Char(' '));
- for (int i = 0; i < list.size(); ++i)
- lprhack.append(list.at(i).toLocal8Bit());
- lphack = lprhack;
- } else {
- lprhack.append("-P");
- lphack.append("-d");
- }
- lprhack.append(pr.toLocal8Bit());
- lphack.append(pr.toLocal8Bit());
- }
- lphack.append("-s");
-
- char ** lpargs = new char *[lphack.size()+6];
- char lp[] = "lp";
- lpargs[0] = lp;
- int i;
- for (i = 0; i < lphack.size(); ++i)
- lpargs[i+1] = (char *)lphack.at(i).constData();
-#ifndef Q_OS_OSF
- if (QPdf::paperSizeToString(paperSize)) {
- char dash_o[] = "-o";
- lpargs[++i] = dash_o;
- lpargs[++i] = const_cast<char *>(QPdf::paperSizeToString(paperSize));
- lpargs[++i] = dash_o;
- media = "media=";
- media += QPdf::paperSizeToString(paperSize);
- lpargs[++i] = media.data();
- }
+void QPdfBaseEnginePrivate::writeHeader()
+{
+ addXrefEntry(0,false);
+
+ xprintf("%%PDF-1.4\n");
+
+ writeInfo();
+
+ catalog = addXrefEntry(-1);
+ pageRoot = requestObject();
+ xprintf("<<\n"
+ "/Type /Catalog\n"
+ "/Pages %d 0 R\n"
+ ">>\n"
+ "endobj\n", pageRoot);
+
+ // graphics state
+ graphicsState = addXrefEntry(-1);
+ xprintf("<<\n"
+ "/Type /ExtGState\n"
+ "/SA true\n"
+ "/SM 0.02\n"
+ "/ca 1.0\n"
+ "/CA 1.0\n"
+ "/AIS false\n"
+ "/SMask /None"
+ ">>\n"
+ "endobj\n");
+
+ // color space for pattern
+ patternColorSpace = addXrefEntry(-1);
+ xprintf("[/Pattern /DeviceRGB]\n"
+ "endobj\n");
+}
+
+void QPdfBaseEnginePrivate::writeInfo()
+{
+ info = addXrefEntry(-1);
+ xprintf("<<\n/Title ");
+ printString(title);
+ xprintf("\n/Creator ");
+ printString(creator);
+ xprintf("\n/Producer ");
+ printString(QString::fromLatin1("Qt " QT_VERSION_STR " (C) 2011 Nokia Corporation and/or its subsidiary(-ies)"));
+ QDateTime now = QDateTime::currentDateTime().toUTC();
+ QTime t = now.time();
+ QDate d = now.date();
+ xprintf("\n/CreationDate (D:%d%02d%02d%02d%02d%02d)\n",
+ d.year(),
+ d.month(),
+ d.day(),
+ t.hour(),
+ t.minute(),
+ t.second());
+ xprintf(">>\n"
+ "endobj\n");
+}
+
+void QPdfBaseEnginePrivate::writePageRoot()
+{
+ addXrefEntry(pageRoot);
+
+ xprintf("<<\n"
+ "/Type /Pages\n"
+ "/Kids \n"
+ "[\n");
+ int size = pages.size();
+ for (int i = 0; i < size; ++i)
+ xprintf("%d 0 R\n", pages[i]);
+ xprintf("]\n");
+
+ //xprintf("/Group <</S /Transparency /I true /K false>>\n");
+ xprintf("/Count %d\n", pages.size());
+
+ xprintf("/ProcSet [/PDF /Text /ImageB /ImageC]\n"
+ ">>\n"
+ "endobj\n");
+}
+
+
+void QPdfBaseEnginePrivate::embedFont(QFontSubset *font)
+{
+ //qDebug() << "embedFont" << font->object_id;
+ int fontObject = font->object_id;
+ QByteArray fontData = font->toTruetype();
+#ifdef FONT_DUMP
+ static int i = 0;
+ QString fileName("font%1.ttf");
+ fileName = fileName.arg(i++);
+ QFile ff(fileName);
+ ff.open(QFile::WriteOnly);
+ ff.write(fontData);
+ ff.close();
#endif
- lpargs[++i] = 0;
- char **lprargs = new char *[lprhack.size()+2];
- char lpr[] = "lpr";
- lprargs[0] = lpr;
- for (int i = 0; i < lprhack.size(); ++i)
- lprargs[i+1] = (char *)lprhack[i].constData();
- lprargs[lprhack.size() + 1] = 0;
- (void)execvp("lp", lpargs);
- (void)execvp("lpr", lprargs);
- (void)execv("/bin/lp", lpargs);
- (void)execv("/bin/lpr", lprargs);
- (void)execv("/usr/bin/lp", lpargs);
- (void)execv("/usr/bin/lpr", lprargs);
-
- delete []lpargs;
- delete []lprargs;
- }
- // if we couldn't exec anything, close the fd,
- // wait for a second so the parent process (the
- // child of the GUI process) has exited. then
- // exit.
- QT_CLOSE(0);
- (void)::sleep(1);
- ::_exit(0);
+
+ int fontDescriptor = requestObject();
+ int fontstream = requestObject();
+ int cidfont = requestObject();
+ int toUnicode = requestObject();
+
+ QFontEngine::Properties properties = font->fontEngine->properties();
+
+ {
+ qreal scale = 1000/properties.emSquare.toReal();
+ addXrefEntry(fontDescriptor);
+ QByteArray descriptor;
+ QPdf::ByteStream s(&descriptor);
+ s << "<< /Type /FontDescriptor\n"
+ "/FontName /Q";
+ int tag = fontDescriptor;
+ for (int i = 0; i < 5; ++i) {
+ s << (char)('A' + (tag % 26));
+ tag /= 26;
}
- // parent process
- QT_CLOSE(fds[0]);
- fd = fds[1];
- (void)qt_safe_waitpid(pid, 0, 0);
+ s << '+' << properties.postscriptName << "\n"
+ "/Flags " << 4 << "\n"
+ "/FontBBox ["
+ << properties.boundingBox.x()*scale
+ << -(properties.boundingBox.y() + properties.boundingBox.height())*scale
+ << (properties.boundingBox.x() + properties.boundingBox.width())*scale
+ << -properties.boundingBox.y()*scale << "]\n"
+ "/ItalicAngle " << properties.italicAngle.toReal() << "\n"
+ "/Ascent " << properties.ascent.toReal()*scale << "\n"
+ "/Descent " << -properties.descent.toReal()*scale << "\n"
+ "/CapHeight " << properties.capHeight.toReal()*scale << "\n"
+ "/StemV " << properties.lineWidth.toReal()*scale << "\n"
+ "/FontFile2 " << fontstream << "0 R\n"
+ ">> endobj\n";
+ write(descriptor);
+ }
+ {
+ addXrefEntry(fontstream);
+ QByteArray header;
+ QPdf::ByteStream s(&header);
+
+ int length_object = requestObject();
+ s << "<<\n"
+ "/Length1 " << fontData.size() << "\n"
+ "/Length " << length_object << "0 R\n";
+ if (do_compress)
+ s << "/Filter /FlateDecode\n";
+ s << ">>\n"
+ "stream\n";
+ write(header);
+ int len = writeCompressed(fontData);
+ write("endstream\n"
+ "endobj\n");
+ addXrefEntry(length_object);
+ xprintf("%d\n"
+ "endobj\n", len);
+ }
+ {
+ addXrefEntry(cidfont);
+ QByteArray cid;
+ QPdf::ByteStream s(&cid);
+ s << "<< /Type /Font\n"
+ "/Subtype /CIDFontType2\n"
+ "/BaseFont /" << properties.postscriptName << "\n"
+ "/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>\n"
+ "/FontDescriptor " << fontDescriptor << "0 R\n"
+ "/CIDToGIDMap /Identity\n"
+ << font->widthArray() <<
+ ">>\n"
+ "endobj\n";
+ write(cid);
+ }
+ {
+ addXrefEntry(toUnicode);
+ QByteArray touc = font->createToUnicodeMap();
+ xprintf("<< /Length %d >>\n"
+ "stream\n", touc.length());
+ write(touc);
+ write("endstream\n"
+ "endobj\n");
+ }
+ {
+ addXrefEntry(fontObject);
+ QByteArray font;
+ QPdf::ByteStream s(&font);
+ s << "<< /Type /Font\n"
+ "/Subtype /Type0\n"
+ "/BaseFont /" << properties.postscriptName << "\n"
+ "/Encoding /Identity-H\n"
+ "/DescendantFonts [" << cidfont << "0 R]\n"
+ "/ToUnicode " << toUnicode << "0 R"
+ ">>\n"
+ "endobj\n";
+ write(font);
+ }
+}
- if (fd < 0)
- return false;
- outDevice = new QFile();
- static_cast<QFile *>(outDevice)->open(fd, QIODevice::WriteOnly);
-#endif
+void QPdfBaseEnginePrivate::writeFonts()
+{
+ for (QHash<QFontEngine::FaceId, QFontSubset *>::iterator it = fonts.begin(); it != fonts.end(); ++it) {
+ embedFont(*it);
+ delete *it;
}
+ fonts.clear();
+}
- return true;
+void QPdfBaseEnginePrivate::writePage()
+{
+ if (pages.empty())
+ return;
+
+ *currentPage << "Q Q\n";
+
+ uint pageStream = requestObject();
+ uint pageStreamLength = requestObject();
+ uint resources = requestObject();
+ uint annots = requestObject();
+
+ addXrefEntry(pages.last());
+ xprintf("<<\n"
+ "/Type /Page\n"
+ "/Parent %d 0 R\n"
+ "/Contents %d 0 R\n"
+ "/Resources %d 0 R\n"
+ "/Annots %d 0 R\n"
+ "/MediaBox [0 0 %d %d]\n"
+ ">>\n"
+ "endobj\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());
+
+ addXrefEntry(resources);
+ xprintf("<<\n"
+ "/ColorSpace <<\n"
+ "/PCSp %d 0 R\n"
+ "/CSp /DeviceRGB\n"
+ "/CSpg /DeviceGray\n"
+ ">>\n"
+ "/ExtGState <<\n"
+ "/GSa %d 0 R\n",
+ patternColorSpace, graphicsState);
+
+ for (int i = 0; i < currentPage->graphicStates.size(); ++i)
+ xprintf("/GState%d %d 0 R\n", currentPage->graphicStates.at(i), currentPage->graphicStates.at(i));
+ xprintf(">>\n");
+
+ xprintf("/Pattern <<\n");
+ for (int i = 0; i < currentPage->patterns.size(); ++i)
+ xprintf("/Pat%d %d 0 R\n", currentPage->patterns.at(i), currentPage->patterns.at(i));
+ xprintf(">>\n");
+
+ xprintf("/Font <<\n");
+ for (int i = 0; i < currentPage->fonts.size();++i)
+ xprintf("/F%d %d 0 R\n", currentPage->fonts[i], currentPage->fonts[i]);
+ xprintf(">>\n");
+
+ xprintf("/XObject <<\n");
+ for (int i = 0; i<currentPage->images.size(); ++i) {
+ xprintf("/Im%d %d 0 R\n", currentPage->images.at(i), currentPage->images.at(i));
+ }
+ xprintf(">>\n");
+
+ xprintf(">>\n"
+ "endobj\n");
+
+ addXrefEntry(annots);
+ xprintf("[ ");
+ for (int i = 0; i<currentPage->annotations.size(); ++i) {
+ xprintf("%d 0 R ", currentPage->annotations.at(i));
+ }
+ xprintf("]\nendobj\n");
+
+ addXrefEntry(pageStream);
+ xprintf("<<\n"
+ "/Length %d 0 R\n", pageStreamLength); // object number for stream length object
+ if (do_compress)
+ xprintf("/Filter /FlateDecode\n");
+
+ xprintf(">>\n");
+ xprintf("stream\n");
+ QIODevice *content = currentPage->stream();
+ int len = writeCompressed(content);
+ xprintf("endstream\n"
+ "endobj\n");
+
+ addXrefEntry(pageStreamLength);
+ xprintf("%d\nendobj\n",len);
+}
+
+void QPdfBaseEnginePrivate::writeTail()
+{
+ writePage();
+ writeFonts();
+ writePageRoot();
+ addXrefEntry(xrefPositions.size(),false);
+ xprintf("xref\n"
+ "0 %d\n"
+ "%010d 65535 f \n", xrefPositions.size()-1, xrefPositions[0]);
+
+ 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.last());
+}
+
+int QPdfBaseEnginePrivate::addXrefEntry(int object, bool printostr)
+{
+ if (object < 0)
+ object = requestObject();
+
+ if (object>=xrefPositions.size())
+ xrefPositions.resize(object+1);
+
+ xrefPositions[object] = streampos;
+ if (printostr)
+ xprintf("%d 0 obj\n",object);
+
+ return object;
}
-void QPdfBaseEnginePrivate::closePrintDevice()
+void QPdfBaseEnginePrivate::printString(const QString &string) {
+ // The 'text string' type in PDF is encoded either as PDFDocEncoding, or
+ // Unicode UTF-16 with a Unicode byte order mark as the first character
+ // (0xfeff), with the high-order byte first.
+ QByteArray array("(\xfe\xff");
+ const ushort *utf16 = string.utf16();
+
+ for (int i=0; i < string.size(); ++i) {
+ char part[2] = {char((*(utf16 + i)) >> 8), char((*(utf16 + i)) & 0xff)};
+ for(int j=0; j < 2; ++j) {
+ if (part[j] == '(' || part[j] == ')' || part[j] == '\\')
+ array.append('\\');
+ array.append(part[j]);
+ }
+ }
+ array.append(")");
+ write(array);
+}
+
+
+// For strings up to 10000 bytes only !
+void QPdfBaseEnginePrivate::xprintf(const char* fmt, ...)
{
- if (!outDevice)
+ if (!stream)
return;
- outDevice->close();
- if (fd >= 0)
-#if defined(Q_OS_WIN) && defined(_MSC_VER) && _MSC_VER >= 1400
- ::_close(fd);
-#else
- ::close(fd);
-#endif
- fd = -1;
- delete outDevice;
- outDevice = 0;
-
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
- if (!cupsTempFile.isEmpty()) {
- QString tempFile = cupsTempFile;
- cupsTempFile.clear();
- QCUPSSupport cups;
-
- // Set up print options.
- QByteArray prnName;
- QList<QPair<QByteArray, QByteArray> > options;
- QVector<cups_option_t> cupsOptStruct;
-
- if (!printerName.isEmpty()) {
- prnName = printerName.toLocal8Bit();
- } else {
- QPrinterInfo def = QPrinterInfo::defaultPrinter();
- if (def.isNull()) {
- qWarning("Could not determine printer to print to");
- QFile::remove(tempFile);
- return;
+
+ const int msize = 10000;
+ char buf[msize];
+
+ va_list args;
+ va_start(args, fmt);
+ int bufsize = qvsnprintf(buf, msize, fmt, args);
+
+ Q_ASSERT(bufsize<msize);
+
+ va_end(args);
+
+ stream->writeRawData(buf, bufsize);
+ streampos += bufsize;
+}
+
+int QPdfBaseEnginePrivate::writeCompressed(QIODevice *dev)
+{
+#ifndef QT_NO_COMPRESS
+ if (do_compress) {
+ int size = QPdfPage::chunkSize();
+ int sum = 0;
+ ::z_stream zStruct;
+ zStruct.zalloc = Z_NULL;
+ zStruct.zfree = Z_NULL;
+ zStruct.opaque = Z_NULL;
+ if (::deflateInit(&zStruct, Z_DEFAULT_COMPRESSION) != Z_OK) {
+ qWarning("QPdfStream::writeCompressed: Error in deflateInit()");
+ return sum;
+ }
+ zStruct.avail_in = 0;
+ QByteArray in, out;
+ out.resize(size);
+ while (!dev->atEnd() || zStruct.avail_in != 0) {
+ if (zStruct.avail_in == 0) {
+ in = dev->read(size);
+ zStruct.avail_in = in.size();
+ zStruct.next_in = reinterpret_cast<unsigned char*>(in.data());
+ if (in.size() <= 0) {
+ qWarning("QPdfStream::writeCompressed: Error in read()");
+ ::deflateEnd(&zStruct);
+ return sum;
+ }
}
- prnName = def.printerName().toLocal8Bit();
+ zStruct.next_out = reinterpret_cast<unsigned char*>(out.data());
+ zStruct.avail_out = out.size();
+ if (::deflate(&zStruct, 0) != Z_OK) {
+ qWarning("QPdfStream::writeCompressed: Error in deflate()");
+ ::deflateEnd(&zStruct);
+ return sum;
+ }
+ int written = out.size() - zStruct.avail_out;
+ stream->writeRawData(out.constData(), written);
+ streampos += written;
+ sum += written;
}
+ int ret;
+ do {
+ zStruct.next_out = reinterpret_cast<unsigned char*>(out.data());
+ zStruct.avail_out = out.size();
+ ret = ::deflate(&zStruct, Z_FINISH);
+ if (ret != Z_OK && ret != Z_STREAM_END) {
+ qWarning("QPdfStream::writeCompressed: Error in deflate()");
+ ::deflateEnd(&zStruct);
+ return sum;
+ }
+ int written = out.size() - zStruct.avail_out;
+ stream->writeRawData(out.constData(), written);
+ streampos += written;
+ sum += written;
+ } while (ret == Z_OK);
- if (!cupsStringPageSize.isEmpty()) {
- options.append(QPair<QByteArray, QByteArray>("media", cupsStringPageSize.toLocal8Bit()));
- }
+ ::deflateEnd(&zStruct);
- if (copies > 1) {
- options.append(QPair<QByteArray, QByteArray>("copies", QString::number(copies).toLocal8Bit()));
+ return sum;
+ } else
+#endif
+ {
+ QByteArray arr;
+ int sum = 0;
+ while (!dev->atEnd()) {
+ arr = dev->read(QPdfPage::chunkSize());
+ stream->writeRawData(arr.constData(), arr.size());
+ streampos += arr.size();
+ sum += arr.size();
}
+ return sum;
+ }
+}
- if (collate) {
- options.append(QPair<QByteArray, QByteArray>("Collate", "True"));
+int QPdfBaseEnginePrivate::writeCompressed(const char *src, int len)
+{
+#ifndef QT_NO_COMPRESS
+ if(do_compress) {
+ uLongf destLen = len + len/100 + 13; // zlib requirement
+ Bytef* dest = new Bytef[destLen];
+ if (Z_OK == ::compress(dest, &destLen, (const Bytef*) src, (uLongf)len)) {
+ stream->writeRawData((const char*)dest, destLen);
+ } else {
+ qWarning("QPdfStream::writeCompressed: Error in compress()");
+ destLen = 0;
}
+ delete [] dest;
+ len = destLen;
+ } else
+#endif
+ {
+ stream->writeRawData(src,len);
+ }
+ streampos += len;
+ return len;
+}
- if (duplex != QPrinter::DuplexNone) {
- switch(duplex) {
- case QPrinter::DuplexNone: break;
- case QPrinter::DuplexAuto:
- if (orientation == QPrinter::Portrait)
- options.append(QPair<QByteArray, QByteArray>("sides", "two-sided-long-edge"));
- else
- options.append(QPair<QByteArray, QByteArray>("sides", "two-sided-short-edge"));
- break;
- case QPrinter::DuplexLongSide:
- options.append(QPair<QByteArray, QByteArray>("sides", "two-sided-long-edge"));
- break;
- case QPrinter::DuplexShortSide:
- options.append(QPair<QByteArray, QByteArray>("sides", "two-sided-short-edge"));
+int QPdfBaseEnginePrivate::writeImage(const QByteArray &data, int width, int height, int depth,
+ int maskObject, int softMaskObject, bool dct)
+{
+ int image = addXrefEntry(-1);
+ xprintf("<<\n"
+ "/Type /XObject\n"
+ "/Subtype /Image\n"
+ "/Width %d\n"
+ "/Height %d\n", width, height);
+
+ if (depth == 1) {
+ xprintf("/ImageMask true\n"
+ "/Decode [1 0]\n");
+ } else {
+ xprintf("/BitsPerComponent 8\n"
+ "/ColorSpace %s\n", (depth == 32) ? "/DeviceRGB" : "/DeviceGray");
+ }
+ if (maskObject > 0)
+ xprintf("/Mask %d 0 R\n", maskObject);
+ if (softMaskObject > 0)
+ xprintf("/SMask %d 0 R\n", softMaskObject);
+
+ int lenobj = requestObject();
+ xprintf("/Length %d 0 R\n", lenobj);
+ if (interpolateImages)
+ xprintf("/Interpolate true\n");
+ int len = 0;
+ if (dct) {
+ //qDebug() << "DCT";
+ xprintf("/Filter /DCTDecode\n>>\nstream\n");
+ write(data);
+ len = data.length();
+ } else {
+ if (do_compress)
+ xprintf("/Filter /FlateDecode\n>>\nstream\n");
+ else
+ xprintf(">>\nstream\n");
+ len = writeCompressed(data);
+ }
+ xprintf("endstream\n"
+ "endobj\n");
+ addXrefEntry(lenobj);
+ xprintf("%d\n"
+ "endobj\n", len);
+ return image;
+}
+
+#ifdef USE_NATIVE_GRADIENTS
+int QPdfBaseEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int *gStateObject)
+{
+ const QGradient *gradient = b.gradient();
+ if (!gradient)
+ return 0;
+
+ QTransform inv = matrix.inverted();
+ QPointF page_rect[4] = { inv.map(QPointF(0, 0)),
+ inv.map(QPointF(width_, 0)),
+ inv.map(QPointF(0, height_)),
+ inv.map(QPointF(width_, height_)) };
+
+ bool opaque = b.isOpaque();
+
+ QByteArray shader;
+ QByteArray alphaShader;
+ if (gradient->type() == QGradient::LinearGradient) {
+ const QLinearGradient *lg = static_cast<const QLinearGradient *>(gradient);
+ shader = QPdf::generateLinearGradientShader(lg, page_rect);
+ if (!opaque)
+ alphaShader = QPdf::generateLinearGradientShader(lg, page_rect, true);
+ } else {
+ // #############
+ return 0;
+ }
+ int shaderObject = addXrefEntry(-1);
+ write(shader);
+
+ QByteArray str;
+ QPdf::ByteStream s(&str);
+ s << "<<\n"
+ "/Type /Pattern\n"
+ "/PatternType 2\n"
+ "/Shading " << shaderObject << "0 R\n"
+ "/Matrix ["
+ << matrix.m11()
+ << matrix.m12()
+ << matrix.m21()
+ << matrix.m22()
+ << matrix.dx()
+ << matrix.dy() << "]\n";
+ s << ">>\n"
+ "endobj\n";
+
+ int patternObj = addXrefEntry(-1);
+ write(str);
+ currentPage->patterns.append(patternObj);
+
+ if (!opaque) {
+ bool ca = true;
+ QGradientStops stops = gradient->stops();
+ int a = stops.at(0).second.alpha();
+ for (int i = 1; i < stops.size(); ++i) {
+ if (stops.at(i).second.alpha() != a) {
+ ca = false;
break;
}
}
-
- if (QCUPSSupport::cupsVersion() >= 10300 && orientation == QPrinter::Landscape) {
- options.append(QPair<QByteArray, QByteArray>("landscape", ""));
+ if (ca) {
+ *gStateObject = addConstantAlphaObject(stops.at(0).second.alpha());
+ } else {
+ int alphaShaderObject = addXrefEntry(-1);
+ write(alphaShader);
+
+ QByteArray content;
+ QPdf::ByteStream c(&content);
+ c << "/Shader" << alphaShaderObject << "sh\n";
+
+ QByteArray form;
+ QPdf::ByteStream f(&form);
+ f << "<<\n"
+ "/Type /XObject\n"
+ "/Subtype /Form\n"
+ "/BBox [0 0 " << width_ << height_ << "]\n"
+ "/Group <</S /Transparency >>\n"
+ "/Resources <<\n"
+ "/Shading << /Shader" << alphaShaderObject << alphaShaderObject << "0 R >>\n"
+ ">>\n";
+
+ f << "/Length " << content.length() << "\n"
+ ">>\n"
+ "stream\n"
+ << content
+ << "endstream\n"
+ "endobj\n";
+
+ int softMaskFormObject = addXrefEntry(-1);
+ write(form);
+ *gStateObject = addXrefEntry(-1);
+ xprintf("<< /SMask << /S /Alpha /G %d 0 R >> >>\n"
+ "endobj\n", softMaskFormObject);
+ currentPage->graphicStates.append(*gStateObject);
}
+ }
- QStringList::const_iterator it = cupsOptions.constBegin();
- while (it != cupsOptions.constEnd()) {
- options.append(QPair<QByteArray, QByteArray>((*it).toLocal8Bit(), (*(it+1)).toLocal8Bit()));
- it += 2;
- }
+ return patternObj;
+}
+#endif
- for (int c = 0; c < options.size(); ++c) {
- cups_option_t opt;
- opt.name = options[c].first.data();
- opt.value = options[c].second.data();
- cupsOptStruct.append(opt);
- }
+int QPdfBaseEnginePrivate::addConstantAlphaObject(int brushAlpha, int penAlpha)
+{
+ if (brushAlpha == 255 && penAlpha == 255)
+ return 0;
+ int object = alphaCache.value(QPair<uint, uint>(brushAlpha, penAlpha), 0);
+ if (!object) {
+ object = addXrefEntry(-1);
+ QByteArray alphaDef;
+ QPdf::ByteStream s(&alphaDef);
+ s << "<<\n/ca " << (brushAlpha/qreal(255.)) << '\n';
+ s << "/CA " << (penAlpha/qreal(255.)) << "\n>>";
+ xprintf("%s\nendobj\n", alphaDef.constData());
+ alphaCache.insert(QPair<uint, uint>(brushAlpha, penAlpha), object);
+ }
+ if (currentPage->graphicStates.indexOf(object) < 0)
+ currentPage->graphicStates.append(object);
+
+ return object;
+}
- // Print the file.
- cups_option_t* optPtr = cupsOptStruct.size() ? &cupsOptStruct.first() : 0;
- cups.printFile(prnName.constData(), tempFile.toLocal8Bit().constData(),
- title.toLocal8Bit().constData(), cupsOptStruct.size(), optPtr);
+int QPdfBaseEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor, int *gStateObject)
+{
+ int paintType = 2; // Uncolored tiling
+ int w = 8;
+ int h = 8;
- QFile::remove(tempFile);
- }
+ *specifyColor = true;
+ *gStateObject = 0;
+
+ QTransform matrix = m;
+ matrix.translate(brushOrigin.x(), brushOrigin.y());
+ matrix = matrix * pageMatrix();
+ //qDebug() << brushOrigin << matrix;
+
+ Qt::BrushStyle style = brush.style();
+ if (style == Qt::LinearGradientPattern) {// && style <= Qt::ConicalGradientPattern) {
+#ifdef USE_NATIVE_GRADIENTS
+ *specifyColor = false;
+ return gradientBrush(b, matrix, gStateObject);
+#else
+ return 0;
#endif
+ }
+
+ if ((!brush.isOpaque() && brush.style() < Qt::LinearGradientPattern) || opacity != 1.0)
+ *gStateObject = addConstantAlphaObject(qRound(brush.color().alpha() * opacity),
+ qRound(pen.color().alpha() * opacity));
+
+ int imageObject = -1;
+ QByteArray pattern = QPdf::patternForBrush(brush);
+ if (pattern.isEmpty()) {
+ if (brush.style() != Qt::TexturePattern)
+ return 0;
+ QImage image = brush.texture().toImage();
+ bool bitmap = true;
+ imageObject = addImage(image, &bitmap, brush.texture().cacheKey());
+ if (imageObject != -1) {
+ QImage::Format f = image.format();
+ if (f != QImage::Format_MonoLSB && f != QImage::Format_Mono) {
+ paintType = 1; // Colored tiling
+ *specifyColor = false;
+ }
+ w = image.width();
+ h = image.height();
+ QTransform m(w, 0, 0, -h, 0, h);
+ QPdf::ByteStream s(&pattern);
+ s << QPdf::generateMatrix(m);
+ s << "/Im" << imageObject << " Do\n";
+ }
+ }
+
+ QByteArray str;
+ QPdf::ByteStream s(&str);
+ s << "<<\n"
+ "/Type /Pattern\n"
+ "/PatternType 1\n"
+ "/PaintType " << paintType << "\n"
+ "/TilingType 1\n"
+ "/BBox [0 0 " << w << h << "]\n"
+ "/XStep " << w << "\n"
+ "/YStep " << h << "\n"
+ "/Matrix ["
+ << matrix.m11()
+ << matrix.m12()
+ << matrix.m21()
+ << matrix.m22()
+ << matrix.dx()
+ << matrix.dy() << "]\n"
+ "/Resources \n<< "; // open resource tree
+ if (imageObject > 0) {
+ s << "/XObject << /Im" << imageObject << ' ' << imageObject << "0 R >> ";
+ }
+ s << ">>\n"
+ "/Length " << pattern.length() << "\n"
+ ">>\n"
+ "stream\n"
+ << pattern
+ << "endstream\n"
+ "endobj\n";
+
+ int patternObj = addXrefEntry(-1);
+ write(str);
+ currentPage->patterns.append(patternObj);
+ return patternObj;
}
-QPdfBaseEnginePrivate::~QPdfBaseEnginePrivate()
+/*!
+ * Adds an image to the pdf and return the pdf-object id. Returns -1 if adding the image failed.
+ */
+int QPdfBaseEnginePrivate::addImage(const QImage &img, bool *bitmap, qint64 serial_no)
{
- qDeleteAll(fonts);
- delete currentPage;
+ if (img.isNull())
+ return -1;
+
+ int object = imageCache.value(serial_no);
+ if(object)
+ return object;
+
+ QImage image = img;
+ QImage::Format format = image.format();
+ if (image.depth() == 1 && *bitmap && img.colorTable().size() == 2
+ && img.colorTable().at(0) == QColor(Qt::black).rgba()
+ && img.colorTable().at(1) == QColor(Qt::white).rgba())
+ {
+ if (format == QImage::Format_MonoLSB)
+ image = image.convertToFormat(QImage::Format_Mono);
+ format = QImage::Format_Mono;
+ } else {
+ *bitmap = false;
+ if (format != QImage::Format_RGB32 && format != QImage::Format_ARGB32) {
+ image = image.convertToFormat(QImage::Format_ARGB32);
+ format = QImage::Format_ARGB32;
+ }
+ }
+
+ int w = image.width();
+ int h = image.height();
+ int d = image.depth();
+
+ if (format == QImage::Format_Mono) {
+ int bytesPerLine = (w + 7) >> 3;
+ QByteArray data;
+ data.resize(bytesPerLine * h);
+ char *rawdata = data.data();
+ for (int y = 0; y < h; ++y) {
+ memcpy(rawdata, image.scanLine(y), bytesPerLine);
+ rawdata += bytesPerLine;
+ }
+ object = writeImage(data, w, h, d, 0, 0);
+ } else {
+ QByteArray softMaskData;
+ bool dct = false;
+ QByteArray imageData;
+ bool hasAlpha = false;
+ bool hasMask = false;
+
+ if (QImageWriter::supportedImageFormats().contains("jpeg") && colorMode != QPrinter::GrayScale) {
+ QBuffer buffer(&imageData);
+ QImageWriter writer(&buffer, "jpeg");
+ writer.setQuality(94);
+ writer.write(image);
+ dct = true;
+
+ if (format != QImage::Format_RGB32) {
+ softMaskData.resize(w * h);
+ uchar *sdata = (uchar *)softMaskData.data();
+ for (int y = 0; y < h; ++y) {
+ const QRgb *rgb = (const QRgb *)image.scanLine(y);
+ for (int x = 0; x < w; ++x) {
+ uchar alpha = qAlpha(*rgb);
+ *sdata++ = alpha;
+ hasMask |= (alpha < 255);
+ hasAlpha |= (alpha != 0 && alpha != 255);
+ ++rgb;
+ }
+ }
+ }
+ } else {
+ imageData.resize(colorMode == QPrinter::GrayScale ? w * h : 3 * w * h);
+ uchar *data = (uchar *)imageData.data();
+ softMaskData.resize(w * h);
+ uchar *sdata = (uchar *)softMaskData.data();
+ for (int y = 0; y < h; ++y) {
+ const QRgb *rgb = (const QRgb *)image.scanLine(y);
+ if (colorMode == QPrinter::GrayScale) {
+ for (int x = 0; x < w; ++x) {
+ *(data++) = qGray(*rgb);
+ uchar alpha = qAlpha(*rgb);
+ *sdata++ = alpha;
+ hasMask |= (alpha < 255);
+ hasAlpha |= (alpha != 0 && alpha != 255);
+ ++rgb;
+ }
+ } else {
+ for (int x = 0; x < w; ++x) {
+ *(data++) = qRed(*rgb);
+ *(data++) = qGreen(*rgb);
+ *(data++) = qBlue(*rgb);
+ uchar alpha = qAlpha(*rgb);
+ *sdata++ = alpha;
+ hasMask |= (alpha < 255);
+ hasAlpha |= (alpha != 0 && alpha != 255);
+ ++rgb;
+ }
+ }
+ }
+ if (format == QImage::Format_RGB32)
+ hasAlpha = hasMask = false;
+ }
+ int maskObject = 0;
+ int softMaskObject = 0;
+ if (hasAlpha) {
+ softMaskObject = writeImage(softMaskData, w, h, 8, 0, 0);
+ } else if (hasMask) {
+ // dither the soft mask to 1bit and add it. This also helps PDF viewers
+ // without transparency support
+ int bytesPerLine = (w + 7) >> 3;
+ QByteArray mask(bytesPerLine * h, 0);
+ uchar *mdata = (uchar *)mask.data();
+ const uchar *sdata = (const uchar *)softMaskData.constData();
+ for (int y = 0; y < h; ++y) {
+ for (int x = 0; x < w; ++x) {
+ if (*sdata)
+ mdata[x>>3] |= (0x80 >> (x&7));
+ ++sdata;
+ }
+ mdata += bytesPerLine;
+ }
+ maskObject = writeImage(mask, w, h, 1, 0, 0);
+ }
+ object = writeImage(imageData, w, h, colorMode == QPrinter::GrayScale ? 8 : 32,
+ maskObject, softMaskObject, dct);
+ }
+ imageCache.insert(serial_no, object);
+ return object;
}
void QPdfBaseEnginePrivate::drawTextItem(const QPointF &p, const QTextItemInt &ti)
{
Q_Q(QPdfBaseEngine);
+ if (ti.charFormat.isAnchor()) {
+ qreal size = ti.fontEngine->fontDef.pixelSize;
+#ifdef Q_WS_WIN
+ if (ti.fontEngine->type() == QFontEngine::Win) {
+ QFontEngineWin *fe = static_cast<QFontEngineWin *>(ti.fontEngine);
+ size = fe->tm.tmHeight;
+ }
+#endif
+ int synthesized = ti.fontEngine->synthesized();
+ qreal stretch = synthesized & QFontEngine::SynthesizedStretch ? ti.fontEngine->fontDef.stretch/100. : 1.;
+
+ QTransform trans;
+ // Build text rendering matrix (Trm). We need it to map the text area to user
+ // space units on the PDF page.
+ trans = QTransform(size*stretch, 0, 0, size, 0, 0);
+ // Apply text matrix (Tm).
+ trans *= QTransform(1,0,0,-1,p.x(),p.y());
+ // Apply page displacement (Identity for first page).
+ trans *= stroker.matrix;
+ // Apply Current Transformation Matrix (CTM)
+ trans *= pageMatrix();
+ qreal x1, y1, x2, y2;
+ trans.map(0, 0, &x1, &y1);
+ trans.map(ti.width.toReal()/size, (ti.ascent.toReal()-ti.descent.toReal())/size, &x2, &y2);
+
+ uint annot = addXrefEntry(-1);
+#ifdef Q_DEBUG_PDF_LINKS
+ xprintf("<<\n/Type /Annot\n/Subtype /Link\n/Rect [%f %f %f %f]\n/Border [16 16 1]\n/A <<\n",
+#else
+ xprintf("<<\n/Type /Annot\n/Subtype /Link\n/Rect [%f %f %f %f]\n/Border [0 0 0]\n/A <<\n",
+#endif
+ static_cast<double>(x1),
+ static_cast<double>(y1),
+ static_cast<double>(x2),
+ static_cast<double>(y2));
+ xprintf("/Type /Action\n/S /URI\n/URI (%s)\n",
+ ti.charFormat.anchorHref().toLatin1().constData());
+ xprintf(">>\n>>\n");
+ xprintf("endobj\n");
+
+ if (!currentPage->annotations.contains(annot)) {
+ currentPage->annotations.append(annot);
+ }
+ }
+
QFontEngine *fe = ti.fontEngine;
QFontEngine::FaceId face_id = fe->faceId();
@@ -2024,83 +2682,33 @@ void QPdfBaseEnginePrivate::drawTextItem(const QPointF &p, const QTextItemInt &t
*currentPage << "ET\n";
}
-QRect QPdfBaseEnginePrivate::paperRect() const
+QTransform QPdfBaseEnginePrivate::pageMatrix() const
{
- int w;
- int h;
- if (paperSize == QPrinter::Custom) {
- w = qRound(customPaperSize.width()*resolution/72.);
- h = qRound(customPaperSize.height()*resolution/72.);
- } else {
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
- if (QCUPSSupport::isAvailable() && !cupsPaperRect.isNull()) {
- QRect r = cupsPaperRect;
- w = r.width();
- h = r.height();
- } else
-#endif
- {
- QPdf::PaperSize s = QPdf::paperSize(paperSize);
- w = s.width;
- h = s.height;
- }
- w = qRound(w*resolution/72.);
- h = qRound(h*resolution/72.);
+ qreal scale = 72./resolution;
+ QTransform tmp(scale, 0.0, 0.0, -scale, 0.0, height());
+ if (!fullPage) {
+ QRect r = pageRect();
+ tmp.translate(r.left(), r.top());
}
- if (orientation == QPrinter::Portrait)
- return QRect(0, 0, w, h);
- else
- return QRect(0, 0, h, w);
+ return tmp;
}
-QRect QPdfBaseEnginePrivate::pageRect() const
+void QPdfBaseEnginePrivate::newPage()
{
- if(fullPage)
- return paperRect();
-
- QRect r;
+ if (currentPage && currentPage->pageSize.isEmpty())
+ currentPage->pageSize = QSize(width(), height());
+ writePage();
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
- if (!hasCustomPageMargins && QCUPSSupport::isAvailable() && !cupsPageRect.isNull()) {
- r = cupsPageRect;
- if (r == cupsPaperRect) {
- // if cups doesn't define any margins, give it at least approx 3.5 mm
- r = QRect(10, 10, r.width() - 20, r.height() - 20);
- }
- } else
-#endif
- {
- QPdf::PaperSize s;
- if (paperSize == QPrinter::Custom) {
- s.width = qRound(customPaperSize.width());
- s.height = qRound(customPaperSize.height());
- } else {
- s = QPdf::paperSize(paperSize);
- }
- if (hasCustomPageMargins)
- r = QRect(0, 0, s.width, s.height);
- else
- r = QRect(72/3, 72/3, s.width - 2*72/3, s.height - 2*72/3);
- }
-
- int x = qRound(r.left()*resolution/72.);
- int y = qRound(r.top()*resolution/72.);
- int w = qRound(r.width()*resolution/72.);
- int h = qRound(r.height()*resolution/72.);
- if (orientation == QPrinter::Portrait)
- r = QRect(x, y, w, h);
- else
- r = QRect(y, x, h, w);
-
- if (hasCustomPageMargins) {
- r.adjust(qRound(leftMargin*(resolution/72.)),
- qRound(topMargin*(resolution/72.)),
- -qRound(rightMargin*(resolution/72.)),
- -qRound(bottomMargin*(resolution/72.)));
- }
- return r;
+ delete currentPage;
+ currentPage = new QPdfPage;
+ currentPage->pageSize = QSize(width(), height());
+ stroker.stream = currentPage;
+ pages.append(requestObject());
+
+ *currentPage << "/GSa gs /CSp cs /CSp CS\n"
+ << QPdf::generateMatrix(pageMatrix())
+ << "q q\n";
}
-#endif
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpdf_p.h b/src/gui/painting/qpdf_p.h
index c9e14b6b7b..8efa51743d 100644
--- a/src/gui/painting/qpdf_p.h
+++ b/src/gui/painting/qpdf_p.h
@@ -56,14 +56,12 @@
#include "QtCore/qstring.h"
#include "QtCore/qvector.h"
#include "private/qstroker_p.h"
+#include "private/qpaintengine_alpha_p.h"
#include "private/qfontengine_p.h"
-#include "QtGui/qprinter.h"
#include "private/qfontsubset_p.h"
-#include "private/qpaintengine_alpha_p.h"
-#include "qprintengine.h"
-#include "qbuffer.h"
-#ifndef QT_NO_PRINTER
+// ### remove!
+#include <qprinter.h>
QT_BEGIN_NAMESPACE
@@ -179,7 +177,7 @@ private:
class QPdfBaseEnginePrivate;
-class QPdfBaseEngine : public QAlphaPaintEngine, public QPrintEngine
+class QPdfBaseEngine : public QAlphaPaintEngine
{
Q_DECLARE_PRIVATE(QPdfBaseEngine)
public:
@@ -198,18 +196,22 @@ public:
void drawTextItem(const QPointF &p, const QTextItem &textItem);
+ void drawPixmap (const QRectF & rectangle, const QPixmap & pixmap, const QRectF & sr);
+ void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
+ Qt::ImageConversionFlags flags = Qt::AutoColor);
+ void drawTiledPixmap (const QRectF & rectangle, const QPixmap & pixmap, const QPointF & point);
+
void updateState(const QPaintEngineState &state);
int metric(QPaintDevice::PaintDeviceMetric metricType) const;
+ Type type() const;
// end reimplementations QPaintEngine
// Printer stuff...
bool newPage();
- void setProperty(PrintEnginePropertyKey key, const QVariant &value);
- QVariant property(PrintEnginePropertyKey key) const;
void setPen();
- virtual void setBrush() = 0;
+ void setBrush();
void setupGraphicsState(QPaintEngine::DirtyFlags flags);
private:
@@ -223,16 +225,33 @@ public:
QPdfBaseEnginePrivate(QPrinter::PrinterMode m);
~QPdfBaseEnginePrivate();
- bool openPrintDevice();
- void closePrintDevice();
-
-
- virtual void drawTextItem(const QPointF &p, const QTextItemInt &ti);
inline uint requestObject() { return currentObject++; }
QRect paperRect() const;
QRect pageRect() const;
+ int width() const {
+ QRect r = paperRect();
+ return qRound(r.width()*72./resolution);
+ }
+ int height() const {
+ QRect r = paperRect();
+ return qRound(r.height()*72./resolution);
+ }
+
+ void writeHeader();
+ void writeTail();
+
+ int addImage(const QImage &image, bool *bitmap, qint64 serial_no);
+ int addConstantAlphaObject(int brushAlpha, int penAlpha = 255);
+ int addBrushPattern(const QTransform &matrix, bool *specifyColor, int *gStateObject);
+
+ void drawTextItem(const QPointF &p, const QTextItemInt &ti);
+
+ QTransform pageMatrix() const;
+
+ void newPage();
+
bool postscript;
int currentObject;
@@ -289,11 +308,45 @@ public:
#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
QString cupsTempFile;
#endif
+
+private:
+#ifdef USE_NATIVE_GRADIENTS
+ int gradientBrush(const QBrush &b, const QMatrix &matrix, int *gStateObject);
+#endif
+
+ void writeInfo();
+ void writePageRoot();
+ void writeFonts();
+ void embedFont(QFontSubset *font);
+
+ QVector<int> xrefPositions;
+ QDataStream* stream;
+ int streampos;
+
+ int writeImage(const QByteArray &data, int width, int height, int depth,
+ int maskObject, int softMaskObject, bool dct = false);
+ void writePage();
+
+ int addXrefEntry(int object, bool printostr = true);
+ void printString(const QString &string);
+ void xprintf(const char* fmt, ...);
+ inline void write(const QByteArray &data) {
+ stream->writeRawData(data.constData(), data.size());
+ streampos += data.size();
+ }
+
+ int writeCompressed(const char *src, int len);
+ inline int writeCompressed(const QByteArray &data) { return writeCompressed(data.constData(), data.length()); }
+ int writeCompressed(QIODevice *dev);
+
+ // various PDF objects
+ int pageRoot, catalog, info, graphicsState, patternColorSpace;
+ QVector<uint> pages;
+ QHash<qint64, uint> imageCache;
+ QHash<QPair<uint, uint>, uint > alphaCache;
};
QT_END_NAMESPACE
-#endif // QT_NO_PRINTER
-
#endif // QPDF_P_H
diff --git a/src/gui/painting/qprintengine_pdf.cpp b/src/gui/painting/qprintengine_pdf.cpp
index 4b5d41cf1c..b796cd59e7 100644
--- a/src/gui/painting/qprintengine_pdf.cpp
+++ b/src/gui/painting/qprintengine_pdf.cpp
@@ -42,22 +42,15 @@
#include <QtGui/qprintengine.h>
#include <qiodevice.h>
-#include <qpainter.h>
-#include <qbitmap.h>
-#include <qpainterpath.h>
-#include <qpaintdevice.h>
#include <qfile.h>
#include <qdebug.h>
-#include <qimagewriter.h>
#include <qbuffer.h>
-#include <qdatetime.h>
+#include "private/qcups_p.h"
+#include "qprinterinfo.h"
#ifndef QT_NO_PRINTER
#include <limits.h>
#include <math.h>
-#ifndef QT_NO_COMPRESS
-#include <zlib.h>
-#endif
#if defined(Q_OS_WINCE)
#include "qwinfunctions_wince.h"
@@ -66,31 +59,13 @@
#include "qprintengine_pdf_p.h"
#include "private/qdrawhelper_p.h"
-QT_BEGIN_NAMESPACE
-
-//#define FONT_DUMP
-
-// might be helpful for smooth transforms of images
-// Can't use it though, as gs generates completely wrong images if this is true.
-static const bool interpolateImages = false;
-
-#ifdef QT_NO_COMPRESS
-static const bool do_compress = false;
-#else
-static const bool do_compress = true;
+#ifdef Q_OS_UNIX
+#include "private/qcore_unix_p.h" // overrides QT_OPEN
#endif
-QPdfPage::QPdfPage()
- : QPdf::ByteStream(true) // Enable file backing
-{
-}
+QT_BEGIN_NAMESPACE
-void QPdfPage::streamImage(int w, int h, int object)
-{
- *this << w << "0 0 " << -h << "0 " << h << "cm /Im" << object << " Do\n";
- if (!images.contains(object))
- images.append(object);
-}
+//#define FONT_DUMP
inline QPaintEngine::PaintEngineFeatures qt_pdf_decide_features()
@@ -109,6 +84,32 @@ inline QPaintEngine::PaintEngineFeatures qt_pdf_decide_features()
QPdfEngine::QPdfEngine(QPrinter::PrinterMode m)
: QPdfBaseEngine(*new QPdfEnginePrivate(m), qt_pdf_decide_features())
{
+ Q_D(QPdfEngine);
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ if (QCUPSSupport::isAvailable()) {
+ QCUPSSupport cups;
+ const cups_dest_t* printers = cups.availablePrinters();
+ int prnCount = cups.availablePrintersCount();
+
+ for (int i = 0; i < prnCount; ++i) {
+ if (printers[i].is_default) {
+ d->printerName = QString::fromLocal8Bit(printers[i].name);
+ break;
+ }
+ }
+
+ } else
+#endif
+ {
+ d->printerName = QString::fromLocal8Bit(qgetenv("PRINTER"));
+ if (d->printerName.isEmpty())
+ d->printerName = QString::fromLocal8Bit(qgetenv("LPDEST"));
+ if (d->printerName.isEmpty())
+ d->printerName = QString::fromLocal8Bit(qgetenv("NPRINTER"));
+ if (d->printerName.isEmpty())
+ d->printerName = QString::fromLocal8Bit(qgetenv("NGPRINTER"));
+ }
+
state = QPrinter::Idle;
}
@@ -120,1121 +121,514 @@ bool QPdfEngine::begin(QPaintDevice *pdev)
{
Q_D(QPdfEngine);
- if(!QPdfBaseEngine::begin(pdev)) {
+ if (!d->openPrintDevice()) {
state = QPrinter::Error;
return false;
}
- d->stream->setDevice(d->outDevice);
-
- d->streampos = 0;
- d->hasPen = true;
- d->hasBrush = false;
- d->clipEnabled = false;
- d->allClipped = false;
-
- d->xrefPositions.clear();
- d->pageRoot = 0;
- d->catalog = 0;
- d->info = 0;
- d->graphicsState = 0;
- d->patternColorSpace = 0;
-
- d->pages.clear();
- d->imageCache.clear();
-
- setActive(true);
state = QPrinter::Active;
- d->writeHeader();
- newPage();
- return true;
+ return QPdfBaseEngine::begin(pdev);
}
bool QPdfEngine::end()
{
Q_D(QPdfEngine);
- d->writeTail();
- d->stream->unsetDevice();
QPdfBaseEngine::end();
- setActive(false);
- state = QPrinter::Idle;
- return true;
-}
-
-
-void QPdfEngine::drawPixmap (const QRectF &rectangle, const QPixmap &pixmap, const QRectF &sr)
-{
- if (sr.isEmpty() || rectangle.isEmpty() || pixmap.isNull())
- return;
- Q_D(QPdfEngine);
-
- QBrush b = d->brush;
-
- QRect sourceRect = sr.toRect();
- 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());
- if (object < 0)
- return;
-
- *d->currentPage << "q\n/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));
- if (bitmap) {
- // set current pen as d->brush
- d->brush = d->pen.brush();
- }
- setBrush();
- d->currentPage->streamImage(image.width(), image.height(), object);
- *d->currentPage << "Q\n";
-
- d->brush = b;
-}
-
-void QPdfEngine::drawImage(const QRectF &rectangle, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags)
-{
- if (sr.isEmpty() || rectangle.isEmpty() || image.isNull())
- return;
- Q_D(QPdfEngine);
-
- 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());
- if (object < 0)
- return;
-
- *d->currentPage << "q\n/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));
- setBrush();
- d->currentPage->streamImage(im.width(), im.height(), object);
- *d->currentPage << "Q\n";
-}
-
-void QPdfEngine::drawTiledPixmap (const QRectF &rectangle, const QPixmap &pixmap, const QPointF &point)
-{
- Q_D(QPdfEngine);
-
- bool bitmap = (pixmap.depth() == 1);
- QBrush b = d->brush;
- QPointF bo = d->brushOrigin;
- bool hp = d->hasPen;
- d->hasPen = false;
- bool hb = d->hasBrush;
- d->hasBrush = true;
-
- d->brush = QBrush(pixmap);
- if (bitmap)
- // #### fix bitmap case where we have a brush pen
- d->brush.setColor(d->pen.color());
-
- d->brushOrigin = -point;
- *d->currentPage << "q\n";
- setBrush();
-
- drawRects(&rectangle, 1);
- *d->currentPage << "Q\n";
-
- d->hasPen = hp;
- d->hasBrush = hb;
- d->brush = b;
- d->brushOrigin = bo;
-}
-
-
-void QPdfEngine::setBrush()
-{
- Q_D(QPdfEngine);
- Qt::BrushStyle style = d->brush.style();
- if (style == Qt::NoBrush)
- return;
-
- bool specifyColor;
- int gStateObject = 0;
- int patternObject = d->addBrushPattern(d->stroker.matrix, &specifyColor, &gStateObject);
-
- *d->currentPage << (patternObject ? "/PCSp cs " : "/CSp cs ");
- if (specifyColor) {
- QColor rgba = d->brush.color();
- if (d->colorMode == QPrinter::GrayScale) {
- qreal gray = qGray(rgba.rgba())/255.;
- *d->currentPage << gray << gray << gray;
- } else {
- *d->currentPage << rgba.redF()
- << rgba.greenF()
- << rgba.blueF();
- }
- }
- if (patternObject)
- *d->currentPage << "/Pat" << patternObject;
- *d->currentPage << "scn\n";
- if (gStateObject)
- *d->currentPage << "/GState" << gStateObject << "gs\n";
- else
- *d->currentPage << "/GSa gs\n";
-}
+ d->closePrintDevice();
+ state = QPrinter::Idle;
-QPaintEngine::Type QPdfEngine::type() const
-{
- return QPaintEngine::Pdf;
+ return true;
}
bool QPdfEngine::newPage()
{
- Q_D(QPdfEngine);
- if (!isActive())
- return false;
- d->newPage();
return QPdfBaseEngine::newPage();
}
-QPdfEnginePrivate::QPdfEnginePrivate(QPrinter::PrinterMode m)
- : QPdfBaseEnginePrivate(m)
-{
- streampos = 0;
-
- stream = new QDataStream;
- pageOrder = QPrinter::FirstPageFirst;
- orientation = QPrinter::Portrait;
- fullPage = false;
-}
-
-QPdfEnginePrivate::~QPdfEnginePrivate()
-{
- delete stream;
-}
-
-
-#ifdef USE_NATIVE_GRADIENTS
-int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int *gStateObject)
-{
- const QGradient *gradient = b.gradient();
- if (!gradient)
- return 0;
-
- QTransform inv = matrix.inverted();
- QPointF page_rect[4] = { inv.map(QPointF(0, 0)),
- inv.map(QPointF(width_, 0)),
- inv.map(QPointF(0, height_)),
- inv.map(QPointF(width_, height_)) };
-
- bool opaque = b.isOpaque();
-
- QByteArray shader;
- QByteArray alphaShader;
- if (gradient->type() == QGradient::LinearGradient) {
- const QLinearGradient *lg = static_cast<const QLinearGradient *>(gradient);
- shader = QPdf::generateLinearGradientShader(lg, page_rect);
- if (!opaque)
- alphaShader = QPdf::generateLinearGradientShader(lg, page_rect, true);
- } else {
- // #############
- return 0;
+int QPdfEngine::metric(QPaintDevice::PaintDeviceMetric m) const
+{
+ return QPdfBaseEngine::metric(m);
+}
+
+void QPdfEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value)
+{
+ Q_D(QPdfBaseEngine);
+ switch (int(key)) {
+ case PPK_CollateCopies:
+ d->collate = value.toBool();
+ break;
+ case PPK_ColorMode:
+ d->colorMode = QPrinter::ColorMode(value.toInt());
+ break;
+ case PPK_Creator:
+ d->creator = value.toString();
+ break;
+ case PPK_DocumentName:
+ d->title = value.toString();
+ break;
+ case PPK_FullPage:
+ d->fullPage = value.toBool();
+ break;
+ case PPK_CopyCount: // fallthrough
+ case PPK_NumberOfCopies:
+ d->copies = value.toInt();
+ break;
+ case PPK_Orientation:
+ d->orientation = QPrinter::Orientation(value.toInt());
+ break;
+ case PPK_OutputFileName:
+ d->outputFileName = value.toString();
+ break;
+ case PPK_PageOrder:
+ d->pageOrder = QPrinter::PageOrder(value.toInt());
+ break;
+ case PPK_PaperSize:
+ d->paperSize = QPrinter::PaperSize(value.toInt());
+ break;
+ case PPK_PaperSource:
+ d->paperSource = QPrinter::PaperSource(value.toInt());
+ break;
+ case PPK_PrinterName:
+ d->printerName = value.toString();
+ break;
+ case PPK_PrinterProgram:
+ d->printProgram = value.toString();
+ break;
+ case PPK_Resolution:
+ d->resolution = value.toInt();
+ break;
+ case PPK_SelectionOption:
+ d->selectionOption = value.toString();
+ break;
+ case PPK_FontEmbedding:
+ d->embedFonts = value.toBool();
+ break;
+ case PPK_Duplex:
+ d->duplex = static_cast<QPrinter::DuplexMode> (value.toInt());
+ break;
+ case PPK_CupsPageRect:
+ d->cupsPageRect = value.toRect();
+ break;
+ case PPK_CupsPaperRect:
+ d->cupsPaperRect = value.toRect();
+ break;
+ case PPK_CupsOptions:
+ d->cupsOptions = value.toStringList();
+ break;
+ case PPK_CupsStringPageSize:
+ d->cupsStringPageSize = value.toString();
+ break;
+ case PPK_CustomPaperSize:
+ d->paperSize = QPrinter::Custom;
+ d->customPaperSize = value.toSizeF();
+ break;
+ case PPK_PageMargins:
+ {
+ QList<QVariant> margins(value.toList());
+ Q_ASSERT(margins.size() == 4);
+ d->leftMargin = margins.at(0).toReal();
+ d->topMargin = margins.at(1).toReal();
+ d->rightMargin = margins.at(2).toReal();
+ d->bottomMargin = margins.at(3).toReal();
+ d->hasCustomPageMargins = true;
+ break;
}
- int shaderObject = addXrefEntry(-1);
- write(shader);
-
- QByteArray str;
- QPdf::ByteStream s(&str);
- s << "<<\n"
- "/Type /Pattern\n"
- "/PatternType 2\n"
- "/Shading " << shaderObject << "0 R\n"
- "/Matrix ["
- << matrix.m11()
- << matrix.m12()
- << matrix.m21()
- << matrix.m22()
- << matrix.dx()
- << matrix.dy() << "]\n";
- s << ">>\n"
- "endobj\n";
-
- int patternObj = addXrefEntry(-1);
- write(str);
- currentPage->patterns.append(patternObj);
+ default:
+ break;
+ }
+}
- if (!opaque) {
- bool ca = true;
- QGradientStops stops = gradient->stops();
- int a = stops.at(0).second.alpha();
- for (int i = 1; i < stops.size(); ++i) {
- if (stops.at(i).second.alpha() != a) {
- ca = false;
- break;
- }
- }
- if (ca) {
- *gStateObject = addConstantAlphaObject(stops.at(0).second.alpha());
+QVariant QPdfEngine::property(PrintEnginePropertyKey key) const
+{
+ Q_D(const QPdfBaseEngine);
+
+ QVariant ret;
+ switch (int(key)) {
+ case PPK_CollateCopies:
+ ret = d->collate;
+ break;
+ case PPK_ColorMode:
+ ret = d->colorMode;
+ break;
+ case PPK_Creator:
+ ret = d->creator;
+ break;
+ case PPK_DocumentName:
+ ret = d->title;
+ break;
+ case PPK_FullPage:
+ ret = d->fullPage;
+ break;
+ case PPK_CopyCount:
+ ret = d->copies;
+ break;
+ case PPK_SupportsMultipleCopies:
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ if (QCUPSSupport::isAvailable())
+ ret = true;
+ else
+#endif
+ ret = false;
+ break;
+ case PPK_NumberOfCopies:
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ if (QCUPSSupport::isAvailable())
+ ret = 1;
+ else
+#endif
+ ret = d->copies;
+ break;
+ case PPK_Orientation:
+ ret = d->orientation;
+ break;
+ case PPK_OutputFileName:
+ ret = d->outputFileName;
+ break;
+ case PPK_PageOrder:
+ ret = d->pageOrder;
+ break;
+ case PPK_PaperSize:
+ ret = d->paperSize;
+ break;
+ case PPK_PaperSource:
+ ret = d->paperSource;
+ break;
+ case PPK_PrinterName:
+ ret = d->printerName;
+ break;
+ case PPK_PrinterProgram:
+ ret = d->printProgram;
+ break;
+ case PPK_Resolution:
+ ret = d->resolution;
+ break;
+ case PPK_SupportedResolutions:
+ ret = QList<QVariant>() << 72;
+ break;
+ case PPK_PaperRect:
+ ret = d->paperRect();
+ break;
+ case PPK_PageRect:
+ ret = d->pageRect();
+ break;
+ case PPK_SelectionOption:
+ ret = d->selectionOption;
+ break;
+ case PPK_FontEmbedding:
+ ret = d->embedFonts;
+ break;
+ case PPK_Duplex:
+ ret = d->duplex;
+ break;
+ case PPK_CupsPageRect:
+ ret = d->cupsPageRect;
+ break;
+ case PPK_CupsPaperRect:
+ ret = d->cupsPaperRect;
+ break;
+ case PPK_CupsOptions:
+ ret = d->cupsOptions;
+ break;
+ case PPK_CupsStringPageSize:
+ ret = d->cupsStringPageSize;
+ break;
+ case PPK_CustomPaperSize:
+ ret = d->customPaperSize;
+ break;
+ case PPK_PageMargins:
+ {
+ QList<QVariant> margins;
+ if (d->hasCustomPageMargins) {
+ margins << d->leftMargin << d->topMargin
+ << d->rightMargin << d->bottomMargin;
} else {
- int alphaShaderObject = addXrefEntry(-1);
- write(alphaShader);
-
- QByteArray content;
- QPdf::ByteStream c(&content);
- c << "/Shader" << alphaShaderObject << "sh\n";
-
- QByteArray form;
- QPdf::ByteStream f(&form);
- f << "<<\n"
- "/Type /XObject\n"
- "/Subtype /Form\n"
- "/BBox [0 0 " << width_ << height_ << "]\n"
- "/Group <</S /Transparency >>\n"
- "/Resources <<\n"
- "/Shading << /Shader" << alphaShaderObject << alphaShaderObject << "0 R >>\n"
- ">>\n";
-
- f << "/Length " << content.length() << "\n"
- ">>\n"
- "stream\n"
- << content
- << "endstream\n"
- "endobj\n";
-
- int softMaskFormObject = addXrefEntry(-1);
- write(form);
- *gStateObject = addXrefEntry(-1);
- xprintf("<< /SMask << /S /Alpha /G %d 0 R >> >>\n"
- "endobj\n", softMaskFormObject);
- currentPage->graphicStates.append(*gStateObject);
+ const qreal defaultMargin = 10; // ~3.5 mm
+ margins << defaultMargin << defaultMargin
+ << defaultMargin << defaultMargin;
}
+ ret = margins;
+ break;
}
-
- return patternObj;
-}
-#endif
-
-int QPdfEnginePrivate::addConstantAlphaObject(int brushAlpha, int penAlpha)
-{
- if (brushAlpha == 255 && penAlpha == 255)
- return 0;
- int object = alphaCache.value(QPair<uint, uint>(brushAlpha, penAlpha), 0);
- if (!object) {
- object = addXrefEntry(-1);
- QByteArray alphaDef;
- QPdf::ByteStream s(&alphaDef);
- s << "<<\n/ca " << (brushAlpha/qreal(255.)) << '\n';
- s << "/CA " << (penAlpha/qreal(255.)) << "\n>>";
- xprintf("%s\nendobj\n", alphaDef.constData());
- alphaCache.insert(QPair<uint, uint>(brushAlpha, penAlpha), object);
+ default:
+ break;
}
- if (currentPage->graphicStates.indexOf(object) < 0)
- currentPage->graphicStates.append(object);
-
- return object;
+ return ret;
}
-int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor, int *gStateObject)
-{
- int paintType = 2; // Uncolored tiling
- int w = 8;
- int h = 8;
-
- *specifyColor = true;
- *gStateObject = 0;
- QTransform matrix = m;
- matrix.translate(brushOrigin.x(), brushOrigin.y());
- matrix = matrix * pageMatrix();
- //qDebug() << brushOrigin << matrix;
-
- Qt::BrushStyle style = brush.style();
- if (style == Qt::LinearGradientPattern) {// && style <= Qt::ConicalGradientPattern) {
-#ifdef USE_NATIVE_GRADIENTS
- *specifyColor = false;
- return gradientBrush(b, matrix, gStateObject);
+#ifndef QT_NO_LPR
+static void closeAllOpenFds()
+{
+ // hack time... getting the maximum number of open
+ // files, if possible. if not we assume it's the
+ // larger of 256 and the fd we got
+ int i;
+#if defined(_SC_OPEN_MAX)
+ i = (int)sysconf(_SC_OPEN_MAX);
+#elif defined(_POSIX_OPEN_MAX)
+ i = (int)_POSIX_OPEN_MAX;
+#elif defined(OPEN_MAX)
+ i = (int)OPEN_MAX;
#else
- return 0;
+ i = 256;
#endif
- }
-
- if ((!brush.isOpaque() && brush.style() < Qt::LinearGradientPattern) || opacity != 1.0)
- *gStateObject = addConstantAlphaObject(qRound(brush.color().alpha() * opacity),
- qRound(pen.color().alpha() * opacity));
-
- int imageObject = -1;
- QByteArray pattern = QPdf::patternForBrush(brush);
- if (pattern.isEmpty()) {
- if (brush.style() != Qt::TexturePattern)
- return 0;
- QImage image = brush.texture().toImage();
- bool bitmap = true;
- imageObject = addImage(image, &bitmap, brush.texture().cacheKey());
- if (imageObject != -1) {
- QImage::Format f = image.format();
- if (f != QImage::Format_MonoLSB && f != QImage::Format_Mono) {
- paintType = 1; // Colored tiling
- *specifyColor = false;
- }
- w = image.width();
- h = image.height();
- QTransform m(w, 0, 0, -h, 0, h);
- QPdf::ByteStream s(&pattern);
- s << QPdf::generateMatrix(m);
- s << "/Im" << imageObject << " Do\n";
- }
- }
-
- QByteArray str;
- QPdf::ByteStream s(&str);
- s << "<<\n"
- "/Type /Pattern\n"
- "/PatternType 1\n"
- "/PaintType " << paintType << "\n"
- "/TilingType 1\n"
- "/BBox [0 0 " << w << h << "]\n"
- "/XStep " << w << "\n"
- "/YStep " << h << "\n"
- "/Matrix ["
- << matrix.m11()
- << matrix.m12()
- << matrix.m21()
- << matrix.m22()
- << matrix.dx()
- << matrix.dy() << "]\n"
- "/Resources \n<< "; // open resource tree
- if (imageObject > 0) {
- s << "/XObject << /Im" << imageObject << ' ' << imageObject << "0 R >> ";
- }
- s << ">>\n"
- "/Length " << pattern.length() << "\n"
- ">>\n"
- "stream\n"
- << pattern
- << "endstream\n"
- "endobj\n";
-
- int patternObj = addXrefEntry(-1);
- write(str);
- currentPage->patterns.append(patternObj);
- return patternObj;
+ // leave stdin/out/err untouched
+ while(--i > 2)
+ QT_CLOSE(i);
}
+#endif
-/*!
- * 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)
+bool QPdfEnginePrivate::openPrintDevice()
{
- if (img.isNull())
- return -1;
-
- int object = imageCache.value(serial_no);
- if(object)
- return object;
+ if(outDevice)
+ return false;
- QImage image = img;
- QImage::Format format = image.format();
- if (image.depth() == 1 && *bitmap && img.colorTable().size() == 2
- && img.colorTable().at(0) == QColor(Qt::black).rgba()
- && img.colorTable().at(1) == QColor(Qt::white).rgba())
- {
- if (format == QImage::Format_MonoLSB)
- image = image.convertToFormat(QImage::Format_Mono);
- format = QImage::Format_Mono;
- } else {
- *bitmap = false;
- if (format != QImage::Format_RGB32 && format != QImage::Format_ARGB32) {
- image = image.convertToFormat(QImage::Format_ARGB32);
- format = QImage::Format_ARGB32;
+ if (!outputFileName.isEmpty()) {
+ QFile *file = new QFile(outputFileName);
+ if (! file->open(QFile::WriteOnly|QFile::Truncate)) {
+ delete file;
+ return false;
}
- }
-
- int w = image.width();
- int h = image.height();
- int d = image.depth();
-
- if (format == QImage::Format_Mono) {
- int bytesPerLine = (w + 7) >> 3;
- QByteArray data;
- data.resize(bytesPerLine * h);
- char *rawdata = data.data();
- for (int y = 0; y < h; ++y) {
- memcpy(rawdata, image.scanLine(y), bytesPerLine);
- rawdata += bytesPerLine;
+ outDevice = file;
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ } else if (QCUPSSupport::isAvailable()) {
+ QCUPSSupport cups;
+ QPair<int, QString> ret = cups.tempFd();
+ if (ret.first < 0) {
+ qWarning("QPdfPrinter: Could not open temporary file to print");
+ return false;
}
- object = writeImage(data, w, h, d, 0, 0);
+ cupsTempFile = ret.second;
+ outDevice = new QFile();
+ static_cast<QFile *>(outDevice)->open(ret.first, QIODevice::WriteOnly);
+#endif
+#ifndef QT_NO_LPR
} else {
- QByteArray softMaskData;
- bool dct = false;
- QByteArray imageData;
- bool hasAlpha = false;
- bool hasMask = false;
-
- if (QImageWriter::supportedImageFormats().contains("jpeg") && colorMode != QPrinter::GrayScale) {
- QBuffer buffer(&imageData);
- QImageWriter writer(&buffer, "jpeg");
- writer.setQuality(94);
- writer.write(image);
- dct = true;
+ QString pr;
+ if (!printerName.isEmpty())
+ pr = printerName;
+ int fds[2];
+ if (qt_safe_pipe(fds) != 0) {
+ qWarning("QPdfPrinter: Could not open pipe to print");
+ return false;
+ }
- if (format != QImage::Format_RGB32) {
- softMaskData.resize(w * h);
- uchar *sdata = (uchar *)softMaskData.data();
- for (int y = 0; y < h; ++y) {
- const QRgb *rgb = (const QRgb *)image.scanLine(y);
- for (int x = 0; x < w; ++x) {
- uchar alpha = qAlpha(*rgb);
- *sdata++ = alpha;
- hasMask |= (alpha < 255);
- hasAlpha |= (alpha != 0 && alpha != 255);
- ++rgb;
- }
- }
+ pid_t pid = fork();
+ if (pid == 0) { // child process
+ // if possible, exit quickly, so the actual lp/lpr
+ // becomes a child of init, and ::waitpid() is
+ // guaranteed not to wait.
+ if (fork() > 0) {
+ closeAllOpenFds();
+
+ // try to replace this process with "true" - this prevents
+ // global destructors from being called (that could possibly
+ // do wrong things to the parent process)
+ (void)execlp("true", "true", (char *)0);
+ (void)execl("/bin/true", "true", (char *)0);
+ (void)execl("/usr/bin/true", "true", (char *)0);
+ ::_exit(0);
}
- } else {
- imageData.resize(colorMode == QPrinter::GrayScale ? w * h : 3 * w * h);
- uchar *data = (uchar *)imageData.data();
- softMaskData.resize(w * h);
- uchar *sdata = (uchar *)softMaskData.data();
- for (int y = 0; y < h; ++y) {
- const QRgb *rgb = (const QRgb *)image.scanLine(y);
- if (colorMode == QPrinter::GrayScale) {
- for (int x = 0; x < w; ++x) {
- *(data++) = qGray(*rgb);
- uchar alpha = qAlpha(*rgb);
- *sdata++ = alpha;
- hasMask |= (alpha < 255);
- hasAlpha |= (alpha != 0 && alpha != 255);
- ++rgb;
- }
- } else {
- for (int x = 0; x < w; ++x) {
- *(data++) = qRed(*rgb);
- *(data++) = qGreen(*rgb);
- *(data++) = qBlue(*rgb);
- uchar alpha = qAlpha(*rgb);
- *sdata++ = alpha;
- hasMask |= (alpha < 255);
- hasAlpha |= (alpha != 0 && alpha != 255);
- ++rgb;
+ qt_safe_dup2(fds[0], 0, 0);
+
+ closeAllOpenFds();
+
+ if (!printProgram.isEmpty()) {
+ if (!selectionOption.isEmpty())
+ pr.prepend(selectionOption);
+ else
+ pr.prepend(QLatin1String("-P"));
+ (void)execlp(printProgram.toLocal8Bit().data(), printProgram.toLocal8Bit().data(),
+ pr.toLocal8Bit().data(), (char *)0);
+ } else {
+ // if no print program has been specified, be smart
+ // about the option string too.
+ QList<QByteArray> lprhack;
+ QList<QByteArray> lphack;
+ QByteArray media;
+ if (!pr.isEmpty() || !selectionOption.isEmpty()) {
+ if (!selectionOption.isEmpty()) {
+ QStringList list = selectionOption.split(QLatin1Char(' '));
+ for (int i = 0; i < list.size(); ++i)
+ lprhack.append(list.at(i).toLocal8Bit());
+ lphack = lprhack;
+ } else {
+ lprhack.append("-P");
+ lphack.append("-d");
}
+ lprhack.append(pr.toLocal8Bit());
+ lphack.append(pr.toLocal8Bit());
}
- }
- if (format == QImage::Format_RGB32)
- hasAlpha = hasMask = false;
- }
- int maskObject = 0;
- int softMaskObject = 0;
- if (hasAlpha) {
- softMaskObject = writeImage(softMaskData, w, h, 8, 0, 0);
- } else if (hasMask) {
- // dither the soft mask to 1bit and add it. This also helps PDF viewers
- // without transparency support
- int bytesPerLine = (w + 7) >> 3;
- QByteArray mask(bytesPerLine * h, 0);
- uchar *mdata = (uchar *)mask.data();
- const uchar *sdata = (const uchar *)softMaskData.constData();
- for (int y = 0; y < h; ++y) {
- for (int x = 0; x < w; ++x) {
- if (*sdata)
- mdata[x>>3] |= (0x80 >> (x&7));
- ++sdata;
+ lphack.append("-s");
+
+ char ** lpargs = new char *[lphack.size()+6];
+ char lp[] = "lp";
+ lpargs[0] = lp;
+ int i;
+ for (i = 0; i < lphack.size(); ++i)
+ lpargs[i+1] = (char *)lphack.at(i).constData();
+#ifndef Q_OS_OSF
+ if (QPdf::paperSizeToString(paperSize)) {
+ char dash_o[] = "-o";
+ lpargs[++i] = dash_o;
+ lpargs[++i] = const_cast<char *>(QPdf::paperSizeToString(paperSize));
+ lpargs[++i] = dash_o;
+ media = "media=";
+ media += QPdf::paperSizeToString(paperSize);
+ lpargs[++i] = media.data();
}
- mdata += bytesPerLine;
+#endif
+ lpargs[++i] = 0;
+ char **lprargs = new char *[lprhack.size()+2];
+ char lpr[] = "lpr";
+ lprargs[0] = lpr;
+ for (int i = 0; i < lprhack.size(); ++i)
+ lprargs[i+1] = (char *)lprhack[i].constData();
+ lprargs[lprhack.size() + 1] = 0;
+ (void)execvp("lp", lpargs);
+ (void)execvp("lpr", lprargs);
+ (void)execv("/bin/lp", lpargs);
+ (void)execv("/bin/lpr", lprargs);
+ (void)execv("/usr/bin/lp", lpargs);
+ (void)execv("/usr/bin/lpr", lprargs);
+
+ delete []lpargs;
+ delete []lprargs;
}
- maskObject = writeImage(mask, w, h, 1, 0, 0);
- }
- object = writeImage(imageData, w, h, colorMode == QPrinter::GrayScale ? 8 : 32,
- maskObject, softMaskObject, dct);
- }
- imageCache.insert(serial_no, object);
- return object;
-}
-
-void QPdfEnginePrivate::drawTextItem(const QPointF &p, const QTextItemInt &ti)
-{
- if (ti.charFormat.isAnchor()) {
- qreal size = ti.fontEngine->fontDef.pixelSize;
-#ifdef Q_WS_WIN
- if (ti.fontEngine->type() == QFontEngine::Win) {
- QFontEngineWin *fe = static_cast<QFontEngineWin *>(ti.fontEngine);
- size = fe->tm.tmHeight;
+ // if we couldn't exec anything, close the fd,
+ // wait for a second so the parent process (the
+ // child of the GUI process) has exited. then
+ // exit.
+ QT_CLOSE(0);
+ (void)::sleep(1);
+ ::_exit(0);
}
-#endif
- int synthesized = ti.fontEngine->synthesized();
- qreal stretch = synthesized & QFontEngine::SynthesizedStretch ? ti.fontEngine->fontDef.stretch/100. : 1.;
+ // parent process
+ QT_CLOSE(fds[0]);
+ fd = fds[1];
+ (void)qt_safe_waitpid(pid, 0, 0);
- QTransform trans;
- // Build text rendering matrix (Trm). We need it to map the text area to user
- // space units on the PDF page.
- trans = QTransform(size*stretch, 0, 0, size, 0, 0);
- // Apply text matrix (Tm).
- trans *= QTransform(1,0,0,-1,p.x(),p.y());
- // Apply page displacement (Identity for first page).
- trans *= stroker.matrix;
- // Apply Current Transformation Matrix (CTM)
- trans *= pageMatrix();
- qreal x1, y1, x2, y2;
- trans.map(0, 0, &x1, &y1);
- trans.map(ti.width.toReal()/size, (ti.ascent.toReal()-ti.descent.toReal())/size, &x2, &y2);
+ if (fd < 0)
+ return false;
- uint annot = addXrefEntry(-1);
-#ifdef Q_DEBUG_PDF_LINKS
- xprintf("<<\n/Type /Annot\n/Subtype /Link\n/Rect [%f %f %f %f]\n/Border [16 16 1]\n/A <<\n",
-#else
- xprintf("<<\n/Type /Annot\n/Subtype /Link\n/Rect [%f %f %f %f]\n/Border [0 0 0]\n/A <<\n",
+ outDevice = new QFile();
+ static_cast<QFile *>(outDevice)->open(fd, QIODevice::WriteOnly);
#endif
- static_cast<double>(x1),
- static_cast<double>(y1),
- static_cast<double>(x2),
- static_cast<double>(y2));
- xprintf("/Type /Action\n/S /URI\n/URI (%s)\n",
- ti.charFormat.anchorHref().toLatin1().constData());
- xprintf(">>\n>>\n");
- xprintf("endobj\n");
-
- if (!currentPage->annotations.contains(annot)) {
- currentPage->annotations.append(annot);
- }
}
- QPdfBaseEnginePrivate::drawTextItem(p, ti);
-}
-
-QTransform QPdfEnginePrivate::pageMatrix() const
-{
- qreal scale = 72./resolution;
- QTransform tmp(scale, 0.0, 0.0, -scale, 0.0, height());
- if (!fullPage) {
- QRect r = pageRect();
- tmp.translate(r.left(), r.top());
- }
- return tmp;
-}
-
-void QPdfEnginePrivate::newPage()
-{
- if (currentPage && currentPage->pageSize.isEmpty())
- currentPage->pageSize = QSize(width(), height());
- writePage();
-
- delete currentPage;
- currentPage = new QPdfPage;
- currentPage->pageSize = QSize(width(), height());
- stroker.stream = currentPage;
- pages.append(requestObject());
-
- *currentPage << "/GSa gs /CSp cs /CSp CS\n"
- << QPdf::generateMatrix(pageMatrix())
- << "q q\n";
+ return true;
}
-
-// For strings up to 10000 bytes only !
-void QPdfEnginePrivate::xprintf(const char* fmt, ...)
+void QPdfEnginePrivate::closePrintDevice()
{
- if (!stream)
+ if (!outDevice)
return;
+ outDevice->close();
+ if (fd >= 0)
+#if defined(Q_OS_WIN) && defined(_MSC_VER) && _MSC_VER >= 1400
+ ::_close(fd);
+#else
+ ::close(fd);
+#endif
+ fd = -1;
+ delete outDevice;
+ outDevice = 0;
+
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ if (!cupsTempFile.isEmpty()) {
+ QString tempFile = cupsTempFile;
+ cupsTempFile.clear();
+ QCUPSSupport cups;
+
+ // Set up print options.
+ QByteArray prnName;
+ QList<QPair<QByteArray, QByteArray> > options;
+ QVector<cups_option_t> cupsOptStruct;
+
+ if (!printerName.isEmpty()) {
+ prnName = printerName.toLocal8Bit();
+ } else {
+ QPrinterInfo def = QPrinterInfo::defaultPrinter();
+ if (def.isNull()) {
+ qWarning("Could not determine printer to print to");
+ QFile::remove(tempFile);
+ return;
+ }
+ prnName = def.printerName().toLocal8Bit();
+ }
- const int msize = 10000;
- char buf[msize];
-
- va_list args;
- va_start(args, fmt);
- int bufsize = qvsnprintf(buf, msize, fmt, args);
-
- Q_ASSERT(bufsize<msize);
-
- va_end(args);
+ if (!cupsStringPageSize.isEmpty()) {
+ options.append(QPair<QByteArray, QByteArray>("media", cupsStringPageSize.toLocal8Bit()));
+ }
- stream->writeRawData(buf, bufsize);
- streampos += bufsize;
-}
+ if (copies > 1) {
+ options.append(QPair<QByteArray, QByteArray>("copies", QString::number(copies).toLocal8Bit()));
+ }
-int QPdfEnginePrivate::writeCompressed(QIODevice *dev)
-{
-#ifndef QT_NO_COMPRESS
- if (do_compress) {
- int size = QPdfPage::chunkSize();
- int sum = 0;
- ::z_stream zStruct;
- zStruct.zalloc = Z_NULL;
- zStruct.zfree = Z_NULL;
- zStruct.opaque = Z_NULL;
- if (::deflateInit(&zStruct, Z_DEFAULT_COMPRESSION) != Z_OK) {
- qWarning("QPdfStream::writeCompressed: Error in deflateInit()");
- return sum;
+ if (collate) {
+ options.append(QPair<QByteArray, QByteArray>("Collate", "True"));
}
- zStruct.avail_in = 0;
- QByteArray in, out;
- out.resize(size);
- while (!dev->atEnd() || zStruct.avail_in != 0) {
- if (zStruct.avail_in == 0) {
- in = dev->read(size);
- zStruct.avail_in = in.size();
- zStruct.next_in = reinterpret_cast<unsigned char*>(in.data());
- if (in.size() <= 0) {
- qWarning("QPdfStream::writeCompressed: Error in read()");
- ::deflateEnd(&zStruct);
- return sum;
- }
- }
- zStruct.next_out = reinterpret_cast<unsigned char*>(out.data());
- zStruct.avail_out = out.size();
- if (::deflate(&zStruct, 0) != Z_OK) {
- qWarning("QPdfStream::writeCompressed: Error in deflate()");
- ::deflateEnd(&zStruct);
- return sum;
+
+ if (duplex != QPrinter::DuplexNone) {
+ switch(duplex) {
+ case QPrinter::DuplexNone: break;
+ case QPrinter::DuplexAuto:
+ if (orientation == QPrinter::Portrait)
+ options.append(QPair<QByteArray, QByteArray>("sides", "two-sided-long-edge"));
+ else
+ options.append(QPair<QByteArray, QByteArray>("sides", "two-sided-short-edge"));
+ break;
+ case QPrinter::DuplexLongSide:
+ options.append(QPair<QByteArray, QByteArray>("sides", "two-sided-long-edge"));
+ break;
+ case QPrinter::DuplexShortSide:
+ options.append(QPair<QByteArray, QByteArray>("sides", "two-sided-short-edge"));
+ break;
}
- int written = out.size() - zStruct.avail_out;
- stream->writeRawData(out.constData(), written);
- streampos += written;
- sum += written;
}
- int ret;
- do {
- zStruct.next_out = reinterpret_cast<unsigned char*>(out.data());
- zStruct.avail_out = out.size();
- ret = ::deflate(&zStruct, Z_FINISH);
- if (ret != Z_OK && ret != Z_STREAM_END) {
- qWarning("QPdfStream::writeCompressed: Error in deflate()");
- ::deflateEnd(&zStruct);
- return sum;
- }
- int written = out.size() - zStruct.avail_out;
- stream->writeRawData(out.constData(), written);
- streampos += written;
- sum += written;
- } while (ret == Z_OK);
- ::deflateEnd(&zStruct);
-
- return sum;
- } else
-#endif
- {
- QByteArray arr;
- int sum = 0;
- while (!dev->atEnd()) {
- arr = dev->read(QPdfPage::chunkSize());
- stream->writeRawData(arr.constData(), arr.size());
- streampos += arr.size();
- sum += arr.size();
+ if (QCUPSSupport::cupsVersion() >= 10300 && orientation == QPrinter::Landscape) {
+ options.append(QPair<QByteArray, QByteArray>("landscape", ""));
}
- return sum;
- }
-}
-int QPdfEnginePrivate::writeCompressed(const char *src, int len)
-{
-#ifndef QT_NO_COMPRESS
- if(do_compress) {
- uLongf destLen = len + len/100 + 13; // zlib requirement
- Bytef* dest = new Bytef[destLen];
- if (Z_OK == ::compress(dest, &destLen, (const Bytef*) src, (uLongf)len)) {
- stream->writeRawData((const char*)dest, destLen);
- } else {
- qWarning("QPdfStream::writeCompressed: Error in compress()");
- destLen = 0;
+ QStringList::const_iterator it = cupsOptions.constBegin();
+ while (it != cupsOptions.constEnd()) {
+ options.append(QPair<QByteArray, QByteArray>((*it).toLocal8Bit(), (*(it+1)).toLocal8Bit()));
+ it += 2;
}
- delete [] dest;
- len = destLen;
- } else
-#endif
- {
- stream->writeRawData(src,len);
- }
- streampos += len;
- return len;
-}
-int QPdfEnginePrivate::writeImage(const QByteArray &data, int width, int height, int depth,
- int maskObject, int softMaskObject, bool dct)
-{
- int image = addXrefEntry(-1);
- xprintf("<<\n"
- "/Type /XObject\n"
- "/Subtype /Image\n"
- "/Width %d\n"
- "/Height %d\n", width, height);
+ for (int c = 0; c < options.size(); ++c) {
+ cups_option_t opt;
+ opt.name = options[c].first.data();
+ opt.value = options[c].second.data();
+ cupsOptStruct.append(opt);
+ }
- if (depth == 1) {
- xprintf("/ImageMask true\n"
- "/Decode [1 0]\n");
- } else {
- xprintf("/BitsPerComponent 8\n"
- "/ColorSpace %s\n", (depth == 32) ? "/DeviceRGB" : "/DeviceGray");
- }
- if (maskObject > 0)
- xprintf("/Mask %d 0 R\n", maskObject);
- if (softMaskObject > 0)
- xprintf("/SMask %d 0 R\n", softMaskObject);
+ // Print the file.
+ cups_option_t* optPtr = cupsOptStruct.size() ? &cupsOptStruct.first() : 0;
+ cups.printFile(prnName.constData(), tempFile.toLocal8Bit().constData(),
+ title.toLocal8Bit().constData(), cupsOptStruct.size(), optPtr);
- int lenobj = requestObject();
- xprintf("/Length %d 0 R\n", lenobj);
- if (interpolateImages)
- xprintf("/Interpolate true\n");
- int len = 0;
- if (dct) {
- //qDebug() << "DCT";
- xprintf("/Filter /DCTDecode\n>>\nstream\n");
- write(data);
- len = data.length();
- } else {
- if (do_compress)
- xprintf("/Filter /FlateDecode\n>>\nstream\n");
- else
- xprintf(">>\nstream\n");
- len = writeCompressed(data);
+ QFile::remove(tempFile);
}
- xprintf("endstream\n"
- "endobj\n");
- addXrefEntry(lenobj);
- xprintf("%d\n"
- "endobj\n", len);
- return image;
-}
-
-
-void QPdfEnginePrivate::writeHeader()
-{
- addXrefEntry(0,false);
-
- xprintf("%%PDF-1.4\n");
-
- writeInfo();
-
- catalog = addXrefEntry(-1);
- pageRoot = requestObject();
- xprintf("<<\n"
- "/Type /Catalog\n"
- "/Pages %d 0 R\n"
- ">>\n"
- "endobj\n", pageRoot);
-
- // graphics state
- graphicsState = addXrefEntry(-1);
- xprintf("<<\n"
- "/Type /ExtGState\n"
- "/SA true\n"
- "/SM 0.02\n"
- "/ca 1.0\n"
- "/CA 1.0\n"
- "/AIS false\n"
- "/SMask /None"
- ">>\n"
- "endobj\n");
-
- // color space for pattern
- patternColorSpace = addXrefEntry(-1);
- xprintf("[/Pattern /DeviceRGB]\n"
- "endobj\n");
-}
-
-void QPdfEnginePrivate::writeInfo()
-{
- info = addXrefEntry(-1);
- xprintf("<<\n/Title ");
- printString(title);
- xprintf("\n/Creator ");
- printString(creator);
- xprintf("\n/Producer ");
- printString(QString::fromLatin1("Qt " QT_VERSION_STR " (C) 2011 Nokia Corporation and/or its subsidiary(-ies)"));
- QDateTime now = QDateTime::currentDateTime().toUTC();
- QTime t = now.time();
- QDate d = now.date();
- xprintf("\n/CreationDate (D:%d%02d%02d%02d%02d%02d)\n",
- d.year(),
- d.month(),
- d.day(),
- t.hour(),
- t.minute(),
- t.second());
- xprintf(">>\n"
- "endobj\n");
-}
-
-void QPdfEnginePrivate::writePageRoot()
-{
- addXrefEntry(pageRoot);
-
- xprintf("<<\n"
- "/Type /Pages\n"
- "/Kids \n"
- "[\n");
- int size = pages.size();
- for (int i = 0; i < size; ++i)
- xprintf("%d 0 R\n", pages[i]);
- xprintf("]\n");
-
- //xprintf("/Group <</S /Transparency /I true /K false>>\n");
- xprintf("/Count %d\n", pages.size());
-
- xprintf("/ProcSet [/PDF /Text /ImageB /ImageC]\n"
- ">>\n"
- "endobj\n");
-}
-
-
-void QPdfEnginePrivate::embedFont(QFontSubset *font)
-{
- //qDebug() << "embedFont" << font->object_id;
- int fontObject = font->object_id;
- QByteArray fontData = font->toTruetype();
-#ifdef FONT_DUMP
- static int i = 0;
- QString fileName("font%1.ttf");
- fileName = fileName.arg(i++);
- QFile ff(fileName);
- ff.open(QFile::WriteOnly);
- ff.write(fontData);
- ff.close();
#endif
-
- int fontDescriptor = requestObject();
- int fontstream = requestObject();
- int cidfont = requestObject();
- int toUnicode = requestObject();
-
- QFontEngine::Properties properties = font->fontEngine->properties();
-
- {
- qreal scale = 1000/properties.emSquare.toReal();
- addXrefEntry(fontDescriptor);
- QByteArray descriptor;
- QPdf::ByteStream s(&descriptor);
- s << "<< /Type /FontDescriptor\n"
- "/FontName /Q";
- int tag = fontDescriptor;
- for (int i = 0; i < 5; ++i) {
- s << (char)('A' + (tag % 26));
- tag /= 26;
- }
- s << '+' << properties.postscriptName << "\n"
- "/Flags " << 4 << "\n"
- "/FontBBox ["
- << properties.boundingBox.x()*scale
- << -(properties.boundingBox.y() + properties.boundingBox.height())*scale
- << (properties.boundingBox.x() + properties.boundingBox.width())*scale
- << -properties.boundingBox.y()*scale << "]\n"
- "/ItalicAngle " << properties.italicAngle.toReal() << "\n"
- "/Ascent " << properties.ascent.toReal()*scale << "\n"
- "/Descent " << -properties.descent.toReal()*scale << "\n"
- "/CapHeight " << properties.capHeight.toReal()*scale << "\n"
- "/StemV " << properties.lineWidth.toReal()*scale << "\n"
- "/FontFile2 " << fontstream << "0 R\n"
- ">> endobj\n";
- write(descriptor);
- }
- {
- addXrefEntry(fontstream);
- QByteArray header;
- QPdf::ByteStream s(&header);
-
- int length_object = requestObject();
- s << "<<\n"
- "/Length1 " << fontData.size() << "\n"
- "/Length " << length_object << "0 R\n";
- if (do_compress)
- s << "/Filter /FlateDecode\n";
- s << ">>\n"
- "stream\n";
- write(header);
- int len = writeCompressed(fontData);
- write("endstream\n"
- "endobj\n");
- addXrefEntry(length_object);
- xprintf("%d\n"
- "endobj\n", len);
- }
- {
- addXrefEntry(cidfont);
- QByteArray cid;
- QPdf::ByteStream s(&cid);
- s << "<< /Type /Font\n"
- "/Subtype /CIDFontType2\n"
- "/BaseFont /" << properties.postscriptName << "\n"
- "/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>\n"
- "/FontDescriptor " << fontDescriptor << "0 R\n"
- "/CIDToGIDMap /Identity\n"
- << font->widthArray() <<
- ">>\n"
- "endobj\n";
- write(cid);
- }
- {
- addXrefEntry(toUnicode);
- QByteArray touc = font->createToUnicodeMap();
- xprintf("<< /Length %d >>\n"
- "stream\n", touc.length());
- write(touc);
- write("endstream\n"
- "endobj\n");
- }
- {
- addXrefEntry(fontObject);
- QByteArray font;
- QPdf::ByteStream s(&font);
- s << "<< /Type /Font\n"
- "/Subtype /Type0\n"
- "/BaseFont /" << properties.postscriptName << "\n"
- "/Encoding /Identity-H\n"
- "/DescendantFonts [" << cidfont << "0 R]\n"
- "/ToUnicode " << toUnicode << "0 R"
- ">>\n"
- "endobj\n";
- write(font);
- }
}
-void QPdfEnginePrivate::writeFonts()
-{
- for (QHash<QFontEngine::FaceId, QFontSubset *>::iterator it = fonts.begin(); it != fonts.end(); ++it) {
- embedFont(*it);
- delete *it;
- }
- fonts.clear();
-}
-void QPdfEnginePrivate::writePage()
+QPdfEnginePrivate::QPdfEnginePrivate(QPrinter::PrinterMode m)
+ : QPdfBaseEnginePrivate(m)
{
- if (pages.empty())
- return;
-
- *currentPage << "Q Q\n";
-
- uint pageStream = requestObject();
- uint pageStreamLength = requestObject();
- uint resources = requestObject();
- uint annots = requestObject();
-
- addXrefEntry(pages.last());
- xprintf("<<\n"
- "/Type /Page\n"
- "/Parent %d 0 R\n"
- "/Contents %d 0 R\n"
- "/Resources %d 0 R\n"
- "/Annots %d 0 R\n"
- "/MediaBox [0 0 %d %d]\n"
- ">>\n"
- "endobj\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());
-
- addXrefEntry(resources);
- xprintf("<<\n"
- "/ColorSpace <<\n"
- "/PCSp %d 0 R\n"
- "/CSp /DeviceRGB\n"
- "/CSpg /DeviceGray\n"
- ">>\n"
- "/ExtGState <<\n"
- "/GSa %d 0 R\n",
- patternColorSpace, graphicsState);
-
- for (int i = 0; i < currentPage->graphicStates.size(); ++i)
- xprintf("/GState%d %d 0 R\n", currentPage->graphicStates.at(i), currentPage->graphicStates.at(i));
- xprintf(">>\n");
-
- xprintf("/Pattern <<\n");
- for (int i = 0; i < currentPage->patterns.size(); ++i)
- xprintf("/Pat%d %d 0 R\n", currentPage->patterns.at(i), currentPage->patterns.at(i));
- xprintf(">>\n");
-
- xprintf("/Font <<\n");
- for (int i = 0; i < currentPage->fonts.size();++i)
- xprintf("/F%d %d 0 R\n", currentPage->fonts[i], currentPage->fonts[i]);
- xprintf(">>\n");
-
- xprintf("/XObject <<\n");
- for (int i = 0; i<currentPage->images.size(); ++i) {
- xprintf("/Im%d %d 0 R\n", currentPage->images.at(i), currentPage->images.at(i));
- }
- xprintf(">>\n");
-
- xprintf(">>\n"
- "endobj\n");
-
- addXrefEntry(annots);
- xprintf("[ ");
- for (int i = 0; i<currentPage->annotations.size(); ++i) {
- xprintf("%d 0 R ", currentPage->annotations.at(i));
- }
- xprintf("]\nendobj\n");
-
- addXrefEntry(pageStream);
- xprintf("<<\n"
- "/Length %d 0 R\n", pageStreamLength); // object number for stream length object
- if (do_compress)
- xprintf("/Filter /FlateDecode\n");
-
- xprintf(">>\n");
- xprintf("stream\n");
- QIODevice *content = currentPage->stream();
- int len = writeCompressed(content);
- xprintf("endstream\n"
- "endobj\n");
-
- addXrefEntry(pageStreamLength);
- xprintf("%d\nendobj\n",len);
}
-void QPdfEnginePrivate::writeTail()
+QPdfEnginePrivate::~QPdfEnginePrivate()
{
- writePage();
- writeFonts();
- writePageRoot();
- addXrefEntry(xrefPositions.size(),false);
- xprintf("xref\n"
- "0 %d\n"
- "%010d 65535 f \n", xrefPositions.size()-1, xrefPositions[0]);
-
- 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.last());
}
-int QPdfEnginePrivate::addXrefEntry(int object, bool printostr)
-{
- if (object < 0)
- object = requestObject();
-
- if (object>=xrefPositions.size())
- xrefPositions.resize(object+1);
-
- xrefPositions[object] = streampos;
- if (printostr)
- xprintf("%d 0 obj\n",object);
- return object;
-}
-void QPdfEnginePrivate::printString(const QString &string) {
- // The 'text string' type in PDF is encoded either as PDFDocEncoding, or
- // Unicode UTF-16 with a Unicode byte order mark as the first character
- // (0xfeff), with the high-order byte first.
- QByteArray array("(\xfe\xff");
- const ushort *utf16 = string.utf16();
-
- for (int i=0; i < string.size(); ++i) {
- char part[2] = {char((*(utf16 + i)) >> 8), char((*(utf16 + i)) & 0xff)};
- for(int j=0; j < 2; ++j) {
- if (part[j] == '(' || part[j] == ')' || part[j] == '\\')
- array.append('\\');
- array.append(part[j]);
- }
- }
- array.append(")");
- write(array);
-}
QT_END_NAMESPACE
diff --git a/src/gui/painting/qprintengine_pdf_p.h b/src/gui/painting/qprintengine_pdf_p.h
index ee77e1599c..aa4a6c820a 100644
--- a/src/gui/painting/qprintengine_pdf_p.h
+++ b/src/gui/painting/qprintengine_pdf_p.h
@@ -67,6 +67,7 @@
#include "private/qfontengine_p.h"
#include "private/qpdf_p.h"
#include "private/qpaintengine_p.h"
+#include "qprintengine.h"
QT_BEGIN_NAMESPACE
@@ -82,7 +83,7 @@ class QPdfEngine;
class QPdfEnginePrivate;
-class QPdfEngine : public QPdfBaseEngine
+class QPdfEngine : public QPdfBaseEngine, public QPrintEngine
{
Q_DECLARE_PRIVATE(QPdfEngine)
public:
@@ -92,32 +93,22 @@ public:
// reimplementations QPaintEngine
bool begin(QPaintDevice *pdev);
bool end();
- void drawPixmap (const QRectF & rectangle, const QPixmap & pixmap, const QRectF & sr);
- void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
- Qt::ImageConversionFlags flags = Qt::AutoColor);
- void drawTiledPixmap (const QRectF & rectangle, const QPixmap & pixmap, const QPointF & point);
-
- Type type() const;
// end reimplementations QPaintEngine
// reimplementations QPrintEngine
bool abort() {return false;}
- bool newPage();
QPrinter::PrinterState printerState() const {return state;}
- // end reimplementations QPrintEngine
-
- void setBrush();
- // ### unused, should have something for this in QPrintEngine
- void setAuthor(const QString &author);
- QString author() const;
+ bool newPage();
+ int metric(QPaintDevice::PaintDeviceMetric) const;
+ void setProperty(PrintEnginePropertyKey key, const QVariant &value);
+ QVariant property(PrintEnginePropertyKey key) const;
+ // end reimplementations QPrintEngine
- void setDevice(QIODevice* dev);
+ QPrinter::PrinterState state;
private:
Q_DISABLE_COPY(QPdfEngine)
-
- QPrinter::PrinterState state;
};
class QPdfEnginePrivate : public QPdfBaseEnginePrivate
@@ -127,65 +118,12 @@ public:
QPdfEnginePrivate(QPrinter::PrinterMode m);
~QPdfEnginePrivate();
- void newPage();
-
- int width() const {
- QRect r = paperRect();
- return qRound(r.width()*72./resolution);
- }
- int height() const {
- QRect r = paperRect();
- return qRound(r.height()*72./resolution);
- }
-
- void writeHeader();
- void writeTail();
-
- int addImage(const QImage &image, bool *bitmap, qint64 serial_no);
- int addConstantAlphaObject(int brushAlpha, int penAlpha = 255);
- int addBrushPattern(const QTransform &matrix, bool *specifyColor, int *gStateObject);
-
- void drawTextItem(const QPointF &p, const QTextItemInt &ti);
-
- QTransform pageMatrix() const;
+ bool openPrintDevice();
+ void closePrintDevice();
private:
Q_DISABLE_COPY(QPdfEnginePrivate)
-#ifdef USE_NATIVE_GRADIENTS
- int gradientBrush(const QBrush &b, const QMatrix &matrix, int *gStateObject);
-#endif
-
- void writeInfo();
- void writePageRoot();
- void writeFonts();
- void embedFont(QFontSubset *font);
-
- QVector<int> xrefPositions;
- QDataStream* stream;
- int streampos;
-
- int writeImage(const QByteArray &data, int width, int height, int depth,
- int maskObject, int softMaskObject, bool dct = false);
- void writePage();
-
- int addXrefEntry(int object, bool printostr = true);
- void printString(const QString &string);
- void xprintf(const char* fmt, ...);
- inline void write(const QByteArray &data) {
- stream->writeRawData(data.constData(), data.size());
- streampos += data.size();
- }
-
- int writeCompressed(const char *src, int len);
- inline int writeCompressed(const QByteArray &data) { return writeCompressed(data.constData(), data.length()); }
- int writeCompressed(QIODevice *dev);
-
- // various PDF objects
- int pageRoot, catalog, info, graphicsState, patternColorSpace;
- QVector<uint> pages;
- QHash<qint64, uint> imageCache;
- QHash<QPair<uint, uint>, uint > alphaCache;
};
QT_END_NAMESPACE