| 1 | /****************************************************************************
|
|---|
| 2 | **
|
|---|
| 3 | ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|---|
| 4 | ** All rights reserved.
|
|---|
| 5 | ** Contact: Nokia Corporation ([email protected])
|
|---|
| 6 | **
|
|---|
| 7 | ** This file is part of the QtGui module of the Qt Toolkit.
|
|---|
| 8 | **
|
|---|
| 9 | ** $QT_BEGIN_LICENSE:LGPL$
|
|---|
| 10 | ** Commercial Usage
|
|---|
| 11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
|---|
| 12 | ** accordance with the Qt Commercial License Agreement provided with the
|
|---|
| 13 | ** Software or, alternatively, in accordance with the terms contained in
|
|---|
| 14 | ** a written agreement between you and Nokia.
|
|---|
| 15 | **
|
|---|
| 16 | ** GNU Lesser General Public License Usage
|
|---|
| 17 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
|---|
| 18 | ** General Public License version 2.1 as published by the Free Software
|
|---|
| 19 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
|---|
| 20 | ** packaging of this file. Please review the following information to
|
|---|
| 21 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
|---|
| 22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|---|
| 23 | **
|
|---|
| 24 | ** In addition, as a special exception, Nokia gives you certain additional
|
|---|
| 25 | ** rights. These rights are described in the Nokia Qt LGPL Exception
|
|---|
| 26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|---|
| 27 | **
|
|---|
| 28 | ** GNU General Public License Usage
|
|---|
| 29 | ** Alternatively, this file may be used under the terms of the GNU
|
|---|
| 30 | ** General Public License version 3.0 as published by the Free Software
|
|---|
| 31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
|---|
| 32 | ** packaging of this file. Please review the following information to
|
|---|
| 33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
|---|
| 34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
|---|
| 35 | **
|
|---|
| 36 | ** If you have questions regarding the use of this file, please contact
|
|---|
| 37 | ** Nokia at [email protected].
|
|---|
| 38 | ** $QT_END_LICENSE$
|
|---|
| 39 | **
|
|---|
| 40 | ****************************************************************************/
|
|---|
| 41 |
|
|---|
| 42 | #include "qplatformdefs.h"
|
|---|
| 43 |
|
|---|
| 44 | #include <private/qprintengine_ps_p.h>
|
|---|
| 45 | #include <private/qpainter_p.h>
|
|---|
| 46 | #include <private/qfontengine_p.h>
|
|---|
| 47 | #include <private/qpaintengine_p.h>
|
|---|
| 48 | #include <private/qpdf_p.h>
|
|---|
| 49 |
|
|---|
| 50 | #ifndef QT_NO_PRINTER
|
|---|
| 51 |
|
|---|
| 52 | #include "qprinter.h"
|
|---|
| 53 | #include "qpainter.h"
|
|---|
| 54 | #include "qapplication.h"
|
|---|
| 55 | #include "qpixmap.h"
|
|---|
| 56 | #include "qimage.h"
|
|---|
| 57 | #include "qdatetime.h"
|
|---|
| 58 | #include "qstring.h"
|
|---|
| 59 | #include "qbytearray.h"
|
|---|
| 60 | #include "qhash.h"
|
|---|
| 61 | #include "qbuffer.h"
|
|---|
| 62 | #include "qsettings.h"
|
|---|
| 63 | #include "qmap.h"
|
|---|
| 64 | #include "qbitmap.h"
|
|---|
| 65 | #include "qregion.h"
|
|---|
| 66 | #include "qimagewriter.h"
|
|---|
| 67 | #include <private/qunicodetables_p.h>
|
|---|
| 68 | #include <private/qpainterpath_p.h>
|
|---|
| 69 | #include <qdebug.h>
|
|---|
| 70 | #include <private/qdrawhelper_p.h>
|
|---|
| 71 | #include <private/qmutexpool_p.h>
|
|---|
| 72 |
|
|---|
| 73 | #ifndef Q_OS_WIN
|
|---|
| 74 | #include <unistd.h>
|
|---|
| 75 | #endif
|
|---|
| 76 | #include <stdlib.h>
|
|---|
| 77 | #include <limits.h>
|
|---|
| 78 |
|
|---|
| 79 | QT_BEGIN_NAMESPACE
|
|---|
| 80 |
|
|---|
| 81 | static bool qt_gen_epsf = false;
|
|---|
| 82 |
|
|---|
| 83 | void qt_generate_epsf(bool b)
|
|---|
| 84 | {
|
|---|
| 85 | qt_gen_epsf = b;
|
|---|
| 86 | }
|
|---|
| 87 |
|
|---|
| 88 | static const char *const ps_header =
|
|---|
| 89 | "/BD{bind def}bind def/d2{dup dup}BD/ED{exch def}BD/D0{0 ED}BD/F{setfont}BD\n"
|
|---|
| 90 | "/RL{rlineto}BD/CM{currentmatrix}BD/SM{setmatrix}BD/TR{translate}BD/SD\n"
|
|---|
| 91 | "{setdash}BD/SC{aload pop setrgbcolor}BD/CR{currentfile read pop}BD/i{index}\n"
|
|---|
| 92 | "BD/scs{setcolorspace}BD/DB{dict dup begin}BD/DE{end def}BD/ie{ifelse}BD/gs\n"
|
|---|
| 93 | "{gsave}BD/gr{grestore}BD/w{setlinewidth}BD/d{setdash}BD/J{setlinecap}BD/j\n"
|
|---|
| 94 | "{setlinejoin}BD/scn{3 array astore/BCol exch def}BD/SCN{3 array astore/PCol\n"
|
|---|
| 95 | "exch def}BD/cm{6 array astore concat}BD/m{moveto}BD/l{lineto}BD/c{curveto}BD\n"
|
|---|
| 96 | "/h{closepath}BD/W{clip}BD/W*{eoclip}BD/n{newpath}BD/q{gsave 10 dict begin}BD\n"
|
|---|
| 97 | "/Q{end grestore}BD/re{4 2 roll m dup 0 exch RL exch 0 RL 0 exch neg RL h}BD\n"
|
|---|
| 98 | "/S{gs PCol SC stroke gr n}BD/BT{gsave 10 dict begin/_m matrix CM def BCol\n"
|
|---|
| 99 | "SC}BD/ET{end grestore}BD/Tf{/_fs ED findfont[_fs 0 0 _fs 0 0]makefont F}BD\n"
|
|---|
| 100 | "/Tm{6 array astore concat}BD/Td{translate}BD/Tj{0 0 m show}BD/BDC{pop pop}BD\n"
|
|---|
| 101 | "/EMC{}BD/BSt 0 def/WFi false def/BCol[1 1 1]def/PCol[0 0 0]def/BDArr[0.94\n"
|
|---|
| 102 | "0.88 0.63 0.50 0.37 0.12 0.06]def/level3{/languagelevel where{pop\n"
|
|---|
| 103 | "languagelevel 3 ge}{false}ie}BD/QCIgray D0/QCIcolor D0/QCIindex D0/QCI{\n"
|
|---|
| 104 | "/colorimage where{pop false 3 colorimage}{exec/QCIcolor ED/QCIgray QCIcolor\n"
|
|---|
| 105 | "length 3 idiv string def 0 1 QCIcolor length 3 idiv 1 sub{/QCIindex ED/_x\n"
|
|---|
| 106 | "QCIindex 3 mul def QCIgray QCIindex QCIcolor _x get 0.30 mul QCIcolor _x 1\n"
|
|---|
| 107 | "add get 0.59 mul QCIcolor _x 2 add get 0.11 mul add add cvi put}for QCIgray\n"
|
|---|
| 108 | "image}ie}BD/di{gs TR 1 i 1 eq{pop pop false 3 1 roll BCol SC imagemask}{dup\n"
|
|---|
| 109 | "false ne{level3}{false}ie{/_ma ED 8 eq{/_dc[0 1]def/DeviceGray}{/_dc[0 1 0 1\n"
|
|---|
| 110 | "0 1]def/DeviceRGB}ie scs/_im ED/_mt ED/_h ED/_w ED <</ImageType 3/DataDict\n"
|
|---|
| 111 | "<</ImageType 1/Width _w/Height _h/ImageMatrix _mt/DataSource _im\n"
|
|---|
| 112 | "/BitsPerComponent 8/Decode _dc >>/MaskDict <</ImageType 1/Width _w/Height _h\n"
|
|---|
| 113 | "/ImageMatrix _mt/DataSource _ma/BitsPerComponent 1/Decode[0 1]>>\n"
|
|---|
| 114 | "/InterleaveType 3 >> image}{pop 8 4 1 roll 8 eq{image}{QCI}ie}ie}ie gr}BD/BF\n"
|
|---|
| 115 | "{gs BSt 1 eq{BCol SC WFi{fill}{eofill}ie}if BSt 2 ge BSt 8 le and{BDArr BSt\n"
|
|---|
| 116 | "2 sub get/_sc ED BCol{1. exch sub _sc mul 1. exch sub}forall 3 array astore\n"
|
|---|
| 117 | "SC WFi{fill}{eofill}ie}if BSt 9 ge BSt 14 le and{WFi{W}{W*}ie pathbbox 3 i 3\n"
|
|---|
| 118 | "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"
|
|---|
| 119 | "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"
|
|---|
| 120 | "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"
|
|---|
| 121 | "sub _h l}for}{0 6 _w _h add{dup 0 exch m _w sub _w exch l}for}ie}if BSt 13\n"
|
|---|
| 122 | "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"
|
|---|
| 123 | "add{dup _w exch m _w sub 0 exch l}for}ie}if stroke}if BSt 15 eq{}if BSt 24\n"
|
|---|
| 124 | "eq{}if gr}BD/f{/WFi true def BF n}BD/f*{/WFi false def BF n}BD/B{/WFi true\n"
|
|---|
| 125 | "def BF S n}BD/B*{/WFi false def BF S n}BD/QI{/C save def pageinit q n}BD/QP{\n"
|
|---|
| 126 | "Q C restore showpage}BD/SPD{/setpagedevice where{<< 3 1 roll >>\n"
|
|---|
| 127 | "setpagedevice}{pop pop}ie}BD/T1AddMapping{10 dict begin/glyphs ED/fnt ED\n"
|
|---|
| 128 | "/current fnt/NumGlyphs get def/CMap fnt/CMap get def 0 1 glyphs length 1 sub\n"
|
|---|
| 129 | "{glyphs exch get/gn ED current dup 256 mod/min ED 256 idiv/maj ED CMap dup\n"
|
|---|
| 130 | "maj get dup null eq{pop 256 array 0 1 255{1 i exch/.notdef put}for}if dup\n"
|
|---|
| 131 | "min gn put maj exch put/current current 1 add def}for fnt/CMap CMap put fnt\n"
|
|---|
| 132 | "/NumGlyphs current put end}def/T1AddGlyphs{10 dict begin/glyphs ED/fnt ED\n"
|
|---|
| 133 | "/current fnt/NumGlyphs get def/CMap fnt/CMap get def/CharStrings fnt\n"
|
|---|
| 134 | "/CharStrings get def 0 1 glyphs length 2 idiv 1 sub{2 mul dup glyphs exch\n"
|
|---|
| 135 | "get/gn ED 1 add glyphs exch get/cs ED current dup 256 mod/min ED 256 idiv\n"
|
|---|
| 136 | "/maj ED CMap dup maj get dup null eq{pop 256 array 0 1 255{1 i exch/.notdef\n"
|
|---|
| 137 | "put}for}if dup min gn put maj exch put CharStrings gn cs put/current current\n"
|
|---|
| 138 | "1 add def}for fnt/CharStrings CharStrings put fnt/CMap CMap put fnt\n"
|
|---|
| 139 | "/NumGlyphs current put end}def/StringAdd{1 i length 1 i length add string 3\n"
|
|---|
| 140 | "1 roll 2 i 0 3 i putinterval 2 i 2 i length 2 i putinterval pop pop}def\n"
|
|---|
| 141 | "/T1Setup{10 dict begin dup/FontName ED (-Base) StringAdd cvx cvn/Font ED\n"
|
|---|
| 142 | "/MaxPage Font/NumGlyphs get 1 sub 256 idiv def/FDepVector MaxPage 1 add\n"
|
|---|
| 143 | "array def/Encoding MaxPage 1 add array def 0 1 MaxPage{dup Encoding exch dup\n"
|
|---|
| 144 | "put dup/Page ED FontName (-) StringAdd exch 20 string cvs StringAdd cvn Font\n"
|
|---|
| 145 | "0 dict copy d2/CMap get Page get/Encoding exch put definefont FDepVector\n"
|
|---|
| 146 | "exch Page exch put}for FontName cvn <</FontType 0/FMapType 2/FontMatrix[1 0\n"
|
|---|
| 147 | "0 1 0 0]/Encoding Encoding/FDepVector FDepVector >> definefont pop end}def\n";
|
|---|
| 148 |
|
|---|
| 149 |
|
|---|
| 150 |
|
|---|
| 151 | // ------------------------------End of static data ----------------------------------
|
|---|
| 152 |
|
|---|
| 153 | // make sure DSC comments are not longer than 255 chars per line.
|
|---|
| 154 | static QByteArray wrapDSC(const QByteArray &str)
|
|---|
| 155 | {
|
|---|
| 156 | QByteArray dsc = str.simplified();
|
|---|
| 157 | const int wrapAt = 254;
|
|---|
| 158 | QByteArray wrapped;
|
|---|
| 159 | if (dsc.length() < wrapAt)
|
|---|
| 160 | wrapped = dsc;
|
|---|
| 161 | else {
|
|---|
| 162 | wrapped = dsc.left(wrapAt);
|
|---|
| 163 | QByteArray tmp = dsc.mid(wrapAt);
|
|---|
| 164 | while (tmp.length() > wrapAt-3) {
|
|---|
| 165 | wrapped += "\n%%+" + tmp.left(wrapAt-3);
|
|---|
| 166 | tmp = tmp.mid(wrapAt-3);
|
|---|
| 167 | }
|
|---|
| 168 | wrapped += "\n%%+" + tmp;
|
|---|
| 169 | }
|
|---|
| 170 | return wrapped + '\n';
|
|---|
| 171 | }
|
|---|
| 172 |
|
|---|
| 173 | // ----------------------------- Internal class declarations -----------------------------
|
|---|
| 174 |
|
|---|
| 175 | QPSPrintEnginePrivate::QPSPrintEnginePrivate(QPrinter::PrinterMode m)
|
|---|
| 176 | : QPdfBaseEnginePrivate(m),
|
|---|
| 177 | printerState(QPrinter::Idle), hugeDocument(false), headerDone(false)
|
|---|
| 178 | {
|
|---|
| 179 | useAlphaEngine = true;
|
|---|
| 180 | postscript = true;
|
|---|
| 181 |
|
|---|
| 182 | firstPage = true;
|
|---|
| 183 |
|
|---|
| 184 | #ifndef QT_NO_SETTINGS
|
|---|
| 185 | QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
|
|---|
| 186 | settings.beginGroup(QLatin1String("Qt"));
|
|---|
| 187 | embedFonts = settings.value(QLatin1String("embedFonts"), true).toBool();
|
|---|
| 188 | #else
|
|---|
| 189 | embedFonts = true;
|
|---|
| 190 | #endif
|
|---|
| 191 | }
|
|---|
| 192 |
|
|---|
| 193 | QPSPrintEnginePrivate::~QPSPrintEnginePrivate()
|
|---|
| 194 | {
|
|---|
| 195 | }
|
|---|
| 196 |
|
|---|
| 197 | QT_BEGIN_INCLUDE_NAMESPACE
|
|---|
| 198 | #include <qdebug.h>
|
|---|
| 199 | QT_END_INCLUDE_NAMESPACE
|
|---|
| 200 |
|
|---|
| 201 | static void ps_r7(QPdf::ByteStream& stream, const char * s, int l)
|
|---|
| 202 | {
|
|---|
| 203 | int i = 0;
|
|---|
| 204 | uchar line[84];
|
|---|
| 205 | int col = 0;
|
|---|
| 206 |
|
|---|
| 207 | while(i < l) {
|
|---|
| 208 | line[col++] = s[i++];
|
|---|
| 209 | if (i < l - 1 && col >= 76) {
|
|---|
| 210 | line[col++] = '\n';
|
|---|
| 211 | line[col++] = '\0';
|
|---|
| 212 | stream << (const char *)line;
|
|---|
| 213 | col = 0;
|
|---|
| 214 | }
|
|---|
| 215 | }
|
|---|
| 216 | if (col > 0) {
|
|---|
| 217 | while((col&3) != 0)
|
|---|
| 218 | line[col++] = '%'; // use a comment as padding
|
|---|
| 219 | line[col++] = '\n';
|
|---|
| 220 | line[col++] = '\0';
|
|---|
| 221 | stream << (const char *)line;
|
|---|
| 222 | }
|
|---|
| 223 | }
|
|---|
| 224 |
|
|---|
| 225 | static QByteArray runlengthEncode(const QByteArray &input)
|
|---|
| 226 | {
|
|---|
| 227 | if (!input.length())
|
|---|
| 228 | return input;
|
|---|
| 229 |
|
|---|
| 230 | const char *data = input.constData();
|
|---|
| 231 |
|
|---|
| 232 | QByteArray out;
|
|---|
| 233 | int start = 0;
|
|---|
| 234 | char last = *data;
|
|---|
| 235 |
|
|---|
| 236 | enum State {
|
|---|
| 237 | Undef,
|
|---|
| 238 | Equal,
|
|---|
| 239 | Diff
|
|---|
| 240 | };
|
|---|
| 241 | State state = Undef;
|
|---|
| 242 |
|
|---|
| 243 | int i = 1;
|
|---|
| 244 | int written = 0;
|
|---|
| 245 | while (1) {
|
|---|
| 246 | bool flush = (i == input.size());
|
|---|
| 247 | if (!flush) {
|
|---|
| 248 | switch(state) {
|
|---|
| 249 | case Undef:
|
|---|
| 250 | state = (last == data[i]) ? Equal : Diff;
|
|---|
| 251 | break;
|
|---|
| 252 | case Equal:
|
|---|
| 253 | if (data[i] != last)
|
|---|
| 254 | flush = true;
|
|---|
| 255 | break;
|
|---|
| 256 | case Diff:
|
|---|
| 257 | if (data[i] == last) {
|
|---|
| 258 | --i;
|
|---|
| 259 | flush = true;
|
|---|
| 260 | }
|
|---|
| 261 | }
|
|---|
| 262 | }
|
|---|
| 263 | if (flush || i - start == 128) {
|
|---|
| 264 | int size = i - start;
|
|---|
| 265 | if (state == Equal) {
|
|---|
| 266 | out.append((char)(uchar)(257-size));
|
|---|
| 267 | out.append(last);
|
|---|
| 268 | written += size;
|
|---|
| 269 | } else {
|
|---|
| 270 | out.append((char)(uchar)size-1);
|
|---|
| 271 | while (start < i)
|
|---|
| 272 | out.append(data[start++]);
|
|---|
| 273 | written += size;
|
|---|
| 274 | }
|
|---|
| 275 | state = Undef;
|
|---|
| 276 | start = i;
|
|---|
| 277 | if (i == input.size())
|
|---|
| 278 | break;
|
|---|
| 279 | }
|
|---|
| 280 | last = data[i];
|
|---|
| 281 | ++i;
|
|---|
| 282 | };
|
|---|
| 283 | out.append((char)(uchar)128);
|
|---|
| 284 | return out;
|
|---|
| 285 | }
|
|---|
| 286 |
|
|---|
| 287 | enum format {
|
|---|
| 288 | Raw,
|
|---|
| 289 | Runlength,
|
|---|
| 290 | DCT
|
|---|
| 291 | };
|
|---|
| 292 | static const char *const filters[3] = {
|
|---|
| 293 | " ",
|
|---|
| 294 | "/RunLengthDecode filter ",
|
|---|
| 295 | "/DCTDecode filter "
|
|---|
| 296 | };
|
|---|
| 297 |
|
|---|
| 298 | static QByteArray compressHelper(const QImage &image, bool gray, int *format)
|
|---|
| 299 | {
|
|---|
| 300 | // we can't use premultiplied here
|
|---|
| 301 | QByteArray pixelData;
|
|---|
| 302 | int depth = image.depth();
|
|---|
| 303 |
|
|---|
| 304 | Q_ASSERT(image.format() != QImage::Format_ARGB32_Premultiplied);
|
|---|
| 305 |
|
|---|
| 306 | if (depth != 1 && !gray && QImageWriter::supportedImageFormats().contains("jpeg")) {
|
|---|
| 307 | QBuffer buffer(&pixelData);
|
|---|
| 308 | QImageWriter writer(&buffer, "jpeg");
|
|---|
| 309 | writer.setQuality(94);
|
|---|
| 310 | writer.write(image);
|
|---|
| 311 | *format = DCT;
|
|---|
| 312 | } else {
|
|---|
| 313 | int width = image.width();
|
|---|
| 314 | int height = image.height();
|
|---|
| 315 | int size = width*height;
|
|---|
| 316 |
|
|---|
| 317 | if (depth == 1)
|
|---|
| 318 | size = (width+7)/8*height;
|
|---|
| 319 | else if (!gray)
|
|---|
| 320 | size = size*3;
|
|---|
| 321 |
|
|---|
| 322 | pixelData.resize(size);
|
|---|
| 323 | uchar *pixel = (uchar *)pixelData.data();
|
|---|
| 324 | int i = 0;
|
|---|
| 325 | if (depth == 1) {
|
|---|
| 326 | QImage::Format format = image.format();
|
|---|
| 327 | memset(pixel, 0xff, size);
|
|---|
| 328 | for(int y=0; y < height; y++) {
|
|---|
| 329 | const uchar * s = image.scanLine(y);
|
|---|
| 330 | for(int x=0; x < width; x++) {
|
|---|
| 331 | // need to copy bit for bit...
|
|---|
| 332 | bool b = (format == QImage::Format_MonoLSB) ?
|
|---|
| 333 | (*(s + (x >> 3)) >> (x & 7)) & 1 :
|
|---|
| 334 | (*(s + (x >> 3)) << (x & 7)) & 0x80 ;
|
|---|
| 335 | if (b)
|
|---|
| 336 | pixel[i >> 3] ^= (0x80 >> (i & 7));
|
|---|
| 337 | i++;
|
|---|
| 338 | }
|
|---|
| 339 | // we need to align to 8 bit here
|
|---|
| 340 | i = (i+7) & 0xffffff8;
|
|---|
| 341 | }
|
|---|
| 342 | } else if (depth == 8) {
|
|---|
| 343 | for(int y=0; y < height; y++) {
|
|---|
| 344 | const uchar * s = image.scanLine(y);
|
|---|
| 345 | for(int x=0; x < width; x++) {
|
|---|
| 346 | QRgb rgb = image.color(s[x]);
|
|---|
| 347 | if (gray) {
|
|---|
| 348 | pixel[i] = (unsigned char) qGray(rgb);
|
|---|
| 349 | i++;
|
|---|
| 350 | } else {
|
|---|
| 351 | pixel[i] = (unsigned char) qRed(rgb);
|
|---|
| 352 | pixel[i+1] = (unsigned char) qGreen(rgb);
|
|---|
| 353 | pixel[i+2] = (unsigned char) qBlue(rgb);
|
|---|
| 354 | i += 3;
|
|---|
| 355 | }
|
|---|
| 356 | }
|
|---|
| 357 | }
|
|---|
| 358 | } else {
|
|---|
| 359 | for(int y=0; y < height; y++) {
|
|---|
| 360 | QRgb * s = (QRgb*)(image.scanLine(y));
|
|---|
| 361 | for(int x=0; x < width; x++) {
|
|---|
| 362 | QRgb rgb = (*s++);
|
|---|
| 363 | if (gray) {
|
|---|
| 364 | pixel[i] = (unsigned char) qGray(rgb);
|
|---|
| 365 | i++;
|
|---|
| 366 | } else {
|
|---|
| 367 | pixel[i] = (unsigned char) qRed(rgb);
|
|---|
| 368 | pixel[i+1] = (unsigned char) qGreen(rgb);
|
|---|
| 369 | pixel[i+2] = (unsigned char) qBlue(rgb);
|
|---|
| 370 | i += 3;
|
|---|
| 371 | }
|
|---|
| 372 | }
|
|---|
| 373 | }
|
|---|
| 374 | }
|
|---|
| 375 | *format = Raw;
|
|---|
| 376 | if (depth == 1) {
|
|---|
| 377 | pixelData = runlengthEncode(pixelData);
|
|---|
| 378 | *format = Runlength;
|
|---|
| 379 | }
|
|---|
| 380 | }
|
|---|
| 381 | QByteArray outarr = QPdf::ascii85Encode(pixelData);
|
|---|
| 382 | return outarr;
|
|---|
| 383 | }
|
|---|
| 384 |
|
|---|
| 385 | void QPSPrintEnginePrivate::drawImageHelper(qreal x, qreal y, qreal w, qreal h, const QImage &img,
|
|---|
| 386 | const QImage &mask, bool gray, qreal scaleX, qreal scaleY)
|
|---|
| 387 | {
|
|---|
| 388 | Q_UNUSED(h);
|
|---|
| 389 | Q_UNUSED(w);
|
|---|
| 390 | int width = img.width();
|
|---|
| 391 | int height = img.height();
|
|---|
| 392 |
|
|---|
| 393 | QByteArray out;
|
|---|
| 394 | int size = 0;
|
|---|
| 395 | const char *bits;
|
|---|
| 396 |
|
|---|
| 397 | if (!mask.isNull()) {
|
|---|
| 398 | int format;
|
|---|
| 399 | out = compressHelper(mask, true, &format);
|
|---|
| 400 | size = (width+7)/8*height;
|
|---|
| 401 | *currentPage << "/mask currentfile/ASCII85Decode filter"
|
|---|
| 402 | << filters[format]
|
|---|
| 403 | << size << " string readstring\n";
|
|---|
| 404 | ps_r7(*currentPage, out, out.size());
|
|---|
| 405 | *currentPage << " pop def\n";
|
|---|
| 406 | }
|
|---|
| 407 | if (img.depth() == 1) {
|
|---|
| 408 | size = (width+7)/8*height;
|
|---|
| 409 | bits = "1 ";
|
|---|
| 410 | } else if (gray) {
|
|---|
| 411 | size = width*height;
|
|---|
| 412 | bits = "8 ";
|
|---|
| 413 | } else {
|
|---|
| 414 | size = width*height*3;
|
|---|
| 415 | bits = "24 ";
|
|---|
| 416 | }
|
|---|
| 417 |
|
|---|
| 418 | int format;
|
|---|
| 419 | out = compressHelper(img, gray, &format);
|
|---|
| 420 | *currentPage << "/sl currentfile/ASCII85Decode filter"
|
|---|
| 421 | << filters[format]
|
|---|
| 422 | << size << " string readstring\n";
|
|---|
| 423 | ps_r7(*currentPage, out, out.size());
|
|---|
| 424 | *currentPage << " pop def\n";
|
|---|
| 425 | *currentPage << width << ' ' << height << '[' << scaleX << " 0 0 " << scaleY << " 0 0]sl "
|
|---|
| 426 | << bits << (!mask.isNull() ? "mask " : "false ")
|
|---|
| 427 | << x << ' ' << y << " di\n";
|
|---|
| 428 | }
|
|---|
| 429 |
|
|---|
| 430 |
|
|---|
| 431 | void QPSPrintEnginePrivate::drawImage(qreal x, qreal y, qreal w, qreal h,
|
|---|
| 432 | const QImage &image, const QImage &msk)
|
|---|
| 433 | {
|
|---|
| 434 | if (!w || !h || image.isNull()) return;
|
|---|
| 435 |
|
|---|
| 436 | QImage img(image);
|
|---|
| 437 | QImage mask(msk);
|
|---|
| 438 |
|
|---|
| 439 | if (image.format() == QImage::Format_ARGB32_Premultiplied)
|
|---|
| 440 | img = image.convertToFormat(QImage::Format_ARGB32);
|
|---|
| 441 |
|
|---|
| 442 | if (!msk.isNull() && msk.format() == QImage::Format_ARGB32_Premultiplied)
|
|---|
| 443 | mask = msk.convertToFormat(QImage::Format_ARGB32);
|
|---|
| 444 |
|
|---|
| 445 | int width = img.width();
|
|---|
| 446 | int height = img.height();
|
|---|
| 447 | qreal scaleX = width/w;
|
|---|
| 448 | qreal scaleY = height/h;
|
|---|
| 449 |
|
|---|
| 450 | bool gray = (colorMode == QPrinter::GrayScale) || img.allGray();
|
|---|
| 451 | int splitSize = 21830 * (gray ? 3 : 1);
|
|---|
| 452 | if (width * height > splitSize) { // 65535/3, tolerance for broken printers
|
|---|
| 453 | int images, subheight;
|
|---|
| 454 | images = (width * height + splitSize - 1) / splitSize;
|
|---|
| 455 | subheight = (height + images-1) / images;
|
|---|
| 456 | while (subheight * width > splitSize) {
|
|---|
| 457 | images++;
|
|---|
| 458 | subheight = (height + images-1) / images;
|
|---|
| 459 | }
|
|---|
| 460 | int suby = 0;
|
|---|
| 461 | const QImage constImg(img);
|
|---|
| 462 | const QImage constMask(mask);
|
|---|
| 463 | while(suby < height) {
|
|---|
| 464 | qreal subImageHeight = qMin(subheight, height-suby);
|
|---|
| 465 | const QImage subImage(constImg.scanLine(suby), width, subImageHeight,
|
|---|
| 466 | constImg.bytesPerLine(), constImg.format());
|
|---|
| 467 | const QImage subMask = mask.isNull() ? mask : QImage(constMask.scanLine(suby), width, subImageHeight,
|
|---|
| 468 | constMask.bytesPerLine(), constMask.format());
|
|---|
| 469 | drawImageHelper(x, y + suby/scaleY, w, subImageHeight/scaleY,
|
|---|
| 470 | subImage, subMask, gray, scaleX, scaleY);
|
|---|
| 471 | suby += subheight;
|
|---|
| 472 | }
|
|---|
| 473 | } else {
|
|---|
| 474 | drawImageHelper(x, y, width, height, img, mask, gray, scaleX, scaleY);
|
|---|
| 475 | }
|
|---|
| 476 | }
|
|---|
| 477 |
|
|---|
| 478 | void QPSPrintEnginePrivate::emitHeader(bool finished)
|
|---|
| 479 | {
|
|---|
| 480 | QPSPrintEngine *q = static_cast<QPSPrintEngine *>(q_ptr);
|
|---|
| 481 | QPrinter *printer = static_cast<QPrinter*>(pdev);
|
|---|
| 482 |
|
|---|
| 483 | if (creator.isEmpty())
|
|---|
| 484 | creator = QLatin1String("Qt " QT_VERSION_STR);
|
|---|
| 485 |
|
|---|
| 486 | QByteArray header;
|
|---|
| 487 | QPdf::ByteStream s(&header);
|
|---|
| 488 | s << "%!PS-Adobe-1.0";
|
|---|
| 489 |
|
|---|
| 490 | qreal scale = 72. / ((qreal) q->metric(QPaintDevice::PdmDpiY));
|
|---|
| 491 | QRect pageRect = this->pageRect();
|
|---|
| 492 | QRect paperRect = this->paperRect();
|
|---|
| 493 | int mtop = pageRect.top() - paperRect.top();
|
|---|
| 494 | int mleft = pageRect.left() - paperRect.left();
|
|---|
| 495 | int mbottom = paperRect.bottom() - pageRect.bottom();
|
|---|
| 496 | int mright = paperRect.right() - pageRect.right();
|
|---|
| 497 | int width = pageRect.width();
|
|---|
| 498 | int height = pageRect.height();
|
|---|
| 499 | if (finished && pageCount == 1 && copies == 1 &&
|
|---|
| 500 | ((fullPage && qt_gen_epsf) || (outputFileName.endsWith(QLatin1String(".eps"))))
|
|---|
| 501 | ) {
|
|---|
| 502 | if (!boundingBox.isValid())
|
|---|
| 503 | boundingBox.setRect(0, 0, width, height);
|
|---|
| 504 | if (orientation == QPrinter::Landscape) {
|
|---|
| 505 | if (!fullPage)
|
|---|
| 506 | boundingBox.translate(-mleft, -mtop);
|
|---|
| 507 | s << " EPSF-3.0\n%%BoundingBox: "
|
|---|
| 508 | << (int)(printer->height() - boundingBox.bottom())*scale // llx
|
|---|
| 509 | << (int)(printer->width() - boundingBox.right())*scale - 1 // lly
|
|---|
| 510 | << (int)(printer->height() - boundingBox.top())*scale + 1 // urx
|
|---|
| 511 | << (int)(printer->width() - boundingBox.left())*scale; // ury
|
|---|
| 512 | } else {
|
|---|
| 513 | if (!fullPage)
|
|---|
| 514 | boundingBox.translate(mleft, -mtop);
|
|---|
| 515 | s << " EPSF-3.0\n%%BoundingBox: "
|
|---|
| 516 | << (int)(boundingBox.left())*scale
|
|---|
| 517 | << (int)(printer->height() - boundingBox.bottom())*scale - 1
|
|---|
| 518 | << (int)(boundingBox.right())*scale + 1
|
|---|
| 519 | << (int)(printer->height() - boundingBox.top())*scale;
|
|---|
| 520 | }
|
|---|
| 521 | } else {
|
|---|
| 522 | int w = width + (fullPage ? 0 : mleft + mright);
|
|---|
| 523 | int h = height + (fullPage ? 0 : mtop + mbottom);
|
|---|
| 524 | w = (int)(w*scale);
|
|---|
| 525 | h = (int)(h*scale);
|
|---|
| 526 | // set a bounding box according to the DSC
|
|---|
| 527 | if (orientation == QPrinter::Landscape)
|
|---|
| 528 | s << "\n%%BoundingBox: 0 0 " << h << w;
|
|---|
| 529 | else
|
|---|
| 530 | s << "\n%%BoundingBox: 0 0 " << w << h;
|
|---|
| 531 | }
|
|---|
| 532 | s << '\n' << wrapDSC("%%Creator: " + creator.toUtf8());
|
|---|
| 533 | if (!title.isEmpty())
|
|---|
| 534 | s << wrapDSC("%%Title: " + title.toUtf8());
|
|---|
| 535 | #ifndef QT_NO_DATESTRING
|
|---|
| 536 | s << "%%CreationDate: " << QDateTime::currentDateTime().toString().toUtf8();
|
|---|
| 537 | #endif
|
|---|
| 538 | s << "\n%%Orientation: ";
|
|---|
| 539 | if (orientation == QPrinter::Landscape)
|
|---|
| 540 | s << "Landscape";
|
|---|
| 541 | else
|
|---|
| 542 | s << "Portrait";
|
|---|
| 543 |
|
|---|
| 544 | s << "\n%%Pages: (atend)"
|
|---|
| 545 | "\n%%DocumentFonts: (atend)"
|
|---|
| 546 | "\n%%EndComments\n"
|
|---|
| 547 |
|
|---|
| 548 | "%%BeginProlog\n"
|
|---|
| 549 | "% Prolog copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).\n"
|
|---|
| 550 | "% You may copy this prolog in any way that is directly related to this document.\n"
|
|---|
| 551 | "% For other use of this prolog, see your licensing agreement for Qt.\n"
|
|---|
| 552 | << ps_header << '\n';
|
|---|
| 553 |
|
|---|
| 554 |
|
|---|
| 555 | s << "/pageinit {\n";
|
|---|
| 556 | if (!fullPage) {
|
|---|
| 557 | if (orientation == QPrinter::Portrait)
|
|---|
| 558 | s << mleft*scale << mbottom*scale << "translate\n";
|
|---|
| 559 | else
|
|---|
| 560 | s << mtop*scale << mleft*scale << "translate\n";
|
|---|
| 561 | }
|
|---|
| 562 | if (orientation == QPrinter::Portrait) {
|
|---|
| 563 | s << "% " << printer->widthMM() << '*' << printer->heightMM()
|
|---|
| 564 | << "mm (portrait)\n0 " << height*scale
|
|---|
| 565 | << "translate " << scale << '-' << scale << "scale } def\n";
|
|---|
| 566 | } else {
|
|---|
| 567 | s << "% " << printer->heightMM() << '*' << printer->widthMM()
|
|---|
| 568 | << " mm (landscape)\n 90 rotate " << scale << '-' << scale << "scale } def\n";
|
|---|
| 569 | }
|
|---|
| 570 | s << "%%EndProlog\n";
|
|---|
| 571 |
|
|---|
| 572 | outDevice->write(header);
|
|---|
| 573 | headerDone = true;
|
|---|
| 574 | }
|
|---|
| 575 |
|
|---|
| 576 |
|
|---|
| 577 | void QPSPrintEnginePrivate::emitPages()
|
|---|
| 578 | {
|
|---|
| 579 | if (!hugeDocument) {
|
|---|
| 580 | for (QHash<QFontEngine::FaceId, QFontSubset *>::const_iterator it = fonts.constBegin();
|
|---|
| 581 | it != fonts.constEnd(); ++it)
|
|---|
| 582 | outDevice->write((*it)->toType1());
|
|---|
| 583 | }
|
|---|
| 584 |
|
|---|
| 585 | QIODevice *content = buffer.stream();
|
|---|
| 586 | // Write the page contents in chunks.
|
|---|
| 587 | while (!content->atEnd()) {
|
|---|
| 588 | QByteArray buf = content->read(currentPage->chunkSize());
|
|---|
| 589 | if (!buf.isEmpty())
|
|---|
| 590 | outDevice->write(buf);
|
|---|
| 591 | }
|
|---|
| 592 | content = currentPage->stream();
|
|---|
| 593 | // Write the page contents in chunks.
|
|---|
| 594 | while (!content->atEnd()) {
|
|---|
| 595 | QByteArray buf = content->read(currentPage->chunkSize());
|
|---|
| 596 | if (!buf.isEmpty())
|
|---|
| 597 | outDevice->write(buf);
|
|---|
| 598 | }
|
|---|
| 599 | outDevice->write(trailer);
|
|---|
| 600 |
|
|---|
| 601 | buffer.clear();
|
|---|
| 602 | currentPage->clear();
|
|---|
| 603 | trailer = QByteArray();
|
|---|
| 604 | hugeDocument = true;
|
|---|
| 605 | }
|
|---|
| 606 |
|
|---|
| 607 |
|
|---|
| 608 | #ifdef Q_WS_QWS
|
|---|
| 609 | static const int max_in_memory_size = 2000000;
|
|---|
| 610 | #else
|
|---|
| 611 | static const int max_in_memory_size = 32000000;
|
|---|
| 612 | #endif
|
|---|
| 613 |
|
|---|
| 614 | void QPSPrintEnginePrivate::flushPage(bool last)
|
|---|
| 615 | {
|
|---|
| 616 | if (!last && currentPage->stream()->size() == 0)
|
|---|
| 617 | return;
|
|---|
| 618 |
|
|---|
| 619 | QPdf::ByteStream e(&trailer);
|
|---|
| 620 | buffer << "%%Page: "
|
|---|
| 621 | << pageCount << pageCount << "\n"
|
|---|
| 622 | "%%BeginPageSetup\n"
|
|---|
| 623 | "QI\n";
|
|---|
| 624 | if (hugeDocument) {
|
|---|
| 625 | for (QHash<QFontEngine::FaceId, QFontSubset *>::const_iterator it = fonts.constBegin();
|
|---|
| 626 | it != fonts.constEnd(); ++it) {
|
|---|
| 627 | if (currentPage->fonts.contains((*it)->object_id)) {
|
|---|
| 628 | if ((*it)->downloaded_glyphs == 0) {
|
|---|
| 629 | buffer << (*it)->toType1();
|
|---|
| 630 | (*it)->downloaded_glyphs = 0;
|
|---|
| 631 | } else {
|
|---|
| 632 | buffer << (*it)->type1AddedGlyphs();
|
|---|
| 633 | }
|
|---|
| 634 | }
|
|---|
| 635 | }
|
|---|
| 636 | }
|
|---|
| 637 | for (int i = 0; i < currentPage->fonts.size(); ++i)
|
|---|
| 638 | buffer << "(F" << QByteArray::number(currentPage->fonts.at(i)) << ") T1Setup\n";
|
|---|
| 639 |
|
|---|
| 640 | buffer << "%%EndPageSetup\nq\n";
|
|---|
| 641 | e << "\nQ QP\n";
|
|---|
| 642 | if (last || hugeDocument
|
|---|
| 643 | || buffer.stream()->size() + currentPage->stream()->size() > max_in_memory_size) {
|
|---|
| 644 | // qDebug("emiting header at page %d", pageCount);
|
|---|
| 645 | if (!headerDone)
|
|---|
| 646 | emitHeader(last);
|
|---|
| 647 | emitPages();
|
|---|
| 648 | } else {
|
|---|
| 649 | buffer << *currentPage << e;
|
|---|
| 650 | currentPage->clear();
|
|---|
| 651 | trailer.clear();
|
|---|
| 652 | }
|
|---|
| 653 | pageCount++;
|
|---|
| 654 | }
|
|---|
| 655 |
|
|---|
| 656 | // ================ PSPrinter class ========================
|
|---|
| 657 |
|
|---|
| 658 | QPSPrintEngine::QPSPrintEngine(QPrinter::PrinterMode m)
|
|---|
| 659 | : QPdfBaseEngine(*(new QPSPrintEnginePrivate(m)),
|
|---|
| 660 | PrimitiveTransform
|
|---|
| 661 | | PatternTransform
|
|---|
| 662 | | PixmapTransform
|
|---|
| 663 | | PainterPaths
|
|---|
| 664 | | PatternBrush
|
|---|
| 665 | )
|
|---|
| 666 | {
|
|---|
| 667 | }
|
|---|
| 668 |
|
|---|
| 669 | static void ignoreSigPipe(bool b)
|
|---|
| 670 | {
|
|---|
| 671 | #ifndef QT_NO_LPR
|
|---|
| 672 | static struct sigaction *users_sigpipe_handler = 0;
|
|---|
| 673 | static int lockCount = 0;
|
|---|
| 674 |
|
|---|
| 675 | #ifndef QT_NO_THREAD
|
|---|
| 676 | QMutexLocker locker(QMutexPool::globalInstanceGet(&users_sigpipe_handler));
|
|---|
| 677 | #endif
|
|---|
| 678 |
|
|---|
| 679 | if (b) {
|
|---|
| 680 | if (lockCount++ > 0)
|
|---|
| 681 | return;
|
|---|
| 682 |
|
|---|
| 683 | if (users_sigpipe_handler != 0)
|
|---|
| 684 | return; // already ignoring sigpipe
|
|---|
| 685 |
|
|---|
| 686 | users_sigpipe_handler = new struct sigaction;
|
|---|
| 687 | struct sigaction tmp_sigpipe_handler;
|
|---|
| 688 | tmp_sigpipe_handler.sa_handler = SIG_IGN;
|
|---|
| 689 | sigemptyset(&tmp_sigpipe_handler.sa_mask);
|
|---|
| 690 | tmp_sigpipe_handler.sa_flags = 0;
|
|---|
| 691 |
|
|---|
| 692 | if (sigaction(SIGPIPE, &tmp_sigpipe_handler, users_sigpipe_handler) == -1) {
|
|---|
| 693 | delete users_sigpipe_handler;
|
|---|
| 694 | users_sigpipe_handler = 0;
|
|---|
| 695 | }
|
|---|
| 696 | }
|
|---|
| 697 | else {
|
|---|
| 698 | if (--lockCount > 0)
|
|---|
| 699 | return;
|
|---|
| 700 |
|
|---|
| 701 | if (users_sigpipe_handler == 0)
|
|---|
| 702 | return; // not ignoring sigpipe
|
|---|
| 703 |
|
|---|
| 704 | if (sigaction(SIGPIPE, users_sigpipe_handler, 0) == -1)
|
|---|
| 705 | qWarning("QPSPrintEngine: Could not restore SIGPIPE handler");
|
|---|
| 706 |
|
|---|
| 707 | delete users_sigpipe_handler;
|
|---|
| 708 | users_sigpipe_handler = 0;
|
|---|
| 709 | }
|
|---|
| 710 | #else
|
|---|
| 711 | Q_UNUSED(b);
|
|---|
| 712 | #endif
|
|---|
| 713 | }
|
|---|
| 714 | QPSPrintEngine::~QPSPrintEngine()
|
|---|
| 715 | {
|
|---|
| 716 | Q_D(QPSPrintEngine);
|
|---|
| 717 | if (d->fd >= 0)
|
|---|
| 718 | #if defined(Q_OS_WIN) && defined(_MSC_VER) && _MSC_VER >= 1400
|
|---|
| 719 | ::_close(d->fd);
|
|---|
| 720 | #else
|
|---|
| 721 | ::close(d->fd);
|
|---|
| 722 | #endif
|
|---|
| 723 | }
|
|---|
| 724 |
|
|---|
| 725 | bool QPSPrintEngine::begin(QPaintDevice *pdev)
|
|---|
| 726 | {
|
|---|
| 727 | Q_D(QPSPrintEngine);
|
|---|
| 728 |
|
|---|
| 729 | if (d->fd >= 0)
|
|---|
| 730 | return true;
|
|---|
| 731 |
|
|---|
| 732 | if (d->useAlphaEngine) {
|
|---|
| 733 | QAlphaPaintEngine::begin(pdev);
|
|---|
| 734 | if (!continueCall())
|
|---|
| 735 | return true;
|
|---|
| 736 | }
|
|---|
| 737 |
|
|---|
| 738 | if(!QPdfBaseEngine::begin(pdev)) {
|
|---|
| 739 | d->printerState = QPrinter::Error;
|
|---|
| 740 | return false;
|
|---|
| 741 | }
|
|---|
| 742 |
|
|---|
| 743 | d->pageCount = 1; // initialize state
|
|---|
| 744 |
|
|---|
| 745 | d->pen = QPen(Qt::black);
|
|---|
| 746 | d->brush = Qt::NoBrush;
|
|---|
| 747 | d->hasPen = true;
|
|---|
| 748 | d->hasBrush = false;
|
|---|
| 749 | d->clipEnabled = false;
|
|---|
| 750 | d->allClipped = false;
|
|---|
| 751 | d->boundingBox = QRect();
|
|---|
| 752 | d->fontsUsed = "";
|
|---|
| 753 | d->hugeDocument = false;
|
|---|
| 754 | d->simplePen = false;
|
|---|
| 755 |
|
|---|
| 756 | setActive(true);
|
|---|
| 757 | d->printerState = QPrinter::Active;
|
|---|
| 758 |
|
|---|
| 759 | newPage();
|
|---|
| 760 |
|
|---|
| 761 | return true;
|
|---|
| 762 | }
|
|---|
| 763 |
|
|---|
| 764 | bool QPSPrintEngine::end()
|
|---|
| 765 | {
|
|---|
| 766 | Q_D(QPSPrintEngine);
|
|---|
| 767 |
|
|---|
| 768 | if (d->useAlphaEngine) {
|
|---|
| 769 | QAlphaPaintEngine::end();
|
|---|
| 770 | if (!continueCall())
|
|---|
| 771 | return true;
|
|---|
| 772 | }
|
|---|
| 773 |
|
|---|
| 774 | // we're writing to lp/lpr through a pipe, we don't want to crash with SIGPIPE
|
|---|
| 775 | // if lp/lpr dies
|
|---|
| 776 | ignoreSigPipe(true);
|
|---|
| 777 | d->flushPage(true);
|
|---|
| 778 | QByteArray trailer;
|
|---|
| 779 | QPdf::ByteStream s(&trailer);
|
|---|
| 780 | s << "%%Trailer\n"
|
|---|
| 781 | "%%Pages: " << d->pageCount - 1 << '\n' <<
|
|---|
| 782 | wrapDSC("%%DocumentFonts: " + d->fontsUsed);
|
|---|
| 783 | s << "%%EOF\n";
|
|---|
| 784 | d->outDevice->write(trailer);
|
|---|
| 785 |
|
|---|
| 786 | QPdfBaseEngine::end();
|
|---|
| 787 | ignoreSigPipe(false);
|
|---|
| 788 |
|
|---|
| 789 | d->firstPage = true;
|
|---|
| 790 | d->headerDone = false;
|
|---|
| 791 |
|
|---|
| 792 | setActive(false);
|
|---|
| 793 | d->printerState = QPrinter::Idle;
|
|---|
| 794 | d->pdev = 0;
|
|---|
| 795 |
|
|---|
| 796 | return true;
|
|---|
| 797 | }
|
|---|
| 798 |
|
|---|
| 799 | void QPSPrintEngine::setBrush()
|
|---|
| 800 | {
|
|---|
| 801 | Q_D(QPSPrintEngine);
|
|---|
| 802 | #if 0
|
|---|
| 803 | bool specifyColor;
|
|---|
| 804 | int gStateObject = 0;
|
|---|
| 805 | int patternObject = d->addBrushPattern(brush, d->stroker.matrix, brushOrigin, &specifyColor, &gStateObject);
|
|---|
| 806 |
|
|---|
| 807 | *d->currentPage << (patternObject ? "/PCSp cs " : "/CSp cs ");
|
|---|
| 808 | if (specifyColor) {
|
|---|
| 809 | QColor rgba = brush.color();
|
|---|
| 810 | *d->currentPage << rgba.redF()
|
|---|
| 811 | << rgba.greenF()
|
|---|
| 812 | << rgba.blueF();
|
|---|
| 813 | }
|
|---|
| 814 | if (patternObject)
|
|---|
| 815 | *d->currentPage << "/Pat" << patternObject;
|
|---|
| 816 | *d->currentPage << "scn\n";
|
|---|
| 817 | #endif
|
|---|
| 818 | QColor rgba = d->brush.color();
|
|---|
| 819 | if (d->colorMode == QPrinter::GrayScale) {
|
|---|
| 820 | qreal gray = qGray(rgba.rgba())/255.;
|
|---|
| 821 | *d->currentPage << gray << gray << gray;
|
|---|
| 822 | } else {
|
|---|
| 823 | *d->currentPage << rgba.redF()
|
|---|
| 824 | << rgba.greenF()
|
|---|
| 825 | << rgba.blueF();
|
|---|
| 826 | }
|
|---|
| 827 | *d->currentPage << "scn\n"
|
|---|
| 828 | << "/BSt " << d->brush.style() << "def\n";
|
|---|
| 829 | }
|
|---|
| 830 |
|
|---|
| 831 | void QPSPrintEngine::drawImageInternal(const QRectF &r, QImage image, bool bitmap)
|
|---|
| 832 | {
|
|---|
| 833 | Q_D(QPSPrintEngine);
|
|---|
| 834 | if (d->clipEnabled && d->allClipped)
|
|---|
| 835 | return;
|
|---|
| 836 | if (bitmap && image.depth() != 1)
|
|---|
| 837 | bitmap = false;
|
|---|
| 838 | QImage mask;
|
|---|
| 839 | // the below is not necessary since it's handled by the alpha
|
|---|
| 840 | // engine
|
|---|
| 841 | if (!d->useAlphaEngine && !bitmap) {
|
|---|
| 842 | if (image.format() == QImage::Format_Mono || image.format() == QImage::Format_MonoLSB)
|
|---|
| 843 | image = image.convertToFormat(QImage::Format_Indexed8);
|
|---|
| 844 | if (image.hasAlphaChannel()) {
|
|---|
| 845 | // get better alpha dithering
|
|---|
| 846 | int xscale = image.width();
|
|---|
| 847 | xscale *= xscale <= 800 ? 4 : (xscale <= 1600 ? 2 : 1);
|
|---|
| 848 | int yscale = image.height();
|
|---|
| 849 | yscale *= yscale <= 800 ? 4 : (yscale <= 1600 ? 2 : 1);
|
|---|
| 850 | image = image.scaled(xscale, yscale);
|
|---|
| 851 | mask = image.createAlphaMask(Qt::OrderedAlphaDither);
|
|---|
| 852 | }
|
|---|
| 853 | }
|
|---|
| 854 | *d->currentPage << "q\n";
|
|---|
| 855 | if(!d->simplePen)
|
|---|
| 856 | *d->currentPage << QPdf::generateMatrix(d->stroker.matrix);
|
|---|
| 857 | QBrush b = d->brush;
|
|---|
| 858 | if (image.depth() == 1) {
|
|---|
| 859 | // set current pen as brush
|
|---|
| 860 | d->brush = d->pen.brush();
|
|---|
| 861 | setBrush();
|
|---|
| 862 | }
|
|---|
| 863 | d->drawImage(r.x(), r.y(), r.width(), r.height(), image, mask);
|
|---|
| 864 | *d->currentPage << "Q\n";
|
|---|
| 865 | d->brush = b;
|
|---|
| 866 | }
|
|---|
| 867 |
|
|---|
| 868 |
|
|---|
| 869 | void QPSPrintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
|
|---|
| 870 | Qt::ImageConversionFlags)
|
|---|
| 871 | {
|
|---|
| 872 | Q_D(QPSPrintEngine);
|
|---|
| 873 |
|
|---|
| 874 | if (d->useAlphaEngine) {
|
|---|
| 875 | QAlphaPaintEngine::drawImage(r, img, sr);
|
|---|
| 876 | if (!continueCall())
|
|---|
| 877 | return;
|
|---|
| 878 | }
|
|---|
| 879 | QImage image = img.copy(sr.toRect());
|
|---|
| 880 | drawImageInternal(r, image, false);
|
|---|
| 881 | }
|
|---|
| 882 |
|
|---|
| 883 | void QPSPrintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
|
|---|
| 884 | {
|
|---|
| 885 | Q_D(QPSPrintEngine);
|
|---|
| 886 |
|
|---|
| 887 | if (d->useAlphaEngine) {
|
|---|
| 888 | QAlphaPaintEngine::drawPixmap(r, pm, sr);
|
|---|
| 889 | if (!continueCall())
|
|---|
| 890 | return;
|
|---|
| 891 | }
|
|---|
| 892 |
|
|---|
| 893 | QImage img = pm.copy(sr.toRect()).toImage();
|
|---|
| 894 | drawImageInternal(r, img, true);
|
|---|
| 895 | }
|
|---|
| 896 |
|
|---|
| 897 | void QPSPrintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &p)
|
|---|
| 898 | {
|
|---|
| 899 | Q_D(QPSPrintEngine);
|
|---|
| 900 |
|
|---|
| 901 | if (d->useAlphaEngine) {
|
|---|
| 902 | QAlphaPaintEngine::drawTiledPixmap(r, pixmap, p);
|
|---|
| 903 | if (!continueCall())
|
|---|
| 904 | return;
|
|---|
| 905 | }
|
|---|
| 906 |
|
|---|
| 907 | if (d->clipEnabled && d->allClipped)
|
|---|
| 908 | return;
|
|---|
| 909 | // ### Optimise implementation!
|
|---|
| 910 | qreal yPos = r.y();
|
|---|
| 911 | qreal yOff = p.y();
|
|---|
| 912 | while(yPos < r.y() + r.height()) {
|
|---|
| 913 | qreal drawH = pixmap.height() - yOff; // Cropping first row
|
|---|
| 914 | if (yPos + drawH > r.y() + r.height()) // Cropping last row
|
|---|
| 915 | drawH = r.y() + r.height() - yPos;
|
|---|
| 916 | qreal xPos = r.x();
|
|---|
| 917 | qreal xOff = p.x();
|
|---|
| 918 | while(xPos < r.x() + r.width()) {
|
|---|
| 919 | qreal drawW = pixmap.width() - xOff; // Cropping first column
|
|---|
| 920 | if (xPos + drawW > r.x() + r.width()) // Cropping last column
|
|---|
| 921 | drawW = r.x() + r.width() - xPos;
|
|---|
| 922 | // ########
|
|---|
| 923 | painter()->drawPixmap(QPointF(xPos, yPos).toPoint(), pixmap,
|
|---|
| 924 | QRectF(xOff, yOff, drawW, drawH).toRect());
|
|---|
| 925 | xPos += drawW;
|
|---|
| 926 | xOff = 0;
|
|---|
| 927 | }
|
|---|
| 928 | yPos += drawH;
|
|---|
| 929 | yOff = 0;
|
|---|
| 930 | }
|
|---|
| 931 |
|
|---|
| 932 | }
|
|---|
| 933 |
|
|---|
| 934 | bool QPSPrintEngine::newPage()
|
|---|
| 935 | {
|
|---|
| 936 | Q_D(QPSPrintEngine);
|
|---|
| 937 |
|
|---|
| 938 | if (!d->firstPage && d->useAlphaEngine)
|
|---|
| 939 | flushAndInit();
|
|---|
| 940 |
|
|---|
| 941 | // we're writing to lp/lpr through a pipe, we don't want to crash with SIGPIPE
|
|---|
| 942 | // if lp/lpr dies
|
|---|
| 943 | ignoreSigPipe(true);
|
|---|
| 944 | if (!d->firstPage)
|
|---|
| 945 | d->flushPage();
|
|---|
| 946 | d->firstPage = false;
|
|---|
| 947 | ignoreSigPipe(false);
|
|---|
| 948 |
|
|---|
| 949 | delete d->currentPage;
|
|---|
| 950 | d->currentPage = new QPdfPage;
|
|---|
| 951 | d->stroker.stream = d->currentPage;
|
|---|
| 952 |
|
|---|
| 953 | return QPdfBaseEngine::newPage();
|
|---|
| 954 | }
|
|---|
| 955 |
|
|---|
| 956 | bool QPSPrintEngine::abort()
|
|---|
| 957 | {
|
|---|
| 958 | // ### abort!?!
|
|---|
| 959 | return false;
|
|---|
| 960 | }
|
|---|
| 961 |
|
|---|
| 962 | QPrinter::PrinterState QPSPrintEngine::printerState() const
|
|---|
| 963 | {
|
|---|
| 964 | Q_D(const QPSPrintEngine);
|
|---|
| 965 | return d->printerState;
|
|---|
| 966 | }
|
|---|
| 967 |
|
|---|
| 968 | QT_END_NAMESPACE
|
|---|
| 969 |
|
|---|
| 970 | #endif // QT_NO_PRINTER
|
|---|