• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KImgIO

pcx.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2002-2005 Nadeem Hasan <nhasan@kde.org>
00003 
00004    This program is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License (LGPL) as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 */
00009 
00010 #include "pcx.h"
00011 
00012 #include <QtGui/QImage>
00013 
00014 #include <kdebug.h>
00015 
00016 static QDataStream &operator>>( QDataStream &s, RGB &rgb )
00017 {
00018   quint8 r, g, b;
00019   
00020   s >> r >> g >> b;
00021   rgb.r = r;
00022   rgb.g = g;
00023   rgb.b = b;
00024 
00025   return s;
00026 }
00027 
00028 static QDataStream &operator>>( QDataStream &s, Palette &pal )
00029 {
00030   for ( int i=0; i<16; ++i )
00031     s >> pal.rgb[ i ];
00032 
00033   return s;
00034 }
00035 
00036 static QDataStream &operator>>( QDataStream &s, PCXHEADER &ph )
00037 {
00038   quint8 m, ver, enc, bpp;
00039   s >> m >> ver >> enc >> bpp;
00040   ph.Manufacturer = m;
00041   ph.Version = ver;
00042   ph.Encoding = enc;
00043   ph.Bpp = bpp;
00044   quint16 xmin, ymin, xmax, ymax;
00045   s >> xmin >> ymin >> xmax >> ymax;
00046   ph.XMin = xmin;
00047   ph.YMin = ymin;
00048   ph.XMax = xmax;
00049   ph.YMax = ymax;
00050   quint16 hdpi, ydpi;
00051   s >> hdpi >> ydpi;
00052   ph.HDpi = hdpi;
00053   ph.YDpi = ydpi;
00054   Palette colorMap;
00055   quint8 res, np;
00056   s >> colorMap >> res >> np;
00057   ph.ColorMap = colorMap;
00058   ph.Reserved = res;
00059   ph.NPlanes = np;
00060   quint16 bytesperline;
00061   s >> bytesperline; ph.BytesPerLine = bytesperline;
00062   quint16 paletteinfo;
00063   s >> paletteinfo; ph.PaletteInfo = paletteinfo;
00064   quint16 hscreensize, vscreensize;
00065   s >> hscreensize; ph.HScreenSize = hscreensize;
00066   s >> vscreensize; ph.VScreenSize = vscreensize;
00067 
00068   // Skip the rest of the header
00069   quint8 byte;
00070   while ( s.device()->pos() < 128 )
00071     s >> byte;
00072 
00073   return s;
00074 }
00075 
00076 static QDataStream &operator<<( QDataStream &s, const RGB &rgb )
00077 {
00078   s << rgb.r << rgb.g << rgb.b;
00079 
00080   return s;
00081 }
00082 
00083 static QDataStream &operator<<( QDataStream &s, const Palette &pal )
00084 {
00085   for ( int i=0; i<16; ++i )
00086     s << pal.rgb[ i ];
00087 
00088   return s;
00089 }
00090 
00091 static QDataStream &operator<<( QDataStream &s, const PCXHEADER &ph )
00092 {
00093   s << ph.Manufacturer;
00094   s << ph.Version;
00095   s << ph.Encoding;
00096   s << ph.Bpp;
00097   s << ph.XMin << ph.YMin << ph.XMax << ph.YMax;
00098   s << ph.HDpi << ph.YDpi;
00099   s << ph.ColorMap;
00100   s << ph.Reserved;
00101   s << ph.NPlanes;
00102   s << ph.BytesPerLine;
00103   s << ph.PaletteInfo;
00104   s << ph.HScreenSize;
00105   s << ph.VScreenSize;
00106 
00107   quint8 byte = 0;
00108   for ( int i=0; i<54; ++i )
00109     s << byte;
00110 
00111   return s;
00112 }
00113 
00114 PCXHEADER::PCXHEADER()
00115 {
00116   // Initialize all data to zero
00117   QByteArray dummy( 128, 0 );
00118   dummy.fill( 0 );
00119   QDataStream s( &dummy, QIODevice::ReadOnly );
00120   s >> *this;
00121 }
00122 
00123 static void readLine( QDataStream &s, QByteArray &buf, const PCXHEADER &header )
00124 {
00125   quint32 i=0;
00126   quint32 size = buf.size();
00127   quint8 byte, count;
00128 
00129   if ( header.isCompressed() )
00130   {
00131     // Uncompress the image data
00132     while ( i < size )
00133     {
00134       count = 1;
00135       s >> byte;
00136       if ( byte > 0xc0 )
00137       {
00138         count = byte - 0xc0;
00139         s >> byte;
00140       }
00141       while ( count-- && i < size )
00142         buf[ i++ ] = byte;
00143     }
00144   }
00145   else
00146   {
00147     // Image is not compressed (possible?)
00148     while ( i < size )
00149     {
00150       s >> byte;
00151       buf[ i++ ] = byte;
00152     }
00153   }
00154 }
00155 
00156 static void readImage1( QImage &img, QDataStream &s, const PCXHEADER &header )
00157 {
00158   QByteArray buf( header.BytesPerLine, 0 );
00159 
00160   img = QImage( header.width(), header.height(), QImage::Format_Mono );
00161   img.setNumColors( 2 );
00162 
00163   for ( int y=0; y<header.height(); ++y )
00164   {
00165     if ( s.atEnd() )
00166     {
00167       img = QImage();
00168       return;
00169     }
00170 
00171     readLine( s, buf, header );
00172     uchar *p = img.scanLine( y );
00173     unsigned int bpl = qMin((quint16)((header.width()+7)/8), header.BytesPerLine);
00174     for ( unsigned int x=0; x< bpl; ++x )
00175       p[ x ] = buf[x];
00176   }
00177 
00178   // Set the color palette
00179   img.setColor( 0, qRgb( 0, 0, 0 ) );
00180   img.setColor( 1, qRgb( 255, 255, 255 ) );
00181 }
00182 
00183 static void readImage4( QImage &img, QDataStream &s, const PCXHEADER &header )
00184 {
00185   QByteArray buf( header.BytesPerLine*4, 0 );
00186   QByteArray pixbuf( header.width(), 0 );
00187 
00188   img = QImage( header.width(), header.height(), QImage::Format_Indexed8 );
00189   img.setNumColors( 16 );
00190 
00191   for ( int y=0; y<header.height(); ++y )
00192   {
00193     if ( s.atEnd() )
00194     {
00195       img = QImage();
00196       return;
00197     }
00198 
00199     pixbuf.fill( 0 );
00200     readLine( s, buf, header );
00201 
00202     for ( int i=0; i<4; i++ )
00203     {
00204       quint32 offset = i*header.BytesPerLine;
00205       for ( int x=0; x<header.width(); ++x )
00206         if ( buf[ offset + ( x/8 ) ] & ( 128 >> ( x%8 ) ) )
00207           pixbuf[ x ] = (int)(pixbuf[ x ]) + ( 1 << i );
00208     }
00209 
00210     uchar *p = img.scanLine( y );
00211     for ( int x=0; x<header.width(); ++x )
00212       p[ x ] = pixbuf[ x ];
00213   }
00214 
00215   // Read the palette
00216   for ( int i=0; i<16; ++i )
00217     img.setColor( i, header.ColorMap.color( i ) );
00218 }
00219 
00220 static void readImage8( QImage &img, QDataStream &s, const PCXHEADER &header )
00221 {
00222   QByteArray buf( header.BytesPerLine, 0 );
00223 
00224   img = QImage( header.width(), header.height(), QImage::Format_Indexed8 );
00225   img.setNumColors( 256 );
00226 
00227   for ( int y=0; y<header.height(); ++y )
00228   {
00229     if ( s.atEnd() )
00230     {
00231       img = QImage();
00232       return;
00233     }
00234 
00235     readLine( s, buf, header );
00236 
00237     uchar *p = img.scanLine( y );
00238     unsigned int bpl = qMin(header.BytesPerLine, (quint16)header.width());
00239     for ( unsigned int x=0; x<bpl; ++x )
00240       p[ x ] = buf[ x ];
00241   }
00242 
00243   quint8 flag;
00244   s >> flag;
00245   kDebug( 399 ) << "Palette Flag: " << flag;
00246 
00247   if ( flag == 12 && ( header.Version == 5 || header.Version == 2 ) )
00248   {
00249     // Read the palette
00250     quint8 r, g, b;
00251     for ( int i=0; i<256; ++i )
00252     {
00253       s >> r >> g >> b;
00254       img.setColor( i, qRgb( r, g, b ) );
00255     }
00256   }
00257 }
00258 
00259 static void readImage24( QImage &img, QDataStream &s, const PCXHEADER &header )
00260 {
00261   QByteArray r_buf( header.BytesPerLine, 0 );
00262   QByteArray g_buf( header.BytesPerLine, 0 );
00263   QByteArray b_buf( header.BytesPerLine, 0 );
00264 
00265   img = QImage( header.width(), header.height(), QImage::Format_RGB32 );
00266 
00267   for ( int y=0; y<header.height(); ++y )
00268   {
00269     if ( s.atEnd() )
00270     {
00271       img = QImage();
00272       return;
00273     }
00274 
00275     readLine( s, r_buf, header );
00276     readLine( s, g_buf, header );
00277     readLine( s, b_buf, header );
00278 
00279     uint *p = ( uint * )img.scanLine( y );
00280     for ( int x=0; x<header.width(); ++x )
00281       p[ x ] = qRgb( r_buf[ x ], g_buf[ x ], b_buf[ x ] );
00282   }
00283 }
00284 
00285 static void writeLine( QDataStream &s, QByteArray &buf )
00286 {
00287   quint32 i = 0;
00288   quint32 size = buf.size();
00289   quint8 count, data;
00290   char byte;
00291 
00292   while ( i < size )
00293   {
00294     count = 1;
00295     byte = buf[ i++ ];
00296 
00297     while ( ( i < size ) && ( byte == buf[ i ] ) && ( count < 63 ) )
00298     {
00299       ++i;
00300       ++count;
00301     }
00302 
00303     data = byte;
00304 
00305     if ( count > 1 || data >= 0xc0 )
00306     {
00307       count |= 0xc0;
00308       s << count;
00309     }
00310 
00311     s << data;
00312   }
00313 }
00314 
00315 static void writeImage1( QImage &img, QDataStream &s, PCXHEADER &header )
00316 {
00317   img = img.convertToFormat( QImage::Format_Mono );
00318 
00319   header.Bpp = 1;
00320   header.NPlanes = 1;
00321   header.BytesPerLine = img.bytesPerLine();
00322 
00323   s << header;
00324 
00325   QByteArray buf( header.BytesPerLine, 0 );
00326 
00327   for ( int y=0; y<header.height(); ++y )
00328   {
00329     quint8 *p = img.scanLine( y );
00330 
00331     // Invert as QImage uses reverse palette for monochrome images?
00332     for ( int i=0; i<header.BytesPerLine; ++i )
00333       buf[ i ] = ~p[ i ];
00334 
00335     writeLine( s, buf );
00336   }
00337 }
00338 
00339 static void writeImage4( QImage &img, QDataStream &s, PCXHEADER &header )
00340 {
00341   header.Bpp = 1;
00342   header.NPlanes = 4;
00343   header.BytesPerLine = header.width()/8;
00344 
00345   for ( int i=0; i<16; ++i )
00346     header.ColorMap.setColor( i, img.color( i ) );
00347 
00348   s << header;
00349 
00350   QByteArray buf[ 4 ];
00351 
00352   for ( int i=0; i<4; ++i )
00353       buf[ i ].resize( header.BytesPerLine );
00354 
00355   for ( int y=0; y<header.height(); ++y )
00356   {
00357     quint8 *p = img.scanLine( y );
00358 
00359     for ( int i=0; i<4; ++i )
00360       buf[ i ].fill( 0 );
00361 
00362     for ( int x=0; x<header.width(); ++x )
00363     {
00364       for ( int i=0; i<4; ++i )
00365         if ( *( p+x ) & ( 1 << i ) )
00366           buf[ i ][ x/8 ] = (int)(buf[ i ][ x/8 ])| 1 << ( 7-x%8 );
00367     }
00368 
00369     for ( int i=0; i<4; ++i )
00370       writeLine( s, buf[ i ] );
00371   }
00372 }
00373 
00374 static void writeImage8( QImage &img, QDataStream &s, PCXHEADER &header )
00375 {
00376   header.Bpp = 8;
00377   header.NPlanes = 1;
00378   header.BytesPerLine = img.bytesPerLine();
00379 
00380   s << header;
00381 
00382   QByteArray buf( header.BytesPerLine, 0 );
00383 
00384   for ( int y=0; y<header.height(); ++y )
00385   {
00386     quint8 *p = img.scanLine( y );
00387 
00388     for ( int i=0; i<header.BytesPerLine; ++i )
00389       buf[ i ] = p[ i ];
00390 
00391     writeLine( s, buf );
00392   }
00393 
00394   // Write palette flag
00395   quint8 byte = 12;
00396   s << byte;
00397 
00398   // Write palette
00399   for ( int i=0; i<256; ++i )
00400     s << RGB::from( img.color( i ) );
00401 }
00402 
00403 static void writeImage24( QImage &img, QDataStream &s, PCXHEADER &header )
00404 {
00405   header.Bpp = 8;
00406   header.NPlanes = 3;
00407   header.BytesPerLine = header.width();
00408 
00409   s << header;
00410 
00411   QByteArray r_buf( header.width(), 0 );
00412   QByteArray g_buf( header.width(), 0 );
00413   QByteArray b_buf( header.width(), 0 );
00414 
00415   for ( int y=0; y<header.height(); ++y )
00416   {
00417     uint *p = ( uint * )img.scanLine( y );
00418 
00419     for ( int x=0; x<header.width(); ++x )
00420     {
00421       QRgb rgb = *p++;
00422       r_buf[ x ] = qRed( rgb );
00423       g_buf[ x ] = qGreen( rgb );
00424       b_buf[ x ] = qBlue( rgb );
00425     }
00426 
00427     writeLine( s, r_buf );
00428     writeLine( s, g_buf );
00429     writeLine( s, b_buf );
00430   }
00431 }
00432 
00433 
00434 PCXHandler::PCXHandler()
00435 {
00436 }
00437 
00438 bool PCXHandler::canRead() const
00439 {
00440   if (canRead(device()))
00441   {
00442     setFormat("pcx");
00443     return true;
00444   }
00445   return false;
00446 }
00447 
00448 bool PCXHandler::read(QImage *outImage)
00449 {
00450   QDataStream s( device() );
00451   s.setByteOrder( QDataStream::LittleEndian );
00452 
00453   if ( s.device()->size() < 128 )
00454   {
00455     return false;
00456   }
00457 
00458   PCXHEADER header;
00459 
00460   s >> header;
00461 
00462   if ( header.Manufacturer != 10 || s.atEnd())
00463   {
00464     return false;
00465   }
00466 
00467   int w = header.width();
00468   int h = header.height();
00469 
00470   kDebug( 399 ) << "Manufacturer: " << header.Manufacturer;
00471   kDebug( 399 ) << "Version: " << header.Version;
00472   kDebug( 399 ) << "Encoding: " << header.Encoding;
00473   kDebug( 399 ) << "Bpp: " << header.Bpp;
00474   kDebug( 399 ) << "Width: " << w;
00475   kDebug( 399 ) << "Height: " << h;
00476   kDebug( 399 ) << "Window: " << header.XMin << "," << header.XMax << ","
00477                  << header.YMin << "," << header.YMax << endl;
00478   kDebug( 399 ) << "BytesPerLine: " << header.BytesPerLine;
00479   kDebug( 399 ) << "NPlanes: " << header.NPlanes;
00480 
00481   QImage img;
00482 
00483   if ( header.Bpp == 1 && header.NPlanes == 1 )
00484   {
00485     readImage1( img, s, header );
00486   }
00487   else if ( header.Bpp == 1 && header.NPlanes == 4 )
00488   {
00489     readImage4( img, s, header );
00490   }
00491   else if ( header.Bpp == 8 && header.NPlanes == 1 )
00492   {
00493     readImage8( img, s, header );
00494   }
00495   else if ( header.Bpp == 8 && header.NPlanes == 3 )
00496   {
00497     readImage24( img, s, header );
00498   }
00499 
00500   kDebug( 399 ) << "Image Bytes: " << img.numBytes();
00501   kDebug( 399 ) << "Image Bytes Per Line: " << img.bytesPerLine();
00502   kDebug( 399 ) << "Image Depth: " << img.depth();
00503 
00504   if ( !img.isNull() )
00505   {
00506     *outImage = img;
00507     return true;
00508   }
00509   else
00510   {
00511     return false;
00512   }
00513 }
00514 
00515 bool PCXHandler::write(const QImage &image)
00516 {
00517   QDataStream s( device() );
00518   s.setByteOrder( QDataStream::LittleEndian );
00519 
00520   QImage img = image;
00521 
00522   int w = img.width();
00523   int h = img.height();
00524 
00525   kDebug( 399 ) << "Width: " << w;
00526   kDebug( 399 ) << "Height: " << h;
00527   kDebug( 399 ) << "Depth: " << img.depth();
00528   kDebug( 399 ) << "BytesPerLine: " << img.bytesPerLine();
00529   kDebug( 399 ) << "Num Colors: " << img.numColors();
00530 
00531   PCXHEADER header;
00532 
00533   header.Manufacturer = 10;
00534   header.Version = 5;
00535   header.Encoding = 1;
00536   header.XMin = 0;
00537   header.YMin = 0;
00538   header.XMax = w-1;
00539   header.YMax = h-1;
00540   header.HDpi = 300;
00541   header.YDpi = 300;
00542   header.Reserved = 0;
00543   header.PaletteInfo =1;
00544 
00545   if ( img.depth() == 1 )
00546   {
00547     writeImage1( img, s, header );
00548   }
00549   else if ( img.depth() == 8 && img.numColors() <= 16 )
00550   {
00551     writeImage4( img, s, header );
00552   }
00553   else if ( img.depth() == 8 )
00554   {
00555     writeImage8( img, s, header );
00556   }
00557   else if ( img.depth() == 32 )
00558   {
00559     writeImage24( img, s, header );
00560   }
00561 
00562   return true;
00563 }
00564 
00565 QByteArray PCXHandler::name() const
00566 {
00567     return "pcx";
00568 }
00569 
00570 bool PCXHandler::canRead(QIODevice *device)
00571 {
00572     if (!device) {
00573         qWarning("PCXHandler::canRead() called with no device");
00574         return false;
00575     }
00576 
00577     qint64 oldPos = device->pos();
00578 
00579     char head[1];
00580     qint64 readBytes = device->read(head, sizeof(head));
00581     if (readBytes != sizeof(head)) {
00582         if (device->isSequential()) {
00583             while (readBytes > 0)
00584                 device->ungetChar(head[readBytes-- - 1]);
00585         } else {
00586             device->seek(oldPos);
00587         }
00588         return false;
00589     }
00590 
00591     if (device->isSequential()) {
00592         while (readBytes > 0)
00593             device->ungetChar(head[readBytes-- - 1]);
00594     } else {
00595         device->seek(oldPos);
00596     }
00597 
00598     return qstrncmp(head, "\012", 1) == 0;
00599 }
00600 
00601 class PCXPlugin : public QImageIOPlugin
00602 {
00603 public:
00604     QStringList keys() const;
00605     Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
00606     QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
00607 };
00608 
00609 QStringList PCXPlugin::keys() const
00610 {
00611     return QStringList() << "pcx" << "PCX";
00612 }
00613 
00614 QImageIOPlugin::Capabilities PCXPlugin::capabilities(QIODevice *device, const QByteArray &format) const
00615 {
00616     if (format == "pcx" || format == "PCX")
00617         return Capabilities(CanRead | CanWrite);
00618     if (!format.isEmpty())
00619         return 0;
00620     if (!device->isOpen())
00621         return 0;
00622 
00623     Capabilities cap;
00624     if (device->isReadable() && PCXHandler::canRead(device))
00625         cap |= CanRead;
00626     if (device->isWritable())
00627         cap |= CanWrite;
00628     return cap;
00629 }
00630 
00631 QImageIOHandler *PCXPlugin::create(QIODevice *device, const QByteArray &format) const
00632 {
00633     QImageIOHandler *handler = new PCXHandler;
00634     handler->setDevice(device);
00635     handler->setFormat(format);
00636     return handler;
00637 }
00638 
00639 Q_EXPORT_STATIC_PLUGIN(PCXPlugin)
00640 Q_EXPORT_PLUGIN2(pcx, PCXPlugin)
00641 
00642 /* vim: et sw=2 ts=2
00643 */
00644 

KImgIO

Skip menu "KImgIO"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal