#include "src/webp/encode.h"
#include <assert.h>
#include <stdlib.h>
#include "src/enc/vp8i_enc.h"
#if !defined(WEBP_REDUCE_SIZE)
#include "src/utils/rescaler_utils.h"
#include "src/utils/utils.h"
#endif
#define HALVE(x) …
static void PictureGrabSpecs(const WebPPicture* const src,
WebPPicture* const dst) { … }
static void SnapTopLeftPosition(const WebPPicture* const pic,
int* const left, int* const top) { … }
static int AdjustAndCheckRectangle(const WebPPicture* const pic,
int* const left, int* const top,
int width, int height) { … }
#if !defined(WEBP_REDUCE_SIZE)
int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) {
if (src == NULL || dst == NULL) return 0;
if (src == dst) return 1;
PictureGrabSpecs(src, dst);
if (!WebPPictureAlloc(dst)) return 0;
if (!src->use_argb) {
WebPCopyPlane(src->y, src->y_stride,
dst->y, dst->y_stride, dst->width, dst->height);
WebPCopyPlane(src->u, src->uv_stride, dst->u, dst->uv_stride,
HALVE(dst->width), HALVE(dst->height));
WebPCopyPlane(src->v, src->uv_stride, dst->v, dst->uv_stride,
HALVE(dst->width), HALVE(dst->height));
if (dst->a != NULL) {
WebPCopyPlane(src->a, src->a_stride,
dst->a, dst->a_stride, dst->width, dst->height);
}
} else {
WebPCopyPlane((const uint8_t*)src->argb, 4 * src->argb_stride,
(uint8_t*)dst->argb, 4 * dst->argb_stride,
4 * dst->width, dst->height);
}
return 1;
}
#endif
int WebPPictureIsView(const WebPPicture* picture) { … }
int WebPPictureView(const WebPPicture* src,
int left, int top, int width, int height,
WebPPicture* dst) { … }
#if !defined(WEBP_REDUCE_SIZE)
int WebPPictureCrop(WebPPicture* pic,
int left, int top, int width, int height) {
WebPPicture tmp;
if (pic == NULL) return 0;
if (!AdjustAndCheckRectangle(pic, &left, &top, width, height)) return 0;
PictureGrabSpecs(pic, &tmp);
tmp.width = width;
tmp.height = height;
if (!WebPPictureAlloc(&tmp)) {
return WebPEncodingSetError(pic, tmp.error_code);
}
if (!pic->use_argb) {
const int y_offset = top * pic->y_stride + left;
const int uv_offset = (top / 2) * pic->uv_stride + left / 2;
WebPCopyPlane(pic->y + y_offset, pic->y_stride,
tmp.y, tmp.y_stride, width, height);
WebPCopyPlane(pic->u + uv_offset, pic->uv_stride,
tmp.u, tmp.uv_stride, HALVE(width), HALVE(height));
WebPCopyPlane(pic->v + uv_offset, pic->uv_stride,
tmp.v, tmp.uv_stride, HALVE(width), HALVE(height));
if (tmp.a != NULL) {
const int a_offset = top * pic->a_stride + left;
WebPCopyPlane(pic->a + a_offset, pic->a_stride,
tmp.a, tmp.a_stride, width, height);
}
} else {
const uint8_t* const src =
(const uint8_t*)(pic->argb + top * pic->argb_stride + left);
WebPCopyPlane(src, pic->argb_stride * 4, (uint8_t*)tmp.argb,
tmp.argb_stride * 4, width * 4, height);
}
WebPPictureFree(pic);
*pic = tmp;
return 1;
}
static int RescalePlane(const uint8_t* src,
int src_width, int src_height, int src_stride,
uint8_t* dst,
int dst_width, int dst_height, int dst_stride,
rescaler_t* const work,
int num_channels) {
WebPRescaler rescaler;
int y = 0;
if (!WebPRescalerInit(&rescaler, src_width, src_height,
dst, dst_width, dst_height, dst_stride,
num_channels, work)) {
return 0;
}
while (y < src_height) {
y += WebPRescalerImport(&rescaler, src_height - y,
src + y * src_stride, src_stride);
WebPRescalerExport(&rescaler);
}
return 1;
}
static void AlphaMultiplyARGB(WebPPicture* const pic, int inverse) {
assert(pic->argb != NULL);
WebPMultARGBRows((uint8_t*)pic->argb, pic->argb_stride * sizeof(*pic->argb),
pic->width, pic->height, inverse);
}
static void AlphaMultiplyY(WebPPicture* const pic, int inverse) {
if (pic->a != NULL) {
WebPMultRows(pic->y, pic->y_stride, pic->a, pic->a_stride,
pic->width, pic->height, inverse);
}
}
int WebPPictureRescale(WebPPicture* picture, int width, int height) {
WebPPicture tmp;
int prev_width, prev_height;
rescaler_t* work;
if (picture == NULL) return 0;
prev_width = picture->width;
prev_height = picture->height;
if (!WebPRescalerGetScaledDimensions(
prev_width, prev_height, &width, &height)) {
return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
}
PictureGrabSpecs(picture, &tmp);
tmp.width = width;
tmp.height = height;
if (!WebPPictureAlloc(&tmp)) {
return WebPEncodingSetError(picture, tmp.error_code);
}
if (!picture->use_argb) {
work = (rescaler_t*)WebPSafeMalloc(2ULL * width, sizeof(*work));
if (work == NULL) {
WebPPictureFree(&tmp);
return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
if (picture->a != NULL) {
WebPInitAlphaProcessing();
if (!RescalePlane(picture->a, prev_width, prev_height, picture->a_stride,
tmp.a, width, height, tmp.a_stride, work, 1)) {
return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
}
}
AlphaMultiplyY(picture, 0);
if (!RescalePlane(picture->y, prev_width, prev_height, picture->y_stride,
tmp.y, width, height, tmp.y_stride, work, 1) ||
!RescalePlane(picture->u, HALVE(prev_width), HALVE(prev_height),
picture->uv_stride, tmp.u, HALVE(width), HALVE(height),
tmp.uv_stride, work, 1) ||
!RescalePlane(picture->v, HALVE(prev_width), HALVE(prev_height),
picture->uv_stride, tmp.v, HALVE(width), HALVE(height),
tmp.uv_stride, work, 1)) {
return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
}
AlphaMultiplyY(&tmp, 1);
} else {
work = (rescaler_t*)WebPSafeMalloc(2ULL * width * 4, sizeof(*work));
if (work == NULL) {
WebPPictureFree(&tmp);
return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
WebPInitAlphaProcessing();
AlphaMultiplyARGB(picture, 0);
if (!RescalePlane((const uint8_t*)picture->argb, prev_width, prev_height,
picture->argb_stride * 4, (uint8_t*)tmp.argb, width,
height, tmp.argb_stride * 4, work, 4)) {
return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
}
AlphaMultiplyARGB(&tmp, 1);
}
WebPPictureFree(picture);
WebPSafeFree(work);
*picture = tmp;
return 1;
}
#else
int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) { … }
int WebPPictureCrop(WebPPicture* pic,
int left, int top, int width, int height) { … }
int WebPPictureRescale(WebPPicture* pic, int width, int height) { … }
#endif