xref: /plan9/sys/src/cmd/gs/src/siinterp.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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