1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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
QtopiaPrintEngine(QPrinter::PrinterMode mode)59 QtopiaPrintEngine::QtopiaPrintEngine(QPrinter::PrinterMode mode)
60 : QPaintEngine(*(new QtopiaPrintEnginePrivate( mode )))
61 {
62 d_func()->initialize();
63 }
64
begin(QPaintDevice *)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
end()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
paintEngine() const145 QPaintEngine *QtopiaPrintEngine::paintEngine() const
146 {
147 return const_cast<QtopiaPrintEnginePrivate *>(d_func())->paintEngine();
148 }
149
drawPixmap(const QRectF & r,const QPixmap & pm,const QRectF & sr)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
drawTextItem(const QPointF & p,const QTextItem & ti)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
updateState(const QPaintEngineState & state)164 void QtopiaPrintEngine::updateState(const QPaintEngineState &state)
165 {
166 Q_D(QtopiaPrintEngine);
167 d->paintEngine()->updateState(state);
168 }
169
paperRect() const170 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
pageRect() const183 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
newPage()192 bool QtopiaPrintEngine::newPage()
193 {
194 flushPage();
195 clearPage();
196 ++(d_func()->pageNumber);
197 return true;
198 }
199
abort()200 bool QtopiaPrintEngine::abort()
201 {
202 return false;
203 }
204
printerState() const205 QPrinter::PrinterState QtopiaPrintEngine::printerState() const
206 {
207 return d_func()->printerState;
208 }
209
metric(QPaintDevice::PaintDeviceMetric metricType) const210 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
property(PrintEnginePropertyKey key) const250 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_CopyCount: // fallthrough
272 case PPK_NumberOfCopies:
273 ret = d->numCopies;
274 break;
275 case PPK_SupportsMultipleCopies:
276 ret = false;
277 break;
278 case PPK_Orientation:
279 ret = d->orientation;
280 break;
281 case PPK_OutputFileName:
282 ret = d->outputFileName;
283 break;
284 case PPK_PageOrder:
285 ret = d->pageOrder;
286 break;
287 case PPK_PageRect:
288 ret = pageRect();
289 break;
290 case PPK_PaperSize:
291 ret = d->paperSize;
292 break;
293 case PPK_PaperRect:
294 ret = paperRect();
295 break;
296 case PPK_PaperSource:
297 ret = d->paperSource;
298 break;
299 case PPK_PrinterName:
300 ret = d->printerName;
301 break;
302 case PPK_PrinterProgram:
303 ret = d->printProgram;
304 break;
305 case PPK_Resolution:
306 ret = d->resolution;
307 break;
308 case PPK_SupportedResolutions:
309 ret = QList<QVariant>() << QT_QWS_PRINTER_DEFAULT_DPI;
310 break;
311 default:
312 break;
313 }
314 return ret;
315 }
316
setProperty(PrintEnginePropertyKey key,const QVariant & value)317 void QtopiaPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value)
318 {
319 Q_D(QtopiaPrintEngine);
320 switch (key) {
321 case PPK_CollateCopies:
322 d->collateCopies = value.toBool();
323 break;
324 case PPK_ColorMode:
325 d->colorMode = QPrinter::ColorMode(value.toInt());
326 break;
327 case PPK_Creator:
328 d->creator = value.toString();
329 break;
330 case PPK_DocumentName:
331 d->docName = value.toString();
332 break;
333 case PPK_FullPage:
334 d->fullPage = value.toBool();
335 break;
336 case PPK_CopyCount: // fallthrough
337 case PPK_NumberOfCopies:
338 d->numCopies = value.toInt();
339 break;
340 case PPK_Orientation:
341 d->orientation = QPrinter::Orientation(value.toInt());
342 break;
343 case PPK_OutputFileName:
344 d->outputFileName = value.toString();
345 break;
346 case PPK_PageOrder:
347 d->pageOrder = QPrinter::PageOrder(value.toInt());
348 break;
349 case PPK_PaperSize:
350 d->paperSize = QPrinter::PaperSize(value.toInt());
351 break;
352 case PPK_PaperSource:
353 d->paperSource = QPrinter::PaperSource(value.toInt());
354 case PPK_PrinterName:
355 d->printerName = value.toString();
356 break;
357 case PPK_PrinterProgram:
358 d->printProgram = value.toString();
359 break;
360 case PPK_Resolution:
361 d->resolution = value.toInt();
362 break;
363 default:
364 break;
365 }
366 }
367
clearPage()368 void QtopiaPrintEngine::clearPage()
369 {
370 d_func()->pageImage->fill(QColor(255, 255, 255).rgb());
371 }
372
flushPage()373 void QtopiaPrintEngine::flushPage()
374 {
375 d_func()->writeG3FaxPage();
376 }
377
~QtopiaPrintEnginePrivate()378 QtopiaPrintEnginePrivate::~QtopiaPrintEnginePrivate()
379 {
380 if ( pageImage )
381 delete pageImage;
382 }
383
initialize()384 void QtopiaPrintEnginePrivate::initialize()
385 {
386 _paintEngine = 0;
387 }
388
paintEngine()389 QPaintEngine *QtopiaPrintEnginePrivate::paintEngine()
390 {
391 if (!_paintEngine)
392 _paintEngine = new QRasterPaintEngine(pageImage);
393 return _paintEngine;
394 }
395
writeG3FaxHeader()396 void QtopiaPrintEnginePrivate::writeG3FaxHeader()
397 {
398 // Write the TIFF file magic number (little-endian TIFF).
399 buffer.append( (char)'I' );
400 buffer.append( (char)'I' );
401 buffer.append( (char)42 );
402 buffer.append( (char)0 );
403
404 // Leave a place-holder for the IFD offset of the first page.
405 ifdPatch = buffer.size();
406 buffer.append( (int)0 );
407 }
408
409 // Tag values, from RFC 2301.
410 #define TIFF_IFD_NEW_SUB_FILE_TYPE 254
411 #define TIFF_IFD_IMAGE_WIDTH 256
412 #define TIFF_IFD_IMAGE_LENGTH 257
413 #define TIFF_IFD_BITS_PER_SAMPLE 258
414 #define TIFF_IFD_COMPRESSION 259
415 #define TIFF_IFD_PHOTOMETRIC_INTERP 262
416 #define TIFF_IFD_FILL_ORDER 266
417 #define TIFF_IFD_STRIP_OFFSETS 273
418 #define TIFF_IFD_ORIENTATION 274
419 #define TIFF_IFD_SAMPLES_PER_PIXEL 277
420 #define TIFF_IFD_ROWS_PER_STRIP 278
421 #define TIFF_IFD_STRIP_BYTE_COUNTS 279
422 #define TIFF_IFD_X_RESOLUTION 282
423 #define TIFF_IFD_Y_RESOLUTION 283
424 #define TIFF_IFD_PLANAR_CONFIG 284
425 #define TIFF_IFD_T4_OPTIONS 292
426 #define TIFF_IFD_RESOLUTION_UNIT 296
427 #define TIFF_IFD_PAGE_NUMBER 297
428 #define TIFF_IFD_CLEAN_FAX_DATA 327
429
430 // IFD type values.
431 #define TIFF_TYPE_SHORT 3
432 #define TIFF_TYPE_LONG 4
433 #define TIFF_TYPE_RATIONAL 5
434
435 // Construct a SHORT pair from two values.
436 #define TIFF_SHORT_PAIR(a,b) (((a) & 0xFFFF) | ((b) << 16))
437
438 // Width of a FAX page in pixels, in the baseline specification from RFC 2301.
439 // This must be hard-wired, as per the RFC. We truncate any pixels that
440 // are beyond this limit, or pad lines to reach this limit.
441 #define TIFF_FAX_WIDTH 1728
442
writeG3FaxPage()443 void QtopiaPrintEnginePrivate::writeG3FaxPage()
444 {
445 // Pad the image file to a word boundary, just in case.
446 buffer.pad();
447
448 // Back-patch the IFD link for the previous page.
449 buffer.patch( ifdPatch, buffer.size() );
450
451 // Output the contents of the IFD for this page (these must be
452 // in ascending order of tag value).
453 buffer.append( (short)19 ); // Number of IFD entries.
454 writeG3IFDEntry( TIFF_IFD_NEW_SUB_FILE_TYPE, TIFF_TYPE_LONG, 1, 2 );
455 writeG3IFDEntry( TIFF_IFD_IMAGE_WIDTH, TIFF_TYPE_LONG, 1, TIFF_FAX_WIDTH );
456 writeG3IFDEntry
457 ( TIFF_IFD_IMAGE_LENGTH, TIFF_TYPE_LONG, 1, pageImage->height() );
458 writeG3IFDEntry( TIFF_IFD_BITS_PER_SAMPLE, TIFF_TYPE_SHORT, 1, 1 );
459 writeG3IFDEntry( TIFF_IFD_COMPRESSION, TIFF_TYPE_SHORT, 1, 3 );
460 writeG3IFDEntry( TIFF_IFD_PHOTOMETRIC_INTERP, TIFF_TYPE_SHORT, 1, 0 );
461 writeG3IFDEntry( TIFF_IFD_FILL_ORDER, TIFF_TYPE_SHORT, 1, 1 );
462 int stripOffsets =
463 writeG3IFDEntry( TIFF_IFD_STRIP_OFFSETS, TIFF_TYPE_LONG, 1, 0 );
464 writeG3IFDEntry( TIFF_IFD_ORIENTATION, TIFF_TYPE_SHORT, 1, 1 );
465 writeG3IFDEntry( TIFF_IFD_SAMPLES_PER_PIXEL, TIFF_TYPE_SHORT, 1, 1 );
466 writeG3IFDEntry
467 ( TIFF_IFD_ROWS_PER_STRIP, TIFF_TYPE_LONG, 1, pageImage->height() );
468 int stripBytes = writeG3IFDEntry
469 ( TIFF_IFD_STRIP_BYTE_COUNTS, TIFF_TYPE_LONG, 1, 0 );
470 int xres =
471 writeG3IFDEntry( TIFF_IFD_X_RESOLUTION, TIFF_TYPE_RATIONAL, 1, 0 );
472 int yres =
473 writeG3IFDEntry( TIFF_IFD_Y_RESOLUTION, TIFF_TYPE_RATIONAL, 1, 0 );
474 writeG3IFDEntry( TIFF_IFD_PLANAR_CONFIG, TIFF_TYPE_SHORT, 1, 1 );
475 writeG3IFDEntry( TIFF_IFD_T4_OPTIONS, TIFF_TYPE_LONG, 1, 2 );
476 writeG3IFDEntry( TIFF_IFD_RESOLUTION_UNIT, TIFF_TYPE_SHORT, 1, 2 );
477 writeG3IFDEntry( TIFF_IFD_PAGE_NUMBER, TIFF_TYPE_SHORT, 2,
478 TIFF_SHORT_PAIR( pageNumber, 0 ) );
479 writeG3IFDEntry( TIFF_IFD_CLEAN_FAX_DATA, TIFF_TYPE_SHORT, 1, 0 );
480
481 // Leave a place-holder for the IFD offset of the next page.
482 ifdPatch = buffer.size();
483 buffer.append( (int)0 );
484
485 // Output the X and Y resolutions, as rational values (usually 200/1).
486 buffer.patch( xres, buffer.size() );
487 buffer.append( (int)resolution );
488 buffer.append( (int)1 );
489 buffer.patch( yres, buffer.size() );
490 buffer.append( (int)resolution );
491 buffer.append( (int)1 );
492
493 // We are now at the start of the image data - set the strip offset.
494 int start = buffer.size();
495 buffer.patch( stripOffsets, start );
496
497 // Output the image data.
498 int width = pageImage->width();
499 QImage::Format imageFormat = pageImage->format();
500 for ( int y = 0; y < pageImage->height(); ++y ) {
501 unsigned char *scan = pageImage->scanLine(y);
502 int prev, pixel, len;
503 writeG3EOL();
504 prev = 0;
505 len = 0;
506
507 uint currentColor = qRgb(255, 255, 255); // start with white
508
509 for ( int x = 0; x < width && x < TIFF_FAX_WIDTH; ++x ) {
510 if ( imageFormat == QImage::Format_RGB32 ) {
511 // read color of the current pixel
512 uint *p = (uint *)scan + x;
513
514 if ( *p == currentColor ) { // if it is the same color
515 len++; // imcrement length
516 } else { // otherwise write color into the buffer
517 if ( len > 0 ) {
518 if ( currentColor == qRgb(0, 0, 0) )
519 writeG3BlackRun( len );
520 else
521 writeG3WhiteRun( len );
522 }
523 // initialise length and color;
524 len = 1;
525 currentColor = *p;
526 }
527 } else if ( imageFormat == QImage::Format_Mono ) {
528 pixel = ((scan[x >> 3] & (1 << (x & 7))) != 0);
529 if ( pixel != prev ) {
530 if ( prev ) {
531 writeG3BlackRun( len );
532 } else {
533 writeG3WhiteRun( len );
534 }
535 prev = pixel;
536 len = 1;
537 } else {
538 ++len;
539 }
540 }
541 }
542
543 if ( imageFormat == QImage::Format_RGB32 ) {
544 // Output the last run on the line, and pad to TIFF_FAX_WIDTH.
545 if ( len != 0 ) {
546 if ( currentColor == qRgb(0, 0, 0) )
547 writeG3BlackRun( len );
548 else
549 writeG3WhiteRun( len );
550 }
551 if ( width < TIFF_FAX_WIDTH )
552 writeG3WhiteRun( TIFF_FAX_WIDTH - width );
553 } else if ( imageFormat == QImage::Format_Mono ) {
554 if ( len != 0 ) {
555 if ( prev ) {
556 writeG3BlackRun( len );
557 if ( width < TIFF_FAX_WIDTH ) {
558 writeG3WhiteRun( TIFF_FAX_WIDTH - width );
559 }
560 } else {
561 if ( width < TIFF_FAX_WIDTH ) {
562 writeG3WhiteRun( len + ( TIFF_FAX_WIDTH - width ) );
563 } else {
564 writeG3WhiteRun( len );
565 }
566 }
567 }
568 }
569 }
570
571 // Flush the last partial byte, which is padded with zero fill bits.
572 if ( partialBits > 0 ) {
573 buffer.append( (char)( partialByte << ( 8 - partialBits ) ) );
574 partialByte = 0;
575 partialBits = 0;
576 }
577
578 // end of page add six EOLs
579 for ( int i = 0; i < 6; i++ )
580 writeG3EOL();
581
582 // Update the byte count for the image data strip.
583 buffer.patch( stripBytes, buffer.size() - start );
584 }
585
writeG3IFDEntry(int tag,int type,int count,int value)586 int QtopiaPrintEnginePrivate::writeG3IFDEntry
587 ( int tag, int type, int count, int value )
588 {
589 buffer.append( (short)tag );
590 buffer.append( (short)type );
591 buffer.append( count );
592 buffer.append( value );
593 return buffer.size() - 4; // Offset of the value for back-patching.
594 }
595
writeG3Code(int code,int bits)596 void QtopiaPrintEnginePrivate::writeG3Code( int code, int bits )
597 {
598 partialByte = ( ( partialByte << bits ) | code );
599 partialBits += bits;
600 while ( partialBits >= 8 ) {
601 partialBits -= 8;
602 buffer.append( (char)( partialByte >> partialBits ) );
603 }
604 }
605
writeG3WhiteRun(int len)606 void QtopiaPrintEnginePrivate::writeG3WhiteRun( int len )
607 {
608 static struct {
609 unsigned short code;
610 unsigned short bits;
611 } whiteCodes[64 + 27] = {
612 {0x0035, 8}, // 0
613 {0x0007, 6},
614 {0x0007, 4},
615 {0x0008, 4},
616 {0x000B, 4},
617 {0x000C, 4},
618 {0x000E, 4},
619 {0x000F, 4},
620 {0x0013, 5}, // 8
621 {0x0014, 5},
622 {0x0007, 5},
623 {0x0008, 5},
624 {0x0008, 6},
625 {0x0003, 6},
626 {0x0034, 6},
627 {0x0035, 6},
628 {0x002A, 6}, // 16
629 {0x002B, 6},
630 {0x0027, 7},
631 {0x000C, 7},
632 {0x0008, 7},
633 {0x0017, 7},
634 {0x0003, 7},
635 {0x0004, 7},
636 {0x0028, 7}, // 24
637 {0x002B, 7},
638 {0x0013, 7},
639 {0x0024, 7},
640 {0x0018, 7},
641 {0x0002, 8},
642 {0x0003, 8},
643 {0x001A, 8},
644 {0x001B, 8}, // 32
645 {0x0012, 8},
646 {0x0013, 8},
647 {0x0014, 8},
648 {0x0015, 8},
649 {0x0016, 8},
650 {0x0017, 8},
651 {0x0028, 8},
652 {0x0029, 8}, // 40
653 {0x002A, 8},
654 {0x002B, 8},
655 {0x002C, 8},
656 {0x002D, 8},
657 {0x0004, 8},
658 {0x0005, 8},
659 {0x000A, 8},
660 {0x000B, 8}, // 48
661 {0x0052, 8},
662 {0x0053, 8},
663 {0x0054, 8},
664 {0x0055, 8},
665 {0x0024, 8},
666 {0x0025, 8},
667 {0x0058, 8},
668 {0x0059, 8}, // 56
669 {0x005A, 8},
670 {0x005B, 8},
671 {0x004A, 8},
672 {0x004B, 8},
673 {0x0032, 8},
674 {0x0033, 8},
675 {0x0034, 8},
676 {0x001B, 5}, // Make up codes: 64
677 {0x0012, 5}, // 128
678 {0x0017, 6}, // 192
679 {0x0037, 7}, // 256
680 {0x0036, 8}, // 320
681 {0x0037, 8}, // 384
682 {0x0064, 8}, // 448
683 {0x0065, 8}, // 512
684 {0x0068, 8}, // 576
685 {0x0067, 8}, // 640
686 {0x00CC, 9}, // 704
687 {0x00CD, 9}, // 768
688 {0x00D2, 9}, // 832
689 {0x00D3, 9}, // 896
690 {0x00D4, 9}, // 960
691 {0x00D5, 9}, // 1024
692 {0x00D6, 9}, // 1088
693 {0x00D7, 9}, // 1152
694 {0x00D8, 9}, // 1216
695 {0x00D9, 9}, // 1280
696 {0x00DA, 9}, // 1344
697 {0x00DB, 9}, // 1408
698 {0x0098, 9}, // 1472
699 {0x0099, 9}, // 1536
700 {0x009A, 9}, // 1600
701 {0x0018, 6}, // 1664
702 {0x009B, 9}, // 1728
703 };
704 if ( len >= 64 ) {
705 int index = 63 + (len >> 6);
706 writeG3Code( whiteCodes[index].code, whiteCodes[index].bits );
707 len &= 63;
708 }
709 writeG3Code( whiteCodes[len].code, whiteCodes[len].bits );
710 }
711
writeG3BlackRun(int len)712 void QtopiaPrintEnginePrivate::writeG3BlackRun( int len )
713 {
714 static struct {
715 unsigned short code;
716 unsigned short bits;
717 } blackCodes[64 + 27] = {
718 {0x0037, 10}, // 0
719 {0x0002, 3},
720 {0x0003, 2},
721 {0x0002, 2},
722 {0x0003, 3},
723 {0x0003, 4},
724 {0x0002, 4},
725 {0x0003, 5},
726 {0x0005, 6}, // 8
727 {0x0004, 6},
728 {0x0004, 7},
729 {0x0005, 7},
730 {0x0007, 7},
731 {0x0004, 8},
732 {0x0007, 8},
733 {0x0018, 9},
734 {0x0017, 10}, // 16
735 {0x0018, 10},
736 {0x0008, 10},
737 {0x0067, 11},
738 {0x0068, 11},
739 {0x006C, 11},
740 {0x0037, 11},
741 {0x0028, 11},
742 {0x0017, 11}, // 24
743 {0x0018, 11},
744 {0x00CA, 12},
745 {0x00CB, 12},
746 {0x00CC, 12},
747 {0x00CD, 12},
748 {0x0068, 12},
749 {0x0069, 12},
750 {0x006A, 12}, // 32
751 {0x006B, 12},
752 {0x00D2, 12},
753 {0x00D3, 12},
754 {0x00D4, 12},
755 {0x00D5, 12},
756 {0x00D6, 12},
757 {0x00D7, 12},
758 {0x006C, 12}, // 40
759 {0x006D, 12},
760 {0x00DA, 12},
761 {0x00DB, 12},
762 {0x0054, 12},
763 {0x0055, 12},
764 {0x0056, 12},
765 {0x0057, 12},
766 {0x0064, 12}, // 48
767 {0x0065, 12},
768 {0x0052, 12},
769 {0x0053, 12},
770 {0x0024, 12},
771 {0x0037, 12},
772 {0x0038, 12},
773 {0x0027, 12},
774 {0x0028, 12}, // 56
775 {0x0058, 12},
776 {0x0059, 12},
777 {0x002B, 12},
778 {0x002C, 12},
779 {0x005A, 12},
780 {0x0066, 12},
781 {0x0067, 12},
782 {0x000F, 10}, // Make up codes: 64
783 {0x00C8, 12}, // 128
784 {0x00C9, 12}, // 192
785 {0x005B, 12}, // 256
786 {0x0033, 12}, // 320
787 {0x0034, 12}, // 384
788 {0x0035, 12}, // 448
789 {0x006C, 13}, // 512
790 {0x006D, 13}, // 576
791 {0x004A, 13}, // 640
792 {0x004B, 13}, // 704
793 {0x004C, 13}, // 768
794 {0x004D, 13}, // 832
795 {0x0072, 13}, // 896
796 {0x0073, 13}, // 960
797 {0x0074, 13}, // 1024
798 {0x0075, 13}, // 1088
799 {0x0076, 13}, // 1152
800 {0x0077, 13}, // 1216
801 {0x0052, 13}, // 1280
802 {0x0053, 13}, // 1344
803 {0x0054, 13}, // 1408
804 {0x0055, 13}, // 1472
805 {0x005A, 13}, // 1536
806 {0x005B, 13}, // 1600
807 {0x0064, 13}, // 1664
808 {0x0065, 13}, // 1728
809 };
810 if ( len >= 64 ) {
811 int index = 63 + (len >> 6);
812 writeG3Code( blackCodes[index].code, blackCodes[index].bits );
813 len &= 63;
814 }
815 writeG3Code( blackCodes[len].code, blackCodes[len].bits );
816 }
817
writeG3EOL()818 void QtopiaPrintEnginePrivate::writeG3EOL()
819 {
820 int bitToPad;
821 if ( partialBits <= 4 ) {
822 bitToPad = 4 - partialBits;
823 } else {
824 bitToPad = 8 - partialBits + 4;
825 }
826
827 partialByte = ((partialByte << (bitToPad + 12)) | 0x0001);
828 partialBits += bitToPad + 12;
829
830 while ( partialBits >= 8 ) {
831 partialBits -= 8;
832 buffer.append( (char)(partialByte >> partialBits ) );
833 }
834 // writeG3Code( 0x0001, 12 );
835 }
836
append(short value)837 void QtopiaPrintBuffer::append( short value )
838 {
839 if ( _bigEndian ) {
840 _data.append( (char)(value >> 8) );
841 _data.append( (char)value );
842 } else {
843 _data.append( (char)value );
844 _data.append( (char)(value >> 8) );
845 }
846 }
847
append(int value)848 void QtopiaPrintBuffer::append( int value )
849 {
850 if ( _bigEndian ) {
851 _data.append( (char)(value >> 24) );
852 _data.append( (char)(value >> 16) );
853 _data.append( (char)(value >> 8) );
854 _data.append( (char)value );
855 } else {
856 _data.append( (char)value );
857 _data.append( (char)(value >> 8) );
858 _data.append( (char)(value >> 16) );
859 _data.append( (char)(value >> 24) );
860 }
861 }
862
patch(int posn,int value)863 void QtopiaPrintBuffer::patch( int posn, int value )
864 {
865 if ( _bigEndian ) {
866 _data[posn] = (char)(value >> 24);
867 _data[posn + 1] = (char)(value >> 16);
868 _data[posn + 2] = (char)(value >> 8);
869 _data[posn + 3] = (char)value;
870 } else {
871 _data[posn] = (char)value;
872 _data[posn + 1] = (char)(value >> 8);
873 _data[posn + 2] = (char)(value >> 16);
874 _data[posn + 3] = (char)(value >> 24);
875 }
876 }
877
pad()878 void QtopiaPrintBuffer::pad()
879 {
880 while ( ( _data.size() % 4 ) != 0 )
881 _data.append( (char)0 );
882 }
883
884 QT_END_NAMESPACE
885
886 #endif // QT_NO_PRINTER
887