oil 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Copyright (c) 2014-2019 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
+
22
+ #ifndef OIL_RESAMPLE_H
23
+ #define OIL_RESAMPLE_H
24
+
25
+ /**
26
+ * Color spaces currently supported by oil.
27
+ */
28
+ enum oil_colorspace {
29
+ // error
30
+ OIL_CS_UNKNOWN = 0,
31
+
32
+ // greyscale - no color space conversions
33
+ OIL_CS_G = 0x0001,
34
+
35
+ // greyscale w/ alpha - uses premultiplied alpha
36
+ OIL_CS_GA = 0x0002,
37
+
38
+ // sRGB - input will be converted to linear RGB during processing
39
+ OIL_CS_RGB = 0x0003,
40
+
41
+ // sRGB w/ padding - same as OIL_CS_RGB, but padded with an extra byte
42
+ OIL_CS_RGBX = 0x0004, // sRGB w/ padding
43
+
44
+ // sRGB w/ alpha - sRGB to linear conversion and premultiplied alpha
45
+ OIL_CS_RGBA = 0x0104, // sRGB w/ alpha
46
+
47
+ // CMYK - no color space conversions
48
+ OIL_CS_CMYK = 0x0204, // four color CMYK
49
+ };
50
+
51
+ /**
52
+ * Macro to get the number of components from an oil color space.
53
+ */
54
+ #define OIL_CMP(x) ((x)&0xFF)
55
+
56
+ /**
57
+ * Struct to hold state for scaling.
58
+ */
59
+ struct oil_scale {
60
+ int in_height; // input image height.
61
+ int out_height; // output image height.
62
+ int in_width; // input image width.
63
+ int out_width; // output image height.
64
+ enum oil_colorspace cs; // color space of input & output.
65
+ int in_pos; // current row of input image.
66
+ int out_pos; // current row of output image.
67
+ int taps; // number of taps required to perform scaling.
68
+ int target; // where the ring buffer should be on next scaling.
69
+ int sl_len; // length in bytes of a row.
70
+ float ty; // sub-pixel offset for next scaling.
71
+ float *coeffs_y; // buffer for holding temporary y-coefficients.
72
+ float *coeffs_x; // buffer for holding precalculated coefficients.
73
+ int *borders; // holds precalculated coefficient rotation points.
74
+ float *rb; // ring buffer holding scanlines.
75
+ float **virt; // space to provide scanline pointers for scaling.
76
+ };
77
+
78
+ /**
79
+ * Initialize static, pre-calculated tables. This only needs to be called once.
80
+ * A call to oil_scale_init() will initialize these tables if not already done,
81
+ * so explicityly calling oil_global_init() is only needed if there are
82
+ * concurrency concerns.
83
+ */
84
+ void oil_global_init();
85
+
86
+ /**
87
+ * Initialize an oil scaler struct.
88
+ * @os: Pointer to the scaler struct to be initialized.
89
+ * @in_height: Height, in pixels, of the input image.
90
+ * @out_height: Height, in pixels, of the output image.
91
+ * @in_width: Width, in pixels, of the input image.
92
+ * @out_width: Width, in pixels, of the output image.
93
+ * @cs: Color space of the input/output images.
94
+ *
95
+ * Returns 0 on success.
96
+ * Returns -1 if an argument is bad.
97
+ * Returns -2 if unable to allocate memory.
98
+ */
99
+ int oil_scale_init(struct oil_scale *os, int in_height, int out_height,
100
+ int in_width, int out_width, enum oil_colorspace cs);
101
+
102
+ /**
103
+ * Free heap allocations associated with a yscaler struct.
104
+ * @ys: Pointer to the yscaler struct to be freed.
105
+ */
106
+ void oil_scale_free(struct oil_scale *os);
107
+
108
+ /**
109
+ * Get a pointer to the next scanline to be filled in the ring buffer.
110
+ * @ys: Pointer to the yscaler struct to advance.
111
+ *
112
+ * Returns 0 if no more input lines are needed to produce the next output line.
113
+ * Otherwise, returns the number of input lines that are needed.
114
+ */
115
+ int oil_scale_slots(struct oil_scale *ys);
116
+
117
+ /**
118
+ * Ingest & buffer an input scanline. Input is unsigned chars.
119
+ * @os: Pointer to the scaler struct.
120
+ * @in: Pointer to the input buffer containing a scanline.
121
+ */
122
+ void oil_scale_in(struct oil_scale *os, unsigned char *in);
123
+
124
+ /**
125
+ * Scale previously ingested & buffered contents to produce the next scaled output
126
+ * scanline.
127
+ * @ys: Pointer to the scaler struct.
128
+ * @out: Pointer to the buffer where the output scanline will be written.
129
+ */
130
+ void oil_scale_out(struct oil_scale *ys, unsigned char *out);
131
+
132
+ /**
133
+ * Calculate an output ratio that preserves the input aspect ratio.
134
+ * @src_width: Width, in pixels, of the input image.
135
+ * @src_height: Height, in pixels, of the input image.
136
+ * @out_width: Width, in pixels, of the output bounding box.
137
+ * @out_height: Height, in pixels, of the output bounding box.
138
+ *
139
+ * The out_width and out_height parameters will be modified, if necessary, to
140
+ * maintain the input aspect ratio while staying within the given bounding box.
141
+ *
142
+ * Returns 0 on success.
143
+ * Returns -1 if an argument is bad.
144
+ * Returns -3 if an adjusted dimension would be out of range.
145
+ */
146
+ int oil_fix_ratio(int src_width, int src_height, int *out_width,
147
+ int *out_height);
148
+
149
+ #endif
@@ -1,6 +1,6 @@
1
1
  #include <ruby.h>
2
2
  #include <png.h>
3
- #include "resample.h"
3
+ #include "oil_libpng.h"
4
4
 
5
5
  static ID id_read;
6
6
 
@@ -8,8 +8,8 @@ struct readerdata {
8
8
  png_structp png;
9
9
  png_infop info;
10
10
  VALUE source_io;
11
- uint32_t scale_width;
12
- uint32_t scale_height;
11
+ int scale_width;
12
+ int scale_height;
13
13
  int locked;
14
14
  };
15
15
 
@@ -210,69 +210,26 @@ struct each_args {
210
210
  struct readerdata *reader;
211
211
  png_structp wpng;
212
212
  png_infop winfo;
213
- unsigned char *inwidthbuf;
214
213
  unsigned char *outwidthbuf;
215
- unsigned char **scanlines;
216
- struct yscaler ys;
217
- struct preprocess_xscaler xs;
214
+ struct oil_libpng ol;
218
215
  };
219
216
 
220
- static VALUE each_interlace(struct each_args *args)
217
+ static VALUE each2(struct each_args *args)
221
218
  {
222
219
  struct readerdata *reader;
223
- unsigned char **scanlines, *outwidthbuf;
224
- uint32_t i, n, scaley;
225
- uint16_t *yinbuf;
226
- struct yscaler *ys;
227
- struct preprocess_xscaler *xs;
228
-
229
- reader = args->reader;
230
- xs = &args->xs;
231
- ys = &args->ys;
232
- scanlines = args->scanlines;
233
- outwidthbuf = args->outwidthbuf;
234
- scaley = reader->scale_height;
235
-
236
- png_write_info(args->wpng, args->winfo);
237
- png_read_image(args->reader->png, (png_bytepp)args->scanlines);
238
-
239
- n = 0;
240
- for(i=0; i<scaley; i++) {
241
- while ((yinbuf = yscaler_next(ys))) {
242
- preprocess_xscaler_scale(xs, scanlines[n++], yinbuf);
243
- }
244
- yscaler_scale(ys, outwidthbuf, i);
245
- png_write_row(args->wpng, outwidthbuf);
246
- }
247
-
248
- png_write_end(args->wpng, args->winfo);
249
- return Qnil;
250
- }
251
-
252
- static VALUE each_interlace_none(struct each_args *args)
253
- {
254
- struct readerdata *reader;
255
- unsigned char *inwidthbuf, *outwidthbuf;
256
- uint16_t *yinbuf;
257
- struct preprocess_xscaler *xs;
258
- struct yscaler *ys;
259
- uint32_t i, scaley;
220
+ unsigned char *outwidthbuf;
221
+ struct oil_libpng *ol;
222
+ int i, scaley;
260
223
 
261
224
  reader = args->reader;
262
- xs = &args->xs;
263
- inwidthbuf = args->inwidthbuf;
264
225
  outwidthbuf = args->outwidthbuf;
265
- ys = &args->ys;
226
+ ol = &args->ol;
266
227
  scaley = reader->scale_height;
267
228
 
268
229
  png_write_info(args->wpng, args->winfo);
269
230
 
270
231
  for(i=0; i<scaley; i++) {
271
- while ((yinbuf = yscaler_next(ys))) {
272
- png_read_row(reader->png, inwidthbuf, NULL);
273
- preprocess_xscaler_scale(xs, inwidthbuf, yinbuf);
274
- }
275
- yscaler_scale(ys, outwidthbuf, i);
232
+ oil_libpng_read_scanline(ol, outwidthbuf);
276
233
  png_write_row(args->wpng, outwidthbuf);
277
234
  }
278
235
 
@@ -280,21 +237,6 @@ static VALUE each_interlace_none(struct each_args *args)
280
237
  return Qnil;
281
238
  }
282
239
 
283
- static enum oil_colorspace png_cs_to_oil(png_byte cs)
284
- {
285
- switch(cs) {
286
- case PNG_COLOR_TYPE_GRAY:
287
- return OIL_CS_G;
288
- case PNG_COLOR_TYPE_GA:
289
- return OIL_CS_GA;
290
- case PNG_COLOR_TYPE_RGB:
291
- return OIL_CS_RGB;
292
- case PNG_COLOR_TYPE_RGBA:
293
- return OIL_CS_RGBA;
294
- }
295
- rb_raise(rb_eRuntimeError, "Color space not recognized.");
296
- }
297
-
298
240
  /*
299
241
  * call-seq:
300
242
  * reader.each(opts, &block) -> self
@@ -315,13 +257,9 @@ static VALUE each(int argc, VALUE *argv, VALUE self)
315
257
  png_infop winfo;
316
258
  png_structp wpng;
317
259
  VALUE opts;
318
- int cmp, state;
260
+ int cmp, state, ret;
319
261
  struct each_args args;
320
- uint32_t i, height, width;
321
262
  png_byte ctype;
322
- unsigned char **scanlines;
323
- size_t row_bytes;
324
- enum oil_colorspace cs;
325
263
 
326
264
  rb_scan_args(argc, argv, "01", &opts);
327
265
 
@@ -332,7 +270,6 @@ static VALUE each(int argc, VALUE *argv, VALUE self)
332
270
 
333
271
  cmp = png_get_channels(reader->png, reader->info);
334
272
  ctype = png_get_color_type(reader->png, reader->info);
335
- cs = png_cs_to_oil(ctype);
336
273
 
337
274
  wpng = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
338
275
  (png_error_ptr)error, (png_error_ptr)warning);
@@ -343,39 +280,24 @@ static VALUE each(int argc, VALUE *argv, VALUE self)
343
280
  ctype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
344
281
  PNG_FILTER_TYPE_DEFAULT);
345
282
 
346
- width = png_get_image_width(reader->png, reader->info);
347
- height = png_get_image_height(reader->png, reader->info);
348
- row_bytes = png_get_rowbytes(reader->png, reader->info);
349
-
350
283
  args.reader = reader;
351
284
  args.wpng = wpng;
352
285
  args.winfo = winfo;
353
286
  args.outwidthbuf = malloc(reader->scale_width * cmp);
287
+ if (!args.outwidthbuf) {
288
+ rb_raise(rb_eRuntimeError, "Unable to allocate memory.");
289
+ }
354
290
 
355
- preprocess_xscaler_init(&args.xs, width, reader->scale_width, cs);
356
- yscaler_init(&args.ys, height, reader->scale_height, reader->scale_width, cs);
357
-
358
- if (png_get_interlace_type(reader->png, reader->info) == PNG_INTERLACE_NONE) {
359
- args.inwidthbuf = malloc(width * cmp);
360
- rb_protect((VALUE(*)(VALUE))each_interlace_none, (VALUE)&args, &state);
361
- free(args.inwidthbuf);
362
- } else {
363
- scanlines = malloc(height * sizeof(unsigned char *));
364
- for (i=0; i<height; i++) {
365
- scanlines[i] = malloc(row_bytes);
366
- }
367
-
368
- args.scanlines = scanlines;
369
- rb_protect((VALUE(*)(VALUE))each_interlace, (VALUE)&args, &state);
370
-
371
- for (i=0; i<height; i++) {
372
- free(scanlines[i]);
373
- }
374
- free(scanlines);
291
+ ret = oil_libpng_init(&args.ol, reader->png, reader->info,
292
+ reader->scale_width, reader->scale_height);
293
+ if (ret!=0) {
294
+ free(args.outwidthbuf);
295
+ rb_raise(rb_eRuntimeError, "Unable to allocate memory.");
375
296
  }
376
297
 
377
- yscaler_free(&args.ys);
378
- preprocess_xscaler_free(&args.xs);
298
+ rb_protect((VALUE(*)(VALUE))each2, (VALUE)&args, &state);
299
+
300
+ oil_libpng_free(&args.ol);
379
301
  free(args.outwidthbuf);
380
302
  png_destroy_write_struct(&wpng, &winfo);
381
303
 
data/lib/oil.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Oil
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
 
4
4
  def self.sniff_signature(io)
5
5
  a = io.getc
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oil
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Timothy Elliott
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-11 00:00:00.000000000 Z
11
+ date: 2019-02-23 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Resize JPEG and PNG images, aiming for fast performance and low memory
14
14
  use.
@@ -25,9 +25,13 @@ files:
25
25
  - ext/oil/extconf.rb
26
26
  - ext/oil/jpeg.c
27
27
  - ext/oil/oil.c
28
+ - ext/oil/oil_libjpeg.c
29
+ - ext/oil/oil_libjpeg.h
30
+ - ext/oil/oil_libpng.c
31
+ - ext/oil/oil_libpng.h
32
+ - ext/oil/oil_resample.c
33
+ - ext/oil/oil_resample.h
28
34
  - ext/oil/png.c
29
- - ext/oil/resample.c
30
- - ext/oil/resample.h
31
35
  - lib/oil.rb
32
36
  - test/helper.rb
33
37
  - test/test_jpeg.rb
@@ -51,8 +55,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
51
55
  - !ruby/object:Gem::Version
52
56
  version: '0'
53
57
  requirements: []
54
- rubyforge_project:
55
- rubygems_version: 2.7.6
58
+ rubygems_version: 3.0.2
56
59
  signing_key:
57
60
  specification_version: 4
58
61
  summary: Resize JPEG and PNG images.
@@ -1,938 +0,0 @@
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
-
22
- #include "resample.h"
23
- #include <stdint.h>
24
- #include <math.h>
25
- #include <stdlib.h>
26
- #include <string.h>
27
- #include <stdio.h>
28
-
29
- /**
30
- * Bicubic interpolation. 2 base taps on either side.
31
- */
32
- #define TAPS 4
33
-
34
- /**
35
- * 64-bit type that uses 1 bit for signedness, 33 bits for the integer, and 30
36
- * bits for the fraction.
37
- *
38
- * 0-29: fraction, 30-62: integer, 63: sign.
39
- *
40
- * Useful for storing the product of a fix1_30 type and an unsigned char.
41
- */
42
- typedef int64_t fix33_30;
43
-
44
- /**
45
- * We add this to a fix33_30 value in order to bump up rounding errors.
46
- *
47
- * The best possible value was determined by comparing to a reference
48
- * implementation and comparing values for the minimal number of errors.
49
- */
50
- #define TOPOFF 8192
51
-
52
- /**
53
- * Signed type that uses 1 bit for signedness, 1 bit for the integer, and 30
54
- * bits for the fraction.
55
- *
56
- * 0-29: fraction, 30: integer, 31: sign.
57
- *
58
- * Useful for storing coefficients.
59
- */
60
- typedef int32_t fix1_30;
61
- #define ONE_FIX1_30 (1<<30)
62
-
63
- /**
64
- * Calculate the greatest common denominator between a and b.
65
- */
66
- static uint32_t gcd(uint32_t a, uint32_t b)
67
- {
68
- uint32_t c;
69
- while (a != 0) {
70
- c = a;
71
- a = b%a;
72
- b = c;
73
- }
74
- return b;
75
- }
76
-
77
- /**
78
- * Round and clamp a fix33_30 value between 0 and 255. Returns an unsigned char.
79
- */
80
- static uint16_t clamp(fix33_30 x)
81
- {
82
- x += 1 << 29;
83
- x = x < 0 ? 0 : (x > (65535L << 30) ? (65535L << 30) : x);
84
- return x >> 30;
85
- }
86
-
87
- static uint8_t clamp8(fix33_30 x)
88
- {
89
- return (clamp(x) + (1 << 7)) / 257;
90
- }
91
-
92
- /**
93
- * Given input and output dimensions and an output position, return the
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.
99
- */
100
- int32_t split_map(uint32_t dim_in, uint32_t dim_out, uint32_t pos, float *rest)
101
- {
102
- double smp;
103
- int32_t smp_i;
104
-
105
- smp = (pos + 0.5) * ((double)dim_in / dim_out) - 0.5;
106
- smp_i = smp < 0 ? -1 : smp;
107
- *rest = smp - smp_i;
108
- return smp_i;
109
- }
110
-
111
- /**
112
- * Given input and output dimension, calculate the total number of taps that
113
- * will be needed to calculate an output sample.
114
- *
115
- * When we reduce an image by a factor of two, we need to scale our resampling
116
- * function by two as well in order to avoid aliasing.
117
- */
118
- uint64_t calc_taps(uint32_t dim_in, uint32_t dim_out)
119
- {
120
- uint64_t tmp;
121
- if (dim_out > dim_in) {
122
- return TAPS;
123
- }
124
- tmp = (uint64_t)TAPS * dim_in / dim_out;
125
- return tmp - (tmp & 1);
126
- }
127
-
128
- /**
129
- * Catmull-Rom interpolator.
130
- */
131
- static float catrom(float x)
132
- {
133
- if (x<1) {
134
- return ((3*x - 5)*x*x + 2) / 2;
135
- }
136
- return (((5 - x)*x - 8)*x + 4) / 2;
137
- }
138
-
139
- /**
140
- * Convert a single-precision float to a fix1_30 fixed point int. x must be
141
- * between 0 and 1.
142
- */
143
- static fix1_30 f_to_fix1_30(float x)
144
- {
145
- return x * ONE_FIX1_30;
146
- }
147
-
148
- /**
149
- * Given an offset tx, calculate TAPS * tap_mult coefficients.
150
- *
151
- * The coefficients are stored as fix1_30 fixed point ints in coeffs.
152
- */
153
- static void calc_coeffs(fix1_30 *coeffs, float tx, uint32_t taps)
154
- {
155
- uint32_t i;
156
- float tmp, tap_mult, fudge;
157
- fix1_30 tmp_fixed;
158
-
159
- tap_mult = (float)taps / TAPS;
160
- tx = 1 - tx - taps / 2;
161
- fudge = 1.0;
162
-
163
- for (i=0; i<taps; i++) {
164
- tmp = catrom(fabsf(tx) / tap_mult) / tap_mult;
165
- fudge -= tmp;
166
- tmp_fixed = f_to_fix1_30(tmp);
167
- coeffs[i] = tmp_fixed;
168
- tx += 1;
169
- }
170
- coeffs[taps / 2] += f_to_fix1_30(fudge);
171
- }
172
-
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;
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;
186
- }
187
-
188
- static void strip_scale_rgbx(uint16_t **in, uint32_t strip_height, size_t len,
189
- uint8_t *out, fix1_30 *coeffs)
190
- {
191
- size_t i;
192
- uint32_t j;
193
- fix33_30 coeff, sum[3];
194
-
195
- for (i=0; i<len; i+=4) {
196
- sum[0] = sum[1] = sum[2] = 0;
197
- for (j=0; j<strip_height; j++) {
198
- coeff = coeffs[j];
199
- sum[0] += coeff * in[j][i];
200
- sum[1] += coeff * in[j][i + 1];
201
- sum[2] += coeff * in[j][i + 2];
202
- }
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;
208
- }
209
- }
210
-
211
- static void strip_scale_rgb(uint16_t **in, uint32_t strip_height, size_t len,
212
- uint8_t *out, fix1_30 *coeffs)
213
- {
214
- size_t i;
215
- uint32_t j;
216
- fix33_30 coeff, sum[3];
217
-
218
- for (i=0; i<len; i+=4) {
219
- sum[0] = sum[1] = sum[2] = 0;
220
- for (j=0; j<strip_height; j++) {
221
- coeff = coeffs[j];
222
- sum[0] += coeff * in[j][i];
223
- sum[1] += coeff * in[j][i + 1];
224
- sum[2] += coeff * in[j][i + 2];
225
- }
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;
230
- }
231
- }
232
-
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)
251
- {
252
- size_t i;
253
- uint32_t j;
254
- fix33_30 coeff, sum[4];
255
-
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++) {
259
- coeff = coeffs[j];
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];
264
- }
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;
270
- }
271
- }
272
-
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)
299
- {
300
- fix1_30 *coeffs;
301
-
302
- coeffs = malloc(strip_height * sizeof(fix1_30));
303
- if (!coeffs) {
304
- return -2; // unable to allocate
305
- }
306
- calc_coeffs(coeffs, ty, strip_height);
307
-
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;
325
- }
326
-
327
- free(coeffs);
328
- return 0;
329
- }
330
-
331
- /* Bicubic x scaler */
332
-
333
- static void sample_generic(uint32_t taps, fix1_30 *coeffs, uint16_t *in,
334
- uint16_t *out, uint8_t cmp)
335
- {
336
- uint8_t i;
337
- uint32_t j;
338
- fix33_30 total, coeff;
339
-
340
- for (i=0; i<cmp; i++) {
341
- total = 0;
342
- for (j=0; j<taps; j++){
343
- coeff = coeffs[j];
344
- total += coeff * in[j * cmp + i];
345
- }
346
- out[i] = clamp(total);
347
- }
348
- }
349
-
350
- static void sample_rgba(uint32_t taps, fix1_30 *coeffs, uint16_t *in,
351
- uint16_t *out)
352
- {
353
- uint32_t i;
354
- fix33_30 sum[4], coeff;
355
-
356
- sum[0] = sum[1] = sum[2] = sum[3] = 0;
357
- for (i=0; i<taps; i++) {
358
- coeff = coeffs[i];
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;
364
- }
365
- out[0] = clamp(sum[0]);
366
- out[1] = clamp(sum[1]);
367
- out[2] = clamp(sum[2]);
368
- out[3] = clamp(sum[3]);
369
- }
370
-
371
- static void sample_rgbx(uint32_t taps, fix1_30 *coeffs, uint16_t *in,
372
- uint16_t *out)
373
- {
374
- uint32_t i;
375
- fix33_30 sum[3], coeff;
376
-
377
- sum[0] = sum[1] = sum[2] = 0;
378
- for (i=0; i<taps; i++) {
379
- coeff = coeffs[i];
380
- sum[0] += coeff * in[0];
381
- sum[1] += coeff * in[1];
382
- sum[2] += coeff * in[2];
383
- in += 4;
384
- }
385
- out[0] = clamp(sum[0]);
386
- out[1] = clamp(sum[1]);
387
- out[2] = clamp(sum[2]);
388
- out[3] = 0;
389
- }
390
-
391
- static void xscale_set_sample(uint32_t taps, fix1_30 *coeffs, uint16_t *in,
392
- uint16_t *out, enum oil_colorspace cs)
393
- {
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;
407
- }
408
- }
409
-
410
- void padded_sl_extend_edges(uint16_t *buf, uint32_t width, size_t pad_len,
411
- uint8_t cmp)
412
- {
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
- }
420
- }
421
-
422
- size_t padded_sl_len_offset(uint32_t in_width, uint32_t out_width,
423
- uint8_t cmp, size_t *offset)
424
- {
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);
429
- }
430
-
431
- int xscale_padded(uint16_t *in, uint32_t in_width, uint16_t *out,
432
- uint32_t out_width, enum oil_colorspace cs)
433
- {
434
- float tx;
435
- fix1_30 *coeffs;
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
- }
445
-
446
- cmp = CS_TO_CMP(cs);
447
- taps = calc_taps(in_width, out_width);
448
- coeffs = malloc(taps * sizeof(fix1_30));
449
- if (!coeffs) {
450
- return -2; // unable to allocate space for coefficients
451
- }
452
-
453
- scale_gcd = gcd(in_width, out_width);
454
- in_chunk = in_width / scale_gcd;
455
- out_chunk = out_width / scale_gcd;
456
-
457
- for (i=0; i<out_chunk; i++) {
458
- xsmp_i = split_map(in_width, out_width, i, &tx);
459
- calc_coeffs(coeffs, tx, taps);
460
-
461
- xsmp_i += 1 - taps / 2;
462
- out_pos = out + i * cmp;
463
- for (j=0; j<scale_gcd; j++) {
464
- tmp = in + xsmp_i * cmp;
465
- xscale_set_sample(taps, coeffs, tmp, out_pos, cs);
466
- out_pos += out_chunk * cmp;
467
- xsmp_i += in_chunk;
468
- }
469
- }
470
-
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
- }
938
- }