Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/libwebp/src/enc/picture_rescale_enc.c
9917 views
1
// Copyright 2014 Google Inc. All Rights Reserved.
2
//
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
// -----------------------------------------------------------------------------
9
//
10
// WebPPicture tools: copy, crop, rescaling and view.
11
//
12
// Author: Skal ([email protected])
13
14
#include "src/webp/encode.h"
15
16
#include <assert.h>
17
#include <stdlib.h>
18
19
#include "src/enc/vp8i_enc.h"
20
21
#if !defined(WEBP_REDUCE_SIZE)
22
#include "src/utils/rescaler_utils.h"
23
#include "src/utils/utils.h"
24
#endif // !defined(WEBP_REDUCE_SIZE)
25
26
#define HALVE(x) (((x) + 1) >> 1)
27
28
// Grab the 'specs' (writer, *opaque, width, height...) from 'src' and copy them
29
// into 'dst'. Mark 'dst' as not owning any memory.
30
static void PictureGrabSpecs(const WebPPicture* const src,
31
WebPPicture* const dst) {
32
assert(src != NULL && dst != NULL);
33
*dst = *src;
34
WebPPictureResetBuffers(dst);
35
}
36
37
//------------------------------------------------------------------------------
38
39
// Adjust top-left corner to chroma sample position.
40
static void SnapTopLeftPosition(const WebPPicture* const pic,
41
int* const left, int* const top) {
42
if (!pic->use_argb) {
43
*left &= ~1;
44
*top &= ~1;
45
}
46
}
47
48
// Adjust top-left corner and verify that the sub-rectangle is valid.
49
static int AdjustAndCheckRectangle(const WebPPicture* const pic,
50
int* const left, int* const top,
51
int width, int height) {
52
SnapTopLeftPosition(pic, left, top);
53
if ((*left) < 0 || (*top) < 0) return 0;
54
if (width <= 0 || height <= 0) return 0;
55
if ((*left) + width > pic->width) return 0;
56
if ((*top) + height > pic->height) return 0;
57
return 1;
58
}
59
60
#if !defined(WEBP_REDUCE_SIZE)
61
int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) {
62
if (src == NULL || dst == NULL) return 0;
63
if (src == dst) return 1;
64
65
PictureGrabSpecs(src, dst);
66
if (!WebPPictureAlloc(dst)) return 0;
67
68
if (!src->use_argb) {
69
WebPCopyPlane(src->y, src->y_stride,
70
dst->y, dst->y_stride, dst->width, dst->height);
71
WebPCopyPlane(src->u, src->uv_stride, dst->u, dst->uv_stride,
72
HALVE(dst->width), HALVE(dst->height));
73
WebPCopyPlane(src->v, src->uv_stride, dst->v, dst->uv_stride,
74
HALVE(dst->width), HALVE(dst->height));
75
if (dst->a != NULL) {
76
WebPCopyPlane(src->a, src->a_stride,
77
dst->a, dst->a_stride, dst->width, dst->height);
78
}
79
} else {
80
WebPCopyPlane((const uint8_t*)src->argb, 4 * src->argb_stride,
81
(uint8_t*)dst->argb, 4 * dst->argb_stride,
82
4 * dst->width, dst->height);
83
}
84
return 1;
85
}
86
#endif // !defined(WEBP_REDUCE_SIZE)
87
88
int WebPPictureIsView(const WebPPicture* picture) {
89
if (picture == NULL) return 0;
90
if (picture->use_argb) {
91
return (picture->memory_argb_ == NULL);
92
}
93
return (picture->memory_ == NULL);
94
}
95
96
int WebPPictureView(const WebPPicture* src,
97
int left, int top, int width, int height,
98
WebPPicture* dst) {
99
if (src == NULL || dst == NULL) return 0;
100
101
// verify rectangle position.
102
if (!AdjustAndCheckRectangle(src, &left, &top, width, height)) return 0;
103
104
if (src != dst) { // beware of aliasing! We don't want to leak 'memory_'.
105
PictureGrabSpecs(src, dst);
106
}
107
dst->width = width;
108
dst->height = height;
109
if (!src->use_argb) {
110
dst->y = src->y + top * src->y_stride + left;
111
dst->u = src->u + (top >> 1) * src->uv_stride + (left >> 1);
112
dst->v = src->v + (top >> 1) * src->uv_stride + (left >> 1);
113
dst->y_stride = src->y_stride;
114
dst->uv_stride = src->uv_stride;
115
if (src->a != NULL) {
116
dst->a = src->a + top * src->a_stride + left;
117
dst->a_stride = src->a_stride;
118
}
119
} else {
120
dst->argb = src->argb + top * src->argb_stride + left;
121
dst->argb_stride = src->argb_stride;
122
}
123
return 1;
124
}
125
126
#if !defined(WEBP_REDUCE_SIZE)
127
//------------------------------------------------------------------------------
128
// Picture cropping
129
130
int WebPPictureCrop(WebPPicture* pic,
131
int left, int top, int width, int height) {
132
WebPPicture tmp;
133
134
if (pic == NULL) return 0;
135
if (!AdjustAndCheckRectangle(pic, &left, &top, width, height)) return 0;
136
137
PictureGrabSpecs(pic, &tmp);
138
tmp.width = width;
139
tmp.height = height;
140
if (!WebPPictureAlloc(&tmp)) {
141
return WebPEncodingSetError(pic, tmp.error_code);
142
}
143
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
WebPCopyPlane(pic->y + y_offset, pic->y_stride,
148
tmp.y, tmp.y_stride, width, height);
149
WebPCopyPlane(pic->u + uv_offset, pic->uv_stride,
150
tmp.u, tmp.uv_stride, HALVE(width), HALVE(height));
151
WebPCopyPlane(pic->v + uv_offset, pic->uv_stride,
152
tmp.v, tmp.uv_stride, HALVE(width), HALVE(height));
153
154
if (tmp.a != NULL) {
155
const int a_offset = top * pic->a_stride + left;
156
WebPCopyPlane(pic->a + a_offset, pic->a_stride,
157
tmp.a, tmp.a_stride, width, height);
158
}
159
} else {
160
const uint8_t* const src =
161
(const uint8_t*)(pic->argb + top * pic->argb_stride + left);
162
WebPCopyPlane(src, pic->argb_stride * 4, (uint8_t*)tmp.argb,
163
tmp.argb_stride * 4, width * 4, height);
164
}
165
WebPPictureFree(pic);
166
*pic = tmp;
167
return 1;
168
}
169
170
//------------------------------------------------------------------------------
171
// Simple picture rescaler
172
173
static int RescalePlane(const uint8_t* src,
174
int src_width, int src_height, int src_stride,
175
uint8_t* dst,
176
int dst_width, int dst_height, int dst_stride,
177
rescaler_t* const work,
178
int num_channels) {
179
WebPRescaler rescaler;
180
int y = 0;
181
if (!WebPRescalerInit(&rescaler, src_width, src_height,
182
dst, dst_width, dst_height, dst_stride,
183
num_channels, work)) {
184
return 0;
185
}
186
while (y < src_height) {
187
y += WebPRescalerImport(&rescaler, src_height - y,
188
src + y * src_stride, src_stride);
189
WebPRescalerExport(&rescaler);
190
}
191
return 1;
192
}
193
194
static void AlphaMultiplyARGB(WebPPicture* const pic, int inverse) {
195
assert(pic->argb != NULL);
196
WebPMultARGBRows((uint8_t*)pic->argb, pic->argb_stride * sizeof(*pic->argb),
197
pic->width, pic->height, inverse);
198
}
199
200
static void AlphaMultiplyY(WebPPicture* const pic, int inverse) {
201
if (pic->a != NULL) {
202
WebPMultRows(pic->y, pic->y_stride, pic->a, pic->a_stride,
203
pic->width, pic->height, inverse);
204
}
205
}
206
207
int WebPPictureRescale(WebPPicture* picture, int width, int height) {
208
WebPPicture tmp;
209
int prev_width, prev_height;
210
rescaler_t* work;
211
212
if (picture == NULL) return 0;
213
prev_width = picture->width;
214
prev_height = picture->height;
215
if (!WebPRescalerGetScaledDimensions(
216
prev_width, prev_height, &width, &height)) {
217
return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
218
}
219
220
PictureGrabSpecs(picture, &tmp);
221
tmp.width = width;
222
tmp.height = height;
223
if (!WebPPictureAlloc(&tmp)) {
224
return WebPEncodingSetError(picture, tmp.error_code);
225
}
226
227
if (!picture->use_argb) {
228
work = (rescaler_t*)WebPSafeMalloc(2ULL * width, sizeof(*work));
229
if (work == NULL) {
230
WebPPictureFree(&tmp);
231
return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
232
}
233
// If present, we need to rescale alpha first (for AlphaMultiplyY).
234
if (picture->a != NULL) {
235
WebPInitAlphaProcessing();
236
if (!RescalePlane(picture->a, prev_width, prev_height, picture->a_stride,
237
tmp.a, width, height, tmp.a_stride, work, 1)) {
238
return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
239
}
240
}
241
242
// We take transparency into account on the luma plane only. That's not
243
// totally exact blending, but still is a good approximation.
244
AlphaMultiplyY(picture, 0);
245
if (!RescalePlane(picture->y, prev_width, prev_height, picture->y_stride,
246
tmp.y, width, height, tmp.y_stride, work, 1) ||
247
!RescalePlane(picture->u, HALVE(prev_width), HALVE(prev_height),
248
picture->uv_stride, tmp.u, HALVE(width), HALVE(height),
249
tmp.uv_stride, work, 1) ||
250
!RescalePlane(picture->v, HALVE(prev_width), HALVE(prev_height),
251
picture->uv_stride, tmp.v, HALVE(width), HALVE(height),
252
tmp.uv_stride, work, 1)) {
253
return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
254
}
255
AlphaMultiplyY(&tmp, 1);
256
} else {
257
work = (rescaler_t*)WebPSafeMalloc(2ULL * width * 4, sizeof(*work));
258
if (work == NULL) {
259
WebPPictureFree(&tmp);
260
return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
261
}
262
// In order to correctly interpolate colors, we need to apply the alpha
263
// weighting first (black-matting), scale the RGB values, and remove
264
// the premultiplication afterward (while preserving the alpha channel).
265
WebPInitAlphaProcessing();
266
AlphaMultiplyARGB(picture, 0);
267
if (!RescalePlane((const uint8_t*)picture->argb, prev_width, prev_height,
268
picture->argb_stride * 4, (uint8_t*)tmp.argb, width,
269
height, tmp.argb_stride * 4, work, 4)) {
270
return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
271
}
272
AlphaMultiplyARGB(&tmp, 1);
273
}
274
WebPPictureFree(picture);
275
WebPSafeFree(work);
276
*picture = tmp;
277
return 1;
278
}
279
280
#else // defined(WEBP_REDUCE_SIZE)
281
282
int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) {
283
(void)src;
284
(void)dst;
285
return 0;
286
}
287
288
int WebPPictureCrop(WebPPicture* pic,
289
int left, int top, int width, int height) {
290
(void)pic;
291
(void)left;
292
(void)top;
293
(void)width;
294
(void)height;
295
return 0;
296
}
297
298
int WebPPictureRescale(WebPPicture* pic, int width, int height) {
299
(void)pic;
300
(void)width;
301
(void)height;
302
return 0;
303
}
304
#endif // !defined(WEBP_REDUCE_SIZE)
305
306