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; }
/** Encode a FIBITMAP to a WebP image @param hmem Memory output stream, containing on return the encoded image @param dib The FIBITMAP to encode @param flags FreeImage save flags @return Returns TRUE if successfull, returns FALSE otherwise */ static BOOL EncodeImage(FIMEMORY *hmem, FIBITMAP *dib, int flags) { WebPPicture picture; // Input buffer WebPConfig config; // Coding parameters BOOL bIsFlipped = FALSE; try { const unsigned width = FreeImage_GetWidth(dib); const unsigned height = FreeImage_GetHeight(dib); const unsigned bpp = FreeImage_GetBPP(dib); const unsigned pitch = FreeImage_GetPitch(dib); // check image type FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); if( !((image_type == FIT_BITMAP) && ((bpp == 24) || (bpp == 32))) ) { throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } // check format limits if(MAX(width, height) > WEBP_MAX_DIMENSION) { FreeImage_OutputMessageProc(s_format_id, "Unsupported image size: width x height = %d x %d", width, height); return FALSE; } // Initialize output I/O if(WebPPictureInit(&picture) == 1) { picture.writer = WebP_MemoryWriter; picture.custom_ptr = hmem; picture.width = (int)width; picture.height = (int)height; } else { throw "Couldn't initialize WebPPicture"; } // --- Set encoding parameters --- // Initialize encoding parameters to default values WebPConfigInit(&config); // quality/speed trade-off (0=fast, 6=slower-better) config.method = 6; if((flags & WEBP_LOSSLESS) == WEBP_LOSSLESS) { // lossless encoding config.lossless = 1; picture.use_argb = 1; } else if((flags & 0x7F) > 0) { // lossy encoding config.lossless = 0; // quality is between 1 (smallest file) and 100 (biggest) - default to 75 config.quality = (float)(flags & 0x7F); if(config.quality > 100) { config.quality = 100; } } // validate encoding parameters if(WebPValidateConfig(&config) == 0) { throw "Failed to initialize encoder"; } // --- Perform encoding --- // Invert dib scanlines bIsFlipped = FreeImage_FlipVertical(dib); // convert dib buffer to output stream const BYTE *bits = FreeImage_GetBits(dib); #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR switch(bpp) { case 24: WebPPictureImportBGR(&picture, bits, pitch); break; case 32: WebPPictureImportBGRA(&picture, bits, pitch); break; } #else switch(bpp) { case 24: WebPPictureImportRGB(&picture, bits, pitch); break; case 32: WebPPictureImportRGBA(&picture, bits, pitch); break; } #endif // FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR if(!WebPEncode(&config, &picture)) { throw "Failed to encode image"; } WebPPictureFree(&picture); if(bIsFlipped) { // invert dib scanlines FreeImage_FlipVertical(dib); } return TRUE; } catch (const char* text) { WebPPictureFree(&picture); if(bIsFlipped) { // invert dib scanlines FreeImage_FlipVertical(dib); } if(NULL != text) { FreeImage_OutputMessageProc(s_format_id, text); } } return FALSE; }
status_t WebPTranslator::_TranslateFromBits(BPositionIO* stream, BMessage* ioExtension, uint32 outType, BPositionIO* target) { if (!outType) outType = WEBP_IMAGE_FORMAT; if (outType != WEBP_IMAGE_FORMAT) return B_NO_TRANSLATOR; TranslatorBitmap bitsHeader; status_t status; status = identify_bits_header(stream, NULL, &bitsHeader); if (status != B_OK) return status; if (bitsHeader.colors == B_CMAP8) { // TODO: support whatever colospace by intermediate colorspace conversion printf("Error! Colorspace not supported\n"); return B_NO_TRANSLATOR; } int32 bitsBytesPerPixel = 0; switch (bitsHeader.colors) { case B_RGB32: case B_RGB32_BIG: case B_RGBA32: case B_RGBA32_BIG: case B_CMY32: case B_CMYA32: case B_CMYK32: bitsBytesPerPixel = 4; break; case B_RGB24: case B_RGB24_BIG: case B_CMY24: bitsBytesPerPixel = 3; break; case B_RGB16: case B_RGB16_BIG: case B_RGBA15: case B_RGBA15_BIG: case B_RGB15: case B_RGB15_BIG: bitsBytesPerPixel = 2; break; case B_CMAP8: case B_GRAY8: bitsBytesPerPixel = 1; break; default: return B_ERROR; } if (bitsBytesPerPixel < 3) { // TODO support return B_NO_TRANSLATOR; } WebPPicture picture; WebPConfig config; if (!WebPPictureInit(&picture) || !WebPConfigInit(&config)) { printf("Error! Version mismatch!\n"); return B_ERROR; } WebPPreset preset = (WebPPreset)fSettings->SetGetInt32(WEBP_SETTING_PRESET); config.quality = (float)fSettings->SetGetInt32(WEBP_SETTING_QUALITY); if (!WebPConfigPreset(&config, (WebPPreset)preset, config.quality)) { printf("Error! Could initialize configuration with preset."); return B_ERROR; } config.method = fSettings->SetGetInt32(WEBP_SETTING_METHOD); config.preprocessing = fSettings->SetGetBool(WEBP_SETTING_PREPROCESSING); if (!WebPValidateConfig(&config)) { printf("Error! Invalid configuration.\n"); return B_ERROR; } picture.width = bitsHeader.bounds.IntegerWidth() + 1; picture.height = bitsHeader.bounds.IntegerHeight() + 1; int stride = bitsHeader.rowBytes; int bitsSize = picture.height * stride; uint8* bits = (uint8*)malloc(bitsSize); if (bits == NULL) return B_NO_MEMORY; if (stream->Read(bits, bitsSize) != bitsSize) { free(bits); return B_IO_ERROR; } if (!WebPPictureImportBGRA(&picture, bits, stride)) { printf("Error! WebPEncode() failed!\n"); free(bits); return B_ERROR; } free(bits); picture.writer = _EncodedWriter; picture.custom_ptr = target; picture.stats = NULL; if (!WebPEncode(&config, &picture)) { printf("Error! WebPEncode() failed!\n"); status = B_NO_TRANSLATOR; } else status = B_OK; WebPPictureFree(&picture); return status; }