📄 qprintengine_pdf.cpp
字号:
QByteArray imageData; bool hasAlpha = false; bool hasMask = false; if (QImageWriter::supportedImageFormats().contains("jpeg")) { 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(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); 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, 32, maskObject, softMaskObject, dct); } imageCache.insert(serial_no, object); return object;}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(){ writePage(); delete currentPage; currentPage = new QPdfPage; stroker.stream = currentPage; pages.append(requestObject()); *currentPage << "/GSa gs /CSp cs /CSp CS\n" << QPdf::generateMatrix(pageMatrix()) << "q 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 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;}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); 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;}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(){ tm *newtime;#if defined(Q_OS_WIN) && defined(_MSC_VER) && _MSC_VER >= 1400 __time32_t now; _time32(&now); tm buffer; _gmtime32_s(&buffer, &now); newtime = &buffer;#else time_t now; time(&now); newtime = gmtime(&now);#endif QByteArray y; if (newtime && newtime->tm_year+1900 > 1992) y += QByteArray::number(newtime->tm_year+1900); info = addXrefEntry(-1); xprintf("<<\n" "/Title (%s)\n"// "/Author (%s)\n" "/Creator (%s)\n" "/Producer (Qt %s (C) 1992-%s Trolltech ASA)\n", title.toUtf8().constData(),// author.toUtf8().constData(), creator.toUtf8().constData(), qVersion(), y.constData()); if (newtime) { xprintf("/CreationDate (D:%d%02d%02d%02d%02d%02d)\n", newtime->tm_year+1900, newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec); } 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" "/MediaBox [%d %d %d %d]\n", pages.size(), 0, 0, width(), height()); 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(){ if (pages.empty()) return; *currentPage << "Q Q\n"; uint pageStream = requestObject(); uint pageStreamLength = requestObject(); uint resources = requestObject(); addXrefEntry(pages.last()); xprintf("<<\n" "/Type /Page\n" "/Parent %d 0 R\n" "/Contents %d 0 R\n" "/Resources %d 0 R\n" ">>\n" "endobj\n", pageRoot, pageStream, resources); 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(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"); QByteArray content = currentPage->content(); int len = writeCompressed(content); xprintf("endstream\n" "endobj\n"); addXrefEntry(pageStreamLength); xprintf("%d\nendobj\n",len);}void QPdfEnginePrivate::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 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;}#endif // QT_NO_PRINTER
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -