1 /* Copyright (C) 1995, 2000 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: gxidata.c,v 1.9 2005/06/08 14:38:21 igor Exp $ */
18 /* Generic image enumeration and cleanup */
19 #include "gx.h"
20 #include "memory_.h"
21 #include "gserrors.h"
22 #include "gxdevice.h"
23 #include "gxcpath.h"
24 #include "gximage.h"
25
26 /* Forward declarations */
27 private void update_strip(gx_image_enum *penum);
28 private void repack_bit_planes(const gx_image_plane_t *src_planes,
29 const ulong *offsets, int num_planes,
30 byte *buffer, int width,
31 const sample_lookup_t * ptab, int spread);
32 private gx_device *setup_image_device(const gx_image_enum *penum);
33
34 /* Process the next piece of an ImageType 1 image. */
35 int
gx_image1_plane_data(gx_image_enum_common_t * info,const gx_image_plane_t * planes,int height,int * rows_used)36 gx_image1_plane_data(gx_image_enum_common_t * info,
37 const gx_image_plane_t * planes, int height,
38 int *rows_used)
39 {
40 gx_image_enum *penum = (gx_image_enum *) info;
41 gx_device *dev;
42 const int y = penum->y;
43 int y_end = min(y + height, penum->rect.h);
44 int width_spp = penum->rect.w * penum->spp;
45 int num_planes = penum->num_planes;
46 int num_components_per_plane = 1;
47
48 #define BCOUNT(plane) /* bytes per data row */\
49 (((penum->rect.w + (plane).data_x) * penum->spp * penum->bps / num_planes\
50 + 7) >> 3)
51
52 fixed adjust = penum->adjust;
53 ulong offsets[gs_image_max_planes];
54 int ignore_data_x;
55 bool bit_planar = penum->num_planes > penum->spp;
56 int code;
57
58 if (height == 0) {
59 *rows_used = 0;
60 return 0;
61 }
62 dev = setup_image_device(penum);
63
64 /* Now render complete rows. */
65
66 if (penum->used.y) {
67 /*
68 * Processing was interrupted by an error. Skip over rows
69 * already processed.
70 */
71 int px;
72
73 for (px = 0; px < num_planes; ++px)
74 offsets[px] = planes[px].raster * penum->used.y;
75 penum->used.y = 0;
76 } else
77 memset(offsets, 0, num_planes * sizeof(offsets[0]));
78 if (num_planes == 1 && penum->plane_depths[0] != penum->bps) {
79 /* A single plane with multiple components. */
80 num_components_per_plane = penum->plane_depths[0] / penum->bps;
81 }
82 for (; penum->y < y_end; penum->y++) {
83 int px;
84 const byte *buffer;
85 int sourcex;
86 int x_used = penum->used.x;
87
88 if (bit_planar) {
89 /* Repack the bit planes into byte-wide samples. */
90
91 buffer = penum->buffer;
92 sourcex = 0;
93 for (px = 0; px < num_planes; px += penum->bps)
94 repack_bit_planes(planes, offsets, penum->bps, penum->buffer,
95 penum->rect.w, &penum->map[px].table,
96 penum->spread);
97 for (px = 0; px < num_planes; ++px)
98 offsets[px] += planes[px].raster;
99 } else {
100 /*
101 * Normally, we unpack the data into the buffer, but if
102 * there is only one plane and we don't need to expand the
103 * input samples, we may use the data directly.
104 */
105 sourcex = planes[0].data_x;
106 buffer =
107 (*penum->unpack)(penum->buffer, &sourcex,
108 planes[0].data + offsets[0],
109 planes[0].data_x, BCOUNT(planes[0]),
110 &penum->map[0], penum->spread, num_components_per_plane);
111
112 offsets[0] += planes[0].raster;
113 for (px = 1; px < num_planes; ++px) {
114 (*penum->unpack)(penum->buffer + (px << penum->log2_xbytes),
115 &ignore_data_x,
116 planes[px].data + offsets[px],
117 planes[px].data_x, BCOUNT(planes[px]),
118 &penum->map[px], penum->spread, 1);
119 offsets[px] += planes[px].raster;
120 }
121 }
122 #ifdef DEBUG
123 if (gs_debug_c('b'))
124 dprintf1("[b]image1 y=%d\n", y);
125 if (gs_debug_c('B')) {
126 int i, n = width_spp;
127
128 if (penum->bps > 8)
129 n *= 2;
130 else if (penum->bps == 1 && penum->unpack_bps == 8)
131 n = (n + 7) / 8;
132 dlputs("[B]row:");
133 for (i = 0; i < n; i++)
134 dprintf1(" %02x", buffer[i]);
135 dputs("\n");
136 }
137 #endif
138 penum->cur.x = dda_current(penum->dda.row.x);
139 dda_next(penum->dda.row.x);
140 penum->cur.y = dda_current(penum->dda.row.y);
141 dda_next(penum->dda.row.y);
142 if (!penum->interpolate)
143 switch (penum->posture) {
144 case image_portrait:
145 { /* Precompute integer y and height, */
146 /* and check for clipping. */
147 fixed yc = penum->cur.y,
148 yn = dda_current(penum->dda.row.y);
149
150 if (yn < yc) {
151 fixed temp = yn;
152
153 yn = yc;
154 yc = temp;
155 }
156 yc -= adjust;
157 if (yc >= penum->clip_outer.q.y)
158 goto mt;
159 yn += adjust;
160 if (yn <= penum->clip_outer.p.y)
161 goto mt;
162 penum->yci = fixed2int_pixround(yc);
163 penum->hci = fixed2int_pixround(yn) - penum->yci;
164 if (penum->hci == 0)
165 goto mt;
166 if_debug2('b', "[b]yci=%d, hci=%d\n",
167 penum->yci, penum->hci);
168 }
169 break;
170 case image_landscape:
171 { /* Check for no pixel centers in x. */
172 fixed xc = penum->cur.x,
173 xn = dda_current(penum->dda.row.x);
174
175 if (xn < xc) {
176 fixed temp = xn;
177
178 xn = xc;
179 xc = temp;
180 }
181 xc -= adjust;
182 if (xc >= penum->clip_outer.q.x)
183 goto mt;
184 xn += adjust;
185 if (xn <= penum->clip_outer.p.x)
186 goto mt;
187 penum->xci = fixed2int_pixround(xc);
188 penum->wci = fixed2int_pixround(xn) - penum->xci;
189 if (penum->wci == 0)
190 goto mt;
191 if_debug2('b', "[b]xci=%d, wci=%d\n",
192 penum->xci, penum->wci);
193 }
194 break;
195 case image_skewed:
196 ;
197 }
198 update_strip(penum);
199 if (x_used) {
200 /*
201 * Processing was interrupted by an error. Skip over pixels
202 * already processed.
203 */
204 dda_advance(penum->dda.pixel0.x, x_used);
205 dda_advance(penum->dda.pixel0.y, x_used);
206 penum->used.x = 0;
207 }
208 if_debug2('b', "[b]pixel0 x=%g, y=%g\n",
209 fixed2float(dda_current(penum->dda.pixel0.x)),
210 fixed2float(dda_current(penum->dda.pixel0.y)));
211 code = (*penum->render)(penum, buffer, sourcex + x_used,
212 width_spp - x_used * penum->spp, 1, dev);
213 if (code < 0) {
214 /* Error or interrupt, restore original state. */
215 penum->used.x += x_used;
216 if (!penum->used.y) {
217 dda_previous(penum->dda.row.x);
218 dda_previous(penum->dda.row.y);
219 dda_translate(penum->dda.strip.x,
220 penum->prev.x - penum->cur.x);
221 dda_translate(penum->dda.strip.y,
222 penum->prev.y - penum->cur.y);
223 }
224 goto out;
225 }
226 penum->prev = penum->cur;
227 mt:;
228 }
229 if (penum->y < penum->rect.h) {
230 code = 0;
231 } else {
232 /* End of input data. Render any left-over buffered data. */
233 code = gx_image1_flush(info);
234 if (code >= 0)
235 code = 1;
236 }
237 out:
238 /* Note that caller must call end_image */
239 /* for both error and normal termination. */
240 *rows_used = penum->y - y;
241 return code;
242 }
243
244 /* Flush any buffered data. */
245 int
gx_image1_flush(gx_image_enum_common_t * info)246 gx_image1_flush(gx_image_enum_common_t * info)
247 {
248 gx_image_enum *penum = (gx_image_enum *)info;
249 int width_spp = penum->rect.w * penum->spp;
250 fixed adjust = penum->adjust;
251
252 penum->cur.x = dda_current(penum->dda.row.x);
253 penum->cur.y = dda_current(penum->dda.row.y);
254 switch (penum->posture) {
255 case image_portrait:
256 {
257 fixed yc = penum->cur.y;
258
259 penum->yci = fixed2int_rounded(yc - adjust);
260 penum->hci = fixed2int_rounded(yc + adjust) - penum->yci;
261 }
262 break;
263 case image_landscape:
264 {
265 fixed xc = penum->cur.x;
266
267 penum->xci = fixed2int_rounded(xc - adjust);
268 penum->wci = fixed2int_rounded(xc + adjust) - penum->xci;
269 }
270 break;
271 case image_skewed: /* pacify compilers */
272 ;
273 }
274 update_strip(penum);
275 penum->prev = penum->cur;
276 return (*penum->render)(penum, NULL, 0, width_spp, 0,
277 setup_image_device(penum));
278 }
279
280 /* Update the strip DDA when moving to a new row. */
281 private void
update_strip(gx_image_enum * penum)282 update_strip(gx_image_enum *penum)
283 {
284 dda_translate(penum->dda.strip.x, penum->cur.x - penum->prev.x);
285 dda_translate(penum->dda.strip.y, penum->cur.y - penum->prev.y);
286 penum->dda.pixel0 = penum->dda.strip;
287 }
288
289 /*
290 * Repack 1 to 8 individual bit planes into 8-bit samples.
291 * buffer is aligned, and includes padding to an 8-byte boundary.
292 * This procedure repacks one row, so the only relevant members of
293 * src_planes are data and data_x (not raster).
294 */
295 private void
repack_bit_planes(const gx_image_plane_t * src_planes,const ulong * offsets,int num_planes,byte * buffer,int width,const sample_lookup_t * ptab,int spread)296 repack_bit_planes(const gx_image_plane_t *src_planes, const ulong *offsets,
297 int num_planes, byte *buffer, int width,
298 const sample_lookup_t * ptab, int spread)
299 {
300 gx_image_plane_t planes[8];
301 byte *zeros = 0;
302 byte *dest = buffer;
303 int any_data_x = 0;
304 bool direct = (spread == 1 && ptab->lookup8[0] == 0 &&
305 ptab->lookup8[255] == 255);
306 int pi, x;
307 gx_image_plane_t *pp;
308
309 /*
310 * Set up the row pointers, taking data_x and null planes into account.
311 * If there are any null rows, we need to create a block of zeros in
312 * order to avoid tests in the loop.
313 */
314 for (pi = 0, pp = planes; pi < num_planes; ++pi, ++pp)
315 if (src_planes[pi].data == 0) {
316 if (!zeros) {
317 zeros = buffer + width - ((width + 7) >> 3);
318 }
319 pp->data = zeros;
320 pp->data_x = 0;
321 } else {
322 int dx = src_planes[pi].data_x;
323
324 pp->data = src_planes[pi].data + (dx >> 3) + offsets[pi];
325 any_data_x |= (pp->data_x = dx & 7);
326 }
327 if (zeros)
328 memset(zeros, 0, buffer + width - zeros);
329
330 /*
331 * Now process the data, in blocks of one input byte column
332 * (8 output bytes).
333 */
334 for (x = 0; x < width; x += 8) {
335 bits32 w0 = 0, w1 = 0;
336 #if arch_is_big_endian
337 static const bits32 expand[16] = {
338 0x00000000, 0x00000001, 0x00000100, 0x00000101,
339 0x00010000, 0x00010001, 0x00010100, 0x00010101,
340 0x01000000, 0x01000001, 0x01000100, 0x01000101,
341 0x01010000, 0x01010001, 0x01010100, 0x01010101
342 };
343 #else
344 static const bits32 expand[16] = {
345 0x00000000, 0x01000000, 0x00010000, 0x01010000,
346 0x00000100, 0x01000100, 0x00010100, 0x01010100,
347 0x00000001, 0x01000001, 0x00010001, 0x01010001,
348 0x00000101, 0x01000101, 0x00010101, 0x01010101
349 };
350 #endif
351
352 if (any_data_x) {
353 for (pi = 0, pp = planes; pi < num_planes; ++pi, ++pp) {
354 uint b = *(pp->data++);
355 int dx = pp->data_x;
356
357 if (dx) {
358 b <<= dx;
359 if (x + 8 - dx < width)
360 b += *pp->data >> (8 - dx);
361 }
362 w0 = (w0 << 1) | expand[b >> 4];
363 w1 = (w1 << 1) | expand[b & 0xf];
364 }
365 } else {
366 for (pi = 0, pp = planes; pi < num_planes; ++pi, ++pp) {
367 uint b = *(pp->data++);
368
369 w0 = (w0 << 1) | expand[b >> 4];
370 w1 = (w1 << 1) | expand[b & 0xf];
371 }
372 }
373 /*
374 * We optimize spread == 1 and identity ptab together, although
375 * we could subdivide these 2 cases into 4 if we wanted.
376 */
377 if (direct) {
378 ((bits32 *)dest)[0] = w0;
379 ((bits32 *)dest)[1] = w1;
380 dest += 8;
381 } else {
382 #define MAP_BYTE(v) (ptab->lookup8[(byte)(v)])
383 dest[0] = MAP_BYTE(w0 >> 24); dest += spread;
384 dest[1] = MAP_BYTE(w0 >> 16); dest += spread;
385 dest[2] = MAP_BYTE(w0 >> 8); dest += spread;
386 dest[3] = MAP_BYTE(w0); dest += spread;
387 dest[4] = MAP_BYTE(w1 >> 24); dest += spread;
388 dest[5] = MAP_BYTE(w1 >> 16); dest += spread;
389 dest[6] = MAP_BYTE(w1 >> 8); dest += spread;
390 dest[7] = MAP_BYTE(w1); dest += spread;
391 #undef MAP_BYTE
392 }
393 }
394 }
395
396 /* Set up the device for drawing an image. */
397 private gx_device *
setup_image_device(const gx_image_enum * penum)398 setup_image_device(const gx_image_enum *penum)
399 {
400 gx_device *dev = penum->dev;
401
402 if (penum->clip_dev) {
403 gx_device_clip *cdev = penum->clip_dev;
404
405 gx_device_set_target((gx_device_forward *)cdev, dev);
406 dev = (gx_device *) cdev;
407 }
408 if (penum->rop_dev) {
409 gx_device_rop_texture *rtdev = penum->rop_dev;
410
411 gx_device_set_target((gx_device_forward *)rtdev, dev);
412 dev = (gx_device *) rtdev;
413 }
414 return dev;
415 }
416
417 /* Clean up by releasing the buffers. */
418 /* Currently we ignore draw_last. */
419 int
gx_image1_end_image(gx_image_enum_common_t * info,bool draw_last)420 gx_image1_end_image(gx_image_enum_common_t * info, bool draw_last)
421 {
422 gx_image_enum *penum = (gx_image_enum *) info;
423 gs_memory_t *mem = penum->memory;
424 stream_image_scale_state *scaler = penum->scaler;
425
426 if_debug2('b', "[b]%send_image, y=%d\n",
427 (penum->y < penum->rect.h ? "premature " : ""), penum->y);
428 if (draw_last) {
429 int code = gx_image_flush(info);
430
431 if (code < 0)
432 return code;
433 }
434 gs_free_object(mem, penum->rop_dev, "image RasterOp");
435 gs_free_object(mem, penum->clip_dev, "image clipper");
436 if (scaler != 0) {
437 (*scaler->template->release) ((stream_state *) scaler);
438 gs_free_object(mem, scaler, "image scaler state");
439 }
440 gs_free_object(mem, penum->line, "image line");
441 gs_free_object(mem, penum->buffer, "image buffer");
442 gs_free_object(mem, penum, "gx_default_end_image");
443 return 0;
444 }
445