summaryrefslogtreecommitdiff
path: root/gs/src/gsfunc0.c
diff options
context:
space:
mode:
Diffstat (limited to 'gs/src/gsfunc0.c')
-rw-r--r--gs/src/gsfunc0.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/gs/src/gsfunc0.c b/gs/src/gsfunc0.c
new file mode 100644
index 000000000..270d9002b
--- /dev/null
+++ b/gs/src/gsfunc0.c
@@ -0,0 +1,246 @@
+/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gsfunc0.c */
+/* Implementation of FunctionType 0 (Sampled) Functions */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsfunc0.h"
+#include "gxfunc.h"
+
+typedef struct gs_function_Sd_s {
+ gs_function_head_t head;
+ gs_function_Sd_params_t params;
+} gs_function_Sd_t;
+private_st_function_Sd();
+
+/* Define the maximum plausible number of inputs and outputs */
+/* for a Sampled function. */
+#define max_Sd_m 16
+#define max_Sd_n 16
+
+/* Get one set of sample values. */
+private int
+fn_get_samples(const gs_function_Sd_t *pfn, ulong offset, uint *samples)
+{ int bps = pfn->params.BitsPerSample;
+ int n = pfn->params.n;
+ byte buf[max_Sd_n * 4];
+ const byte *p;
+ int i;
+
+ data_source_access(&pfn->params.DataSource, offset >> 3,
+ (bps * n + 7) >> 3, buf, &p);
+ switch ( bps ) {
+ case 1:
+ for ( i = 0; i < n; ++i ) {
+ samples[i] = (*p >> (~offset & 7)) & 1;
+ if ( !(++offset & 7) )
+ p++;
+ }
+ break;
+ case 2:
+ for ( i = 0; i < n; ++i ) {
+ samples[i] = (*p >> (6 - (offset & 7))) & 3;
+ if ( !((offset += 2) & 7) )
+ p++;
+ }
+ break;
+ case 4:
+ for ( i = 0; i < n; offset ^= 4, ++i )
+ samples[i] = (offset & 4 ? *p++ & 0xf : *p >> 4);
+ break;
+ case 8:
+ for ( i = 0; i < n; ++i )
+ samples[i] = *p++;
+ break;
+ case 12:
+ for ( i = 0; i < n; offset ^= 4, ++i )
+ if ( offset & 4 )
+ samples[i] = ((*p & 0xf) << 8) + p[1], p += 2;
+ else
+ samples[i] = (*p << 4) + (p[1] >> 4), p++;
+ break;
+ case 16:
+ for ( i = 0; i < n; p += 2, ++i )
+ samples[i] = (*p << 8) + p[1];
+ break;
+ case 24:
+ for ( i = 0; i < n; p += 3, ++i )
+ samples[i] = (*p << 16) + (p[1] << 8) + p[2];
+ break;
+ case 32:
+ for ( i = 0; i < n; p += 4, ++i )
+ samples[i] = (*p << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
+ break;
+ }
+ return 0;
+}
+
+/* Calculate a result by multilinear interpolation. */
+private void
+fn_interpolate_linear(const gs_function_Sd_t *pfn, const float *values,
+ const ulong *factors, uint *samples, ulong offset, int i)
+{ if ( i == pfn->params.m )
+ fn_get_samples(pfn, offset, samples);
+ else {
+ float fpart = values[i] - floor(values[i]);
+
+ fn_interpolate_linear(pfn, values, factors, samples, offset, i + 1);
+ if ( fpart != 0 ) {
+ int j;
+ uint samples1[max_Sd_n];
+
+ fn_interpolate_linear(pfn, values, factors, samples1,
+ offset + factors[i], i + 1);
+ for ( j = 0; j < pfn->params.n; ++j )
+ samples[j] += (samples1[j] - samples[j]) * fpart;
+ }
+ }
+}
+
+/* Evaluate a Sampled function. */
+private int
+fn_Sd_evaluate(const gs_function_t *pfn_common, const float *in, float *out)
+{ const gs_function_Sd_t *pfn = (const gs_function_Sd_t *)pfn_common;
+ int bps = pfn->params.BitsPerSample;
+ ulong offset = 0;
+ int i;
+ float encoded[max_Sd_m];
+ ulong factors[max_Sd_m];
+ uint samples[max_Sd_n];
+
+ /* Encode the input values. */
+
+ for ( i = 0; i < pfn->params.m; ++i ) {
+ float d0 = pfn->params.Domain[2 * i],
+ d1 = pfn->params.Domain[2 * i + 1];
+ float arg = in[i], enc;
+
+ if ( arg < d0 )
+ arg = d0;
+ else if ( arg > d1 )
+ arg = d1;
+ if ( pfn->params.Encode ) {
+ float e0 = pfn->params.Encode[2 * i];
+ float e1 = pfn->params.Encode[2 * i + 1];
+
+ enc = (arg - d0) * (e1 - e0) / (d1 - d0) + e0;
+ if ( enc < 0 )
+ encoded[i] = 0;
+ else if ( enc >= pfn->params.Size[i] - 1 )
+ encoded[i] = pfn->params.Size[i] - 1;
+ else
+ encoded[i] = enc;
+ } else {
+ /* arg is guaranteed to be in bounds, ergo so is enc */
+ encoded[i] = (arg - d0) * (pfn->params.Size[i] - 1) / (d1 - d0);
+ }
+ }
+
+ /* Look up and interpolate the output values. */
+
+ { ulong factor = bps * pfn->params.n;
+
+ for ( i = 0; i < pfn->params.m; factor *= pfn->params.Size[i++] )
+ offset += (factors[i] = factor) * (int)encoded[i];
+ }
+ /****** LINEAR INTERPOLATION ONLY ******/
+ fn_interpolate_linear(pfn, encoded, factors, samples, offset, 0);
+
+ /* Encode the output values. */
+
+ for ( i = 0; i < pfn->params.n; offset += bps, ++i ) {
+ float d0, d1, r0, r1, value;
+
+ if ( pfn->params.Range )
+ r0 = pfn->params.Range[2 * i], r1 = pfn->params.Range[2 * i + 1];
+ else
+ r0 = 0, r1 = (1 << bps) - 1;
+ if ( pfn->params.Decode )
+ d0 = pfn->params.Decode[2 * i], d1 = pfn->params.Decode[2 * i + 1];
+ else
+ d0 = r0, d1 = r1;
+
+ value = samples[i] * (d1 - d0) / ((1 << bps) - 1) + d0;
+ if ( value < r0 )
+ out[i] = r0;
+ else if ( value > r1 )
+ out[i] = r1;
+ else
+ out[i] = value;
+ }
+
+ return 0;
+}
+
+/* Free the parameters of a Sampled function. */
+void
+gs_function_Sd_free_params(gs_function_Sd_params_t *params, gs_memory_t *mem)
+{ gs_free_object(mem, (void *)params->Size, "Size"); /* break const */
+ gs_free_object(mem, (void *)params->Decode, "Decode"); /* break const */
+ gs_free_object(mem, (void *)params->Encode, "Encode"); /* break const */
+ fn_common_free_params((gs_function_params_t *)params, mem);
+}
+
+/* Allocate and initialize a Sampled function. */
+int
+gs_function_Sd_init(gs_function_t **ppfn,
+ const gs_function_Sd_params_t *params, gs_memory_t *mem)
+{ static const gs_function_head_t function_Sd_head = {
+ function_type_Sampled,
+ (fn_evaluate_proc_t)fn_Sd_evaluate,
+ (fn_free_params_proc_t)gs_function_Sd_free_params,
+ fn_common_free
+ };
+ int i;
+
+ *ppfn = 0; /* in case of error */
+ fn_check_mnDR(params, params->m, params->n);
+ if ( params->m > max_Sd_m )
+ return_error(gs_error_limitcheck);
+ switch ( params->Order ) {
+ case 0: /* use default */
+ case 1: case 3:
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ switch ( params->BitsPerSample ) {
+ case 1: case 2: case 4: case 8: case 12: case 16: case 24: case 32:
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ for ( i = 0; i < params->m; ++i )
+ if ( params->Size[i] <= 0 )
+ return_error(gs_error_rangecheck);
+ { gs_function_Sd_t *pfn =
+ gs_alloc_struct(mem, gs_function_Sd_t, &st_function_Sd,
+ "gs_function_Sd_init");
+
+ if ( pfn == 0 )
+ return_error(gs_error_VMerror);
+ pfn->params = *params;
+ if ( params->Order == 0 )
+ pfn->params.Order = 1; /* default */
+ pfn->head = function_Sd_head;
+ *ppfn = (gs_function_t *)pfn;
+ }
+ return 0;
+}