1a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Copyright 2012 Google Inc. All Rights Reserved.
2a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//
30406ce1417f76f2034833414dcecc9f56253640cVikas Arora// Use of this source code is governed by a BSD-style license
40406ce1417f76f2034833414dcecc9f56253640cVikas Arora// that can be found in the COPYING file in the root of the source
50406ce1417f76f2034833414dcecc9f56253640cVikas Arora// tree. An additional intellectual property rights grant can be found
60406ce1417f76f2034833414dcecc9f56253640cVikas Arora// in the file PATENTS. All contributing project authors may
70406ce1417f76f2034833414dcecc9f56253640cVikas Arora// be found in the AUTHORS file in the root of the source tree.
8a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// -----------------------------------------------------------------------------
9a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//
10a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Rescaling functions
11a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//
12a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Author: Skal (pascal.massimino@gmail.com)
13a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
14a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#include <assert.h>
15a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#include <stdlib.h>
16e8a1b86cc3afe4791ab40d89240c40797a400131James Zern#include <string.h>
1733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#include "../dsp/dsp.h"
18fa39824bb690c5806358871f46940d0450973d8aJames Zern#include "./rescaler_utils.h"
1933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
2033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
2133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
2233f74dabbc7920a65ed435d7417987589febdc16Vikas Aroravoid WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height,
23e8a1b86cc3afe4791ab40d89240c40797a400131James Zern                      uint8_t* const dst,
24e8a1b86cc3afe4791ab40d89240c40797a400131James Zern                      int dst_width, int dst_height, int dst_stride,
25e8a1b86cc3afe4791ab40d89240c40797a400131James Zern                      int num_channels, rescaler_t* const work) {
26e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  const int x_add = src_width, x_sub = dst_width;
27e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  const int y_add = src_height, y_sub = dst_height;
2833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  wrk->x_expand = (src_width < dst_width);
29e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  wrk->y_expand = (src_height < dst_height);
3033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  wrk->src_width = src_width;
3133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  wrk->src_height = src_height;
3233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  wrk->dst_width = dst_width;
3333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  wrk->dst_height = dst_height;
34e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  wrk->src_y = 0;
35e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  wrk->dst_y = 0;
3633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  wrk->dst = dst;
3733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  wrk->dst_stride = dst_stride;
3833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  wrk->num_channels = num_channels;
39e8a1b86cc3afe4791ab40d89240c40797a400131James Zern
4033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  // for 'x_expand', we use bilinear interpolation
41e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add;
4233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  wrk->x_sub = wrk->x_expand ? (x_add - 1) : x_sub;
43e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  if (!wrk->x_expand) {  // fx_scale is not used otherwise
44e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    wrk->fx_scale = WEBP_RESCALER_FRAC(1, wrk->x_sub);
45e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  }
46e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  // vertical scaling parameters
47e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  wrk->y_add = wrk->y_expand ? y_add - 1 : y_add;
48e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  wrk->y_sub = wrk->y_expand ? y_sub - 1 : y_sub;
49e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  wrk->y_accum = wrk->y_expand ? wrk->y_sub : wrk->y_add;
50e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  if (!wrk->y_expand) {
5198a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    // This is WEBP_RESCALER_FRAC(dst_height, x_add * y_add) without the cast.
5298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    // Its value is <= WEBP_RESCALER_ONE, because dst_height <= wrk->y_add, and
5398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    // wrk->x_add >= 1;
54e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    const uint64_t ratio =
55e8a1b86cc3afe4791ab40d89240c40797a400131James Zern        (uint64_t)dst_height * WEBP_RESCALER_ONE / (wrk->x_add * wrk->y_add);
56e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    if (ratio != (uint32_t)ratio) {
5798a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      // When ratio == WEBP_RESCALER_ONE, we can't represent the ratio with the
5898a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      // current fixed-point precision. This happens when src_height ==
5998a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      // wrk->y_add (which == src_height), and wrk->x_add == 1.
60e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      // => We special-case fxy_scale = 0, in WebPRescalerExportRow().
61e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      wrk->fxy_scale = 0;
62e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    } else {
63e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      wrk->fxy_scale = (uint32_t)ratio;
64e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    }
65e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    wrk->fy_scale = WEBP_RESCALER_FRAC(1, wrk->y_sub);
66e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  } else {
67e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    wrk->fy_scale = WEBP_RESCALER_FRAC(1, wrk->x_add);
68e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    // wrk->fxy_scale is unused here.
69e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  }
7033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  wrk->irow = work;
7133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  wrk->frow = work + num_channels * dst_width;
72e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  memset(work, 0, 2 * dst_width * num_channels * sizeof(*work));
7333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
747c8da7ce66017295a65ec028084b90800be377f8James Zern  WebPRescalerDspInit();
757c8da7ce66017295a65ec028084b90800be377f8James Zern}
767c8da7ce66017295a65ec028084b90800be377f8James Zern
777c8da7ce66017295a65ec028084b90800be377f8James Zernint WebPRescalerGetScaledDimensions(int src_width, int src_height,
787c8da7ce66017295a65ec028084b90800be377f8James Zern                                    int* const scaled_width,
797c8da7ce66017295a65ec028084b90800be377f8James Zern                                    int* const scaled_height) {
807c8da7ce66017295a65ec028084b90800be377f8James Zern  assert(scaled_width != NULL);
817c8da7ce66017295a65ec028084b90800be377f8James Zern  assert(scaled_height != NULL);
827c8da7ce66017295a65ec028084b90800be377f8James Zern  {
837c8da7ce66017295a65ec028084b90800be377f8James Zern    int width = *scaled_width;
847c8da7ce66017295a65ec028084b90800be377f8James Zern    int height = *scaled_height;
857c8da7ce66017295a65ec028084b90800be377f8James Zern
867c8da7ce66017295a65ec028084b90800be377f8James Zern    // if width is unspecified, scale original proportionally to height ratio.
877c8da7ce66017295a65ec028084b90800be377f8James Zern    if (width == 0) {
887c8da7ce66017295a65ec028084b90800be377f8James Zern      width = (src_width * height + src_height / 2) / src_height;
8933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
907c8da7ce66017295a65ec028084b90800be377f8James Zern    // if height is unspecified, scale original proportionally to width ratio.
917c8da7ce66017295a65ec028084b90800be377f8James Zern    if (height == 0) {
927c8da7ce66017295a65ec028084b90800be377f8James Zern      height = (src_height * width + src_width / 2) / src_width;
937c8da7ce66017295a65ec028084b90800be377f8James Zern    }
947c8da7ce66017295a65ec028084b90800be377f8James Zern    // Check if the overall dimensions still make sense.
957c8da7ce66017295a65ec028084b90800be377f8James Zern    if (width <= 0 || height <= 0) {
967c8da7ce66017295a65ec028084b90800be377f8James Zern      return 0;
977c8da7ce66017295a65ec028084b90800be377f8James Zern    }
987c8da7ce66017295a65ec028084b90800be377f8James Zern
997c8da7ce66017295a65ec028084b90800be377f8James Zern    *scaled_width = width;
1007c8da7ce66017295a65ec028084b90800be377f8James Zern    *scaled_height = height;
1017c8da7ce66017295a65ec028084b90800be377f8James Zern    return 1;
102a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
103a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
104a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
105a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
106a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// all-in-one calls
107a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
1088b720228d581a84fd173b6dcb2fa295b59db489aVikas Aroraint WebPRescaleNeededLines(const WebPRescaler* const wrk, int max_num_lines) {
1098b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int num_lines = (wrk->y_accum + wrk->y_sub - 1) / wrk->y_sub;
1108b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return (num_lines > max_num_lines) ? max_num_lines : num_lines;
1118b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora}
1128b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
113a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Aroraint WebPRescalerImport(WebPRescaler* const wrk, int num_lines,
114a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                       const uint8_t* src, int src_stride) {
115a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int total_imported = 0;
116e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  while (total_imported < num_lines && !WebPRescalerHasPendingOutput(wrk)) {
117e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    if (wrk->y_expand) {
118e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      rescaler_t* const tmp = wrk->irow;
119e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      wrk->irow = wrk->frow;
120e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      wrk->frow = tmp;
121e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    }
122e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    WebPRescalerImportRow(wrk, src);
123e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    if (!wrk->y_expand) {     // Accumulate the contribution of the new row.
124e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      int x;
125e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      for (x = 0; x < wrk->num_channels * wrk->dst_width; ++x) {
126e8a1b86cc3afe4791ab40d89240c40797a400131James Zern        wrk->irow[x] += wrk->frow[x];
127e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      }
128a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
129e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    ++wrk->src_y;
130a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    src += src_stride;
131a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    ++total_imported;
132a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    wrk->y_accum -= wrk->y_sub;
133a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
134a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return total_imported;
135a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
136a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
137a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Aroraint WebPRescalerExport(WebPRescaler* const rescaler) {
138a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int total_exported = 0;
139a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  while (WebPRescalerHasPendingOutput(rescaler)) {
140e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    WebPRescalerExportRow(rescaler);
141a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    ++total_exported;
142a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
143a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return total_exported;
144a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
145a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
146a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
147