1af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// Copyright 2014 Google Inc. All Rights Reserved.
2af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora//
3af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// Use of this source code is governed by a BSD-style license
4af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// that can be found in the COPYING file in the root of the source
5af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// tree. An additional intellectual property rights grant can be found
6af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// in the file PATENTS. All contributing project authors may
7af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// be found in the AUTHORS file in the root of the source tree.
8af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// -----------------------------------------------------------------------------
9af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora//
10af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// WebPPicture tools: copy, crop, rescaling and view.
11af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora//
12af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// Author: Skal (pascal.massimino@gmail.com)
13af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
14af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#include <assert.h>
15af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#include <stdlib.h>
16af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
17af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#include "./vp8enci.h"
18af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#include "../utils/rescaler.h"
19af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#include "../utils/utils.h"
20af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
21af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#define HALVE(x) (((x) + 1) >> 1)
22af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
23af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// Grab the 'specs' (writer, *opaque, width, height...) from 'src' and copy them
24af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// into 'dst'. Mark 'dst' as not owning any memory.
25af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic void PictureGrabSpecs(const WebPPicture* const src,
26af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                             WebPPicture* const dst) {
27af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  assert(src != NULL && dst != NULL);
28af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  *dst = *src;
29af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  WebPPictureResetBuffers(dst);
30af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora}
31af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
32af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora//------------------------------------------------------------------------------
33af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// Picture copying
34af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
35af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic void CopyPlane(const uint8_t* src, int src_stride,
36af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                      uint8_t* dst, int dst_stride, int width, int height) {
37af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  while (height-- > 0) {
38af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    memcpy(dst, src, width);
39af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    src += src_stride;
40af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    dst += dst_stride;
41af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  }
42af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora}
43af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
44af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// Adjust top-left corner to chroma sample position.
45af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic void SnapTopLeftPosition(const WebPPicture* const pic,
46af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                                int* const left, int* const top) {
47af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (!pic->use_argb) {
48af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    *left &= ~1;
49af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    *top &= ~1;
50af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  }
51af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora}
52af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
53af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// Adjust top-left corner and verify that the sub-rectangle is valid.
54af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic int AdjustAndCheckRectangle(const WebPPicture* const pic,
55af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                                   int* const left, int* const top,
56af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                                   int width, int height) {
57af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  SnapTopLeftPosition(pic, left, top);
58af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if ((*left) < 0 || (*top) < 0) return 0;
59af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (width <= 0 || height <= 0) return 0;
60af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if ((*left) + width > pic->width) return 0;
61af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if ((*top) + height > pic->height) return 0;
62af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  return 1;
63af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora}
64af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
65af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Aroraint WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) {
66af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (src == NULL || dst == NULL) return 0;
67af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (src == dst) return 1;
68af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
69af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  PictureGrabSpecs(src, dst);
70af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (!WebPPictureAlloc(dst)) return 0;
71af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
72af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (!src->use_argb) {
73af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    CopyPlane(src->y, src->y_stride,
74af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora              dst->y, dst->y_stride, dst->width, dst->height);
75af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    CopyPlane(src->u, src->uv_stride,
76af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora              dst->u, dst->uv_stride, HALVE(dst->width), HALVE(dst->height));
77af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    CopyPlane(src->v, src->uv_stride,
78af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora              dst->v, dst->uv_stride, HALVE(dst->width), HALVE(dst->height));
79af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    if (dst->a != NULL)  {
80af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora      CopyPlane(src->a, src->a_stride,
81af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                dst->a, dst->a_stride, dst->width, dst->height);
82af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    }
83af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  } else {
84af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    CopyPlane((const uint8_t*)src->argb, 4 * src->argb_stride,
85af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora              (uint8_t*)dst->argb, 4 * dst->argb_stride,
86af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora              4 * dst->width, dst->height);
87af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  }
88af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  return 1;
89af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora}
90af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
91af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Aroraint WebPPictureIsView(const WebPPicture* picture) {
92af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (picture == NULL) return 0;
93af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (picture->use_argb) {
94af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    return (picture->memory_argb_ == NULL);
95af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  }
96af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  return (picture->memory_ == NULL);
97af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora}
98af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
99af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Aroraint WebPPictureView(const WebPPicture* src,
100af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                    int left, int top, int width, int height,
101af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                    WebPPicture* dst) {
102af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (src == NULL || dst == NULL) return 0;
103af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
104af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  // verify rectangle position.
105af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (!AdjustAndCheckRectangle(src, &left, &top, width, height)) return 0;
106af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
107af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (src != dst) {  // beware of aliasing! We don't want to leak 'memory_'.
108af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    PictureGrabSpecs(src, dst);
109af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  }
110af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  dst->width = width;
111af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  dst->height = height;
112af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (!src->use_argb) {
113af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    dst->y = src->y + top * src->y_stride + left;
114af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    dst->u = src->u + (top >> 1) * src->uv_stride + (left >> 1);
115af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    dst->v = src->v + (top >> 1) * src->uv_stride + (left >> 1);
116af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    dst->y_stride = src->y_stride;
117af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    dst->uv_stride = src->uv_stride;
118af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    if (src->a != NULL) {
119af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora      dst->a = src->a + top * src->a_stride + left;
120af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora      dst->a_stride = src->a_stride;
121af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    }
122af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  } else {
123af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    dst->argb = src->argb + top * src->argb_stride + left;
124af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    dst->argb_stride = src->argb_stride;
125af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  }
126af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  return 1;
127af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora}
128af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
129af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora//------------------------------------------------------------------------------
130af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// Picture cropping
131af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
132af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Aroraint WebPPictureCrop(WebPPicture* pic,
133af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                    int left, int top, int width, int height) {
134af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  WebPPicture tmp;
135af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
136af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (pic == NULL) return 0;
137af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (!AdjustAndCheckRectangle(pic, &left, &top, width, height)) return 0;
138af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
139af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  PictureGrabSpecs(pic, &tmp);
140af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  tmp.width = width;
141af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  tmp.height = height;
142af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (!WebPPictureAlloc(&tmp)) return 0;
143af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
144af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (!pic->use_argb) {
145af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    const int y_offset = top * pic->y_stride + left;
146af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    const int uv_offset = (top / 2) * pic->uv_stride + left / 2;
147af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    CopyPlane(pic->y + y_offset, pic->y_stride,
148af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora              tmp.y, tmp.y_stride, width, height);
149af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    CopyPlane(pic->u + uv_offset, pic->uv_stride,
150af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora              tmp.u, tmp.uv_stride, HALVE(width), HALVE(height));
151af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    CopyPlane(pic->v + uv_offset, pic->uv_stride,
152af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora              tmp.v, tmp.uv_stride, HALVE(width), HALVE(height));
153af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
154af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    if (tmp.a != NULL) {
155af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora      const int a_offset = top * pic->a_stride + left;
156af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora      CopyPlane(pic->a + a_offset, pic->a_stride,
157af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                tmp.a, tmp.a_stride, width, height);
158af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    }
159af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  } else {
160af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    const uint8_t* const src =
161af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora        (const uint8_t*)(pic->argb + top * pic->argb_stride + left);
162af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    CopyPlane(src, pic->argb_stride * 4,
163af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora              (uint8_t*)tmp.argb, tmp.argb_stride * 4,
164af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora              width * 4, height);
165af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  }
166af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  WebPPictureFree(pic);
167af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  *pic = tmp;
168af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  return 1;
169af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora}
170af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
171af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora//------------------------------------------------------------------------------
172af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// Simple picture rescaler
173af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
174af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic void RescalePlane(const uint8_t* src,
175af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                         int src_width, int src_height, int src_stride,
176af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                         uint8_t* dst,
177af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                         int dst_width, int dst_height, int dst_stride,
178af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                         int32_t* const work,
179af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                         int num_channels) {
180af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  WebPRescaler rescaler;
181af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  int y = 0;
182af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  WebPRescalerInit(&rescaler, src_width, src_height,
183af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                   dst, dst_width, dst_height, dst_stride,
184af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                   num_channels,
185af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                   src_width, dst_width,
186af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                   src_height, dst_height,
187af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                   work);
188af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  memset(work, 0, 2 * dst_width * num_channels * sizeof(*work));
189af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  while (y < src_height) {
190af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    y += WebPRescalerImport(&rescaler, src_height - y,
191af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                            src + y * src_stride, src_stride);
192af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    WebPRescalerExport(&rescaler);
193af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  }
194af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora}
195af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
196af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic void AlphaMultiplyARGB(WebPPicture* const pic, int inverse) {
197af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  assert(pic->argb != NULL);
198af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  WebPMultARGBRows((uint8_t*)pic->argb, pic->argb_stride * sizeof(*pic->argb),
199af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                   pic->width, pic->height, inverse);
200af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora}
201af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
202af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic void AlphaMultiplyY(WebPPicture* const pic, int inverse) {
203af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (pic->a != NULL) {
204af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    WebPMultRows(pic->y, pic->y_stride, pic->a, pic->a_stride,
205af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                 pic->width, pic->height, inverse);
206af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  }
207af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora}
208af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
209af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Aroraint WebPPictureRescale(WebPPicture* pic, int width, int height) {
210af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  WebPPicture tmp;
211af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  int prev_width, prev_height;
212af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  int32_t* work;
213af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
214af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (pic == NULL) return 0;
215af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  prev_width = pic->width;
216af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  prev_height = pic->height;
217af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  // if width is unspecified, scale original proportionally to height ratio.
218af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (width == 0) {
219af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    width = (prev_width * height + prev_height / 2) / prev_height;
220af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  }
221af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  // if height is unspecified, scale original proportionally to width ratio.
222af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (height == 0) {
223af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    height = (prev_height * width + prev_width / 2) / prev_width;
224af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  }
225af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  // Check if the overall dimensions still make sense.
226af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (width <= 0 || height <= 0) return 0;
227af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
228af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  PictureGrabSpecs(pic, &tmp);
229af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  tmp.width = width;
230af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  tmp.height = height;
231af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (!WebPPictureAlloc(&tmp)) return 0;
232af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
233af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  if (!pic->use_argb) {
234af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    work = (int32_t*)WebPSafeMalloc(2ULL * width, sizeof(*work));
235af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    if (work == NULL) {
236af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora      WebPPictureFree(&tmp);
237af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora      return 0;
238af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    }
239af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    // If present, we need to rescale alpha first (for AlphaMultiplyY).
240af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    if (pic->a != NULL) {
241af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora      WebPInitAlphaProcessing();
242af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora      RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
243af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                   tmp.a, width, height, tmp.a_stride, work, 1);
244af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    }
245af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
246af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    // We take transparency into account on the luma plane only. That's not
247af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    // totally exact blending, but still is a good approximation.
248af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    AlphaMultiplyY(pic, 0);
249af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    RescalePlane(pic->y, prev_width, prev_height, pic->y_stride,
250af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                 tmp.y, width, height, tmp.y_stride, work, 1);
251af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    AlphaMultiplyY(&tmp, 1);
252af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
253af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    RescalePlane(pic->u,
254af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                 HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
255af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                 tmp.u,
256af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                 HALVE(width), HALVE(height), tmp.uv_stride, work, 1);
257af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    RescalePlane(pic->v,
258af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                 HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
259af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                 tmp.v,
260af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                 HALVE(width), HALVE(height), tmp.uv_stride, work, 1);
261af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  } else {
262af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    work = (int32_t*)WebPSafeMalloc(2ULL * width * 4, sizeof(*work));
263af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    if (work == NULL) {
264af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora      WebPPictureFree(&tmp);
265af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora      return 0;
266af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    }
267af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    // In order to correctly interpolate colors, we need to apply the alpha
268af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    // weighting first (black-matting), scale the RGB values, and remove
269af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    // the premultiplication afterward (while preserving the alpha channel).
270af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    WebPInitAlphaProcessing();
271af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    AlphaMultiplyARGB(pic, 0);
272af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height,
273af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                 pic->argb_stride * 4,
274af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                 (uint8_t*)tmp.argb, width, height,
275af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                 tmp.argb_stride * 4,
276af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora                 work, 4);
277af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora    AlphaMultiplyARGB(&tmp, 1);
278af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  }
279af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  WebPPictureFree(pic);
280af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  WebPSafeFree(work);
281af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  *pic = tmp;
282af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora  return 1;
283af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora}
284af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
285af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora//------------------------------------------------------------------------------
286