mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-26 13:48:21 +01: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:
parent
00c3c4e114
commit
5da185522b
15
README
15
README
@ -262,19 +262,20 @@ Use following options to convert into alternate image formats:
|
||||
-yuv ......... save the raw YUV samples in flat layout
|
||||
|
||||
Other options are:
|
||||
-version .... print version number and exit.
|
||||
-nofancy ..... don't use the fancy YUV420 upscaler.
|
||||
-nofilter .... disable in-loop filtering.
|
||||
-nodither .... disable dithering.
|
||||
-version .... print version number and exit
|
||||
-nofancy ..... don't use the fancy YUV420 upscaler
|
||||
-nofilter .... disable in-loop filtering
|
||||
-nodither .... disable dithering
|
||||
-dither <d> .. dithering strength (in 0..100)
|
||||
-mt .......... use multi-threading
|
||||
-crop <x> <y> <w> <h> ... crop output with the given rectangle
|
||||
-scale <w> <h> .......... scale the output (*after* any cropping)
|
||||
-alpha ....... only save the alpha plane.
|
||||
-flip ........ flip the output vertically
|
||||
-alpha ....... only save the alpha plane
|
||||
-incremental . use incremental decoding (useful for tests)
|
||||
-h ....... this help message.
|
||||
-h ....... this help message
|
||||
-v ....... verbose (e.g. print encoding/decoding times)
|
||||
-noasm ....... disable all assembly optimizations.
|
||||
-noasm ....... disable all assembly optimizations
|
||||
|
||||
Visualization tool:
|
||||
===================
|
||||
|
@ -552,20 +552,21 @@ static void Help(void) {
|
||||
" -yuv ......... save the raw YUV samples in flat layout\n"
|
||||
"\n"
|
||||
" Other options are:\n"
|
||||
" -version .... print version number and exit.\n"
|
||||
" -nofancy ..... don't use the fancy YUV420 upscaler.\n"
|
||||
" -nofilter .... disable in-loop filtering.\n"
|
||||
" -nodither .... disable dithering.\n"
|
||||
" -version .... print version number and exit\n"
|
||||
" -nofancy ..... don't use the fancy YUV420 upscaler\n"
|
||||
" -nofilter .... disable in-loop filtering\n"
|
||||
" -nodither .... disable dithering\n"
|
||||
" -dither <d> .. dithering strength (in 0..100)\n"
|
||||
" -mt .......... use multi-threading\n"
|
||||
" -crop <x> <y> <w> <h> ... crop output with the given rectangle\n"
|
||||
" -scale <w> <h> .......... scale the output (*after* any cropping)\n"
|
||||
" -alpha ....... only save the alpha plane.\n"
|
||||
" -flip ........ flip the output vertically\n"
|
||||
" -alpha ....... only save the alpha plane\n"
|
||||
" -incremental . use incremental decoding (useful for tests)\n"
|
||||
" -h ....... this help message.\n"
|
||||
" -h ....... this help message\n"
|
||||
" -v ....... verbose (e.g. print encoding/decoding times)\n"
|
||||
#ifndef WEBP_DLL
|
||||
" -noasm ....... disable all assembly optimizations.\n"
|
||||
" -noasm ....... disable all assembly optimizations\n"
|
||||
#endif
|
||||
);
|
||||
}
|
||||
@ -641,6 +642,8 @@ int main(int argc, const char *argv[]) {
|
||||
config.options.use_scaling = 1;
|
||||
config.options.scaled_width = strtol(argv[++c], NULL, 0);
|
||||
config.options.scaled_height = strtol(argv[++c], NULL, 0);
|
||||
} else if (!strcmp(argv[c], "-flip")) {
|
||||
config.options.flip = 1;
|
||||
} else if (!strcmp(argv[c], "-v")) {
|
||||
verbose = 1;
|
||||
#ifndef WEBP_DLL
|
||||
|
@ -1,5 +1,5 @@
|
||||
.\" Hey, EMACS: -*- nroff -*-
|
||||
.TH DWEBP 1 "December 12, 2013"
|
||||
.TH DWEBP 1 "January 11, 2014"
|
||||
.SH NAME
|
||||
dwebp \- decompress a WebP file to an image file
|
||||
.SH SYNOPSIS
|
||||
@ -76,6 +76,9 @@ The top-left corner will be snapped to even coordinates if needed.
|
||||
This option is meant to reduce the memory needed for cropping large images.
|
||||
Note: the cropping is applied \fIbefore\fP any scaling.
|
||||
.TP
|
||||
.B \-flip
|
||||
Flip decoded image vertically (can be useful for OpenGL textures for instance).
|
||||
.TP
|
||||
.BI \-scale " width height
|
||||
Rescale the decoded picture to dimension \fBwidth\fP x \fBheight\fP. This
|
||||
option is mostly intended to reducing the memory needed to decode large images,
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user