JPEG2000Boxes.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * Copyright (c) 2024, Nico Weber <thakis@chromium.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "JPEG2000Boxes.h"
  7. #include <AK/Function.h>
  8. namespace Gfx::ISOBMFF {
  9. ErrorOr<void> JPEG2000HeaderBox::read_from_stream(BoxStream& stream)
  10. {
  11. auto make_subbox = [](BoxType type, BoxStream& stream) -> ErrorOr<Optional<NonnullOwnPtr<Box>>> {
  12. switch (type) {
  13. case BoxType::JPEG2000ChannelDefinitionBox:
  14. return TRY(JPEG2000ChannelDefinitionBox::create_from_stream(stream));
  15. case BoxType::JPEG2000ColorSpecificationBox:
  16. return TRY(JPEG2000ColorSpecificationBox::create_from_stream(stream));
  17. case BoxType::JPEG2000ImageHeaderBox:
  18. return TRY(JPEG2000ImageHeaderBox::create_from_stream(stream));
  19. case BoxType::JPEG2000ResolutionBox:
  20. return TRY(JPEG2000ResolutionBox::create_from_stream(stream));
  21. default:
  22. return OptionalNone {};
  23. }
  24. };
  25. TRY(SuperBox::read_from_stream(stream, move(make_subbox)));
  26. return {};
  27. }
  28. void JPEG2000HeaderBox::dump(String const& prepend) const
  29. {
  30. SuperBox::dump(prepend);
  31. }
  32. ErrorOr<void> JPEG2000ImageHeaderBox::read_from_stream(BoxStream& stream)
  33. {
  34. height = TRY(stream.read_value<BigEndian<u32>>());
  35. width = TRY(stream.read_value<BigEndian<u32>>());
  36. num_components = TRY(stream.read_value<BigEndian<u16>>());
  37. bits_per_component = TRY(stream.read_value<u8>());
  38. compression_type = TRY(stream.read_value<u8>());
  39. is_colorspace_unknown = TRY(stream.read_value<u8>());
  40. contains_intellectual_property_rights = TRY(stream.read_value<u8>());
  41. return {};
  42. }
  43. void JPEG2000ImageHeaderBox::dump(String const& prepend) const
  44. {
  45. Box::dump(prepend);
  46. outln("{}- height = {}", prepend, height);
  47. outln("{}- width = {}", prepend, width);
  48. outln("{}- num_components = {}", prepend, num_components);
  49. if (bits_per_component == 0xFF) {
  50. outln("{}- components vary in bit depth", prepend);
  51. } else {
  52. outln("{}- are_components_signed = {}", prepend, (bits_per_component & 0x80) != 0);
  53. outln("{}- bits_per_component = {}", prepend, (bits_per_component & 0x7f) + 1);
  54. }
  55. outln("{}- compression_type = {}", prepend, compression_type);
  56. outln("{}- is_colorspace_unknown = {}", prepend, is_colorspace_unknown);
  57. outln("{}- contains_intellectual_property_rights = {}", prepend, contains_intellectual_property_rights);
  58. }
  59. ErrorOr<void> JPEG2000ColorSpecificationBox::read_from_stream(BoxStream& stream)
  60. {
  61. method = TRY(stream.read_value<u8>());
  62. precedence = TRY(stream.read_value<i8>());
  63. approximation = TRY(stream.read_value<u8>());
  64. if (method == 1)
  65. enumerated_color_space = TRY(stream.read_value<BigEndian<u32>>());
  66. if (method == 2) {
  67. ByteBuffer local_icc_data = TRY(ByteBuffer::create_uninitialized(stream.remaining()));
  68. TRY(stream.read_until_filled(local_icc_data));
  69. icc_data = move(local_icc_data);
  70. }
  71. return {};
  72. }
  73. void JPEG2000ColorSpecificationBox::dump(String const& prepend) const
  74. {
  75. Box::dump(prepend);
  76. outln("{}- method = {}", prepend, method);
  77. outln("{}- precedence = {}", prepend, precedence);
  78. outln("{}- approximation = {}", prepend, approximation);
  79. if (method == 1)
  80. outln("{}- enumerated_color_space = {}", prepend, enumerated_color_space);
  81. if (method == 2)
  82. outln("{}- icc_data = {} bytes", prepend, icc_data.size());
  83. }
  84. ErrorOr<void> JPEG2000ChannelDefinitionBox::read_from_stream(BoxStream& stream)
  85. {
  86. u16 count = TRY(stream.read_value<BigEndian<u16>>());
  87. for (u32 i = 0; i < count; ++i) {
  88. Channel channel;
  89. channel.channel_index = TRY(stream.read_value<BigEndian<u16>>());
  90. channel.channel_type = TRY(stream.read_value<BigEndian<u16>>());
  91. channel.channel_association = TRY(stream.read_value<BigEndian<u16>>());
  92. channels.append(channel);
  93. }
  94. return {};
  95. }
  96. void JPEG2000ChannelDefinitionBox::dump(String const& prepend) const
  97. {
  98. Box::dump(prepend);
  99. for (auto const& channel : channels) {
  100. outln("{}- channel_index = {}", prepend, channel.channel_index);
  101. out("{}- channel_type = {}", prepend, channel.channel_type);
  102. if (channel.channel_type == 0)
  103. outln(" (color)");
  104. else if (channel.channel_type == 1)
  105. outln(" (opacity)");
  106. else if (channel.channel_type == 2)
  107. outln(" (premultiplied opacity)");
  108. else
  109. outln(" (unknown)");
  110. outln("{}- channel_association = {}", prepend, channel.channel_association);
  111. }
  112. }
  113. ErrorOr<void> JPEG2000ResolutionBox::read_from_stream(BoxStream& stream)
  114. {
  115. auto make_subbox = [](BoxType type, BoxStream& stream) -> ErrorOr<Optional<NonnullOwnPtr<Box>>> {
  116. switch (type) {
  117. case BoxType::JPEG2000CaptureResolutionBox:
  118. return TRY(JPEG2000CaptureResolutionBox::create_from_stream(stream));
  119. default:
  120. return OptionalNone {};
  121. }
  122. };
  123. TRY(SuperBox::read_from_stream(stream, move(make_subbox)));
  124. return {};
  125. }
  126. void JPEG2000ResolutionBox::dump(String const& prepend) const
  127. {
  128. SuperBox::dump(prepend);
  129. }
  130. ErrorOr<void> JPEG2000CaptureResolutionBox::read_from_stream(BoxStream& stream)
  131. {
  132. vertical_capture_grid_resolution_numerator = TRY(stream.read_value<BigEndian<u16>>());
  133. vertical_capture_grid_resolution_denominator = TRY(stream.read_value<BigEndian<u16>>());
  134. horizontal_capture_grid_resolution_numerator = TRY(stream.read_value<BigEndian<u16>>());
  135. horizontal_capture_grid_resolution_denominator = TRY(stream.read_value<BigEndian<u16>>());
  136. vertical_capture_grid_resolution_exponent = TRY(stream.read_value<i8>());
  137. horizontal_capture_grid_resolution_exponent = TRY(stream.read_value<i8>());
  138. return {};
  139. }
  140. void JPEG2000CaptureResolutionBox::dump(String const& prepend) const
  141. {
  142. Box::dump(prepend);
  143. outln("{}- vertical_capture_grid_resolution = {}/{} * 10^{}", prepend, vertical_capture_grid_resolution_numerator, vertical_capture_grid_resolution_denominator, vertical_capture_grid_resolution_exponent);
  144. outln("{}- horizontal_capture_grid_resolution = {}/{} * 10^{}", prepend, horizontal_capture_grid_resolution_numerator, horizontal_capture_grid_resolution_denominator, horizontal_capture_grid_resolution_exponent);
  145. }
  146. ErrorOr<void> JPEG2000ContiguousCodestreamBox::read_from_stream(BoxStream& stream)
  147. {
  148. // FIXME: It's wasteful to make a copy of all the image data here. Having just a ReadonlyBytes
  149. // or streaming it into the jpeg2000 decoder would be nicer.
  150. ByteBuffer local_codestream = TRY(ByteBuffer::create_uninitialized(stream.remaining()));
  151. TRY(stream.read_until_filled(local_codestream));
  152. codestream = move(local_codestream);
  153. return {};
  154. }
  155. void JPEG2000ContiguousCodestreamBox::dump(String const& prepend) const
  156. {
  157. Box::dump(prepend);
  158. outln("{}- codestream = {} bytes", prepend, codestream.size());
  159. }
  160. ErrorOr<void> JPEG2000SignatureBox::read_from_stream(BoxStream& stream)
  161. {
  162. signature = TRY(stream.read_value<BigEndian<u32>>());
  163. return {};
  164. }
  165. void JPEG2000SignatureBox::dump(String const& prepend) const
  166. {
  167. Box::dump(prepend);
  168. outln("{}- signature = {:#08x}", prepend, signature);
  169. }
  170. ErrorOr<void> JPEG2000UUIDInfoBox::read_from_stream(BoxStream& stream)
  171. {
  172. auto make_subbox = [](BoxType type, BoxStream& stream) -> ErrorOr<Optional<NonnullOwnPtr<Box>>> {
  173. switch (type) {
  174. case BoxType::JPEG2000UUIDListBox:
  175. return TRY(JPEG2000UUIDListBox::create_from_stream(stream));
  176. case BoxType::JPEG2000URLBox:
  177. return TRY(JPEG2000URLBox::create_from_stream(stream));
  178. default:
  179. return OptionalNone {};
  180. }
  181. };
  182. TRY(SuperBox::read_from_stream(stream, move(make_subbox)));
  183. return {};
  184. }
  185. void JPEG2000UUIDInfoBox::dump(String const& prepend) const
  186. {
  187. SuperBox::dump(prepend);
  188. }
  189. ErrorOr<void> JPEG2000UUIDListBox::read_from_stream(BoxStream& stream)
  190. {
  191. u16 count = TRY(stream.read_value<BigEndian<u16>>());
  192. for (u32 i = 0; i < count; ++i) {
  193. Array<u8, 16> uuid;
  194. TRY(stream.read_until_filled(uuid));
  195. uuids.append(uuid);
  196. }
  197. return {};
  198. }
  199. void JPEG2000UUIDListBox::dump(String const& prepend) const
  200. {
  201. Box::dump(prepend);
  202. for (auto const& uuid : uuids) {
  203. out("{}- ", prepend);
  204. for (auto byte : uuid) {
  205. out("{:02x}", byte);
  206. }
  207. outln();
  208. }
  209. }
  210. ErrorOr<String> JPEG2000URLBox::url_as_string() const
  211. {
  212. // Zero-terminated UTF-8 per spec.
  213. if (url_bytes.is_empty() || url_bytes.bytes().last() != '\0')
  214. return Error::from_string_literal("URL not zero-terminated");
  215. return String::from_utf8(StringView { url_bytes.bytes().trim(url_bytes.size() - 1) });
  216. }
  217. ErrorOr<void> JPEG2000URLBox::read_from_stream(BoxStream& stream)
  218. {
  219. version_number = TRY(stream.read_value<u8>());
  220. flag = TRY(stream.read_value<u8>()) << 16;
  221. flag |= TRY(stream.read_value<BigEndian<u16>>());
  222. url_bytes = TRY(ByteBuffer::create_uninitialized(stream.remaining()));
  223. TRY(stream.read_until_filled(url_bytes));
  224. return {};
  225. }
  226. void JPEG2000URLBox::dump(String const& prepend) const
  227. {
  228. Box::dump(prepend);
  229. outln("{}- version_number = {}", prepend, version_number);
  230. outln("{}- flag = {:#06x}", prepend, flag);
  231. auto url_or_err = url_as_string();
  232. if (url_or_err.is_error())
  233. outln("{}- url = <invalid {}; {} bytes>", prepend, url_or_err.release_error(), url_bytes.size());
  234. else
  235. outln("{}- url = {}", prepend, url_or_err.release_value());
  236. }
  237. }