1// Aseprite TGA Library
2// Copyright (C) 2020-2022 Igara Studio S.A.
3//
4// This file is released under the terms of the MIT license.
5// Read LICENSE.txt for more information.
6
7#include "tga.h"
8
9#include <cassert>
10
11namespace tga {
12
13static inline uint8_t scale_5bits_to_8bits(uint8_t v) {
14 assert(v >= 0 && v < 32);
15 return (v << 3) | (v >> 2);
16}
17
18Decoder::Decoder(FileInterface* file)
19 : m_file(file)
20{
21}
22
23bool Decoder::readHeader(Header& header)
24{
25 header.idLength = read8();
26 header.colormapType = read8();
27 header.imageType = read8();
28 header.colormapOrigin = read16();
29 header.colormapLength = read16();
30 header.colormapDepth = read8();
31 header.xOrigin = read16();
32 header.yOrigin = read16();
33 header.width = read16();
34 header.height = read16();
35 header.bitsPerPixel = read8();
36 header.imageDescriptor = read8();
37
38 // Invalid image size
39 if (header.width == 0 ||
40 header.height == 0)
41 return false;
42
43 // Skip ID string (idLength bytes)
44 if (header.idLength > 0) {
45 uint8_t i = header.idLength;
46 while (i--) {
47 uint8_t chr = m_file->read8();
48 header.imageId.push_back(chr);
49 }
50 }
51
52#if 0
53 // In the best case the "alphaBits" should be valid, but there are
54 // invalid TGA files out there which don't indicate the
55 // "alphaBits" correctly, so they could be 0 and use the alpha
56 // channel anyway on each pixel.
57 int alphaBits = (header.imageDescriptor & 15);
58 m_hasAlpha =
59 (header.bitsPerPixel == 32 && alphaBits == 8) ||
60 (header.bitsPerPixel == 16 && alphaBits == 1);
61#else
62 // So to detect if a 32bpp or 16bpp TGA image has alpha, we'll use
63 // the "alpha histogram" in postProcessImage() to check if there are
64 // different alpha values. If there is only one alpha value (all 0
65 // or all 255), we create an opaque image anyway. The only exception
66 // to this rule is when all pixels are black and transparent
67 // (RGBA=0), that is the only case when an image is fully
68 // transparent.
69 //
70 // Note: This same heuristic is used in apps like macOS Preview:
71 // https://twitter.com/davidcapello/status/1242803110868893697
72 m_hasAlpha =
73 (header.bitsPerPixel == 32) ||
74 (header.bitsPerPixel == 16);
75#endif
76
77 // Read colormap
78 if (header.colormapType == 1)
79 readColormap(header);
80
81 return (header.validColormapType() &&
82 header.valid());
83}
84
85void Decoder::readColormap(Header& header)
86{
87 header.colormap = Colormap(header.colormapLength);
88
89 for (int i=0; i<header.colormapLength; ++i) {
90 switch (header.colormapDepth) {
91
92 case 15:
93 case 16: {
94 const uint16_t c = read16();
95 header.colormap[i] =
96 rgba(scale_5bits_to_8bits((c >> 10) & 0x1F),
97 scale_5bits_to_8bits((c >> 5) & 0x1F),
98 scale_5bits_to_8bits(c & 0x1F));
99 break;
100 }
101
102 case 24:
103 case 32: {
104 const uint8_t b = read8();
105 const uint8_t g = read8();
106 const uint8_t r = read8();
107 uint8_t a;
108 if (header.colormapDepth == 32)
109 a = read8();
110 else
111 a = 255;
112 header.colormap[i] = rgba(r, g, b, a);
113 break;
114 }
115 }
116 }
117}
118
119bool Decoder::readImage(const Header& header,
120 Image& image,
121 Delegate* delegate)
122{
123 // Bit 4 means right-to-left, else left-to-right
124 // Bit 5 means top-to-bottom, else bottom-to-top
125 m_iterator = details::ImageIterator(header, image);
126
127 for (int y=0; y<header.height; ++y) {
128 switch (header.imageType) {
129
130 case UncompressedIndexed:
131 assert(header.bitsPerPixel == 8);
132 if (readUncompressedData<uint8_t>(header.width, &Decoder::read8Color))
133 return true;
134 break;
135
136 case UncompressedRgb:
137 switch (header.bitsPerPixel) {
138 case 15:
139 case 16:
140 if (readUncompressedData<uint32_t>(header.width, &Decoder::read16AsRgb))
141 return true;
142 break;
143 case 24:
144 if (readUncompressedData<uint32_t>(header.width, &Decoder::read24AsRgb))
145 return true;
146 break;
147 case 32:
148 if (readUncompressedData<uint32_t>(header.width, &Decoder::read32AsRgb))
149 return true;
150 break;
151 default:
152 assert(false);
153 break;
154 }
155 break;
156
157 case UncompressedGray:
158 assert(header.bitsPerPixel == 8);
159 if (readUncompressedData<uint8_t>(header.width, &Decoder::read8Color))
160 return true;
161 break;
162
163 case RleIndexed:
164 assert(header.bitsPerPixel == 8);
165 if (readRleData<uint8_t>(header.width, &Decoder::read8Color))
166 return true;
167 break;
168
169 case RleRgb:
170 switch (header.bitsPerPixel) {
171 case 15:
172 case 16:
173 if (readRleData<uint32_t>(header.width, &Decoder::read16AsRgb))
174 return true;
175 break;
176 case 24:
177 if (readRleData<uint32_t>(header.width, &Decoder::read24AsRgb))
178 return true;
179 break;
180 case 32:
181 if (readRleData<uint32_t>(header.width, &Decoder::read32AsRgb))
182 return true;
183 break;
184 default:
185 assert(false);
186 break;
187 }
188 break;
189
190 case RleGray:
191 assert(header.bitsPerPixel == 8);
192 if (readRleData<uint8_t>(header.width, &Decoder::read8Color))
193 return true;
194 break;
195 }
196
197 if (delegate &&
198 !delegate->notifyProgress(float(y) / float(header.height))) {
199 break;
200 }
201 }
202
203 return true;
204}
205
206void Decoder::postProcessImage(const Header& header,
207 Image& image)
208{
209 // The post-processing is only for RGB images with possible invalid
210 // alpha information.
211 if (!header.isRgb() || !m_hasAlpha)
212 return;
213
214 bool transparentImage = true;
215 bool blackImage = true;
216
217 for (int y=0; y<header.height; ++y) {
218 auto p = (uint32_t*)(image.pixels + y*image.rowstride);
219 for (int x=0; x<header.width; ++x, ++p) {
220 color_t c = *p;
221 if (transparentImage &&
222 geta(c) != 0) {
223 transparentImage = false;
224 }
225 if (blackImage &&
226 (getr(c) != 0 ||
227 getg(c) != 0 ||
228 getb(c) != 0)) {
229 blackImage = false;
230 }
231 }
232 }
233
234 // If the image is fully transparent (all pixels with alpha=0) and
235 // there are pixels with RGB != 0 (!blackImage), we have to make the
236 // image completely opaque (alpha=255).
237 if (transparentImage && !blackImage) {
238 for (int y=0; y<header.height; ++y) {
239 auto p = (uint32_t*)(image.pixels + y*image.rowstride);
240 for (int x=0; x<header.width; ++x, ++p) {
241 color_t c = *p;
242 *p = rgba(getr(c),
243 getg(c),
244 getb(c), 255);
245 }
246 }
247 }
248}
249
250template<typename T>
251bool Decoder::readUncompressedData(const int w, color_t (Decoder::*readPixel)())
252{
253 for (int x=0; x<w && m_file->ok(); ++x) {
254 if (m_iterator.putPixel<T>(static_cast<T>((this->*readPixel)())))
255 return true;
256 }
257 return false;
258}
259
260// In the best case (TGA 2.0 spec) this should read just one
261// scanline, but in old TGA versions (1.0) it was possible to save
262// several scanlines with the same RLE data.
263//
264// Returns true when are are done.
265template<typename T>
266bool Decoder::readRleData(const int w, color_t (Decoder::*readPixel)())
267{
268 for (int x=0; x<w && m_file->ok(); ) {
269 int c = read8();
270 if (c & 0x80) {
271 c = (c & 0x7f) + 1;
272 x += c;
273 const T pixel = static_cast<T>((this->*readPixel)());
274 while (c-- > 0)
275 if (m_iterator.putPixel<T>(pixel))
276 return true;
277 }
278 else {
279 ++c;
280 x += c;
281 while (c-- > 0) {
282 if (m_iterator.putPixel<T>(static_cast<T>((this->*readPixel)())))
283 return true;
284 }
285 }
286 }
287 return false;
288}
289
290uint8_t Decoder::read8()
291{
292 return m_file->read8();
293}
294
295// Reads a WORD (16 bits) using in little-endian byte ordering.
296uint16_t Decoder::read16()
297{
298 uint8_t b1 = m_file->read8();
299 uint8_t b2 = m_file->read8();
300
301 if (m_file->ok()) {
302 return ((b2 << 8) | b1); // Little endian
303 }
304 else
305 return 0;
306}
307
308// Reads a DWORD (32 bits) using in little-endian byte ordering.
309uint32_t Decoder::read32()
310{
311 const uint8_t b1 = m_file->read8();
312 const uint8_t b2 = m_file->read8();
313 const uint8_t b3 = m_file->read8();
314 const uint8_t b4 = m_file->read8();
315
316 if (m_file->ok()) {
317 // Little endian
318 return ((b4 << 24) | (b3 << 16) | (b2 << 8) | b1);
319 }
320 else
321 return 0;
322}
323
324color_t Decoder::read32AsRgb()
325{
326 const uint8_t b = read8();
327 const uint8_t g = read8();
328 const uint8_t r = read8();
329 uint8_t a = read8();
330 if (!m_hasAlpha)
331 a = 255;
332 return rgba(r, g, b, a);
333}
334
335color_t Decoder::read24AsRgb()
336{
337 const uint8_t b = read8();
338 const uint8_t g = read8();
339 const uint8_t r = read8();
340 return rgba(r, g, b, 255);
341}
342
343color_t Decoder::read16AsRgb()
344{
345 const uint16_t v = read16();
346 uint8_t a = 255;
347 if (m_hasAlpha) {
348 if ((v & 0x8000) == 0) // Transparent bit
349 a = 0;
350 }
351 return rgba(scale_5bits_to_8bits((v >> 10) & 0x1F),
352 scale_5bits_to_8bits((v >> 5) & 0x1F),
353 scale_5bits_to_8bits(v & 0x1F),
354 a);
355}
356
357} // namespace tga
358