oil 0.2.0 → 0.2.1

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.
@@ -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
- }