PortableImageLoaderCommon.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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. inline ErrorOr<String> read_token(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. return TRY(sb.to_string());
  38. }
  39. static inline ErrorOr<u16> read_number(SeekableStream& stream)
  40. {
  41. auto const maybe_value = TRY(read_token(stream)).to_number<u16>();
  42. if (!maybe_value.has_value())
  43. return Error::from_string_literal("Can't convert bytes to a number");
  44. return *maybe_value;
  45. }
  46. template<typename TContext>
  47. static ErrorOr<void> read_comment(TContext& context)
  48. {
  49. auto& stream = *context.stream;
  50. bool is_first_char = true;
  51. u8 byte {};
  52. while ((byte = TRY(stream.template read_value<u8>()))) {
  53. if (is_first_char) {
  54. if (byte != '#')
  55. return Error::from_string_literal("Can't read comment from stream");
  56. is_first_char = false;
  57. } else if (byte == '\t' || byte == '\n') {
  58. break;
  59. }
  60. }
  61. return {};
  62. }
  63. template<typename TContext>
  64. static ErrorOr<void> read_magic_number(TContext& context)
  65. {
  66. if (TRY(context.stream->size()) < 2) {
  67. dbgln_if(PORTABLE_IMAGE_LOADER_DEBUG, "There is no enough data for {}", TContext::FormatDetails::image_type);
  68. return Error::from_string_literal("There is no enough data to read magic number.");
  69. }
  70. Array<u8, 2> magic_number {};
  71. TRY(context.stream->read_until_filled(Bytes { magic_number }));
  72. if constexpr (requires { TContext::FormatDetails::ascii_magic_number; }) {
  73. if (magic_number[0] == 'P' && magic_number[1] == TContext::FormatDetails::ascii_magic_number) {
  74. context.type = TContext::Type::ASCII;
  75. return {};
  76. }
  77. }
  78. if (magic_number[0] == 'P' && magic_number[1] == TContext::FormatDetails::binary_magic_number) {
  79. context.type = TContext::Type::RAWBITS;
  80. return {};
  81. }
  82. dbgln_if(PORTABLE_IMAGE_LOADER_DEBUG, "Magic number is not valid for {}{}{}", magic_number[0], magic_number[1], TContext::FormatDetails::image_type);
  83. return Error::from_string_literal("Unable to recognize magic bytes");
  84. }
  85. template<typename TContext>
  86. static ErrorOr<void> read_whitespace(TContext& context)
  87. {
  88. auto& stream = *context.stream;
  89. bool is_first_char = true;
  90. while (true) {
  91. auto byte_or_error = stream.template read_value<u8>();
  92. // Nothing went wrong if we reached eof while reading a comment.
  93. if (byte_or_error.is_error())
  94. return {};
  95. auto const byte = byte_or_error.value();
  96. if (byte == '#') {
  97. TRY(stream.seek(-1, SeekMode::FromCurrentPosition));
  98. TRY(read_comment(context));
  99. continue;
  100. }
  101. if (byte != ' ' && byte != '\t' && byte != '\n' && byte != '\r') {
  102. TRY(stream.seek(-1, SeekMode::FromCurrentPosition));
  103. if (is_first_char)
  104. return Error::from_string_literal("Can't read whitespace from stream");
  105. break;
  106. }
  107. if (is_first_char)
  108. is_first_char = false;
  109. }
  110. return {};
  111. }
  112. template<typename TContext>
  113. static ErrorOr<void> read_width(TContext& context)
  114. {
  115. context.width = TRY(read_number(*context.stream));
  116. return {};
  117. }
  118. template<typename TContext>
  119. static ErrorOr<void> read_height(TContext& context)
  120. {
  121. context.height = TRY(read_number(*context.stream));
  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 == 0)
  129. return Error::from_string_literal("The image has a maximum value of 0");
  130. if (context.format_details.max_val > 255) {
  131. dbgln_if(PORTABLE_IMAGE_LOADER_DEBUG, "We can't parse 2 byte color for {}", TContext::FormatDetails::image_type);
  132. return Error::from_string_literal("Can't parse 2 byte color");
  133. }
  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 Context>
  143. static ErrorOr<void> read_header(Context& context)
  144. {
  145. TRY(read_magic_number(context));
  146. TRY(read_whitespace(context));
  147. TRY(read_width(context));
  148. TRY(read_whitespace(context));
  149. TRY(read_height(context));
  150. TRY(read_whitespace(context));
  151. if constexpr (requires { context.format_details.max_val; }) {
  152. TRY(read_max_val(context));
  153. TRY(read_whitespace(context));
  154. }
  155. context.state = Context::State::HeaderDecoded;
  156. return {};
  157. }
  158. template<typename Context>
  159. static ErrorOr<void> read_pam_header(Context& context);
  160. template<typename TContext>
  161. static ErrorOr<void> decode(TContext& context)
  162. {
  163. VERIFY(context.state == TContext::State::HeaderDecoded);
  164. TRY(read_image_data(context));
  165. context.state = TContext::State::BitmapDecoded;
  166. return {};
  167. }
  168. }