mirror of
https://github.com/webmproject/libwebp.git
synced 2025-07-13 14:34:33 +02:00
add a decoding option to flip image vertically
New API options: WebPDecoderOptions.flip and 'dwebp -flip ...' it uses negative stride trick. Also changed the decoder code to support user-supplied buffers with negative stride, independently of the WebPDecoderOptions.flip value. Change-Id: I4dc0d06f0c87e51a3f3428be4fee2d6b5ad76053
This commit is contained in:
@ -42,29 +42,34 @@ static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
|
||||
ok = 0;
|
||||
} else if (!WebPIsRGBMode(mode)) { // YUV checks
|
||||
const WebPYUVABuffer* const buf = &buffer->u.YUVA;
|
||||
const uint64_t y_size = (uint64_t)buf->y_stride * height;
|
||||
const uint64_t u_size = (uint64_t)buf->u_stride * ((height + 1) / 2);
|
||||
const uint64_t v_size = (uint64_t)buf->v_stride * ((height + 1) / 2);
|
||||
const uint64_t a_size = (uint64_t)buf->a_stride * height;
|
||||
const int y_stride = abs(buf->y_stride);
|
||||
const int u_stride = abs(buf->u_stride);
|
||||
const int v_stride = abs(buf->v_stride);
|
||||
const int a_stride = abs(buf->a_stride);
|
||||
const uint64_t y_size = (uint64_t)y_stride * height;
|
||||
const uint64_t u_size = (uint64_t)u_stride * ((height + 1) / 2);
|
||||
const uint64_t v_size = (uint64_t)v_stride * ((height + 1) / 2);
|
||||
const uint64_t a_size = (uint64_t)a_stride * height;
|
||||
ok &= (y_size <= buf->y_size);
|
||||
ok &= (u_size <= buf->u_size);
|
||||
ok &= (v_size <= buf->v_size);
|
||||
ok &= (buf->y_stride >= width);
|
||||
ok &= (buf->u_stride >= (width + 1) / 2);
|
||||
ok &= (buf->v_stride >= (width + 1) / 2);
|
||||
ok &= (y_stride >= width);
|
||||
ok &= (u_stride >= (width + 1) / 2);
|
||||
ok &= (v_stride >= (width + 1) / 2);
|
||||
ok &= (buf->y != NULL);
|
||||
ok &= (buf->u != NULL);
|
||||
ok &= (buf->v != NULL);
|
||||
if (mode == MODE_YUVA) {
|
||||
ok &= (buf->a_stride >= width);
|
||||
ok &= (a_stride >= width);
|
||||
ok &= (a_size <= buf->a_size);
|
||||
ok &= (buf->a != NULL);
|
||||
}
|
||||
} else { // RGB checks
|
||||
const WebPRGBABuffer* const buf = &buffer->u.RGBA;
|
||||
const uint64_t size = (uint64_t)buf->stride * height;
|
||||
const int stride = abs(buf->stride);
|
||||
const uint64_t size = (uint64_t)stride * height;
|
||||
ok &= (size <= buf->size);
|
||||
ok &= (buf->stride >= width * kModeBpp[mode]);
|
||||
ok &= (stride >= width * kModeBpp[mode]);
|
||||
ok &= (buf->rgba != NULL);
|
||||
}
|
||||
return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM;
|
||||
@ -131,9 +136,35 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
|
||||
return CheckDecBuffer(buffer);
|
||||
}
|
||||
|
||||
VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer) {
|
||||
if (buffer == NULL) {
|
||||
return VP8_STATUS_INVALID_PARAM;
|
||||
}
|
||||
if (WebPIsRGBMode(buffer->colorspace)) {
|
||||
WebPRGBABuffer* const buf = &buffer->u.RGBA;
|
||||
buf->rgba += (buffer->height - 1) * buf->stride;
|
||||
buf->stride = -buf->stride;
|
||||
} else {
|
||||
WebPYUVABuffer* const buf = &buffer->u.YUVA;
|
||||
const int H = buffer->height;
|
||||
buf->y += (H - 1) * buf->y_stride;
|
||||
buf->y_stride = -buf->y_stride;
|
||||
buf->u += ((H - 1) >> 1) * buf->u_stride;
|
||||
buf->u_stride = -buf->u_stride;
|
||||
buf->v += ((H - 1) >> 1) * buf->v_stride;
|
||||
buf->v_stride = -buf->v_stride;
|
||||
if (buf->a != NULL) {
|
||||
buf->a += (H - 1) * buf->a_stride;
|
||||
buf->a_stride = -buf->a_stride;
|
||||
}
|
||||
}
|
||||
return VP8_STATUS_OK;
|
||||
}
|
||||
|
||||
VP8StatusCode WebPAllocateDecBuffer(int w, int h,
|
||||
const WebPDecoderOptions* const options,
|
||||
WebPDecBuffer* const out) {
|
||||
VP8StatusCode status;
|
||||
if (out == NULL || w <= 0 || h <= 0) {
|
||||
return VP8_STATUS_INVALID_PARAM;
|
||||
}
|
||||
@ -160,8 +191,15 @@ VP8StatusCode WebPAllocateDecBuffer(int w, int h,
|
||||
out->width = w;
|
||||
out->height = h;
|
||||
|
||||
// Then, allocate buffer for real
|
||||
return AllocateBuffer(out);
|
||||
// Then, allocate buffer for real.
|
||||
status = AllocateBuffer(out);
|
||||
if (status != VP8_STATUS_OK) return status;
|
||||
|
||||
// Use the stride trick if vertical flip is needed.
|
||||
if (options != NULL && options->flip) {
|
||||
status = WebPFlipBuffer(out);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -246,6 +246,19 @@ static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// To be called last.
|
||||
static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) {
|
||||
const WebPDecoderOptions* const options = idec->params_.options;
|
||||
WebPDecBuffer* const output = idec->params_.output;
|
||||
|
||||
idec->state_ = STATE_DONE;
|
||||
if (options != NULL && options->flip) {
|
||||
return WebPFlipBuffer(output);
|
||||
} else {
|
||||
return VP8_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Macroblock-decoding contexts
|
||||
|
||||
@ -476,9 +489,7 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
|
||||
return IDecError(idec, VP8_STATUS_USER_ABORT);
|
||||
}
|
||||
dec->ready_ = 0;
|
||||
idec->state_ = STATE_DONE;
|
||||
|
||||
return VP8_STATUS_OK;
|
||||
return FinishDecoding(idec);
|
||||
}
|
||||
|
||||
static VP8StatusCode ErrorStatusLossless(WebPIDecoder* const idec,
|
||||
@ -530,9 +541,7 @@ static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) {
|
||||
return ErrorStatusLossless(idec, dec->status_);
|
||||
}
|
||||
|
||||
idec->state_ = STATE_DONE;
|
||||
|
||||
return VP8_STATUS_OK;
|
||||
return FinishDecoding(idec);
|
||||
}
|
||||
|
||||
// Main decoding loop
|
||||
|
@ -512,6 +512,10 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
|
||||
if (status != VP8_STATUS_OK) {
|
||||
WebPFreeDecBuffer(params->output);
|
||||
}
|
||||
|
||||
if (params->options != NULL && params->options->flip) {
|
||||
status = WebPFlipBuffer(params->output);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -93,10 +93,15 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
|
||||
// dimension / etc.). If *options is not NULL, also verify that the options'
|
||||
// parameters are valid and apply them to the width/height dimensions of the
|
||||
// output buffer. This takes cropping / scaling / rotation into account.
|
||||
// Also incorporates the options->flip flag to flip the buffer parameters if
|
||||
// needed.
|
||||
VP8StatusCode WebPAllocateDecBuffer(int width, int height,
|
||||
const WebPDecoderOptions* const options,
|
||||
WebPDecBuffer* const buffer);
|
||||
|
||||
// Flip buffer vertically by negating the various strides.
|
||||
VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer);
|
||||
|
||||
// Copy 'src' into 'dst' buffer, making sure 'dst' is not marked as owner of the
|
||||
// memory (still held by 'src').
|
||||
void WebPCopyDecBuffer(const WebPDecBuffer* const src,
|
||||
@ -105,8 +110,6 @@ void WebPCopyDecBuffer(const WebPDecBuffer* const src,
|
||||
// Copy and transfer ownership from src to dst (beware of parameter order!)
|
||||
void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst);
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -20,7 +20,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define WEBP_DECODER_ABI_VERSION 0x0203 // MAJOR(8b) + MINOR(8b)
|
||||
#define WEBP_DECODER_ABI_VERSION 0x0204 // MAJOR(8b) + MINOR(8b)
|
||||
|
||||
// Note: forward declaring enumerations is not allowed in (strict) C and C++,
|
||||
// the types are left here for reference.
|
||||
@ -442,11 +442,12 @@ struct WebPDecoderOptions {
|
||||
int scaled_width, scaled_height; // final resolution
|
||||
int use_threads; // if true, use multi-threaded decoding
|
||||
int dithering_strength; // dithering strength (0=Off, 100=full)
|
||||
int flip; // flip output vertically
|
||||
|
||||
// Unused for now:
|
||||
int force_rotation; // forced rotation (to be applied _last_)
|
||||
int no_enhancement; // if true, discard enhancement layer
|
||||
uint32_t pad[5]; // padding for later use
|
||||
uint32_t pad[4]; // padding for later use
|
||||
};
|
||||
|
||||
// Main object storing the configuration for advanced decoding.
|
||||
|
Reference in New Issue
Block a user