oil 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -0
- data/Rakefile +1 -3
- data/ext/oil/extconf.rb +1 -1
- data/ext/oil/jpeg.c +68 -42
- data/ext/oil/oil.c +19 -2
- data/ext/oil/png.c +52 -31
- data/ext/oil/resample.c +719 -245
- data/ext/oil/resample.h +101 -28
- data/lib/oil.rb +2 -39
- data/test/test_png.rb +1 -2
- metadata +3 -5
- data/ext/oil/yscaler.c +0 -167
- data/ext/oil/yscaler.h +0 -33
data/ext/oil/resample.c
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (c) 2014-2016 Timothy Elliott
|
3
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
* of this software and associated documentation files (the "Software"), to deal
|
5
|
+
* in the Software without restriction, including without limitation the rights
|
6
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
* copies of the Software, and to permit persons to whom the Software is
|
8
|
+
* furnished to do so, subject to the following conditions:
|
9
|
+
*
|
10
|
+
* The above copyright notice and this permission notice shall be included in
|
11
|
+
* all copies or substantial portions of the Software.
|
12
|
+
*
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
* THE SOFTWARE.
|
20
|
+
*/
|
21
|
+
|
1
22
|
#include "resample.h"
|
2
23
|
#include <stdint.h>
|
3
24
|
#include <math.h>
|
@@ -26,7 +47,7 @@ typedef int64_t fix33_30;
|
|
26
47
|
* The best possible value was determined by comparing to a reference
|
27
48
|
* implementation and comparing values for the minimal number of errors.
|
28
49
|
*/
|
29
|
-
#define TOPOFF
|
50
|
+
#define TOPOFF 8192
|
30
51
|
|
31
52
|
/**
|
32
53
|
* Signed type that uses 1 bit for signedness, 1 bit for the integer, and 30
|
@@ -42,9 +63,9 @@ typedef int32_t fix1_30;
|
|
42
63
|
/**
|
43
64
|
* Calculate the greatest common denominator between a and b.
|
44
65
|
*/
|
45
|
-
static
|
66
|
+
static uint32_t gcd(uint32_t a, uint32_t b)
|
46
67
|
{
|
47
|
-
|
68
|
+
uint32_t c;
|
48
69
|
while (a != 0) {
|
49
70
|
c = a;
|
50
71
|
a = b%a;
|
@@ -56,46 +77,32 @@ static long gcd (long a, long b)
|
|
56
77
|
/**
|
57
78
|
* Round and clamp a fix33_30 value between 0 and 255. Returns an unsigned char.
|
58
79
|
*/
|
59
|
-
static
|
80
|
+
static uint16_t clamp(fix33_30 x)
|
60
81
|
{
|
61
|
-
|
62
|
-
|
63
|
-
}
|
64
|
-
|
65
|
-
/* bump up rounding errors before truncating */
|
66
|
-
x += TOPOFF;
|
67
|
-
|
68
|
-
/* This is safe because we have the < 0 check above and a sample can't
|
69
|
-
* end up with a value over 512 */
|
70
|
-
if (x & (1l<<38)) {
|
71
|
-
return 255;
|
72
|
-
}
|
73
|
-
|
82
|
+
x += 1 << 29;
|
83
|
+
x = x < 0 ? 0 : (x > (65535L << 30) ? (65535L << 30) : x);
|
74
84
|
return x >> 30;
|
75
85
|
}
|
76
86
|
|
77
|
-
|
78
|
-
* Map from a discreet dest coordinate to a continuous source coordinate.
|
79
|
-
* The resulting coordinate can range from -0.5 to the maximum of the
|
80
|
-
* destination image dimension.
|
81
|
-
*/
|
82
|
-
static double map(long pos, double scale)
|
87
|
+
static uint8_t clamp8(fix33_30 x)
|
83
88
|
{
|
84
|
-
return (
|
89
|
+
return (clamp(x) + (1 << 7)) / 257;
|
85
90
|
}
|
86
91
|
|
87
92
|
/**
|
88
93
|
* Given input and output dimensions and an output position, return the
|
89
94
|
* corresponding input position and put the sub-pixel remainder in rest.
|
95
|
+
*
|
96
|
+
* Map from a discreet dest coordinate to a continuous source coordinate.
|
97
|
+
* The resulting coordinate can range from -0.5 to the maximum of the
|
98
|
+
* destination image dimension.
|
90
99
|
*/
|
91
|
-
|
92
|
-
float *rest)
|
100
|
+
int32_t split_map(uint32_t dim_in, uint32_t dim_out, uint32_t pos, float *rest)
|
93
101
|
{
|
94
|
-
double
|
95
|
-
|
102
|
+
double smp;
|
103
|
+
int32_t smp_i;
|
96
104
|
|
97
|
-
|
98
|
-
smp = map(pos, scale);
|
105
|
+
smp = (pos + 0.5) * ((double)dim_in / dim_out) - 0.5;
|
99
106
|
smp_i = smp < 0 ? -1 : smp;
|
100
107
|
*rest = smp - smp_i;
|
101
108
|
return smp_i;
|
@@ -108,42 +115,14 @@ long split_map(unsigned long dim_in, unsigned long dim_out, unsigned long pos,
|
|
108
115
|
* When we reduce an image by a factor of two, we need to scale our resampling
|
109
116
|
* function by two as well in order to avoid aliasing.
|
110
117
|
*/
|
111
|
-
|
118
|
+
uint64_t calc_taps(uint32_t dim_in, uint32_t dim_out)
|
112
119
|
{
|
113
|
-
|
114
|
-
|
120
|
+
uint64_t tmp;
|
115
121
|
if (dim_out > dim_in) {
|
116
122
|
return TAPS;
|
117
123
|
}
|
118
|
-
|
119
|
-
tmp
|
120
|
-
/* Round up to the nearest even integer */
|
121
|
-
return tmp + (tmp&1);
|
122
|
-
}
|
123
|
-
|
124
|
-
/**
|
125
|
-
* Helper macros to extract byte components from an int32_t holding rgba.
|
126
|
-
*/
|
127
|
-
#define rgba_r(x) ((x) & 0x000000FF)
|
128
|
-
#define rgba_g(x) (((x) & 0x0000FF00) >> 8)
|
129
|
-
#define rgba_b(x) (((x) & 0x00FF0000) >> 16)
|
130
|
-
#define rgba_a(x) (((x) & 0xFF000000) >> 24)
|
131
|
-
|
132
|
-
/**
|
133
|
-
* Convert rgb values in fix33_30 types to a uint32_t.
|
134
|
-
*/
|
135
|
-
static uint32_t fix33_30_to_rgbx(fix33_30 r, fix33_30 g, fix33_30 b)
|
136
|
-
{
|
137
|
-
return clamp(r) + ((uint32_t)clamp(g) << 8) +
|
138
|
-
((uint32_t)clamp(b) << 16);
|
139
|
-
}
|
140
|
-
|
141
|
-
/**
|
142
|
-
* Convert rgba values in fix33_30 types to a uint32_t.
|
143
|
-
*/
|
144
|
-
static uint32_t fix33_30_to_rgba(fix33_30 r, fix33_30 g, fix33_30 b, fix33_30 a)
|
145
|
-
{
|
146
|
-
return fix33_30_to_rgbx(r, g, b) + ((uint32_t)clamp(a) << 24);
|
124
|
+
tmp = (uint64_t)TAPS * dim_in / dim_out;
|
125
|
+
return tmp - (tmp & 1);
|
147
126
|
}
|
148
127
|
|
149
128
|
/**
|
@@ -152,9 +131,9 @@ static uint32_t fix33_30_to_rgba(fix33_30 r, fix33_30 g, fix33_30 b, fix33_30 a)
|
|
152
131
|
static float catrom(float x)
|
153
132
|
{
|
154
133
|
if (x<1) {
|
155
|
-
return (3*x
|
134
|
+
return ((3*x - 5)*x*x + 2) / 2;
|
156
135
|
}
|
157
|
-
return (-
|
136
|
+
return (((5 - x)*x - 8)*x + 4) / 2;
|
158
137
|
}
|
159
138
|
|
160
139
|
/**
|
@@ -171,127 +150,191 @@ static fix1_30 f_to_fix1_30(float x)
|
|
171
150
|
*
|
172
151
|
* The coefficients are stored as fix1_30 fixed point ints in coeffs.
|
173
152
|
*/
|
174
|
-
static void calc_coeffs(fix1_30 *coeffs, float tx,
|
153
|
+
static void calc_coeffs(fix1_30 *coeffs, float tx, uint32_t taps)
|
175
154
|
{
|
176
|
-
|
177
|
-
float tmp,
|
155
|
+
uint32_t i;
|
156
|
+
float tmp, tap_mult, fudge;
|
178
157
|
fix1_30 tmp_fixed;
|
179
158
|
|
180
|
-
|
181
|
-
|
182
|
-
tap_mult = (double)taps / TAPS;
|
159
|
+
tap_mult = (float)taps / TAPS;
|
183
160
|
tx = 1 - tx - taps / 2;
|
161
|
+
fudge = 1.0;
|
184
162
|
|
185
163
|
for (i=0; i<taps; i++) {
|
186
|
-
tmp = catrom(fabsf(tx) / tap_mult);
|
164
|
+
tmp = catrom(fabsf(tx) / tap_mult) / tap_mult;
|
165
|
+
fudge -= tmp;
|
187
166
|
tmp_fixed = f_to_fix1_30(tmp);
|
188
167
|
coeffs[i] = tmp_fixed;
|
189
|
-
total += tmp;
|
190
168
|
tx += 1;
|
191
169
|
}
|
170
|
+
coeffs[taps / 2] += f_to_fix1_30(fudge);
|
171
|
+
}
|
192
172
|
|
193
|
-
|
194
|
-
|
173
|
+
/* bicubic y-scaler */
|
174
|
+
|
175
|
+
static uint8_t linear_sample_to_srgb(uint16_t in)
|
176
|
+
{
|
177
|
+
double in_f, s1, s2, s3;
|
178
|
+
if (in <= 248) {
|
179
|
+
return (in * 3295 + 32768) >> 16;
|
195
180
|
}
|
181
|
+
in_f = in / 65535.0;
|
182
|
+
s1 = sqrt(in_f);
|
183
|
+
s2 = sqrt(s1);
|
184
|
+
s3 = sqrt(s2);
|
185
|
+
return (0.0427447 + 0.547242 * s1 + 0.928361 * s2 - 0.518123 * s3) * 255 + 0.5;
|
196
186
|
}
|
197
187
|
|
198
|
-
|
199
|
-
*
|
200
|
-
*/
|
201
|
-
static void yscale_gen(long len, long height, fix1_30 *coeffs,
|
202
|
-
unsigned char **in, unsigned char *out)
|
188
|
+
static void strip_scale_rgbx(uint16_t **in, uint32_t strip_height, size_t len,
|
189
|
+
uint8_t *out, fix1_30 *coeffs)
|
203
190
|
{
|
204
|
-
|
205
|
-
|
191
|
+
size_t i;
|
192
|
+
uint32_t j;
|
193
|
+
fix33_30 coeff, sum[3];
|
206
194
|
|
207
|
-
for (i=0; i<len; i
|
208
|
-
|
209
|
-
for (j=0; j<
|
195
|
+
for (i=0; i<len; i+=4) {
|
196
|
+
sum[0] = sum[1] = sum[2] = 0;
|
197
|
+
for (j=0; j<strip_height; j++) {
|
210
198
|
coeff = coeffs[j];
|
211
|
-
|
199
|
+
sum[0] += coeff * in[j][i];
|
200
|
+
sum[1] += coeff * in[j][i + 1];
|
201
|
+
sum[2] += coeff * in[j][i + 2];
|
212
202
|
}
|
213
|
-
out[
|
203
|
+
out[0] = linear_sample_to_srgb(clamp(sum[0]));
|
204
|
+
out[1] = linear_sample_to_srgb(clamp(sum[1]));
|
205
|
+
out[2] = linear_sample_to_srgb(clamp(sum[2]));
|
206
|
+
out[3] = 0;
|
207
|
+
out += 4;
|
214
208
|
}
|
215
209
|
}
|
216
210
|
|
217
|
-
|
218
|
-
*
|
219
|
-
* performance.
|
220
|
-
*/
|
221
|
-
static void yscale_rgba(long width, long height, fix1_30 *coeffs,
|
222
|
-
uint32_t **sl_in, uint32_t *sl_out)
|
211
|
+
static void strip_scale_rgb(uint16_t **in, uint32_t strip_height, size_t len,
|
212
|
+
uint8_t *out, fix1_30 *coeffs)
|
223
213
|
{
|
224
|
-
|
225
|
-
|
226
|
-
|
214
|
+
size_t i;
|
215
|
+
uint32_t j;
|
216
|
+
fix33_30 coeff, sum[3];
|
227
217
|
|
228
|
-
for (i=0; i<
|
229
|
-
|
230
|
-
for (j=0; j<
|
218
|
+
for (i=0; i<len; i+=4) {
|
219
|
+
sum[0] = sum[1] = sum[2] = 0;
|
220
|
+
for (j=0; j<strip_height; j++) {
|
231
221
|
coeff = coeffs[j];
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
b += coeff * rgba_b(sample);
|
236
|
-
a += coeff * rgba_a(sample);
|
222
|
+
sum[0] += coeff * in[j][i];
|
223
|
+
sum[1] += coeff * in[j][i + 1];
|
224
|
+
sum[2] += coeff * in[j][i + 2];
|
237
225
|
}
|
238
|
-
|
226
|
+
out[0] = linear_sample_to_srgb(clamp(sum[0]));
|
227
|
+
out[1] = linear_sample_to_srgb(clamp(sum[1]));
|
228
|
+
out[2] = linear_sample_to_srgb(clamp(sum[2]));
|
229
|
+
out += 3;
|
239
230
|
}
|
240
231
|
}
|
241
232
|
|
242
|
-
|
243
|
-
*
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
233
|
+
static void strip_scale_g(uint16_t **in, uint32_t strip_height, size_t len,
|
234
|
+
uint8_t *out, fix1_30 *coeffs)
|
235
|
+
{
|
236
|
+
size_t i;
|
237
|
+
uint32_t j;
|
238
|
+
fix33_30 sum;
|
239
|
+
|
240
|
+
for (i=0; i<len; i++) {
|
241
|
+
sum = 0;
|
242
|
+
for (j=0; j<strip_height; j++) {
|
243
|
+
sum += (fix33_30)coeffs[j] * in[j][i];
|
244
|
+
}
|
245
|
+
out[i] = clamp8(sum);
|
246
|
+
}
|
247
|
+
}
|
248
|
+
|
249
|
+
static void strip_scale_rgba(uint16_t **in, uint32_t strip_height, size_t len,
|
250
|
+
uint8_t *out, fix1_30 *coeffs)
|
248
251
|
{
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
+
size_t i;
|
253
|
+
uint32_t j;
|
254
|
+
fix33_30 coeff, sum[4];
|
252
255
|
|
253
|
-
for (i=0; i<
|
254
|
-
|
255
|
-
for (j=0; j<
|
256
|
+
for (i=0; i<len; i+=4) {
|
257
|
+
sum[0] = sum[1] = sum[2] = sum[3] = 0;
|
258
|
+
for (j=0; j<strip_height; j++) {
|
256
259
|
coeff = coeffs[j];
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
260
|
+
sum[0] += coeff * in[j][i];
|
261
|
+
sum[1] += coeff * in[j][i + 1];
|
262
|
+
sum[2] += coeff * in[j][i + 2];
|
263
|
+
sum[3] += coeff * in[j][i + 3];
|
261
264
|
}
|
262
|
-
|
265
|
+
out[0] = linear_sample_to_srgb(clamp(sum[0]));
|
266
|
+
out[1] = linear_sample_to_srgb(clamp(sum[1]));
|
267
|
+
out[2] = linear_sample_to_srgb(clamp(sum[2]));
|
268
|
+
out[3] = clamp8(sum[3]);
|
269
|
+
out += 4;
|
263
270
|
}
|
264
271
|
}
|
265
272
|
|
266
|
-
void
|
267
|
-
|
273
|
+
static void strip_scale_cmyk(uint16_t **in, uint32_t strip_height, size_t len,
|
274
|
+
uint8_t *out, fix1_30 *coeffs)
|
275
|
+
{
|
276
|
+
size_t i;
|
277
|
+
uint32_t j;
|
278
|
+
fix33_30 coeff, sum[4];
|
279
|
+
|
280
|
+
for (i=0; i<len; i+=4) {
|
281
|
+
sum[0] = sum[1] = sum[2] = sum[3] = 0;
|
282
|
+
for (j=0; j<strip_height; j++) {
|
283
|
+
coeff = coeffs[j];
|
284
|
+
sum[0] += coeff * in[j][i];
|
285
|
+
sum[1] += coeff * in[j][i + 1];
|
286
|
+
sum[2] += coeff * in[j][i + 2];
|
287
|
+
sum[3] += coeff * in[j][i + 3];
|
288
|
+
}
|
289
|
+
out[0] = clamp8(sum[0]);
|
290
|
+
out[1] = clamp8(sum[1]);
|
291
|
+
out[2] = clamp8(sum[2]);
|
292
|
+
out[3] = clamp8(sum[3]);
|
293
|
+
out += 4;
|
294
|
+
}
|
295
|
+
}
|
296
|
+
|
297
|
+
int strip_scale(uint16_t **in, uint32_t strip_height, size_t len, uint8_t *out,
|
298
|
+
float ty, enum oil_colorspace cs)
|
268
299
|
{
|
269
300
|
fix1_30 *coeffs;
|
270
301
|
|
271
302
|
coeffs = malloc(strip_height * sizeof(fix1_30));
|
303
|
+
if (!coeffs) {
|
304
|
+
return -2; // unable to allocate
|
305
|
+
}
|
272
306
|
calc_coeffs(coeffs, ty, strip_height);
|
273
307
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
308
|
+
switch(cs) {
|
309
|
+
case OIL_CS_G:
|
310
|
+
case OIL_CS_GA:
|
311
|
+
strip_scale_g(in, strip_height, len, out, coeffs);
|
312
|
+
break;
|
313
|
+
case OIL_CS_RGB:
|
314
|
+
strip_scale_rgb(in, strip_height, len, out, coeffs);
|
315
|
+
break;
|
316
|
+
case OIL_CS_RGBX:
|
317
|
+
strip_scale_rgbx(in, strip_height, len, out, coeffs);
|
318
|
+
break;
|
319
|
+
case OIL_CS_RGBA:
|
320
|
+
strip_scale_rgba(in, strip_height, len, out, coeffs);
|
321
|
+
break;
|
322
|
+
case OIL_CS_CMYK:
|
323
|
+
strip_scale_cmyk(in, strip_height, len, out, coeffs);
|
324
|
+
break;
|
283
325
|
}
|
284
326
|
|
285
327
|
free(coeffs);
|
328
|
+
return 0;
|
286
329
|
}
|
287
330
|
|
288
331
|
/* Bicubic x scaler */
|
289
332
|
|
290
|
-
static void sample_generic(
|
291
|
-
|
333
|
+
static void sample_generic(uint32_t taps, fix1_30 *coeffs, uint16_t *in,
|
334
|
+
uint16_t *out, uint8_t cmp)
|
292
335
|
{
|
293
|
-
|
294
|
-
|
336
|
+
uint8_t i;
|
337
|
+
uint32_t j;
|
295
338
|
fix33_30 total, coeff;
|
296
339
|
|
297
340
|
for (i=0; i<cmp; i++) {
|
@@ -304,139 +347,113 @@ static void sample_generic(int cmp, long taps, fix1_30 *coeffs,
|
|
304
347
|
}
|
305
348
|
}
|
306
349
|
|
307
|
-
static
|
350
|
+
static void sample_rgba(uint32_t taps, fix1_30 *coeffs, uint16_t *in,
|
351
|
+
uint16_t *out)
|
308
352
|
{
|
309
|
-
|
310
|
-
fix33_30
|
311
|
-
uint32_t sample;
|
353
|
+
uint32_t i;
|
354
|
+
fix33_30 sum[4], coeff;
|
312
355
|
|
313
|
-
|
356
|
+
sum[0] = sum[1] = sum[2] = sum[3] = 0;
|
314
357
|
for (i=0; i<taps; i++) {
|
315
358
|
coeff = coeffs[i];
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
359
|
+
sum[0] += coeff * in[0];
|
360
|
+
sum[1] += coeff * in[1];
|
361
|
+
sum[2] += coeff * in[2];
|
362
|
+
sum[3] += coeff * in[3];
|
363
|
+
in += 4;
|
321
364
|
}
|
322
|
-
|
365
|
+
out[0] = clamp(sum[0]);
|
366
|
+
out[1] = clamp(sum[1]);
|
367
|
+
out[2] = clamp(sum[2]);
|
368
|
+
out[3] = clamp(sum[3]);
|
323
369
|
}
|
324
370
|
|
325
|
-
static
|
371
|
+
static void sample_rgbx(uint32_t taps, fix1_30 *coeffs, uint16_t *in,
|
372
|
+
uint16_t *out)
|
326
373
|
{
|
327
|
-
|
328
|
-
fix33_30
|
329
|
-
uint32_t sample;
|
374
|
+
uint32_t i;
|
375
|
+
fix33_30 sum[3], coeff;
|
330
376
|
|
331
|
-
|
377
|
+
sum[0] = sum[1] = sum[2] = 0;
|
332
378
|
for (i=0; i<taps; i++) {
|
333
379
|
coeff = coeffs[i];
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
380
|
+
sum[0] += coeff * in[0];
|
381
|
+
sum[1] += coeff * in[1];
|
382
|
+
sum[2] += coeff * in[2];
|
383
|
+
in += 4;
|
338
384
|
}
|
339
|
-
|
385
|
+
out[0] = clamp(sum[0]);
|
386
|
+
out[1] = clamp(sum[1]);
|
387
|
+
out[2] = clamp(sum[2]);
|
388
|
+
out[3] = 0;
|
340
389
|
}
|
341
390
|
|
342
|
-
static void xscale_set_sample(
|
343
|
-
|
391
|
+
static void xscale_set_sample(uint32_t taps, fix1_30 *coeffs, uint16_t *in,
|
392
|
+
uint16_t *out, enum oil_colorspace cs)
|
344
393
|
{
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
394
|
+
switch(cs) {
|
395
|
+
case OIL_CS_G:
|
396
|
+
case OIL_CS_GA:
|
397
|
+
case OIL_CS_RGB:
|
398
|
+
sample_generic(taps, coeffs, in, out, CS_TO_CMP(cs));
|
399
|
+
break;
|
400
|
+
case OIL_CS_RGBX:
|
401
|
+
sample_rgbx(taps, coeffs, in, out);
|
402
|
+
break;
|
403
|
+
case OIL_CS_RGBA:
|
404
|
+
case OIL_CS_CMYK:
|
405
|
+
sample_rgba(taps, coeffs, in, out);
|
406
|
+
break;
|
351
407
|
}
|
352
408
|
}
|
353
409
|
|
354
|
-
|
355
|
-
|
356
|
-
/**
|
357
|
-
* Scanline with extra space at the beginning and end. This allows us to extend
|
358
|
-
* a scanline to the left and right. This in turn allows resizing functions
|
359
|
-
* to operate past the edges of the scanline without having to check for
|
360
|
-
* boundaries.
|
361
|
-
*/
|
362
|
-
struct padded_sl {
|
363
|
-
unsigned char *buf;
|
364
|
-
unsigned char *pad_left;
|
365
|
-
long inner_width;
|
366
|
-
long pad_width;
|
367
|
-
int cmp;
|
368
|
-
};
|
369
|
-
|
370
|
-
void padded_sl_init(struct padded_sl *psl, long inner_width, long pad_width,
|
371
|
-
int cmp)
|
372
|
-
{
|
373
|
-
psl->inner_width = inner_width;
|
374
|
-
psl->pad_width = pad_width;
|
375
|
-
psl->cmp = cmp;
|
376
|
-
psl->pad_left = malloc((inner_width + 2 * pad_width) * cmp);
|
377
|
-
psl->buf = psl->pad_left + pad_width * cmp;
|
378
|
-
}
|
379
|
-
|
380
|
-
void padded_sl_free(struct padded_sl *psl)
|
381
|
-
{
|
382
|
-
free(psl->pad_left);
|
383
|
-
}
|
384
|
-
|
385
|
-
/**
|
386
|
-
* pad points to the first byte in the pad area.
|
387
|
-
* src points to the sample that will be replicated in the pad area.
|
388
|
-
* width is the number of samples in the pad area.
|
389
|
-
* cmp is the number of components per sample.
|
390
|
-
*/
|
391
|
-
static void padded_sl_pad(unsigned char *pad, unsigned char *src, int width,
|
392
|
-
int cmp)
|
410
|
+
void padded_sl_extend_edges(uint16_t *buf, uint32_t width, size_t pad_len,
|
411
|
+
uint8_t cmp)
|
393
412
|
{
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
413
|
+
uint16_t *pad_right;
|
414
|
+
size_t i;
|
415
|
+
pad_right = buf + pad_len + (size_t)width * cmp;
|
416
|
+
for (i=0; i<pad_len; i++) {
|
417
|
+
buf[i] = (buf + pad_len)[i % cmp];
|
418
|
+
pad_right[i] = (pad_right - cmp)[i % cmp];
|
419
|
+
}
|
399
420
|
}
|
400
421
|
|
401
|
-
|
422
|
+
size_t padded_sl_len_offset(uint32_t in_width, uint32_t out_width,
|
423
|
+
uint8_t cmp, size_t *offset)
|
402
424
|
{
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
padded_sl_pad(pad_right, pad_right - psl->cmp, psl->pad_width, psl->cmp);
|
425
|
+
uint64_t taps;
|
426
|
+
taps = calc_taps(in_width, out_width);
|
427
|
+
*offset = (taps / 2 + 1) * cmp;
|
428
|
+
return ((size_t)in_width * cmp + *offset * 2) * sizeof(uint16_t);
|
408
429
|
}
|
409
430
|
|
410
|
-
|
411
|
-
|
431
|
+
int xscale_padded(uint16_t *in, uint32_t in_width, uint16_t *out,
|
432
|
+
uint32_t out_width, enum oil_colorspace cs)
|
412
433
|
{
|
413
434
|
float tx;
|
414
435
|
fix1_30 *coeffs;
|
415
|
-
|
416
|
-
|
417
|
-
|
436
|
+
uint32_t i, j, in_chunk, out_chunk, scale_gcd;
|
437
|
+
int32_t xsmp_i;
|
438
|
+
uint64_t taps;
|
439
|
+
uint16_t *out_pos, *tmp;
|
440
|
+
uint8_t cmp;
|
441
|
+
|
442
|
+
if (!in_width || !out_width) {
|
443
|
+
return -1; // bad input parameter
|
444
|
+
}
|
418
445
|
|
446
|
+
cmp = CS_TO_CMP(cs);
|
419
447
|
taps = calc_taps(in_width, out_width);
|
420
448
|
coeffs = malloc(taps * sizeof(fix1_30));
|
449
|
+
if (!coeffs) {
|
450
|
+
return -2; // unable to allocate space for coefficients
|
451
|
+
}
|
421
452
|
|
422
453
|
scale_gcd = gcd(in_width, out_width);
|
423
454
|
in_chunk = in_width / scale_gcd;
|
424
455
|
out_chunk = out_width / scale_gcd;
|
425
456
|
|
426
|
-
if (in_width < taps * 2) {
|
427
|
-
padded_sl_init(&psl, in_width, taps / 2 + 1, cmp);
|
428
|
-
memcpy(psl.buf, in, in_width * cmp);
|
429
|
-
rpadv = psl.buf;
|
430
|
-
} else {
|
431
|
-
/* just the ends of the scanline with edges extended */
|
432
|
-
padded_sl_init(&psl, 2 * taps - 2, taps / 2 + 1, cmp);
|
433
|
-
memcpy(psl.buf, in, (taps - 1) * cmp);
|
434
|
-
memcpy(psl.buf + (taps - 1) * cmp, in + (in_width - taps + 1) * cmp, (taps - 1) * cmp);
|
435
|
-
rpadv = psl.buf + (2 * taps - 2 - in_width) * cmp;
|
436
|
-
}
|
437
|
-
|
438
|
-
padded_sl_extend_edges(&psl);
|
439
|
-
|
440
457
|
for (i=0; i<out_chunk; i++) {
|
441
458
|
xsmp_i = split_map(in_width, out_width, i, &tx);
|
442
459
|
calc_coeffs(coeffs, tx, taps);
|
@@ -444,21 +461,478 @@ void xscale(unsigned char *in, long in_width, unsigned char *out,
|
|
444
461
|
xsmp_i += 1 - taps / 2;
|
445
462
|
out_pos = out + i * cmp;
|
446
463
|
for (j=0; j<scale_gcd; j++) {
|
447
|
-
|
448
|
-
|
449
|
-
} else if (xsmp_i > in_width - taps) {
|
450
|
-
tmp = rpadv;
|
451
|
-
} else {
|
452
|
-
tmp = in;
|
453
|
-
}
|
454
|
-
tmp += xsmp_i * cmp;
|
455
|
-
xscale_set_sample(taps, coeffs, tmp, out_pos, cmp, opts);
|
464
|
+
tmp = in + xsmp_i * cmp;
|
465
|
+
xscale_set_sample(taps, coeffs, tmp, out_pos, cs);
|
456
466
|
out_pos += out_chunk * cmp;
|
457
|
-
|
458
467
|
xsmp_i += in_chunk;
|
459
468
|
}
|
460
469
|
}
|
461
470
|
|
462
|
-
padded_sl_free(&psl);
|
463
471
|
free(coeffs);
|
472
|
+
return 0;
|
473
|
+
}
|
474
|
+
|
475
|
+
/* scanline ring buffer */
|
476
|
+
|
477
|
+
int sl_rbuf_init(struct sl_rbuf *rb, uint32_t height, size_t sl_len)
|
478
|
+
{
|
479
|
+
rb->height = height;
|
480
|
+
rb->count = 0;
|
481
|
+
rb->length = sl_len;
|
482
|
+
rb->buf = malloc(sl_len * height * sizeof(uint16_t));
|
483
|
+
if (!rb->buf) {
|
484
|
+
return -2;
|
485
|
+
}
|
486
|
+
rb->virt = malloc(sizeof(uint8_t *) * height);
|
487
|
+
if (!rb->virt) {
|
488
|
+
free(rb->buf);
|
489
|
+
return -2;
|
490
|
+
}
|
491
|
+
return 0;
|
492
|
+
}
|
493
|
+
|
494
|
+
void sl_rbuf_free(struct sl_rbuf *rb)
|
495
|
+
{
|
496
|
+
free(rb->buf);
|
497
|
+
free(rb->virt);
|
498
|
+
}
|
499
|
+
|
500
|
+
uint16_t *sl_rbuf_next(struct sl_rbuf *rb)
|
501
|
+
{
|
502
|
+
return rb->buf + (rb->count++ % rb->height) * rb->length;
|
503
|
+
}
|
504
|
+
|
505
|
+
uint16_t **sl_rbuf_virt(struct sl_rbuf *rb, uint32_t last_target)
|
506
|
+
{
|
507
|
+
uint32_t i, safe, height, last_idx;
|
508
|
+
height = rb->height;
|
509
|
+
last_idx = rb->count - 1;
|
510
|
+
|
511
|
+
// Make sure we have the 1st scanline if extending upwards
|
512
|
+
if (last_target < last_idx && last_idx > height - 1) {
|
513
|
+
return 0;
|
514
|
+
}
|
515
|
+
|
516
|
+
for (i=0; i<height; i++) {
|
517
|
+
safe = last_target < i ? 0 : last_target - i;
|
518
|
+
safe = safe > last_idx ? last_idx : safe;
|
519
|
+
rb->virt[height - i - 1] = rb->buf + (safe % height) * rb->length;
|
520
|
+
}
|
521
|
+
return rb->virt;
|
522
|
+
}
|
523
|
+
|
524
|
+
/* xscaler */
|
525
|
+
|
526
|
+
int xscaler_init(struct xscaler *xs, uint32_t width_in, uint32_t width_out,
|
527
|
+
enum oil_colorspace cs)
|
528
|
+
{
|
529
|
+
size_t psl_len, psl_offset;
|
530
|
+
uint16_t *psl_buf;
|
531
|
+
|
532
|
+
psl_len = padded_sl_len_offset(width_in, width_out, CS_TO_CMP(cs), &psl_offset);
|
533
|
+
psl_buf = malloc(psl_len);
|
534
|
+
if (!psl_buf) {
|
535
|
+
return -2;
|
536
|
+
}
|
537
|
+
|
538
|
+
xs->psl_buf = psl_buf;
|
539
|
+
xs->psl_offset = psl_offset;
|
540
|
+
xs->psl_pos0 = psl_buf + psl_offset;
|
541
|
+
xs->width_in = width_in;
|
542
|
+
xs->width_out = width_out;
|
543
|
+
xs->cs = cs;
|
544
|
+
|
545
|
+
return 0;
|
546
|
+
}
|
547
|
+
|
548
|
+
void xscaler_free(struct xscaler *xs)
|
549
|
+
{
|
550
|
+
free(xs->psl_buf);
|
551
|
+
}
|
552
|
+
|
553
|
+
void xscaler_scale(struct xscaler *xs, uint16_t *out_buf)
|
554
|
+
{
|
555
|
+
padded_sl_extend_edges(xs->psl_buf, xs->width_in, xs->psl_offset, CS_TO_CMP(xs->cs));
|
556
|
+
xscale_padded(xs->psl_pos0, xs->width_in, out_buf, xs->width_out, xs->cs);
|
557
|
+
}
|
558
|
+
|
559
|
+
/* yscaler */
|
560
|
+
|
561
|
+
static void yscaler_map_pos(struct yscaler *ys, uint32_t pos)
|
562
|
+
{
|
563
|
+
long target;
|
564
|
+
target = split_map(ys->in_height, ys->out_height, pos, &ys->ty);
|
565
|
+
ys->target = target + ys->rb.height / 2;
|
566
|
+
}
|
567
|
+
|
568
|
+
int yscaler_init(struct yscaler *ys, uint32_t in_height, uint32_t out_height,
|
569
|
+
uint32_t width, enum oil_colorspace cs)
|
570
|
+
{
|
571
|
+
uint8_t cmp;
|
572
|
+
int ret;
|
573
|
+
uint32_t taps;
|
574
|
+
taps = calc_taps(in_height, out_height);
|
575
|
+
ys->in_height = in_height;
|
576
|
+
ys->out_height = out_height;
|
577
|
+
ys->width = width;
|
578
|
+
ys->cs = cs;
|
579
|
+
cmp = CS_TO_CMP(cs);
|
580
|
+
if (cs == OIL_CS_RGB) {
|
581
|
+
cmp = 4;
|
582
|
+
}
|
583
|
+
ret = sl_rbuf_init(&ys->rb, taps, width * cmp);
|
584
|
+
yscaler_map_pos(ys, 0);
|
585
|
+
return ret;
|
586
|
+
}
|
587
|
+
|
588
|
+
void yscaler_free(struct yscaler *ys)
|
589
|
+
{
|
590
|
+
sl_rbuf_free(&ys->rb);
|
591
|
+
}
|
592
|
+
|
593
|
+
uint16_t *yscaler_next(struct yscaler *ys)
|
594
|
+
{
|
595
|
+
if (ys->rb.count == ys->in_height || ys->rb.count > ys->target) {
|
596
|
+
return 0;
|
597
|
+
}
|
598
|
+
return sl_rbuf_next(&ys->rb);
|
599
|
+
}
|
600
|
+
|
601
|
+
int yscaler_scale(struct yscaler *ys, uint8_t *out, uint32_t pos)
|
602
|
+
{
|
603
|
+
int ret;
|
604
|
+
uint16_t **virt;
|
605
|
+
virt = sl_rbuf_virt(&ys->rb, ys->target);
|
606
|
+
ret = strip_scale(virt, ys->rb.height, ys->rb.length, out, ys->ty, ys->cs);
|
607
|
+
yscaler_map_pos(ys, pos + 1);
|
608
|
+
return ret;
|
609
|
+
}
|
610
|
+
|
611
|
+
/* Color Space Helpers */
|
612
|
+
|
613
|
+
#define EXPAND8(X) ((X<<8) + X)
|
614
|
+
|
615
|
+
static uint16_t srgb_sample_to_linear(uint8_t x)
|
616
|
+
{
|
617
|
+
static const uint16_t s2l_map[256] = {
|
618
|
+
0x0000, 0x0014, 0x0028, 0x003c, 0x0050, 0x0063, 0x0077, 0x008b,
|
619
|
+
0x009f, 0x00b3, 0x00c7, 0x00db, 0x00f1, 0x0108, 0x0120, 0x0139,
|
620
|
+
0x0154, 0x016f, 0x018c, 0x01ab, 0x01ca, 0x01eb, 0x020e, 0x0232,
|
621
|
+
0x0257, 0x027d, 0x02a5, 0x02ce, 0x02f9, 0x0325, 0x0353, 0x0382,
|
622
|
+
0x03b3, 0x03e5, 0x0418, 0x044d, 0x0484, 0x04bc, 0x04f6, 0x0532,
|
623
|
+
0x056f, 0x05ad, 0x05ed, 0x062f, 0x0673, 0x06b8, 0x06fe, 0x0747,
|
624
|
+
0x0791, 0x07dd, 0x082a, 0x087a, 0x08ca, 0x091d, 0x0972, 0x09c8,
|
625
|
+
0x0a20, 0x0a79, 0x0ad5, 0x0b32, 0x0b91, 0x0bf2, 0x0c55, 0x0cba,
|
626
|
+
0x0d20, 0x0d88, 0x0df2, 0x0e5e, 0x0ecc, 0x0f3c, 0x0fae, 0x1021,
|
627
|
+
0x1097, 0x110e, 0x1188, 0x1203, 0x1280, 0x1300, 0x1381, 0x1404,
|
628
|
+
0x1489, 0x1510, 0x159a, 0x1625, 0x16b2, 0x1741, 0x17d3, 0x1866,
|
629
|
+
0x18fb, 0x1993, 0x1a2c, 0x1ac8, 0x1b66, 0x1c06, 0x1ca7, 0x1d4c,
|
630
|
+
0x1df2, 0x1e9a, 0x1f44, 0x1ff1, 0x20a0, 0x2150, 0x2204, 0x22b9,
|
631
|
+
0x2370, 0x242a, 0x24e5, 0x25a3, 0x2664, 0x2726, 0x27eb, 0x28b1,
|
632
|
+
0x297b, 0x2a46, 0x2b14, 0x2be3, 0x2cb6, 0x2d8a, 0x2e61, 0x2f3a,
|
633
|
+
0x3015, 0x30f2, 0x31d2, 0x32b4, 0x3399, 0x3480, 0x3569, 0x3655,
|
634
|
+
0x3742, 0x3833, 0x3925, 0x3a1a, 0x3b12, 0x3c0b, 0x3d07, 0x3e06,
|
635
|
+
0x3f07, 0x400a, 0x4110, 0x4218, 0x4323, 0x4430, 0x453f, 0x4651,
|
636
|
+
0x4765, 0x487c, 0x4995, 0x4ab1, 0x4bcf, 0x4cf0, 0x4e13, 0x4f39,
|
637
|
+
0x5061, 0x518c, 0x52b9, 0x53e9, 0x551b, 0x5650, 0x5787, 0x58c1,
|
638
|
+
0x59fe, 0x5b3d, 0x5c7e, 0x5dc2, 0x5f09, 0x6052, 0x619e, 0x62ed,
|
639
|
+
0x643e, 0x6591, 0x66e8, 0x6840, 0x699c, 0x6afa, 0x6c5b, 0x6dbe,
|
640
|
+
0x6f24, 0x708d, 0x71f8, 0x7366, 0x74d7, 0x764a, 0x77c0, 0x7939,
|
641
|
+
0x7ab4, 0x7c32, 0x7db3, 0x7f37, 0x80bd, 0x8246, 0x83d1, 0x855f,
|
642
|
+
0x86f0, 0x8884, 0x8a1b, 0x8bb4, 0x8d50, 0x8eef, 0x9090, 0x9235,
|
643
|
+
0x93dc, 0x9586, 0x9732, 0x98e2, 0x9a94, 0x9c49, 0x9e01, 0x9fbb,
|
644
|
+
0xa179, 0xa339, 0xa4fc, 0xa6c2, 0xa88b, 0xaa56, 0xac25, 0xadf6,
|
645
|
+
0xafca, 0xb1a1, 0xb37b, 0xb557, 0xb737, 0xb919, 0xbaff, 0xbce7,
|
646
|
+
0xbed2, 0xc0c0, 0xc2b1, 0xc4a5, 0xc69c, 0xc895, 0xca92, 0xcc91,
|
647
|
+
0xce94, 0xd099, 0xd2a1, 0xd4ad, 0xd6bb, 0xd8cc, 0xdae0, 0xdcf7,
|
648
|
+
0xdf11, 0xe12e, 0xe34e, 0xe571, 0xe797, 0xe9c0, 0xebec, 0xee1b,
|
649
|
+
0xf04d, 0xf282, 0xf4ba, 0xf6f5, 0xf933, 0xfb74, 0xfdb8, 0xffff,
|
650
|
+
};
|
651
|
+
return s2l_map[x];
|
652
|
+
}
|
653
|
+
|
654
|
+
static void srgbx_preprocess_nx(uint8_t *in, uint16_t *out, uint32_t in_width, uint32_t n)
|
655
|
+
{
|
656
|
+
uint32_t i, j;
|
657
|
+
uint32_t sums[3];
|
658
|
+
for (i=0; i<in_width/n; i++) {
|
659
|
+
sums[0] = sums[1] = sums[2] = 0;
|
660
|
+
for (j=0; j<n; j++) {
|
661
|
+
sums[0] += srgb_sample_to_linear(in[0]);
|
662
|
+
sums[1] += srgb_sample_to_linear(in[1]);
|
663
|
+
sums[2] += srgb_sample_to_linear(in[2]);
|
664
|
+
in += 4;
|
665
|
+
}
|
666
|
+
out[0] = sums[0] / n;
|
667
|
+
out[1] = sums[1] / n;
|
668
|
+
out[2] = sums[2] / n;
|
669
|
+
out[3] = 0;
|
670
|
+
out += 4;
|
671
|
+
}
|
672
|
+
}
|
673
|
+
|
674
|
+
static void srgba_preprocess_nx(uint8_t *in, uint16_t *out, uint32_t in_width, uint32_t n)
|
675
|
+
{
|
676
|
+
uint32_t i, j;
|
677
|
+
uint32_t sums[4];
|
678
|
+
for (i=0; i<in_width/n; i++) {
|
679
|
+
sums[0] = sums[1] = sums[2] = sums[3] = 0;
|
680
|
+
for (j=0; j<n; j++) {
|
681
|
+
sums[0] += srgb_sample_to_linear(in[0]);
|
682
|
+
sums[1] += srgb_sample_to_linear(in[1]);
|
683
|
+
sums[2] += srgb_sample_to_linear(in[2]);
|
684
|
+
sums[3] += EXPAND8(in[3]);
|
685
|
+
in += 4;
|
686
|
+
}
|
687
|
+
out[0] = sums[0] / n;
|
688
|
+
out[1] = sums[1] / n;
|
689
|
+
out[2] = sums[2] / n;
|
690
|
+
out[3] = sums[3] / n;
|
691
|
+
out += 4;
|
692
|
+
}
|
693
|
+
}
|
694
|
+
|
695
|
+
static void srgb_preprocess_nx(uint8_t *in, uint16_t *out, uint32_t in_width, uint32_t n)
|
696
|
+
{
|
697
|
+
uint32_t i, j;
|
698
|
+
uint32_t sums[3];
|
699
|
+
for (i=0; i<in_width/n; i++) {
|
700
|
+
sums[0] = sums[1] = sums[2] = 0;
|
701
|
+
for (j=0; j<n; j++) {
|
702
|
+
sums[0] += srgb_sample_to_linear(in[0]);
|
703
|
+
sums[1] += srgb_sample_to_linear(in[1]);
|
704
|
+
sums[2] += srgb_sample_to_linear(in[2]);
|
705
|
+
in += 3;
|
706
|
+
}
|
707
|
+
out[0] = sums[0] / n;
|
708
|
+
out[1] = sums[1] / n;
|
709
|
+
out[2] = sums[2] / n;
|
710
|
+
out[3] = 0;
|
711
|
+
out += 4;
|
712
|
+
}
|
713
|
+
}
|
714
|
+
|
715
|
+
static void g_preprocess_nx(uint8_t *in, uint16_t *out, uint32_t in_width, uint32_t n)
|
716
|
+
{
|
717
|
+
uint32_t i, j;
|
718
|
+
uint32_t sum;
|
719
|
+
for (i=0; i<in_width/n; i++) {
|
720
|
+
sum = 0;
|
721
|
+
for (j=0; j<n; j++) {
|
722
|
+
sum += EXPAND8(in[0]);
|
723
|
+
in++;
|
724
|
+
}
|
725
|
+
out[0] = sum / n;
|
726
|
+
out++;
|
727
|
+
}
|
728
|
+
}
|
729
|
+
|
730
|
+
static void ga_preprocess_nx(uint8_t *in, uint16_t *out, uint32_t in_width, uint32_t n)
|
731
|
+
{
|
732
|
+
uint32_t i, j;
|
733
|
+
uint32_t sums[2];
|
734
|
+
for (i=0; i<in_width/n; i++) {
|
735
|
+
sums[0] = sums[1] = 0;
|
736
|
+
for (j=0; j<n; j++) {
|
737
|
+
sums[0] += EXPAND8(in[0]);
|
738
|
+
sums[1] += EXPAND8(in[1]);
|
739
|
+
in += 2;
|
740
|
+
}
|
741
|
+
out[0] = sums[0] / n;
|
742
|
+
out[1] = sums[1] / n;
|
743
|
+
out += 2;
|
744
|
+
}
|
745
|
+
}
|
746
|
+
|
747
|
+
static void cmyk_preprocess_nx(uint8_t *in, uint16_t *out, uint32_t in_width, uint32_t n)
|
748
|
+
{
|
749
|
+
uint32_t i, j;
|
750
|
+
uint32_t sums[4];
|
751
|
+
for (i=0; i<in_width/n; i++) {
|
752
|
+
sums[0] = sums[1] = sums[2] = sums[3] = 0;
|
753
|
+
for (j=0; j<n; j++) {
|
754
|
+
sums[0] += EXPAND8(in[0]);
|
755
|
+
sums[1] += EXPAND8(in[1]);
|
756
|
+
sums[2] += EXPAND8(in[2]);
|
757
|
+
sums[3] += EXPAND8(in[3]);
|
758
|
+
in += 4;
|
759
|
+
}
|
760
|
+
out[0] = sums[0] / n;
|
761
|
+
out[1] = sums[1] / n;
|
762
|
+
out[2] = sums[2] / n;
|
763
|
+
out[3] = sums[3] / n;
|
764
|
+
out += 4;
|
765
|
+
}
|
766
|
+
}
|
767
|
+
|
768
|
+
static uint32_t calc_pre_shrink(uint32_t dim_in, uint32_t dim_out)
|
769
|
+
{
|
770
|
+
uint32_t max;
|
771
|
+
max = (2 * dim_in) / dim_out / 3;
|
772
|
+
if (max >= 4 && (dim_in % 4) == 0) {
|
773
|
+
return 4;
|
774
|
+
}
|
775
|
+
if (max >= 2 && (dim_in % 2) == 0) {
|
776
|
+
return 2;
|
777
|
+
}
|
778
|
+
return 1;
|
779
|
+
}
|
780
|
+
|
781
|
+
int preprocess_xscaler_init(struct preprocess_xscaler *pxs, uint32_t width_in,
|
782
|
+
uint32_t width_out, enum oil_colorspace cs_in)
|
783
|
+
{
|
784
|
+
enum oil_colorspace cs_out;
|
785
|
+
|
786
|
+
pxs->width_in = width_in;
|
787
|
+
pxs->cs_in = cs_in;
|
788
|
+
pxs->scale_factor = calc_pre_shrink(width_in, width_out);
|
789
|
+
|
790
|
+
/* Auto promote rgb components to rgbx for performance */
|
791
|
+
cs_out = cs_in == OIL_CS_RGB ? OIL_CS_RGBX : cs_in;
|
792
|
+
return xscaler_init(&pxs->xs, width_in / pxs->scale_factor, width_out, cs_out);
|
793
|
+
}
|
794
|
+
|
795
|
+
void preprocess_xscaler_free(struct preprocess_xscaler *pxs)
|
796
|
+
{
|
797
|
+
xscaler_free(&pxs->xs);
|
798
|
+
}
|
799
|
+
|
800
|
+
static void pre_convert_g(uint8_t *in, uint16_t *out,
|
801
|
+
uint32_t width_in, uint32_t scale_factor)
|
802
|
+
{
|
803
|
+
switch(scale_factor) {
|
804
|
+
case 1:
|
805
|
+
g_preprocess_nx(in, out, width_in, 1);
|
806
|
+
break;
|
807
|
+
case 2:
|
808
|
+
g_preprocess_nx(in, out, width_in, 2);
|
809
|
+
break;
|
810
|
+
case 4:
|
811
|
+
g_preprocess_nx(in, out, width_in, 4);
|
812
|
+
break;
|
813
|
+
}
|
814
|
+
}
|
815
|
+
|
816
|
+
static void pre_convert_ga(uint8_t *in, uint16_t *out,
|
817
|
+
uint32_t width_in, uint32_t scale_factor)
|
818
|
+
{
|
819
|
+
switch(scale_factor) {
|
820
|
+
case 1:
|
821
|
+
ga_preprocess_nx(in, out, width_in, 1);
|
822
|
+
break;
|
823
|
+
case 2:
|
824
|
+
ga_preprocess_nx(in, out, width_in, 2);
|
825
|
+
break;
|
826
|
+
case 4:
|
827
|
+
ga_preprocess_nx(in, out, width_in, 4);
|
828
|
+
break;
|
829
|
+
}
|
830
|
+
}
|
831
|
+
|
832
|
+
static void pre_convert_cmyk(uint8_t *in, uint16_t *out,
|
833
|
+
uint32_t width_in, uint32_t scale_factor)
|
834
|
+
{
|
835
|
+
switch(scale_factor) {
|
836
|
+
case 1:
|
837
|
+
cmyk_preprocess_nx(in, out, width_in, 1);
|
838
|
+
break;
|
839
|
+
case 2:
|
840
|
+
cmyk_preprocess_nx(in, out, width_in, 2);
|
841
|
+
break;
|
842
|
+
case 4:
|
843
|
+
cmyk_preprocess_nx(in, out, width_in, 4);
|
844
|
+
break;
|
845
|
+
}
|
846
|
+
}
|
847
|
+
|
848
|
+
static void pre_convert_rgbx(uint8_t *in, uint16_t *out,
|
849
|
+
uint32_t width_in, uint32_t scale_factor)
|
850
|
+
{
|
851
|
+
switch(scale_factor) {
|
852
|
+
case 1:
|
853
|
+
srgbx_preprocess_nx(in, out, width_in, 1);
|
854
|
+
break;
|
855
|
+
case 2:
|
856
|
+
srgbx_preprocess_nx(in, out, width_in, 2);
|
857
|
+
break;
|
858
|
+
case 4:
|
859
|
+
srgbx_preprocess_nx(in, out, width_in, 4);
|
860
|
+
break;
|
861
|
+
}
|
862
|
+
}
|
863
|
+
|
864
|
+
static void pre_convert_rgba(uint8_t *in, uint16_t *out,
|
865
|
+
uint32_t width_in, uint32_t scale_factor)
|
866
|
+
{
|
867
|
+
switch(scale_factor) {
|
868
|
+
case 1:
|
869
|
+
srgba_preprocess_nx(in, out, width_in, 1);
|
870
|
+
break;
|
871
|
+
case 2:
|
872
|
+
srgba_preprocess_nx(in, out, width_in, 2);
|
873
|
+
break;
|
874
|
+
case 4:
|
875
|
+
srgba_preprocess_nx(in, out, width_in, 4);
|
876
|
+
break;
|
877
|
+
}
|
878
|
+
}
|
879
|
+
|
880
|
+
static void pre_convert_rgb(uint8_t *in, uint16_t *out,
|
881
|
+
uint32_t width_in, uint32_t scale_factor)
|
882
|
+
{
|
883
|
+
switch(scale_factor) {
|
884
|
+
case 1:
|
885
|
+
srgb_preprocess_nx(in, out, width_in, 1);
|
886
|
+
break;
|
887
|
+
case 2:
|
888
|
+
srgb_preprocess_nx(in, out, width_in, 2);
|
889
|
+
break;
|
890
|
+
case 4:
|
891
|
+
srgb_preprocess_nx(in, out, width_in, 4);
|
892
|
+
break;
|
893
|
+
}
|
894
|
+
}
|
895
|
+
|
896
|
+
void preprocess_xscaler_scale(struct preprocess_xscaler *pxs, uint8_t *in,
|
897
|
+
uint16_t *out)
|
898
|
+
{
|
899
|
+
switch(pxs->cs_in) {
|
900
|
+
case OIL_CS_G:
|
901
|
+
pre_convert_g(in, pxs->xs.psl_pos0, pxs->width_in, pxs->scale_factor);
|
902
|
+
break;
|
903
|
+
case OIL_CS_GA:
|
904
|
+
pre_convert_ga(in, pxs->xs.psl_pos0, pxs->width_in, pxs->scale_factor);
|
905
|
+
break;
|
906
|
+
case OIL_CS_RGB:
|
907
|
+
pre_convert_rgb(in, pxs->xs.psl_pos0, pxs->width_in, pxs->scale_factor);
|
908
|
+
break;
|
909
|
+
case OIL_CS_RGBX:
|
910
|
+
pre_convert_rgbx(in, pxs->xs.psl_pos0, pxs->width_in, pxs->scale_factor);
|
911
|
+
break;
|
912
|
+
case OIL_CS_RGBA:
|
913
|
+
pre_convert_rgba(in, pxs->xs.psl_pos0, pxs->width_in, pxs->scale_factor);
|
914
|
+
break;
|
915
|
+
case OIL_CS_CMYK:
|
916
|
+
pre_convert_cmyk(in, pxs->xs.psl_pos0, pxs->width_in, pxs->scale_factor);
|
917
|
+
break;
|
918
|
+
}
|
919
|
+
xscaler_scale(&pxs->xs, out);
|
920
|
+
}
|
921
|
+
|
922
|
+
|
923
|
+
/* Utility helpers */
|
924
|
+
void fix_ratio(uint32_t src_width, uint32_t src_height, uint32_t *out_width,
|
925
|
+
uint32_t *out_height)
|
926
|
+
{
|
927
|
+
double width_ratio, height_ratio;
|
928
|
+
|
929
|
+
width_ratio = *out_width / (double)src_width;
|
930
|
+
height_ratio = *out_height / (double)src_height;
|
931
|
+
if (width_ratio < height_ratio) {
|
932
|
+
*out_height = round(width_ratio * src_height);
|
933
|
+
*out_height = *out_height ? *out_height : 1;
|
934
|
+
} else {
|
935
|
+
*out_width = round(height_ratio * src_width);
|
936
|
+
*out_width = *out_width ? *out_width : 1;
|
937
|
+
}
|
464
938
|
}
|