• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • 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 <qimage.h>
00013 
00014 #include <kdebug.h>
00015 
00016 static QDataStream &operator>>( QDataStream &s, RGB &rgb )
00017 {
00018   s >> rgb.r >> rgb.g >> rgb.b;
00019 
00020   return s;
00021 }
00022 
00023 static QDataStream &operator>>( QDataStream &s, Palette &pal )
00024 {
00025   for ( int i=0; i<16; ++i )
00026     s >> pal.rgb[ i ];
00027 
00028   return s;
00029 }
00030 
00031 static QDataStream &operator>>( QDataStream &s, PCXHEADER &ph )
00032 {
00033   s >> ph.Manufacturer;
00034   s >> ph.Version;
00035   s >> ph.Encoding;
00036   s >> ph.Bpp;
00037   s >> ph.XMin >> ph.YMin >> ph.XMax >> ph.YMax;
00038   s >> ph.HDpi >> ph.YDpi;
00039   s >> ph.ColorMap;
00040   s >> ph.Reserved;
00041   s >> ph.NPlanes;
00042   s >> ph.BytesPerLine;
00043   s >> ph.PaletteInfo;
00044   s >> ph.HScreenSize;
00045   s >> ph.VScreenSize;
00046 
00047   // Skip the rest of the header
00048   Q_UINT8 byte;
00049   while ( s.device()->at() < 128 )
00050     s >> byte;
00051 
00052   return s;
00053 }
00054 
00055 static QDataStream &operator<<( QDataStream &s, const RGB &rgb )
00056 {
00057   s << rgb.r << rgb.g << rgb.b;
00058 
00059   return s;
00060 }
00061 
00062 static QDataStream &operator<<( QDataStream &s, const Palette &pal )
00063 {
00064   for ( int i=0; i<16; ++i )
00065     s << pal.rgb[ i ];
00066 
00067   return s;
00068 }
00069 
00070 static QDataStream &operator<<( QDataStream &s, const PCXHEADER &ph )
00071 {
00072   s << ph.Manufacturer;
00073   s << ph.Version;
00074   s << ph.Encoding;
00075   s << ph.Bpp;
00076   s << ph.XMin << ph.YMin << ph.XMax << ph.YMax;
00077   s << ph.HDpi << ph.YDpi;
00078   s << ph.ColorMap;
00079   s << ph.Reserved;
00080   s << ph.NPlanes;
00081   s << ph.BytesPerLine;
00082   s << ph.PaletteInfo;
00083   s << ph.HScreenSize;
00084   s << ph.VScreenSize;
00085 
00086   Q_UINT8 byte = 0;
00087   for ( int i=0; i<54; ++i )
00088     s << byte;
00089 
00090   return s;
00091 }
00092 
00093 PCXHEADER::PCXHEADER()
00094 {
00095   // Initialize all data to zero
00096   QByteArray dummy( 128 );
00097   dummy.fill( 0 );
00098   QDataStream s( dummy, IO_ReadOnly );
00099   s >> *this;
00100 }
00101 
00102 static void readLine( QDataStream &s, QByteArray &buf, const PCXHEADER &header )
00103 {
00104   Q_UINT32 i=0;
00105   Q_UINT32 size = buf.size();
00106   Q_UINT8 byte, count;
00107 
00108   if ( header.isCompressed() )
00109   {
00110     // Uncompress the image data
00111     while ( i < size )
00112     {
00113       count = 1;
00114       s >> byte;
00115       if ( byte > 0xc0 )
00116       {
00117         count = byte - 0xc0;
00118         s >> byte;
00119       }
00120       while ( count-- && i < size )
00121         buf[ i++ ] = byte;
00122     }
00123   }
00124   else
00125   {
00126     // Image is not compressed (possible?)
00127     while ( i < size )
00128     {
00129       s >> byte;
00130       buf[ i++ ] = byte;
00131     }
00132   }
00133 }
00134 
00135 static void readImage1( QImage &img, QDataStream &s, const PCXHEADER &header )
00136 {
00137   QByteArray buf( header.BytesPerLine );
00138 
00139   if(!img.create( header.width(), header.height(), 1, 2, QImage::BigEndian ))
00140     return;
00141 
00142   for ( int y=0; y<header.height(); ++y )
00143   {
00144     if ( s.atEnd() )
00145     {
00146       img.reset();
00147       return;
00148     }
00149 
00150     readLine( s, buf, header );
00151     uchar *p = img.scanLine( y );
00152     unsigned int bpl = QMIN((header.width()+7)/8, header.BytesPerLine);
00153     for ( unsigned int x=0; x< bpl; ++x )
00154       p[ x ] = buf[x];
00155   }
00156 
00157   // Set the color palette
00158   img.setColor( 0, qRgb( 0, 0, 0 ) );
00159   img.setColor( 1, qRgb( 255, 255, 255 ) );
00160 }
00161 
00162 static void readImage4( QImage &img, QDataStream &s, const PCXHEADER &header )
00163 {
00164   QByteArray buf( header.BytesPerLine*4 );
00165   QByteArray pixbuf( header.width() );
00166 
00167   if(!img.create( header.width(), header.height(), 8, 16 ))
00168     return;
00169 
00170   for ( int y=0; y<header.height(); ++y )
00171   {
00172     if ( s.atEnd() )
00173     {
00174       img.reset();
00175       return;
00176     }
00177 
00178     pixbuf.fill( 0 );
00179     readLine( s, buf, header );
00180 
00181     for ( int i=0; i<4; i++ )
00182     {
00183       Q_UINT32 offset = i*header.BytesPerLine;
00184       for ( unsigned int x=0; x<header.width(); ++x )
00185         if ( buf[ offset + ( x/8 ) ] & ( 128 >> ( x%8 ) ) )
00186           pixbuf[ x ] += ( 1 << i );
00187     }
00188 
00189     uchar *p = img.scanLine( y );
00190     for ( unsigned int x=0; x<header.width(); ++x )
00191       p[ x ] = pixbuf[ x ];
00192   }
00193 
00194   // Read the palette
00195   for ( int i=0; i<16; ++i )
00196     img.setColor( i, header.ColorMap.color( i ) );
00197 }
00198 
00199 static void readImage8( QImage &img, QDataStream &s, const PCXHEADER &header )
00200 {
00201   QByteArray buf( header.BytesPerLine );
00202 
00203   if(!img.create( header.width(), header.height(), 8, 256 ))
00204     return;
00205 
00206   for ( int y=0; y<header.height(); ++y )
00207   {
00208     if ( s.atEnd() )
00209     {
00210       img.reset();
00211       return;
00212     }
00213 
00214     readLine( s, buf, header );
00215 
00216     uchar *p = img.scanLine( y );
00217     unsigned int bpl = QMIN(header.BytesPerLine, header.width());
00218     for ( unsigned int x=0; x<bpl; ++x )
00219       p[ x ] = buf[ x ];
00220   }
00221 
00222   Q_UINT8 flag;
00223   s >> flag;
00224   kdDebug( 399 ) << "Palette Flag: " << flag << endl;
00225 
00226   if ( flag == 12 && ( header.Version == 5 || header.Version == 2 ) )
00227   {
00228     // Read the palette
00229     Q_UINT8 r, g, b;
00230     for ( int i=0; i<256; ++i )
00231     {
00232       s >> r >> g >> b;
00233       img.setColor( i, qRgb( r, g, b ) );
00234     }
00235   }
00236 }
00237 
00238 static void readImage24( QImage &img, QDataStream &s, const PCXHEADER &header )
00239 {
00240   QByteArray r_buf( header.BytesPerLine );
00241   QByteArray g_buf( header.BytesPerLine );
00242   QByteArray b_buf( header.BytesPerLine );
00243 
00244   if(!img.create( header.width(), header.height(), 32 ))
00245     return;
00246 
00247   for ( int y=0; y<header.height(); ++y )
00248   {
00249     if ( s.atEnd() )
00250     {
00251       img.reset();
00252       return;
00253     }
00254 
00255     readLine( s, r_buf, header );
00256     readLine( s, g_buf, header );
00257     readLine( s, b_buf, header );
00258 
00259     uint *p = ( uint * )img.scanLine( y );
00260     for ( unsigned int x=0; x<header.width(); ++x )
00261       p[ x ] = qRgb( r_buf[ x ], g_buf[ x ], b_buf[ x ] );
00262   }
00263 }
00264 
00265 KDE_EXPORT void kimgio_pcx_read( QImageIO *io )
00266 {
00267   QDataStream s( io->ioDevice() );
00268   s.setByteOrder( QDataStream::LittleEndian );
00269 
00270   if ( s.device()->size() < 128 )
00271   {
00272     io->setStatus( -1 );
00273     return;
00274   }
00275 
00276   PCXHEADER header;
00277 
00278   s >> header;
00279 
00280   if ( header.Manufacturer != 10 || s.atEnd())
00281   {
00282     io->setStatus( -1 );
00283     return;
00284   }
00285 
00286   int w = header.width();
00287   int h = header.height();
00288 
00289   kdDebug( 399 ) << "Manufacturer: " << header.Manufacturer << endl;
00290   kdDebug( 399 ) << "Version: " << header.Version << endl;
00291   kdDebug( 399 ) << "Encoding: " << header.Encoding << endl;
00292   kdDebug( 399 ) << "Bpp: " << header.Bpp << endl;
00293   kdDebug( 399 ) << "Width: " << w << endl;
00294   kdDebug( 399 ) << "Height: " << h << endl;
00295   kdDebug( 399 ) << "Window: " << header.XMin << "," << header.XMax << "," 
00296                  << header.YMin << "," << header.YMax << endl;
00297   kdDebug( 399 ) << "BytesPerLine: " << header.BytesPerLine << endl;
00298   kdDebug( 399 ) << "NPlanes: " << header.NPlanes << endl;
00299 
00300   QImage img;
00301 
00302   if ( header.Bpp == 1 && header.NPlanes == 1 )
00303   {
00304     readImage1( img, s, header );
00305   }
00306   else if ( header.Bpp == 1 && header.NPlanes == 4 )
00307   {
00308     readImage4( img, s, header );
00309   }
00310   else if ( header.Bpp == 8 && header.NPlanes == 1 )
00311   {
00312     readImage8( img, s, header );
00313   }
00314   else if ( header.Bpp == 8 && header.NPlanes == 3 )
00315   {
00316     readImage24( img, s, header );
00317   }
00318 
00319   kdDebug( 399 ) << "Image Bytes: " << img.numBytes() << endl;
00320   kdDebug( 399 ) << "Image Bytes Per Line: " << img.bytesPerLine() << endl;
00321   kdDebug( 399 ) << "Image Depth: " << img.depth() << endl;
00322 
00323   if ( !img.isNull() )
00324   {
00325     io->setImage( img );
00326     io->setStatus( 0 );
00327   }
00328   else
00329   {
00330     io->setStatus( -1 );
00331   }
00332 }
00333 
00334 static void writeLine( QDataStream &s, QByteArray &buf )
00335 {
00336   Q_UINT32 i = 0;
00337   Q_UINT32 size = buf.size();
00338   Q_UINT8 count, data;
00339   char byte;
00340 
00341   while ( i < size )
00342   {
00343     count = 1;
00344     byte = buf[ i++ ];
00345 
00346     while ( ( i < size ) && ( byte == buf[ i ] ) && ( count < 63 ) )
00347     {
00348       ++i;
00349       ++count;
00350     }
00351 
00352     data = byte;
00353 
00354     if ( count > 1 || data >= 0xc0 )
00355     {
00356       count |= 0xc0;
00357       s << count;
00358     }
00359 
00360     s << data;
00361   }
00362 }
00363 
00364 static void writeImage1( QImage &img, QDataStream &s, PCXHEADER &header )
00365 {
00366   img = img.convertBitOrder( QImage::BigEndian );
00367 
00368   header.Bpp = 1;
00369   header.NPlanes = 1;
00370   header.BytesPerLine = img.bytesPerLine();
00371 
00372   s << header;
00373 
00374   QByteArray buf( header.BytesPerLine );
00375 
00376   for ( int y=0; y<header.height(); ++y )
00377   {
00378     Q_UINT8 *p = img.scanLine( y );
00379 
00380     // Invert as QImage uses reverse palette for monochrome images?
00381     for ( int i=0; i<header.BytesPerLine; ++i )
00382       buf[ i ] = ~p[ i ];
00383 
00384     writeLine( s, buf );
00385   }
00386 }
00387 
00388 static void writeImage4( QImage &img, QDataStream &s, PCXHEADER &header )
00389 {
00390   header.Bpp = 1;
00391   header.NPlanes = 4;
00392   header.BytesPerLine = header.width()/8;
00393 
00394   for ( int i=0; i<16; ++i )
00395     header.ColorMap.setColor( i, img.color( i ) );
00396 
00397   s << header;
00398 
00399   QByteArray buf[ 4 ];
00400 
00401   for ( int i=0; i<4; ++i )
00402       buf[ i ].resize( header.BytesPerLine );
00403 
00404   for ( int y=0; y<header.height(); ++y )
00405   {
00406     Q_UINT8 *p = img.scanLine( y );
00407 
00408     for ( int i=0; i<4; ++i )
00409       buf[ i ].fill( 0 );
00410 
00411     for ( unsigned int x=0; x<header.width(); ++x )
00412     {
00413       for ( int i=0; i<4; ++i )
00414         if ( *( p+x ) & ( 1 << i ) )
00415           buf[ i ][ x/8 ] |= 1 << ( 7-x%8 );
00416     }
00417 
00418     for ( int i=0; i<4; ++i )
00419       writeLine( s, buf[ i ] );
00420   }
00421 }
00422 
00423 static void writeImage8( QImage &img, QDataStream &s, PCXHEADER &header )
00424 {
00425   header.Bpp = 8;
00426   header.NPlanes = 1;
00427   header.BytesPerLine = img.bytesPerLine();
00428 
00429   s << header;
00430 
00431   QByteArray buf( header.BytesPerLine );
00432 
00433   for ( int y=0; y<header.height(); ++y )
00434   {
00435     Q_UINT8 *p = img.scanLine( y );
00436 
00437     for ( int i=0; i<header.BytesPerLine; ++i )
00438       buf[ i ] = p[ i ];
00439 
00440     writeLine( s, buf );
00441   }
00442 
00443   // Write palette flag
00444   Q_UINT8 byte = 12;
00445   s << byte;
00446 
00447   // Write palette
00448   for ( int i=0; i<256; ++i )
00449     s << RGB( img.color( i ) );
00450 }
00451 
00452 static void writeImage24( QImage &img, QDataStream &s, PCXHEADER &header )
00453 {
00454   header.Bpp = 8;
00455   header.NPlanes = 3;
00456   header.BytesPerLine = header.width();
00457 
00458   s << header;
00459 
00460   QByteArray r_buf( header.width() );
00461   QByteArray g_buf( header.width() );
00462   QByteArray b_buf( header.width() );
00463 
00464   for ( int y=0; y<header.height(); ++y )
00465   {
00466     uint *p = ( uint * )img.scanLine( y );
00467 
00468     for ( unsigned int x=0; x<header.width(); ++x )
00469     {
00470       QRgb rgb = *p++;
00471       r_buf[ x ] = qRed( rgb );
00472       g_buf[ x ] = qGreen( rgb );
00473       b_buf[ x ] = qBlue( rgb );
00474     }
00475 
00476     writeLine( s, r_buf );
00477     writeLine( s, g_buf );
00478     writeLine( s, b_buf );
00479   }
00480 }
00481 
00482 KDE_EXPORT void kimgio_pcx_write( QImageIO *io )
00483 {
00484   QDataStream s( io->ioDevice() );
00485   s.setByteOrder( QDataStream::LittleEndian );
00486 
00487   QImage img = io->image();
00488 
00489   int w = img.width();
00490   int h = img.height();
00491 
00492   kdDebug( 399 ) << "Width: " << w << endl;
00493   kdDebug( 399 ) << "Height: " << h << endl;
00494   kdDebug( 399 ) << "Depth: " << img.depth() << endl;
00495   kdDebug( 399 ) << "BytesPerLine: " << img.bytesPerLine() << endl;
00496   kdDebug( 399 ) << "Num Colors: " << img.numColors() << endl;
00497 
00498   PCXHEADER header;
00499 
00500   header.Manufacturer = 10;
00501   header.Version = 5;
00502   header.Encoding = 1;
00503   header.XMin = 0;
00504   header.YMin = 0;
00505   header.XMax = w-1;
00506   header.YMax = h-1;
00507   header.HDpi = 300;
00508   header.YDpi = 300;
00509   header.Reserved = 0;
00510   header.PaletteInfo =1;
00511 
00512   if ( img.depth() == 1 )
00513   {
00514     writeImage1( img, s, header );
00515   }
00516   else if ( img.depth() == 8 && img.numColors() <= 16 )
00517   {
00518     writeImage4( img, s, header );
00519   }
00520   else if ( img.depth() == 8 )
00521   {
00522     writeImage8( img, s, header );
00523   }
00524   else if ( img.depth() == 32 )
00525   {
00526     writeImage24( img, s, header );
00527   }
00528 
00529   io->setStatus( 0 );
00530 }
00531 
00532 /* vim: et sw=2 ts=2
00533 */
00534 

KImgIO

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

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
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