• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KImgIO

  • sources
  • kde-4.14
  • kdelibs
  • kimgio
tga.cpp
Go to the documentation of this file.
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 <QtGui/QImage>
26 #include <QtCore/QDataStream>
27 
28 #include <kdebug.h>
29 
30 typedef quint32 uint;
31 typedef quint16 ushort;
32 typedef quint8 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 QDataStream & operator>> ( QDataStream & 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  /*qDebug() << "id_length: " << head.id_length << " - colormap_type: " << head.colormap_type << " - image_type: " << head.image_type;
92  qDebug() << "colormap_index: " << head.colormap_index << " - colormap_length: " << head.colormap_length << " - colormap_size: " << head.colormap_size;
93  qDebug() << "x_origin: " << head.x_origin << " - y_origin: " << head.y_origin << " - width:" << head.width << " - height:" << head.height << " - pixelsize: " << head.pixel_size << " - flags: " << head.flags;*/
94  return s;
95  }
96 
97  static bool IsSupported( const TgaHeader & head )
98  {
99  if( head.image_type != TGA_TYPE_INDEXED &&
100  head.image_type != TGA_TYPE_RGB &&
101  head.image_type != TGA_TYPE_GREY &&
102  head.image_type != TGA_TYPE_RLE_INDEXED &&
103  head.image_type != TGA_TYPE_RLE_RGB &&
104  head.image_type != TGA_TYPE_RLE_GREY )
105  {
106  return false;
107  }
108  if( head.image_type == TGA_TYPE_INDEXED ||
109  head.image_type == TGA_TYPE_RLE_INDEXED )
110  {
111  if( head.colormap_length > 256 || head.colormap_size != 24 || head.colormap_type != 1 )
112  {
113  return false;
114  }
115  }
116  if( head.image_type == TGA_TYPE_RGB ||
117  head.image_type == TGA_TYPE_GREY ||
118  head.image_type == TGA_TYPE_RLE_RGB ||
119  head.image_type == TGA_TYPE_RLE_GREY )
120  {
121  if( head.colormap_type != 0 )
122  {
123  return false;
124  }
125  }
126  if( head.width == 0 || head.height == 0 )
127  {
128  return false;
129  }
130  if( head.pixel_size != 8 && head.pixel_size != 16 &&
131  head.pixel_size != 24 && head.pixel_size != 32 )
132  {
133  return false;
134  }
135  return true;
136  }
137 
138  struct Color555 {
139  ushort b : 5;
140  ushort g : 5;
141  ushort r : 5;
142  };
143 
144  struct TgaHeaderInfo {
145  bool rle;
146  bool pal;
147  bool rgb;
148  bool grey;
149 
150  TgaHeaderInfo( const TgaHeader & tga ) : rle(false), pal(false), rgb(false), grey(false)
151  {
152  switch( tga.image_type ) {
153  case TGA_TYPE_RLE_INDEXED:
154  rle = true;
155  // no break is intended!
156  case TGA_TYPE_INDEXED:
157  pal = true;
158  break;
159 
160  case TGA_TYPE_RLE_RGB:
161  rle = true;
162  // no break is intended!
163  case TGA_TYPE_RGB:
164  rgb = true;
165  break;
166 
167  case TGA_TYPE_RLE_GREY:
168  rle = true;
169  // no break is intended!
170  case TGA_TYPE_GREY:
171  grey = true;
172  break;
173 
174  default:
175  // Error, unknown image type.
176  break;
177  }
178  }
179  };
180 
181 
182 
183  static bool LoadTGA( QDataStream & s, const TgaHeader & tga, QImage &img )
184  {
185  // Create image.
186  img = QImage( tga.width, tga.height, QImage::Format_RGB32 );
187 
188  TgaHeaderInfo info(tga);
189 
190  // Bits 0-3 are the numbers of alpha bits (can be zero!)
191  const int numAlphaBits = tga.flags & 0xf;
192  // However alpha exists only in the 32 bit format.
193  if( ( tga.pixel_size == 32 ) && ( tga.flags & 0xf ) ) {
194  img = QImage( tga.width, tga.height, QImage::Format_ARGB32 );
195  }
196 
197  uint pixel_size = (tga.pixel_size/8);
198  uint size = tga.width * tga.height * pixel_size;
199 
200  if (size < 1)
201  {
202  kDebug(399) << "This TGA file is broken with size " << size;
203  return false;
204  }
205 
206  // Read palette.
207  char palette[768];
208  if( info.pal ) {
209  // @todo Support palettes in other formats!
210  s.readRawData( palette, 3 * tga.colormap_length );
211  }
212 
213  // Allocate image.
214  uchar * const image = new uchar[size];
215 
216  if( info.rle ) {
217  // Decode image.
218  char * dst = (char *)image;
219  int num = size;
220 
221  while (num > 0) {
222  // Get packet header.
223  uchar c;
224  s >> c;
225 
226  uint count = (c & 0x7f) + 1;
227  num -= count * pixel_size;
228 
229  if (c & 0x80) {
230  // RLE pixels.
231  assert(pixel_size <= 8);
232  char pixel[8];
233  s.readRawData( pixel, pixel_size );
234  do {
235  memcpy(dst, pixel, pixel_size);
236  dst += pixel_size;
237  } while (--count);
238  }
239  else {
240  // Raw pixels.
241  count *= pixel_size;
242  s.readRawData( dst, count );
243  dst += count;
244  }
245  }
246  }
247  else {
248  // Read raw image.
249  s.readRawData( (char *)image, size );
250  }
251 
252  // Convert image to internal format.
253  int y_start, y_step, y_end;
254  if( tga.flags & TGA_ORIGIN_UPPER ) {
255  y_start = 0;
256  y_step = 1;
257  y_end = tga.height;
258  }
259  else {
260  y_start = tga.height - 1;
261  y_step = -1;
262  y_end = -1;
263  }
264 
265  uchar * src = image;
266 
267  for( int y = y_start; y != y_end; y += y_step ) {
268  QRgb * scanline = (QRgb *) img.scanLine( y );
269 
270  if( info.pal ) {
271  // Paletted.
272  for( int x = 0; x < tga.width; x++ ) {
273  uchar idx = *src++;
274  scanline[x] = qRgb( palette[3*idx+2], palette[3*idx+1], palette[3*idx+0] );
275  }
276  }
277  else if( info.grey ) {
278  // Greyscale.
279  for( int x = 0; x < tga.width; x++ ) {
280  scanline[x] = qRgb( *src, *src, *src );
281  src++;
282  }
283  }
284  else {
285  // True Color.
286  if( tga.pixel_size == 16 ) {
287  for( int x = 0; x < tga.width; x++ ) {
288  Color555 c = *reinterpret_cast<Color555 *>(src);
289  scanline[x] = qRgb( (c.r << 3) | (c.r >> 2), (c.g << 3) | (c.g >> 2), (c.b << 3) | (c.b >> 2) );
290  src += 2;
291  }
292  }
293  else if( tga.pixel_size == 24 ) {
294  for( int x = 0; x < tga.width; x++ ) {
295  scanline[x] = qRgb( src[2], src[1], src[0] );
296  src += 3;
297  }
298  }
299  else if( tga.pixel_size == 32 ) {
300  for( int x = 0; x < tga.width; x++ ) {
301  // ### TODO: verify with images having really some alpha data
302  const uchar alpha = ( src[3] << ( 8 - numAlphaBits ) );
303  scanline[x] = qRgba( src[2], src[1], src[0], alpha );
304  src += 4;
305  }
306  }
307  }
308  }
309 
310  // Free image.
311  delete [] image;
312 
313  return true;
314  }
315 
316 } // namespace
317 
318 
319 TGAHandler::TGAHandler()
320 {
321 }
322 
323 bool TGAHandler::canRead() const
324 {
325  if (canRead(device())) {
326  setFormat("tga");
327  return true;
328  }
329  return false;
330 }
331 
332 bool TGAHandler::read(QImage *outImage)
333 {
334  //kDebug(399) << "Loading TGA file!";
335 
336  QDataStream s( device() );
337  s.setByteOrder( QDataStream::LittleEndian );
338 
339 
340  // Read image header.
341  TgaHeader tga;
342  s >> tga;
343  s.device()->seek( TgaHeader::SIZE + tga.id_length );
344 
345  // Check image file format.
346  if( s.atEnd() ) {
347  kDebug(399) << "This TGA file is not valid.";
348  return false;
349  }
350 
351  // Check supported file types.
352  if( !IsSupported(tga) ) {
353  kDebug(399) << "This TGA file is not supported.";
354  return false;
355  }
356 
357 
358  QImage img;
359  bool result = LoadTGA(s, tga, img);
360 
361  if( result == false ) {
362  kDebug(399) << "Error loading TGA file.";
363  return false;
364  }
365 
366 
367  *outImage = img;
368  return true;
369 }
370 
371 bool TGAHandler::write(const QImage &image)
372 {
373  QDataStream s( device() );
374  s.setByteOrder( QDataStream::LittleEndian );
375 
376  const QImage& img = image;
377  const bool hasAlpha = (img.format() == QImage::Format_ARGB32);
378  for( int i = 0; i < 12; i++ )
379  s << targaMagic[i];
380 
381  // write header
382  s << quint16( img.width() ); // width
383  s << quint16( img.height() ); // height
384  s << quint8( hasAlpha ? 32 : 24 ); // depth (24 bit RGB + 8 bit alpha)
385  s << quint8( hasAlpha ? 0x24 : 0x20 ); // top left image (0x20) + 8 bit alpha (0x4)
386 
387  for( int y = 0; y < img.height(); y++ )
388  for( int x = 0; x < img.width(); x++ ) {
389  const QRgb color = img.pixel( x, y );
390  s << quint8( qBlue( color ) );
391  s << quint8( qGreen( color ) );
392  s << quint8( qRed( color ) );
393  if( hasAlpha )
394  s << quint8( qAlpha( color ) );
395  }
396 
397  return true;
398 }
399 
400 QByteArray TGAHandler::name() const
401 {
402  return "tga";
403 }
404 
405 bool TGAHandler::canRead(QIODevice *device)
406 {
407  if (!device) {
408  qWarning("TGAHandler::canRead() called with no device");
409  return false;
410  }
411 
412  qint64 oldPos = device->pos();
413  QByteArray head = device->read(TgaHeader::SIZE);
414  int readBytes = head.size();
415 
416  if (device->isSequential()) {
417  for (int pos = readBytes - 1; pos >= 0; --pos) {
418  device->ungetChar(head[pos]);
419  }
420  } else {
421  device->seek(oldPos);
422  }
423 
424  if (readBytes < TgaHeader::SIZE) {
425  return false;
426  }
427 
428  QDataStream stream(head);
429  stream.setByteOrder(QDataStream::LittleEndian);
430  TgaHeader tga;
431  stream >> tga;
432  return IsSupported(tga);
433 }
434 
435 
436 class TGAPlugin : public QImageIOPlugin
437 {
438 public:
439  QStringList keys() const;
440  Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
441  QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
442 };
443 
444 QStringList TGAPlugin::keys() const
445 {
446  return QStringList() << "tga" << "TGA";
447 }
448 
449 QImageIOPlugin::Capabilities TGAPlugin::capabilities(QIODevice *device, const QByteArray &format) const
450 {
451  if (format == "tga" || format == "TGA")
452  return Capabilities(CanRead | CanWrite);
453  if (!format.isEmpty())
454  return 0;
455  if (!device->isOpen())
456  return 0;
457 
458  Capabilities cap;
459  if (device->isReadable() && TGAHandler::canRead(device))
460  cap |= CanRead;
461  if (device->isWritable())
462  cap |= CanWrite;
463  return cap;
464 }
465 
466 QImageIOHandler *TGAPlugin::create(QIODevice *device, const QByteArray &format) const
467 {
468  QImageIOHandler *handler = new TGAHandler;
469  handler->setDevice(device);
470  handler->setFormat(format);
471  return handler;
472 }
473 
474 Q_EXPORT_STATIC_PLUGIN(TGAPlugin)
475 Q_EXPORT_PLUGIN2(tga, TGAPlugin)
QIODevice
QImage::scanLine
uchar * scanLine(int i)
QImageIOPlugin::Capabilities
typedef Capabilities
QIODevice::isWritable
bool isWritable() const
QImageIOPlugin::create
virtual QImageIOHandler * create(QIODevice *device, const QByteArray &format) const =0
QImageIOHandler::device
QIODevice * device() const
QIODevice::seek
virtual bool seek(qint64 pos)
QByteArray
uint
quint32 uint
Definition: tga.cpp:30
QDataStream
ushort
quint16 ushort
Definition: dds.cpp:37
QByteArray::isEmpty
bool isEmpty() const
hasAlpha
bool hasAlpha(PICChannel *channels)
Definition: pic_read.cpp:250
TGAType
TGAType
Definition: tga.cpp:39
TGAHandler
Definition: tga.h:15
QIODevice::isReadable
bool isReadable() const
QIODevice::isSequential
virtual bool isSequential() const
QDataStream::readRawData
int readRawData(char *s, int len)
QIODevice::pos
virtual qint64 pos() const
QImage::pixel
QRgb pixel(int x, int y) const
operator>>
static QDataStream & operator>>(QDataStream &s, DDSPixelFormat &pf)
Definition: dds.cpp:144
QImage::width
int width() const
TGA_ORIGIN_UPPER
#define TGA_ORIGIN_UPPER
Definition: tga.cpp:57
ushort
quint16 ushort
Definition: tga.cpp:31
QImageIOHandler::setDevice
void setDevice(QIODevice *device)
TGAHandler::canRead
bool canRead() const
Definition: tga.cpp:323
QIODevice::read
qint64 read(char *data, qint64 maxSize)
QIODevice::isOpen
bool isOpen() const
QImageIOPlugin::capabilities
virtual Capabilities capabilities(QIODevice *device, const QByteArray &format) const =0
QDataStream::atEnd
bool atEnd() const
TGAHandler::name
QByteArray name() const
Definition: tga.cpp:400
QImageIOPlugin
QStringList
QImageIOHandler
uchar
quint8 uchar
Definition: tga.cpp:32
IsSupported
static bool IsSupported(const DDSHeader &header)
Definition: dds.cpp:276
uchar
quint8 uchar
Definition: dds.cpp:38
QImage
QDataStream::setByteOrder
void setByteOrder(ByteOrder bo)
tga.h
QImageIOPlugin::keys
virtual QStringList keys() const =0
TGAHandler::TGAHandler
TGAHandler()
Definition: tga.cpp:319
qRgba
QRgb qRgba(const QRgb &rgb, int a)
Change a QRgb value's alpha only.
Definition: xcf.cpp:67
QImageIOHandler::setFormat
void setFormat(const QByteArray &format)
QImage::height
int height() const
uint
quint32 uint
Definition: dds.cpp:36
QDataStream::device
QIODevice * device() const
TGAHandler::read
bool read(QImage *image)
Definition: tga.cpp:332
QByteArray::size
int size() const
QIODevice::ungetChar
void ungetChar(char c)
QImage::format
Format format() const
TGAHandler::write
bool write(const QImage &image)
Definition: tga.cpp:371
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:22:49 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KImgIO

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

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal