• 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
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
30typedef TQ_UINT32 uint;
31typedef TQ_UINT16 ushort;
32typedef TQ_UINT8 uchar;
33
34namespace { // 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 TQRgb * scanline = (TQRgb *) 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
316TDE_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
362TDE_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 TQRgb 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
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kimgio by doxygen 1.9.4
This website is maintained by Timothy Pearson.