src/gui/painting/qprintengine_qws.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     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