static void decode_callback(int what) { if (what == 0 && !kParams.done) { int duration = 0; if (kParams.dmux != NULL) { WebPIterator* const curr = &kParams.curr_frame; if (!WebPDemuxNextFrame(curr)) { WebPDemuxReleaseIterator(curr); if (WebPDemuxGetFrame(kParams.dmux, 1, curr)) { --kParams.loop_count; kParams.done = (kParams.loop_count == 0); } else { kParams.decoding_error = 1; kParams.done = 1; return; } } duration = curr->duration; } if (!Decode()) { kParams.decoding_error = 1; kParams.done = 1; } else { glutPostRedisplay(); glutTimerFunc(duration, decode_callback, what); } } }
static void decode_callback(int what) { if (what == 0 && !kParams.done) { int duration = 0; if (kParams.dmux != NULL) { WebPIterator* const curr = &kParams.curr_frame; if (!WebPDemuxNextFrame(curr)) { WebPDemuxReleaseIterator(curr); if (WebPDemuxGetFrame(kParams.dmux, 1, curr)) { --kParams.loop_count; kParams.done = (kParams.loop_count == 0); if (kParams.done) return; ClearPreviousFrame(); } else { kParams.decoding_error = 1; kParams.done = 1; return; } } duration = curr->duration; // Behavior copied from Chrome, cf: // https://cs.chromium.org/chromium/src/third_party/WebKit/Source/ // platform/graphics/DeferredImageDecoder.cpp? // rcl=b4c33049f096cd283f32be9a58b9a9e768227c26&l=246 if (duration <= 10) duration = 100; } if (!Decode()) { kParams.decoding_error = 1; kParams.done = 1; } else { glutPostRedisplay(); glutTimerFunc(duration, decode_callback, what); } } }
bool QWebpHandler::read(QImage *image) { if (!ensureScanned() || device()->isSequential()) return false; if (m_hasFirstFrameRead) { if (!WebPDemuxNextFrame(&m_iter)) return false; } else { m_hasFirstFrameRead = true; } WebPBitstreamFeatures features; VP8StatusCode status = WebPGetFeatures(m_iter.fragment.bytes, m_iter.fragment.size, &features); if (status != VP8_STATUS_OK) return false; QImage result(features.width, features.height, QImage::Format_ARGB32); uint8_t *output = result.bits(); size_t output_size = result.byteCount(); #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN if (!WebPDecodeBGRAInto( reinterpret_cast<const uint8_t*>(m_iter.fragment.bytes), m_iter.fragment.size, output, output_size, result.bytesPerLine())) #else if (!WebPDecodeARGBInto( reinterpret_cast<const uint8_t*>(m_iter.fragment.bytes), m_iter.fragment.size, output, output_size, result.bytesPerLine())) #endif return false; *image = result; return true; }
bool QWebpHandler::write(const QImage &image) { if (image.isNull()) { qWarning() << "source image is null."; return false; } QImage srcImage = image; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN if (srcImage.format() != QImage::Format_ARGB32) srcImage = srcImage.convertToFormat(QImage::Format_ARGB32); #else /* Q_BIG_ENDIAN */ if (srcImage.format() != QImage::Format_RGBA8888) srcImage = srcImage.convertToFormat(QImage::Format_RGBA8888); #endif WebPPicture picture; WebPConfig config; if (!WebPPictureInit(&picture) || !WebPConfigInit(&config)) { qWarning() << "failed to init webp picture and config"; return false; } picture.width = srcImage.width(); picture.height = srcImage.height(); picture.use_argb = 1; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN if (!WebPPictureImportBGRA(&picture, srcImage.bits(), srcImage.bytesPerLine())) { #else /* Q_BIG_ENDIAN */ if (!WebPPictureImportRGBA(&picture, srcImage.bits(), srcImage.bytesPerLine())) { #endif qWarning() << "failed to import image data to webp picture."; WebPPictureFree(&picture); return false; } config.lossless = m_lossless; config.quality = m_quality; picture.writer = pictureWriter; picture.custom_ptr = device(); if (!WebPEncode(&config, &picture)) { qWarning() << "failed to encode webp picture, error code: " << picture.error_code; WebPPictureFree(&picture); return false; } WebPPictureFree(&picture); return true; } QVariant QWebpHandler::option(ImageOption option) const { if (!supportsOption(option) || !ensureScanned()) return QVariant(); switch (option) { case Quality: return m_quality; case Size: return QSize(m_width, m_height); case Animation: return (m_flags & ANIMATION_FLAG) == ANIMATION_FLAG; default: return QVariant(); } } void QWebpHandler::setOption(ImageOption option, const QVariant &value) { switch (option) { case Quality: m_quality = qBound(0, value.toInt(), 100); m_lossless = (m_quality >= 100); return; default: break; } return QImageIOHandler::setOption(option, value); } bool QWebpHandler::supportsOption(ImageOption option) const { return option == Quality || option == Size || option == Animation; } QByteArray QWebpHandler::name() const { return QByteArrayLiteral("webp"); } int QWebpHandler::imageCount() const { if (!ensureScanned()) return 0; if ((m_flags & ANIMATION_FLAG) == 0) return 1; return m_frameCount; } int QWebpHandler::currentImageNumber() const { if (!ensureScanned()) return 0; return m_iter.frame_num; } QRect QWebpHandler::currentImageRect() const { if (!ensureScanned()) return QRect(); return QRect(m_iter.x_offset, m_iter.y_offset, m_iter.width, m_iter.height); } bool QWebpHandler::jumpToImage(int imageNumber) { if (!ensureScanned()) return false; WebPDemuxReleaseIterator(&m_iter); return WebPDemuxGetFrame(m_demuxer, imageNumber, &m_iter); } bool QWebpHandler::jumpToNextImage() { if (!ensureScanned()) return false; return WebPDemuxNextFrame(&m_iter); } int QWebpHandler::loopCount() const { if (!ensureScanned() || (m_flags & ANIMATION_FLAG) == 0) return 0; return m_loop; } int QWebpHandler::nextImageDelay() const { if (!ensureScanned()) return 0; return m_iter.duration; }