00001
00002
00003
00004
00005
00006
00007
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
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
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
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
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
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
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
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
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
00444 Q_UINT8 byte = 12;
00445 s << byte;
00446
00447
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
00533
00534