📄 qprintengine_ps.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 "qplatformdefs.h"#include <private/qprintengine_ps_p.h>#include <private/qpainter_p.h>#include <private/qfontengine_p.h>#include <private/qpaintengine_p.h>#include <private/qpdf_p.h>#ifndef QT_NO_PRINTER#include "qprinter.h"#include "qpainter.h"#include "qapplication.h"#include "qpixmap.h"#include "qimage.h"#include "qdatetime.h"#include "qstring.h"#include "qbytearray.h"#include "qhash.h"#include "qbuffer.h"#include "qsettings.h"#include "qmap.h"#include "qbitmap.h"#include "qregion.h"#include "qimagewriter.h"#include <private/qunicodetables_p.h>#include <private/qpainterpath_p.h>#include <qdebug.h>#include <private/qdrawhelper_p.h>#ifndef Q_OS_WIN#include <unistd.h>#endif#include <stdlib.h>#include <limits.h>static bool qt_gen_epsf = false;void qt_generate_epsf(bool b){ qt_gen_epsf = b;}static const char *const ps_header ="/BD{bind def}bind def/d2{dup dup}BD/ED{exch def}BD/D0{0 ED}BD/F{setfont}BD\n""/RL{rlineto}BD/CM{currentmatrix}BD/SM{setmatrix}BD/TR{translate}BD/SD\n""{setdash}BD/SC{aload pop setrgbcolor}BD/CR{currentfile read pop}BD/i{index}\n""BD/scs{setcolorspace}BD/DB{dict dup begin}BD/DE{end def}BD/ie{ifelse}BD/gs\n""{gsave}BD/gr{grestore}BD/w{setlinewidth}BD/d{setdash}BD/J{setlinecap}BD/j\n""{setlinejoin}BD/scn{3 array astore/BCol exch def}BD/SCN{3 array astore/PCol\n""exch def}BD/cm{6 array astore concat}BD/m{moveto}BD/l{lineto}BD/c{curveto}BD\n""/h{closepath}BD/W{clip}BD/W*{eoclip}BD/n{newpath}BD/q{gsave 10 dict begin}BD\n""/Q{end grestore}BD/re{4 2 roll m dup 0 exch RL exch 0 RL 0 exch neg RL h}BD\n""/S{gs PCol SC stroke gr n}BD/BT{gsave 10 dict begin/_m matrix CM def BCol\n""SC}BD/ET{end grestore}BD/Tf{/_fs ED findfont[_fs 0 0 _fs 0 0]makefont F}BD\n""/Tm{6 array astore concat}BD/Td{translate}BD/Tj{0 0 m show}BD/BDC{pop pop}BD\n""/EMC{}BD/BSt 0 def/WFi false def/BCol[1 1 1]def/PCol[0 0 0]def/BDArr[0.94\n""0.88 0.63 0.50 0.37 0.12 0.06]def/level3{/languagelevel where{pop\n""languagelevel 3 ge}{false}ie}BD/QCIgray D0/QCIcolor D0/QCIindex D0/QCI{\n""/colorimage where{pop false 3 colorimage}{exec/QCIcolor ED/QCIgray QCIcolor\n""length 3 idiv string def 0 1 QCIcolor length 3 idiv 1 sub{/QCIindex ED/_x\n""QCIindex 3 mul def QCIgray QCIindex QCIcolor _x get 0.30 mul QCIcolor _x 1\n""add get 0.59 mul QCIcolor _x 2 add get 0.11 mul add add cvi put}for QCIgray\n""image}ie}BD/di{gs TR 1 i 1 eq{pop pop false 3 1 roll BCol SC imagemask}{dup\n""false ne{level3}{false}ie{/_ma ED 8 eq{/_dc[0 1]def/DeviceGray}{/_dc[0 1 0 1\n""0 1]def/DeviceRGB}ie scs/_im ED/_mt ED/_h ED/_w ED <</ImageType 3/DataDict\n""<</ImageType 1/Width _w/Height _h/ImageMatrix _mt/DataSource _im\n""/BitsPerComponent 8/Decode _dc >>/MaskDict <</ImageType 1/Width _w/Height _h\n""/ImageMatrix _mt/DataSource _ma/BitsPerComponent 1/Decode[0 1]>>\n""/InterleaveType 3 >> image}{pop 8 4 1 roll 8 eq{image}{QCI}ie}ie}ie gr}BD/BF\n""{gs BSt 1 eq{BCol SC WFi{fill}{eofill}ie}if BSt 2 ge BSt 8 le and{BDArr BSt\n""2 sub get/_sc ED BCol{1. exch sub _sc mul 1. exch sub}forall 3 array astore\n""SC WFi{fill}{eofill}ie}if BSt 9 ge BSt 14 le and{WFi{W}{W*}ie pathbbox 3 i 3\n""i TR 4 2 roll 3 2 roll exch sub/_h ED sub/_w ED BCol SC 0.3 w n BSt 9 eq BSt\n""11 eq or{0 4 _h{dup 0 exch m _w exch l}for}if BSt 10 eq BSt 11 eq or{0 4 _w{\n""dup 0 m _h l}for}if BSt 12 eq BSt 14 eq or{_w _h gt{0 6 _w _h add{dup 0 m _h\n""sub _h l}for}{0 6 _w _h add{dup 0 exch m _w sub _w exch l}for}ie}if BSt 13\n""eq BSt 14 eq or{_w _h gt{0 6 _w _h add{dup _h m _h sub 0 l}for}{0 6 _w _h\n""add{dup _w exch m _w sub 0 exch l}for}ie}if stroke}if BSt 15 eq{}if BSt 24\n""eq{}if gr}BD/f{/WFi true def BF n}BD/f*{/WFi false def BF n}BD/B{/WFi true\n""def BF S n}BD/B*{/WFi false def BF S n}BD/QI{/C save def pageinit q n}BD/QP{\n""Q C restore showpage}BD/SPD{/setpagedevice where{<< 3 1 roll >>\n""setpagedevice}{pop pop}ie}BD/T1AddMapping{10 dict begin/glyphs ED/fnt ED\n""/current fnt/NumGlyphs get def/CMap fnt/CMap get def 0 1 glyphs length 1 sub\n""{glyphs exch get/gn ED current dup 256 mod/min ED 256 idiv/maj ED CMap dup\n""maj get dup null eq{pop 256 array 0 1 255{1 i exch/.notdef put}for}if dup\n""min gn put maj exch put/current current 1 add def}for fnt/CMap CMap put fnt\n""/NumGlyphs current put end}def/T1AddGlyphs{10 dict begin/glyphs ED/fnt ED\n""/current fnt/NumGlyphs get def/CMap fnt/CMap get def/CharStrings fnt\n""/CharStrings get def 0 1 glyphs length 2 idiv 1 sub{2 mul dup glyphs exch\n""get/gn ED 1 add glyphs exch get/cs ED current dup 256 mod/min ED 256 idiv\n""/maj ED CMap dup maj get dup null eq{pop 256 array 0 1 255{1 i exch/.notdef\n""put}for}if dup min gn put maj exch put CharStrings gn cs put/current current\n""1 add def}for fnt/CharStrings CharStrings put fnt/CMap CMap put fnt\n""/NumGlyphs current put end}def/StringAdd{1 i length 1 i length add string 3\n""1 roll 2 i 0 3 i putinterval 2 i 2 i length 2 i putinterval pop pop}def\n""/T1Setup{10 dict begin dup/FontName ED (-Base) StringAdd cvx cvn/Font ED\n""/MaxPage Font/NumGlyphs get 1 sub 256 idiv def/FDepVector MaxPage 1 add\n""array def/Encoding MaxPage 1 add array def 0 1 MaxPage{dup Encoding exch dup\n""put dup/Page ED FontName (-) StringAdd exch 20 string cvs StringAdd cvn Font\n""0 dict copy d2/CMap get Page get/Encoding exch put definefont FDepVector\n""exch Page exch put}for FontName cvn <</FontType 0/FMapType 2/FontMatrix[1 0\n""0 1 0 0]/Encoding Encoding/FDepVector FDepVector >> definefont pop end}def\n";// ------------------------------End of static data ----------------------------------// make sure DSC comments are not longer than 255 chars per line.static QByteArray wrapDSC(const QByteArray &str){ QByteArray dsc = str.simplified(); const int wrapAt = 254; QByteArray wrapped; if (dsc.length() < wrapAt) wrapped = dsc; else { wrapped = dsc.left(wrapAt); QByteArray tmp = dsc.mid(wrapAt); while (tmp.length() > wrapAt-3) { wrapped += "\n%%+" + tmp.left(wrapAt-3); tmp = tmp.mid(wrapAt-3); } wrapped += "\n%%+" + tmp; } return wrapped + "\n";}// ----------------------------- Internal class declarations -----------------------------QPSPrintEnginePrivate::QPSPrintEnginePrivate(QPrinter::PrinterMode m) : QPdfBaseEnginePrivate(m), printerState(QPrinter::Idle), hugeDocument(false), headerDone(false){ postscript = true; firstPage = true;#ifndef QT_NO_SETTINGS QSettings settings(QSettings::UserScope, QLatin1String("Trolltech")); settings.beginGroup(QLatin1String("Qt")); embedFonts = settings.value(QLatin1String("embedFonts"), true).toBool();#else embedFonts = true;#endif}QPSPrintEnginePrivate::~QPSPrintEnginePrivate(){}#include <qdebug.h>static void ps_r7(QPdf::ByteStream& stream, const char * s, int l){ int i = 0; uchar line[84]; int col = 0; while(i < l) { line[col++] = s[i++]; if (i < l - 1 && col >= 76) { line[col++] = '\n'; line[col++] = '\0'; stream << (const char *)line; col = 0; } } if (col > 0) { while((col&3) != 0) line[col++] = '%'; // use a comment as padding line[col++] = '\n'; line[col++] = '\0'; stream << (const char *)line; }}static QByteArray runlengthEncode(const QByteArray &input){ if (!input.length()) return input; const char *data = input.constData(); QByteArray out; int start = 0; char last = *data; enum State { Undef, Equal, Diff }; State state = Undef; int i = 1; int written = 0; while (1) { bool flush = (i == input.size()); if (!flush) { switch(state) { case Undef: state = (last == data[i]) ? Equal : Diff; break; case Equal: if (data[i] != last) flush = true; break; case Diff: if (data[i] == last) { --i; flush = true; } } } if (flush || i - start == 128) { int size = i - start; if (state == Equal) { out.append((char)(uchar)(257-size)); out.append(last); written += size; } else { out.append((char)(uchar)size-1); while (start < i) out.append(data[start++]); written += size; } state = Undef; start = i; if (i == input.size()) break; } last = data[i]; ++i; }; out.append((char)(uchar)128); return out;}enum format { Raw, Runlength, DCT};static const char *const filters[3] = { " ", "/RunLengthDecode filter ", "/DCTDecode filter "};static QByteArray compress(const QImage &img, bool gray, int *format){ // we can't use premultiplied here QImage image = img; if (image.format() == QImage::Format_ARGB32_Premultiplied) image = image.convertToFormat(QImage::Format_ARGB32); QByteArray pixelData; int depth = image.depth(); if (depth != 1 && !gray && QImageWriter::supportedImageFormats().contains("jpeg")) { QBuffer buffer(&pixelData); QImageWriter writer(&buffer, "jpeg"); writer.setQuality(94); writer.write(img); *format = DCT; } else { int width = image.width(); int height = image.height(); int size = width*height; if (depth == 1) size = (width+7)/8*height; else if (!gray) size = size*3; pixelData.resize(size); uchar *pixel = (uchar *)pixelData.data(); int i = 0; if (depth == 1) { QImage::Format format = image.format(); memset(pixel, 0xff, size); for(int y=0; y < height; y++) { const uchar * s = image.scanLine(y); for(int x=0; x < width; x++) { // need to copy bit for bit... bool b = (format == QImage::Format_MonoLSB) ? (*(s + (x >> 3)) >> (x & 7)) & 1 : (*(s + (x >> 3)) << (x & 7)) & 0x80 ; if (b) pixel[i >> 3] ^= (0x80 >> (i & 7)); i++; } // we need to align to 8 bit here i = (i+7) & 0xffffff8; } } else if (depth == 8) { for(int y=0; y < height; y++) { const uchar * s = image.scanLine(y); for(int x=0; x < width; x++) { QRgb rgb = image.color(s[x]); if (gray) { pixel[i] = (unsigned char) qGray(rgb); i++; } else { pixel[i] = (unsigned char) qRed(rgb); pixel[i+1] = (unsigned char) qGreen(rgb); pixel[i+2] = (unsigned char) qBlue(rgb); i += 3; } } } } else { for(int y=0; y < height; y++) { QRgb * s = (QRgb*)(image.scanLine(y)); for(int x=0; x < width; x++) { QRgb rgb = (*s++); if (gray) { pixel[i] = (unsigned char) qGray(rgb); i++; } else { pixel[i] = (unsigned char) qRed(rgb); pixel[i+1] = (unsigned char) qGreen(rgb); pixel[i+2] = (unsigned char) qBlue(rgb); i += 3; } } } } *format = Raw; if (depth == 1) { pixelData = runlengthEncode(pixelData); *format = Runlength; } } QByteArray outarr = QPdf::ascii85Encode(pixelData); return outarr;}void QPSPrintEnginePrivate::drawImage(qreal x, qreal y, qreal w, qreal h, const QImage &img, const QImage &mask){ if (!w || !h || img.isNull()) return; int width = img.width(); int height = img.height(); qreal scaleX = width/w; qreal scaleY = height/h; bool gray = (colorMode == QPrinter::GrayScale) || img.allGray(); int splitSize = 21830 * (gray ? 3 : 1); if (width * height > splitSize) { // 65535/3, tolerance for broken printers int images, subheight; images = (width * height + splitSize - 1) / splitSize; subheight = (height + images-1) / images; while (subheight * width > splitSize) { images++; subheight = (height + images-1) / images; } int suby = 0; while(suby < height) { drawImage(x, y + suby/scaleY, w, qMin(subheight, height-suby)/scaleY, img.copy(0, suby, width, qMin(subheight, height-suby)), mask.isNull() ? mask : mask.copy(0, suby, width, qMin(subheight, height-suby))); suby += subheight; } } else { QByteArray out; int size = 0; const char *bits; if (!mask.isNull()) { int format; out = ::compress(mask, true, &format); size = (width+7)/8*height; *currentPage << "/mask currentfile/ASCII85Decode filter" << filters[format] << size << " string readstring\n"; ps_r7(*currentPage, out, out.size()); *currentPage << " pop def\n"; } if (img.depth() == 1) { size = (width+7)/8*height; bits = "1 "; } else if (gray) { size = width*height; bits = "8 "; } else { size = width*height*3; bits = "24 "; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -