00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "qplatformdefs.h"
00025
00026 #include <private/qprintengine_ps_p.h>
00027 #include <private/qpainter_p.h>
00028 #include <private/qfontengine_p.h>
00029 #include <private/qpaintengine_p.h>
00030 #include <private/qpdf_p.h>
00031
00032 #ifndef QT_NO_PRINTER
00033
00034 #include "qprinter.h"
00035 #include "qpainter.h"
00036 #include "qapplication.h"
00037 #include "qpixmap.h"
00038 #include "qimage.h"
00039 #include "qdatetime.h"
00040 #include "qstring.h"
00041 #include "qbytearray.h"
00042 #include "qhash.h"
00043 #include "qbuffer.h"
00044 #include "qsettings.h"
00045 #include "qmap.h"
00046 #include "qbitmap.h"
00047 #include "qregion.h"
00048 #include "qimagewriter.h"
00049 #include <private/qunicodetables_p.h>
00050 #include <private/qpainterpath_p.h>
00051 #include <qdebug.h>
00052 #include <private/qdrawhelper_p.h>
00053
00054 #ifndef Q_OS_WIN
00055 #include <unistd.h>
00056 #endif
00057 #include <stdlib.h>
00058 #include <limits.h>
00059
00060 static bool qt_gen_epsf = false;
00061
00062 void qt_generate_epsf(bool b)
00063 {
00064 qt_gen_epsf = b;
00065 }
00066
00067 static const char *const ps_header =
00068 "/BD{bind def}bind def/d2{dup dup}BD/ED{exch def}BD/D0{0 ED}BD/F{setfont}BD\n"
00069 "/RL{rlineto}BD/CM{currentmatrix}BD/SM{setmatrix}BD/TR{translate}BD/SD\n"
00070 "{setdash}BD/SC{aload pop setrgbcolor}BD/CR{currentfile read pop}BD/i{index}\n"
00071 "BD/scs{setcolorspace}BD/DB{dict dup begin}BD/DE{end def}BD/ie{ifelse}BD/gs\n"
00072 "{gsave}BD/gr{grestore}BD/w{setlinewidth}BD/d{setdash}BD/J{setlinecap}BD/j\n"
00073 "{setlinejoin}BD/scn{3 array astore/BCol exch def}BD/SCN{3 array astore/PCol\n"
00074 "exch def}BD/cm{6 array astore concat}BD/m{moveto}BD/l{lineto}BD/c{curveto}BD\n"
00075 "/h{closepath}BD/W{clip}BD/W*{eoclip}BD/n{newpath}BD/q{gsave 10 dict begin}BD\n"
00076 "/Q{end grestore}BD/re{4 2 roll m dup 0 exch RL exch 0 RL 0 exch neg RL h}BD\n"
00077 "/S{gs PCol SC stroke gr n}BD/BT{gsave 10 dict begin/_m matrix CM def BCol\n"
00078 "SC}BD/ET{end grestore}BD/Tf{/_fs ED findfont[_fs 0 0 _fs 0 0]makefont F}BD\n"
00079 "/Tm{6 array astore concat}BD/Td{translate}BD/Tj{0 0 m show}BD/BDC{pop pop}BD\n"
00080 "/EMC{}BD/BSt 0 def/WFi false def/BCol[1 1 1]def/PCol[0 0 0]def/BDArr[0.94\n"
00081 "0.88 0.63 0.50 0.37 0.12 0.06]def/level3{/languagelevel where{pop\n"
00082 "languagelevel 3 ge}{false}ie}BD/QCIgray D0/QCIcolor D0/QCIindex D0/QCI{\n"
00083 "/colorimage where{pop false 3 colorimage}{exec/QCIcolor ED/QCIgray QCIcolor\n"
00084 "length 3 idiv string def 0 1 QCIcolor length 3 idiv 1 sub{/QCIindex ED/_x\n"
00085 "QCIindex 3 mul def QCIgray QCIindex QCIcolor _x get 0.30 mul QCIcolor _x 1\n"
00086 "add get 0.59 mul QCIcolor _x 2 add get 0.11 mul add add cvi put}for QCIgray\n"
00087 "image}ie}BD/di{gs TR 1 i 1 eq{pop pop false 3 1 roll BCol SC imagemask}{dup\n"
00088 "false ne{level3}{false}ie{/_ma ED 8 eq{/_dc[0 1]def/DeviceGray}{/_dc[0 1 0 1\n"
00089 "0 1]def/DeviceRGB}ie scs/_im ED/_mt ED/_h ED/_w ED <</ImageType 3/DataDict\n"
00090 "<</ImageType 1/Width _w/Height _h/ImageMatrix _mt/DataSource _im\n"
00091 "/BitsPerComponent 8/Decode _dc >>/MaskDict <</ImageType 1/Width _w/Height _h\n"
00092 "/ImageMatrix _mt/DataSource _ma/BitsPerComponent 1/Decode[0 1]>>\n"
00093 "/InterleaveType 3 >> image}{pop 8 4 1 roll 8 eq{image}{QCI}ie}ie}ie gr}BD/BF\n"
00094 "{gs BSt 1 eq{BCol SC WFi{fill}{eofill}ie}if BSt 2 ge BSt 8 le and{BDArr BSt\n"
00095 "2 sub get/_sc ED BCol{1. exch sub _sc mul 1. exch sub}forall 3 array astore\n"
00096 "SC WFi{fill}{eofill}ie}if BSt 9 ge BSt 14 le and{WFi{W}{W*}ie pathbbox 3 i 3\n"
00097 "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"
00098 "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"
00099 "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"
00100 "sub _h l}for}{0 6 _w _h add{dup 0 exch m _w sub _w exch l}for}ie}if BSt 13\n"
00101 "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"
00102 "add{dup _w exch m _w sub 0 exch l}for}ie}if S}if BSt 15 eq{}if BSt 24 eq{}if\n"
00103 "gr}BD/f{/WFi true def BF n}BD/f*{/WFi false def BF n}BD/B{/WFi true def BF S\n"
00104 "n}BD/B*{/WFi false def BF S n}BD/QI{/C save def pageinit q n}BD/QP{Q C\n"
00105 "restore showpage}BD/SPD{/setpagedevice where{<< 3 1 roll >> setpagedevice}{\n"
00106 "pop pop}ie}BD/T1AddMapping{10 dict begin/glyphs ED/fnt ED/current fnt\n"
00107 "/NumGlyphs get def/CMap fnt/CMap get def 0 1 glyphs length 1 sub{glyphs exch\n"
00108 "get/gn ED current dup 256 mod/min ED 256 idiv/maj ED CMap dup maj get dup\n"
00109 "null eq{pop 256 array 0 1 255{1 i exch/.notdef put}for}if dup min gn put maj\n"
00110 "exch put/current current 1 add def}for fnt/CMap CMap put fnt/NumGlyphs\n"
00111 "current put end}def/T1AddGlyphs{10 dict begin/glyphs ED/fnt ED/current fnt\n"
00112 "/NumGlyphs get def/CMap fnt/CMap get def/CharStrings fnt/CharStrings get def\n"
00113 "0 1 glyphs length 2 idiv 1 sub{2 mul dup glyphs exch get/gn ED 1 add glyphs\n"
00114 "exch get/cs ED current dup 256 mod/min ED 256 idiv/maj ED CMap dup maj get\n"
00115 "dup null eq{pop 256 array 0 1 255{1 i exch/.notdef put}for}if dup min gn put\n"
00116 "maj exch put CharStrings gn cs put/current current 1 add def}for fnt\n"
00117 "/CharStrings CharStrings put fnt/CMap CMap put fnt/NumGlyphs current put end\n"
00118 "}def/StringAdd{1 i length 1 i length add string 3 1 roll 2 i 0 3 i\n"
00119 "putinterval 2 i 2 i length 2 i putinterval pop pop}def/T1Setup{10 dict begin\n"
00120 "dup/FontName ED (-Base) StringAdd cvx cvn/Font ED/MaxPage Font/NumGlyphs get\n"
00121 "1 sub 256 idiv def/FDepVector MaxPage 1 add array def/Encoding MaxPage 1 add\n"
00122 "array def 0 1 MaxPage{dup Encoding exch dup put dup/Page ED FontName (-)\n"
00123 "StringAdd exch 20 string cvs StringAdd cvn Font 0 dict copy d2/CMap get Page\n"
00124 "get/Encoding exch put definefont FDepVector exch Page exch put}for FontName\n"
00125 "cvn <</FontType 0/FMapType 2/FontMatrix[1 0 0 1 0 0]/Encoding Encoding\n"
00126 "/FDepVector FDepVector >> definefont pop end}def\n";
00127
00128
00129
00130
00131
00132
00133 static QByteArray wrapDSC(const QByteArray &str)
00134 {
00135 QByteArray dsc = str.simplified();
00136 const int wrapAt = 254;
00137 QByteArray wrapped;
00138 if (dsc.length() < wrapAt)
00139 wrapped = dsc;
00140 else {
00141 wrapped = dsc.left(wrapAt);
00142 QByteArray tmp = dsc.mid(wrapAt);
00143 while (tmp.length() > wrapAt-3) {
00144 wrapped += "\n%%+" + tmp.left(wrapAt-3);
00145 tmp = tmp.mid(wrapAt-3);
00146 }
00147 wrapped += "\n%%+" + tmp;
00148 }
00149 return wrapped + "\n";
00150 }
00151
00152
00153
00154 QPSPrintEnginePrivate::QPSPrintEnginePrivate(QPrinter::PrinterMode m)
00155 : QPdfBaseEnginePrivate(m),
00156 printerState(QPrinter::Idle), hugeDocument(false), headerDone(false)
00157 {
00158 postscript = true;
00159
00160 firstPage = true;
00161
00162 #ifndef QT_NO_SETTINGS
00163 QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
00164 settings.beginGroup(QLatin1String("Qt"));
00165 embedFonts = settings.value(QLatin1String("embedFonts"), true).toBool();
00166 #else
00167 embedFonts = true;
00168 #endif
00169 }
00170
00171 QPSPrintEnginePrivate::~QPSPrintEnginePrivate()
00172 {
00173 }
00174
00175 #include <QDebug>
00176
00177 static void ps_r7(QPdf::ByteStream& stream, const char * s, int l)
00178 {
00179 int i = 0;
00180 uchar line[84];
00181 int col = 0;
00182
00183 while(i < l) {
00184 line[col++] = s[i++];
00185 if (i < l - 1 && col >= 76) {
00186 line[col++] = '\n';
00187 line[col++] = '\0';
00188 stream << (const char *)line;
00189 col = 0;
00190 }
00191 }
00192 if (col > 0) {
00193 while((col&3) != 0)
00194 line[col++] = '%';
00195 line[col++] = '\n';
00196 line[col++] = '\0';
00197 stream << (const char *)line;
00198 }
00199 }
00200
00201 static QByteArray runlengthEncode(const QByteArray &input)
00202 {
00203 if (!input.length())
00204 return input;
00205
00206 const char *data = input.constData();
00207
00208 QByteArray out;
00209 int start = 0;
00210 char last = *data;
00211
00212 enum State {
00213 Undef,
00214 Equal,
00215 Diff
00216 };
00217 State state = Undef;
00218
00219 int i = 1;
00220 int written = 0;
00221 while (1) {
00222 bool flush = (i == input.size());
00223 if (!flush) {
00224 switch(state) {
00225 case Undef:
00226 state = (last == data[i]) ? Equal : Diff;
00227 break;
00228 case Equal:
00229 if (data[i] != last)
00230 flush = true;
00231 break;
00232 case Diff:
00233 if (data[i] == last) {
00234 --i;
00235 flush = true;
00236 }
00237 }
00238 }
00239 if (flush || i - start == 128) {
00240 int size = i - start;
00241 if (state == Equal) {
00242 out.append((char)(uchar)(257-size));
00243 out.append(last);
00244 written += size;
00245 } else {
00246 out.append((char)(uchar)size-1);
00247 while (start < i)
00248 out.append(data[start++]);
00249 written += size;
00250 }
00251 state = Undef;
00252 start = i;
00253 if (i == input.size())
00254 break;
00255 }
00256 last = data[i];
00257 ++i;
00258 };
00259 out.append((char)(uchar)128);
00260 return out;
00261 }
00262
00263 enum format {
00264 Raw,
00265 Runlength,
00266 DCT
00267 };
00268 static const char *const filters[3] = {
00269 " ",
00270 "/RunLengthDecode filter ",
00271 "/DCTDecode filter "
00272 };
00273
00274 static QByteArray compress(const QImage &img, bool gray, int *format)
00275 {
00276
00277 QImage image = img;
00278
00279 if (image.format() == QImage::Format_ARGB32_Premultiplied)
00280 image = image.convertToFormat(QImage::Format_ARGB32);
00281
00282 QByteArray pixelData;
00283 int depth = image.depth();
00284
00285 if (depth != 1 && !gray && QImageWriter::supportedImageFormats().contains("jpeg")) {
00286 QBuffer buffer(&pixelData);
00287 QImageWriter writer(&buffer, "jpeg");
00288 writer.setQuality(94);
00289 writer.write(img);
00290 *format = DCT;
00291 } else {
00292 int width = image.width();
00293 int height = image.height();
00294 int size = width*height;
00295
00296 if (depth == 1)
00297 size = (width+7)/8*height;
00298 else if (!gray)
00299 size = size*3;
00300
00301 pixelData.resize(size);
00302 uchar *pixel = (uchar *)pixelData.data();
00303 int i = 0;
00304 if (depth == 1) {
00305 QImage::Format format = image.format();
00306 memset(pixel, 0xff, size);
00307 for(int y=0; y < height; y++) {
00308 const uchar * s = image.scanLine(y);
00309 for(int x=0; x < width; x++) {
00310
00311 bool b = (format == QImage::Format_MonoLSB) ?
00312 (*(s + (x >> 3)) >> (x & 7)) & 1 :
00313 (*(s + (x >> 3)) << (x & 7)) & 0x80 ;
00314 if (b)
00315 pixel[i >> 3] ^= (0x80 >> (i & 7));
00316 i++;
00317 }
00318
00319 i = (i+7) & 0xffffff8;
00320 }
00321 } else if (depth == 8) {
00322 for(int y=0; y < height; y++) {
00323 const uchar * s = image.scanLine(y);
00324 for(int x=0; x < width; x++) {
00325 QRgb rgb = image.color(s[x]);
00326 if (gray) {
00327 pixel[i] = (unsigned char) qGray(rgb);
00328 i++;
00329 } else {
00330 pixel[i] = (unsigned char) qRed(rgb);
00331 pixel[i+1] = (unsigned char) qGreen(rgb);
00332 pixel[i+2] = (unsigned char) qBlue(rgb);
00333 i += 3;
00334 }
00335 }
00336 }
00337 } else {
00338 for(int y=0; y < height; y++) {
00339 QRgb * s = (QRgb*)(image.scanLine(y));
00340 for(int x=0; x < width; x++) {
00341 QRgb rgb = (*s++);
00342 if (gray) {
00343 pixel[i] = (unsigned char) qGray(rgb);
00344 i++;
00345 } else {
00346 pixel[i] = (unsigned char) qRed(rgb);
00347 pixel[i+1] = (unsigned char) qGreen(rgb);
00348 pixel[i+2] = (unsigned char) qBlue(rgb);
00349 i += 3;
00350 }
00351 }
00352 }
00353 }
00354 *format = Raw;
00355 if (depth == 1) {
00356 pixelData = runlengthEncode(pixelData);
00357 *format = Runlength;
00358 }
00359 }
00360 QByteArray outarr = QPdf::ascii85Encode(pixelData);
00361 return outarr;
00362 }
00363
00364
00365 void QPSPrintEnginePrivate::drawImage(qreal x, qreal y, qreal w, qreal h,
00366 const QImage &img, const QImage &mask)
00367 {
00368 if (!w || !h || img.isNull()) return;
00369
00370 int width = img.width();
00371 int height = img.height();
00372 qreal scaleX = width/w;
00373 qreal scaleY = height/h;
00374
00375 bool gray = (colorMode == QPrinter::GrayScale) ||
00376 img.allGray();
00377 int splitSize = 21830 * (gray ? 3 : 1);
00378 if (width * height > splitSize) {
00379 int images, subheight;
00380 images = (width * height + splitSize - 1) / splitSize;
00381 subheight = (height + images-1) / images;
00382 while (subheight * width > splitSize) {
00383 images++;
00384 subheight = (height + images-1) / images;
00385 }
00386 int suby = 0;
00387 while(suby < height) {
00388 drawImage(x, y + suby/scaleY, w, qMin(subheight, height-suby)/scaleY,
00389 img.copy(0, suby, width, qMin(subheight, height-suby)),
00390 mask.isNull() ? mask : mask.copy(0, suby, width, qMin(subheight, height-suby)));
00391 suby += subheight;
00392 }
00393 } else {
00394 QByteArray out;
00395 int size = 0;
00396 const char *bits;
00397
00398 if (!mask.isNull()) {
00399 int format;
00400 out = ::compress(mask, true, &format);
00401 size = (width+7)/8*height;
00402 *currentPage << "/mask currentfile/ASCII85Decode filter"
00403 << filters[format]
00404 << size << " string readstring\n";
00405 ps_r7(*currentPage, out, out.size());
00406 *currentPage << " pop def\n";
00407 }
00408 if (img.depth() == 1) {
00409 size = (width+7)/8*height;
00410 bits = "1 ";
00411 } else if (gray) {
00412 size = width*height;
00413 bits = "8 ";
00414 } else {
00415 size = width*height*3;
00416 bits = "24 ";
00417 }
00418
00419 int format;
00420 out = ::compress(img, gray, &format);
00421 *currentPage << "/sl currentfile/ASCII85Decode filter"
00422 << filters[format]
00423 << size << " string readstring\n";
00424 ps_r7(*currentPage, out, out.size());
00425 *currentPage << " pop def\n";
00426 *currentPage << width << ' ' << height << "[" << scaleX << " 0 0 " << scaleY << " 0 0]sl "
00427 << bits << (!mask.isNull() ? "mask " : "false ")
00428 << x << ' ' << y << " di\n";
00429 }
00430 }
00431
00432 void QPSPrintEnginePrivate::emitHeader(bool finished)
00433 {
00434 QPSPrintEngine *q = static_cast<QPSPrintEngine *>(q_ptr);
00435 QPrinter *printer = static_cast<QPrinter*>(pdev);
00436
00437 if (creator.isEmpty())
00438 creator = QLatin1String("Qt " QT_VERSION_STR);
00439
00440 QByteArray header;
00441 QPdf::ByteStream s(&header);
00442 s << "%!PS-Adobe-1.0";
00443
00444 qreal scale = 72. / ((qreal) q->metric(QPaintDevice::PdmDpiY));
00445 QRect pageRect = this->pageRect();
00446 QRect paperRect = this->paperRect();
00447 int mtop = pageRect.top() - paperRect.top();
00448 int mleft = pageRect.left() - paperRect.left();
00449 int mbottom = paperRect.bottom() - pageRect.bottom();
00450 int mright = paperRect.right() - pageRect.right();
00451 int width = pageRect.width();
00452 int height = pageRect.height();
00453 if (finished && pageCount == 1 && copies == 1 &&
00454 ((fullPage && qt_gen_epsf) || (outputFileName.endsWith(QLatin1String(".eps"))))
00455 ) {
00456 if (!boundingBox.isValid())
00457 boundingBox.setRect(0, 0, width, height);
00458 if (orientation == QPrinter::Landscape) {
00459 if (!fullPage)
00460 boundingBox.translate(-mleft, -mtop);
00461 s << " EPSF-3.0\n%%BoundingBox: "
00462 << (int)(printer->height() - boundingBox.bottom())*scale
00463 << (int)(printer->width() - boundingBox.right())*scale - 1
00464 << (int)(printer->height() - boundingBox.top())*scale + 1
00465 << (int)(printer->width() - boundingBox.left())*scale;
00466 } else {
00467 if (!fullPage)
00468 boundingBox.translate(mleft, -mtop);
00469 s << " EPSF-3.0\n%%BoundingBox: "
00470 << (int)(boundingBox.left())*scale
00471 << (int)(printer->height() - boundingBox.bottom())*scale - 1
00472 << (int)(boundingBox.right())*scale + 1
00473 << (int)(printer->height() - boundingBox.top())*scale;
00474 }
00475 } else {
00476 int w = width + (fullPage ? 0 : mleft + mright);
00477 int h = height + (fullPage ? 0 : mtop + mbottom);
00478 w = (int)(w*scale);
00479 h = (int)(h*scale);
00480
00481 if (orientation == QPrinter::Landscape)
00482 s << "\n%%BoundingBox: 0 0 " << h << w;
00483 else
00484 s << "\n%%BoundingBox: 0 0 " << w << h;
00485 }
00486 s << "\n" << wrapDSC("%%Creator: " + creator.toUtf8());
00487 if (!title.isEmpty())
00488 s << wrapDSC("%%Title: " + title.toUtf8());
00489 #ifndef QT_NO_DATESTRING
00490 s << "%%CreationDate: " << QDateTime::currentDateTime().toString().toUtf8();
00491 #endif
00492 s << "\n%%Orientation: ";
00493 if (orientation == QPrinter::Landscape)
00494 s << "Landscape";
00495 else
00496 s << "Portrait";
00497
00498 s << "\n%%Pages: (atend)"
00499 "\n%%DocumentFonts: (atend)"
00500 "\n%%EndComments\n"
00501
00502 "%%BeginProlog\n"
00503 "% Prolog copyright 1994-2006 Trolltech. You may copy this prolog in any way\n"
00504 "% that is directly related to this document. For other use of this prolog,\n"
00505 "% see your licensing agreement for Qt.\n"
00506 << ps_header << "\n";
00507
00508
00509 s << "/pageinit {\n";
00510 if (!fullPage) {
00511 if (orientation == QPrinter::Portrait)
00512 s << mleft*scale << mbottom*scale << "translate\n";
00513 else
00514 s << mtop*scale << mleft*scale << "translate\n";
00515 }
00516 if (orientation == QPrinter::Portrait) {
00517 s << "% " << printer->widthMM() << "*" << printer->heightMM()
00518 << "mm (portrait)\n0 " << height*scale
00519 << "translate " << scale << "-" << scale << "scale } def\n";
00520 } else {
00521 s << "% " << printer->heightMM() << "*" << printer->widthMM()
00522 << " mm (landscape)\n 90 rotate " << scale << "-" << scale << "scale } def\n";
00523 }
00524 s << "%%EndProlog\n";
00525
00526
00527 s << "%%BeginSetup\n";
00528 if (copies > 1) {
00529 s << "/#copies " << copies << " def\n";
00530 s << "/NumCopies " << copies << " SPD\n";
00531 s << "/Collate " << (collate ? "true" : "false") << " SPD\n";
00532 }
00533 s << "%%EndSetup\n";
00534
00535 outDevice->write(header);
00536 headerDone = true;
00537 }
00538
00539
00540 void QPSPrintEnginePrivate::emitPages()
00541 {
00542 if (!hugeDocument) {
00543 for (QHash<QFontEngine::FaceId, QFontSubset *>::const_iterator it = fonts.constBegin();
00544 it != fonts.constEnd(); ++it)
00545 outDevice->write((*it)->toType1());
00546 }
00547
00548 outDevice->write(buffer);
00549
00550 buffer = QByteArray();
00551 hugeDocument = true;
00552 }
00553
00554
00555 #ifdef Q_WS_QWS
00556 static const int max_in_memory_size = 2000000;
00557 #else
00558 static const int max_in_memory_size = 32000000;
00559 #endif
00560
00561 void QPSPrintEnginePrivate::flushPage(bool last)
00562 {
00563 if (!last && currentPage->content().isEmpty())
00564 return;
00565
00566 QPdf::ByteStream s(&buffer);
00567 s << "%%Page: "
00568 << pageCount << pageCount << "\n"
00569 << "%%BeginPageSetup\n"
00570 << "QI\n";
00571 if (hugeDocument) {
00572 for (QHash<QFontEngine::FaceId, QFontSubset *>::const_iterator it = fonts.constBegin();
00573 it != fonts.constEnd(); ++it) {
00574 if (currentPage->fonts.contains((*it)->object_id)) {
00575 if ((*it)->downloaded_glyphs == 0) {
00576 s << (*it)->toType1();
00577 (*it)->downloaded_glyphs = 0;
00578 } else {
00579 s << (*it)->type1AddedGlyphs();
00580 }
00581 }
00582 }
00583 }
00584 for (int i = 0; i < currentPage->fonts.size(); ++i)
00585 s << "(F" << QByteArray::number(currentPage->fonts.at(i)) << ") T1Setup\n";
00586
00587 s << "%%EndPageSetup\nq\n"
00588 << currentPage->content()
00589 << "\nQ QP\n";
00590 if (last || hugeDocument || buffer.size() > max_in_memory_size) {
00591
00592 if (!headerDone)
00593 emitHeader(last);
00594 emitPages();
00595 }
00596 pageCount++;
00597 }
00598
00599
00600
00601 QPSPrintEngine::QPSPrintEngine(QPrinter::PrinterMode m)
00602 : QPdfBaseEngine(*(new QPSPrintEnginePrivate(m)),
00603 PrimitiveTransform
00604 | PatternTransform
00605 | PixmapTransform
00606 | PainterPaths
00607 | PatternBrush
00608 )
00609 {
00610 }
00611
00612 static void ignoreSigPipe(bool b)
00613 {
00614 #ifndef QT_NO_LPR
00615 static struct sigaction *users_sigpipe_handler = 0;
00616
00617 if (b) {
00618 if (users_sigpipe_handler != 0)
00619 return;
00620
00621 users_sigpipe_handler = new struct sigaction;
00622 struct sigaction tmp_sigpipe_handler;
00623 tmp_sigpipe_handler.sa_handler = SIG_IGN;
00624 sigemptyset(&tmp_sigpipe_handler.sa_mask);
00625 tmp_sigpipe_handler.sa_flags = 0;
00626
00627 if (sigaction(SIGPIPE, &tmp_sigpipe_handler, users_sigpipe_handler) == -1) {
00628 delete users_sigpipe_handler;
00629 users_sigpipe_handler = 0;
00630 }
00631 }
00632 else {
00633 if (users_sigpipe_handler == 0)
00634 return;
00635
00636 if (sigaction(SIGPIPE, users_sigpipe_handler, 0) == -1)
00637 qWarning("QPSPrintEngine: Could not restore SIGPIPE handler");
00638
00639 delete users_sigpipe_handler;
00640 users_sigpipe_handler = 0;
00641 }
00642 #else
00643 Q_UNUSED(b);
00644 #endif
00645 }
00646 QPSPrintEngine::~QPSPrintEngine()
00647 {
00648 Q_D(QPSPrintEngine);
00649 if (d->fd >= 0)
00650 #if defined(Q_OS_WIN) && defined(_MSC_VER) && _MSC_VER >= 1400
00651 ::_close(d->fd);
00652 #else
00653 ::close(d->fd);
00654 #endif
00655 }
00656
00657 bool QPSPrintEngine::begin(QPaintDevice *pdev)
00658 {
00659 Q_D(QPSPrintEngine);
00660
00661 if (d->fd >= 0)
00662 return true;
00663
00664 if(!QPdfBaseEngine::begin(pdev))
00665 return false;
00666
00667 d->pageCount = 1;
00668
00669 d->pen = QPen(Qt::black);
00670 d->brush = Qt::NoBrush;
00671 d->hasPen = true;
00672 d->hasBrush = false;
00673 d->clipEnabled = false;
00674 d->allClipped = false;
00675 d->boundingBox = QRect();
00676 d->fontsUsed = "";
00677 d->hugeDocument = false;
00678
00679 setActive(true);
00680 d->printerState = QPrinter::Active;
00681
00682 newPage();
00683
00684 return true;
00685 }
00686
00687 bool QPSPrintEngine::end()
00688 {
00689 Q_D(QPSPrintEngine);
00690
00691
00692
00693 ignoreSigPipe(true);
00694 d->flushPage(true);
00695 QByteArray trailer;
00696 QPdf::ByteStream s(&trailer);
00697 s << "%%Trailer\n";
00698 s << "%%Pages: " << d->pageCount - 1 << "\n" <<
00699 wrapDSC("%%DocumentFonts: " + d->fontsUsed);
00700 s << "%%EOF\n";
00701 d->outDevice->write(trailer);
00702 ignoreSigPipe(false);
00703
00704 QPdfBaseEngine::end();
00705
00706 d->firstPage = true;
00707 d->headerDone = false;
00708
00709 setActive(false);
00710 d->printerState = QPrinter::Idle;
00711 d->pdev = 0;
00712
00713 return true;
00714 }
00715
00716 void QPSPrintEngine::setBrush()
00717 {
00718 Q_D(QPSPrintEngine);
00719 #if 0
00720 bool specifyColor;
00721 int gStateObject = 0;
00722 int patternObject = d->addBrushPattern(brush, d->stroker.matrix, brushOrigin, &specifyColor, &gStateObject);
00723
00724 *d->currentPage << (patternObject ? "/PCSp cs " : "/CSp cs ");
00725 if (specifyColor) {
00726 QColor rgba = brush.color();
00727 *d->currentPage << rgba.redF()
00728 << rgba.greenF()
00729 << rgba.blueF();
00730 }
00731 if (patternObject)
00732 *d->currentPage << "/Pat" << patternObject;
00733 *d->currentPage << "scn\n";
00734 #endif
00735 QColor rgba = d->brush.color();
00736 *d->currentPage << rgba.redF()
00737 << rgba.greenF()
00738 << rgba.blueF()
00739 << "scn\n";
00740 *d->currentPage << "/BSt " << d->brush.style() << "def\n";
00741 }
00742
00743 void QPSPrintEngine::drawImageInternal(const QRectF &r, QImage image, bool bitmap)
00744 {
00745 Q_D(QPSPrintEngine);
00746 if (d->clipEnabled && d->allClipped)
00747 return;
00748 if (bitmap && image.depth() != 1)
00749 bitmap = false;
00750 QImage mask;
00751 if (!bitmap) {
00752 if (image.format() == QImage::Format_Mono || image.format() == QImage::Format_MonoLSB)
00753 image = image.convertToFormat(QImage::Format_Indexed8);
00754 if (image.hasAlphaChannel()) {
00755
00756 int xscale = image.width();
00757 xscale *= xscale <= 800 ? 4 : (xscale <= 1600 ? 2 : 1);
00758 int yscale = image.height();
00759 yscale *= yscale <= 800 ? 4 : (yscale <= 1600 ? 2 : 1);
00760 image = image.scaled(xscale, yscale);
00761 mask = image.createAlphaMask(Qt::OrderedAlphaDither);
00762 }
00763 }
00764 *d->currentPage << "q\n";
00765 if(!d->simplePen)
00766 *d->currentPage << QPdf::generateMatrix(d->stroker.matrix);
00767 QBrush b = d->brush;
00768 if (image.depth() == 1) {
00769
00770 d->brush = d->pen.brush();
00771 setBrush();
00772 }
00773 d->drawImage(r.x(), r.y(), r.width(), r.height(), image, mask);
00774 *d->currentPage << "Q\n";
00775 d->brush = b;
00776 }
00777
00778
00779 void QPSPrintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
00780 Qt::ImageConversionFlags)
00781 {
00782 QImage image = img.copy(sr.toRect());
00783 drawImageInternal(r, image, false);
00784 }
00785
00786 void QPSPrintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
00787 {
00788 QImage img = pm.copy(sr.toRect()).toImage();
00789 drawImageInternal(r, img, true);
00790 }
00791
00792 void QPSPrintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &p)
00793 {
00794 Q_D(QPSPrintEngine);
00795 if (d->clipEnabled && d->allClipped)
00796 return;
00797
00798 qreal yPos = r.y();
00799 qreal yOff = p.y();
00800 while(yPos < r.y() + r.height()) {
00801 qreal drawH = pixmap.height() - yOff;
00802 if (yPos + drawH > r.y() + r.height())
00803 drawH = r.y() + r.height() - yPos;
00804 qreal xPos = r.x();
00805 qreal xOff = p.x();
00806 while(xPos < r.x() + r.width()) {
00807 qreal drawW = pixmap.width() - xOff;
00808 if (xPos + drawW > r.x() + r.width())
00809 drawW = r.x() + r.width() - xPos;
00810
00811 painter()->drawPixmap(QPointF(xPos, yPos).toPoint(), pixmap,
00812 QRectF(xOff, yOff, drawW, drawH).toRect());
00813 xPos += drawW;
00814 xOff = 0;
00815 }
00816 yPos += drawH;
00817 yOff = 0;
00818 }
00819
00820 }
00821
00822 bool QPSPrintEngine::newPage()
00823 {
00824 Q_D(QPSPrintEngine);
00825
00826
00827 ignoreSigPipe(true);
00828 if (!d->firstPage)
00829 d->flushPage();
00830 d->firstPage = false;
00831 ignoreSigPipe(false);
00832
00833 delete d->currentPage;
00834 d->currentPage = new QPdfPage;
00835 d->stroker.stream = d->currentPage;
00836
00837 return QPdfBaseEngine::newPage();
00838 }
00839
00840 bool QPSPrintEngine::abort()
00841 {
00842
00843 return false;
00844 }
00845
00846 QPrinter::PrinterState QPSPrintEngine::printerState() const
00847 {
00848 Q_D(const QPSPrintEngine);
00849 return d->printerState;
00850 }
00851
00852 #endif // QT_NO_PRINTER
00853
00854