summaryrefslogtreecommitdiffstats
path: root/src/gui/painting/qprintengine_pdf.cpp
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 /src/gui/painting/qprintengine_pdf.cpp
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>
Diffstat (limited to 'src/gui/painting/qprintengine_pdf.cpp')
-rw-r--r--src/gui/painting/qprintengine_pdf.cpp1522
1 files changed, 458 insertions, 1064 deletions
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