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