PortableImageLoaderCommon.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
  3. * Copyright (c) 2020-2022, the SerenityOS developers.
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #pragma once
  8. #include <AK/Debug.h>
  9. #include <AK/Endian.h>
  10. #include <AK/ScopeGuard.h>
  11. #include <AK/String.h>
  12. #include <AK/StringBuilder.h>
  13. #include <AK/Types.h>
  14. #include <AK/Vector.h>
  15. #include <LibGfx/Bitmap.h>
  16. #include <LibGfx/Color.h>
  17. #include <LibGfx/ImageFormats/ImageDecoder.h>
  18. namespace Gfx {
  19. static constexpr Color adjust_color(u16 max_val, Color color)
  20. {
  21. color.set_red((color.red() * 255) / max_val);
  22. color.set_green((color.green() * 255) / max_val);
  23. color.set_blue((color.blue() * 255) / max_val);
  24. return color;
  25. }
  26. static inline ErrorOr<u16> read_number(SeekableStream& stream)
  27. {
  28. StringBuilder sb {};
  29. u8 byte {};
  30. for (auto buffer = TRY(stream.read_some({ &byte, 1 })); !buffer.is_empty(); buffer = TRY(stream.read_some({ &byte, 1 }))) {
  31. if (byte == ' ' || byte == '\t' || byte == '\n' || byte == '\r') {
  32. TRY(stream.seek(-1, SeekMode::FromCurrentPosition));
  33. break;
  34. }
  35. sb.append(byte);
  36. }
  37. auto const maybe_value = TRY(sb.to_string()).to_number<u16>();
  38. if (!maybe_value.has_value())
  39. return Error::from_string_literal("Can't convert bytes to a number");
  40. return *maybe_value;
  41. }
  42. template<typename TContext>
  43. static ErrorOr<void> read_comment(TContext& context)
  44. {
  45. auto& stream = *context.stream;
  46. bool is_first_char = true;
  47. u8 byte {};
  48. while ((byte = TRY(stream.template read_value<u8>()))) {
  49. if (is_first_char) {
  50. if (byte != '#')
  51. return Error::from_string_literal("Can't read comment from stream");
  52. is_first_char = false;
  53. } else if (byte == '\t' || byte == '\n') {
  54. break;
  55. }
  56. }
  57. return {};
  58. }
  59. template<typename TContext>
  60. static ErrorOr<void> read_magic_number(TContext& context)
  61. {
  62. if (context.state >= TContext::State::MagicNumber)
  63. return {};
  64. if (TRY(context.stream->size()) < 2) {
  65. dbgln_if(PORTABLE_IMAGE_LOADER_DEBUG, "There is no enough data for {}", TContext::FormatDetails::image_type);
  66. return Error::from_string_literal("There is no enough data to read magic number.");
  67. }
  68. Array<u8, 2> magic_number {};
  69. TRY(context.stream->read_until_filled(Bytes { magic_number }));
  70. if (magic_number[0] == 'P' && magic_number[1] == TContext::FormatDetails::ascii_magic_number) {
  71. context.type = TContext::Type::ASCII;
  72. context.state = TContext::State::MagicNumber;
  73. return {};
  74. }
  75. if (magic_number[0] == 'P' && magic_number[1] == TContext::FormatDetails::binary_magic_number) {
  76. context.type = TContext::Type::RAWBITS;
  77. context.state = TContext::State::MagicNumber;
  78. return {};
  79. }
  80. dbgln_if(PORTABLE_IMAGE_LOADER_DEBUG, "Magic number is not valid for {}{}{}", magic_number[0], magic_number[1], TContext::FormatDetails::image_type);
  81. return Error::from_string_literal("Unable to recognize magic bytes");
  82. }
  83. template<typename TContext>
  84. static ErrorOr<void> read_whitespace(TContext& context)
  85. {
  86. auto& stream = *context.stream;
  87. bool is_first_char = true;
  88. while (true) {
  89. auto byte_or_error = stream.template read_value<u8>();
  90. // Nothing went wrong if we reached eof while reading a comment.
  91. if (byte_or_error.is_error())
  92. return {};
  93. auto const byte = byte_or_error.value();
  94. if (byte == '#') {
  95. stream.seek(-1, SeekMode::FromCurrentPosition).release_value_but_fixme_should_propagate_errors();
  96. TRY(read_comment(context));
  97. continue;
  98. }
  99. if (byte != ' ' && byte != '\t' && byte != '\n' && byte != '\r') {
  100. stream.seek(-1, SeekMode::FromCurrentPosition).release_value_but_fixme_should_propagate_errors();
  101. if (is_first_char)
  102. return Error::from_string_literal("Can't read whitespace from stream");
  103. break;
  104. }
  105. if (is_first_char)
  106. is_first_char = false;
  107. }
  108. return {};
  109. }
  110. template<typename TContext>
  111. static ErrorOr<void> read_width(TContext& context)
  112. {
  113. context.width = TRY(read_number(*context.stream));
  114. context.state = TContext::State::Width;
  115. return {};
  116. }
  117. template<typename TContext>
  118. static ErrorOr<void> read_height(TContext& context)
  119. {
  120. context.height = TRY(read_number(*context.stream));
  121. context.state = TContext::State::Height;
  122. return {};
  123. }
  124. template<typename TContext>
  125. static ErrorOr<void> read_max_val(TContext& context)
  126. {
  127. context.format_details.max_val = TRY(read_number(*context.stream));
  128. if (context.format_details.max_val > 255) {
  129. dbgln_if(PORTABLE_IMAGE_LOADER_DEBUG, "We can't parse 2 byte color for {}", TContext::FormatDetails::image_type);
  130. context.state = TContext::State::Error;
  131. return Error::from_string_literal("Can't parse 2 byte color");
  132. }
  133. context.state = TContext::State::Maxval;
  134. return {};
  135. }
  136. template<typename TContext>
  137. static ErrorOr<void> create_bitmap(TContext& context)
  138. {
  139. context.bitmap = TRY(Bitmap::create(BitmapFormat::BGRx8888, { context.width, context.height }));
  140. return {};
  141. }
  142. template<typename TContext>
  143. static void set_pixels(TContext& context, Vector<Gfx::Color> const& color_data)
  144. {
  145. size_t index = 0;
  146. for (size_t y = 0; y < context.height; ++y) {
  147. for (size_t x = 0; x < context.width; ++x) {
  148. context.bitmap->set_pixel(x, y, color_data.at(index));
  149. index++;
  150. }
  151. }
  152. }
  153. template<typename TContext>
  154. static ErrorOr<void> decode(TContext& context)
  155. {
  156. if (context.state >= TContext::State::Decoded)
  157. return {};
  158. TRY(read_magic_number(context));
  159. TRY(read_whitespace(context));
  160. TRY(read_width(context));
  161. TRY(read_whitespace(context));
  162. TRY(read_height(context));
  163. if (context.width > maximum_width_for_decoded_images || context.height > maximum_height_for_decoded_images) {
  164. dbgln("This portable network image is too large for comfort: {}x{}", context.width, context.height);
  165. return Error::from_string_literal("This portable network image is too large.");
  166. }
  167. TRY(read_whitespace(context));
  168. if constexpr (requires { context.format_details.max_val; }) {
  169. TRY(read_max_val(context));
  170. TRY(read_whitespace(context));
  171. }
  172. TRY(read_image_data(context));
  173. context.state = TContext::State::Decoded;
  174. return {};
  175. }
  176. }