1 /* Copyright (C) 1999 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: siinterp.c,v 1.7 2004/12/08 21:35:13 stefan Exp $ */
18 /* Image interpolation filter */
19 #include "memory_.h"
20 #include <assert.h>
21 #include "gxfixed.h" /* for gxdda.h */
22 #include "gxdda.h"
23 #include "gxfrac.h"
24 #include "strimpl.h"
25 #include "siinterp.h"
26
27 /* ImageInterpolateEncode state */
28 typedef struct gx_dda_int_s {
29 dda_state_struct(ia_, int, uint) state;
30 dda_step_struct(ie_, int, uint) step;
31 } gx_dda_int_t;
32 typedef enum {
33 SCALE_SAME = 0,
34 SCALE_SAME_ALIGNED,
35 SCALE_8_8,
36 SCALE_8_8_ALIGNED,
37 SCALE_8_16_BYTE2FRAC,
38 SCALE_8_16_BYTE2FRAC_ALIGNED,
39 SCALE_8_16_BYTE2FRAC_3,
40 SCALE_8_16_BYTE2FRAC_3_ALIGNED,
41 SCALE_8_16_GENERAL,
42 SCALE_8_16_GENERAL_ALIGNED,
43 SCALE_16_8,
44 SCALE_16_8_ALIGNED,
45 SCALE_16_16,
46 SCALE_16_16_ALIGNED
47 } scale_case_t;
48 typedef struct stream_IIEncode_state_s {
49 /* The client sets the params values before initialization. */
50 stream_image_scale_state_common; /* = state_common + params */
51 /* The init procedure sets the following. */
52 int sizeofPixelIn; /* bytes per input pixel, 1 or 2 * Colors */
53 int sizeofPixelOut; /* bytes per output pixel, 1 or 2 * Colors */
54 uint src_size; /* bytes per row of input */
55 uint dst_size; /* bytes per row of output */
56 void /*PixelOut */ *prev; /* previous row of input data in output fmt, */
57 /* [WidthIn * sizeofPixelOut] */
58 void /*PixelOut */ *cur; /* current row of input data in output fmt, */
59 /* [WidthIn * sizeofPixelOut] */
60 scale_case_t scale_case;
61 /* The following are updated dynamically. */
62 int dst_x;
63 gx_dda_int_t dda_x; /* DDA for dest X in current scan line */
64 gx_dda_int_t dda_x_init; /* initial setting of dda_x */
65 int src_y, dst_y;
66 gx_dda_int_t dda_y; /* DDA for dest Y */
67 int src_offset, dst_offset;
68 } stream_IIEncode_state;
69
70 gs_private_st_ptrs2(st_IIEncode_state, stream_IIEncode_state,
71 "ImageInterpolateEncode state",
72 iiencode_state_enum_ptrs, iiencode_state_reloc_ptrs,
73 prev, cur);
74
75 /* Forward references */
76 private void s_IIEncode_release(stream_state * st);
77
78 /* Initialize the filter. */
79 private int
s_IIEncode_init(stream_state * st)80 s_IIEncode_init(stream_state * st)
81 {
82 stream_IIEncode_state *const ss = (stream_IIEncode_state *) st;
83 gs_memory_t *mem = ss->memory;
84
85 ss->sizeofPixelIn =
86 ss->params.BitsPerComponentIn / 8 * ss->params.Colors;
87 ss->sizeofPixelOut =
88 ss->params.BitsPerComponentOut / 8 * ss->params.Colors;
89 ss->src_size = ss->sizeofPixelIn * ss->params.WidthIn;
90 ss->dst_size = ss->sizeofPixelOut * ss->params.WidthOut;
91
92 /* Initialize destination DDAs. */
93 ss->dst_x = 0;
94 ss->src_offset = ss->dst_offset = 0;
95 dda_init(ss->dda_x, 0, ss->params.WidthIn, ss->params.WidthOut);
96 ss->dda_x_init = ss->dda_x;
97 ss->src_y = ss->dst_y = 0;
98 dda_init(ss->dda_y, 0, ss->params.HeightOut, ss->params.HeightIn);
99
100 /* Allocate buffers for 2 rows of input data. */
101 ss->prev = gs_alloc_byte_array(mem, ss->params.WidthIn,
102 ss->sizeofPixelOut, "IIEncode prev");
103 ss->cur = gs_alloc_byte_array(mem, ss->params.WidthIn,
104 ss->sizeofPixelOut, "IIEncode cur");
105 if (ss->prev == 0 || ss->cur == 0) {
106 s_IIEncode_release(st);
107 return ERRC; /****** WRONG ******/
108 }
109
110 /* Determine the case for the inner loop. */
111 ss->scale_case =
112 (ss->params.BitsPerComponentIn == 8 ?
113 (ss->params.BitsPerComponentOut == 8 ?
114 (ss->params.MaxValueIn == ss->params.MaxValueOut ?
115 SCALE_SAME : SCALE_8_8) :
116 (ss->params.MaxValueIn == 255 && ss->params.MaxValueOut == frac_1 ?
117 (ss->params.Colors == 3 ? SCALE_8_16_BYTE2FRAC_3 :
118 SCALE_8_16_BYTE2FRAC) :
119 SCALE_8_16_GENERAL)) :
120 (ss->params.BitsPerComponentOut == 8 ? SCALE_16_8 :
121 ss->params.MaxValueIn == ss->params.MaxValueOut ?
122 SCALE_SAME : SCALE_16_16));
123
124 return 0;
125 }
126
127 /* Process a buffer. */
128 private int
s_IIEncode_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)129 s_IIEncode_process(stream_state * st, stream_cursor_read * pr,
130 stream_cursor_write * pw, bool last)
131 {
132 stream_IIEncode_state *const ss = (stream_IIEncode_state *) st;
133 const scale_case_t scale_case = ss->scale_case +
134 ALIGNMENT_MOD(pw->ptr, 2); /* ptr odd => buffer is aligned */
135 byte *out = pw->ptr + 1;
136 /****** WRONG, requires an entire output pixel ******/
137 byte *limit = pw->limit + 1 - ss->sizeofPixelOut;
138
139 /* Check whether we need to deliver any output. */
140
141 top:
142 if (dda_current(ss->dda_y) > ss->dst_y) {
143 /* Deliver some or all of the current scaled row. */
144 while (ss->dst_x < ss->params.WidthOut) {
145 uint sx = dda_current(ss->dda_x) * ss->sizeofPixelIn;
146 const byte *in = (const byte *)ss->cur + sx;
147 int c;
148
149 if (out > limit) {
150 pw->ptr = out - 1;
151 return 1;
152 }
153 switch (scale_case) {
154 case SCALE_SAME:
155 case SCALE_SAME_ALIGNED:
156 memcpy(out, in, ss->sizeofPixelIn);
157 out += ss->sizeofPixelIn;
158 break;
159 case SCALE_8_8:
160 case SCALE_8_8_ALIGNED:
161 for (c = ss->params.Colors; --c >= 0; ++in, ++out)
162 *out = (byte)(*in * ss->params.MaxValueOut /
163 ss->params.MaxValueIn);
164 break;
165 case SCALE_8_16_BYTE2FRAC:
166 case SCALE_8_16_BYTE2FRAC_ALIGNED: /* could be optimized */
167 case SCALE_8_16_BYTE2FRAC_3: /* could be optimized */
168 for (c = ss->params.Colors; --c >= 0; ++in, out += 2) {
169 uint b = *in;
170 uint value = byte2frac(b);
171
172 out[0] = (byte)(value >> 8), out[1] = (byte)value;
173 }
174 break;
175 case SCALE_8_16_BYTE2FRAC_3_ALIGNED:
176 {
177 uint b = in[0];
178
179 ((bits16 *)out)[0] = byte2frac(b);
180 b = in[1];
181 ((bits16 *)out)[1] = byte2frac(b);
182 b = in[2];
183 ((bits16 *)out)[2] = byte2frac(b);
184 }
185 out += 6;
186 break;
187 case SCALE_8_16_GENERAL:
188 case SCALE_8_16_GENERAL_ALIGNED: /* could be optimized */
189 for (c = ss->params.Colors; --c >= 0; ++in, out += 2) {
190 uint value = *in * ss->params.MaxValueOut /
191 ss->params.MaxValueIn;
192
193 out[0] = (byte)(value >> 8), out[1] = (byte)value;
194 }
195 break;
196 case SCALE_16_8:
197 case SCALE_16_8_ALIGNED:
198 for (c = ss->params.Colors; --c >= 0; in += 2, ++out)
199 *out = (byte)(*(const bits16 *)in *
200 ss->params.MaxValueOut /
201 ss->params.MaxValueIn);
202 break;
203 case SCALE_16_16:
204 case SCALE_16_16_ALIGNED: /* could be optimized */
205 for (c = ss->params.Colors; --c >= 0; in += 2, out += 2) {
206 uint value = *(const bits16 *)in *
207 ss->params.MaxValueOut / ss->params.MaxValueIn;
208
209 out[0] = (byte)(value >> 8), out[1] = (byte)value;
210 }
211 }
212 dda_next(ss->dda_x);
213 ss->dst_x++;
214 }
215 ss->dst_x = 0;
216 ss->dst_y++;
217 ss->dda_x = ss->dda_x_init;
218 goto top;
219 }
220 pw->ptr = out - 1;
221 if (ss->dst_y >= ss->params.HeightOut)
222 return EOFC;
223
224 if (ss->src_offset < ss->src_size) {
225 uint count = min(ss->src_size - ss->src_offset, pr->limit - pr->ptr);
226
227 if (count == 0)
228 return 0;
229 memcpy((byte *)ss->cur + ss->src_offset, pr->ptr + 1, count);
230 ss->src_offset += count;
231 pr->ptr += count;
232 if (ss->src_offset < ss->src_size)
233 return 0;
234 }
235 ss->src_offset = 0;
236 ss->dst_x = 0;
237 ss->dda_x = ss->dda_x_init;
238 dda_next(ss->dda_y);
239 goto top;
240 }
241
242 /* Release the filter's storage. */
243 private void
s_IIEncode_release(stream_state * st)244 s_IIEncode_release(stream_state * st)
245 {
246 stream_IIEncode_state *const ss = (stream_IIEncode_state *) st;
247 gs_memory_t *mem = ss->memory;
248
249 gs_free_object(mem, ss->cur, "IIEncode cur");
250 ss->cur = 0;
251 gs_free_object(mem, ss->prev, "IIEncode prev");
252 ss->prev = 0;
253 }
254
255 /* Stream template */
256 const stream_template s_IIEncode_template = {
257 &st_IIEncode_state, s_IIEncode_init, s_IIEncode_process, 1, 1,
258 s_IIEncode_release
259 };
260