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