1 // Copyright 2011 Google Inc.
2 //
3 // This code is licensed under the same terms as WebM:
4 // Software License Agreement: http://www.webmproject.org/license/software/
5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/
6 // -----------------------------------------------------------------------------
7 //
8 // WebPPicture utils: colorspace conversion, crop, ...
9 //
10 // Author: Skal (pascal.massimino@gmail.com)
11
12 #include <assert.h>
13 #include <stdlib.h>
14 #include "vp8enci.h"
15
16 #if defined(__cplusplus) || defined(c_plusplus)
17 extern "C" {
18 #endif
19
20 //-----------------------------------------------------------------------------
21 // WebPPicture
22 //-----------------------------------------------------------------------------
23
WebPPictureAlloc(WebPPicture * const picture)24 int WebPPictureAlloc(WebPPicture* const picture) {
25 if (picture) {
26 const WebPEncCSP uv_csp = picture->colorspace & WEBP_CSP_UV_MASK;
27 const int has_alpha = picture->colorspace & WEBP_CSP_ALPHA_BIT;
28 const int width = picture->width;
29 const int height = picture->height;
30 const int y_stride = width;
31 const int uv_width = (width + 1) / 2;
32 const int uv_height = (height + 1) / 2;
33 const int uv_stride = uv_width;
34 int uv0_stride = 0;
35 int a_width, a_stride;
36 uint64_t y_size, uv_size, uv0_size, a_size, total_size;
37 uint8_t* mem;
38
39 // U/V
40 switch (uv_csp) {
41 case WEBP_YUV420:
42 break;
43 #ifdef WEBP_EXPERIMENTAL_FEATURES
44 case WEBP_YUV400: // for now, we'll just reset the U/V samples
45 break;
46 case WEBP_YUV422:
47 uv0_stride = uv_width;
48 break;
49 case WEBP_YUV444:
50 uv0_stride = width;
51 break;
52 #endif
53 default:
54 return 0;
55 }
56 uv0_size = height * uv0_stride;
57
58 // alpha
59 a_width = has_alpha ? width : 0;
60 a_stride = a_width;
61 y_size = (uint64_t)y_stride * height;
62 uv_size = (uint64_t)uv_stride * uv_height;
63 a_size = (uint64_t)a_stride * height;
64
65 total_size = y_size + a_size + 2 * uv_size + 2 * uv0_size;
66
67 // Security and validation checks
68 if (width <= 0 || height <= 0 || // check for luma/alpha param error
69 uv_width < 0 || uv_height < 0 || // check for u/v param error
70 y_size >= (1ULL << 40) || // check for reasonable global size
71 (size_t)total_size != total_size) { // check for overflow on 32bit
72 return 0;
73 }
74 picture->y_stride = y_stride;
75 picture->uv_stride = uv_stride;
76 picture->a_stride = a_stride;
77 picture->uv0_stride = uv0_stride;
78 WebPPictureFree(picture); // erase previous buffer
79 mem = (uint8_t*)malloc((size_t)total_size);
80 if (mem == NULL) return 0;
81
82 picture->y = mem;
83 mem += y_size;
84
85 picture->u = mem;
86 mem += uv_size;
87 picture->v = mem;
88 mem += uv_size;
89
90 if (a_size) {
91 picture->a = mem;
92 mem += a_size;
93 }
94 if (uv0_size) {
95 picture->u0 = mem;
96 mem += uv0_size;
97 picture->v0 = mem;
98 mem += uv0_size;
99 }
100 }
101 return 1;
102 }
103
104 // Grab the 'specs' (writer, *opaque, width, height...) from 'src' and copy them
105 // into 'dst'. Mark 'dst' as not owning any memory. 'src' can be NULL.
WebPPictureGrabSpecs(const WebPPicture * const src,WebPPicture * const dst)106 static void WebPPictureGrabSpecs(const WebPPicture* const src,
107 WebPPicture* const dst) {
108 if (src) *dst = *src;
109 dst->y = dst->u = dst->v = NULL;
110 dst->u0 = dst->v0 = NULL;
111 dst->a = NULL;
112 }
113
114 // Release memory owned by 'picture'.
WebPPictureFree(WebPPicture * const picture)115 void WebPPictureFree(WebPPicture* const picture) {
116 if (picture) {
117 free(picture->y);
118 WebPPictureGrabSpecs(NULL, picture);
119 }
120 }
121
122 //-----------------------------------------------------------------------------
123 // Picture copying
124
WebPPictureCopy(const WebPPicture * const src,WebPPicture * const dst)125 int WebPPictureCopy(const WebPPicture* const src, WebPPicture* const dst) {
126 int y;
127 if (src == NULL || dst == NULL) return 0;
128 if (src == dst) return 1;
129
130 WebPPictureGrabSpecs(src, dst);
131 if (!WebPPictureAlloc(dst)) return 0;
132
133 for (y = 0; y < dst->height; ++y) {
134 memcpy(dst->y + y * dst->y_stride,
135 src->y + y * src->y_stride, src->width);
136 }
137 for (y = 0; y < (dst->height + 1) / 2; ++y) {
138 memcpy(dst->u + y * dst->uv_stride,
139 src->u + y * src->uv_stride, (src->width + 1) / 2);
140 memcpy(dst->v + y * dst->uv_stride,
141 src->v + y * src->uv_stride, (src->width + 1) / 2);
142 }
143 #ifdef WEBP_EXPERIMENTAL_FEATURES
144 if (dst->a != NULL) {
145 for (y = 0; y < dst->height; ++y) {
146 memcpy(dst->a + y * dst->a_stride,
147 src->a + y * src->a_stride, src->width);
148 }
149 }
150 if (dst->u0 != NULL) {
151 int uv0_width = src->width;
152 if ((dst->colorspace & WEBP_CSP_UV_MASK) == WEBP_YUV422) {
153 uv0_width = (uv0_width + 1) / 2;
154 }
155 for (y = 0; y < dst->height; ++y) {
156 memcpy(dst->u0 + y * dst->uv0_stride,
157 src->u0 + y * src->uv0_stride, uv0_width);
158 memcpy(dst->v0 + y * dst->uv0_stride,
159 src->v0 + y * src->uv0_stride, uv0_width);
160 }
161 }
162 #endif
163 return 1;
164 }
165
166 //-----------------------------------------------------------------------------
167 // Picture cropping
168
WebPPictureCrop(WebPPicture * const pic,int left,int top,int width,int height)169 int WebPPictureCrop(WebPPicture* const pic,
170 int left, int top, int width, int height) {
171 WebPPicture tmp;
172 int y;
173
174 if (pic == NULL) return 0;
175 if (width <= 0 || height <= 0) return 0;
176 if (left < 0 || ((left + width + 1) & ~1) > pic->width) return 0;
177 if (top < 0 || ((top + height + 1) & ~1) > pic->height) return 0;
178
179 WebPPictureGrabSpecs(pic, &tmp);
180 tmp.width = width;
181 tmp.height = height;
182 if (!WebPPictureAlloc(&tmp)) return 0;
183
184 for (y = 0; y < height; ++y) {
185 memcpy(tmp.y + y * tmp.y_stride,
186 pic->y + (top + y) * pic->y_stride + left, width);
187 }
188 for (y = 0; y < (height + 1) / 2; ++y) {
189 const int offset = (y + top / 2) * pic->uv_stride + left / 2;
190 memcpy(tmp.u + y * tmp.uv_stride, pic->u + offset, (width + 1) / 2);
191 memcpy(tmp.v + y * tmp.uv_stride, pic->v + offset, (width + 1) / 2);
192 }
193
194 #ifdef WEBP_EXPERIMENTAL_FEATURES
195 if (tmp.a) {
196 for (y = 0; y < height; ++y) {
197 memcpy(tmp.a + y * tmp.a_stride,
198 pic->a + (top + y) * pic->a_stride + left, width);
199 }
200 }
201 if (tmp.u0) {
202 int w = width;
203 int l = left;
204 if (tmp.colorspace == WEBP_YUV422) {
205 w = (w + 1) / 2;
206 l = (l + 1) / 2;
207 }
208 for (y = 0; y < height; ++y) {
209 memcpy(tmp.u0 + y * tmp.uv0_stride,
210 pic->u0 + (top + y) * pic->uv0_stride + l, w);
211 memcpy(tmp.v0 + y * tmp.uv0_stride,
212 pic->v0 + (top + y) * pic->uv0_stride + l, w);
213 }
214 }
215 #endif
216
217 WebPPictureFree(pic);
218 *pic = tmp;
219 return 1;
220 }
221
222 //-----------------------------------------------------------------------------
223 // Simple picture rescaler
224
225 #define RFIX 30
226 #define MULT(x,y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX)
ImportRow(const uint8_t * src,int src_width,int32_t * frow,int32_t * irow,int dst_width)227 static inline void ImportRow(const uint8_t* src, int src_width,
228 int32_t* frow, int32_t* irow, int dst_width) {
229 const int x_expand = (src_width < dst_width);
230 const int fx_scale = (1 << RFIX) / dst_width;
231 int x_in = 0;
232 int x_out;
233 int x_accum = 0;
234 if (!x_expand) {
235 int sum = 0;
236 for (x_out = 0; x_out < dst_width; ++x_out) {
237 x_accum += src_width - dst_width;
238 for (; x_accum > 0; x_accum -= dst_width) {
239 sum += src[x_in++];
240 }
241 { // Emit next horizontal pixel.
242 const int32_t base = src[x_in++];
243 const int32_t frac = base * (-x_accum);
244 frow[x_out] = (sum + base) * dst_width - frac;
245 sum = MULT(frac, fx_scale); // fresh fractional start for next pixel
246 }
247 }
248 } else { // simple bilinear interpolation
249 int left = src[0], right = src[0];
250 for (x_out = 0; x_out < dst_width; ++x_out) {
251 if (x_accum < 0) {
252 left = right;
253 right = src[++x_in];
254 x_accum += dst_width - 1;
255 }
256 frow[x_out] = right * (dst_width - 1) + (left - right) * x_accum;
257 x_accum -= src_width - 1;
258 }
259 }
260 // Accumulate the new row's contribution
261 for (x_out = 0; x_out < dst_width; ++x_out) {
262 irow[x_out] += frow[x_out];
263 }
264 }
265
ExportRow(int32_t * frow,int32_t * irow,uint8_t * dst,int dst_width,const int yscale,const int64_t fxy_scale)266 static void ExportRow(int32_t* frow, int32_t* irow, uint8_t* dst, int dst_width,
267 const int yscale, const int64_t fxy_scale) {
268 int x_out;
269 for (x_out = 0; x_out < dst_width; ++x_out) {
270 const int frac = MULT(frow[x_out], yscale);
271 const int v = MULT(irow[x_out] - frac, fxy_scale);
272 dst[x_out] = (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255;
273 irow[x_out] = frac; // new fractional start
274 }
275 }
276
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,int32_t * const work)277 static void RescalePlane(const uint8_t* src,
278 int src_width, int src_height, int src_stride,
279 uint8_t* dst,
280 int dst_width, int dst_height, int dst_stride,
281 int32_t* const work) {
282 const int x_expand = (src_width < dst_width);
283 const int fy_scale = (1 << RFIX) / dst_height;
284 const int64_t fxy_scale = x_expand ?
285 ((int64_t)dst_height << RFIX) / (dst_width * src_height) :
286 ((int64_t)dst_height << RFIX) / (src_width * src_height);
287 int y_accum = src_height;
288 int y;
289 int32_t* irow = work; // integral contribution
290 int32_t* frow = work + dst_width; // fractional contribution
291
292 memset(work, 0, 2 * dst_width * sizeof(*work));
293 for (y = 0; y < src_height; ++y) {
294 // import new contribution of one source row.
295 ImportRow(src, src_width, frow, irow, dst_width);
296 src += src_stride;
297 // emit output row(s)
298 y_accum -= dst_height;
299 for (; y_accum <= 0; y_accum += src_height) {
300 const int yscale = fy_scale * (-y_accum);
301 ExportRow(frow, irow, dst, dst_width, yscale, fxy_scale);
302 dst += dst_stride;
303 }
304 }
305 }
306 #undef MULT
307 #undef RFIX
308
WebPPictureRescale(WebPPicture * const pic,int width,int height)309 int WebPPictureRescale(WebPPicture* const pic, int width, int height) {
310 WebPPicture tmp;
311 int prev_width, prev_height;
312 int32_t* work;
313
314 if (pic == NULL) return 0;
315 prev_width = pic->width;
316 prev_height = pic->height;
317 // if width is unspecified, scale original proportionally to height ratio.
318 if (width == 0) {
319 width = (prev_width * height + prev_height / 2) / prev_height;
320 }
321 // if height is unspecified, scale original proportionally to width ratio.
322 if (height == 0) {
323 height = (prev_height * width + prev_width / 2) / prev_width;
324 }
325 // Check if the overall dimensions still make sense.
326 if (width <= 0 || height <= 0) return 0;
327
328 WebPPictureGrabSpecs(pic, &tmp);
329 tmp.width = width;
330 tmp.height = height;
331 if (!WebPPictureAlloc(&tmp)) return 0;
332
333 work = malloc(2 * width * sizeof(int32_t));
334 if (work == NULL) {
335 WebPPictureFree(&tmp);
336 return 0;
337 }
338
339 RescalePlane(pic->y, prev_width, prev_height, pic->y_stride,
340 tmp.y, width, height, tmp.y_stride, work);
341 RescalePlane(pic->u,
342 (prev_width + 1) / 2, (prev_height + 1) / 2, pic->uv_stride,
343 tmp.u,
344 (width + 1) / 2, (height + 1) / 2, tmp.uv_stride, work);
345 RescalePlane(pic->v,
346 (prev_width + 1) / 2, (prev_height + 1) / 2, pic->uv_stride,
347 tmp.v,
348 (width + 1) / 2, (height + 1) / 2, tmp.uv_stride, work);
349
350 #ifdef WEBP_EXPERIMENTAL_FEATURES
351 if (tmp.a) {
352 RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
353 tmp.a, width, height, tmp.a_stride, work);
354 }
355 if (tmp.u0) {
356 int s = 1;
357 if ((tmp.colorspace & WEBP_CSP_UV_MASK) == WEBP_YUV422) {
358 s = 2;
359 }
360 RescalePlane(
361 pic->u0, (prev_width + s / 2) / s, prev_height, pic->uv0_stride,
362 tmp.u0, (width + s / 2) / s, height, tmp.uv0_stride, work);
363 RescalePlane(
364 pic->v0, (prev_width + s / 2) / s, prev_height, pic->uv0_stride,
365 tmp.v0, (width + s / 2) / s, height, tmp.uv0_stride, work);
366 }
367 #endif
368
369 WebPPictureFree(pic);
370 free(work);
371 *pic = tmp;
372 return 1;
373 }
374
375 //-----------------------------------------------------------------------------
376 // Write-to-memory
377
378 typedef struct {
379 uint8_t** mem;
380 size_t max_size;
381 size_t* size;
382 } WebPMemoryWriter;
383
InitMemoryWriter(WebPMemoryWriter * const writer)384 static void InitMemoryWriter(WebPMemoryWriter* const writer) {
385 *writer->mem = NULL;
386 *writer->size = 0;
387 writer->max_size = 0;
388 }
389
WebPMemoryWrite(const uint8_t * data,size_t data_size,const WebPPicture * const picture)390 static int WebPMemoryWrite(const uint8_t* data, size_t data_size,
391 const WebPPicture* const picture) {
392 WebPMemoryWriter* const w = (WebPMemoryWriter*)picture->custom_ptr;
393 size_t next_size;
394 if (w == NULL) {
395 return 1;
396 }
397 next_size = (*w->size) + data_size;
398 if (next_size > w->max_size) {
399 uint8_t* new_mem;
400 size_t next_max_size = w->max_size * 2;
401 if (next_max_size < next_size) next_max_size = next_size;
402 if (next_max_size < 8192) next_max_size = 8192;
403 new_mem = (uint8_t*)malloc(next_max_size);
404 if (new_mem == NULL) {
405 return 0;
406 }
407 if ((*w->size) > 0) {
408 memcpy(new_mem, *w->mem, *w->size);
409 }
410 free(*w->mem);
411 *w->mem = new_mem;
412 w->max_size = next_max_size;
413 }
414 if (data_size) {
415 memcpy((*w->mem) + (*w->size), data, data_size);
416 *w->size += data_size;
417 }
418 return 1;
419 }
420
421 //-----------------------------------------------------------------------------
422 // RGB -> YUV conversion
423 // The exact naming is Y'CbCr, following the ITU-R BT.601 standard.
424 // More information at: http://en.wikipedia.org/wiki/YCbCr
425 // Y = 0.2569 * R + 0.5044 * G + 0.0979 * B + 16
426 // U = -0.1483 * R - 0.2911 * G + 0.4394 * B + 128
427 // V = 0.4394 * R - 0.3679 * G - 0.0715 * B + 128
428 // We use 16bit fixed point operations.
429
430 enum { YUV_FRAC = 16 };
431
clip_uv(int v)432 static inline int clip_uv(int v) {
433 v = (v + (257 << (YUV_FRAC + 2 - 1))) >> (YUV_FRAC + 2);
434 return ((v & ~0xff) == 0) ? v : (v < 0) ? 0 : 255;
435 }
436
rgb_to_y(int r,int g,int b)437 static inline int rgb_to_y(int r, int g, int b) {
438 const int kRound = (1 << (YUV_FRAC - 1)) + (16 << YUV_FRAC);
439 const int luma = 16839 * r + 33059 * g + 6420 * b;
440 return (luma + kRound) >> YUV_FRAC; // no need to clip
441 }
442
rgb_to_u(int r,int g,int b)443 static inline int rgb_to_u(int r, int g, int b) {
444 return clip_uv(-9719 * r - 19081 * g + 28800 * b);
445 }
446
rgb_to_v(int r,int g,int b)447 static inline int rgb_to_v(int r, int g, int b) {
448 return clip_uv(+28800 * r - 24116 * g - 4684 * b);
449 }
450
451 // TODO: we can do better than simply 2x2 averaging on U/V samples.
452 #define SUM4(ptr) ((ptr)[0] + (ptr)[step] + \
453 (ptr)[rgb_stride] + (ptr)[rgb_stride + step])
454 #define SUM2H(ptr) (2 * (ptr)[0] + 2 * (ptr)[step])
455 #define SUM2V(ptr) (2 * (ptr)[0] + 2 * (ptr)[rgb_stride])
456 #define SUM1(ptr) (4 * (ptr)[0])
457 #define RGB_TO_UV(x, y, SUM) { \
458 const int src = (2 * (step * (x) + (y) * rgb_stride)); \
459 const int dst = (x) + (y) * picture->uv_stride; \
460 const int r = SUM(r_ptr + src); \
461 const int g = SUM(g_ptr + src); \
462 const int b = SUM(b_ptr + src); \
463 picture->u[dst] = rgb_to_u(r, g, b); \
464 picture->v[dst] = rgb_to_v(r, g, b); \
465 }
466
467 #define RGB_TO_UV0(x_in, x_out, y, SUM) { \
468 const int src = (step * (x_in) + (y) * rgb_stride); \
469 const int dst = (x_out) + (y) * picture->uv0_stride; \
470 const int r = SUM(r_ptr + src); \
471 const int g = SUM(g_ptr + src); \
472 const int b = SUM(b_ptr + src); \
473 picture->u0[dst] = rgb_to_u(r, g, b); \
474 picture->v0[dst] = rgb_to_v(r, g, b); \
475 }
476
MakeGray(WebPPicture * const picture)477 static void MakeGray(WebPPicture* const picture) {
478 int y;
479 const int uv_width = (picture->width + 1) >> 1;
480 for (y = 0; y < ((picture->height + 1) >> 1); ++y) {
481 memset(picture->u + y * picture->uv_stride, 128, uv_width);
482 memset(picture->v + y * picture->uv_stride, 128, uv_width);
483 }
484 }
485
Import(WebPPicture * const picture,const uint8_t * const rgb,int rgb_stride,int step,int swap_rb,int import_alpha)486 static int Import(WebPPicture* const picture,
487 const uint8_t* const rgb, int rgb_stride,
488 int step, int swap_rb, int import_alpha) {
489 const WebPEncCSP uv_csp = picture->colorspace & WEBP_CSP_UV_MASK;
490 int x, y;
491 const uint8_t* const r_ptr = rgb + (swap_rb ? 2 : 0);
492 const uint8_t* const g_ptr = rgb + 1;
493 const uint8_t* const b_ptr = rgb + (swap_rb ? 0 : 2);
494 const int width = picture->width;
495 const int height = picture->height;
496
497 // Import luma plane
498 for (y = 0; y < height; ++y) {
499 for (x = 0; x < width; ++x) {
500 const int offset = step * x + y * rgb_stride;
501 picture->y[x + y * picture->y_stride] =
502 rgb_to_y(r_ptr[offset], g_ptr[offset], b_ptr[offset]);
503 }
504 }
505
506 // Downsample U/V plane
507 if (uv_csp != WEBP_YUV400) {
508 for (y = 0; y < (height >> 1); ++y) {
509 for (x = 0; x < (width >> 1); ++x) {
510 RGB_TO_UV(x, y, SUM4);
511 }
512 if (picture->width & 1) {
513 RGB_TO_UV(x, y, SUM2V);
514 }
515 }
516 if (height & 1) {
517 for (x = 0; x < (width >> 1); ++x) {
518 RGB_TO_UV(x, y, SUM2H);
519 }
520 if (width & 1) {
521 RGB_TO_UV(x, y, SUM1);
522 }
523 }
524
525 #ifdef WEBP_EXPERIMENTAL_FEATURES
526 // Store original U/V samples too
527 if (uv_csp == WEBP_YUV422) {
528 for (y = 0; y < height; ++y) {
529 for (x = 0; x < (width >> 1); ++x) {
530 RGB_TO_UV0(2 * x, x, y, SUM2H);
531 }
532 if (width & 1) {
533 RGB_TO_UV0(2 * x, x, y, SUM1);
534 }
535 }
536 } else if (uv_csp == WEBP_YUV444) {
537 for (y = 0; y < height; ++y) {
538 for (x = 0; x < width; ++x) {
539 RGB_TO_UV0(x, x, y, SUM1);
540 }
541 }
542 }
543 #endif
544 } else {
545 MakeGray(picture);
546 }
547
548 if (import_alpha) {
549 #ifdef WEBP_EXPERIMENTAL_FEATURES
550 const uint8_t* const a_ptr = rgb + 3;
551 assert(step >= 4);
552 for (y = 0; y < height; ++y) {
553 for (x = 0; x < width; ++x) {
554 picture->a[x + y * picture->a_stride] =
555 a_ptr[step * x + y * rgb_stride];
556 }
557 }
558 #endif
559 }
560 return 1;
561 }
562 #undef SUM4
563 #undef SUM2V
564 #undef SUM2H
565 #undef SUM1
566 #undef RGB_TO_UV
567
WebPPictureImportRGB(WebPPicture * const picture,const uint8_t * const rgb,int rgb_stride)568 int WebPPictureImportRGB(WebPPicture* const picture,
569 const uint8_t* const rgb, int rgb_stride) {
570 picture->colorspace &= ~WEBP_CSP_ALPHA_BIT;
571 if (!WebPPictureAlloc(picture)) return 0;
572 return Import(picture, rgb, rgb_stride, 3, 0, 0);
573 }
574
WebPPictureImportBGR(WebPPicture * const picture,const uint8_t * const rgb,int rgb_stride)575 int WebPPictureImportBGR(WebPPicture* const picture,
576 const uint8_t* const rgb, int rgb_stride) {
577 picture->colorspace &= ~WEBP_CSP_ALPHA_BIT;
578 if (!WebPPictureAlloc(picture)) return 0;
579 return Import(picture, rgb, rgb_stride, 3, 1, 0);
580 }
581
WebPPictureImportRGBA(WebPPicture * const picture,const uint8_t * const rgba,int rgba_stride)582 int WebPPictureImportRGBA(WebPPicture* const picture,
583 const uint8_t* const rgba, int rgba_stride) {
584 picture->colorspace |= WEBP_CSP_ALPHA_BIT;
585 if (!WebPPictureAlloc(picture)) return 0;
586 return Import(picture, rgba, rgba_stride, 4, 0, 1);
587 }
588
WebPPictureImportBGRA(WebPPicture * const picture,const uint8_t * const rgba,int rgba_stride)589 int WebPPictureImportBGRA(WebPPicture* const picture,
590 const uint8_t* const rgba, int rgba_stride) {
591 picture->colorspace |= WEBP_CSP_ALPHA_BIT;
592 if (!WebPPictureAlloc(picture)) return 0;
593 return Import(picture, rgba, rgba_stride, 4, 1, 1);
594 }
595
596 //-----------------------------------------------------------------------------
597 // Simplest call:
598
599 typedef int (*Importer)(WebPPicture* const, const uint8_t* const, int);
600
Encode(const uint8_t * rgba,int width,int height,int stride,Importer import,float quality_factor,uint8_t ** output)601 static size_t Encode(const uint8_t* rgba, int width, int height, int stride,
602 Importer import, float quality_factor, uint8_t** output) {
603 size_t output_size = 0;
604 WebPPicture pic;
605 WebPConfig config;
606 WebPMemoryWriter wrt;
607 int ok;
608
609 if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, quality_factor) ||
610 !WebPPictureInit(&pic)) {
611 return 0; // shouldn't happen, except if system installation is broken
612 }
613
614 pic.width = width;
615 pic.height = height;
616 pic.writer = WebPMemoryWrite;
617 pic.custom_ptr = &wrt;
618
619 wrt.mem = output;
620 wrt.size = &output_size;
621 InitMemoryWriter(&wrt);
622
623 ok = import(&pic, rgba, stride) && WebPEncode(&config, &pic);
624 WebPPictureFree(&pic);
625 if (!ok) {
626 free(*output);
627 *output = NULL;
628 return 0;
629 }
630 return output_size;
631 }
632
633 #define ENCODE_FUNC(NAME, IMPORTER) \
634 size_t NAME(const uint8_t* in, int w, int h, int bps, float q, \
635 uint8_t** out) { \
636 return Encode(in, w, h, bps, IMPORTER, q, out); \
637 }
638
639 ENCODE_FUNC(WebPEncodeRGB, WebPPictureImportRGB);
640 ENCODE_FUNC(WebPEncodeBGR, WebPPictureImportBGR);
641 ENCODE_FUNC(WebPEncodeRGBA, WebPPictureImportRGBA);
642 ENCODE_FUNC(WebPEncodeBGRA, WebPPictureImportBGRA);
643
644 #undef ENCODE_FUNC
645
646 //-----------------------------------------------------------------------------
647
648 #if defined(__cplusplus) || defined(c_plusplus)
649 } // extern "C"
650 #endif
651