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