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