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

KImgIO

tga.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2003 Dominik Seichter <domseichter@web.de>
00003    Copyright (C) 2004 Ignacio Castaņo <castano@ludicon.com>
00004 
00005    This program is free software; you can redistribute it and/or
00006    modify it under the terms of the Lesser GNU General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 */
00010 
00011 /* this code supports:
00012  * reading:
00013  *     uncompressed and run length encoded indexed, grey and color tga files.
00014  *     image types 1, 2, 3, 9, 10 and 11.
00015  *     only RGB color maps with no more than 256 colors.
00016  *     pixel formats 8, 15, 24 and 32.
00017  * writing:
00018  *     uncompressed true color tga files
00019  */
00020 
00021 #include "tga.h"
00022 
00023 #include <assert.h>
00024 
00025 #include <qimage.h>
00026 #include <qdatastream.h>
00027 
00028 #include <kdebug.h>
00029 
00030 typedef Q_UINT32 uint;
00031 typedef Q_UINT16 ushort;
00032 typedef Q_UINT8 uchar;
00033 
00034 namespace { // Private.
00035 
00036     // Header format of saved files.
00037     uchar targaMagic[12] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
00038 
00039     enum TGAType {
00040         TGA_TYPE_INDEXED        = 1,
00041         TGA_TYPE_RGB            = 2,
00042         TGA_TYPE_GREY           = 3,
00043         TGA_TYPE_RLE_INDEXED    = 9,
00044         TGA_TYPE_RLE_RGB        = 10,
00045         TGA_TYPE_RLE_GREY       = 11
00046     };
00047 
00048 #define TGA_INTERLEAVE_MASK 0xc0
00049 #define TGA_INTERLEAVE_NONE 0x00
00050 #define TGA_INTERLEAVE_2WAY 0x40
00051 #define TGA_INTERLEAVE_4WAY 0x80
00052 
00053 #define TGA_ORIGIN_MASK     0x30
00054 #define TGA_ORIGIN_LEFT     0x00
00055 #define TGA_ORIGIN_RIGHT    0x10
00056 #define TGA_ORIGIN_LOWER    0x00
00057 #define TGA_ORIGIN_UPPER    0x20
00058 
00060     struct TgaHeader {
00061         uchar id_length;
00062         uchar colormap_type;
00063         uchar image_type;
00064         ushort colormap_index;
00065         ushort colormap_length;
00066         uchar colormap_size;
00067         ushort x_origin;
00068         ushort y_origin;
00069         ushort width;
00070         ushort height;
00071         uchar pixel_size;
00072         uchar flags;
00073     
00074         enum { SIZE = 18 }; // const static int SIZE = 18;
00075     };
00076 
00077     static QDataStream & operator>> ( QDataStream & s, TgaHeader & head )
00078     {
00079         s >> head.id_length;
00080         s >> head.colormap_type;
00081         s >> head.image_type;
00082         s >> head.colormap_index;
00083         s >> head.colormap_length;
00084         s >> head.colormap_size;
00085         s >> head.x_origin;
00086         s >> head.y_origin;
00087         s >> head.width;
00088         s >> head.height;
00089         s >> head.pixel_size;
00090         s >> head.flags;
00091         return s;
00092     }
00093 
00094     static bool IsSupported( const TgaHeader & head )
00095     {
00096         if( head.image_type != TGA_TYPE_INDEXED &&
00097             head.image_type != TGA_TYPE_RGB &&
00098             head.image_type != TGA_TYPE_GREY &&
00099             head.image_type != TGA_TYPE_RLE_INDEXED &&
00100             head.image_type != TGA_TYPE_RLE_RGB &&
00101             head.image_type != TGA_TYPE_RLE_GREY )
00102         {
00103             return false;
00104         }
00105         if( head.image_type == TGA_TYPE_INDEXED ||
00106             head.image_type == TGA_TYPE_RLE_INDEXED )
00107         {
00108             if( head.colormap_length > 256 || head.colormap_size != 24 )
00109             {
00110                 return false;
00111             }
00112         }
00113         if( head.width == 0 || head.height == 0 )
00114         {
00115             return false;
00116         }
00117         if( head.pixel_size != 8 && head.pixel_size != 16 &&
00118             head.pixel_size != 24 && head.pixel_size != 32 )
00119         {
00120             return false;
00121         }
00122         return true;
00123     }
00124 
00125     struct Color555 {
00126         ushort b : 5;
00127         ushort g : 5;
00128         ushort r : 5;
00129     };
00130     
00131     struct TgaHeaderInfo {
00132         bool rle;
00133         bool pal;
00134         bool rgb;
00135         bool grey;
00136         bool supported;
00137     
00138         TgaHeaderInfo( const TgaHeader & tga ) : rle(false), pal(false), rgb(false), grey(false), supported(true)
00139         {
00140             switch( tga.image_type ) {
00141                 case TGA_TYPE_RLE_INDEXED:
00142                     rle = true;
00143                     // no break is intended!
00144                 case TGA_TYPE_INDEXED:
00145                     if( tga.colormap_type!=1 || tga.colormap_size!=24 || tga.colormap_length>256 ) {
00146                         supported = false;
00147                     }
00148                     pal = true;
00149                     break;
00150         
00151                 case TGA_TYPE_RLE_RGB:
00152                     rle = true;
00153                     // no break is intended!
00154                 case TGA_TYPE_RGB:
00155                     rgb = true;
00156                     break;
00157         
00158                 case TGA_TYPE_RLE_GREY:
00159                     rle = true;
00160                     // no break is intended!
00161                 case TGA_TYPE_GREY:
00162                     grey = true;
00163                     break;
00164         
00165                 default:
00166                     // Error, unknown image type.
00167                     supported = false;
00168             }
00169         }
00170     };
00171 
00172     static bool LoadTGA( QDataStream & s, const TgaHeader & tga, QImage &img )
00173     {
00174         // Create image.
00175         if( !img.create( tga.width, tga.height, 32 )) {
00176             return false;
00177         }
00178 
00179         TgaHeaderInfo info(tga);
00180         if( !info.supported ) {
00181             // File not supported.
00182             kdDebug(399) << "This TGA file is not supported." << endl;
00183             return false;
00184         }
00185         
00186                 // Bits 0-3 are the numbers of alpha bits (can be zero!)
00187                 const int numAlphaBits = tga.flags & 0xf;
00188                 // However alpha exists only in the 32 bit format.
00189         if( ( tga.pixel_size == 32 ) && ( tga.flags & 0xf ) ) {
00190             img.setAlphaBuffer( true );
00191         }
00192 
00193         uint pixel_size = (tga.pixel_size/8);
00194         uint size = tga.width * tga.height * pixel_size;
00195 
00196         if (size < 1)
00197         {
00198             kdDebug(399) << "This TGA file is broken with size " << size << endl;
00199             return false;
00200         }
00201 
00202         
00203         // Read palette.
00204         char palette[768];
00205         if( info.pal ) {
00206             // @todo Support palettes in other formats!
00207             s.readRawBytes( palette, 3 * tga.colormap_length );
00208         }
00209 
00210         // Allocate image.
00211         uchar * const image = new uchar[size];
00212 
00213         if( info.rle ) {
00214             // Decode image.
00215             char * dst = (char *)image;
00216             int num = size;
00217     
00218             while (num > 0) {
00219                 // Get packet header.
00220                 uchar c; 
00221                 s >> c;
00222     
00223                 uint count = (c & 0x7f) + 1;
00224                 num -= count * pixel_size;
00225     
00226                 if (c & 0x80) {
00227                     // RLE pixels.
00228                                         assert(pixel_size <= 8);
00229                     char pixel[8];
00230                     s.readRawBytes( pixel, pixel_size );
00231                     do {
00232                         memcpy(dst, pixel, pixel_size);
00233                         dst += pixel_size;
00234                     } while (--count);
00235                 }
00236                 else {
00237                     // Raw pixels.
00238                     count *= pixel_size;
00239                     s.readRawBytes( dst, count );
00240                     dst += count;
00241                 }
00242             }
00243         }
00244         else {
00245             // Read raw image.
00246             s.readRawBytes( (char *)image, size );
00247         }
00248 
00249         // Convert image to internal format.                
00250         int y_start, y_step, y_end;
00251         if( tga.flags & TGA_ORIGIN_UPPER ) {
00252             y_start = 0;
00253             y_step = 1;
00254             y_end = tga.height;
00255         }
00256         else {
00257             y_start = tga.height - 1;
00258             y_step = -1;
00259             y_end = -1;
00260         }
00261 
00262         uchar * src = image;
00263                
00264         for( int y = y_start; y != y_end; y += y_step ) {
00265             QRgb * scanline = (QRgb *) img.scanLine( y );
00266         
00267             if( info.pal ) {
00268                 // Paletted.
00269                 for( int x = 0; x < tga.width; x++ ) {
00270                     uchar idx = *src++;
00271                     scanline[x] = qRgb( palette[3*idx+2], palette[3*idx+1], palette[3*idx+0] );
00272                 }
00273             }
00274             else if( info.grey ) {
00275                 // Greyscale.
00276                 for( int x = 0; x < tga.width; x++ ) {
00277                     scanline[x] = qRgb( *src, *src, *src );
00278                     src++;
00279                 }
00280             }
00281             else {
00282                 // True Color.
00283                 if( tga.pixel_size == 16 ) {
00284                     for( int x = 0; x < tga.width; x++ ) {
00285                         Color555 c = *reinterpret_cast<Color555 *>(src);
00286                         scanline[x] = qRgb( (c.r << 3) | (c.r >> 2), (c.g << 3) | (c.g >> 2), (c.b << 3) | (c.b >> 2) );
00287                         src += 2;
00288                     }
00289                 }
00290                 else if( tga.pixel_size == 24 ) {
00291                     for( int x = 0; x < tga.width; x++ ) {
00292                         scanline[x] = qRgb( src[2], src[1], src[0] );
00293                         src += 3;
00294                     }
00295                 }
00296                 else if( tga.pixel_size == 32 ) {
00297                     for( int x = 0; x < tga.width; x++ ) {
00298                                                 // ### TODO: verify with images having really some alpha data
00299                                                 const uchar alpha = ( src[3] << ( 8 - numAlphaBits ) );
00300                         scanline[x] = qRgba( src[2], src[1], src[0], alpha );
00301                         src += 4;
00302                     }
00303                 }
00304             }
00305         }
00306 
00307         // Free image.
00308         delete [] image;
00309         
00310         return true;
00311     }
00312     
00313 } // namespace
00314 
00315 
00316 KDE_EXPORT void kimgio_tga_read( QImageIO *io )
00317 {
00318     //kdDebug(399) << "Loading TGA file!" << endl;
00319     
00320     QDataStream s( io->ioDevice() );
00321     s.setByteOrder( QDataStream::LittleEndian );
00322 
00323 
00324     // Read image header.
00325     TgaHeader tga;
00326     s >> tga;
00327     s.device()->at( TgaHeader::SIZE + tga.id_length );
00328 
00329     // Check image file format.
00330     if( s.atEnd() ) {
00331         kdDebug(399) << "This TGA file is not valid." << endl;
00332         io->setImage( 0 );
00333         io->setStatus( -1 );
00334         return;
00335     }
00336 
00337     // Check supported file types.
00338     if( !IsSupported(tga) ) {
00339         kdDebug(399) << "This TGA file is not supported." << endl;
00340         io->setImage( 0 );
00341         io->setStatus( -1 );
00342         return;
00343     }
00344                 
00345 
00346     QImage img;
00347     bool result = LoadTGA(s, tga, img);
00348         
00349     if( result == false ) {
00350         kdDebug(399) << "Error loading TGA file." << endl;
00351         io->setImage( 0 );
00352         io->setStatus( -1 );
00353         return;
00354     }
00355 
00356 
00357     io->setImage( img );
00358     io->setStatus( 0 );
00359 }
00360 
00361 
00362 KDE_EXPORT void kimgio_tga_write( QImageIO *io )
00363 {
00364     QDataStream s( io->ioDevice() );
00365     s.setByteOrder( QDataStream::LittleEndian );
00366 
00367     const QImage img = io->image();
00368     const bool hasAlpha = img.hasAlphaBuffer();
00369     for( int i = 0; i < 12; i++ )
00370         s << targaMagic[i];
00371 
00372     // write header
00373     s << Q_UINT16( img.width() ); // width
00374     s << Q_UINT16( img.height() ); // height
00375     s << Q_UINT8( hasAlpha ? 32 : 24 ); // depth (24 bit RGB + 8 bit alpha)
00376     s << Q_UINT8( hasAlpha ? 0x24 : 0x20 ); // top left image (0x20) + 8 bit alpha (0x4)
00377 
00378     for( int y = 0; y < img.height(); y++ )
00379         for( int x = 0; x < img.width(); x++ ) {
00380             const QRgb color = img.pixel( x, y );
00381             s << Q_UINT8( qBlue( color ) );
00382             s << Q_UINT8( qGreen( color ) );
00383             s << Q_UINT8( qRed( color ) );
00384             if( hasAlpha )
00385                 s << Q_UINT8( qAlpha( color ) );
00386         }
00387 
00388     io->setStatus( 0 );
00389 }
00390  

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