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"
187c8da7ce66017295a65ec028084b90800be377f8James Zern#include "./rescaler.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) {
51e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    // this is WEBP_RESCALER_FRAC(dst_height, x_add * y_add) without the cast.
52e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    const uint64_t ratio =
53e8a1b86cc3afe4791ab40d89240c40797a400131James Zern        (uint64_t)dst_height * WEBP_RESCALER_ONE / (wrk->x_add * wrk->y_add);
54e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    if (ratio != (uint32_t)ratio) {
55e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      // We can't represent the ratio with the current fixed-point precision.
56e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      // => We special-case fxy_scale = 0, in WebPRescalerExportRow().
57e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      wrk->fxy_scale = 0;
58e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    } else {
59e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      wrk->fxy_scale = (uint32_t)ratio;
60e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    }
61e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    wrk->fy_scale = WEBP_RESCALER_FRAC(1, wrk->y_sub);
62e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  } else {
63e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    wrk->fy_scale = WEBP_RESCALER_FRAC(1, wrk->x_add);
64e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    // wrk->fxy_scale is unused here.
65e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  }
6633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  wrk->irow = work;
6733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  wrk->frow = work + num_channels * dst_width;
68e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  memset(work, 0, 2 * dst_width * num_channels * sizeof(*work));
6933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
707c8da7ce66017295a65ec028084b90800be377f8James Zern  WebPRescalerDspInit();
717c8da7ce66017295a65ec028084b90800be377f8James Zern}
727c8da7ce66017295a65ec028084b90800be377f8James Zern
737c8da7ce66017295a65ec028084b90800be377f8James Zernint WebPRescalerGetScaledDimensions(int src_width, int src_height,
747c8da7ce66017295a65ec028084b90800be377f8James Zern                                    int* const scaled_width,
757c8da7ce66017295a65ec028084b90800be377f8James Zern                                    int* const scaled_height) {
767c8da7ce66017295a65ec028084b90800be377f8James Zern  assert(scaled_width != NULL);
777c8da7ce66017295a65ec028084b90800be377f8James Zern  assert(scaled_height != NULL);
787c8da7ce66017295a65ec028084b90800be377f8James Zern  {
797c8da7ce66017295a65ec028084b90800be377f8James Zern    int width = *scaled_width;
807c8da7ce66017295a65ec028084b90800be377f8James Zern    int height = *scaled_height;
817c8da7ce66017295a65ec028084b90800be377f8James Zern
827c8da7ce66017295a65ec028084b90800be377f8James Zern    // if width is unspecified, scale original proportionally to height ratio.
837c8da7ce66017295a65ec028084b90800be377f8James Zern    if (width == 0) {
847c8da7ce66017295a65ec028084b90800be377f8James Zern      width = (src_width * height + src_height / 2) / src_height;
8533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
867c8da7ce66017295a65ec028084b90800be377f8James Zern    // if height is unspecified, scale original proportionally to width ratio.
877c8da7ce66017295a65ec028084b90800be377f8James Zern    if (height == 0) {
887c8da7ce66017295a65ec028084b90800be377f8James Zern      height = (src_height * width + src_width / 2) / src_width;
897c8da7ce66017295a65ec028084b90800be377f8James Zern    }
907c8da7ce66017295a65ec028084b90800be377f8James Zern    // Check if the overall dimensions still make sense.
917c8da7ce66017295a65ec028084b90800be377f8James Zern    if (width <= 0 || height <= 0) {
927c8da7ce66017295a65ec028084b90800be377f8James Zern      return 0;
937c8da7ce66017295a65ec028084b90800be377f8James Zern    }
947c8da7ce66017295a65ec028084b90800be377f8James Zern
957c8da7ce66017295a65ec028084b90800be377f8James Zern    *scaled_width = width;
967c8da7ce66017295a65ec028084b90800be377f8James Zern    *scaled_height = height;
977c8da7ce66017295a65ec028084b90800be377f8James Zern    return 1;
98a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
99a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
100a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
101a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
102a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// all-in-one calls
103a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
1048b720228d581a84fd173b6dcb2fa295b59db489aVikas Aroraint WebPRescaleNeededLines(const WebPRescaler* const wrk, int max_num_lines) {
1058b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int num_lines = (wrk->y_accum + wrk->y_sub - 1) / wrk->y_sub;
1068b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return (num_lines > max_num_lines) ? max_num_lines : num_lines;
1078b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora}
1088b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
109a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Aroraint WebPRescalerImport(WebPRescaler* const wrk, int num_lines,
110a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                       const uint8_t* src, int src_stride) {
111a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int total_imported = 0;
112e8a1b86cc3afe4791ab40d89240c40797a400131James Zern  while (total_imported < num_lines && !WebPRescalerHasPendingOutput(wrk)) {
113e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    if (wrk->y_expand) {
114e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      rescaler_t* const tmp = wrk->irow;
115e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      wrk->irow = wrk->frow;
116e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      wrk->frow = tmp;
117e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    }
118e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    WebPRescalerImportRow(wrk, src);
119e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    if (!wrk->y_expand) {     // Accumulate the contribution of the new row.
120e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      int x;
121e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      for (x = 0; x < wrk->num_channels * wrk->dst_width; ++x) {
122e8a1b86cc3afe4791ab40d89240c40797a400131James Zern        wrk->irow[x] += wrk->frow[x];
123e8a1b86cc3afe4791ab40d89240c40797a400131James Zern      }
124a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
125e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    ++wrk->src_y;
126a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    src += src_stride;
127a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    ++total_imported;
128a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    wrk->y_accum -= wrk->y_sub;
129a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
130a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return total_imported;
131a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
132a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
133a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Aroraint WebPRescalerExport(WebPRescaler* const rescaler) {
134a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int total_exported = 0;
135a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  while (WebPRescalerHasPendingOutput(rescaler)) {
136e8a1b86cc3afe4791ab40d89240c40797a400131James Zern    WebPRescalerExportRow(rescaler);
137a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    ++total_exported;
138a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
139a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return total_exported;
140a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
141a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
142a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
143