xref: /plan9/sys/src/cmd/gs/src/gximage2.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1997, 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: gximage2.c,v 1.5 2002/08/22 07:12:29 henrys Exp $ */
18 /* ImageType 2 image implementation */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsmatrix.h"		/* for gscoord.h */
24 #include "gscoord.h"
25 #include "gscspace.h"
26 #include "gscpixel.h"
27 #include "gsdevice.h"
28 #include "gsiparm2.h"
29 #include "gxgetbit.h"
30 #include "gxiparam.h"
31 #include "gxpath.h"
32 #include "gscolor2.h"
33 
34 /* Forward references */
35 private dev_proc_begin_typed_image(gx_begin_image2);
36 private image_proc_source_size(gx_image2_source_size);
37 
38 /* Structure descriptor */
39 private_st_gs_image2();
40 
41 /* Define the image type for ImageType 2 images. */
42 const gx_image_type_t gs_image_type_2 = {
43     &st_gs_image2, gx_begin_image2, gx_image2_source_size,
44     gx_image_no_sput, gx_image_no_sget, gx_image_default_release, 2
45 };
46 
47 /* Initialize an ImageType 2 image. */
48 void
gs_image2_t_init(gs_image2_t * pim)49 gs_image2_t_init(gs_image2_t * pim)
50 {
51     pim->type = &gs_image_type_2;
52     pim->UnpaintedPath = 0;
53     pim->PixelCopy = false;
54 }
55 
56 /*
57  * Compute the device space coordinates and source data size for an
58  * ImageType 2 image.  This procedure fills in
59  * image.{Width,Height,ImageMatrix}.
60  */
61 typedef struct image2_data_s {
62     gs_point origin;
63     gs_int_rect bbox;
64     gs_image1_t image;
65 } image2_data_t;
66 private int
image2_set_data(const gs_image2_t * pim,image2_data_t * pid)67 image2_set_data(const gs_image2_t * pim, image2_data_t * pid)
68 {
69     gs_state *pgs = pim->DataSource;
70     gs_matrix smat;
71     gs_rect sbox, dbox;
72 
73     gs_transform(pgs, pim->XOrigin, pim->YOrigin, &pid->origin);
74     sbox.q.x = (sbox.p.x = pim->XOrigin) + pim->Width;
75     sbox.q.y = (sbox.p.y = pim->YOrigin) + pim->Height;
76     gs_currentmatrix(pgs, &smat);
77     gs_bbox_transform(&sbox, &smat, &dbox);
78     pid->bbox.p.x = (int)floor(dbox.p.x);
79     pid->bbox.p.y = (int)floor(dbox.p.y);
80     pid->bbox.q.x = (int)ceil(dbox.q.x);
81     pid->bbox.q.y = (int)ceil(dbox.q.y);
82     pid->image.Width = pid->bbox.q.x - pid->bbox.p.x;
83     pid->image.Height = pid->bbox.q.y - pid->bbox.p.y;
84     pid->image.ImageMatrix = pim->ImageMatrix;
85     return 0;
86 }
87 
88 /* Compute the source size of an ImageType 2 image. */
89 private int
gx_image2_source_size(const gs_imager_state * pis,const gs_image_common_t * pim,gs_int_point * psize)90 gx_image2_source_size(const gs_imager_state * pis, const gs_image_common_t * pim,
91 		      gs_int_point * psize)
92 {
93     image2_data_t idata;
94 
95     image2_set_data((const gs_image2_t *)pim, &idata);
96     psize->x = idata.image.Width;
97     psize->y = idata.image.Height;
98     return 0;
99 }
100 
101 /* Begin an ImageType 2 image. */
102 /* Note that since ImageType 2 images don't have any source data, */
103 /* this procedure does all the work. */
104 private int
gx_begin_image2(gx_device * dev,const gs_imager_state * pis,const gs_matrix * pmat,const gs_image_common_t * pic,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * mem,gx_image_enum_common_t ** pinfo)105 gx_begin_image2(gx_device * dev,
106 		const gs_imager_state * pis, const gs_matrix * pmat,
107 		const gs_image_common_t * pic, const gs_int_rect * prect,
108 	      const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
109 		gs_memory_t * mem, gx_image_enum_common_t ** pinfo)
110 {
111     const gs_image2_t *pim = (const gs_image2_t *)pic;
112     gs_state *pgs = pim->DataSource;
113     gx_device *sdev = gs_currentdevice(pgs);
114     int depth = sdev->color_info.depth;
115     bool pixel_copy = pim->PixelCopy;
116     bool has_alpha;
117     bool direct_copy = false;
118     image2_data_t idata;
119     byte *row;
120     uint row_size, source_size;
121     gx_image_enum_common_t *info;
122     gs_matrix smat, dmat;
123     int code;
124 
125     /* verify that color models are the same for PixelCopy */
126     if ( pixel_copy                            &&
127          memcmp( &dev->color_info,
128                  &sdev->color_info,
129                  sizeof(dev->color_info) ) != 0  )
130         return_error(gs_error_typecheck);
131 
132 /****** ONLY HANDLE depth <= 8 FOR PixelCopy ******/
133     if (pixel_copy && depth <= 8)
134         return_error(gs_error_unregistered);
135 
136     gs_image_t_init(&idata.image, gs_currentcolorspace((const gs_state *)pis));
137 
138     /* Add Decode entries for K and alpha */
139     idata.image.Decode[6] = idata.image.Decode[8] = 0.0;
140     idata.image.Decode[7] = idata.image.Decode[9] = 1.0;
141     if (pmat == 0) {
142 	gs_currentmatrix((const gs_state *)pis, &dmat);
143 	pmat = &dmat;
144     } else
145 	dmat = *pmat;
146     gs_currentmatrix(pgs, &smat);
147     code = image2_set_data(pim, &idata);
148     if (code < 0)
149 	return code;
150 /****** ONLY HANDLE SIMPLE CASES FOR NOW ******/
151     if (idata.bbox.p.x != floor(idata.origin.x))
152 	return_error(gs_error_rangecheck);
153     if (!(idata.bbox.p.y == floor(idata.origin.y) ||
154 	  idata.bbox.q.y == ceil(idata.origin.y))
155 	)
156 	return_error(gs_error_rangecheck);
157     source_size = (idata.image.Width * depth + 7) >> 3;
158     row_size = max(3 * idata.image.Width, source_size);
159     row = gs_alloc_bytes(mem, row_size, "gx_begin_image2");
160     if (row == 0)
161 	return_error(gs_error_VMerror);
162     if (pixel_copy) {
163 	idata.image.BitsPerComponent = depth;
164 	has_alpha = false;	/* no separate alpha channel */
165 
166 	if ( pcpath == NULL ||
167 	     gx_cpath_includes_rectangle(pcpath,
168 				     int2fixed(idata.bbox.p.x),
169 				     int2fixed(idata.bbox.p.y),
170 				     int2fixed(idata.bbox.q.x),
171 				     int2fixed(idata.bbox.q.y)) ) {
172 	    gs_matrix mat;
173 
174 
175 	    /*
176 	     * Figure 7.2 of the Adobe 3010 Supplement says that we should
177 	     * compute CTM x ImageMatrix here, but I'm almost certain it
178 	     * should be the other way around.  Also see gdevx.c.
179 	     */
180 	    gs_matrix_multiply(&idata.image.ImageMatrix, &smat, &mat);
181 	    direct_copy =
182 	        (is_xxyy(&dmat) || is_xyyx(&dmat)) &&
183 #define eqe(e) mat.e == dmat.e
184 	        eqe(xx) && eqe(xy) && eqe(yx) && eqe(yy);
185 #undef eqe
186         }
187     } else {
188 	idata.image.BitsPerComponent = 8;
189 
190 	/* Always use RGB source color for now.
191          *
192 	 * The source device has alpha if the same RGB values with
193 	 * different alphas map to different pixel values.
194 	 ****** THIS IS NOT GOOD ENOUGH: WE WANT TO SKIP TRANSFERRING
195 	 ****** ALPHA IF THE SOURCE IS CAPABLE OF HAVING ALPHA BUT
196 	 ****** DOESN'T CURRENTLY HAVE ANY ACTUAL ALPHA VALUES DIFFERENT
197 	 ****** FROM 1.
198 	 */
199 	/*
200 	 * Since the default implementation of map_rgb_alpha_color
201 	 * premultiplies the color towards white, we can't just test
202 	 * whether changing alpha has an effect on the color.
203 	 */
204 	{
205 	    gx_color_index trans_black =
206 	    (*dev_proc(sdev, map_rgb_alpha_color))
207 	    (sdev, (gx_color_value) 0, (gx_color_value) 0,
208 	     (gx_color_value) 0, (gx_color_value) 0);
209 
210 	    has_alpha =
211 		trans_black != (*dev_proc(sdev, map_rgb_alpha_color))
212 		(sdev, (gx_color_value) 0, (gx_color_value) 0,
213 		 (gx_color_value) 0, gx_max_color_value) &&
214 		trans_black != (*dev_proc(sdev, map_rgb_alpha_color))
215 		(sdev, gx_max_color_value, gx_max_color_value,
216 		 gx_max_color_value, gx_max_color_value);
217 	}
218     }
219     idata.image.Alpha =
220 	(has_alpha ? gs_image_alpha_last : gs_image_alpha_none);
221     if (smat.yy < 0) {
222 	/*
223 	 * The source Y axis is reflected.  Reflect the mapping from
224 	 * user space to source data.
225 	 */
226 	idata.image.ImageMatrix.ty += idata.image.Height *
227 	    idata.image.ImageMatrix.yy;
228 	idata.image.ImageMatrix.xy = -idata.image.ImageMatrix.xy;
229 	idata.image.ImageMatrix.yy = -idata.image.ImageMatrix.yy;
230     }
231     if (!direct_copy)
232 	code = (*dev_proc(dev, begin_typed_image))
233 	    (dev, pis, pmat, (const gs_image_common_t *)&idata.image, NULL,
234 	     pdcolor, pcpath, mem, &info);
235     if (code >= 0) {
236 	int y;
237 	gs_int_rect rect;
238 	gs_get_bits_params_t params;
239 	const byte *data;
240 	uint offset = row_size - source_size;
241 
242 	rect = idata.bbox;
243 	for (y = 0; code >= 0 && y < idata.image.Height; ++y) {
244 	    gs_int_rect *unread = 0;
245 	    int num_unread;
246 
247 /****** y COMPUTATION IS ROUNDED -- WRONG ******/
248 	    rect.q.y = rect.p.y + 1;
249 	    /* Insist on x_offset = 0 to simplify the conversion loop. */
250 	    params.options =
251 		GB_ALIGN_ANY | (GB_RETURN_COPY | GB_RETURN_POINTER) |
252 		GB_OFFSET_0 | (GB_RASTER_STANDARD | GB_RASTER_ANY) |
253 		GB_PACKING_CHUNKY;
254 	    if (pixel_copy) {
255 		params.options |= GB_COLORS_NATIVE;
256 		params.data[0] = row + offset;
257 		code = (*dev_proc(sdev, get_bits_rectangle))
258 		    (sdev, &rect, &params, &unread);
259 		if (code < 0)
260 		    break;
261 		num_unread = code;
262 		data = params.data[0];
263 		if (direct_copy) {
264 		    /*
265 		     * Copy the pixels directly to the destination.
266 		     * We know that the transformation is only a translation,
267 		     * but we must handle an inverted destination Y axis.
268 		     */
269 		    code = (*dev_proc(dev, copy_color))
270 			(dev, data, 0, row_size, gx_no_bitmap_id,
271 			 (int)(dmat.tx - idata.image.ImageMatrix.tx),
272 			 (int)(dmat.ty - idata.image.ImageMatrix.ty +
273 			       (dmat.yy < 0 ? ~y : y)),
274 			 idata.image.Width, 1);
275 		    continue;
276 		}
277 	    } else {
278 		/*
279 		 * Convert the pixels to pure colors.  This may be very
280 		 * slow and painful.  Eventually we will use indexed color for
281 		 * narrow pixels.
282 		 */
283 		/* Always use RGB source color for now. */
284 		params.options |=
285 		    GB_COLORS_RGB | GB_DEPTH_8 |
286 		    (has_alpha ? GB_ALPHA_LAST : GB_ALPHA_NONE);
287 		params.data[0] = row;
288 		code = (*dev_proc(sdev, get_bits_rectangle))
289 		    (sdev, &rect, &params, &unread);
290 		if (code < 0)
291 		    break;
292 		num_unread = code;
293 		data = params.data[0];
294 	    }
295 	    if (num_unread > 0 && pim->UnpaintedPath) {
296 		/* Add the rectangle(s) to the unpainted path. */
297 		int i;
298 
299 		for (i = 0; code >= 0 && i < num_unread; ++i)
300 		    code = gx_path_add_rectangle(pim->UnpaintedPath,
301 						 int2fixed(unread[i].p.x),
302 						 int2fixed(unread[i].p.y),
303 						 int2fixed(unread[i].q.x),
304 						 int2fixed(unread[i].q.y));
305 		gs_free_object(dev->memory, unread, "UnpaintedPath unread");
306 	    }
307 	    code = gx_image_data(info, &data, 0, row_size, 1);
308 	    rect.p.y = rect.q.y;
309 	}
310 	if (!direct_copy) {
311 	    if (code >= 0)
312 		code = gx_image_end(info, true);
313 	    else
314 		discard(gx_image_end(info, false));
315 	}
316     }
317     gs_free_object(mem, row, "gx_begin_image2");
318     return (code < 0 ? code : 1);
319 }
320