2 |
- |
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
|
|
|
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
|
|
|
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
|
|
|
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 |
};
|