• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kimgio
 

kimgio

  • kimgio
tga.cpp
1 /* This file is part of the KDE project
2  Copyright (C) 2003 Dominik Seichter <domseichter@web.de>
3  Copyright (C) 2004 Ignacio Castaņo <castano@ludicon.com>
4 
5  This program is free software; you can redistribute it and/or
6  modify it under the terms of the Lesser GNU General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 */
10 
11 /* this code supports:
12  * reading:
13  * uncompressed and run length encoded indexed, grey and color tga files.
14  * image types 1, 2, 3, 9, 10 and 11.
15  * only RGB color maps with no more than 256 colors.
16  * pixel formats 8, 15, 24 and 32.
17  * writing:
18  * uncompressed true color tga files
19  */
20 
21 #include "tga.h"
22 
23 #include <assert.h>
24 
25 #include <tqimage.h>
26 #include <tqdatastream.h>
27 
28 #include <kdebug.h>
29 
30 typedef TQ_UINT32 uint;
31 typedef TQ_UINT16 ushort;
32 typedef TQ_UINT8 uchar;
33 
34 namespace { // Private.
35 
36  // Header format of saved files.
37  uchar targaMagic[12] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
38 
39  enum TGAType {
40  TGA_TYPE_INDEXED = 1,
41  TGA_TYPE_RGB = 2,
42  TGA_TYPE_GREY = 3,
43  TGA_TYPE_RLE_INDEXED = 9,
44  TGA_TYPE_RLE_RGB = 10,
45  TGA_TYPE_RLE_GREY = 11
46  };
47 
48 #define TGA_INTERLEAVE_MASK 0xc0
49 #define TGA_INTERLEAVE_NONE 0x00
50 #define TGA_INTERLEAVE_2WAY 0x40
51 #define TGA_INTERLEAVE_4WAY 0x80
52 
53 #define TGA_ORIGIN_MASK 0x30
54 #define TGA_ORIGIN_LEFT 0x00
55 #define TGA_ORIGIN_RIGHT 0x10
56 #define TGA_ORIGIN_LOWER 0x00
57 #define TGA_ORIGIN_UPPER 0x20
58 
60  struct TgaHeader {
61  uchar id_length;
62  uchar colormap_type;
63  uchar image_type;
64  ushort colormap_index;
65  ushort colormap_length;
66  uchar colormap_size;
67  ushort x_origin;
68  ushort y_origin;
69  ushort width;
70  ushort height;
71  uchar pixel_size;
72  uchar flags;
73 
74  enum { SIZE = 18 }; // const static int SIZE = 18;
75  };
76 
77  static TQDataStream & operator>> ( TQDataStream & s, TgaHeader & head )
78  {
79  s >> head.id_length;
80  s >> head.colormap_type;
81  s >> head.image_type;
82  s >> head.colormap_index;
83  s >> head.colormap_length;
84  s >> head.colormap_size;
85  s >> head.x_origin;
86  s >> head.y_origin;
87  s >> head.width;
88  s >> head.height;
89  s >> head.pixel_size;
90  s >> head.flags;
91  return s;
92  }
93 
94  static bool IsSupported( const TgaHeader & head )
95  {
96  if( head.image_type != TGA_TYPE_INDEXED &&
97  head.image_type != TGA_TYPE_RGB &&
98  head.image_type != TGA_TYPE_GREY &&
99  head.image_type != TGA_TYPE_RLE_INDEXED &&
100  head.image_type != TGA_TYPE_RLE_RGB &&
101  head.image_type != TGA_TYPE_RLE_GREY )
102  {
103  return false;
104  }
105  if( head.image_type == TGA_TYPE_INDEXED ||
106  head.image_type == TGA_TYPE_RLE_INDEXED )
107  {
108  if( head.colormap_length > 256 || head.colormap_size != 24 )
109  {
110  return false;
111  }
112  }
113  if( head.width == 0 || head.height == 0 )
114  {
115  return false;
116  }
117  if( head.pixel_size != 8 && head.pixel_size != 16 &&
118  head.pixel_size != 24 && head.pixel_size != 32 )
119  {
120  return false;
121  }
122  return true;
123  }
124 
125  struct Color555 {
126  ushort b : 5;
127  ushort g : 5;
128  ushort r : 5;
129  };
130 
131  struct TgaHeaderInfo {
132  bool rle;
133  bool pal;
134  bool rgb;
135  bool grey;
136  bool supported;
137 
138  TgaHeaderInfo( const TgaHeader & tga ) : rle(false), pal(false), rgb(false), grey(false), supported(true)
139  {
140  switch( tga.image_type ) {
141  case TGA_TYPE_RLE_INDEXED:
142  rle = true;
143  // no break is intended!
144  case TGA_TYPE_INDEXED:
145  if( tga.colormap_type!=1 || tga.colormap_size!=24 || tga.colormap_length>256 ) {
146  supported = false;
147  }
148  pal = true;
149  break;
150 
151  case TGA_TYPE_RLE_RGB:
152  rle = true;
153  // no break is intended!
154  case TGA_TYPE_RGB:
155  rgb = true;
156  break;
157 
158  case TGA_TYPE_RLE_GREY:
159  rle = true;
160  // no break is intended!
161  case TGA_TYPE_GREY:
162  grey = true;
163  break;
164 
165  default:
166  // Error, unknown image type.
167  supported = false;
168  }
169  }
170  };
171 
172  static bool LoadTGA( TQDataStream & s, const TgaHeader & tga, TQImage &img )
173  {
174  // Create image.
175  if( !img.create( tga.width, tga.height, 32 )) {
176  return false;
177  }
178 
179  TgaHeaderInfo info(tga);
180  if( !info.supported ) {
181  // File not supported.
182  kdDebug(399) << "This TGA file is not supported." << endl;
183  return false;
184  }
185 
186  // Bits 0-3 are the numbers of alpha bits (can be zero!)
187  const int numAlphaBits = tga.flags & 0xf;
188  // However alpha exists only in the 32 bit format.
189  if( ( tga.pixel_size == 32 ) && ( tga.flags & 0xf ) ) {
190  img.setAlphaBuffer( true );
191  }
192 
193  uint pixel_size = (tga.pixel_size/8);
194  uint size = tga.width * tga.height * pixel_size;
195 
196  if (size < 1)
197  {
198  kdDebug(399) << "This TGA file is broken with size " << size << endl;
199  return false;
200  }
201 
202 
203  // Read palette.
204  char palette[768];
205  if( info.pal ) {
206  // @todo Support palettes in other formats!
207  s.readRawBytes( palette, 3 * tga.colormap_length );
208  }
209 
210  // Allocate image.
211  uchar * const image = new uchar[size];
212 
213  if( info.rle ) {
214  // Decode image.
215  char * dst = (char *)image;
216  int num = size;
217 
218  while (num > 0) {
219  // Get packet header.
220  uchar c;
221  s >> c;
222 
223  uint count = (c & 0x7f) + 1;
224  num -= count * pixel_size;
225 
226  if (c & 0x80) {
227  // RLE pixels.
228  assert(pixel_size <= 8);
229  char pixel[8];
230  s.readRawBytes( pixel, pixel_size );
231  do {
232  memcpy(dst, pixel, pixel_size);
233  dst += pixel_size;
234  } while (--count);
235  }
236  else {
237  // Raw pixels.
238  count *= pixel_size;
239  s.readRawBytes( dst, count );
240  dst += count;
241  }
242  }
243  }
244  else {
245  // Read raw image.
246  s.readRawBytes( (char *)image, size );
247  }
248 
249  // Convert image to internal format.
250  int y_start, y_step, y_end;
251  if( tga.flags & TGA_ORIGIN_UPPER ) {
252  y_start = 0;
253  y_step = 1;
254  y_end = tga.height;
255  }
256  else {
257  y_start = tga.height - 1;
258  y_step = -1;
259  y_end = -1;
260  }
261 
262  uchar * src = image;
263 
264  for( int y = y_start; y != y_end; y += y_step ) {
265  QRgb * scanline = (QRgb *) img.scanLine( y );
266 
267  if( info.pal ) {
268  // Paletted.
269  for( int x = 0; x < tga.width; x++ ) {
270  uchar idx = *src++;
271  scanline[x] = tqRgb( palette[3*idx+2], palette[3*idx+1], palette[3*idx+0] );
272  }
273  }
274  else if( info.grey ) {
275  // Greyscale.
276  for( int x = 0; x < tga.width; x++ ) {
277  scanline[x] = tqRgb( *src, *src, *src );
278  src++;
279  }
280  }
281  else {
282  // True Color.
283  if( tga.pixel_size == 16 ) {
284  for( int x = 0; x < tga.width; x++ ) {
285  Color555 c = *reinterpret_cast<Color555 *>(src);
286  scanline[x] = tqRgb( (c.r << 3) | (c.r >> 2), (c.g << 3) | (c.g >> 2), (c.b << 3) | (c.b >> 2) );
287  src += 2;
288  }
289  }
290  else if( tga.pixel_size == 24 ) {
291  for( int x = 0; x < tga.width; x++ ) {
292  scanline[x] = tqRgb( src[2], src[1], src[0] );
293  src += 3;
294  }
295  }
296  else if( tga.pixel_size == 32 ) {
297  for( int x = 0; x < tga.width; x++ ) {
298  // ### TODO: verify with images having really some alpha data
299  const uchar alpha = ( src[3] << ( 8 - numAlphaBits ) );
300  scanline[x] = tqRgba( src[2], src[1], src[0], alpha );
301  src += 4;
302  }
303  }
304  }
305  }
306 
307  // Free image.
308  delete [] image;
309 
310  return true;
311  }
312 
313 } // namespace
314 
315 
316 KDE_EXPORT void kimgio_tga_read( TQImageIO *io )
317 {
318  //kdDebug(399) << "Loading TGA file!" << endl;
319 
320  TQDataStream s( io->ioDevice() );
321  s.setByteOrder( TQDataStream::LittleEndian );
322 
323 
324  // Read image header.
325  TgaHeader tga;
326  s >> tga;
327  s.device()->at( TgaHeader::SIZE + tga.id_length );
328 
329  // Check image file format.
330  if( s.atEnd() ) {
331  kdDebug(399) << "This TGA file is not valid." << endl;
332  io->setImage( TQImage() );
333  io->setStatus( -1 );
334  return;
335  }
336 
337  // Check supported file types.
338  if( !IsSupported(tga) ) {
339  kdDebug(399) << "This TGA file is not supported." << endl;
340  io->setImage( TQImage() );
341  io->setStatus( -1 );
342  return;
343  }
344 
345 
346  TQImage img;
347  bool result = LoadTGA(s, tga, img);
348 
349  if( result == false ) {
350  kdDebug(399) << "Error loading TGA file." << endl;
351  io->setImage( TQImage() );
352  io->setStatus( -1 );
353  return;
354  }
355 
356 
357  io->setImage( img );
358  io->setStatus( 0 );
359 }
360 
361 
362 KDE_EXPORT void kimgio_tga_write( TQImageIO *io )
363 {
364  TQDataStream s( io->ioDevice() );
365  s.setByteOrder( TQDataStream::LittleEndian );
366 
367  const TQImage img = io->image();
368  const bool hasAlpha = img.hasAlphaBuffer();
369  for( int i = 0; i < 12; i++ )
370  s << targaMagic[i];
371 
372  // write header
373  s << TQ_UINT16( img.width() ); // width
374  s << TQ_UINT16( img.height() ); // height
375  s << TQ_UINT8( hasAlpha ? 32 : 24 ); // depth (24 bit RGB + 8 bit alpha)
376  s << TQ_UINT8( hasAlpha ? 0x24 : 0x20 ); // top left image (0x20) + 8 bit alpha (0x4)
377 
378  for( int y = 0; y < img.height(); y++ )
379  for( int x = 0; x < img.width(); x++ ) {
380  const QRgb color = img.pixel( x, y );
381  s << TQ_UINT8( tqBlue( color ) );
382  s << TQ_UINT8( tqGreen( color ) );
383  s << TQ_UINT8( tqRed( color ) );
384  if( hasAlpha )
385  s << TQ_UINT8( tqAlpha( color ) );
386  }
387 
388  io->setStatus( 0 );
389 }
390 

kimgio

Skip menu "kimgio"
  • Main Page
  • File List
  • Related Pages

kimgio

Skip menu "kimgio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kimgio by doxygen 1.8.8
This website is maintained by Timothy Pearson.