49 const QByteArray buf = io->readAll();
55 const uint8_t *data =
reinterpret_cast<const uint8_t *
>(buf.constData());
56 const size_t data_size =
static_cast<size_t>(buf.size());
58 const WebPData webpData = {data, data_size};
60 WebPDemuxer *demux = WebPDemux(&webpData);
62 dbgFile <<
"WebP demuxer initialization failure";
66 const uint32_t width = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH);
67 const uint32_t height = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT);
68 const uint32_t flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS);
69 const uint32_t bg = WebPDemuxGetI(demux, WEBP_FF_BACKGROUND_COLOR);
77 WebPChunkIterator chunk_iter;
78 if (flags & ICCP_FLAG) {
79 if (WebPDemuxGetChunk(demux,
"ICCP", 1, &chunk_iter)) {
80 dbgFile <<
"WebPDemuxGetChunk on ICCP succeeded, ICC profile "
83 const QByteArray iccProfile(
84 reinterpret_cast<const char *
>(chunk_iter.chunk.bytes),
85 static_cast<int>(chunk_iter.chunk.size));
97 if (!imageColorSpace) {
108 if (imageColorSpace) {
114 WebPDemuxReleaseChunkIterator(&chunk_iter);
117 if (isRgba && imageColorSpace) {
118 colorSpace = imageColorSpace;
122 QColor(bg >> 8 & 0xFFu, bg >> 16 & 0xFFu, bg >> 24 & 0xFFu, bg & 0xFFu),
126 static_cast<qint32
>(width),
127 static_cast<qint32
>(height),
135 WebPChunkIterator chunk_iter;
136 if (flags & EXIF_FLAG) {
137 if (WebPDemuxGetChunk(demux,
"EXIF", 1, &chunk_iter)) {
138 dbgFile <<
"Loading EXIF data. Size: " << chunk_iter.chunk.size;
142 reinterpret_cast<const char *
>(chunk_iter.chunk.bytes),
143 static_cast<int>(chunk_iter.chunk.size));
151 WebPDemuxReleaseChunkIterator(&chunk_iter);
155 WebPChunkIterator chunk_iter;
156 if (flags & XMP_FLAG) {
157 if (WebPDemuxGetChunk(demux,
"XMP ", 1, &chunk_iter)) {
158 dbgFile <<
"Loading XMP data. Size: " << chunk_iter.chunk.size;
162 reinterpret_cast<const char *
>(chunk_iter.chunk.bytes),
163 static_cast<int>(chunk_iter.chunk.size));
171 WebPDemuxReleaseChunkIterator(&chunk_iter);
176 if (WebPDemuxGetFrame(demux, 1, &iter)) {
177 int nextTimestamp = 0;
178 WebPDecoderConfig config;
184 if (!WebPInitDecoderConfig(&config)) {
185 dbgFile <<
"WebP decode config initialization failure";
190 const VP8StatusCode result =
191 WebPGetFeatures(iter.fragment.bytes,
194 dbgFile <<
"WebP import validation status: " << result;
198 case VP8_STATUS_OUT_OF_MEMORY:
200 case VP8_STATUS_INVALID_PARAM:
202 case VP8_STATUS_BITSTREAM_ERROR:
204 case VP8_STATUS_UNSUPPORTED_FEATURE:
206 case VP8_STATUS_SUSPENDED:
207 case VP8_STATUS_USER_ABORT:
210 case VP8_STATUS_NOT_ENOUGH_DATA:
217 config.output.colorspace = MODE_BGRA;
218 config.options.use_threads = 1;
221 const VP8StatusCode result = WebPDecode(iter.fragment.bytes,
225 dbgFile <<
"WebP frame:" << iter.frame_num
226 <<
", import status: " << result;
230 case VP8_STATUS_OUT_OF_MEMORY:
232 case VP8_STATUS_INVALID_PARAM:
234 case VP8_STATUS_BITSTREAM_ERROR:
236 case VP8_STATUS_UNSUPPORTED_FEATURE:
238 case VP8_STATUS_SUSPENDED:
239 case VP8_STATUS_USER_ABORT:
242 case VP8_STATUS_NOT_ENOUGH_DATA:
251 if (iter.num_frames > 0 && iter.frame_num == 1) {
252 dbgFile <<
"Animation detected, estimated framerate:"
253 <<
static_cast<double>(1000) / iter.duration;
254 const int framerate = std::lround(
255 1000.0 /
static_cast<double>(iter.duration));
262 QPoint{iter.x_offset, iter.y_offset},
263 QSize{config.output.width, config.output.height});
270 currentFrame->
writeBytes(config.output.u.RGBA.rgba,
274 config.output.height);
282 {iter.x_offset, iter.y_offset},
284 {QPoint(iter.x_offset, iter.y_offset),
285 QSize(config.output.width, config.output.height)});
288 if (iter.num_frames > 1) {
289 const int currentFrameTime =
290 std::lround(
static_cast<double>(nextTimestamp)
291 /
static_cast<double>(iter.duration));
293 "Importing frame %1 @ %2, duration %3 ms, "
294 "blending %4, disposal %5")
296 .arg(currentFrameTime)
298 .arg(iter.blend_method)
299 .arg(iter.dispose_method)
308 std::lround(
static_cast<double>(nextTimestamp)
309 /
static_cast<double>(iter.duration)));
310 frame->importFrame(currentFrameTime,
313 nextTimestamp += iter.duration;
319 if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
323 WebPFreeDecBuffer(&config.output);
324 }
while (WebPDemuxNextFrame(&iter));
326 WebPDemuxReleaseIterator(&iter);
329 WebPDemuxDelete(demux);
337 document->setCurrentImage(image);