AVIFLoader.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. * Copyright (c) 2023, Nico Weber <thakis@chromium.org>
  3. * Copyright (c) 2024, doctortheemh <doctortheemh@gmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/ByteBuffer.h>
  8. #include <AK/Error.h>
  9. #include <LibGfx/ImageFormats/AVIFLoader.h>
  10. #include <avif/avif.h>
  11. namespace Gfx {
  12. class AVIFLoadingContext {
  13. AK_MAKE_NONMOVABLE(AVIFLoadingContext);
  14. AK_MAKE_NONCOPYABLE(AVIFLoadingContext);
  15. public:
  16. enum State {
  17. NotDecoded = 0,
  18. Error,
  19. HeaderDecoded,
  20. BitmapDecoded,
  21. };
  22. State state { State::NotDecoded };
  23. ReadonlyBytes data;
  24. avifDecoder* decoder { nullptr };
  25. // image properties
  26. Optional<IntSize> size;
  27. bool has_alpha { false };
  28. size_t image_count { 0 };
  29. size_t repetition_count { 0 };
  30. ByteBuffer icc_data;
  31. Vector<ImageFrameDescriptor> frame_descriptors;
  32. AVIFLoadingContext() = default;
  33. ~AVIFLoadingContext()
  34. {
  35. avifDecoderDestroy(decoder);
  36. decoder = nullptr;
  37. }
  38. };
  39. AVIFImageDecoderPlugin::AVIFImageDecoderPlugin(ReadonlyBytes data, OwnPtr<AVIFLoadingContext> context)
  40. : m_context(move(context))
  41. {
  42. m_context->data = data;
  43. }
  44. AVIFImageDecoderPlugin::~AVIFImageDecoderPlugin()
  45. {
  46. }
  47. static ErrorOr<void> decode_avif_header(AVIFLoadingContext& context)
  48. {
  49. if (context.state >= AVIFLoadingContext::HeaderDecoded)
  50. return {};
  51. if (context.decoder == nullptr) {
  52. context.decoder = avifDecoderCreate();
  53. if (context.decoder == nullptr) {
  54. return Error::from_string_literal("failed to allocate AVIF decoder");
  55. }
  56. }
  57. avifResult result = avifDecoderSetIOMemory(context.decoder, context.data.data(), context.data.size());
  58. if (result != AVIF_RESULT_OK)
  59. return Error::from_string_literal("Cannot set IO on avifDecoder");
  60. result = avifDecoderParse(context.decoder);
  61. if (result != AVIF_RESULT_OK)
  62. return Error::from_string_literal("Failed to decode AVIF");
  63. if (context.decoder->image->depth != 8)
  64. return Error::from_string_literal("Unsupported bitdepth");
  65. // Image header now decoded, save some results for fast access in other parts of the plugin.
  66. context.size = IntSize { context.decoder->image->width, context.decoder->image->height };
  67. context.has_alpha = context.decoder->alphaPresent == 1;
  68. context.image_count = context.decoder->imageCount;
  69. context.repetition_count = context.decoder->repetitionCount <= 0 ? 0 : context.decoder->repetitionCount;
  70. context.state = AVIFLoadingContext::State::HeaderDecoded;
  71. if (context.decoder->image->icc.size > 0) {
  72. context.icc_data.resize(context.decoder->image->icc.size);
  73. memcpy(context.icc_data.data(), context.decoder->image->icc.data, context.decoder->image->icc.size);
  74. }
  75. return {};
  76. }
  77. static ErrorOr<void> decode_avif_image(AVIFLoadingContext& context)
  78. {
  79. VERIFY(context.state >= AVIFLoadingContext::State::HeaderDecoded);
  80. avifRGBImage rgb;
  81. while (avifDecoderNextImage(context.decoder) == AVIF_RESULT_OK) {
  82. auto bitmap_format = context.has_alpha ? BitmapFormat::BGRA8888 : BitmapFormat::BGRx8888;
  83. auto bitmap = TRY(Bitmap::create(bitmap_format, context.size.value()));
  84. avifRGBImageSetDefaults(&rgb, context.decoder->image);
  85. rgb.pixels = bitmap->scanline_u8(0);
  86. rgb.rowBytes = bitmap->pitch();
  87. rgb.format = avifRGBFormat::AVIF_RGB_FORMAT_BGRA;
  88. avifResult result = avifImageYUVToRGB(context.decoder->image, &rgb);
  89. if (result != AVIF_RESULT_OK)
  90. return Error::from_string_literal("Conversion from YUV to RGB failed");
  91. auto duration = context.decoder->imageCount == 1 ? 0 : static_cast<int>(context.decoder->imageTiming.duration * 1000);
  92. context.frame_descriptors.append(ImageFrameDescriptor { bitmap, duration });
  93. context.state = AVIFLoadingContext::BitmapDecoded;
  94. }
  95. return {};
  96. }
  97. IntSize AVIFImageDecoderPlugin::size()
  98. {
  99. return m_context->size.value();
  100. }
  101. bool AVIFImageDecoderPlugin::sniff(ReadonlyBytes data)
  102. {
  103. AVIFLoadingContext context;
  104. context.data = data;
  105. return !decode_avif_header(context).is_error();
  106. }
  107. ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> AVIFImageDecoderPlugin::create(ReadonlyBytes data)
  108. {
  109. auto context = TRY(try_make<AVIFLoadingContext>());
  110. auto plugin = TRY(adopt_nonnull_own_or_enomem(new (nothrow) AVIFImageDecoderPlugin(data, move(context))));
  111. TRY(decode_avif_header(*plugin->m_context));
  112. return plugin;
  113. }
  114. bool AVIFImageDecoderPlugin::is_animated()
  115. {
  116. return m_context->image_count > 1;
  117. }
  118. size_t AVIFImageDecoderPlugin::loop_count()
  119. {
  120. return is_animated() ? m_context->repetition_count : 0;
  121. }
  122. size_t AVIFImageDecoderPlugin::frame_count()
  123. {
  124. if (!is_animated())
  125. return 1;
  126. return m_context->image_count;
  127. }
  128. size_t AVIFImageDecoderPlugin::first_animated_frame_index()
  129. {
  130. return 0;
  131. }
  132. ErrorOr<ImageFrameDescriptor> AVIFImageDecoderPlugin::frame(size_t index, Optional<IntSize>)
  133. {
  134. if (index >= frame_count())
  135. return Error::from_string_literal("AVIFImageDecoderPlugin: Invalid frame index");
  136. if (m_context->state == AVIFLoadingContext::State::Error)
  137. return Error::from_string_literal("AVIFImageDecoderPlugin: Decoding failed");
  138. if (m_context->state < AVIFLoadingContext::State::BitmapDecoded) {
  139. TRY(decode_avif_image(*m_context));
  140. m_context->state = AVIFLoadingContext::State::BitmapDecoded;
  141. }
  142. if (index >= m_context->frame_descriptors.size())
  143. return Error::from_string_literal("AVIFImageDecoderPlugin: Invalid frame index");
  144. return m_context->frame_descriptors[index];
  145. }
  146. ErrorOr<Optional<ReadonlyBytes>> AVIFImageDecoderPlugin::icc_data()
  147. {
  148. if (m_context->state < AVIFLoadingContext::State::HeaderDecoded)
  149. (void)frame(0);
  150. if (!m_context->icc_data.is_empty())
  151. return m_context->icc_data;
  152. return OptionalNone {};
  153. }
  154. }