@@ -53,14 +53,30 @@ class JPEGXLLoadingContext {
53
53
return m_size;
54
54
}
55
55
56
- RefPtr<Bitmap> bitmap () const
56
+ Vector<ImageFrameDescriptor> const & frame_descriptors () const
57
57
{
58
- return m_bitmap;
58
+ return m_frame_descriptors;
59
+ }
60
+
61
+ bool is_animated () const
62
+ {
63
+ return m_animated;
64
+ }
65
+
66
+ u32 loop_count () const
67
+ {
68
+ return m_loop_count;
69
+ }
70
+
71
+ u32 frame_count () const
72
+ {
73
+ return m_frame_count;
59
74
}
60
75
61
76
private:
62
77
ErrorOr<void > run_state_machine_until (State requested_state)
63
78
{
79
+ Optional<u32 > frame_duration;
64
80
for (;;) {
65
81
auto const status = JxlDecoderProcessInput (m_decoder);
66
82
@@ -75,19 +91,36 @@ class JPEGXLLoadingContext {
75
91
return {};
76
92
}
77
93
94
+ if (status == JXL_DEC_FRAME) {
95
+ JxlFrameHeader header;
96
+ if (auto res = JxlDecoderGetFrameHeader (m_decoder, &header);
97
+ res != JXL_DEC_SUCCESS)
98
+ return Error::from_string_literal (" JPEGXLImageDecoderPlugin: Unable to retrieve frame header." );
99
+
100
+ frame_duration = header.duration ;
101
+ continue ;
102
+ }
103
+
78
104
if (status == JXL_DEC_NEED_IMAGE_OUT_BUFFER) {
79
- TRY (set_output_buffer ());
105
+ if (!frame_duration.has_value ())
106
+ return Error::from_string_literal (" JPEGXLImageDecoderPlugin: No frame header was read." );
107
+
108
+ TRY (set_output_buffer (*frame_duration));
80
109
continue ;
81
110
}
82
111
83
112
if (status == JXL_DEC_FULL_IMAGE) {
84
- // Called once per frame, let's return for now
85
- return {} ;
113
+ m_frame_count++;
114
+ continue ;
86
115
}
87
116
88
- if (status == JXL_DEC_SUCCESS)
117
+ if (status == JXL_DEC_SUCCESS) {
118
+ if (m_state != State::Error)
119
+ m_state = State::FrameDecoded;
89
120
return {};
121
+ }
90
122
123
+ warnln (" JPEGXLImageDecoderPlugin: Unknown event." );
91
124
return Error::from_string_literal (" JPEGXLImageDecoderPlugin: Unknown event." );
92
125
}
93
126
}
@@ -101,34 +134,44 @@ class JPEGXLLoadingContext {
101
134
102
135
m_size = { info.xsize , info.ysize };
103
136
137
+ m_animated = static_cast <bool >(info.have_animation );
138
+
139
+ if (m_animated)
140
+ m_loop_count = info.animation .num_loops ;
141
+
104
142
m_state = State::HeaderDecoded;
105
143
return {};
106
144
}
107
145
108
- ErrorOr<void > set_output_buffer ()
146
+ ErrorOr<void > set_output_buffer (u32 duration )
109
147
{
110
- auto result = [this ]() -> ErrorOr<void > {
148
+ auto result = [this , duration ]() -> ErrorOr<void > {
111
149
if (JxlDecoderProcessInput (m_decoder) != JXL_DEC_NEED_IMAGE_OUT_BUFFER)
112
150
return Error::from_string_literal (" JPEGXLImageDecoderPlugin: Decoder is in an unexpected state." );
113
151
114
- m_bitmap = TRY (Bitmap::create (Gfx::BitmapFormat::RGBA8888, m_size));
152
+ auto bitmap = TRY (Bitmap::create (Gfx::BitmapFormat::RGBA8888, m_size));
153
+ TRY (m_frame_descriptors.try_empend (bitmap, static_cast <int >(duration)));
115
154
116
155
JxlPixelFormat format = { 4 , JXL_TYPE_UINT8, JXL_NATIVE_ENDIAN, 0 };
117
156
118
157
size_t needed_size = 0 ;
119
158
JxlDecoderImageOutBufferSize (m_decoder, &format, &needed_size);
120
159
121
- if (needed_size != m_bitmap ->size_in_bytes ())
160
+ if (needed_size != bitmap ->size_in_bytes ())
122
161
return Error::from_string_literal (" JPEGXLImageDecoderPlugin: Expected bitmap size is wrong." );
123
162
124
- if (auto res = JxlDecoderSetImageOutBuffer (m_decoder, &format, m_bitmap ->begin (), m_bitmap ->size_in_bytes ());
163
+ if (auto res = JxlDecoderSetImageOutBuffer (m_decoder, &format, bitmap ->begin (), bitmap ->size_in_bytes ());
125
164
res != JXL_DEC_SUCCESS)
126
165
return Error::from_string_literal (" JPEGXLImageDecoderPlugin: Unable to decode frame." );
127
166
128
167
return {};
129
168
}();
130
169
131
- m_state = result.is_error () ? State::Error : State::FrameDecoded;
170
+ if (result.is_error ()) {
171
+ m_state = State::Error;
172
+ warnln (" {}" , result.error ());
173
+ }
174
+
132
175
return result;
133
176
}
134
177
@@ -137,7 +180,11 @@ class JPEGXLLoadingContext {
137
180
JxlDecoder* m_decoder;
138
181
139
182
IntSize m_size;
140
- RefPtr<Bitmap> m_bitmap;
183
+ Vector<ImageFrameDescriptor> m_frame_descriptors;
184
+
185
+ bool m_animated { false };
186
+ u32 m_loop_count { 0 };
187
+ u32 m_frame_count { 0 };
141
188
};
142
189
143
190
JPEGXLImageDecoderPlugin::JPEGXLImageDecoderPlugin (OwnPtr<JPEGXLLoadingContext> context)
@@ -164,7 +211,8 @@ ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> JPEGXLImageDecoderPlugin::create(Read
164
211
if (!decoder)
165
212
return Error::from_errno (ENOMEM);
166
213
167
- if (auto res = JxlDecoderSubscribeEvents (decoder, JXL_DEC_BASIC_INFO | JXL_DEC_FULL_IMAGE); res == JXL_DEC_ERROR)
214
+ auto const events = JXL_DEC_BASIC_INFO | JXL_DEC_FRAME | JXL_DEC_FULL_IMAGE;
215
+ if (auto res = JxlDecoderSubscribeEvents (decoder, events); res == JXL_DEC_ERROR)
168
216
return Error::from_string_literal (" JPEGXLImageDecoderPlugin: Unable to subscribe to events." );
169
217
170
218
if (auto res = JxlDecoderSetInput (decoder, data.data (), data.size ()); res == JXL_DEC_ERROR)
@@ -182,17 +230,21 @@ ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> JPEGXLImageDecoderPlugin::create(Read
182
230
183
231
bool JPEGXLImageDecoderPlugin::is_animated ()
184
232
{
185
- return false ;
233
+ return m_context-> is_animated () ;
186
234
}
187
235
188
236
size_t JPEGXLImageDecoderPlugin::loop_count ()
189
237
{
190
- return 0 ;
238
+ return m_context-> loop_count () ;
191
239
}
192
240
193
241
size_t JPEGXLImageDecoderPlugin::frame_count ()
194
242
{
195
- return 1 ;
243
+ // FIXME: There doesn't seem to be a way to have that information
244
+ // before decoding all the frames.
245
+ if (m_context->frame_count () == 0 )
246
+ (void )frame (0 );
247
+ return m_context->frame_count ();
196
248
}
197
249
198
250
size_t JPEGXLImageDecoderPlugin::first_animated_frame_index ()
@@ -202,16 +254,15 @@ size_t JPEGXLImageDecoderPlugin::first_animated_frame_index()
202
254
203
255
ErrorOr<ImageFrameDescriptor> JPEGXLImageDecoderPlugin::frame (size_t index, Optional<IntSize>)
204
256
{
205
- if (index > 0 )
206
- return Error::from_string_literal (" JPEGXLImageDecoderPlugin: Invalid frame index." );
207
-
208
257
if (m_context->state () == JPEGXLLoadingContext::State::Error)
209
258
return Error::from_string_literal (" JPEGXLImageDecoderPlugin: Decoding failed." );
210
259
211
260
if (m_context->state () < JPEGXLLoadingContext::State::FrameDecoded)
212
261
TRY (m_context->decode_image ());
213
262
214
- return ImageFrameDescriptor { m_context->bitmap (), 0 };
263
+ if (index >= m_context->frame_descriptors ().size ())
264
+ return Error::from_string_literal (" JPEGXLImageDecoderPlugin: Invalid frame index requested." );
265
+ return m_context->frame_descriptors ()[index];
215
266
}
216
267
217
268
ErrorOr<Optional<ReadonlyBytes>> JPEGXLImageDecoderPlugin::icc_data ()
0 commit comments