|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtGui module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
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 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include <private/qprintengine_qws_p.h> |
|
43 |
|
44 #ifndef QT_NO_PRINTER |
|
45 |
|
46 #include <private/qpaintengine_raster_p.h> |
|
47 #include <qimage.h> |
|
48 #include <qfile.h> |
|
49 #include <qdebug.h> |
|
50 #include <QCopChannel> |
|
51 |
|
52 QT_BEGIN_NAMESPACE |
|
53 |
|
54 #define MM(n) int((n * 720 + 127) / 254) |
|
55 #define IN(n) int(n * 72) |
|
56 |
|
57 extern QSizeF qt_paperSizeToQSizeF(QPrinter::PaperSize size); |
|
58 |
|
59 QtopiaPrintEngine::QtopiaPrintEngine(QPrinter::PrinterMode mode) |
|
60 : QPaintEngine(*(new QtopiaPrintEnginePrivate( mode ))) |
|
61 { |
|
62 d_func()->initialize(); |
|
63 } |
|
64 |
|
65 bool QtopiaPrintEngine::begin(QPaintDevice *) |
|
66 { |
|
67 Q_D(QtopiaPrintEngine); |
|
68 Q_ASSERT_X(d->printerState == QPrinter::Idle, "QtopiaPrintEngine", "printer already active"); |
|
69 |
|
70 // Create a new off-screen monochrome image to handle the drawing process. |
|
71 QSize size = paperRect().size(); |
|
72 if ( d->pageImage ) |
|
73 delete d->pageImage; |
|
74 d->pageImage = new QImage( size, QImage::Format_RGB32 ); |
|
75 if ( !(d->pageImage) ) |
|
76 return false; |
|
77 |
|
78 // Recreate the paint engine on the new image. |
|
79 delete d->_paintEngine; |
|
80 d->_paintEngine = 0; |
|
81 d->paintEngine()->state = state; |
|
82 |
|
83 // Begin the paint process on the image. |
|
84 if (!d->paintEngine()->begin(d->pageImage)) |
|
85 return false; |
|
86 |
|
87 // Clear the first page to all-white. |
|
88 clearPage(); |
|
89 |
|
90 // Clear the print buffer and output the image header. |
|
91 d->buffer.clear(); |
|
92 d->writeG3FaxHeader(); |
|
93 |
|
94 // The print engine is currently active. |
|
95 d->printerState = QPrinter::Active; |
|
96 return true; |
|
97 } |
|
98 |
|
99 bool QtopiaPrintEngine::end() |
|
100 { |
|
101 Q_D(QtopiaPrintEngine); |
|
102 |
|
103 d->paintEngine()->end(); |
|
104 |
|
105 // Flush the last page. |
|
106 flushPage(); |
|
107 |
|
108 // Output the fax data to a file (TODO: send to the print queuing daemon). |
|
109 QString filename; |
|
110 if ( !d->outputFileName.isEmpty() ) |
|
111 filename = QString::fromLocal8Bit(qgetenv("HOME").constData()) + QLatin1String("/Documents/") + d->outputFileName; |
|
112 else |
|
113 filename = QString::fromLocal8Bit(qgetenv("HOME").constData()) + QLatin1String("/tmp/qwsfax.tiff"); |
|
114 |
|
115 setProperty(QPrintEngine::PPK_OutputFileName, filename); |
|
116 QFile file( filename ); |
|
117 if ( !file.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) { |
|
118 qDebug( "Failed to open %s for printer output", |
|
119 filename.toLatin1().constData() ); |
|
120 } else { |
|
121 file.write( d->buffer.data() ); |
|
122 file.close(); |
|
123 } |
|
124 |
|
125 // Free up the memory for the image buffer. |
|
126 d->buffer.clear(); |
|
127 |
|
128 // Finalize the print job. |
|
129 d->printerState = QPrinter::Idle; |
|
130 |
|
131 // call qcop service |
|
132 QMap<QString, QVariant> map; |
|
133 for ( int x = 0; x <= QPrintEngine::PPK_Duplex; x++ ) |
|
134 map.insert( QString::number(x), property((QPrintEngine::PrintEnginePropertyKey)(x))); |
|
135 QVariant variant(map); |
|
136 |
|
137 QByteArray data; |
|
138 QDataStream out(&data, QIODevice::WriteOnly); |
|
139 out << variant; |
|
140 QCopChannel::send(QLatin1String("QPE/Service/Print"), QLatin1String("print(QVariant)"), data); |
|
141 |
|
142 return true; |
|
143 } |
|
144 |
|
145 QPaintEngine *QtopiaPrintEngine::paintEngine() const |
|
146 { |
|
147 return const_cast<QtopiaPrintEnginePrivate *>(d_func())->paintEngine(); |
|
148 } |
|
149 |
|
150 void QtopiaPrintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) |
|
151 { |
|
152 Q_D(QtopiaPrintEngine); |
|
153 Q_ASSERT(d->printerState == QPrinter::Active); |
|
154 d->paintEngine()->drawPixmap(r, pm, sr); |
|
155 } |
|
156 |
|
157 void QtopiaPrintEngine::drawTextItem(const QPointF &p, const QTextItem &ti) |
|
158 { |
|
159 Q_D(QtopiaPrintEngine); |
|
160 Q_ASSERT(d->printerState == QPrinter::Active); |
|
161 d->paintEngine()->drawTextItem(p, ti); |
|
162 } |
|
163 |
|
164 void QtopiaPrintEngine::updateState(const QPaintEngineState &state) |
|
165 { |
|
166 Q_D(QtopiaPrintEngine); |
|
167 d->paintEngine()->updateState(state); |
|
168 } |
|
169 |
|
170 QRect QtopiaPrintEngine::paperRect() const |
|
171 { |
|
172 QSizeF s = qt_paperSizeToQSizeF(d_func()->paperSize); |
|
173 s.rwidth() = MM(s.width()); |
|
174 s.rheight() = MM(s.height()); |
|
175 int w = qRound(s.width()*d_func()->resolution/72.); |
|
176 int h = qRound(s.height()*d_func()->resolution/72.); |
|
177 if (d_func()->orientation == QPrinter::Portrait) |
|
178 return QRect(0, 0, w, h); |
|
179 else |
|
180 return QRect(0, 0, h, w); |
|
181 } |
|
182 |
|
183 QRect QtopiaPrintEngine::pageRect() const |
|
184 { |
|
185 QRect r = paperRect(); |
|
186 if (d_func()->fullPage) |
|
187 return r; |
|
188 // would be nice to get better margins than this. |
|
189 return QRect(d_func()->resolution/3, d_func()->resolution/3, r.width()-2*d_func()->resolution/3, r.height()-2*d_func()->resolution/3); |
|
190 } |
|
191 |
|
192 bool QtopiaPrintEngine::newPage() |
|
193 { |
|
194 flushPage(); |
|
195 clearPage(); |
|
196 ++(d_func()->pageNumber); |
|
197 return true; |
|
198 } |
|
199 |
|
200 bool QtopiaPrintEngine::abort() |
|
201 { |
|
202 return false; |
|
203 } |
|
204 |
|
205 QPrinter::PrinterState QtopiaPrintEngine::printerState() const |
|
206 { |
|
207 return d_func()->printerState; |
|
208 } |
|
209 |
|
210 int QtopiaPrintEngine::metric(QPaintDevice::PaintDeviceMetric metricType) const |
|
211 { |
|
212 int val; |
|
213 QRect r = d_func()->fullPage ? paperRect() : pageRect(); |
|
214 switch (metricType) { |
|
215 case QPaintDevice::PdmWidth: |
|
216 val = r.width(); |
|
217 break; |
|
218 case QPaintDevice::PdmHeight: |
|
219 val = r.height(); |
|
220 break; |
|
221 case QPaintDevice::PdmDpiX: |
|
222 val = d_func()->resolution; |
|
223 break; |
|
224 case QPaintDevice::PdmDpiY: |
|
225 val = d_func()->resolution; |
|
226 break; |
|
227 case QPaintDevice::PdmPhysicalDpiX: |
|
228 case QPaintDevice::PdmPhysicalDpiY: |
|
229 val = QT_QWS_PRINTER_DEFAULT_DPI; |
|
230 break; |
|
231 case QPaintDevice::PdmWidthMM: |
|
232 val = qRound(r.width()*25.4/d_func()->resolution); |
|
233 break; |
|
234 case QPaintDevice::PdmHeightMM: |
|
235 val = qRound(r.height()*25.4/d_func()->resolution); |
|
236 break; |
|
237 case QPaintDevice::PdmNumColors: |
|
238 val = 2; |
|
239 break; |
|
240 case QPaintDevice::PdmDepth: |
|
241 val = 1; |
|
242 break; |
|
243 default: |
|
244 qWarning("QtopiaPrintEngine::metric: Invalid metric command"); |
|
245 return 0; |
|
246 } |
|
247 return val; |
|
248 } |
|
249 |
|
250 QVariant QtopiaPrintEngine::property(PrintEnginePropertyKey key) const |
|
251 { |
|
252 Q_D(const QtopiaPrintEngine); |
|
253 QVariant ret; |
|
254 |
|
255 switch (key) { |
|
256 case PPK_CollateCopies: |
|
257 ret = d->collateCopies; |
|
258 break; |
|
259 case PPK_ColorMode: |
|
260 ret = d->colorMode; |
|
261 break; |
|
262 case PPK_Creator: |
|
263 ret = d->creator; |
|
264 break; |
|
265 case PPK_DocumentName: |
|
266 ret = d->docName; |
|
267 break; |
|
268 case PPK_FullPage: |
|
269 ret = d->fullPage; |
|
270 break; |
|
271 case PPK_NumberOfCopies: |
|
272 ret = d->numCopies; |
|
273 break; |
|
274 case PPK_Orientation: |
|
275 ret = d->orientation; |
|
276 break; |
|
277 case PPK_OutputFileName: |
|
278 ret = d->outputFileName; |
|
279 break; |
|
280 case PPK_PageOrder: |
|
281 ret = d->pageOrder; |
|
282 break; |
|
283 case PPK_PageRect: |
|
284 ret = pageRect(); |
|
285 break; |
|
286 case PPK_PaperSize: |
|
287 ret = d->paperSize; |
|
288 break; |
|
289 case PPK_PaperRect: |
|
290 ret = paperRect(); |
|
291 break; |
|
292 case PPK_PaperSource: |
|
293 ret = d->paperSource; |
|
294 break; |
|
295 case PPK_PrinterName: |
|
296 ret = d->printerName; |
|
297 break; |
|
298 case PPK_PrinterProgram: |
|
299 ret = d->printProgram; |
|
300 break; |
|
301 case PPK_Resolution: |
|
302 ret = d->resolution; |
|
303 break; |
|
304 case PPK_SupportedResolutions: |
|
305 ret = QList<QVariant>() << QT_QWS_PRINTER_DEFAULT_DPI; |
|
306 break; |
|
307 default: |
|
308 break; |
|
309 } |
|
310 return ret; |
|
311 } |
|
312 |
|
313 void QtopiaPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value) |
|
314 { |
|
315 Q_D(QtopiaPrintEngine); |
|
316 switch (key) { |
|
317 case PPK_CollateCopies: |
|
318 d->collateCopies = value.toBool(); |
|
319 break; |
|
320 case PPK_ColorMode: |
|
321 d->colorMode = QPrinter::ColorMode(value.toInt()); |
|
322 break; |
|
323 case PPK_Creator: |
|
324 d->creator = value.toString(); |
|
325 break; |
|
326 case PPK_DocumentName: |
|
327 d->docName = value.toString(); |
|
328 break; |
|
329 case PPK_FullPage: |
|
330 d->fullPage = value.toBool(); |
|
331 break; |
|
332 case PPK_NumberOfCopies: |
|
333 d->numCopies = value.toInt(); |
|
334 break; |
|
335 case PPK_Orientation: |
|
336 d->orientation = QPrinter::Orientation(value.toInt()); |
|
337 break; |
|
338 case PPK_OutputFileName: |
|
339 d->outputFileName = value.toString(); |
|
340 break; |
|
341 case PPK_PageOrder: |
|
342 d->pageOrder = QPrinter::PageOrder(value.toInt()); |
|
343 break; |
|
344 case PPK_PaperSize: |
|
345 d->paperSize = QPrinter::PaperSize(value.toInt()); |
|
346 break; |
|
347 case PPK_PaperSource: |
|
348 d->paperSource = QPrinter::PaperSource(value.toInt()); |
|
349 case PPK_PrinterName: |
|
350 d->printerName = value.toString(); |
|
351 break; |
|
352 case PPK_PrinterProgram: |
|
353 d->printProgram = value.toString(); |
|
354 break; |
|
355 case PPK_Resolution: |
|
356 d->resolution = value.toInt(); |
|
357 break; |
|
358 default: |
|
359 break; |
|
360 } |
|
361 } |
|
362 |
|
363 void QtopiaPrintEngine::clearPage() |
|
364 { |
|
365 d_func()->pageImage->fill(QColor(255, 255, 255).rgb()); |
|
366 } |
|
367 |
|
368 void QtopiaPrintEngine::flushPage() |
|
369 { |
|
370 d_func()->writeG3FaxPage(); |
|
371 } |
|
372 |
|
373 QtopiaPrintEnginePrivate::~QtopiaPrintEnginePrivate() |
|
374 { |
|
375 if ( pageImage ) |
|
376 delete pageImage; |
|
377 } |
|
378 |
|
379 void QtopiaPrintEnginePrivate::initialize() |
|
380 { |
|
381 _paintEngine = 0; |
|
382 } |
|
383 |
|
384 QPaintEngine *QtopiaPrintEnginePrivate::paintEngine() |
|
385 { |
|
386 if (!_paintEngine) |
|
387 _paintEngine = new QRasterPaintEngine(pageImage); |
|
388 return _paintEngine; |
|
389 } |
|
390 |
|
391 void QtopiaPrintEnginePrivate::writeG3FaxHeader() |
|
392 { |
|
393 // Write the TIFF file magic number (little-endian TIFF). |
|
394 buffer.append( (char)'I' ); |
|
395 buffer.append( (char)'I' ); |
|
396 buffer.append( (char)42 ); |
|
397 buffer.append( (char)0 ); |
|
398 |
|
399 // Leave a place-holder for the IFD offset of the first page. |
|
400 ifdPatch = buffer.size(); |
|
401 buffer.append( (int)0 ); |
|
402 } |
|
403 |
|
404 // Tag values, from RFC 2301. |
|
405 #define TIFF_IFD_NEW_SUB_FILE_TYPE 254 |
|
406 #define TIFF_IFD_IMAGE_WIDTH 256 |
|
407 #define TIFF_IFD_IMAGE_LENGTH 257 |
|
408 #define TIFF_IFD_BITS_PER_SAMPLE 258 |
|
409 #define TIFF_IFD_COMPRESSION 259 |
|
410 #define TIFF_IFD_PHOTOMETRIC_INTERP 262 |
|
411 #define TIFF_IFD_FILL_ORDER 266 |
|
412 #define TIFF_IFD_STRIP_OFFSETS 273 |
|
413 #define TIFF_IFD_ORIENTATION 274 |
|
414 #define TIFF_IFD_SAMPLES_PER_PIXEL 277 |
|
415 #define TIFF_IFD_ROWS_PER_STRIP 278 |
|
416 #define TIFF_IFD_STRIP_BYTE_COUNTS 279 |
|
417 #define TIFF_IFD_X_RESOLUTION 282 |
|
418 #define TIFF_IFD_Y_RESOLUTION 283 |
|
419 #define TIFF_IFD_PLANAR_CONFIG 284 |
|
420 #define TIFF_IFD_T4_OPTIONS 292 |
|
421 #define TIFF_IFD_RESOLUTION_UNIT 296 |
|
422 #define TIFF_IFD_PAGE_NUMBER 297 |
|
423 #define TIFF_IFD_CLEAN_FAX_DATA 327 |
|
424 |
|
425 // IFD type values. |
|
426 #define TIFF_TYPE_SHORT 3 |
|
427 #define TIFF_TYPE_LONG 4 |
|
428 #define TIFF_TYPE_RATIONAL 5 |
|
429 |
|
430 // Construct a SHORT pair from two values. |
|
431 #define TIFF_SHORT_PAIR(a,b) (((a) & 0xFFFF) | ((b) << 16)) |
|
432 |
|
433 // Width of a FAX page in pixels, in the baseline specification from RFC 2301. |
|
434 // This must be hard-wired, as per the RFC. We truncate any pixels that |
|
435 // are beyond this limit, or pad lines to reach this limit. |
|
436 #define TIFF_FAX_WIDTH 1728 |
|
437 |
|
438 void QtopiaPrintEnginePrivate::writeG3FaxPage() |
|
439 { |
|
440 // Pad the image file to a word boundary, just in case. |
|
441 buffer.pad(); |
|
442 |
|
443 // Back-patch the IFD link for the previous page. |
|
444 buffer.patch( ifdPatch, buffer.size() ); |
|
445 |
|
446 // Output the contents of the IFD for this page (these must be |
|
447 // in ascending order of tag value). |
|
448 buffer.append( (short)19 ); // Number of IFD entries. |
|
449 writeG3IFDEntry( TIFF_IFD_NEW_SUB_FILE_TYPE, TIFF_TYPE_LONG, 1, 2 ); |
|
450 writeG3IFDEntry( TIFF_IFD_IMAGE_WIDTH, TIFF_TYPE_LONG, 1, TIFF_FAX_WIDTH ); |
|
451 writeG3IFDEntry |
|
452 ( TIFF_IFD_IMAGE_LENGTH, TIFF_TYPE_LONG, 1, pageImage->height() ); |
|
453 writeG3IFDEntry( TIFF_IFD_BITS_PER_SAMPLE, TIFF_TYPE_SHORT, 1, 1 ); |
|
454 writeG3IFDEntry( TIFF_IFD_COMPRESSION, TIFF_TYPE_SHORT, 1, 3 ); |
|
455 writeG3IFDEntry( TIFF_IFD_PHOTOMETRIC_INTERP, TIFF_TYPE_SHORT, 1, 0 ); |
|
456 writeG3IFDEntry( TIFF_IFD_FILL_ORDER, TIFF_TYPE_SHORT, 1, 1 ); |
|
457 int stripOffsets = |
|
458 writeG3IFDEntry( TIFF_IFD_STRIP_OFFSETS, TIFF_TYPE_LONG, 1, 0 ); |
|
459 writeG3IFDEntry( TIFF_IFD_ORIENTATION, TIFF_TYPE_SHORT, 1, 1 ); |
|
460 writeG3IFDEntry( TIFF_IFD_SAMPLES_PER_PIXEL, TIFF_TYPE_SHORT, 1, 1 ); |
|
461 writeG3IFDEntry |
|
462 ( TIFF_IFD_ROWS_PER_STRIP, TIFF_TYPE_LONG, 1, pageImage->height() ); |
|
463 int stripBytes = writeG3IFDEntry |
|
464 ( TIFF_IFD_STRIP_BYTE_COUNTS, TIFF_TYPE_LONG, 1, 0 ); |
|
465 int xres = |
|
466 writeG3IFDEntry( TIFF_IFD_X_RESOLUTION, TIFF_TYPE_RATIONAL, 1, 0 ); |
|
467 int yres = |
|
468 writeG3IFDEntry( TIFF_IFD_Y_RESOLUTION, TIFF_TYPE_RATIONAL, 1, 0 ); |
|
469 writeG3IFDEntry( TIFF_IFD_PLANAR_CONFIG, TIFF_TYPE_SHORT, 1, 1 ); |
|
470 writeG3IFDEntry( TIFF_IFD_T4_OPTIONS, TIFF_TYPE_LONG, 1, 2 ); |
|
471 writeG3IFDEntry( TIFF_IFD_RESOLUTION_UNIT, TIFF_TYPE_SHORT, 1, 2 ); |
|
472 writeG3IFDEntry( TIFF_IFD_PAGE_NUMBER, TIFF_TYPE_SHORT, 2, |
|
473 TIFF_SHORT_PAIR( pageNumber, 0 ) ); |
|
474 writeG3IFDEntry( TIFF_IFD_CLEAN_FAX_DATA, TIFF_TYPE_SHORT, 1, 0 ); |
|
475 |
|
476 // Leave a place-holder for the IFD offset of the next page. |
|
477 ifdPatch = buffer.size(); |
|
478 buffer.append( (int)0 ); |
|
479 |
|
480 // Output the X and Y resolutions, as rational values (usually 200/1). |
|
481 buffer.patch( xres, buffer.size() ); |
|
482 buffer.append( (int)resolution ); |
|
483 buffer.append( (int)1 ); |
|
484 buffer.patch( yres, buffer.size() ); |
|
485 buffer.append( (int)resolution ); |
|
486 buffer.append( (int)1 ); |
|
487 |
|
488 // We are now at the start of the image data - set the strip offset. |
|
489 int start = buffer.size(); |
|
490 buffer.patch( stripOffsets, start ); |
|
491 |
|
492 // Output the image data. |
|
493 int width = pageImage->width(); |
|
494 QImage::Format imageFormat = pageImage->format(); |
|
495 for ( int y = 0; y < pageImage->height(); ++y ) { |
|
496 unsigned char *scan = pageImage->scanLine(y); |
|
497 int prev, pixel, len; |
|
498 writeG3EOL(); |
|
499 prev = 0; |
|
500 len = 0; |
|
501 |
|
502 uint currentColor = qRgb(255, 255, 255); // start with white |
|
503 |
|
504 for ( int x = 0; x < width && x < TIFF_FAX_WIDTH; ++x ) { |
|
505 if ( imageFormat == QImage::Format_RGB32 ) { |
|
506 // read color of the current pixel |
|
507 uint *p = (uint *)scan + x; |
|
508 |
|
509 if ( *p == currentColor ) { // if it is the same color |
|
510 len++; // imcrement length |
|
511 } else { // otherwise write color into the buffer |
|
512 if ( len > 0 ) { |
|
513 if ( currentColor == qRgb(0, 0, 0) ) |
|
514 writeG3BlackRun( len ); |
|
515 else |
|
516 writeG3WhiteRun( len ); |
|
517 } |
|
518 // initialise length and color; |
|
519 len = 1; |
|
520 currentColor = *p; |
|
521 } |
|
522 } else if ( imageFormat == QImage::Format_Mono ) { |
|
523 pixel = ((scan[x >> 3] & (1 << (x & 7))) != 0); |
|
524 if ( pixel != prev ) { |
|
525 if ( prev ) { |
|
526 writeG3BlackRun( len ); |
|
527 } else { |
|
528 writeG3WhiteRun( len ); |
|
529 } |
|
530 prev = pixel; |
|
531 len = 1; |
|
532 } else { |
|
533 ++len; |
|
534 } |
|
535 } |
|
536 } |
|
537 |
|
538 if ( imageFormat == QImage::Format_RGB32 ) { |
|
539 // Output the last run on the line, and pad to TIFF_FAX_WIDTH. |
|
540 if ( len != 0 ) { |
|
541 if ( currentColor == qRgb(0, 0, 0) ) |
|
542 writeG3BlackRun( len ); |
|
543 else |
|
544 writeG3WhiteRun( len ); |
|
545 } |
|
546 if ( width < TIFF_FAX_WIDTH ) |
|
547 writeG3WhiteRun( TIFF_FAX_WIDTH - width ); |
|
548 } else if ( imageFormat == QImage::Format_Mono ) { |
|
549 if ( len != 0 ) { |
|
550 if ( prev ) { |
|
551 writeG3BlackRun( len ); |
|
552 if ( width < TIFF_FAX_WIDTH ) { |
|
553 writeG3WhiteRun( TIFF_FAX_WIDTH - width ); |
|
554 } |
|
555 } else { |
|
556 if ( width < TIFF_FAX_WIDTH ) { |
|
557 writeG3WhiteRun( len + ( TIFF_FAX_WIDTH - width ) ); |
|
558 } else { |
|
559 writeG3WhiteRun( len ); |
|
560 } |
|
561 } |
|
562 } |
|
563 } |
|
564 } |
|
565 |
|
566 // Flush the last partial byte, which is padded with zero fill bits. |
|
567 if ( partialBits > 0 ) { |
|
568 buffer.append( (char)( partialByte << ( 8 - partialBits ) ) ); |
|
569 partialByte = 0; |
|
570 partialBits = 0; |
|
571 } |
|
572 |
|
573 // end of page add six EOLs |
|
574 for ( int i = 0; i < 6; i++ ) |
|
575 writeG3EOL(); |
|
576 |
|
577 // Update the byte count for the image data strip. |
|
578 buffer.patch( stripBytes, buffer.size() - start ); |
|
579 } |
|
580 |
|
581 int QtopiaPrintEnginePrivate::writeG3IFDEntry |
|
582 ( int tag, int type, int count, int value ) |
|
583 { |
|
584 buffer.append( (short)tag ); |
|
585 buffer.append( (short)type ); |
|
586 buffer.append( count ); |
|
587 buffer.append( value ); |
|
588 return buffer.size() - 4; // Offset of the value for back-patching. |
|
589 } |
|
590 |
|
591 void QtopiaPrintEnginePrivate::writeG3Code( int code, int bits ) |
|
592 { |
|
593 partialByte = ( ( partialByte << bits ) | code ); |
|
594 partialBits += bits; |
|
595 while ( partialBits >= 8 ) { |
|
596 partialBits -= 8; |
|
597 buffer.append( (char)( partialByte >> partialBits ) ); |
|
598 } |
|
599 } |
|
600 |
|
601 void QtopiaPrintEnginePrivate::writeG3WhiteRun( int len ) |
|
602 { |
|
603 static struct { |
|
604 unsigned short code; |
|
605 unsigned short bits; |
|
606 } whiteCodes[64 + 27] = { |
|
607 {0x0035, 8}, // 0 |
|
608 {0x0007, 6}, |
|
609 {0x0007, 4}, |
|
610 {0x0008, 4}, |
|
611 {0x000B, 4}, |
|
612 {0x000C, 4}, |
|
613 {0x000E, 4}, |
|
614 {0x000F, 4}, |
|
615 {0x0013, 5}, // 8 |
|
616 {0x0014, 5}, |
|
617 {0x0007, 5}, |
|
618 {0x0008, 5}, |
|
619 {0x0008, 6}, |
|
620 {0x0003, 6}, |
|
621 {0x0034, 6}, |
|
622 {0x0035, 6}, |
|
623 {0x002A, 6}, // 16 |
|
624 {0x002B, 6}, |
|
625 {0x0027, 7}, |
|
626 {0x000C, 7}, |
|
627 {0x0008, 7}, |
|
628 {0x0017, 7}, |
|
629 {0x0003, 7}, |
|
630 {0x0004, 7}, |
|
631 {0x0028, 7}, // 24 |
|
632 {0x002B, 7}, |
|
633 {0x0013, 7}, |
|
634 {0x0024, 7}, |
|
635 {0x0018, 7}, |
|
636 {0x0002, 8}, |
|
637 {0x0003, 8}, |
|
638 {0x001A, 8}, |
|
639 {0x001B, 8}, // 32 |
|
640 {0x0012, 8}, |
|
641 {0x0013, 8}, |
|
642 {0x0014, 8}, |
|
643 {0x0015, 8}, |
|
644 {0x0016, 8}, |
|
645 {0x0017, 8}, |
|
646 {0x0028, 8}, |
|
647 {0x0029, 8}, // 40 |
|
648 {0x002A, 8}, |
|
649 {0x002B, 8}, |
|
650 {0x002C, 8}, |
|
651 {0x002D, 8}, |
|
652 {0x0004, 8}, |
|
653 {0x0005, 8}, |
|
654 {0x000A, 8}, |
|
655 {0x000B, 8}, // 48 |
|
656 {0x0052, 8}, |
|
657 {0x0053, 8}, |
|
658 {0x0054, 8}, |
|
659 {0x0055, 8}, |
|
660 {0x0024, 8}, |
|
661 {0x0025, 8}, |
|
662 {0x0058, 8}, |
|
663 {0x0059, 8}, // 56 |
|
664 {0x005A, 8}, |
|
665 {0x005B, 8}, |
|
666 {0x004A, 8}, |
|
667 {0x004B, 8}, |
|
668 {0x0032, 8}, |
|
669 {0x0033, 8}, |
|
670 {0x0034, 8}, |
|
671 {0x001B, 5}, // Make up codes: 64 |
|
672 {0x0012, 5}, // 128 |
|
673 {0x0017, 6}, // 192 |
|
674 {0x0037, 7}, // 256 |
|
675 {0x0036, 8}, // 320 |
|
676 {0x0037, 8}, // 384 |
|
677 {0x0064, 8}, // 448 |
|
678 {0x0065, 8}, // 512 |
|
679 {0x0068, 8}, // 576 |
|
680 {0x0067, 8}, // 640 |
|
681 {0x00CC, 9}, // 704 |
|
682 {0x00CD, 9}, // 768 |
|
683 {0x00D2, 9}, // 832 |
|
684 {0x00D3, 9}, // 896 |
|
685 {0x00D4, 9}, // 960 |
|
686 {0x00D5, 9}, // 1024 |
|
687 {0x00D6, 9}, // 1088 |
|
688 {0x00D7, 9}, // 1152 |
|
689 {0x00D8, 9}, // 1216 |
|
690 {0x00D9, 9}, // 1280 |
|
691 {0x00DA, 9}, // 1344 |
|
692 {0x00DB, 9}, // 1408 |
|
693 {0x0098, 9}, // 1472 |
|
694 {0x0099, 9}, // 1536 |
|
695 {0x009A, 9}, // 1600 |
|
696 {0x0018, 6}, // 1664 |
|
697 {0x009B, 9}, // 1728 |
|
698 }; |
|
699 if ( len >= 64 ) { |
|
700 int index = 63 + (len >> 6); |
|
701 writeG3Code( whiteCodes[index].code, whiteCodes[index].bits ); |
|
702 len &= 63; |
|
703 } |
|
704 writeG3Code( whiteCodes[len].code, whiteCodes[len].bits ); |
|
705 } |
|
706 |
|
707 void QtopiaPrintEnginePrivate::writeG3BlackRun( int len ) |
|
708 { |
|
709 static struct { |
|
710 unsigned short code; |
|
711 unsigned short bits; |
|
712 } blackCodes[64 + 27] = { |
|
713 {0x0037, 10}, // 0 |
|
714 {0x0002, 3}, |
|
715 {0x0003, 2}, |
|
716 {0x0002, 2}, |
|
717 {0x0003, 3}, |
|
718 {0x0003, 4}, |
|
719 {0x0002, 4}, |
|
720 {0x0003, 5}, |
|
721 {0x0005, 6}, // 8 |
|
722 {0x0004, 6}, |
|
723 {0x0004, 7}, |
|
724 {0x0005, 7}, |
|
725 {0x0007, 7}, |
|
726 {0x0004, 8}, |
|
727 {0x0007, 8}, |
|
728 {0x0018, 9}, |
|
729 {0x0017, 10}, // 16 |
|
730 {0x0018, 10}, |
|
731 {0x0008, 10}, |
|
732 {0x0067, 11}, |
|
733 {0x0068, 11}, |
|
734 {0x006C, 11}, |
|
735 {0x0037, 11}, |
|
736 {0x0028, 11}, |
|
737 {0x0017, 11}, // 24 |
|
738 {0x0018, 11}, |
|
739 {0x00CA, 12}, |
|
740 {0x00CB, 12}, |
|
741 {0x00CC, 12}, |
|
742 {0x00CD, 12}, |
|
743 {0x0068, 12}, |
|
744 {0x0069, 12}, |
|
745 {0x006A, 12}, // 32 |
|
746 {0x006B, 12}, |
|
747 {0x00D2, 12}, |
|
748 {0x00D3, 12}, |
|
749 {0x00D4, 12}, |
|
750 {0x00D5, 12}, |
|
751 {0x00D6, 12}, |
|
752 {0x00D7, 12}, |
|
753 {0x006C, 12}, // 40 |
|
754 {0x006D, 12}, |
|
755 {0x00DA, 12}, |
|
756 {0x00DB, 12}, |
|
757 {0x0054, 12}, |
|
758 {0x0055, 12}, |
|
759 {0x0056, 12}, |
|
760 {0x0057, 12}, |
|
761 {0x0064, 12}, // 48 |
|
762 {0x0065, 12}, |
|
763 {0x0052, 12}, |
|
764 {0x0053, 12}, |
|
765 {0x0024, 12}, |
|
766 {0x0037, 12}, |
|
767 {0x0038, 12}, |
|
768 {0x0027, 12}, |
|
769 {0x0028, 12}, // 56 |
|
770 {0x0058, 12}, |
|
771 {0x0059, 12}, |
|
772 {0x002B, 12}, |
|
773 {0x002C, 12}, |
|
774 {0x005A, 12}, |
|
775 {0x0066, 12}, |
|
776 {0x0067, 12}, |
|
777 {0x000F, 10}, // Make up codes: 64 |
|
778 {0x00C8, 12}, // 128 |
|
779 {0x00C9, 12}, // 192 |
|
780 {0x005B, 12}, // 256 |
|
781 {0x0033, 12}, // 320 |
|
782 {0x0034, 12}, // 384 |
|
783 {0x0035, 12}, // 448 |
|
784 {0x006C, 13}, // 512 |
|
785 {0x006D, 13}, // 576 |
|
786 {0x004A, 13}, // 640 |
|
787 {0x004B, 13}, // 704 |
|
788 {0x004C, 13}, // 768 |
|
789 {0x004D, 13}, // 832 |
|
790 {0x0072, 13}, // 896 |
|
791 {0x0073, 13}, // 960 |
|
792 {0x0074, 13}, // 1024 |
|
793 {0x0075, 13}, // 1088 |
|
794 {0x0076, 13}, // 1152 |
|
795 {0x0077, 13}, // 1216 |
|
796 {0x0052, 13}, // 1280 |
|
797 {0x0053, 13}, // 1344 |
|
798 {0x0054, 13}, // 1408 |
|
799 {0x0055, 13}, // 1472 |
|
800 {0x005A, 13}, // 1536 |
|
801 {0x005B, 13}, // 1600 |
|
802 {0x0064, 13}, // 1664 |
|
803 {0x0065, 13}, // 1728 |
|
804 }; |
|
805 if ( len >= 64 ) { |
|
806 int index = 63 + (len >> 6); |
|
807 writeG3Code( blackCodes[index].code, blackCodes[index].bits ); |
|
808 len &= 63; |
|
809 } |
|
810 writeG3Code( blackCodes[len].code, blackCodes[len].bits ); |
|
811 } |
|
812 |
|
813 void QtopiaPrintEnginePrivate::writeG3EOL() |
|
814 { |
|
815 int bitToPad; |
|
816 if ( partialBits <= 4 ) { |
|
817 bitToPad = 4 - partialBits; |
|
818 } else { |
|
819 bitToPad = 8 - partialBits + 4; |
|
820 } |
|
821 |
|
822 partialByte = ((partialByte << (bitToPad + 12)) | 0x0001); |
|
823 partialBits += bitToPad + 12; |
|
824 |
|
825 while ( partialBits >= 8 ) { |
|
826 partialBits -= 8; |
|
827 buffer.append( (char)(partialByte >> partialBits ) ); |
|
828 } |
|
829 // writeG3Code( 0x0001, 12 ); |
|
830 } |
|
831 |
|
832 void QtopiaPrintBuffer::append( short value ) |
|
833 { |
|
834 if ( _bigEndian ) { |
|
835 _data.append( (char)(value >> 8) ); |
|
836 _data.append( (char)value ); |
|
837 } else { |
|
838 _data.append( (char)value ); |
|
839 _data.append( (char)(value >> 8) ); |
|
840 } |
|
841 } |
|
842 |
|
843 void QtopiaPrintBuffer::append( int value ) |
|
844 { |
|
845 if ( _bigEndian ) { |
|
846 _data.append( (char)(value >> 24) ); |
|
847 _data.append( (char)(value >> 16) ); |
|
848 _data.append( (char)(value >> 8) ); |
|
849 _data.append( (char)value ); |
|
850 } else { |
|
851 _data.append( (char)value ); |
|
852 _data.append( (char)(value >> 8) ); |
|
853 _data.append( (char)(value >> 16) ); |
|
854 _data.append( (char)(value >> 24) ); |
|
855 } |
|
856 } |
|
857 |
|
858 void QtopiaPrintBuffer::patch( int posn, int value ) |
|
859 { |
|
860 if ( _bigEndian ) { |
|
861 _data[posn] = (char)(value >> 24); |
|
862 _data[posn + 1] = (char)(value >> 16); |
|
863 _data[posn + 2] = (char)(value >> 8); |
|
864 _data[posn + 3] = (char)value; |
|
865 } else { |
|
866 _data[posn] = (char)value; |
|
867 _data[posn + 1] = (char)(value >> 8); |
|
868 _data[posn + 2] = (char)(value >> 16); |
|
869 _data[posn + 3] = (char)(value >> 24); |
|
870 } |
|
871 } |
|
872 |
|
873 void QtopiaPrintBuffer::pad() |
|
874 { |
|
875 while ( ( _data.size() % 4 ) != 0 ) |
|
876 _data.append( (char)0 ); |
|
877 } |
|
878 |
|
879 QT_END_NAMESPACE |
|
880 |
|
881 #endif // QT_NO_PRINTER |