static int EncodeLossless(const uint8_t* const data, int width, int height, int effort_level, // in [0..6] range VP8BitWriter* const bw, WebPAuxStats* const stats) { int ok = 0; WebPConfig config; WebPPicture picture; VP8LBitWriter tmp_bw; WebPPictureInit(&picture); picture.width = width; picture.height = height; picture.use_argb = 1; picture.stats = stats; if (!WebPPictureAlloc(&picture)) return 0; // Transfer the alpha values to the green channel. { int i, j; uint32_t* dst = picture.argb; const uint8_t* src = data; for (j = 0; j < picture.height; ++j) { for (i = 0; i < picture.width; ++i) { dst[i] = (src[i] << 8) | 0xff000000u; } src += width; dst += picture.argb_stride; } } WebPConfigInit(&config); config.lossless = 1; config.method = effort_level; // impact is very small // Set moderate default quality setting for alpha. Higher qualities (80 and // above) could be very slow. config.quality = 10.f + 15.f * effort_level; if (config.quality > 100.f) config.quality = 100.f; ok = VP8LBitWriterInit(&tmp_bw, (width * height) >> 3); ok = ok && (VP8LEncodeStream(&config, &picture, &tmp_bw) == VP8_ENC_OK); WebPPictureFree(&picture); if (ok) { const uint8_t* const data = VP8LBitWriterFinish(&tmp_bw); const size_t data_size = VP8LBitWriterNumBytes(&tmp_bw); VP8BitWriterAppend(bw, data, data_size); } VP8LBitWriterDestroy(&tmp_bw); return ok && !bw->error_; }
// This function always returns an initialized 'bw' object, even upon error. static int EncodeAlphaInternal(const uint8_t* const data, int width, int height, int method, int filter, int reduce_levels, int effort_level, // in [0..6] range uint8_t* const tmp_alpha, FilterTrial* result) { int ok = 0; const uint8_t* alpha_src; WebPFilterFunc filter_func; uint8_t header; const size_t data_size = width * height; const uint8_t* output = NULL; size_t output_size = 0; VP8LBitWriter tmp_bw; assert((uint64_t)data_size == (uint64_t)width * height); // as per spec assert(filter >= 0 && filter < WEBP_FILTER_LAST); assert(method >= ALPHA_NO_COMPRESSION); assert(method <= ALPHA_LOSSLESS_COMPRESSION); assert(sizeof(header) == ALPHA_HEADER_LEN); // TODO(skal): have a common function and #define's to validate alpha params. filter_func = WebPFilters[filter]; if (filter_func != NULL) { filter_func(data, width, height, width, tmp_alpha); alpha_src = tmp_alpha; } else { alpha_src = data; } if (method != ALPHA_NO_COMPRESSION) { ok = VP8LBitWriterInit(&tmp_bw, data_size >> 3); ok = ok && EncodeLossless(alpha_src, width, height, effort_level, &tmp_bw, &result->stats); if (ok) { output = VP8LBitWriterFinish(&tmp_bw); output_size = VP8LBitWriterNumBytes(&tmp_bw); if (output_size > data_size) { // compressed size is larger than source! Revert to uncompressed mode. method = ALPHA_NO_COMPRESSION; VP8LBitWriterDestroy(&tmp_bw); } } else { VP8LBitWriterDestroy(&tmp_bw); return 0; } }