• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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