mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-19 20:08:28 +01:00
cleanup WebPPicture struct and API
* add a real proper pointer for holding memory chunk pointer (instead of using y and argb fields) * polish the doc with details * add a WebPPictureView() that extract a view from a picture without any copy (kind of a fast-crop). * properly snap the top-left corner for Crop/View. Previously, the luma position was not snapped, and was off compared to the chroma. Change-Id: I8a3620c7f5fc6f7d1f8dd89d9da167c91e237439
This commit is contained in:
parent
9144a18643
commit
31b68fe639
@ -1023,9 +1023,12 @@ int main(int argc, const char *argv[]) {
|
||||
if (verbose) {
|
||||
StopwatchReadAndReset(&stop_watch);
|
||||
}
|
||||
if (crop != 0 && !WebPPictureCrop(&picture, crop_x, crop_y, crop_w, crop_h)) {
|
||||
fprintf(stderr, "Error! Cannot crop picture\n");
|
||||
goto Error;
|
||||
if (crop != 0) {
|
||||
// We use self-cropping using a view.
|
||||
if (!WebPPictureView(&picture, crop_x, crop_y, crop_w, crop_h, &picture)) {
|
||||
fprintf(stderr, "Error! Cannot crop picture\n");
|
||||
goto Error;
|
||||
}
|
||||
}
|
||||
if ((resize_w | resize_h) > 0) {
|
||||
if (!WebPPictureRescale(&picture, resize_w, resize_h)) {
|
||||
|
@ -21,6 +21,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#define HALVE(x) (((x) + 1) >> 1)
|
||||
#define IS_YUV_CSP(csp, YUV_CSP) (((csp) & WEBP_CSP_UV_MASK) == (YUV_CSP))
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// WebPPicture
|
||||
@ -86,6 +87,9 @@ int WebPPictureAlloc(WebPPicture* const picture) {
|
||||
mem = (uint8_t*)malloc((size_t)total_size);
|
||||
if (mem == NULL) return 0;
|
||||
|
||||
picture->memory_ = (void*)mem;
|
||||
|
||||
// TODO(skal): we could align the y/u/v planes and adjust stride.
|
||||
picture->y = mem;
|
||||
mem += y_size;
|
||||
|
||||
@ -105,6 +109,7 @@ int WebPPictureAlloc(WebPPicture* const picture) {
|
||||
mem += uv0_size;
|
||||
}
|
||||
} else {
|
||||
void* memory;
|
||||
const uint64_t argb_size = (uint64_t)width * height;
|
||||
const uint64_t total_size = argb_size * sizeof(*picture->argb);
|
||||
if (width <= 0 || height <= 0 ||
|
||||
@ -113,8 +118,12 @@ int WebPPictureAlloc(WebPPicture* const picture) {
|
||||
return 0;
|
||||
}
|
||||
WebPPictureFree(picture); // erase previous buffer
|
||||
picture->argb = (uint32_t*)malloc((size_t)total_size);
|
||||
if (picture->argb == NULL) return 0;
|
||||
memory = malloc((size_t)total_size);
|
||||
if (memory == NULL) return 0;
|
||||
picture->memory_argb_ = memory;
|
||||
|
||||
// TODO(skal): align plane to cache line?
|
||||
picture->argb = (uint32_t*)memory;
|
||||
picture->argb_stride = width;
|
||||
}
|
||||
}
|
||||
@ -125,18 +134,21 @@ int WebPPictureAlloc(WebPPicture* const picture) {
|
||||
// into 'dst'. Mark 'dst' as not owning any memory. 'src' can be NULL.
|
||||
static void WebPPictureGrabSpecs(const WebPPicture* const src,
|
||||
WebPPicture* const dst) {
|
||||
assert(dst != NULL);
|
||||
if (src != NULL) *dst = *src;
|
||||
dst->y = dst->u = dst->v = NULL;
|
||||
dst->u0 = dst->v0 = NULL;
|
||||
dst->a = NULL;
|
||||
dst->argb = NULL;
|
||||
dst->memory_ = NULL;
|
||||
dst->memory_argb_ = NULL;
|
||||
}
|
||||
|
||||
// Release memory owned by 'picture'.
|
||||
void WebPPictureFree(WebPPicture* const picture) {
|
||||
if (picture != NULL) {
|
||||
free(picture->y);
|
||||
free(picture->argb);
|
||||
free(picture->memory_);
|
||||
free(picture->memory_argb_);
|
||||
WebPPictureGrabSpecs(NULL, picture);
|
||||
}
|
||||
}
|
||||
@ -154,6 +166,30 @@ static void CopyPlane(const uint8_t* src, int src_stride,
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust top-left corner to chroma sample position.
|
||||
static void SnapTopLeftPosition(const WebPPicture* const pic,
|
||||
int* const left, int* const top) {
|
||||
if (!pic->use_argb_input) {
|
||||
const int is_yuv422 = IS_YUV_CSP(pic->colorspace, WEBP_YUV422);
|
||||
if (IS_YUV_CSP(pic->colorspace, WEBP_YUV420) || is_yuv422) {
|
||||
*left &= ~1;
|
||||
if (!is_yuv422) *top &= ~1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust top-left corner and verify that the sub-rectangle is valid.
|
||||
static int AdjustAndCheckRectangle(const WebPPicture* const pic,
|
||||
int* const left, int* const top,
|
||||
int width, int height) {
|
||||
SnapTopLeftPosition(pic, left, top);
|
||||
if ((*left) < 0 || (*top) < 0) return 0;
|
||||
if (width <= 0 || height <= 0) return 0;
|
||||
if ((*left) + width > pic->width) return 0;
|
||||
if ((*top) + height > pic->height) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WebPPictureCopy(const WebPPicture* const src, WebPPicture* const dst) {
|
||||
if (src == NULL || dst == NULL) return 0;
|
||||
if (src == dst) return 1;
|
||||
@ -175,7 +211,7 @@ int WebPPictureCopy(const WebPPicture* const src, WebPPicture* const dst) {
|
||||
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||
if (dst->u0 != NULL) {
|
||||
int uv0_width = src->width;
|
||||
if ((dst->colorspace & WEBP_CSP_UV_MASK) == WEBP_YUV422) {
|
||||
if (IS_YUV_CSP(dst->colorspace, WEBP_YUV422)) {
|
||||
uv0_width = HALVE(uv0_width);
|
||||
}
|
||||
CopyPlane(src->u0, src->uv0_stride,
|
||||
@ -192,6 +228,48 @@ int WebPPictureCopy(const WebPPicture* const src, WebPPicture* const dst) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WebPPictureIsView(const WebPPicture* const picture) {
|
||||
if (picture == NULL) return 0;
|
||||
if (picture->use_argb_input) {
|
||||
return (picture->memory_argb_ == NULL);
|
||||
}
|
||||
return (picture->memory_ == NULL);
|
||||
}
|
||||
|
||||
int WebPPictureView(const WebPPicture* const src,
|
||||
int left, int top, int width, int height,
|
||||
WebPPicture* const dst) {
|
||||
if (src == NULL || dst == NULL) return 0;
|
||||
|
||||
// verify rectangle position.
|
||||
if (!AdjustAndCheckRectangle(src, &left, &top, width, height)) return 0;
|
||||
|
||||
if (src != dst) { // beware of aliasing! We don't want to leak 'memory_'.
|
||||
WebPPictureGrabSpecs(src, dst);
|
||||
}
|
||||
dst->width = width;
|
||||
dst->height = height;
|
||||
if (!src->use_argb_input) {
|
||||
dst->y = src->y + top * src->y_stride + left;
|
||||
dst->u = src->u + (top >> 1) * src->uv_stride + (left >> 1);
|
||||
dst->v = src->v + (top >> 1) * src->uv_stride + (left >> 1);
|
||||
if (src->a != NULL) {
|
||||
dst->a = src->a + top * src->a_stride + left;
|
||||
}
|
||||
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||
if (src->u0 != NULL) {
|
||||
const int left_pos =
|
||||
IS_YUV_CSP(dst->colorspace, WEBP_YUV422) ? (left >> 1) : left;
|
||||
dst->u0 = src->u0 + top * src->uv0_stride + left_pos;
|
||||
dst->v0 = src->v0 + top * src->uv0_stride + left_pos;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
dst->argb = src->argb + top * src->argb_stride + left;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Picture cropping
|
||||
|
||||
@ -200,9 +278,7 @@ int WebPPictureCrop(WebPPicture* const pic,
|
||||
WebPPicture tmp;
|
||||
|
||||
if (pic == NULL) return 0;
|
||||
if (width <= 0 || height <= 0) return 0;
|
||||
if (left < 0 || ((left + width + 1) & ~1) > pic->width) return 0;
|
||||
if (top < 0 || ((top + height + 1) & ~1) > pic->height) return 0;
|
||||
if (!AdjustAndCheckRectangle(pic, &left, &top, width, height)) return 0;
|
||||
|
||||
WebPPictureGrabSpecs(pic, &tmp);
|
||||
tmp.width = width;
|
||||
@ -227,15 +303,15 @@ int WebPPictureCrop(WebPPicture* const pic,
|
||||
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||
if (tmp.u0 != NULL) {
|
||||
int w = width;
|
||||
int l = left;
|
||||
if (tmp.colorspace == WEBP_YUV422) {
|
||||
int left_pos = left;
|
||||
if (IS_YUV_CSP(tmp.colorspace, WEBP_YUV422)) {
|
||||
w = HALVE(w);
|
||||
l = HALVE(l);
|
||||
left_pos = HALVE(left_pos);
|
||||
}
|
||||
CopyPlane(pic->u0 + top * pic->uv0_stride + l, pic->uv0_stride,
|
||||
tmp.u0, tmp.uv0_stride, w, l);
|
||||
CopyPlane(pic->v0 + top * pic->uv0_stride + l, pic->uv0_stride,
|
||||
tmp.v0, tmp.uv0_stride, w, l);
|
||||
CopyPlane(pic->u0 + top * pic->uv0_stride + left_pos, pic->uv0_stride,
|
||||
tmp.u0, tmp.uv0_stride, w, height);
|
||||
CopyPlane(pic->v0 + top * pic->uv0_stride + left_pos, pic->uv0_stride,
|
||||
tmp.v0, tmp.uv0_stride, w, height);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
@ -323,10 +399,7 @@ int WebPPictureRescale(WebPPicture* const pic, int width, int height) {
|
||||
}
|
||||
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||
if (tmp.u0 != NULL) {
|
||||
int s = 1;
|
||||
if ((tmp.colorspace & WEBP_CSP_UV_MASK) == WEBP_YUV422) {
|
||||
s = 2;
|
||||
}
|
||||
const int s = IS_YUV_CSP(tmp.colorspace, WEBP_YUV422) ? 2 : 1;
|
||||
RescalePlane(
|
||||
pic->u0, (prev_width + s / 2) / s, prev_height, pic->uv0_stride,
|
||||
tmp.u0, (width + s / 2) / s, height, tmp.uv0_stride, work, 1);
|
||||
|
@ -95,8 +95,8 @@ WEBP_EXTERN(int) WebPConfigInitInternal(
|
||||
WebPConfig* const, WebPPreset, float, int);
|
||||
|
||||
// Should always be called, to initialize a fresh WebPConfig structure before
|
||||
// modification. Returns 0 in case of version mismatch. WebPConfigInit() must
|
||||
// have succeeded before using the 'config' object.
|
||||
// modification. Returns false in case of version mismatch. WebPConfigInit()
|
||||
// must have succeeded before using the 'config' object.
|
||||
static WEBP_INLINE int WebPConfigInit(WebPConfig* const config) {
|
||||
return WebPConfigInitInternal(config, WEBP_PRESET_DEFAULT, 75.f,
|
||||
WEBP_ENCODER_ABI_VERSION);
|
||||
@ -105,14 +105,15 @@ static WEBP_INLINE int WebPConfigInit(WebPConfig* const config) {
|
||||
// This function will initialize the configuration according to a predefined
|
||||
// set of parameters (referred to by 'preset') and a given quality factor.
|
||||
// This function can be called as a replacement to WebPConfigInit(). Will
|
||||
// return 0 in case of error.
|
||||
// return false in case of error.
|
||||
static WEBP_INLINE int WebPConfigPreset(WebPConfig* const config,
|
||||
WebPPreset preset, float quality) {
|
||||
return WebPConfigInitInternal(config, preset, quality,
|
||||
WEBP_ENCODER_ABI_VERSION);
|
||||
}
|
||||
|
||||
// Returns 1 if all parameters are in valid range and the configuration is OK.
|
||||
// Returns true if 'config' is non-NULL and all configuration parameters are
|
||||
// within their valid ranges.
|
||||
WEBP_EXTERN(int) WebPValidateConfig(const WebPConfig* const config);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -140,7 +141,7 @@ typedef struct {
|
||||
// used during callbacks (like progress-report e.g.).
|
||||
} WebPAuxStats;
|
||||
|
||||
// Signature for output function. Should return 1 if writing was successful.
|
||||
// Signature for output function. Should return true if writing was successful.
|
||||
// data/data_size is the segment of data to write, and 'picture' is for
|
||||
// reference (and so one can make use of picture->custom_ptr).
|
||||
typedef int (*WebPWriterFunction)(const uint8_t* data, size_t data_size,
|
||||
@ -162,8 +163,9 @@ WEBP_EXTERN(void) WebPMemoryWriterInit(WebPMemoryWriter* const writer);
|
||||
WEBP_EXTERN(int) WebPMemoryWrite(const uint8_t* data, size_t data_size,
|
||||
const WebPPicture* const picture);
|
||||
|
||||
// Progress hook, called from time to time to report progress. It can return 0
|
||||
// to request an abort of the encoding process, or 1 otherwise if all is OK.
|
||||
// Progress hook, called from time to time to report progress. It can return
|
||||
// false to request an abort of the encoding process, or true otherwise if
|
||||
// everything is OK.
|
||||
typedef int (*WebPProgressHook)(int percent, const WebPPicture* const picture);
|
||||
|
||||
typedef enum {
|
||||
@ -237,13 +239,17 @@ struct WebPPicture {
|
||||
int use_argb_input; // Flag for encoder to use argb pixels as input.
|
||||
uint32_t* argb; // Pointer to argb (32 bit) plane.
|
||||
int argb_stride; // This is stride in pixels units, not bytes.
|
||||
|
||||
// private fields:
|
||||
void* memory_; // row chunk of memory for yuva planes
|
||||
void* memory_argb_; // and for argb too.
|
||||
};
|
||||
|
||||
// Internal, version-checked, entry point
|
||||
WEBP_EXTERN(int) WebPPictureInitInternal(WebPPicture* const, int);
|
||||
|
||||
// Should always be called, to initialize the structure. Returns 0 in case of
|
||||
// version mismatch. WebPPictureInit() must have succeeded before using the
|
||||
// Should always be called, to initialize the structure. Returns false in case
|
||||
// of version mismatch. WebPPictureInit() must have succeeded before using the
|
||||
// 'picture' object.
|
||||
static WEBP_INLINE int WebPPictureInit(WebPPicture* const picture) {
|
||||
return WebPPictureInitInternal(picture, WEBP_ENCODER_ABI_VERSION);
|
||||
@ -255,21 +261,23 @@ static WEBP_INLINE int WebPPictureInit(WebPPicture* const picture) {
|
||||
// Convenience allocation / deallocation based on picture->width/height:
|
||||
// Allocate y/u/v buffers as per colorspace/width/height specification.
|
||||
// Note! This function will free the previous buffer if needed.
|
||||
// Returns 0 in case of memory error.
|
||||
// Returns false in case of memory error.
|
||||
WEBP_EXTERN(int) WebPPictureAlloc(WebPPicture* const picture);
|
||||
|
||||
// Release memory allocated by WebPPictureAlloc() or WebPPictureImport*()
|
||||
// Note that this function does _not_ free the memory pointed to by 'picture'.
|
||||
// Release the memory allocated by WebPPictureAlloc() or WebPPictureImport*().
|
||||
// Note that this function does _not_ free the memory used by the 'picture'
|
||||
// object itself.
|
||||
WEBP_EXTERN(void) WebPPictureFree(WebPPicture* const picture);
|
||||
|
||||
// Copy the pixels of *src into *dst, using WebPPictureAlloc.
|
||||
// Returns 0 in case of memory allocation error.
|
||||
// Copy the pixels of *src into *dst, using WebPPictureAlloc. Upon return,
|
||||
// *dst will fully own the copied pixels (this is not a view).
|
||||
// Returns false in case of memory allocation error.
|
||||
WEBP_EXTERN(int) WebPPictureCopy(const WebPPicture* const src,
|
||||
WebPPicture* const dst);
|
||||
|
||||
// Compute PSNR or SSIM distortion between two pictures.
|
||||
// Result is in dB, stores in result[] in the Y/U/V/Alpha/All order.
|
||||
// Returns 0 in case of error (pic1 and pic2 don't have same dimension, ...)
|
||||
// Returns false in case of error (pic1 and pic2 don't have same dimension, ...)
|
||||
// Warning: this function is rather CPU-intensive.
|
||||
WEBP_EXTERN(int) WebPPictureDistortion(
|
||||
const WebPPicture* const pic1, const WebPPicture* const pic2,
|
||||
@ -277,11 +285,33 @@ WEBP_EXTERN(int) WebPPictureDistortion(
|
||||
float result[5]);
|
||||
|
||||
// self-crops a picture to the rectangle defined by top/left/width/height.
|
||||
// Returns 0 in case of memory allocation error, or if the rectangle is
|
||||
// Returns false in case of memory allocation error, or if the rectangle is
|
||||
// outside of the source picture.
|
||||
// The rectangle for the view is defined by the top-left corner pixel
|
||||
// coordinates (left, top) as well as its width and height. This rectangle
|
||||
// must be fully be comprised inside the 'src' source picture. If the source
|
||||
// picture uses the YUV420 colorspace, the top and left coordinates will be
|
||||
// snapped to even values.
|
||||
WEBP_EXTERN(int) WebPPictureCrop(WebPPicture* const picture,
|
||||
int left, int top, int width, int height);
|
||||
|
||||
// Extracts a view from 'src' picture into 'dst'. The rectangle for the view
|
||||
// is defined by the top-left corner pixel coordinates (left, top) as well
|
||||
// as its width and height. This rectangle must be fully be comprised inside
|
||||
// the 'src' source picture. If the source picture uses the YUV420 colorspace,
|
||||
// the top and left coordinates will be snapped to even values.
|
||||
// Picture 'src' must out-live 'dst' picture. Self-extraction of view is allowed
|
||||
// ('src' equal to 'dst') as a mean of fast-cropping (but note that doing so,
|
||||
// the original dimension will be lost).
|
||||
// Returns false in case of memory allocation error or invalid parameters.
|
||||
WEBP_EXTERN(int) WebPPictureView(const WebPPicture* const src,
|
||||
int left, int top, int width, int height,
|
||||
WebPPicture* const dst);
|
||||
|
||||
// Returns true if the 'picture' is actually a view and therefore does
|
||||
// not own the memory for pixels.
|
||||
WEBP_EXTERN(int) WebPPictureIsView(const WebPPicture* const picture);
|
||||
|
||||
// Rescale a picture to new dimension width x height.
|
||||
// Now gamma correction is applied.
|
||||
// Returns false in case of error (invalid parameter or insufficient memory).
|
||||
@ -291,7 +321,7 @@ WEBP_EXTERN(int) WebPPictureRescale(WebPPicture* const pic,
|
||||
// Colorspace conversion function to import RGB samples.
|
||||
// Previous buffer will be free'd, if any.
|
||||
// *rgb buffer should have a size of at least height * rgb_stride.
|
||||
// Returns 0 in case of memory error.
|
||||
// Returns false in case of memory error.
|
||||
WEBP_EXTERN(int) WebPPictureImportRGB(
|
||||
WebPPicture* const picture, const uint8_t* const rgb, int rgb_stride);
|
||||
// Same, but for RGBA buffer.
|
||||
|
Loading…
Reference in New Issue
Block a user