25 #include <QtGui/QImage>
26 #include <QtCore/QDataStream>
37 uchar targaMagic[12] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
43 TGA_TYPE_RLE_INDEXED = 9,
44 TGA_TYPE_RLE_RGB = 10,
45 TGA_TYPE_RLE_GREY = 11
48 #define TGA_INTERLEAVE_MASK 0xc0
49 #define TGA_INTERLEAVE_NONE 0x00
50 #define TGA_INTERLEAVE_2WAY 0x40
51 #define TGA_INTERLEAVE_4WAY 0x80
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
77 static QDataStream &
operator>> ( QDataStream & s, TgaHeader & head )
80 s >> head.colormap_type;
82 s >> head.colormap_index;
83 s >> head.colormap_length;
84 s >> head.colormap_size;
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 )
108 if( head.image_type == TGA_TYPE_INDEXED ||
109 head.image_type == TGA_TYPE_RLE_INDEXED )
111 if( head.colormap_length > 256 || head.colormap_size != 24 || head.colormap_type != 1 )
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 )
121 if( head.colormap_type != 0 )
126 if( head.width == 0 || head.height == 0 )
130 if( head.pixel_size != 8 && head.pixel_size != 16 &&
131 head.pixel_size != 24 && head.pixel_size != 32 )
144 struct TgaHeaderInfo {
150 TgaHeaderInfo(
const TgaHeader & tga ) : rle(false), pal(false), rgb(false), grey(false)
152 switch( tga.image_type ) {
153 case TGA_TYPE_RLE_INDEXED:
156 case TGA_TYPE_INDEXED:
160 case TGA_TYPE_RLE_RGB:
167 case TGA_TYPE_RLE_GREY:
183 static bool LoadTGA( QDataStream & s,
const TgaHeader & tga, QImage &img )
186 img = QImage( tga.width, tga.height, QImage::Format_RGB32 );
188 TgaHeaderInfo info(tga);
191 const int numAlphaBits = tga.flags & 0xf;
193 if( ( tga.pixel_size == 32 ) && ( tga.flags & 0xf ) ) {
194 img = QImage( tga.width, tga.height, QImage::Format_ARGB32 );
197 uint pixel_size = (tga.pixel_size/8);
198 uint size = tga.width * tga.height * pixel_size;
202 kDebug(399) <<
"This TGA file is broken with size " << size;
210 s.readRawData( palette, 3 * tga.colormap_length );
218 char * dst = (
char *)image;
226 uint count = (c & 0x7f) + 1;
227 num -= count * pixel_size;
231 assert(pixel_size <= 8);
233 s.readRawData( pixel, pixel_size );
235 memcpy(dst, pixel, pixel_size);
242 s.readRawData( dst, count );
249 s.readRawData( (
char *)image, size );
253 int y_start, y_step, y_end;
260 y_start = tga.height - 1;
267 for(
int y = y_start; y != y_end; y += y_step ) {
268 QRgb * scanline = (QRgb *) img.scanLine( y );
272 for(
int x = 0; x < tga.width; x++ ) {
274 scanline[x] = qRgb( palette[3*idx+2], palette[3*idx+1], palette[3*idx+0] );
277 else if( info.grey ) {
279 for(
int x = 0; x < tga.width; x++ ) {
280 scanline[x] = qRgb( *src, *src, *src );
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) );
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] );
299 else if( tga.pixel_size == 32 ) {
300 for(
int x = 0; x < tga.width; x++ ) {
302 const uchar alpha = ( src[3] << ( 8 - numAlphaBits ) );
303 scanline[x] =
qRgba( src[2], src[1], src[0], alpha );
336 QDataStream s( device() );
337 s.setByteOrder( QDataStream::LittleEndian );
343 s.device()->seek( TgaHeader::SIZE + tga.id_length );
347 kDebug(399) <<
"This TGA file is not valid.";
353 kDebug(399) <<
"This TGA file is not supported.";
359 bool result = LoadTGA(s, tga, img);
361 if( result ==
false ) {
362 kDebug(399) <<
"Error loading TGA file.";
373 QDataStream s( device() );
374 s.setByteOrder( QDataStream::LittleEndian );
376 const QImage& img = image;
377 const bool hasAlpha = (img.format() == QImage::Format_ARGB32);
378 for(
int i = 0; i < 12; i++ )
382 s << quint16( img.width() );
383 s << quint16( img.height() );
384 s << quint8( hasAlpha ? 32 : 24 );
385 s << quint8( hasAlpha ? 0x24 : 0x20 );
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 ) );
394 s << quint8( qAlpha( color ) );
408 qWarning(
"TGAHandler::canRead() called with no device");
412 qint64 oldPos = device->pos();
413 QByteArray head = device->read(TgaHeader::SIZE);
414 int readBytes = head.size();
416 if (device->isSequential()) {
417 for (
int pos = readBytes - 1; pos >= 0; --pos) {
418 device->ungetChar(head[pos]);
421 device->seek(oldPos);
424 if (readBytes < TgaHeader::SIZE) {
428 QDataStream stream(head);
429 stream.setByteOrder(QDataStream::LittleEndian);
436 class TGAPlugin :
public QImageIOPlugin
439 QStringList keys()
const;
440 Capabilities capabilities(QIODevice *device,
const QByteArray &format)
const;
441 QImageIOHandler *create(QIODevice *device,
const QByteArray &format = QByteArray())
const;
444 QStringList TGAPlugin::keys()
const
446 return QStringList() <<
"tga" <<
"TGA";
449 QImageIOPlugin::Capabilities TGAPlugin::capabilities(QIODevice *device,
const QByteArray &format)
const
451 if (format ==
"tga" || format ==
"TGA")
452 return Capabilities(CanRead | CanWrite);
453 if (!format.isEmpty())
455 if (!device->isOpen())
461 if (device->isWritable())
466 QImageIOHandler *TGAPlugin::create(QIODevice *device,
const QByteArray &format)
const
469 handler->setDevice(device);
470 handler->setFormat(format);
474 Q_EXPORT_STATIC_PLUGIN(TGAPlugin)
475 Q_EXPORT_PLUGIN2(tga, TGAPlugin)
bool hasAlpha(PICChannel *channels)
static QDataStream & operator>>(QDataStream &s, DDSPixelFormat &pf)
static bool IsSupported(const DDSHeader &header)
QRgb qRgba(const QRgb &rgb, int a)
Change a QRgb value's alpha only.
bool write(const QImage &image)