TGALoader.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. * Copyright (c) 2022, Tom Needham <06needhamt@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Span.h>
  7. #include <AK/StdLibExtraDetails.h>
  8. #include <AK/String.h>
  9. #include <LibGfx/ImageFormats/TGALoader.h>
  10. namespace Gfx {
  11. enum TGADataType : u8 {
  12. None = 0,
  13. UncompressedColorMapped = 1,
  14. UncompressedRGB = 2,
  15. UncompressedBlackAndWhite = 3,
  16. RunLengthEncodedColorMapped = 9,
  17. RunLengthEncodedRGB = 10,
  18. CompressedBlackAndWhite = 11,
  19. CompressedColorMapped = 32,
  20. CompressedColorMappedFourPass = 33
  21. };
  22. struct [[gnu::packed]] TGAHeader {
  23. u8 id_length;
  24. u8 color_map_type;
  25. TGADataType data_type_code;
  26. i16 color_map_origin;
  27. i16 color_map_length;
  28. u8 color_map_depth;
  29. i16 x_origin;
  30. i16 y_origin;
  31. u16 width;
  32. u16 height;
  33. u8 bits_per_pixel;
  34. u8 image_descriptor;
  35. };
  36. static_assert(sizeof(TGAHeader) == 18);
  37. union [[gnu::packed]] TGAPixel {
  38. struct TGAColor {
  39. u8 blue;
  40. u8 green;
  41. u8 red;
  42. u8 alpha;
  43. } components;
  44. u32 data;
  45. };
  46. struct TGAPixelPacket {
  47. bool raw;
  48. u8 pixels_count;
  49. };
  50. static_assert(AssertSize<TGAPixel, 4>());
  51. class TGAReader {
  52. public:
  53. TGAReader(ReadonlyBytes data)
  54. : m_data(move(data))
  55. {
  56. }
  57. TGAReader(ReadonlyBytes data, size_t index)
  58. : m_data(move(data))
  59. , m_index(index)
  60. {
  61. }
  62. ALWAYS_INLINE u8 read_u8()
  63. {
  64. u8 value = m_data[m_index];
  65. m_index++;
  66. return value;
  67. }
  68. ALWAYS_INLINE i8 read_i8()
  69. {
  70. return static_cast<i8>(read_u8());
  71. }
  72. ALWAYS_INLINE u16 read_u16()
  73. {
  74. return read_u8() | read_u8() << 8;
  75. }
  76. ALWAYS_INLINE i16 read_i16()
  77. {
  78. return read_i8() | read_i8() << 8;
  79. }
  80. ALWAYS_INLINE u32 read_u32()
  81. {
  82. return read_u16() | read_u16() << 16;
  83. }
  84. ALWAYS_INLINE i32 read_i32()
  85. {
  86. return read_i16() | read_i16() << 16;
  87. }
  88. ALWAYS_INLINE TGAPixelPacket read_packet_type()
  89. {
  90. auto pixel_packet_type = read_u8();
  91. auto pixel_packet = TGAPixelPacket();
  92. pixel_packet.raw = !(pixel_packet_type & 0x80);
  93. pixel_packet.pixels_count = (pixel_packet_type & 0x7f);
  94. // NOTE: Run-length-encoded/Raw pixel packets cannot encode zero pixels,
  95. // so value 0 stands for 1 pixel, 1 stands for 2, etc...
  96. pixel_packet.pixels_count++;
  97. return pixel_packet;
  98. }
  99. ALWAYS_INLINE TGAPixel read_pixel(u8 bits_per_pixel)
  100. {
  101. auto pixel = TGAPixel();
  102. switch (bits_per_pixel) {
  103. case 24:
  104. pixel.components.blue = read_u8();
  105. pixel.components.green = read_u8();
  106. pixel.components.red = read_u8();
  107. pixel.components.alpha = 0xFF;
  108. return pixel;
  109. case 32:
  110. pixel.components.blue = read_u8();
  111. pixel.components.green = read_u8();
  112. pixel.components.red = read_u8();
  113. pixel.components.alpha = read_u8();
  114. return pixel;
  115. default:
  116. VERIFY_NOT_REACHED();
  117. }
  118. }
  119. size_t index() const
  120. {
  121. return m_index;
  122. }
  123. ReadonlyBytes data() const
  124. {
  125. return m_data;
  126. }
  127. private:
  128. ReadonlyBytes m_data;
  129. size_t m_index { 0 };
  130. };
  131. struct TGALoadingContext {
  132. TGAHeader header;
  133. OwnPtr<TGAReader> reader = { nullptr };
  134. RefPtr<Gfx::Bitmap> bitmap;
  135. };
  136. TGAImageDecoderPlugin::TGAImageDecoderPlugin(u8 const* file_data, size_t file_size)
  137. {
  138. m_context = make<TGALoadingContext>();
  139. m_context->reader = make<TGAReader>(ReadonlyBytes { file_data, file_size });
  140. }
  141. TGAImageDecoderPlugin::~TGAImageDecoderPlugin() = default;
  142. IntSize TGAImageDecoderPlugin::size()
  143. {
  144. return IntSize { m_context->header.width, m_context->header.height };
  145. }
  146. void TGAImageDecoderPlugin::set_volatile()
  147. {
  148. if (m_context->bitmap)
  149. m_context->bitmap->set_volatile();
  150. }
  151. bool TGAImageDecoderPlugin::set_nonvolatile(bool& was_purged)
  152. {
  153. if (!m_context->bitmap)
  154. return false;
  155. return m_context->bitmap->set_nonvolatile(was_purged);
  156. }
  157. bool TGAImageDecoderPlugin::decode_tga_header()
  158. {
  159. auto& reader = m_context->reader;
  160. if (reader->data().size() < sizeof(TGAHeader))
  161. return false;
  162. m_context->header = TGAHeader();
  163. m_context->header.id_length = reader->read_u8();
  164. m_context->header.color_map_type = reader->read_u8();
  165. m_context->header.data_type_code = static_cast<TGADataType>(reader->read_u8());
  166. m_context->header.color_map_origin = reader->read_i16();
  167. m_context->header.color_map_length = reader->read_i16();
  168. m_context->header.color_map_depth = reader->read_u8();
  169. m_context->header.x_origin = reader->read_i16();
  170. m_context->header.y_origin = reader->read_i16();
  171. m_context->header.width = reader->read_u16();
  172. m_context->header.height = reader->read_u16();
  173. m_context->header.bits_per_pixel = reader->read_u8();
  174. m_context->header.image_descriptor = reader->read_u8();
  175. auto bytes_remaining = reader->data().size() - reader->index();
  176. // FIXME: Check for multiplication overflow!
  177. if (m_context->header.data_type_code == TGADataType::UncompressedRGB && bytes_remaining < static_cast<size_t>(m_context->header.width * m_context->header.height * (m_context->header.bits_per_pixel / 8)))
  178. return false;
  179. if (m_context->header.bits_per_pixel < 8 || m_context->header.bits_per_pixel > 32)
  180. return false;
  181. return true;
  182. }
  183. bool TGAImageDecoderPlugin::initialize()
  184. {
  185. return decode_tga_header();
  186. }
  187. ErrorOr<bool> TGAImageDecoderPlugin::validate_before_create(ReadonlyBytes data)
  188. {
  189. if (data.size() < sizeof(TGAHeader))
  190. return false;
  191. TGAHeader const& header = *reinterpret_cast<TGAHeader const*>(data.data());
  192. // FIXME: Check for multiplication overflow!
  193. if (header.data_type_code == TGADataType::UncompressedRGB && data.size() < static_cast<size_t>(header.width * header.height * (header.bits_per_pixel / 8)))
  194. return false;
  195. if (header.bits_per_pixel < 8 || header.bits_per_pixel > 32)
  196. return false;
  197. return true;
  198. }
  199. ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> TGAImageDecoderPlugin::create(ReadonlyBytes data)
  200. {
  201. return adopt_nonnull_own_or_enomem(new (nothrow) TGAImageDecoderPlugin(data.data(), data.size()));
  202. }
  203. bool TGAImageDecoderPlugin::is_animated()
  204. {
  205. return false;
  206. }
  207. size_t TGAImageDecoderPlugin::loop_count()
  208. {
  209. return 0;
  210. }
  211. size_t TGAImageDecoderPlugin::frame_count()
  212. {
  213. return 1;
  214. }
  215. size_t TGAImageDecoderPlugin::first_animated_frame_index()
  216. {
  217. return 0;
  218. }
  219. ErrorOr<ImageFrameDescriptor> TGAImageDecoderPlugin::frame(size_t index)
  220. {
  221. auto bits_per_pixel = m_context->header.bits_per_pixel;
  222. auto color_map = m_context->header.color_map_type;
  223. auto data_type = m_context->header.data_type_code;
  224. auto width = m_context->header.width;
  225. auto height = m_context->header.height;
  226. auto x_origin = m_context->header.x_origin;
  227. auto y_origin = m_context->header.y_origin;
  228. if (index != 0)
  229. return Error::from_string_literal("TGAImageDecoderPlugin: frame index must be 0");
  230. if (color_map > 1)
  231. return Error::from_string_literal("TGAImageDecoderPlugin: Invalid color map type");
  232. if (m_context->bitmap) {
  233. return ImageFrameDescriptor { m_context->bitmap, 0 };
  234. } else {
  235. // NOTE: Just to be on the safe side, if m_context->bitmap is nullptr, then
  236. // just re-construct the reader object. This will ensure that if the bitmap
  237. // was set as volatile and therefore it is gone, we can always re-generate it
  238. // with a new call to this method!
  239. VERIFY(m_context->reader);
  240. m_context->reader = make<TGAReader>(m_context->reader->data(), sizeof(TGAHeader));
  241. }
  242. RefPtr<Gfx::Bitmap> bitmap;
  243. switch (bits_per_pixel) {
  244. case 24:
  245. bitmap = TRY(Bitmap::create(BitmapFormat::BGRx8888, { m_context->header.width, m_context->header.height }));
  246. break;
  247. case 32:
  248. bitmap = TRY(Bitmap::create(BitmapFormat::BGRA8888, { m_context->header.width, m_context->header.height }));
  249. break;
  250. default:
  251. // FIXME: Implement other TGA bit depths
  252. return Error::from_string_literal("TGAImageDecoderPlugin: Can only handle 24 and 32 bits per pixel");
  253. }
  254. // FIXME: Try to understand the Image origin (instead of X and Y origin coordinates)
  255. // based on the Image descriptor, Field 5.6, bits 4 and 5.
  256. // NOTE: If Y origin is set to a negative number, just assume the generating software
  257. // meant that we start with Y origin at the top height of the picture.
  258. // At least this is the observed behavior when generating some pictures in GIMP.
  259. if (y_origin < 0)
  260. y_origin = height;
  261. if (y_origin != 0 && y_origin != height)
  262. return Error::from_string_literal("TGAImageDecoderPlugin: Can only handle Y origin which is 0 or the entire height");
  263. if (x_origin != 0 && x_origin != width)
  264. return Error::from_string_literal("TGAImageDecoderPlugin: Can only handle X origin which is 0 or the entire width");
  265. switch (data_type) {
  266. case TGADataType::UncompressedRGB: {
  267. for (int row = 0; row < height; ++row) {
  268. for (int col = 0; col < width; ++col) {
  269. auto pixel = m_context->reader->read_pixel(bits_per_pixel);
  270. auto actual_row = row;
  271. if (y_origin < height)
  272. actual_row = height - 1 - row;
  273. auto actual_col = col;
  274. if (x_origin > width)
  275. actual_col = width - 1 - col;
  276. bitmap->scanline(actual_row)[actual_col] = pixel.data;
  277. }
  278. }
  279. break;
  280. }
  281. case TGADataType::RunLengthEncodedRGB: {
  282. size_t pixel_index = 0;
  283. size_t pixel_count = height * width;
  284. while (pixel_index < pixel_count) {
  285. auto packet_type = m_context->reader->read_packet_type();
  286. VERIFY(packet_type.pixels_count > 0);
  287. TGAPixel pixel = m_context->reader->read_pixel(bits_per_pixel);
  288. auto max_pixel_index = min(pixel_index + packet_type.pixels_count, pixel_count);
  289. for (size_t current_pixel_index = pixel_index; current_pixel_index < max_pixel_index; ++current_pixel_index) {
  290. int row = current_pixel_index / width;
  291. int col = current_pixel_index % width;
  292. auto actual_row = row;
  293. if (y_origin < height)
  294. actual_row = height - 1 - row;
  295. auto actual_col = col;
  296. if (x_origin > width)
  297. actual_col = width - 1 - col;
  298. bitmap->scanline(actual_row)[actual_col] = pixel.data;
  299. if (packet_type.raw && (current_pixel_index + 1) < max_pixel_index)
  300. pixel = m_context->reader->read_pixel(bits_per_pixel);
  301. }
  302. pixel_index += packet_type.pixels_count;
  303. }
  304. break;
  305. }
  306. default:
  307. // FIXME: Implement other TGA data types
  308. return Error::from_string_literal("TGAImageDecoderPlugin: Can currently only handle the UncompressedRGB or CompressedRGB data type");
  309. }
  310. m_context->bitmap = bitmap;
  311. return ImageFrameDescriptor { m_context->bitmap, 0 };
  312. }
  313. ErrorOr<Optional<ReadonlyBytes>> TGAImageDecoderPlugin::icc_data()
  314. {
  315. return OptionalNone {};
  316. }
  317. }