1 // Copyright 2012 Google Inc. All Rights Reserved.
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 // -----------------------------------------------------------------------------
10 // Rescaling functions
12 // Author: Skal (pascal.massimino@gmail.com)
16 #include "./rescaler.h"
18 //------------------------------------------------------------------------------
21 #define MULT_FIX(x, y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX)
23 void WebPRescalerInit(WebPRescaler
* const wrk
, int src_width
, int src_height
,
24 uint8_t* const dst
, int dst_width
, int dst_height
,
25 int dst_stride
, int num_channels
, int x_add
, int x_sub
,
26 int y_add
, int y_sub
, int32_t* const work
) {
27 wrk
->x_expand
= (src_width
< dst_width
);
28 wrk
->src_width
= src_width
;
29 wrk
->src_height
= src_height
;
30 wrk
->dst_width
= dst_width
;
31 wrk
->dst_height
= dst_height
;
33 wrk
->dst_stride
= dst_stride
;
34 wrk
->num_channels
= num_channels
;
35 // for 'x_expand', we use bilinear interpolation
36 wrk
->x_add
= wrk
->x_expand
? (x_sub
- 1) : x_add
- x_sub
;
37 wrk
->x_sub
= wrk
->x_expand
? (x_add
- 1) : x_sub
;
41 wrk
->fx_scale
= (1 << RFIX
) / x_sub
;
42 wrk
->fy_scale
= (1 << RFIX
) / y_sub
;
43 wrk
->fxy_scale
= wrk
->x_expand
?
44 ((int64_t)dst_height
<< RFIX
) / (x_sub
* src_height
) :
45 ((int64_t)dst_height
<< RFIX
) / (x_add
* src_height
);
47 wrk
->frow
= work
+ num_channels
* dst_width
;
50 void WebPRescalerImportRow(WebPRescaler
* const wrk
,
51 const uint8_t* const src
, int channel
) {
52 const int x_stride
= wrk
->num_channels
;
53 const int x_out_max
= wrk
->dst_width
* wrk
->num_channels
;
59 for (x_out
= channel
; x_out
< x_out_max
; x_out
+= x_stride
) {
61 for (; accum
> 0; accum
-= wrk
->x_sub
) {
65 { // Emit next horizontal pixel.
66 const int32_t base
= src
[x_in
];
67 const int32_t frac
= base
* (-accum
);
69 wrk
->frow
[x_out
] = (sum
+ base
) * wrk
->x_sub
- frac
;
70 // fresh fractional start for next pixel
71 sum
= (int)MULT_FIX(frac
, wrk
->fx_scale
);
74 } else { // simple bilinear interpolation
75 int left
= src
[channel
], right
= src
[channel
];
76 for (x_out
= channel
; x_out
< x_out_max
; x_out
+= x_stride
) {
83 wrk
->frow
[x_out
] = right
* wrk
->x_add
+ (left
- right
) * accum
;
87 // Accumulate the new row's contribution
88 for (x_out
= channel
; x_out
< x_out_max
; x_out
+= x_stride
) {
89 wrk
->irow
[x_out
] += wrk
->frow
[x_out
];
93 uint8_t* WebPRescalerExportRow(WebPRescaler
* const wrk
) {
94 if (wrk
->y_accum
<= 0) {
96 uint8_t* const dst
= wrk
->dst
;
97 int32_t* const irow
= wrk
->irow
;
98 const int32_t* const frow
= wrk
->frow
;
99 const int yscale
= wrk
->fy_scale
* (-wrk
->y_accum
);
100 const int x_out_max
= wrk
->dst_width
* wrk
->num_channels
;
102 for (x_out
= 0; x_out
< x_out_max
; ++x_out
) {
103 const int frac
= (int)MULT_FIX(frow
[x_out
], yscale
);
104 const int v
= (int)MULT_FIX(irow
[x_out
] - frac
, wrk
->fxy_scale
);
105 dst
[x_out
] = (!(v
& ~0xff)) ? v
: (v
< 0) ? 0 : 255;
106 irow
[x_out
] = frac
; // new fractional start
108 wrk
->y_accum
+= wrk
->y_add
;
109 wrk
->dst
+= wrk
->dst_stride
;
119 //------------------------------------------------------------------------------
122 int WebPRescaleNeededLines(const WebPRescaler
* const wrk
, int max_num_lines
) {
123 const int num_lines
= (wrk
->y_accum
+ wrk
->y_sub
- 1) / wrk
->y_sub
;
124 return (num_lines
> max_num_lines
) ? max_num_lines
: num_lines
;
127 int WebPRescalerImport(WebPRescaler
* const wrk
, int num_lines
,
128 const uint8_t* src
, int src_stride
) {
129 int total_imported
= 0;
130 while (total_imported
< num_lines
&& wrk
->y_accum
> 0) {
132 for (channel
= 0; channel
< wrk
->num_channels
; ++channel
) {
133 WebPRescalerImportRow(wrk
, src
, channel
);
137 wrk
->y_accum
-= wrk
->y_sub
;
139 return total_imported
;
142 int WebPRescalerExport(WebPRescaler
* const rescaler
) {
143 int total_exported
= 0;
144 while (WebPRescalerHasPendingOutput(rescaler
)) {
145 WebPRescalerExportRow(rescaler
);
148 return total_exported
;
151 //------------------------------------------------------------------------------