📄 qprintengine_pdf.cpp
字号:
QRect r = d->fullPage ? paperRect() : pageRect(); switch (metricType) { case QPaintDevice::PdmWidth: val = r.width(); break; case QPaintDevice::PdmHeight: val = r.height(); break; case QPaintDevice::PdmDpiX: case QPaintDevice::PdmDpiY: val = d->resolution; break; case QPaintDevice::PdmPhysicalDpiX: case QPaintDevice::PdmPhysicalDpiY: val = 1200; break; case QPaintDevice::PdmWidthMM: val = qRound(r.width()*25.4/d->resolution); break; case QPaintDevice::PdmHeightMM: val = qRound(r.height()*25.4/d->resolution); break; case QPaintDevice::PdmNumColors: val = INT_MAX; break; case QPaintDevice::PdmDepth: val = 32; break; default: qWarning("QPdfEngine::metric: Invalid metric command"); return 0; } return val;}QPaintEngine::Type QPdfEngine::type() const{ return QPaintEngine::User;}bool QPdfEngine::newPage(){ Q_D(QPdfEngine); if (!isActive()) return false; d->newPage(); return true;}QPdfEnginePrivate::QPdfEnginePrivate(){ width_ = 0; height_ = 0; 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; QMatrix 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 = addXrefEntry(-1); xprintf("<< /ca %f >>\n" "endobj\n", stops.at(0).second.alphaF()); } 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::addBrushPattern(const QMatrix &m, bool *specifyColor, int *gStateObject){ int paintType = 2; // Uncolored tiling int w = 8; int h = 8; *specifyColor = true; *gStateObject = 0; QMatrix 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) { QByteArray brushDef; QPdf::ByteStream s(&brushDef); s << "<<"; QColor rgba = brush.color(); s << "/ca " << rgba.alphaF(); s << ">>\n"; *gStateObject = addXrefEntry(-1); xprintf(brushDef.constData()); xprintf("endobj\n"); currentPage->graphicStates.append(*gStateObject); } 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(); QMatrix 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); } else { *bitmap = false; if (format != QImage::Format_RGB32 && format != QImage::Format_ARGB32) image = image.convertToFormat(QImage::Format_ARGB32); } int w = image.width(); int h = image.height(); int d = image.depth(); if (d == 1) { 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 imageData; QByteArray softMaskData; imageData.resize(3 * w * h); softMaskData.resize(w * h); uchar *data = (uchar *)imageData.data(); uchar *sdata = (uchar *)softMaskData.data(); bool hasAlpha = false; bool hasMask = false; for (int y = 0; y < h; ++y) { const QRgb *rgb = (const QRgb *)image.scanLine(y); 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; } } 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, 32, maskObject, softMaskObject); } imageCache.insert(serial_no, object); return object;}QMatrix QPdfEnginePrivate::pageMatrix() const{ qreal scale = 72./resolution; QMatrix tmp(scale, 0.0, 0.0, -scale, 0.0, height_); if (!fullPage) tmp.translate(resolution/3, resolution/3); return tmp;}void QPdfEnginePrivate::newPage(){ writePage(); delete currentPage; currentPage = new QPdfPage; stroker.stream = currentPage; pages.append(requestObject()); *currentPage << "/GSa gs /CSp cs /CSp CS\n" << QPdf::generateMatrix(pageMatrix()) << "q\n";}// For strings up to 10000 bytes only !void QPdfEnginePrivate::xprintf(const char* fmt, ...){ if (!stream) 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 QPdfEnginePrivate::writeCompressed(const char *src, int len){#ifndef QT_NO_COMPRESS if(do_compress) { uLongf destLen = len + len/100 + 13; // zlib requirement
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -