tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

picture_rescale_enc.c (10488B)


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