/src/ghostpdl/base/gsfunc0.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Implementation of FunctionType 0 (Sampled) Functions */ |
18 | | #include "math_.h" |
19 | | #include "gx.h" |
20 | | #include "gserrors.h" |
21 | | #include "gsfunc0.h" |
22 | | #include "gsparam.h" |
23 | | #include "gxfarith.h" |
24 | | #include "gxfunc.h" |
25 | | #include "stream.h" |
26 | | #include "gsccolor.h" /* Only for GS_CLIENT_COLOR_MAX_COMPONENTS */ |
27 | | |
28 | | #define POLE_CACHE_DEBUG 0 /* A temporary development technology need. |
29 | | Remove after the beta testing. */ |
30 | 416 | #define POLE_CACHE_GENERIC_1D 1 /* A temporary development technology need. |
31 | | Didn't decide yet - see fn_Sd_evaluate_cubic_cached_1d. */ |
32 | 760 | #define POLE_CACHE_IGNORE 0 /* A temporary development technology need. |
33 | | Remove after the beta testing. */ |
34 | | |
35 | 177k | #define MAX_FAST_COMPS 8 |
36 | | |
37 | | typedef struct gs_function_Sd_s { |
38 | | gs_function_head_t head; |
39 | | gs_function_Sd_params_t params; |
40 | | } gs_function_Sd_t; |
41 | | |
42 | | /* GC descriptor */ |
43 | | private_st_function_Sd(); |
44 | | static |
45 | 170 | ENUM_PTRS_WITH(function_Sd_enum_ptrs, gs_function_Sd_t *pfn) |
46 | 68 | { |
47 | 68 | index -= 6; |
48 | 68 | if (index < st_data_source_max_ptrs) |
49 | 17 | return ENUM_USING(st_data_source, &pfn->params.DataSource, |
50 | 68 | sizeof(pfn->params.DataSource), index); |
51 | 51 | return ENUM_USING_PREFIX(st_function, st_data_source_max_ptrs); |
52 | 68 | } |
53 | 68 | ENUM_PTR3(0, gs_function_Sd_t, params.Encode, params.Decode, params.Size); |
54 | 170 | ENUM_PTR3(3, gs_function_Sd_t, params.pole, params.array_step, params.stream_step); |
55 | 170 | ENUM_PTRS_END |
56 | | static |
57 | 17 | RELOC_PTRS_WITH(function_Sd_reloc_ptrs, gs_function_Sd_t *pfn) |
58 | 17 | { |
59 | 17 | RELOC_PREFIX(st_function); |
60 | 17 | RELOC_USING(st_data_source, &pfn->params.DataSource, |
61 | 17 | sizeof(pfn->params.DataSource)); |
62 | 17 | RELOC_PTR3(gs_function_Sd_t, params.Encode, params.Decode, params.Size); |
63 | 17 | RELOC_PTR3(gs_function_Sd_t, params.pole, params.array_step, params.stream_step); |
64 | 17 | } |
65 | 17 | RELOC_PTRS_END |
66 | | |
67 | | /* Define the maximum plausible number of inputs and outputs */ |
68 | | /* for a Sampled function. */ |
69 | | #ifndef GS_CLIENT_SAMPLED_FN_MAX_COMPONENTS /* Allow override with XCFLAGS */ |
70 | 53.1k | # define max_Sd_m GS_CLIENT_COLOR_MAX_COMPONENTS |
71 | | # define max_Sd_n GS_CLIENT_COLOR_MAX_COMPONENTS |
72 | | #else |
73 | | # define max_Sd_m GS_CLIENT_SAMPLED_FN_MAX_COMPONENTS |
74 | | # define max_Sd_n GS_CLIENT_SAMPLED_FN_MAX_COMPONENTS |
75 | | #endif |
76 | | |
77 | | /* Get one set of sample values. */ |
78 | | #define SETUP_SAMPLES(bps, nbytes)\ |
79 | 53.2M | int n = pfn->params.n;\ |
80 | 53.2M | byte buf[max_Sd_n * ((bps + 7) >> 3)];\ |
81 | 53.2M | const byte *p;\ |
82 | 53.2M | int i;\ |
83 | 53.2M | \ |
84 | 53.2M | data_source_access(&pfn->params.DataSource, offset >> 3,\ |
85 | 53.2M | nbytes, buf, &p) |
86 | | |
87 | | static int |
88 | | fn_gets_1(const gs_function_Sd_t * pfn, ulong offset, uint * samples) |
89 | 0 | { |
90 | 0 | SETUP_SAMPLES(1, ((offset & 7) + n + 7) >> 3); |
91 | 0 | for (i = 0; i < n; ++i) { |
92 | 0 | samples[i] = (*p >> (~offset & 7)) & 1; |
93 | 0 | if (!(++offset & 7)) |
94 | 0 | p++; |
95 | 0 | } |
96 | 0 | return 0; |
97 | 0 | } |
98 | | static int |
99 | | fn_gets_2(const gs_function_Sd_t * pfn, ulong offset, uint * samples) |
100 | 0 | { |
101 | 0 | SETUP_SAMPLES(2, (((offset & 7) >> 1) + n + 3) >> 2); |
102 | 0 | for (i = 0; i < n; ++i) { |
103 | 0 | samples[i] = (*p >> (6 - (offset & 7))) & 3; |
104 | 0 | if (!((offset += 2) & 7)) |
105 | 0 | p++; |
106 | 0 | } |
107 | 0 | return 0; |
108 | 0 | } |
109 | | static int |
110 | | fn_gets_4(const gs_function_Sd_t * pfn, ulong offset, uint * samples) |
111 | 0 | { |
112 | 0 | SETUP_SAMPLES(4, (((offset & 7) >> 2) + n + 1) >> 1); |
113 | 0 | for (i = 0; i < n; ++i) { |
114 | 0 | samples[i] = ((offset ^= 4) & 4 ? *p >> 4 : *p++ & 0xf); |
115 | 0 | } |
116 | 0 | return 0; |
117 | 0 | } |
118 | | static int |
119 | | fn_gets_8(const gs_function_Sd_t * pfn, ulong offset, uint * samples) |
120 | 53.1M | { |
121 | 53.1M | SETUP_SAMPLES(8, n); |
122 | 127M | for (i = 0; i < n; ++i) { |
123 | 74.2M | samples[i] = *p++; |
124 | 74.2M | } |
125 | 53.1M | return 0; |
126 | 53.1M | } |
127 | | static int |
128 | | fn_gets_12(const gs_function_Sd_t * pfn, ulong offset, uint * samples) |
129 | 0 | { |
130 | 0 | SETUP_SAMPLES(12, (((offset & 7) >> 2) + 3 * n + 1) >> 1); |
131 | 0 | for (i = 0; i < n; ++i) { |
132 | 0 | if (offset & 4) |
133 | 0 | samples[i] = ((*p & 0xf) << 8) + p[1], p += 2; |
134 | 0 | else |
135 | 0 | samples[i] = (*p << 4) + (p[1] >> 4), p++; |
136 | 0 | offset ^= 4; |
137 | 0 | } |
138 | 0 | return 0; |
139 | 0 | } |
140 | | static int |
141 | | fn_gets_16(const gs_function_Sd_t * pfn, ulong offset, uint * samples) |
142 | 57.8k | { |
143 | 57.8k | SETUP_SAMPLES(16, n * 2); |
144 | 116k | for (i = 0; i < n; ++i) { |
145 | 58.3k | samples[i] = (*p << 8) + p[1]; |
146 | 58.3k | p += 2; |
147 | 58.3k | } |
148 | 57.8k | return 0; |
149 | 57.8k | } |
150 | | static int |
151 | | fn_gets_24(const gs_function_Sd_t * pfn, ulong offset, uint * samples) |
152 | 0 | { |
153 | 0 | SETUP_SAMPLES(24, n * 3); |
154 | 0 | for (i = 0; i < n; ++i) { |
155 | 0 | samples[i] = (*p << 16) + (p[1] << 8) + p[2]; |
156 | 0 | p += 3; |
157 | 0 | } |
158 | 0 | return 0; |
159 | 0 | } |
160 | | static int |
161 | | fn_gets_32(const gs_function_Sd_t * pfn, ulong offset, uint * samples) |
162 | 0 | { |
163 | 0 | SETUP_SAMPLES(32, n * 4); |
164 | 0 | for (i = 0; i < n; ++i) { |
165 | 0 | samples[i] = (*p << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; |
166 | 0 | p += 4; |
167 | 0 | } |
168 | 0 | return 0; |
169 | 0 | } |
170 | | |
171 | | static int (*const fn_get_samples[]) (const gs_function_Sd_t * pfn, |
172 | | ulong offset, uint * samples) = |
173 | | { |
174 | | 0, fn_gets_1, fn_gets_2, 0, fn_gets_4, 0, 0, 0, |
175 | | fn_gets_8, 0, 0, 0, fn_gets_12, 0, 0, 0, |
176 | | fn_gets_16, 0, 0, 0, 0, 0, 0, 0, |
177 | | fn_gets_24, 0, 0, 0, 0, 0, 0, 0, |
178 | | fn_gets_32 |
179 | | }; |
180 | | |
181 | | /* |
182 | | * Compute a value by cubic interpolation. |
183 | | * f[] = f(0), f(1), f(2), f(3); 1 < x < 2. |
184 | | * The formula is derived from those presented in |
185 | | * http://www.cs.uwa.edu.au/undergraduate/units/233.413/Handouts/Lecture04.html |
186 | | * (thanks to Raph Levien for the reference). |
187 | | */ |
188 | | static double |
189 | | interpolate_cubic(double x, double f0, double f1, double f2, double f3) |
190 | 0 | { |
191 | | /* |
192 | | * The parameter 'a' affects the contribution of the high-frequency |
193 | | * components. The abovementioned source suggests a = -0.5. |
194 | | */ |
195 | 0 | #define a (-0.5) |
196 | 0 | #define SQR(v) ((v) * (v)) |
197 | 0 | #define CUBE(v) ((v) * (v) * (v)) |
198 | 0 | const double xm1 = x - 1, m2x = 2 - x, m3x = 3 - x; |
199 | 0 | const double c = |
200 | 0 | (a * CUBE(x) - 5 * a * SQR(x) + 8 * a * x - 4 * a) * f0 + |
201 | 0 | ((a+2) * CUBE(xm1) - (a+3) * SQR(xm1) + 1) * f1 + |
202 | 0 | ((a+2) * CUBE(m2x) - (a+3) * SQR(m2x) + 1) * f2 + |
203 | 0 | (a * CUBE(m3x) - 5 * a * SQR(m3x) + 8 * a * m3x - 4 * a) * f3; |
204 | |
|
205 | 0 | if_debug6('~', "[~](%g, %g, %g, %g)order3(%g) => %g\n", |
206 | 0 | f0, f1, f2, f3, x, c); |
207 | 0 | return c; |
208 | 0 | #undef a |
209 | 0 | #undef SQR |
210 | 0 | #undef CUBE |
211 | 0 | } |
212 | | |
213 | | /* |
214 | | * Compute a value by quadratic interpolation. |
215 | | * f[] = f(0), f(1), f(2); 0 < x < 1. |
216 | | * |
217 | | * We used to use a quadratic formula for this, derived from |
218 | | * f(0) = f0, f(1) = f1, f'(1) = (f2 - f0) / 2, but now we |
219 | | * match what we believe is Acrobat Reader's behavior. |
220 | | */ |
221 | | static inline double |
222 | | interpolate_quadratic(double x, double f0, double f1, double f2) |
223 | 0 | { |
224 | 0 | return interpolate_cubic(x + 1, f0, f0, f1, f2); |
225 | 0 | } |
226 | | |
227 | | /* Calculate a result by multicubic interpolation. */ |
228 | | static void |
229 | | fn_interpolate_cubic(const gs_function_Sd_t *pfn, const float *fparts, |
230 | | const int *iparts, const ulong *factors, |
231 | | float *samples, ulong offset, int m) |
232 | 0 | { |
233 | 0 | int j; |
234 | |
|
235 | 0 | top: |
236 | 0 | if (m == 0) { |
237 | 0 | uint sdata[max_Sd_n]; |
238 | |
|
239 | 0 | (*fn_get_samples[pfn->params.BitsPerSample])(pfn, offset, sdata); |
240 | 0 | for (j = pfn->params.n - 1; j >= 0; --j) |
241 | 0 | samples[j] = (float)sdata[j]; |
242 | 0 | } else { |
243 | 0 | float fpart = *fparts++; |
244 | 0 | int ipart = *iparts++; |
245 | 0 | ulong delta = *factors++; |
246 | 0 | int size = pfn->params.Size[pfn->params.m - m]; |
247 | 0 | float samples1[max_Sd_n], samplesm1[max_Sd_n], samples2[max_Sd_n]; |
248 | |
|
249 | 0 | --m; |
250 | 0 | if (is_fzero(fpart)) |
251 | 0 | goto top; |
252 | 0 | fn_interpolate_cubic(pfn, fparts, iparts, factors, samples, |
253 | 0 | offset, m); |
254 | 0 | fn_interpolate_cubic(pfn, fparts, iparts, factors, samples1, |
255 | 0 | offset + delta, m); |
256 | | /* Ensure we don't try to access out of bounds. */ |
257 | | /* |
258 | | * If size == 1, the only possible value for ipart and fpart is |
259 | | * 0, so we've already handled this case. |
260 | | */ |
261 | 0 | if (size == 2) { /* ipart = 0 */ |
262 | | /* Use linear interpolation. */ |
263 | 0 | for (j = pfn->params.n - 1; j >= 0; --j) |
264 | 0 | samples[j] += (samples1[j] - samples[j]) * fpart; |
265 | 0 | return; |
266 | 0 | } |
267 | 0 | if (ipart == 0) { |
268 | | /* Use quadratic interpolation. */ |
269 | 0 | fn_interpolate_cubic(pfn, fparts, iparts, factors, |
270 | 0 | samples2, offset + delta * 2, m); |
271 | 0 | for (j = pfn->params.n - 1; j >= 0; --j) |
272 | 0 | samples[j] = |
273 | 0 | interpolate_quadratic(fpart, samples[j], |
274 | 0 | samples1[j], samples2[j]); |
275 | 0 | return; |
276 | 0 | } |
277 | | /* At this point we know ipart > 0, size >= 3. */ |
278 | 0 | fn_interpolate_cubic(pfn, fparts, iparts, factors, samplesm1, |
279 | 0 | offset - delta, m); |
280 | 0 | if (ipart == size - 2) { |
281 | | /* Use quadratic interpolation. */ |
282 | 0 | for (j = pfn->params.n - 1; j >= 0; --j) |
283 | 0 | samples[j] = |
284 | 0 | interpolate_quadratic(1 - fpart, samples1[j], |
285 | 0 | samples[j], samplesm1[j]); |
286 | 0 | return; |
287 | 0 | } |
288 | | /* Now we know 0 < ipart < size - 2, size > 3. */ |
289 | 0 | fn_interpolate_cubic(pfn, fparts, iparts, factors, |
290 | 0 | samples2, offset + delta * 2, m); |
291 | 0 | for (j = pfn->params.n - 1; j >= 0; --j) |
292 | 0 | samples[j] = |
293 | 0 | interpolate_cubic(fpart + 1, samplesm1[j], samples[j], |
294 | 0 | samples1[j], samples2[j]); |
295 | 0 | } |
296 | 0 | } |
297 | | |
298 | | /* Calculate a result by multilinear interpolation. */ |
299 | | static void |
300 | | fn_interpolate_linear(const gs_function_Sd_t *pfn, const float *fparts, |
301 | | const ulong *factors, float *samples, ulong offset, int m) |
302 | 9.99M | { |
303 | 9.99M | int j; |
304 | | |
305 | 10.3M | top: |
306 | 10.3M | if (m == 0) { |
307 | 6.77M | uint sdata[max_Sd_n]; |
308 | | |
309 | 6.77M | (*fn_get_samples[pfn->params.BitsPerSample])(pfn, offset, sdata); |
310 | 22.4M | for (j = pfn->params.n - 1; j >= 0; --j) |
311 | 15.6M | samples[j] = (float)sdata[j]; |
312 | 6.77M | } else { |
313 | 3.55M | float fpart = *fparts++; |
314 | 3.55M | float samples1[max_Sd_n]; |
315 | | |
316 | 3.55M | if (is_fzero(fpart)) { |
317 | 330k | ++factors; |
318 | 330k | --m; |
319 | 330k | goto top; |
320 | 330k | } |
321 | 3.22M | fn_interpolate_linear(pfn, fparts, factors + 1, samples, |
322 | 3.22M | offset, m - 1); |
323 | 3.22M | fn_interpolate_linear(pfn, fparts, factors + 1, samples1, |
324 | 3.22M | offset + *factors, m - 1); |
325 | 10.7M | for (j = pfn->params.n - 1; j >= 0; --j) |
326 | 7.52M | samples[j] += (samples1[j] - samples[j]) * fpart; |
327 | 3.22M | } |
328 | 10.3M | } |
329 | | |
330 | | static inline double |
331 | | fn_Sd_encode(const gs_function_Sd_t *pfn, int i, double sample) |
332 | 66.7M | { |
333 | 66.7M | float d0, d1, r0, r1; |
334 | 66.7M | double value; |
335 | 66.7M | int bps = pfn->params.BitsPerSample; |
336 | | /* x86 machines have problems with shifts if bps >= 32 */ |
337 | 66.7M | uint max_samp = (bps < (sizeof(uint) * 8)) ? ((1 << bps) - 1) : max_uint; |
338 | | |
339 | 66.7M | if (pfn->params.Range) |
340 | 66.7M | r0 = pfn->params.Range[2 * i], r1 = pfn->params.Range[2 * i + 1]; |
341 | 0 | else |
342 | 0 | r0 = 0, r1 = (float)max_samp; |
343 | 66.7M | if (pfn->params.Decode) |
344 | 25.0M | d0 = pfn->params.Decode[2 * i], d1 = pfn->params.Decode[2 * i + 1]; |
345 | 41.7M | else |
346 | 41.7M | d0 = r0, d1 = r1; |
347 | | |
348 | 66.7M | value = sample * (d1 - d0) / max_samp + d0; |
349 | 66.7M | if (value < r0) |
350 | 0 | value = r0; |
351 | 66.7M | else if (value > r1) |
352 | 0 | value = r1; |
353 | 66.7M | return value; |
354 | 66.7M | } |
355 | | |
356 | | /* Evaluate a Sampled function. */ |
357 | | /* A generic algorithm with a recursion by dimentions. */ |
358 | | static int |
359 | | fn_Sd_evaluate_general(const gs_function_t * pfn_common, const float *in, float *out) |
360 | 3.55M | { |
361 | 3.55M | const gs_function_Sd_t *pfn = (const gs_function_Sd_t *)pfn_common; |
362 | 3.55M | int bps = pfn->params.BitsPerSample; |
363 | 3.55M | ulong offset = 0; |
364 | 3.55M | int i; |
365 | 3.55M | float encoded[max_Sd_m]; |
366 | 3.55M | int iparts[max_Sd_m]; /* only needed for cubic interpolation */ |
367 | 3.55M | ulong factors[max_Sd_m]; |
368 | 3.55M | float samples[max_Sd_n]; |
369 | | |
370 | | /* Encode the input values. */ |
371 | | |
372 | 7.10M | for (i = 0; i < pfn->params.m; ++i) { |
373 | 3.55M | float d0 = pfn->params.Domain[2 * i], |
374 | 3.55M | d1 = pfn->params.Domain[2 * i + 1]; |
375 | 3.55M | float arg = in[i], enc; |
376 | | |
377 | 3.55M | if (arg < d0) |
378 | 39 | arg = d0; |
379 | 3.55M | else if (arg > d1) |
380 | 0 | arg = d1; |
381 | 3.55M | if (pfn->params.Encode) { |
382 | 2.28M | float e0 = pfn->params.Encode[2 * i]; |
383 | 2.28M | float e1 = pfn->params.Encode[2 * i + 1]; |
384 | | |
385 | 2.28M | enc = (arg - d0) * (e1 - e0) / (d1 - d0) + e0; |
386 | 2.28M | if (enc < 0) |
387 | 0 | encoded[i] = 0; |
388 | 2.28M | else if (enc >= pfn->params.Size[i] - 1) |
389 | 73.9k | encoded[i] = (float)pfn->params.Size[i] - 1; |
390 | 2.21M | else |
391 | 2.21M | encoded[i] = enc; |
392 | 2.28M | } else { |
393 | | /* arg is guaranteed to be in bounds, ergo so is enc */ |
394 | | /* TODO: possible issue here. if (pfn->params.Size[i] == 1 */ |
395 | 1.26M | encoded[i] = (arg - d0) * (pfn->params.Size[i] - 1) / (d1 - d0); |
396 | 1.26M | } |
397 | 3.55M | } |
398 | | |
399 | | /* Look up and interpolate the output values. */ |
400 | | |
401 | 3.55M | { |
402 | 3.55M | ulong factor = (ulong)bps * pfn->params.n; |
403 | | |
404 | 7.10M | for (i = 0; i < pfn->params.m; factor *= pfn->params.Size[i++]) { |
405 | 3.55M | int ipart = (int)encoded[i]; |
406 | | |
407 | 3.55M | offset += (factors[i] = factor) * ipart; |
408 | 3.55M | iparts[i] = ipart; /* only needed for cubic interpolation */ |
409 | 3.55M | encoded[i] -= ipart; |
410 | 3.55M | } |
411 | 3.55M | } |
412 | 3.55M | if (pfn->params.Order == 3) |
413 | 0 | fn_interpolate_cubic(pfn, encoded, iparts, factors, samples, |
414 | 0 | offset, pfn->params.m); |
415 | 3.55M | else |
416 | 3.55M | fn_interpolate_linear(pfn, encoded, factors, samples, offset, |
417 | 3.55M | pfn->params.m); |
418 | | |
419 | | /* Encode the output values. */ |
420 | | |
421 | 11.7M | for (i = 0; i < pfn->params.n; ++i) |
422 | 8.16M | out[i] = (float)fn_Sd_encode(pfn, i, samples[i]); |
423 | | |
424 | 3.55M | return 0; |
425 | 3.55M | } |
426 | | |
427 | | static const double double_stub = 1e90; |
428 | | |
429 | | static inline void |
430 | | fn_make_cubic_poles(double *p, double f0, double f1, double f2, double f3, |
431 | | const int pole_step_minor) |
432 | 12 | { /* The following is poles of the polinomial, |
433 | | which represents interpolate_cubic in [1,2]. */ |
434 | 12 | const double a = -0.5; |
435 | | |
436 | 12 | p[pole_step_minor * 1] = (a*f0 + 3*f1 - a*f2)/3.0; |
437 | 12 | p[pole_step_minor * 2] = (-a*f1 + 3*f2 + a*f3)/3.0; |
438 | 12 | } |
439 | | |
440 | | static void |
441 | | fn_make_poles(double *p, const int pole_step, int power, int bias) |
442 | 12 | { |
443 | 12 | const int pole_step_minor = pole_step / 3; |
444 | 12 | switch(power) { |
445 | 0 | case 1: /* A linear 3d power curve. */ |
446 | | /* bias must be 0. */ |
447 | 0 | p[pole_step_minor * 1] = (2 * p[pole_step * 0] + 1 * p[pole_step * 1]) / 3; |
448 | 0 | p[pole_step_minor * 2] = (1 * p[pole_step * 0] + 2 * p[pole_step * 1]) / 3; |
449 | 0 | break; |
450 | 0 | case 2: |
451 | | /* bias may be be 0 or 1. */ |
452 | | /* Duplicate the beginning or the ending pole (the old code compatible). */ |
453 | 0 | fn_make_cubic_poles(p + pole_step * bias, |
454 | 0 | p[pole_step * 0], p[pole_step * bias], |
455 | 0 | p[pole_step * (1 + bias)], p[pole_step * 2], |
456 | 0 | pole_step_minor); |
457 | 0 | break; |
458 | 12 | case 3: |
459 | | /* bias must be 1. */ |
460 | 12 | fn_make_cubic_poles(p + pole_step * bias, |
461 | 12 | p[pole_step * 0], p[pole_step * 1], p[pole_step * 2], p[pole_step * 3], |
462 | 12 | pole_step_minor); |
463 | 12 | break; |
464 | 0 | default: /* Must not happen. */ |
465 | 0 | DO_NOTHING; |
466 | 12 | } |
467 | 12 | } |
468 | | |
469 | | /* Evaluate a Sampled function. |
470 | | A cubic interpolation with a pole cache. |
471 | | Allows a fast check for extreme suspection. */ |
472 | | /* This implementation is a particular case of 1 dimension. |
473 | | maybe we'll use as an optimisation of the generic case, |
474 | | so keep it for a while. */ |
475 | | static int |
476 | | fn_Sd_evaluate_cubic_cached_1d(const gs_function_Sd_t *pfn, const float *in, float *out) |
477 | 0 | { |
478 | 0 | float d0 = pfn->params.Domain[2 * 0]; |
479 | 0 | float d1 = pfn->params.Domain[2 * 0 + 1]; |
480 | 0 | const int pole_step_minor = pfn->params.n; |
481 | 0 | const int pole_step = 3 * pole_step_minor; |
482 | 0 | int i0; /* A cell index. */ |
483 | 0 | int ib, ie, i, k; |
484 | 0 | double *p, t0, t1, tt; |
485 | 0 |
|
486 | 0 | tt = (in[0] - d0) * (pfn->params.Size[0] - 1) / (d1 - d0); |
487 | 0 | i0 = (int)floor(tt); |
488 | 0 | ib = max(i0 - 1, 0); |
489 | 0 | ie = min(pfn->params.Size[0], i0 + 3); |
490 | 0 | for (i = ib; i < ie; i++) { |
491 | 0 | if (pfn->params.pole[i * pole_step] == double_stub) { |
492 | 0 | uint sdata[max_Sd_n]; |
493 | 0 | int bps = pfn->params.BitsPerSample; |
494 | 0 |
|
495 | 0 | p = &pfn->params.pole[i * pole_step]; |
496 | 0 | fn_get_samples[pfn->params.BitsPerSample](pfn, (ulong)i * bps * pfn->params.n, sdata); |
497 | 0 | for (k = 0; k < pfn->params.n; k++, p++) |
498 | 0 | *p = fn_Sd_encode(pfn, k, (double)sdata[k]); |
499 | 0 | } |
500 | 0 | } |
501 | 0 | p = &pfn->params.pole[i0 * pole_step]; |
502 | 0 | t0 = tt - i0; |
503 | 0 | if (t0 == 0) { |
504 | 0 | for (k = 0; k < pfn->params.n; k++, p++) |
505 | 0 | out[k] = *p; |
506 | 0 | } else { |
507 | 0 | if (p[1 * pole_step_minor] == double_stub) { |
508 | 0 | for (k = 0; k < pfn->params.n; k++) |
509 | 0 | fn_make_poles(&pfn->params.pole[ib * pole_step + k], pole_step, |
510 | 0 | ie - ib - 1, i0 - ib); |
511 | 0 | } |
512 | 0 | t1 = 1 - t0; |
513 | 0 | for (k = 0; k < pfn->params.n; k++, p++) { |
514 | 0 | double y = p[0 * pole_step_minor] * t1 * t1 * t1 + |
515 | 0 | p[1 * pole_step_minor] * t1 * t1 * t0 * 3 + |
516 | 0 | p[2 * pole_step_minor] * t1 * t0 * t0 * 3 + |
517 | 0 | p[3 * pole_step_minor] * t0 * t0 * t0; |
518 | 0 | if (y < pfn->params.Range[0]) |
519 | 0 | y = pfn->params.Range[0]; |
520 | 0 | if (y > pfn->params.Range[1]) |
521 | 0 | y = pfn->params.Range[1]; |
522 | 0 | out[k] = y; |
523 | 0 | } |
524 | 0 | } |
525 | 0 | return 0; |
526 | 0 | } |
527 | | |
528 | | static inline void |
529 | | decode_argument(const gs_function_Sd_t *pfn, const float *in, double T[max_Sd_m], int I[max_Sd_m]) |
530 | 208 | { |
531 | 208 | int i; |
532 | | |
533 | 416 | for (i = 0; i < pfn->params.m; i++) { |
534 | 208 | float xi = in[i]; |
535 | 208 | float d0 = pfn->params.Domain[2 * i + 0]; |
536 | 208 | float d1 = pfn->params.Domain[2 * i + 1]; |
537 | 208 | double t; |
538 | | |
539 | 208 | if (xi < d0) |
540 | 0 | xi = d0; |
541 | 208 | if (xi > d1) |
542 | 0 | xi = d1; |
543 | 208 | t = (xi - d0) * (pfn->params.Size[i] - 1) / (d1 - d0); |
544 | 208 | I[i] = (int)floor(t); |
545 | 208 | T[i] = t - I[i]; |
546 | 208 | } |
547 | 208 | } |
548 | | |
549 | | static inline void |
550 | | index_span(const gs_function_Sd_t *pfn, int *I, double *T, int ii, int *Ii, int *ib, int *ie) |
551 | 208 | { |
552 | 208 | *Ii = I[ii]; |
553 | 208 | if (T[ii] != 0) { |
554 | 3 | *ib = max(*Ii - 1, 0); |
555 | 3 | *ie = min(pfn->params.Size[ii], *Ii + 3); |
556 | 205 | } else { |
557 | 205 | *ib = *Ii; |
558 | 205 | *ie = *Ii + 1; |
559 | 205 | } |
560 | 208 | } |
561 | | |
562 | | static inline int |
563 | | load_vector_to(const gs_function_Sd_t *pfn, int s_offset, double *V) |
564 | 46.4M | { |
565 | 46.4M | uint sdata[max_Sd_n]; |
566 | 46.4M | int k, code; |
567 | | |
568 | 46.4M | code = fn_get_samples[pfn->params.BitsPerSample](pfn, s_offset, sdata); |
569 | 46.4M | if (code < 0) |
570 | 0 | return code; |
571 | 105M | for (k = 0; k < pfn->params.n; k++) |
572 | 58.5M | V[k] = fn_Sd_encode(pfn, k, (double)sdata[k]); |
573 | 46.4M | return 0; |
574 | 46.4M | } |
575 | | |
576 | | static inline int |
577 | | load_vector(const gs_function_Sd_t *pfn, int a_offset, int s_offset) |
578 | 172 | { |
579 | 172 | if (*(pfn->params.pole + a_offset) == double_stub) { |
580 | 172 | uint sdata[max_Sd_n]; |
581 | 172 | int k, code; |
582 | | |
583 | 172 | code = fn_get_samples[pfn->params.BitsPerSample](pfn, s_offset, sdata); |
584 | 172 | if (code < 0) |
585 | 0 | return code; |
586 | 860 | for (k = 0; k < pfn->params.n; k++) |
587 | 688 | *(pfn->params.pole + a_offset + k) = fn_Sd_encode(pfn, k, (double)sdata[k]); |
588 | 172 | } |
589 | 172 | return 0; |
590 | 172 | } |
591 | | |
592 | | static inline void |
593 | | interpolate_vector(const gs_function_Sd_t *pfn, int offset, int pole_step, int power, int bias) |
594 | 3 | { |
595 | 3 | int k; |
596 | | |
597 | 15 | for (k = 0; k < pfn->params.n; k++) |
598 | 12 | fn_make_poles(pfn->params.pole + offset + k, pole_step, power, bias); |
599 | 3 | } |
600 | | |
601 | | static inline void |
602 | | interpolate_tensors(const gs_function_Sd_t *pfn, int *I, double *T, |
603 | | int offset, int pole_step, int power, int bias, int ii) |
604 | 3 | { |
605 | 3 | if (ii < 0) |
606 | 3 | interpolate_vector(pfn, offset, pole_step, power, bias); |
607 | 0 | else { |
608 | 0 | int s = pfn->params.array_step[ii]; |
609 | 0 | int Ii = I[ii]; |
610 | |
|
611 | 0 | if (T[ii] == 0) { |
612 | 0 | interpolate_tensors(pfn, I, T, offset + Ii * s, pole_step, power, bias, ii - 1); |
613 | 0 | } else { |
614 | 0 | int l; |
615 | |
|
616 | 0 | for (l = 0; l < 4; l++) |
617 | 0 | interpolate_tensors(pfn, I, T, offset + Ii * s + l * s / 3, pole_step, power, bias, ii - 1); |
618 | 0 | } |
619 | 0 | } |
620 | 3 | } |
621 | | |
622 | | static inline bool |
623 | | is_tensor_done(const gs_function_Sd_t *pfn, int *I, double *T, int a_offset, int ii) |
624 | 208 | { |
625 | | /* Check an inner pole of the cell. */ |
626 | 208 | int i, o = 0; |
627 | | |
628 | 416 | for (i = ii; i >= 0; i--) { |
629 | 208 | o += I[i] * pfn->params.array_step[i]; |
630 | 208 | if (T[i] != 0) |
631 | 3 | o += pfn->params.array_step[i] / 3; |
632 | 208 | } |
633 | 208 | if (*(pfn->params.pole + a_offset + o) != double_stub) |
634 | 45 | return true; |
635 | 163 | return false; |
636 | 208 | } |
637 | | |
638 | | /* Creates a tensor of Bezier coefficients by node interpolation. */ |
639 | | static inline int |
640 | | make_interpolation_tensor(const gs_function_Sd_t *pfn, int *I, double *T, |
641 | | int a_offset, int s_offset, int ii) |
642 | 380 | { |
643 | | /* Well, this function isn't obvious. Trying to explain what it does. |
644 | | |
645 | | Suppose we have a 4x4x4...x4 hypercube of nodes, and we want to build |
646 | | a multicubic interpolation function for the inner 2x2x2...x2 hypercube. |
647 | | We represent the multicubic function with a tensor of Besier poles, |
648 | | and the size of the tensor is 4x4x....x4. Note that the corners |
649 | | of the tensor are equal to the corners of the 2x2x...x2 hypercube. |
650 | | |
651 | | We organize the 'pole' array so that a tensor of a cell |
652 | | occupies the cell, and tensors for neighbour cells have a common hyperplane. |
653 | | |
654 | | For a 1-dimentional case let the nodes are n0, n1, n2, n3. |
655 | | It defines 3 cells n0...n1, n1...n2, n2...n3. |
656 | | For the 2nd cell n1...n2 let the tensor coefficients are q10, q11, q12, q13. |
657 | | We choose a cubic approximation, in which tangents at nodes n1, n2 |
658 | | are parallel to (n2 - n0) and (n3 - n1) correspondingly. |
659 | | (Well, this doesn't give a the minimal curvity, but likely it is |
660 | | what Adobe implementations do, see the bug 687352, |
661 | | and we agree that it's some reasonable). |
662 | | |
663 | | Then we have : |
664 | | |
665 | | q11 = n0 |
666 | | q12 = (n0/2 + 3*n1 - n2/2)/3; |
667 | | q11 = (n1/2 + 3*n2 - n3/2)/3; |
668 | | q13 = n2 |
669 | | |
670 | | When the source node array have an insufficient nomber of nodes |
671 | | along a dimension to determine tangents a cell |
672 | | (this happens near the array boundaries), |
673 | | we simply duplicate ending nodes. This solution is done |
674 | | for the compatibility to the old code, and definitely |
675 | | there exists a better one. Likely Adobe does the same. |
676 | | |
677 | | For a 2-dimensional case we apply the 1-dimentional case through |
678 | | the first dimension, and then construct a surface by varying the |
679 | | second coordinate as a parameter. It gives a bicubic surface, |
680 | | and the result doesn't depend on the order of coordinates |
681 | | (I proved the latter with Matematica 3.0). |
682 | | Then we know that an interpolation by one coordinate and |
683 | | a differentiation by another coordinate are interchangeble operators. |
684 | | Due to that poles of the interpolated function are same as |
685 | | interpolated poles of the function (well, we didn't spend time |
686 | | for a strong proof, but this fact was confirmed with testing the |
687 | | implementation with POLE_CACHE_DEBUG). |
688 | | |
689 | | Then we apply the 2-dimentional considerations recursively |
690 | | to all dimensions. This is exactly what the function does. |
691 | | |
692 | | */ |
693 | 380 | int code; |
694 | | |
695 | 380 | if (ii < 0) { |
696 | 172 | if (POLE_CACHE_IGNORE || *(pfn->params.pole + a_offset) == double_stub) { |
697 | 172 | code = load_vector(pfn, a_offset, s_offset); |
698 | 172 | if (code < 0) |
699 | 0 | return code; |
700 | 172 | } |
701 | 208 | } else { |
702 | 208 | int Ii, ib, ie, i; |
703 | 208 | int sa = pfn->params.array_step[ii]; |
704 | 208 | int ss = pfn->params.stream_step[ii]; |
705 | | |
706 | 208 | index_span(pfn, I, T, ii, &Ii, &ib, &ie); |
707 | 208 | if (POLE_CACHE_IGNORE || !is_tensor_done(pfn, I, T, a_offset, ii)) { |
708 | 335 | for (i = ib; i < ie; i++) { |
709 | 172 | code = make_interpolation_tensor(pfn, I, T, |
710 | 172 | a_offset + i * sa, s_offset + i * ss, ii - 1); |
711 | 172 | if (code < 0) |
712 | 0 | return code; |
713 | 172 | } |
714 | 163 | if (T[ii] != 0) |
715 | 3 | interpolate_tensors(pfn, I, T, a_offset + ib * sa, sa, ie - ib - 1, |
716 | 3 | Ii - ib, ii - 1); |
717 | 163 | } |
718 | 208 | } |
719 | 380 | return 0; |
720 | 380 | } |
721 | | |
722 | | /* Creates a subarray of samples. */ |
723 | | static inline int |
724 | | make_interpolation_nodes(const gs_function_Sd_t *pfn, double *T0, double *T1, |
725 | | int *I, double *T, |
726 | | int a_offset, int s_offset, int ii) |
727 | 0 | { |
728 | 0 | int code; |
729 | |
|
730 | 0 | if (ii < 0) { |
731 | 0 | if (POLE_CACHE_IGNORE || *(pfn->params.pole + a_offset) == double_stub) { |
732 | 0 | code = load_vector(pfn, a_offset, s_offset); |
733 | 0 | if (code < 0) |
734 | 0 | return code; |
735 | 0 | } |
736 | 0 | if (pfn->params.Order == 3) { |
737 | 0 | code = make_interpolation_tensor(pfn, I, T, 0, 0, pfn->params.m - 1); |
738 | 0 | if (code < 0) |
739 | 0 | return code; |
740 | 0 | } |
741 | 0 | } else { |
742 | 0 | int i; |
743 | 0 | int i0 = (int)floor(T0[ii]); |
744 | 0 | int i1 = (int)ceil(T1[ii]); |
745 | 0 | int sa = pfn->params.array_step[ii]; |
746 | 0 | int ss = pfn->params.stream_step[ii]; |
747 | |
|
748 | 0 | if (i0 < 0 || i0 >= pfn->params.Size[ii]) |
749 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
750 | 0 | if (i1 < 0 || i1 >= pfn->params.Size[ii]) |
751 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
752 | 0 | I[ii] = i0; |
753 | 0 | T[ii] = (i1 > i0 ? 1 : 0); |
754 | 0 | for (i = i0; i <= i1; i++) { |
755 | 0 | code = make_interpolation_nodes(pfn, T0, T1, I, T, |
756 | 0 | a_offset + i * sa, s_offset + i * ss, ii - 1); |
757 | 0 | if (code < 0) |
758 | 0 | return code; |
759 | 0 | } |
760 | 0 | } |
761 | 0 | return 0; |
762 | 0 | } |
763 | | |
764 | | static inline int |
765 | | evaluate_from_tenzor(const gs_function_Sd_t *pfn, int *I, double *T, int offset, int ii, double *y) |
766 | 425 | { |
767 | 425 | int s = pfn->params.array_step[ii], k, l, code; |
768 | | |
769 | 425 | if (ii < 0) { |
770 | 1.08k | for (k = 0; k < pfn->params.n; k++) |
771 | 868 | y[k] = *(pfn->params.pole + offset + k); |
772 | 217 | } else if (T[ii] == 0) { |
773 | 205 | return evaluate_from_tenzor(pfn, I, T, offset + s * I[ii], ii - 1, y); |
774 | 205 | } else { |
775 | 3 | double t0 = T[ii], t1 = 1 - t0; |
776 | 3 | double p[4][max_Sd_n]; |
777 | | |
778 | 15 | for (l = 0; l < 4; l++) { |
779 | 12 | code = evaluate_from_tenzor(pfn, I, T, offset + s * I[ii] + l * (s / 3), ii - 1, p[l]); |
780 | 12 | if (code < 0) |
781 | 0 | return code; |
782 | 12 | } |
783 | 15 | for (k = 0; k < pfn->params.n; k++) |
784 | 12 | y[k] = p[0][k] * t1 * t1 * t1 + |
785 | 12 | p[1][k] * t1 * t1 * t0 * 3 + |
786 | 12 | p[2][k] * t1 * t0 * t0 * 3 + |
787 | 12 | p[3][k] * t0 * t0 * t0; |
788 | 3 | } |
789 | 220 | return 0; |
790 | 425 | } |
791 | | |
792 | | /* Evaluate a Sampled function. */ |
793 | | /* A cubic interpolation with pole cache. */ |
794 | | /* Allows a fast check for extreme suspection with is_tensor_monotonic. */ |
795 | | static int |
796 | | fn_Sd_evaluate_multicubic_cached(const gs_function_Sd_t *pfn, const float *in, float *out) |
797 | 208 | { |
798 | 208 | double T[max_Sd_m], y[max_Sd_n]; |
799 | 208 | int I[max_Sd_m], k, code; |
800 | | |
801 | 208 | decode_argument(pfn, in, T, I); |
802 | 208 | code = make_interpolation_tensor(pfn, I, T, 0, 0, pfn->params.m - 1); |
803 | 208 | if (code < 0) |
804 | 0 | return code; |
805 | 208 | evaluate_from_tenzor(pfn, I, T, 0, pfn->params.m - 1, y); |
806 | 1.04k | for (k = 0; k < pfn->params.n; k++) { |
807 | 832 | double yk = y[k]; |
808 | | |
809 | 832 | if (yk < pfn->params.Range[k * 2 + 0]) |
810 | 0 | yk = pfn->params.Range[k * 2 + 0]; |
811 | 832 | if (yk > pfn->params.Range[k * 2 + 1]) |
812 | 0 | yk = pfn->params.Range[k * 2 + 1]; |
813 | 832 | out[k] = yk; |
814 | 832 | } |
815 | 208 | return 0; |
816 | 208 | } |
817 | | |
818 | | /* Evaluate a Sampled function. */ |
819 | | static int |
820 | | fn_Sd_evaluate(const gs_function_t * pfn_common, const float *in, float *out) |
821 | 3.55M | { |
822 | 3.55M | const gs_function_Sd_t *pfn = (const gs_function_Sd_t *)pfn_common; |
823 | 3.55M | int code; |
824 | | |
825 | 3.55M | if (pfn->params.Order == 3) { |
826 | 208 | if (POLE_CACHE_GENERIC_1D || pfn->params.m > 1) |
827 | 208 | code = fn_Sd_evaluate_multicubic_cached(pfn, in, out); |
828 | 0 | else |
829 | 0 | code = fn_Sd_evaluate_cubic_cached_1d(pfn, in, out); |
830 | | # if POLE_CACHE_DEBUG |
831 | | { float y[max_Sd_n]; |
832 | | int k, code1; |
833 | | |
834 | | code1 = fn_Sd_evaluate_general(pfn_common, in, y); |
835 | | if (code != code1) |
836 | | return_error(gs_error_unregistered); /* Must not happen. */ |
837 | | for (k = 0; k < pfn->params.n; k++) { |
838 | | if (any_abs(y[k] - out[k]) > 1e-6 * (pfn->params.Range[k * 2 + 1] - pfn->params.Range[k * 2 + 0])) |
839 | | return_error(gs_error_unregistered); /* Must not happen. */ |
840 | | } |
841 | | } |
842 | | # endif |
843 | 208 | } else |
844 | 3.55M | code = fn_Sd_evaluate_general(pfn_common, in, out); |
845 | 3.55M | return code; |
846 | 3.55M | } |
847 | | |
848 | | /* Map a function subdomain to the sample index subdomain. */ |
849 | | static inline int |
850 | | get_scaled_range(const gs_function_Sd_t *const pfn, |
851 | | const float *lower, const float *upper, |
852 | | int i, float *pw0, float *pw1) |
853 | 73.4k | { |
854 | 73.4k | float d0 = pfn->params.Domain[i * 2 + 0], d1 = pfn->params.Domain[i * 2 + 1]; |
855 | 73.4k | float v0 = lower[i], v1 = upper[i]; |
856 | 73.4k | float e0, e1, w0, w1, w; |
857 | 73.4k | const float small_noise = (float)1e-6; |
858 | | |
859 | 73.4k | if (v0 < d0 || v0 > d1) |
860 | 13 | return_error(gs_error_rangecheck); |
861 | 73.4k | if (pfn->params.Encode) |
862 | 33.3k | e0 = pfn->params.Encode[i * 2 + 0], e1 = pfn->params.Encode[i * 2 + 1]; |
863 | 40.1k | else |
864 | 40.1k | e0 = 0, e1 = (float)pfn->params.Size[i] - 1; |
865 | 73.4k | w0 = (v0 - d0) * (e1 - e0) / (d1 - d0) + e0; |
866 | 73.4k | if (w0 < 0) |
867 | 0 | w0 = 0; |
868 | 73.4k | else if (w0 >= pfn->params.Size[i] - 1) |
869 | 15.5k | w0 = (float)pfn->params.Size[i] - 1; |
870 | 73.4k | w1 = (v1 - d0) * (e1 - e0) / (d1 - d0) + e0; |
871 | 73.4k | if (w1 < 0) |
872 | 0 | w1 = 0; |
873 | 73.4k | else if (w1 >= pfn->params.Size[i] - 1) |
874 | 29.0k | w1 = (float)pfn->params.Size[i] - 1; |
875 | 73.4k | if (w0 > w1) { |
876 | 3.84k | w = w0; w0 = w1; w1 = w; |
877 | 3.84k | } |
878 | 73.4k | if (floor(w0 + 1) - w0 < small_noise * any_abs(e1 - e0)) |
879 | 154 | w0 = (floor(w0) + 1); |
880 | 73.4k | if (w1 - floor(w1) < small_noise * any_abs(e1 - e0)) |
881 | 46.3k | w1 = floor(w1); |
882 | 73.4k | if (w0 > w1) |
883 | 100 | w0 = w1; |
884 | 73.4k | *pw0 = w0; |
885 | 73.4k | *pw1 = w1; |
886 | 73.4k | return 0; |
887 | 73.4k | } |
888 | | |
889 | | /* Copy a tensor to a differently indexed pole array. */ |
890 | | static int |
891 | | copy_poles(const gs_function_Sd_t *pfn, int *I, double *T0, double *T1, int a_offset, |
892 | | int ii, double *pole, int p_offset, int pole_step) |
893 | 0 | { |
894 | 0 | int i, ei, sa, code; |
895 | 0 | int order = pfn->params.Order; |
896 | |
|
897 | 0 | if (pole_step <= 0) |
898 | 0 | return_error(gs_error_limitcheck); /* Too small buffer. */ |
899 | 0 | ei = (T0[ii] == T1[ii] ? 1 : order + 1); |
900 | 0 | sa = pfn->params.array_step[ii]; |
901 | 0 | if (ii == 0) { |
902 | 0 | for (i = 0; i < ei; i++) |
903 | 0 | *(pole + p_offset + i * pole_step) = |
904 | 0 | *(pfn->params.pole + a_offset + I[ii] * sa + i * (sa / order)); |
905 | 0 | } else { |
906 | 0 | for (i = 0; i < ei; i++) { |
907 | 0 | code = copy_poles(pfn, I, T0, T1, a_offset + I[ii] * sa + i * (sa / order), ii - 1, |
908 | 0 | pole, p_offset + i * pole_step, pole_step / 4); |
909 | 0 | if (code < 0) |
910 | 0 | return code; |
911 | 0 | } |
912 | 0 | } |
913 | 0 | return 0; |
914 | 0 | } |
915 | | |
916 | | static inline void |
917 | | subcurve(double *pole, int pole_step, double t0, double t1) |
918 | 0 | { |
919 | | /* Generated with subcurve.nb using Mathematica 3.0. */ |
920 | 0 | double q0 = pole[pole_step * 0]; |
921 | 0 | double q1 = pole[pole_step * 1]; |
922 | 0 | double q2 = pole[pole_step * 2]; |
923 | 0 | double q3 = pole[pole_step * 3]; |
924 | 0 | double t01 = t0 - 1, t11 = t1 - 1; |
925 | 0 | double small = 1e-13; |
926 | |
|
927 | 0 | #define Power2(a) (a) * (a) |
928 | 0 | #define Power3(a) (a) * (a) * (a) |
929 | 0 | pole[pole_step * 0] = t0*(t0*(q3*t0 - 3*q2*t01) + 3*q1*Power2(t01)) - q0*Power3(t01); |
930 | 0 | pole[pole_step * 1] = q1*t01*(-2*t0 - t1 + 3*t0*t1) + t0*(q2*t0 + 2*q2*t1 - |
931 | 0 | 3*q2*t0*t1 + q3*t0*t1) - q0*t11*Power2(t01); |
932 | 0 | pole[pole_step * 2] = t1*(2*q2*t0 + q2*t1 - 3*q2*t0*t1 + q3*t0*t1) + |
933 | 0 | q1*(-t0 - 2*t1 + 3*t0*t1)*t11 - q0*t01*Power2(t11); |
934 | 0 | pole[pole_step * 3] = t1*(t1*(3*q2 - 3*q2*t1 + q3*t1) + |
935 | 0 | 3*q1*Power2(t11)) - q0*Power3(t11); |
936 | 0 | #undef Power2 |
937 | 0 | #undef Power3 |
938 | 0 | if (any_abs(pole[pole_step * 1] - pole[pole_step * 0]) < small) |
939 | 0 | pole[pole_step * 1] = pole[pole_step * 0]; |
940 | 0 | if (any_abs(pole[pole_step * 2] - pole[pole_step * 3]) < small) |
941 | 0 | pole[pole_step * 2] = pole[pole_step * 3]; |
942 | 0 | } |
943 | | |
944 | | static inline void |
945 | | subline(double *pole, int pole_step, double t0, double t1) |
946 | 0 | { |
947 | 0 | double q0 = pole[pole_step * 0]; |
948 | 0 | double q1 = pole[pole_step * 1]; |
949 | |
|
950 | 0 | pole[pole_step * 0] = (1 - t0) * q0 + t0 * q1; |
951 | 0 | pole[pole_step * 1] = (1 - t1) * q0 + t1 * q1; |
952 | 0 | } |
953 | | |
954 | | static void |
955 | | clamp_poles(double *T0, double *T1, int ii, int i, double * pole, |
956 | | int p_offset, int pole_step, int pole_step_i, int order) |
957 | 0 | { |
958 | 0 | if (ii < 0) { |
959 | 0 | if (order == 3) |
960 | 0 | subcurve(pole + p_offset, pole_step_i, T0[i], T1[i]); |
961 | 0 | else |
962 | 0 | subline(pole + p_offset, pole_step_i, T0[i], T1[i]); |
963 | 0 | } else if (i == ii) { |
964 | 0 | clamp_poles(T0, T1, ii - 1, i, pole, p_offset, pole_step / 4, pole_step, order); |
965 | 0 | } else { |
966 | 0 | int j, ei = (T0[ii] == T1[ii] ? 1 : order + 1); |
967 | |
|
968 | 0 | for (j = 0; j < ei; j++) |
969 | 0 | clamp_poles(T0, T1, ii - 1, i, pole, p_offset + j * pole_step, |
970 | 0 | pole_step / 4, pole_step_i, order); |
971 | 0 | } |
972 | 0 | } |
973 | | |
974 | | static inline int /* 3 - don't know, 2 - decreesing, 0 - constant, 1 - increasing. */ |
975 | | curve_monotonity(double *pole, int pole_step) |
976 | 0 | { |
977 | 0 | double p0 = pole[pole_step * 0]; |
978 | 0 | double p1 = pole[pole_step * 1]; |
979 | 0 | double p2 = pole[pole_step * 2]; |
980 | 0 | double p3 = pole[pole_step * 3]; |
981 | |
|
982 | 0 | if (p0 == p1 && any_abs(p1 - p2) < 1e-13 && p2 == p3) |
983 | 0 | return 0; |
984 | 0 | if (p0 <= p1 && p1 <= p2 && p2 <= p3) |
985 | 0 | return 1; |
986 | 0 | if (p0 >= p1 && p1 >= p2 && p2 >= p3) |
987 | 0 | return 2; |
988 | | /* Maybe not monotonic. |
989 | | Don't want to solve quadratic equations, so return "don't know". |
990 | | This case should be rare. |
991 | | */ |
992 | 0 | return 3; |
993 | 0 | } |
994 | | |
995 | | static inline int /* 2 - decreesing, 0 - constant, 1 - increasing. */ |
996 | | line_monotonity(double *pole, int pole_step) |
997 | 0 | { |
998 | 0 | double p0 = pole[pole_step * 0]; |
999 | 0 | double p1 = pole[pole_step * 1]; |
1000 | |
|
1001 | 0 | if (p1 - p0 > 1e-13) |
1002 | 0 | return 1; |
1003 | 0 | if (p0 - p1 > 1e-13) |
1004 | 0 | return 2; |
1005 | 0 | return 0; |
1006 | 0 | } |
1007 | | |
1008 | | static int /* 3 bits per guide : 3 - non-monotonic or don't know, |
1009 | | 2 - decreesing, 0 - constant, 1 - increasing. |
1010 | | The number of guides is order+1. */ |
1011 | | tensor_dimension_monotonity(const double *T0, const double *T1, int ii, int i0, double *pole, |
1012 | | int p_offset, int pole_step, int pole_step_i, int order) |
1013 | 0 | { |
1014 | 0 | if (ii < 0) { |
1015 | 0 | if (order == 3) |
1016 | 0 | return curve_monotonity(pole + p_offset, pole_step_i); |
1017 | 0 | else |
1018 | 0 | return line_monotonity(pole + p_offset, pole_step_i); |
1019 | 0 | } else if (i0 == ii) { |
1020 | | /* Delay the dimension till the end, and adjust pole_step. */ |
1021 | 0 | return tensor_dimension_monotonity(T0, T1, ii - 1, i0, pole, p_offset, |
1022 | 0 | pole_step / 4, pole_step, order); |
1023 | 0 | } else { |
1024 | 0 | int j, ei = (T0[ii] == T1[ii] ? 1 : order + 1), m = 0, mm; |
1025 | |
|
1026 | 0 | for (j = 0; j < ei; j++) { |
1027 | 0 | mm = tensor_dimension_monotonity(T0, T1, ii - 1, i0, pole, p_offset + j * pole_step, |
1028 | 0 | pole_step/ 4, pole_step_i, order); |
1029 | 0 | m |= mm << (j * 3); |
1030 | 0 | if (mm == 3) { |
1031 | | /* If one guide is not monotonic, the dimension is not monotonic. |
1032 | | Can return early. */ |
1033 | 0 | break; |
1034 | 0 | } |
1035 | 0 | } |
1036 | 0 | return m; |
1037 | 0 | } |
1038 | 0 | } |
1039 | | |
1040 | | static inline int |
1041 | | is_tensor_monotonic_by_dimension(const gs_function_Sd_t *pfn, int *I, double *T0, double *T1, int i0, int k, |
1042 | | uint *mask /* 3 bits per guide : 3 - non-monotonic or don't know, |
1043 | | 2 - decreesing, 0 - constant, 1 - increasing. |
1044 | | The number of guides is order+1. */) |
1045 | 0 | { |
1046 | 0 | double pole[4*4*4]; /* For a while restricting with 3-in cubic functions. |
1047 | | More arguments need a bigger buffer, but the rest of code is same. */ |
1048 | 0 | int i, code, ii = pfn->params.m - 1; |
1049 | 0 | double TT0[3], TT1[3]; |
1050 | |
|
1051 | 0 | *mask = 0; |
1052 | 0 | if (ii >= 3) { |
1053 | | /* Unimplemented. We don't know practical cases, |
1054 | | because currently it is only called while decomposing a shading. */ |
1055 | 0 | return_error(gs_error_limitcheck); |
1056 | 0 | } |
1057 | 0 | code = copy_poles(pfn, I, T0, T1, k, ii, pole, 0, count_of(pole) / 4); |
1058 | 0 | if (code < 0) |
1059 | 0 | return code; |
1060 | 0 | for (i = ii; i >= 0; i--) { |
1061 | 0 | TT0[i] = 0; |
1062 | 0 | if (T0[i] != T1[i]) { |
1063 | 0 | if (T0[i] != 0 || T1[i] != 1) |
1064 | 0 | clamp_poles(T0, T1, ii, i, pole, 0, count_of(pole) / 4, -1, pfn->params.Order); |
1065 | 0 | TT1[i] = 1; |
1066 | 0 | } else |
1067 | 0 | TT1[i] = 0; |
1068 | 0 | } |
1069 | 0 | *mask = tensor_dimension_monotonity(TT0, TT1, ii, i0, pole, 0, |
1070 | 0 | count_of(pole) / 4, 1, pfn->params.Order); |
1071 | 0 | return 0; |
1072 | 0 | } |
1073 | | |
1074 | | static int /* error code */ |
1075 | | is_lattice_monotonic_by_dimension(const gs_function_Sd_t *pfn, const double *T0, const double *T1, |
1076 | | int *I, double *S0, double *S1, int ii, int i0, int k, |
1077 | | uint *mask /* 3 bits per guide : 1 - non-monotonic or don't know, 0 - monotonic; |
1078 | | The number of guides is order+1. */) |
1079 | 0 | { |
1080 | 0 | if (ii == -1) { |
1081 | | /* fixme : could cache the cell monotonity against redundant evaluation. */ |
1082 | 0 | return is_tensor_monotonic_by_dimension(pfn, I, S0, S1, i0, k, mask); |
1083 | 0 | } else { |
1084 | 0 | int i1 = (ii > i0 ? ii : ii == 0 ? i0 : ii - 1); /* Delay the dimension i0 till the end of recursion. */ |
1085 | 0 | int j, code; |
1086 | 0 | int bi = (int)floor(T0[i1]); |
1087 | 0 | int ei = (int)floor(T1[i1]); |
1088 | 0 | uint m, mm, m1 = 0x49249249 & ((1 << ((pfn->params.Order + 1) * 3)) - 1); |
1089 | |
|
1090 | 0 | if (floor(T1[i1]) == T1[i1]) |
1091 | 0 | ei --; |
1092 | 0 | m = 0; |
1093 | 0 | for (j = bi; j <= ei; j++) { |
1094 | | /* fixme : A better performance may be obtained with comparing central nodes with side ones. */ |
1095 | 0 | I[i1] = j; |
1096 | 0 | S0[i1] = max(T0[i1] - j, 0); |
1097 | 0 | S1[i1] = min(T1[i1] - j, 1); |
1098 | 0 | code = is_lattice_monotonic_by_dimension(pfn, T0, T1, I, S0, S1, ii - 1, i0, k, &mm); |
1099 | 0 | if (code < 0) |
1100 | 0 | return code; |
1101 | 0 | m |= mm; |
1102 | 0 | if (m == m1) /* Don't return early - shadings need to know about all dimensions. */ |
1103 | 0 | break; |
1104 | 0 | } |
1105 | 0 | if (ii == 0) { |
1106 | | /* Detect non-monotonic guides. */ |
1107 | 0 | m = m & (m >> 1); |
1108 | 0 | } |
1109 | 0 | *mask = m; |
1110 | 0 | return 0; |
1111 | 0 | } |
1112 | 0 | } |
1113 | | |
1114 | | static inline int /* error code */ |
1115 | | is_lattice_monotonic(const gs_function_Sd_t *pfn, const double *T0, const double *T1, |
1116 | | int *I, double *S0, double *S1, |
1117 | | int k, uint *mask /* 1 bit per dimension : 1 - non-monotonic or don't know, |
1118 | | 0 - monotonic. */) |
1119 | 0 | { |
1120 | 0 | uint m, mm = 0; |
1121 | 0 | int i, code; |
1122 | |
|
1123 | 0 | for (i = 0; i < pfn->params.m; i++) { |
1124 | 0 | if (T0[i] != T1[i]) { |
1125 | 0 | code = is_lattice_monotonic_by_dimension(pfn, T0, T1, I, S0, S1, pfn->params.m - 1, i, k, &m); |
1126 | 0 | if (code < 0) |
1127 | 0 | return code; |
1128 | 0 | if (m) |
1129 | 0 | mm |= 1 << i; |
1130 | 0 | } |
1131 | 0 | } |
1132 | 0 | *mask = mm; |
1133 | 0 | return 0; |
1134 | 0 | } |
1135 | | |
1136 | | static int /* 3 bits per result : 3 - non-monotonic or don't know, |
1137 | | 2 - decreesing, 0 - constant, 1 - increasing, |
1138 | | <0 - error. */ |
1139 | | fn_Sd_1arg_linear_monotonic_rec(const gs_function_Sd_t *const pfn, int i0, int i1, |
1140 | | const double *V0, const double *V1) |
1141 | 92.8M | { |
1142 | 92.8M | if (i1 - i0 <= 1) { |
1143 | 46.4M | int code = 0, i; |
1144 | | |
1145 | 104M | for (i = 0; i < pfn->params.n; i++) { |
1146 | 58.5M | if (V0[i] < V1[i]) |
1147 | 4.31M | code |= 1 << (i * 3); |
1148 | 54.1M | else if (V0[i] > V1[i]) |
1149 | 3.14M | code |= 2 << (i * 3); |
1150 | 58.5M | } |
1151 | 46.4M | return code; |
1152 | 46.4M | } else { |
1153 | 46.3M | double VV[MAX_FAST_COMPS]; |
1154 | 46.3M | int ii = (i0 + i1) / 2, code, cod1; |
1155 | | |
1156 | 46.3M | code = load_vector_to(pfn, ii * pfn->params.n * pfn->params.BitsPerSample, VV); |
1157 | 46.3M | if (code < 0) |
1158 | 0 | return code; |
1159 | 46.3M | if (code & (code >> 1)) |
1160 | 0 | return code; /* Not monotonic by some component of the result. */ |
1161 | 46.3M | code = fn_Sd_1arg_linear_monotonic_rec(pfn, i0, ii, V0, VV); |
1162 | 46.3M | if (code < 0) |
1163 | 0 | return code; |
1164 | 46.3M | cod1 = fn_Sd_1arg_linear_monotonic_rec(pfn, ii, i1, VV, V1); |
1165 | 46.3M | if (cod1 < 0) |
1166 | 0 | return cod1; |
1167 | 46.3M | return code | cod1; |
1168 | 46.3M | } |
1169 | 92.8M | } |
1170 | | |
1171 | | static int |
1172 | | fn_Sd_1arg_linear_monotonic(const gs_function_Sd_t *const pfn, double T0, double T1, |
1173 | | uint *mask /* 1 - non-monotonic or don't know, 0 - monotonic. */) |
1174 | 73.4k | { |
1175 | 73.4k | int i0 = (int)floor(T0); |
1176 | 73.4k | int i1 = (int)ceil(T1), code; |
1177 | 73.4k | double V0[MAX_FAST_COMPS], V1[MAX_FAST_COMPS]; |
1178 | | |
1179 | 73.4k | if (i1 - i0 > 1) { |
1180 | 40.6k | code = load_vector_to(pfn, i0 * pfn->params.n * pfn->params.BitsPerSample, V0); |
1181 | 40.6k | if (code < 0) |
1182 | 0 | return code; |
1183 | 40.6k | code = load_vector_to(pfn, i1 * pfn->params.n * pfn->params.BitsPerSample, V1); |
1184 | 40.6k | if (code < 0) |
1185 | 0 | return code; |
1186 | 40.6k | code = fn_Sd_1arg_linear_monotonic_rec(pfn, i0, i1, V0, V1); |
1187 | 40.6k | if (code < 0) |
1188 | 0 | return code; |
1189 | 40.6k | if (code & (code >> 1)) { |
1190 | 18.5k | *mask = 1; |
1191 | 18.5k | return 0; |
1192 | 18.5k | } |
1193 | 40.6k | } |
1194 | 54.8k | *mask = 0; |
1195 | 54.8k | return 1; |
1196 | 73.4k | } |
1197 | | |
1198 | 0 | #define DEBUG_Sd_1arg 0 |
1199 | | |
1200 | | /* Test whether a Sampled function is monotonic. */ |
1201 | | static int /* 1 = monotonic, 0 = not or don't know, <0 = error. */ |
1202 | | fn_Sd_is_monotonic_aux(const gs_function_Sd_t *const pfn, |
1203 | | const float *lower, const float *upper, |
1204 | | uint *mask /* 1 bit per dimension : 1 - non-monotonic or don't know, |
1205 | | 0 - monotonic. */) |
1206 | 73.4k | { |
1207 | 73.4k | int i, code, ii = pfn->params.m - 1; |
1208 | 73.4k | int I[4]; |
1209 | 73.4k | double T0[count_of(I)], T1[count_of(I)]; |
1210 | 73.4k | double S0[count_of(I)], S1[count_of(I)]; |
1211 | 73.4k | uint m, mm, m1; |
1212 | | # if DEBUG_Sd_1arg |
1213 | | int code1, mask1; |
1214 | | # endif |
1215 | | |
1216 | 73.4k | if (ii >= count_of(T0)) { |
1217 | | /* Unimplemented. We don't know practical cases, |
1218 | | because currently it is only called while decomposing a shading. */ |
1219 | 0 | return_error(gs_error_limitcheck); |
1220 | 0 | } |
1221 | 146k | for (i = 0; i <= ii; i++) { |
1222 | 73.4k | float w0, w1; |
1223 | | |
1224 | 73.4k | code = get_scaled_range(pfn, lower, upper, i, &w0, &w1); |
1225 | 73.4k | if (code < 0) |
1226 | 13 | return code; |
1227 | 73.4k | T0[i] = w0; |
1228 | 73.4k | T1[i] = w1; |
1229 | 73.4k | } |
1230 | 73.4k | if (pfn->params.m == 1 && pfn->params.Order == 1 && pfn->params.n <= MAX_FAST_COMPS) { |
1231 | 73.4k | code = fn_Sd_1arg_linear_monotonic(pfn, T0[0], T1[0], mask); |
1232 | 73.4k | # if !DEBUG_Sd_1arg |
1233 | 73.4k | return code; |
1234 | | # else |
1235 | | mask1 = *mask; |
1236 | | code1 = code; |
1237 | | # endif |
1238 | 73.4k | } |
1239 | 0 | m1 = (1 << pfn->params.m )- 1; |
1240 | 0 | code = make_interpolation_nodes(pfn, T0, T1, I, S0, 0, 0, ii); |
1241 | 0 | if (code < 0) |
1242 | 0 | return code; |
1243 | 0 | mm = 0; |
1244 | 0 | for (i = 0; i < pfn->params.n; i++) { |
1245 | 0 | code = is_lattice_monotonic(pfn, T0, T1, I, S0, S1, i, &m); |
1246 | 0 | if (code < 0) |
1247 | 0 | return code; |
1248 | 0 | mm |= m; |
1249 | 0 | if (mm == m1) /* Don't return early - shadings need to know about all dimensions. */ |
1250 | 0 | break; |
1251 | 0 | } |
1252 | | # if DEBUG_Sd_1arg |
1253 | | if (mask1 != mm) |
1254 | | return_error(gs_error_unregistered); |
1255 | | if (code1 != !mm) |
1256 | | return_error(gs_error_unregistered); |
1257 | | # endif |
1258 | 0 | *mask = mm; |
1259 | 0 | return !mm; |
1260 | 0 | } |
1261 | | |
1262 | | /* Test whether a Sampled function is monotonic. */ |
1263 | | /* 1 = monotonic, 0 = don't know, <0 = error. */ |
1264 | | static int |
1265 | | fn_Sd_is_monotonic(const gs_function_t * pfn_common, |
1266 | | const float *lower, const float *upper, uint *mask) |
1267 | 73.4k | { |
1268 | 73.4k | const gs_function_Sd_t *const pfn = |
1269 | 73.4k | (const gs_function_Sd_t *)pfn_common; |
1270 | | |
1271 | 73.4k | return fn_Sd_is_monotonic_aux(pfn, lower, upper, mask); |
1272 | 73.4k | } |
1273 | | |
1274 | | /* Return Sampled function information. */ |
1275 | | static void |
1276 | | fn_Sd_get_info(const gs_function_t *pfn_common, gs_function_info_t *pfi) |
1277 | 48.4k | { |
1278 | 48.4k | const gs_function_Sd_t *const pfn = |
1279 | 48.4k | (const gs_function_Sd_t *)pfn_common; |
1280 | 48.4k | long size; |
1281 | 48.4k | int i; |
1282 | | |
1283 | 48.4k | gs_function_get_info_default(pfn_common, pfi); |
1284 | 48.4k | pfi->DataSource = &pfn->params.DataSource; |
1285 | 98.0k | for (i = 0, size = 1; i < pfn->params.m; ++i) |
1286 | 49.6k | size *= pfn->params.Size[i]; |
1287 | 48.4k | pfi->data_size = |
1288 | 48.4k | (size * pfn->params.n * pfn->params.BitsPerSample + 7) >> 3; |
1289 | 48.4k | } |
1290 | | |
1291 | | /* Write Sampled function parameters on a parameter list. */ |
1292 | | static int |
1293 | | fn_Sd_get_params(const gs_function_t *pfn_common, gs_param_list *plist) |
1294 | 17.4k | { |
1295 | 17.4k | const gs_function_Sd_t *const pfn = |
1296 | 17.4k | (const gs_function_Sd_t *)pfn_common; |
1297 | 17.4k | int ecode = fn_common_get_params(pfn_common, plist); |
1298 | 17.4k | int code; |
1299 | | |
1300 | 17.4k | if (pfn->params.Order != 1) { |
1301 | 40 | if ((code = param_write_int(plist, "Order", &pfn->params.Order)) < 0) |
1302 | 0 | ecode = code; |
1303 | 40 | } |
1304 | 17.4k | if ((code = param_write_int(plist, "BitsPerSample", |
1305 | 17.4k | &pfn->params.BitsPerSample)) < 0) |
1306 | 0 | ecode = code; |
1307 | 17.4k | if (pfn->params.Encode) { |
1308 | 760 | if ((code = param_write_float_values(plist, "Encode", |
1309 | 760 | pfn->params.Encode, |
1310 | 760 | 2 * pfn->params.m, false)) < 0) |
1311 | 0 | ecode = code; |
1312 | 760 | } |
1313 | 17.4k | if (pfn->params.Decode) { |
1314 | 4.48k | if ((code = param_write_float_values(plist, "Decode", |
1315 | 4.48k | pfn->params.Decode, |
1316 | 4.48k | 2 * pfn->params.n, false)) < 0) |
1317 | 0 | ecode = code; |
1318 | 4.48k | } |
1319 | 17.4k | if (pfn->params.Size) { |
1320 | 17.4k | if ((code = param_write_int_values(plist, "Size", pfn->params.Size, |
1321 | 17.4k | pfn->params.m, false)) < 0) |
1322 | 0 | ecode = code; |
1323 | 17.4k | } |
1324 | 17.4k | return ecode; |
1325 | 17.4k | } |
1326 | | |
1327 | | /* Make a scaled copy of a Sampled function. */ |
1328 | | static int |
1329 | | fn_Sd_make_scaled(const gs_function_Sd_t *pfn, gs_function_Sd_t **ppsfn, |
1330 | | const gs_range_t *pranges, gs_memory_t *mem) |
1331 | 0 | { |
1332 | 0 | gs_function_Sd_t *psfn = |
1333 | 0 | gs_alloc_struct(mem, gs_function_Sd_t, &st_function_Sd, |
1334 | 0 | "fn_Sd_make_scaled"); |
1335 | 0 | int code; |
1336 | |
|
1337 | 0 | if (psfn == 0) |
1338 | 0 | return_error(gs_error_VMerror); |
1339 | 0 | psfn->params = pfn->params; |
1340 | 0 | psfn->params.Encode = 0; /* in case of failure */ |
1341 | 0 | psfn->params.Decode = 0; |
1342 | 0 | psfn->params.Size = |
1343 | 0 | fn_copy_values(pfn->params.Size, pfn->params.m, sizeof(int), mem); |
1344 | 0 | if ((code = (psfn->params.Size == 0 ? |
1345 | 0 | gs_note_error(gs_error_VMerror) : 0)) < 0 || |
1346 | 0 | (code = fn_common_scale((gs_function_t *)psfn, |
1347 | 0 | (const gs_function_t *)pfn, |
1348 | 0 | pranges, mem)) < 0 || |
1349 | 0 | (code = fn_scale_pairs(&psfn->params.Encode, pfn->params.Encode, |
1350 | 0 | pfn->params.m, NULL, mem)) < 0 || |
1351 | 0 | (code = fn_scale_pairs(&psfn->params.Decode, pfn->params.Decode, |
1352 | 0 | pfn->params.n, pranges, mem)) < 0) { |
1353 | 0 | gs_function_free((gs_function_t *)psfn, true, mem); |
1354 | 0 | } else |
1355 | 0 | *ppsfn = psfn; |
1356 | 0 | return code; |
1357 | 0 | } |
1358 | | |
1359 | | /* Free the parameters of a Sampled function. */ |
1360 | | void |
1361 | | gs_function_Sd_free_params(gs_function_Sd_params_t * params, gs_memory_t * mem) |
1362 | 47.4k | { |
1363 | 47.4k | gs_free_const_object(mem, params->Size, "Size"); |
1364 | 47.4k | params->Size = NULL; |
1365 | 47.4k | gs_free_const_object(mem, params->Decode, "Decode"); |
1366 | 47.4k | params->Decode = NULL; |
1367 | 47.4k | gs_free_const_object(mem, params->Encode, "Encode"); |
1368 | 47.4k | params->Encode = NULL; |
1369 | 47.4k | fn_common_free_params((gs_function_params_t *) params, mem); |
1370 | 47.4k | if (params->DataSource.type == data_source_type_stream && params->DataSource.data.strm != NULL) { |
1371 | 44.0k | s_close_filters(¶ms->DataSource.data.strm, params->DataSource.data.strm->strm); |
1372 | 44.0k | params->DataSource.data.strm = NULL; |
1373 | 44.0k | } |
1374 | 47.4k | gs_free_object(mem, params->pole, "gs_function_Sd_free_params"); |
1375 | 47.4k | params->pole = NULL; |
1376 | 47.4k | gs_free_object(mem, params->array_step, "gs_function_Sd_free_params"); |
1377 | 47.4k | params->array_step = NULL; |
1378 | 47.4k | gs_free_object(mem, params->stream_step, "gs_function_Sd_free_params"); |
1379 | 47.4k | params->stream_step = NULL; |
1380 | 47.4k | } |
1381 | | |
1382 | | /* aA helper for gs_function_Sd_serialize. */ |
1383 | | static int serialize_array(const float *a, int half_size, stream *s) |
1384 | 62.1k | { |
1385 | 62.1k | uint n; |
1386 | 62.1k | const float dummy[2] = {0, 0}; |
1387 | 62.1k | int i, code; |
1388 | | |
1389 | 62.1k | if (a != NULL) |
1390 | 33.8k | return sputs(s, (const byte *)a, sizeof(a[0]) * half_size * 2, &n); |
1391 | 99.2k | for (i = 0; i < half_size; i++) { |
1392 | 70.9k | code = sputs(s, (const byte *)dummy, sizeof(dummy), &n); |
1393 | 70.9k | if (code < 0) |
1394 | 0 | return code; |
1395 | 70.9k | } |
1396 | 28.3k | return 0; |
1397 | 28.3k | } |
1398 | | |
1399 | | /* Serialize. */ |
1400 | | static int |
1401 | | gs_function_Sd_serialize(const gs_function_t * pfn, stream *s) |
1402 | 31.0k | { |
1403 | 31.0k | uint n; |
1404 | 31.0k | const gs_function_Sd_params_t * p = (const gs_function_Sd_params_t *)&pfn->params; |
1405 | 31.0k | gs_function_info_t info; |
1406 | 31.0k | int code = fn_common_serialize(pfn, s); |
1407 | 31.0k | ulong pos; |
1408 | 31.0k | uint count; |
1409 | 31.0k | byte buf[100]; |
1410 | 31.0k | const byte *ptr; |
1411 | | |
1412 | 31.0k | if (code < 0) |
1413 | 0 | return code; |
1414 | 31.0k | code = sputs(s, (const byte *)&p->Order, sizeof(p->Order), &n); |
1415 | 31.0k | if (code < 0) |
1416 | 0 | return code; |
1417 | 31.0k | code = sputs(s, (const byte *)&p->BitsPerSample, sizeof(p->BitsPerSample), &n); |
1418 | 31.0k | if (code < 0) |
1419 | 0 | return code; |
1420 | 31.0k | code = serialize_array(p->Encode, p->m, s); |
1421 | 31.0k | if (code < 0) |
1422 | 0 | return code; |
1423 | 31.0k | code = serialize_array(p->Decode, p->n, s); |
1424 | 31.0k | if (code < 0) |
1425 | 0 | return code; |
1426 | 31.0k | gs_function_get_info(pfn, &info); |
1427 | 31.0k | code = sputs(s, (const byte *)&info.data_size, sizeof(info.data_size), &n); |
1428 | 31.0k | if (code < 0) |
1429 | 0 | return code; |
1430 | 343k | for (pos = 0; pos < info.data_size; pos += count) { |
1431 | 312k | count = min(sizeof(buf), info.data_size - pos); |
1432 | 312k | data_source_access_only(info.DataSource, pos, count, buf, &ptr); |
1433 | 312k | code = sputs(s, ptr, count, &n); |
1434 | 312k | if (code < 0) |
1435 | 0 | return code; |
1436 | 312k | } |
1437 | 31.0k | return 0; |
1438 | 31.0k | } |
1439 | | |
1440 | | /* Allocate and initialize a Sampled function. */ |
1441 | | int |
1442 | | gs_function_Sd_init(gs_function_t ** ppfn, |
1443 | | const gs_function_Sd_params_t * params, gs_memory_t * mem) |
1444 | 53.1k | { |
1445 | 53.1k | static const gs_function_head_t function_Sd_head = { |
1446 | 53.1k | function_type_Sampled, |
1447 | 53.1k | { |
1448 | 53.1k | (fn_evaluate_proc_t) fn_Sd_evaluate, |
1449 | 53.1k | (fn_is_monotonic_proc_t) fn_Sd_is_monotonic, |
1450 | 53.1k | (fn_get_info_proc_t) fn_Sd_get_info, |
1451 | 53.1k | (fn_get_params_proc_t) fn_Sd_get_params, |
1452 | 53.1k | (fn_make_scaled_proc_t) fn_Sd_make_scaled, |
1453 | 53.1k | (fn_free_params_proc_t) gs_function_Sd_free_params, |
1454 | 53.1k | fn_common_free, |
1455 | 53.1k | (fn_serialize_proc_t) gs_function_Sd_serialize, |
1456 | 53.1k | } |
1457 | 53.1k | }; |
1458 | 53.1k | int code; |
1459 | 53.1k | int i; |
1460 | | |
1461 | 53.1k | *ppfn = 0; /* in case of error */ |
1462 | 53.1k | code = fn_check_mnDR((const gs_function_params_t *)params, |
1463 | 53.1k | params->m, params->n); |
1464 | 53.1k | if (code < 0) |
1465 | 21 | return code; |
1466 | 53.1k | if (params->m > max_Sd_m) |
1467 | 0 | return_error(gs_error_limitcheck); |
1468 | 53.1k | switch (params->Order) { |
1469 | 875 | case 0: /* use default */ |
1470 | 52.7k | case 1: |
1471 | 53.1k | case 3: |
1472 | 53.1k | break; |
1473 | 0 | default: |
1474 | 0 | return_error(gs_error_rangecheck); |
1475 | 53.1k | } |
1476 | 53.1k | switch (params->BitsPerSample) { |
1477 | 0 | case 1: |
1478 | 0 | case 2: |
1479 | 0 | case 4: |
1480 | 51.4k | case 8: |
1481 | 51.4k | case 12: |
1482 | 52.8k | case 16: |
1483 | 52.8k | case 24: |
1484 | 52.8k | case 32: |
1485 | 52.8k | break; |
1486 | 270 | default: |
1487 | 270 | return_error(gs_error_rangecheck); |
1488 | 53.1k | } |
1489 | 107k | for (i = 0; i < params->m; ++i) |
1490 | 54.2k | if (params->Size[i] <= 0) |
1491 | 0 | return_error(gs_error_rangecheck); |
1492 | 52.8k | { |
1493 | 52.8k | gs_function_Sd_t *pfn = |
1494 | 52.8k | gs_alloc_struct(mem, gs_function_Sd_t, &st_function_Sd, |
1495 | 52.8k | "gs_function_Sd_init"); |
1496 | 52.8k | int bps, sa, ss, i, order, was; |
1497 | | |
1498 | 52.8k | if (pfn == 0) |
1499 | 0 | return_error(gs_error_VMerror); |
1500 | 52.8k | pfn->params = *params; |
1501 | 52.8k | if (params->Order == 0) |
1502 | 875 | pfn->params.Order = 1; /* default */ |
1503 | 52.8k | pfn->params.pole = NULL; |
1504 | 52.8k | pfn->params.array_step = NULL; |
1505 | 52.8k | pfn->params.stream_step = NULL; |
1506 | 52.8k | pfn->head = function_Sd_head; |
1507 | 52.8k | pfn->params.array_size = 0; |
1508 | 52.8k | if (pfn->params.m == 1 && pfn->params.Order == 1 && pfn->params.n <= MAX_FAST_COMPS && !DEBUG_Sd_1arg) { |
1509 | | /* Won't use pole cache. Call fn_Sd_1arg_linear_monotonic instead. */ |
1510 | 51.3k | } else { |
1511 | 1.54k | pfn->params.array_step = (int *)gs_alloc_byte_array(mem, |
1512 | 1.54k | max_Sd_m, sizeof(int), "gs_function_Sd_init"); |
1513 | 1.54k | pfn->params.stream_step = (int *)gs_alloc_byte_array(mem, |
1514 | 1.54k | max_Sd_m, sizeof(int), "gs_function_Sd_init"); |
1515 | 1.54k | if (pfn->params.array_step == NULL || pfn->params.stream_step == NULL) |
1516 | 0 | return_error(gs_error_VMerror); |
1517 | 1.54k | bps = pfn->params.BitsPerSample; |
1518 | 1.54k | sa = pfn->params.n; |
1519 | 1.54k | ss = pfn->params.n * bps; |
1520 | 1.54k | order = pfn->params.Order; |
1521 | 4.46k | for (i = 0; i < pfn->params.m; i++) { |
1522 | 2.92k | pfn->params.array_step[i] = sa * order; |
1523 | 2.92k | was = sa; |
1524 | 2.92k | sa = (pfn->params.Size[i] * order - (order - 1)) * sa; |
1525 | | /* If the calculation of sa went backwards then we overflowed! */ |
1526 | 2.92k | if (was > sa) |
1527 | 0 | return_error(gs_error_VMerror); |
1528 | 2.92k | pfn->params.stream_step[i] = ss; |
1529 | 2.92k | ss = pfn->params.Size[i] * ss; |
1530 | 2.92k | } |
1531 | 1.54k | pfn->params.pole = (double *)gs_alloc_byte_array(mem, |
1532 | 1.54k | sa, sizeof(double), "gs_function_Sd_init"); |
1533 | 1.54k | if (pfn->params.pole == NULL) |
1534 | 0 | return_error(gs_error_VMerror); |
1535 | 4.22M | for (i = 0; i < sa; i++) |
1536 | 4.22M | pfn->params.pole[i] = double_stub; |
1537 | 1.54k | pfn->params.array_size = sa; |
1538 | 1.54k | } |
1539 | 52.8k | *ppfn = (gs_function_t *) pfn; |
1540 | 52.8k | } |
1541 | 0 | return 0; |
1542 | 52.8k | } |