1 // Copyright 2014 Google Inc. All Rights Reserved.
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the COPYING file in the root of the source
5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS. All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree.
8 // -----------------------------------------------------------------------------
10 // WebPPicture tools: copy, crop, rescaling and view.
12 // Author: Skal (pascal.massimino@gmail.com)
17 #include "./vp8enci.h"
18 #include "../utils/rescaler.h"
19 #include "../utils/utils.h"
21 #define HALVE(x) (((x) + 1) >> 1)
23 // Grab the 'specs' (writer, *opaque, width, height...) from 'src' and copy them
24 // into 'dst'. Mark 'dst' as not owning any memory.
25 static void PictureGrabSpecs(const WebPPicture
* const src
,
26 WebPPicture
* const dst
) {
27 assert(src
!= NULL
&& dst
!= NULL
);
29 WebPPictureResetBuffers(dst
);
32 //------------------------------------------------------------------------------
35 static void CopyPlane(const uint8_t* src
, int src_stride
,
36 uint8_t* dst
, int dst_stride
, int width
, int height
) {
37 while (height
-- > 0) {
38 memcpy(dst
, src
, width
);
44 // Adjust top-left corner to chroma sample position.
45 static void SnapTopLeftPosition(const WebPPicture
* const pic
,
46 int* const left
, int* const top
) {
53 // Adjust top-left corner and verify that the sub-rectangle is valid.
54 static int AdjustAndCheckRectangle(const WebPPicture
* const pic
,
55 int* const left
, int* const top
,
56 int width
, int height
) {
57 SnapTopLeftPosition(pic
, left
, top
);
58 if ((*left
) < 0 || (*top
) < 0) return 0;
59 if (width
<= 0 || height
<= 0) return 0;
60 if ((*left
) + width
> pic
->width
) return 0;
61 if ((*top
) + height
> pic
->height
) return 0;
65 int WebPPictureCopy(const WebPPicture
* src
, WebPPicture
* dst
) {
66 if (src
== NULL
|| dst
== NULL
) return 0;
67 if (src
== dst
) return 1;
69 PictureGrabSpecs(src
, dst
);
70 if (!WebPPictureAlloc(dst
)) return 0;
73 CopyPlane(src
->y
, src
->y_stride
,
74 dst
->y
, dst
->y_stride
, dst
->width
, dst
->height
);
75 CopyPlane(src
->u
, src
->uv_stride
,
76 dst
->u
, dst
->uv_stride
, HALVE(dst
->width
), HALVE(dst
->height
));
77 CopyPlane(src
->v
, src
->uv_stride
,
78 dst
->v
, dst
->uv_stride
, HALVE(dst
->width
), HALVE(dst
->height
));
80 CopyPlane(src
->a
, src
->a_stride
,
81 dst
->a
, dst
->a_stride
, dst
->width
, dst
->height
);
84 CopyPlane((const uint8_t*)src
->argb
, 4 * src
->argb_stride
,
85 (uint8_t*)dst
->argb
, 4 * dst
->argb_stride
,
86 4 * dst
->width
, dst
->height
);
91 int WebPPictureIsView(const WebPPicture
* picture
) {
92 if (picture
== NULL
) return 0;
93 if (picture
->use_argb
) {
94 return (picture
->memory_argb_
== NULL
);
96 return (picture
->memory_
== NULL
);
99 int WebPPictureView(const WebPPicture
* src
,
100 int left
, int top
, int width
, int height
,
102 if (src
== NULL
|| dst
== NULL
) return 0;
104 // verify rectangle position.
105 if (!AdjustAndCheckRectangle(src
, &left
, &top
, width
, height
)) return 0;
107 if (src
!= dst
) { // beware of aliasing! We don't want to leak 'memory_'.
108 PictureGrabSpecs(src
, dst
);
111 dst
->height
= height
;
112 if (!src
->use_argb
) {
113 dst
->y
= src
->y
+ top
* src
->y_stride
+ left
;
114 dst
->u
= src
->u
+ (top
>> 1) * src
->uv_stride
+ (left
>> 1);
115 dst
->v
= src
->v
+ (top
>> 1) * src
->uv_stride
+ (left
>> 1);
116 dst
->y_stride
= src
->y_stride
;
117 dst
->uv_stride
= src
->uv_stride
;
118 if (src
->a
!= NULL
) {
119 dst
->a
= src
->a
+ top
* src
->a_stride
+ left
;
120 dst
->a_stride
= src
->a_stride
;
123 dst
->argb
= src
->argb
+ top
* src
->argb_stride
+ left
;
124 dst
->argb_stride
= src
->argb_stride
;
129 //------------------------------------------------------------------------------
132 int WebPPictureCrop(WebPPicture
* pic
,
133 int left
, int top
, int width
, int height
) {
136 if (pic
== NULL
) return 0;
137 if (!AdjustAndCheckRectangle(pic
, &left
, &top
, width
, height
)) return 0;
139 PictureGrabSpecs(pic
, &tmp
);
142 if (!WebPPictureAlloc(&tmp
)) return 0;
144 if (!pic
->use_argb
) {
145 const int y_offset
= top
* pic
->y_stride
+ left
;
146 const int uv_offset
= (top
/ 2) * pic
->uv_stride
+ left
/ 2;
147 CopyPlane(pic
->y
+ y_offset
, pic
->y_stride
,
148 tmp
.y
, tmp
.y_stride
, width
, height
);
149 CopyPlane(pic
->u
+ uv_offset
, pic
->uv_stride
,
150 tmp
.u
, tmp
.uv_stride
, HALVE(width
), HALVE(height
));
151 CopyPlane(pic
->v
+ uv_offset
, pic
->uv_stride
,
152 tmp
.v
, tmp
.uv_stride
, HALVE(width
), HALVE(height
));
155 const int a_offset
= top
* pic
->a_stride
+ left
;
156 CopyPlane(pic
->a
+ a_offset
, pic
->a_stride
,
157 tmp
.a
, tmp
.a_stride
, width
, height
);
160 const uint8_t* const src
=
161 (const uint8_t*)(pic
->argb
+ top
* pic
->argb_stride
+ left
);
162 CopyPlane(src
, pic
->argb_stride
* 4,
163 (uint8_t*)tmp
.argb
, tmp
.argb_stride
* 4,
166 WebPPictureFree(pic
);
171 //------------------------------------------------------------------------------
172 // Simple picture rescaler
174 static void RescalePlane(const uint8_t* src
,
175 int src_width
, int src_height
, int src_stride
,
177 int dst_width
, int dst_height
, int dst_stride
,
180 WebPRescaler rescaler
;
182 WebPRescalerInit(&rescaler
, src_width
, src_height
,
183 dst
, dst_width
, dst_height
, dst_stride
,
185 src_width
, dst_width
,
186 src_height
, dst_height
,
188 memset(work
, 0, 2 * dst_width
* num_channels
* sizeof(*work
));
189 while (y
< src_height
) {
190 y
+= WebPRescalerImport(&rescaler
, src_height
- y
,
191 src
+ y
* src_stride
, src_stride
);
192 WebPRescalerExport(&rescaler
);
196 static void AlphaMultiplyARGB(WebPPicture
* const pic
, int inverse
) {
197 assert(pic
->argb
!= NULL
);
198 WebPMultARGBRows((uint8_t*)pic
->argb
, pic
->argb_stride
* sizeof(*pic
->argb
),
199 pic
->width
, pic
->height
, inverse
);
202 static void AlphaMultiplyY(WebPPicture
* const pic
, int inverse
) {
203 if (pic
->a
!= NULL
) {
204 WebPMultRows(pic
->y
, pic
->y_stride
, pic
->a
, pic
->a_stride
,
205 pic
->width
, pic
->height
, inverse
);
209 int WebPPictureRescale(WebPPicture
* pic
, int width
, int height
) {
211 int prev_width
, prev_height
;
214 if (pic
== NULL
) return 0;
215 prev_width
= pic
->width
;
216 prev_height
= pic
->height
;
217 // if width is unspecified, scale original proportionally to height ratio.
219 width
= (prev_width
* height
+ prev_height
/ 2) / prev_height
;
221 // if height is unspecified, scale original proportionally to width ratio.
223 height
= (prev_height
* width
+ prev_width
/ 2) / prev_width
;
225 // Check if the overall dimensions still make sense.
226 if (width
<= 0 || height
<= 0) return 0;
228 PictureGrabSpecs(pic
, &tmp
);
231 if (!WebPPictureAlloc(&tmp
)) return 0;
233 if (!pic
->use_argb
) {
234 work
= (int32_t*)WebPSafeMalloc(2ULL * width
, sizeof(*work
));
236 WebPPictureFree(&tmp
);
239 // If present, we need to rescale alpha first (for AlphaMultiplyY).
240 if (pic
->a
!= NULL
) {
241 WebPInitAlphaProcessing();
242 RescalePlane(pic
->a
, prev_width
, prev_height
, pic
->a_stride
,
243 tmp
.a
, width
, height
, tmp
.a_stride
, work
, 1);
246 // We take transparency into account on the luma plane only. That's not
247 // totally exact blending, but still is a good approximation.
248 AlphaMultiplyY(pic
, 0);
249 RescalePlane(pic
->y
, prev_width
, prev_height
, pic
->y_stride
,
250 tmp
.y
, width
, height
, tmp
.y_stride
, work
, 1);
251 AlphaMultiplyY(&tmp
, 1);
254 HALVE(prev_width
), HALVE(prev_height
), pic
->uv_stride
,
256 HALVE(width
), HALVE(height
), tmp
.uv_stride
, work
, 1);
258 HALVE(prev_width
), HALVE(prev_height
), pic
->uv_stride
,
260 HALVE(width
), HALVE(height
), tmp
.uv_stride
, work
, 1);
262 work
= (int32_t*)WebPSafeMalloc(2ULL * width
* 4, sizeof(*work
));
264 WebPPictureFree(&tmp
);
267 // In order to correctly interpolate colors, we need to apply the alpha
268 // weighting first (black-matting), scale the RGB values, and remove
269 // the premultiplication afterward (while preserving the alpha channel).
270 WebPInitAlphaProcessing();
271 AlphaMultiplyARGB(pic
, 0);
272 RescalePlane((const uint8_t*)pic
->argb
, prev_width
, prev_height
,
273 pic
->argb_stride
* 4,
274 (uint8_t*)tmp
.argb
, width
, height
,
277 AlphaMultiplyARGB(&tmp
, 1);
279 WebPPictureFree(pic
);
285 //------------------------------------------------------------------------------