📄 qprintengine_pdf.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtGui module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#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>#ifndef QT_NO_PRINTER#include <time.h>#include <limits.h>#include <math.h>#ifndef QT_NO_COMPRESS#include <zlib.h>#endif#include "qprintengine_pdf_p.h"#include "private/qdrawhelper_p.h"extern qint64 qt_pixmap_id(const QPixmap &pixmap);extern qint64 qt_image_id(const QImage &image);//#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_COMPRESSstatic const bool do_compress = false;#elsestatic const bool do_compress = true;#endifQPdfPage::QPdfPage() : QPdf::ByteStream(&data){}void QPdfPage::streamImage(int w, int h, int object){ *this << "/GSa gs " << w << "0 0 " << -h << "0 " << h << "cm /Im" << object << " Do\n"; if (!images.contains(object)) images.append(object);}inline QPaintEngine::PaintEngineFeatures qt_pdf_decide_features(){ QPaintEngine::PaintEngineFeatures f = QPaintEngine::AllFeatures; f &= ~(QPaintEngine::PorterDuff | QPaintEngine::PerspectiveTransform#ifndef USE_NATIVE_GRADIENTS | QPaintEngine::LinearGradientFill#endif | QPaintEngine::RadialGradientFill | QPaintEngine::ConicalGradientFill); return f;}QPdfEngine::QPdfEngine(QPrinter::PrinterMode m) : QPdfBaseEngine(*new QPdfEnginePrivate(m), qt_pdf_decide_features()){ state = QPrinter::Idle;}QPdfEngine::~QPdfEngine(){}bool QPdfEngine::begin(QPaintDevice *pdev){ Q_D(QPdfEngine); if(!QPdfBaseEngine::begin(pdev)) 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;}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(); *d->currentPage << "q\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)); bool bitmap = true; int object = d->addImage(image, &bitmap, pm.cacheKey()); 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; *d->currentPage << "q\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)); bool bitmap = false; int object = d->addImage(im, &bitmap, im.cacheKey()); 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(); *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";}QPaintEngine::Type QPdfEngine::type() const{ return QPaintEngine::User;}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_GRADIENTSint 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 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 (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); } } return patternObj;}#endifint QPdfEnginePrivate::addConstantAlphaObject(int alpha){ if (alpha == 255) return 0; int object = alphaCache.value(alpha, 0); if (!object) { object = addXrefEntry(-1); QByteArray alphaDef; QPdf::ByteStream s(&alphaDef); s << "<< /ca " << (alpha/qreal(255.)) << ">>"; xprintf("%s\nendobj\n", alphaDef.constData()); } currentPage->graphicStates.append(object); return object;}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);#else return 0;#endif } if (!brush.isOpaque() && brush.style() < Qt::LinearGradientPattern) *gStateObject = addConstantAlphaObject(brush.color().alpha()); int imageObject = 0; 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, qt_pixmap_id(brush.texture())); 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) { 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;}int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, qint64 serial_no){ 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) { 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -