xref: /plan9/sys/src/cmd/gs/src/gximage.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1998, 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: gximage.c,v 1.7 2004/08/04 19:36:12 stefan Exp $ */
18 /* Generic image support */
19 #include "memory_.h"
20 #include "gx.h"
21 #include "gscspace.h"
22 #include "gserrors.h"
23 #include "gsmatrix.h"
24 #include "gsutil.h"
25 #include "gxcolor2.h"		/* for lookup map */
26 #include "gxiparam.h"
27 #include "stream.h"
28 
29 /* ---------------- Generic image support ---------------- */
30 
31 /* Structure descriptors */
32 public_st_gs_image_common();
33 public_st_gs_data_image();
34 public_st_gs_pixel_image();
35 
36 /* Initialize the common parts of image structures. */
37 void
gs_image_common_t_init(gs_image_common_t * pic)38 gs_image_common_t_init(gs_image_common_t * pic)
39 {
40     gs_make_identity(&pic->ImageMatrix);
41 }
42 void
gs_data_image_t_init(gs_data_image_t * pim,int num_components)43 gs_data_image_t_init(gs_data_image_t * pim, int num_components)
44 {
45     int i;
46 
47     gs_image_common_t_init((gs_image_common_t *) pim);
48     pim->Width = pim->Height = 0;
49     pim->BitsPerComponent = 1;
50     if (num_components >= 0) {
51 	for (i = 0; i < num_components * 2; i += 2)
52 	    pim->Decode[i] = 0, pim->Decode[i + 1] = 1;
53     } else {
54 	for (i = 0; i < num_components * -2; i += 2)
55 	    pim->Decode[i] = 1, pim->Decode[i + 1] = 0;
56     }
57     pim->Interpolate = false;
58 }
59 void
gs_pixel_image_t_init(gs_pixel_image_t * pim,const gs_color_space * color_space)60 gs_pixel_image_t_init(gs_pixel_image_t * pim,
61 		      const gs_color_space * color_space)
62 {
63     int num_components;
64 
65     if (color_space == 0 ||
66 	(num_components =
67 	 gs_color_space_num_components(color_space)) < 0
68 	)
69 	num_components = 0;
70     gs_data_image_t_init((gs_data_image_t *) pim, num_components);
71     pim->format = gs_image_format_chunky;
72     pim->ColorSpace = color_space;
73     pim->CombineWithColor = false;
74 }
75 
76 /* Initialize the common part of an image-processing enumerator. */
77 int
gx_image_enum_common_init(gx_image_enum_common_t * piec,const gs_data_image_t * pic,const gx_image_enum_procs_t * piep,gx_device * dev,int num_components,gs_image_format_t format)78 gx_image_enum_common_init(gx_image_enum_common_t * piec,
79 			  const gs_data_image_t * pic,
80 			  const gx_image_enum_procs_t * piep,
81 			  gx_device * dev, int num_components,
82 			  gs_image_format_t format)
83 {
84     int bpc = pic->BitsPerComponent;
85     int i;
86 
87     piec->image_type = pic->type;
88     piec->procs = piep;
89     piec->dev = dev;
90     piec->id = gs_next_ids(dev->memory, 1);
91     switch (format) {
92 	case gs_image_format_chunky:
93 	    piec->num_planes = 1;
94 	    piec->plane_depths[0] = bpc * num_components;
95 	    break;
96 	case gs_image_format_component_planar:
97 	    piec->num_planes = num_components;
98 	    for (i = 0; i < num_components; ++i)
99 		piec->plane_depths[i] = bpc;
100 	    break;
101 	case gs_image_format_bit_planar:
102 	    piec->num_planes = bpc * num_components;
103 	    for (i = 0; i < piec->num_planes; ++i)
104 		piec->plane_depths[i] = 1;
105 	    break;
106 	default:
107 	    return_error(gs_error_rangecheck);
108     }
109     for (i = 0; i < piec->num_planes; ++i)
110 	piec->plane_widths[i] = pic->Width;
111     return 0;
112 }
113 
114 /* Compute the source size of an ordinary image with explicit data. */
115 int
gx_data_image_source_size(const gs_imager_state * pis,const gs_image_common_t * pim,gs_int_point * psize)116 gx_data_image_source_size(const gs_imager_state * pis,
117 			  const gs_image_common_t * pim, gs_int_point * psize)
118 {
119     const gs_data_image_t *pdi = (const gs_data_image_t *)pim;
120 
121     psize->x = pdi->Width;
122     psize->y = pdi->Height;
123     return 0;
124 }
125 
126 /* Process the next piece of an image with no source data. */
127 /* This procedure should never be called. */
128 int
gx_no_plane_data(gx_image_enum_common_t * info,const gx_image_plane_t * planes,int height,int * height_used)129 gx_no_plane_data(gx_image_enum_common_t * info,
130 		 const gx_image_plane_t * planes, int height,
131 		 int *height_used)
132 {
133     return_error(gs_error_Fatal);
134 }
135 
136 /* Clean up after processing an image with no source data. */
137 /* This procedure may be called, but should do nothing. */
138 int
gx_ignore_end_image(gx_image_enum_common_t * info,bool draw_last)139 gx_ignore_end_image(gx_image_enum_common_t * info, bool draw_last)
140 {
141     return 0;
142 }
143 
144 /* ---------------- Client procedures ---------------- */
145 
146 int
gx_image_data(gx_image_enum_common_t * info,const byte ** plane_data,int data_x,uint raster,int height)147 gx_image_data(gx_image_enum_common_t * info, const byte ** plane_data,
148 	      int data_x, uint raster, int height)
149 {
150     int num_planes = info->num_planes;
151     gx_image_plane_t planes[gs_image_max_planes];
152     int i;
153 
154 #ifdef DEBUG
155     if (num_planes > gs_image_max_planes) {
156 	lprintf2("num_planes=%d > gs_image_max_planes=%d!\n",
157 		 num_planes, gs_image_max_planes);
158 	return_error(gs_error_Fatal);
159     }
160 #endif
161     for (i = 0; i < num_planes; ++i) {
162 	planes[i].data = plane_data[i];
163 	planes[i].data_x = data_x;
164 	planes[i].raster = raster;
165     }
166     return gx_image_plane_data(info, planes, height);
167 }
168 
169 int
gx_image_plane_data(gx_image_enum_common_t * info,const gx_image_plane_t * planes,int height)170 gx_image_plane_data(gx_image_enum_common_t * info,
171 		    const gx_image_plane_t * planes, int height)
172 {
173     int ignore_rows_used;
174 
175     return gx_image_plane_data_rows(info, planes, height, &ignore_rows_used);
176 }
177 
178 int
gx_image_plane_data_rows(gx_image_enum_common_t * info,const gx_image_plane_t * planes,int height,int * rows_used)179 gx_image_plane_data_rows(gx_image_enum_common_t * info,
180 			 const gx_image_plane_t * planes, int height,
181 			 int *rows_used)
182 {
183     return info->procs->plane_data(info, planes, height, rows_used);
184 }
185 
186 int
gx_image_flush(gx_image_enum_common_t * info)187 gx_image_flush(gx_image_enum_common_t * info)
188 {
189     int (*flush)(gx_image_enum_common_t *) = info->procs->flush;
190 
191     return (flush ? flush(info) : 0);
192 }
193 
194 bool
gx_image_planes_wanted(const gx_image_enum_common_t * info,byte * wanted)195 gx_image_planes_wanted(const gx_image_enum_common_t *info, byte *wanted)
196 {
197     bool (*planes_wanted)(const gx_image_enum_common_t *, byte *) =
198 	info->procs->planes_wanted;
199 
200     if (planes_wanted)
201 	return planes_wanted(info, wanted);
202     else {
203 	memset(wanted, 0xff, info->num_planes);
204 	return true;
205     }
206 }
207 
208 int
gx_image_end(gx_image_enum_common_t * info,bool draw_last)209 gx_image_end(gx_image_enum_common_t * info, bool draw_last)
210 {
211     return info->procs->end_image(info, draw_last);
212 }
213 
214 /* ---------------- Serialization ---------------- */
215 
216 /*
217  * Define dummy sput/sget/release procedures for image types that don't
218  * implement these functions.
219  */
220 
221 int
gx_image_no_sput(const gs_image_common_t * pic,stream * s,const gs_color_space ** ppcs)222 gx_image_no_sput(const gs_image_common_t *pic, stream *s,
223 		 const gs_color_space **ppcs)
224 {
225     return_error(gs_error_rangecheck);
226 }
227 
228 int
gx_image_no_sget(gs_image_common_t * pic,stream * s,const gs_color_space * pcs)229 gx_image_no_sget(gs_image_common_t *pic, stream *s,
230 		 const gs_color_space *pcs)
231 {
232     return_error(gs_error_rangecheck);
233 }
234 
235 void
gx_image_default_release(gs_image_common_t * pic,gs_memory_t * mem)236 gx_image_default_release(gs_image_common_t *pic, gs_memory_t *mem)
237 {
238     gs_free_object(mem, pic, "gx_image_default_release");
239 }
240 
241 #ifdef DEBUG
242 private void
debug_b_print_matrix(const gs_pixel_image_t * pim)243 debug_b_print_matrix(const gs_pixel_image_t *pim)
244 {
245     if_debug6('b', "      ImageMatrix=[%g %g %g %g %g %g]\n",
246 	      pim->ImageMatrix.xx, pim->ImageMatrix.xy,
247 	      pim->ImageMatrix.yx, pim->ImageMatrix.yy,
248 	      pim->ImageMatrix.tx, pim->ImageMatrix.ty);
249 }
250 private void
debug_b_print_decode(const gs_pixel_image_t * pim,int num_decode)251 debug_b_print_decode(const gs_pixel_image_t *pim, int num_decode)
252 {
253     if (gs_debug_c('b')) {
254 	const char *str = "      Decode=[";
255 	int i;
256 
257 	for (i = 0; i < num_decode; str = " ", ++i)
258 	    dprintf2("%s%g", str, pim->Decode[i]);
259 	dputs("]\n");
260     }
261 }
262 #else
263 #  define debug_b_print_matrix(pim) DO_NOTHING
264 #  define debug_b_print_decode(pim, num_decode) DO_NOTHING
265 #endif
266 
267 /* Test whether an image has a default ImageMatrix. */
268 bool
gx_image_matrix_is_default(const gs_data_image_t * pid)269 gx_image_matrix_is_default(const gs_data_image_t *pid)
270 {
271     return (is_xxyy(&pid->ImageMatrix) &&
272 	    pid->ImageMatrix.xx == pid->Width &&
273 	    pid->ImageMatrix.yy == -pid->Height &&
274 	    is_fzero(pid->ImageMatrix.tx) &&
275 	    pid->ImageMatrix.ty == pid->Height);
276 }
277 
278 /* Put a variable-length uint on a stream. */
279 void
sput_variable_uint(stream * s,uint w)280 sput_variable_uint(stream *s, uint w)
281 {
282     for (; w > 0x7f; w >>= 7)
283 	sputc(s, (byte)(w | 0x80));
284     sputc(s, (byte)w);
285 }
286 
287 /*
288  * Write generic pixel image parameters.  The format is the following,
289  * encoded as a variable-length uint in the usual way:
290  *	xxxFEDCCBBBBA
291  *	    A = 0 if standard ImageMatrix, 1 if explicit ImageMatrix
292  *	    BBBB = BitsPerComponent - 1
293  *	    CC = format
294  *	    D = 0 if standard (0..1) Decode, 1 if explicit Decode
295  *	    E = Interpolate
296  *	    F = CombineWithColor
297  *	    xxx = extra information from caller
298  */
299 #define PI_ImageMatrix 0x001
300 #define PI_BPC_SHIFT 1
301 #define PI_BPC_MASK 0xf
302 #define PI_FORMAT_SHIFT 5
303 #define PI_FORMAT_MASK 0x3
304 #define PI_Decode 0x080
305 #define PI_Interpolate 0x100
306 #define PI_CombineWithColor 0x200
307 #define PI_BITS 10
308 /*
309  *	Width, encoded as a variable-length uint
310  *	Height, encoded ditto
311  *	ImageMatrix (if A = 1), per gs_matrix_store/fetch
312  *	Decode (if D = 1): blocks of up to 4 components
313  *	    aabbccdd, where each xx is decoded as:
314  *		00 = default, 01 = swapped default,
315  *		10 = (0,V), 11 = (U,V)
316  *	    non-defaulted components (up to 8 floats)
317  */
318 int
gx_pixel_image_sput(const gs_pixel_image_t * pim,stream * s,const gs_color_space ** ppcs,int extra)319 gx_pixel_image_sput(const gs_pixel_image_t *pim, stream *s,
320 		    const gs_color_space **ppcs, int extra)
321 {
322     const gs_color_space *pcs = pim->ColorSpace;
323     int bpc = pim->BitsPerComponent;
324     int num_components = gs_color_space_num_components(pcs);
325     int num_decode;
326     uint control = extra << PI_BITS;
327     float decode_default_1 = 1;
328     int i;
329     uint ignore;
330 
331     /* Construct the control word. */
332 
333     if (!gx_image_matrix_is_default((const gs_data_image_t *)pim))
334 	control |= PI_ImageMatrix;
335     switch (pim->format) {
336     case gs_image_format_chunky:
337     case gs_image_format_component_planar:
338 	switch (bpc) {
339 	case 1: case 2: case 4: case 8: case 12: break;
340 	default: return_error(gs_error_rangecheck);
341 	}
342 	break;
343     case gs_image_format_bit_planar:
344 	if (bpc < 1 || bpc > 8)
345 	    return_error(gs_error_rangecheck);
346     }
347     control |= (bpc - 1) << PI_BPC_SHIFT;
348     control |= pim->format << PI_FORMAT_SHIFT;
349     num_decode = num_components * 2;
350     if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed)
351 	decode_default_1 = (float)pcs->params.indexed.hival;
352     for (i = 0; i < num_decode; ++i)
353 	if (pim->Decode[i] != DECODE_DEFAULT(i, decode_default_1)) {
354 	    control |= PI_Decode;
355 	    break;
356 	}
357     if (pim->Interpolate)
358 	control |= PI_Interpolate;
359     if (pim->CombineWithColor)
360 	control |= PI_CombineWithColor;
361 
362     /* Write the encoding on the stream. */
363 
364     if_debug3('b', "[b]put control=0x%x, Width=%d, Height=%d\n",
365 	      control, pim->Width, pim->Height);
366     sput_variable_uint(s, control);
367     sput_variable_uint(s, (uint)pim->Width);
368     sput_variable_uint(s, (uint)pim->Height);
369     if (control & PI_ImageMatrix) {
370 	debug_b_print_matrix(pim);
371 	sput_matrix(s, &pim->ImageMatrix);
372     }
373     if (control & PI_Decode) {
374 	int i;
375 	uint dflags = 1;
376 	float decode[8];
377 	int di = 0;
378 
379 	debug_b_print_decode(pim, num_decode);
380 	for (i = 0; i < num_decode; i += 2) {
381 	    float u = pim->Decode[i], v = pim->Decode[i + 1];
382 	    float dv = DECODE_DEFAULT(i + 1, decode_default_1);
383 
384 	    if (dflags >= 0x100) {
385 		sputc(s, (byte)(dflags & 0xff));
386 		sputs(s, (const byte *)decode, di * sizeof(float), &ignore);
387 		dflags = 1;
388 		di = 0;
389 	    }
390 	    dflags <<= 2;
391 	    if (u == 0 && v == dv)
392 		DO_NOTHING;
393 	    else if (u == dv && v == 0)
394 		dflags += 1;
395 	    else {
396 		if (u != 0) {
397 		    dflags++;
398 		    decode[di++] = u;
399 		}
400 		dflags += 2;
401 		decode[di++] = v;
402 	    }
403 	}
404 	sputc(s, (byte)((dflags << (8 - num_decode)) & 0xff));
405 	sputs(s, (const byte *)decode, di * sizeof(float), &ignore);
406     }
407     *ppcs = pcs;
408     return 0;
409 }
410 
411 /* Set an image's ImageMatrix to the default. */
412 void
gx_image_matrix_set_default(gs_data_image_t * pid)413 gx_image_matrix_set_default(gs_data_image_t *pid)
414 {
415     pid->ImageMatrix.xx = (float)pid->Width;
416     pid->ImageMatrix.xy = 0;
417     pid->ImageMatrix.yx = 0;
418     pid->ImageMatrix.yy = (float)-pid->Height;
419     pid->ImageMatrix.tx = 0;
420     pid->ImageMatrix.ty = (float)pid->Height;
421 }
422 
423 /* Get a variable-length uint from a stream. */
424 int
sget_variable_uint(stream * s,uint * pw)425 sget_variable_uint(stream *s, uint *pw)
426 {
427     uint w = 0;
428     int shift = 0;
429     int ch;
430 
431     for (; (ch = sgetc(s)) >= 0x80; shift += 7)
432 	w += (ch & 0x7f) << shift;
433     if (ch < 0)
434 	return_error(gs_error_ioerror);
435     *pw = w + (ch << shift);
436     return 0;
437 }
438 
439 /*
440  * Read generic pixel image parameters.
441  */
442 int
gx_pixel_image_sget(gs_pixel_image_t * pim,stream * s,const gs_color_space * pcs)443 gx_pixel_image_sget(gs_pixel_image_t *pim, stream *s,
444 		    const gs_color_space *pcs)
445 {
446     uint control;
447     float decode_default_1 = 1;
448     int num_components, num_decode;
449     int i;
450     int code;
451     uint ignore;
452 
453     if ((code = sget_variable_uint(s, &control)) < 0 ||
454 	(code = sget_variable_uint(s, (uint *)&pim->Width)) < 0 ||
455 	(code = sget_variable_uint(s, (uint *)&pim->Height)) < 0
456 	)
457 	return code;
458     if_debug3('b', "[b]get control=0x%x, Width=%d, Height=%d\n",
459 	      control, pim->Width, pim->Height);
460     if (control & PI_ImageMatrix) {
461 	if ((code = sget_matrix(s, &pim->ImageMatrix)) < 0)
462 	    return code;
463 	debug_b_print_matrix(pim);
464     } else
465 	gx_image_matrix_set_default((gs_data_image_t *)pim);
466     pim->BitsPerComponent = ((control >> PI_BPC_SHIFT) & PI_BPC_MASK) + 1;
467     pim->format = (control >> PI_FORMAT_SHIFT) & PI_FORMAT_MASK;
468     pim->ColorSpace = pcs;
469     num_components = gs_color_space_num_components(pcs);
470     num_decode = num_components * 2;
471     if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed)
472 	decode_default_1 = (float)pcs->params.indexed.hival;
473     if (control & PI_Decode) {
474 	uint dflags = 0x10000;
475 	float *dp = pim->Decode;
476 
477 	for (i = 0; i < num_decode; i += 2, dp += 2, dflags <<= 2) {
478 	    if (dflags >= 0x10000) {
479 		dflags = sgetc(s) + 0x100;
480 		if (dflags < 0x100)
481 		    return_error(gs_error_ioerror);
482 	    }
483 	    switch (dflags & 0xc0) {
484 	    case 0x00:
485 		dp[0] = 0, dp[1] = DECODE_DEFAULT(i + 1, decode_default_1);
486 		break;
487 	    case 0x40:
488 		dp[0] = DECODE_DEFAULT(i + 1, decode_default_1), dp[1] = 0;
489 		break;
490 	    case 0x80:
491 		dp[0] = 0;
492 		if (sgets(s, (byte *)(dp + 1), sizeof(float), &ignore) < 0)
493 		    return_error(gs_error_ioerror);
494 		break;
495 	    case 0xc0:
496 		if (sgets(s, (byte *)dp, sizeof(float) * 2, &ignore) < 0)
497 		    return_error(gs_error_ioerror);
498 		break;
499 	    }
500 	}
501 	debug_b_print_decode(pim, num_decode);
502     } else {
503         for (i = 0; i < num_decode; ++i)
504 	    pim->Decode[i] = DECODE_DEFAULT(i, decode_default_1);
505     }
506     pim->Interpolate = (control & PI_Interpolate) != 0;
507     pim->CombineWithColor = (control & PI_CombineWithColor) != 0;
508     return control >> PI_BITS;
509 }
510 
511 /*
512  * Release a pixel image object.  Currently this just frees the object.
513  */
514 void
gx_pixel_image_release(gs_pixel_image_t * pic,gs_memory_t * mem)515 gx_pixel_image_release(gs_pixel_image_t *pic, gs_memory_t *mem)
516 {
517     gx_image_default_release((gs_image_common_t *)pic, mem);
518 }
519