1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: zdpnext.c 9043 2008-08-28 22:48:19Z giles $ */
15 /* NeXT Display PostScript extensions */
16 #include "math_.h"
17 #include "ghost.h"
18 #include "oper.h"
19 #include "gscoord.h"
20 #include "gscspace.h"		/* for iimage.h */
21 #include "gsdpnext.h"
22 #include "gsmatrix.h"
23 #include "gsiparam.h"		/* for iimage.h */
24 #include "gsiparm2.h"
25 #include "gspath2.h"
26 #include "gxcvalue.h"
27 #include "gxdevice.h"
28 #include "gxsample.h"
29 #include "ialloc.h"
30 #include "igstate.h"
31 #include "iimage.h"
32 #include "iimage2.h"
33 #include "store.h"
34 
35 /* ------ alpha channel ------ */
36 
37 /* - currentalpha <alpha> */
38 static int
zcurrentalpha(i_ctx_t * i_ctx_p)39 zcurrentalpha(i_ctx_t *i_ctx_p)
40 {
41     os_ptr op = osp;
42 
43     push(1);
44     make_real(op, gs_currentalpha(igs));
45     return 0;
46 }
47 
48 /* <alpha> setalpha - */
49 static int
zsetalpha(i_ctx_t * i_ctx_p)50 zsetalpha(i_ctx_t *i_ctx_p)
51 {
52     os_ptr op = osp;
53     double alpha;
54     int code;
55 
56     if (real_param(op, &alpha) < 0)
57 	return_op_typecheck(op);
58     if ((code = gs_setalpha(igs, alpha)) < 0)
59 	return code;
60     pop(1);
61     return 0;
62 }
63 
64 /* ------ Imaging/compositing ------ */
65 
66 /*
67  * Miscellaneous notes:
68  *
69  * composite / dissolve respect destination clipping (both clip & viewclip),
70  *   but ignore source clipping.
71  * composite / dissolve must handle overlapping source/destination correctly.
72  * compositing converts the source to the destination's color model
73  *   (including halftoning if needed).
74  */
75 
76 /*
77  * Define the operand and bookeeping structure for a compositing operation.
78  */
79 typedef struct alpha_composite_state_s {
80     /* Compositing parameters */
81     gs_composite_alpha_params_t params;
82     /* Temporary structures */
83     gs_composite_t *pcte;
84     gx_device *cdev;
85     gx_device *orig_dev;
86 } alpha_composite_state_t;
87 
88 /* Forward references */
89 static int begin_composite(i_ctx_t *, alpha_composite_state_t *);
90 static void end_composite(i_ctx_t *, alpha_composite_state_t *);
91 static int xywh_param(os_ptr, double[4]);
92 
93 /* <dict> .alphaimage - */
94 /* This is the dictionary version of the alphaimage operator, which is */
95 /* now a pseudo-operator (see gs_dpnxt.ps). */
96 static int
zalphaimage(i_ctx_t * i_ctx_p)97 zalphaimage(i_ctx_t *i_ctx_p)
98 {
99     return image1_setup(i_ctx_p, true);
100 }
101 
102 /* <destx> <desty> <width> <height> <op> compositerect - */
103 static int
zcompositerect(i_ctx_t * i_ctx_p)104 zcompositerect(i_ctx_t *i_ctx_p)
105 {
106     os_ptr op = osp;
107     double dest_rect[4];
108     alpha_composite_state_t cstate;
109     int code = xywh_param(op - 1, dest_rect);
110 
111     if (code < 0)
112 	return code;
113     check_int_leu(*op, compositerect_last);
114     cstate.params.op = (gs_composite_op_t) op->value.intval;
115     code = begin_composite(i_ctx_p, &cstate);
116     if (code < 0)
117 	return code;
118     {
119 	gs_rect rect;
120 
121 	rect.q.x = (rect.p.x = dest_rect[0]) + dest_rect[2];
122 	rect.q.y = (rect.p.y = dest_rect[1]) + dest_rect[3];
123 	code = gs_rectfill(igs, &rect, 1);
124     }
125     end_composite(i_ctx_p, &cstate);
126     if (code >= 0)
127 	pop(5);
128     return code;
129 }
130 
131 /* Common code for composite and dissolve. */
132 static int
composite_image(i_ctx_t * i_ctx_p,const gs_composite_alpha_params_t * params)133 composite_image(i_ctx_t *i_ctx_p, const gs_composite_alpha_params_t * params)
134 {
135     os_ptr op = osp;
136     alpha_composite_state_t cstate;
137     gs_image2_t image;
138     double src_rect[4];
139     double dest_pt[2];
140     gs_matrix save_ctm;
141     int code = xywh_param(op - 4, src_rect);
142 
143     cstate.params = *params;
144     gs_image2_t_init(&image);
145     if (code < 0 ||
146 	(code = num_params(op - 1, 2, dest_pt)) < 0
147 	)
148 	return code;
149     if (r_has_type(op - 3, t_null))
150 	image.DataSource = igs;
151     else {
152 	check_stype(op[-3], st_igstate_obj);
153 	check_read(op[-3]);
154 	image.DataSource = igstate_ptr(op - 3);
155     }
156     image.XOrigin = src_rect[0];
157     image.YOrigin = src_rect[1];
158     image.Width = src_rect[2];
159     image.Height = src_rect[3];
160     image.PixelCopy = true;
161     /* Compute appropriate transformations. */
162     gs_currentmatrix(igs, &save_ctm);
163     gs_translate(igs, dest_pt[0], dest_pt[1]);
164     gs_make_identity(&image.ImageMatrix);
165     if (image.DataSource == igs) {
166 	image.XOrigin -= dest_pt[0];
167 	image.YOrigin -= dest_pt[1];
168     }
169     code = begin_composite(i_ctx_p, &cstate);
170     if (code >= 0) {
171 	code = process_non_source_image(i_ctx_p,
172 					(const gs_image_common_t *)&image,
173 					"composite_image");
174 	end_composite(i_ctx_p, &cstate);
175 	if (code >= 0)
176 	    pop(8);
177     }
178     gs_setmatrix(igs, &save_ctm);
179     return code;
180 }
181 
182 /* <srcx> <srcy> <width> <height> <srcgstate|null> <destx> <desty> <op> */
183 /*   composite - */
184 static int
zcomposite(i_ctx_t * i_ctx_p)185 zcomposite(i_ctx_t *i_ctx_p)
186 {
187     os_ptr op = osp;
188     gs_composite_alpha_params_t params;
189 
190     check_int_leu(*op, composite_last);
191     params.op = (gs_composite_op_t) op->value.intval;
192     return composite_image(i_ctx_p, &params);
193 }
194 
195 /* <srcx> <srcy> <width> <height> <srcgstate|null> <destx> <desty> <delta> */
196 /*   dissolve - */
197 static int
zdissolve(i_ctx_t * i_ctx_p)198 zdissolve(i_ctx_t *i_ctx_p)
199 {
200     os_ptr op = osp;
201     gs_composite_alpha_params_t params;
202     double delta;
203     int code = real_param(op, &delta);
204 
205     if (code < 0)
206 	return code;
207     if (delta < 0 || delta > 1)
208 	return_error(e_rangecheck);
209     params.op = composite_Dissolve;
210     params.delta = delta;
211     return composite_image(i_ctx_p, &params);
212 }
213 
214 /* ------ Image reading ------ */
215 
216 static int device_is_true_color(gx_device * dev);
217 
218 /* <x> <y> <width> <height> <matrix> .sizeimagebox */
219 /*   <dev_x> <dev_y> <dev_width> <dev_height> <matrix> */
220 static void box_confine(int *pp, int *pq, int wh);
221 static int
zsizeimagebox(i_ctx_t * i_ctx_p)222 zsizeimagebox(i_ctx_t *i_ctx_p)
223 {
224     os_ptr op = osp;
225     const gx_device *dev = gs_currentdevice(igs);
226     gs_rect srect, drect;
227     gs_matrix mat;
228     gs_int_rect rect;
229     int w, h;
230     int code;
231 
232     check_type(op[-4], t_integer);
233     check_type(op[-3], t_integer);
234     check_type(op[-2], t_integer);
235     check_type(op[-1], t_integer);
236     srect.p.x = op[-4].value.intval;
237     srect.p.y = op[-3].value.intval;
238     srect.q.x = srect.p.x + op[-2].value.intval;
239     srect.q.y = srect.p.y + op[-1].value.intval;
240     gs_currentmatrix(igs, &mat);
241     gs_bbox_transform(&srect, &mat, &drect);
242     /*
243      * We want the dimensions of the image as a source, not a
244      * destination, so we need to expand it rather than pixround.
245      */
246     rect.p.x = (int)floor(drect.p.x);
247     rect.p.y = (int)floor(drect.p.y);
248     rect.q.x = (int)ceil(drect.q.x);
249     rect.q.y = (int)ceil(drect.q.y);
250     /*
251      * Clip the rectangle to the device boundaries, since that's what
252      * the NeXT implementation does.
253      */
254     box_confine(&rect.p.x, &rect.q.x, dev->width);
255     box_confine(&rect.p.y, &rect.q.y, dev->height);
256     w = rect.q.x - rect.p.x;
257     h = rect.q.y - rect.p.y;
258     /*
259      * The NeXT documentation doesn't specify very clearly what is
260      * supposed to be in the matrix: the following produces results
261      * that match testing on an actual NeXT system.
262      */
263     mat.tx -= rect.p.x;
264     mat.ty -= rect.p.y;
265     code = write_matrix(op, &mat);
266     if (code < 0)
267 	return code;
268     make_int(op - 4, rect.p.x);
269     make_int(op - 3, rect.p.y);
270     make_int(op - 2, w);
271     make_int(op - 1, h);
272     return 0;
273 }
274 static void
box_confine(int * pp,int * pq,int wh)275 box_confine(int *pp, int *pq, int wh)
276 {
277     if ( *pq <= 0 )
278 	*pp = *pq = 0;
279     else if ( *pp >= wh )
280 	*pp = *pq = wh;
281     else {
282 	if ( *pp < 0 )
283 	    *pp = 0;
284 	if ( *pq > wh )
285 	    *pq = wh;
286     }
287 }
288 
289 /* - .sizeimageparams <bits/sample> <multiproc> <ncolors> */
290 static int
zsizeimageparams(i_ctx_t * i_ctx_p)291 zsizeimageparams(i_ctx_t *i_ctx_p)
292 {
293     os_ptr op = osp;
294     gx_device *dev = gs_currentdevice(igs);
295     int ncomp = dev->color_info.num_components;
296     int bps;
297 
298     push(3);
299     if (device_is_true_color(dev))
300 	bps = dev->color_info.depth / ncomp;
301     else {
302 	/*
303 	 * Set bps to the smallest allowable number of bits that is
304 	 * sufficient to represent the number of different colors.
305 	 */
306 	gx_color_value max_value =
307 	    (dev->color_info.num_components == 1 ?
308 	     dev->color_info.max_gray :
309 	     max(dev->color_info.max_gray, dev->color_info.max_color));
310 	static const gx_color_value sizes[] = {
311 	    1, 2, 4, 8, 12, sizeof(gx_max_color_value) * 8
312 	};
313 	int i;
314 
315 	for (i = 0;; ++i)
316 	    if (max_value <= ((ulong) 1 << sizes[i]) - 1)
317 		break;
318 	bps = sizes[i];
319     }
320     make_int(op - 2, bps);
321     make_false(op - 1);
322     make_int(op, ncomp);
323     return 0;
324 }
325 
326 /* ------ Initialization procedure ------ */
327 
328 const op_def zdpnext_op_defs[] =
329 {
330     {"0currentalpha", zcurrentalpha},
331     {"1setalpha", zsetalpha},
332     {"1.alphaimage", zalphaimage},
333     {"8composite", zcomposite},
334     {"5compositerect", zcompositerect},
335     {"8dissolve", zdissolve},
336     {"5.sizeimagebox", zsizeimagebox},
337     {"0.sizeimageparams", zsizeimageparams},
338     op_def_end(0)
339 };
340 
341 /* ------ Internal routines ------ */
342 
343 /* Collect a rect operand. */
344 static int
xywh_param(os_ptr op,double rect[4])345 xywh_param(os_ptr op, double rect[4])
346 {
347     int code = num_params(op, 4, rect);
348 
349     if (code < 0)
350 	return code;
351     if (rect[2] < 0)
352 	rect[0] += rect[2], rect[2] = -rect[2];
353     if (rect[3] < 0)
354 	rect[1] += rect[3], rect[3] = -rect[3];
355     return code;
356 }
357 
358 /* Begin a compositing operation. */
359 static int
begin_composite(i_ctx_t * i_ctx_p,alpha_composite_state_t * pcp)360 begin_composite(i_ctx_t *i_ctx_p, alpha_composite_state_t * pcp)
361 {
362     gx_device *dev = gs_currentdevice(igs);
363     int code =
364 	gs_create_composite_alpha(&pcp->pcte, &pcp->params, imemory);
365 
366     if (code < 0)
367 	return code;
368     pcp->orig_dev = pcp->cdev = dev;	/* for end_composite */
369     code = (*dev_proc(dev, create_compositor))
370 	(dev, &pcp->cdev, pcp->pcte, (gs_imager_state *)igs, imemory);
371     if (code < 0) {
372 	end_composite(i_ctx_p, pcp);
373 	return code;
374     }
375     gs_setdevice_no_init(igs, pcp->cdev);
376     return 0;
377 }
378 
379 /* End a compositing operation. */
380 static void
end_composite(i_ctx_t * i_ctx_p,alpha_composite_state_t * pcp)381 end_composite(i_ctx_t *i_ctx_p, alpha_composite_state_t * pcp)
382 {
383     /* Close and free the compositor and the compositing object. */
384     if (pcp->cdev != pcp->orig_dev) {
385 	gs_closedevice(pcp->cdev);	/* also frees the device */
386 	gs_setdevice_no_init(igs, pcp->orig_dev);
387     }
388     ifree_object(pcp->pcte, "end_composite(gs_composite_t)");
389 }
390 
391 /*
392  * Determine whether a device has decomposed pixels with the components
393  * in the standard PostScript order, and a 1-for-1 color map
394  * (possibly inverted).  Return 0 if not true color, 1 if true color,
395  * -1 if inverted true color.
396  */
397 static int
device_is_true_color(gx_device * dev)398 device_is_true_color(gx_device * dev)
399 {
400     int ncomp = dev->color_info.num_components;
401     int depth = dev->color_info.depth;
402     int i, max_v;
403 
404 #define CV(i) (gx_color_value)((ulong)gx_max_color_value * i / max_v)
405 #define CV0 ((gx_color_value)0)
406 
407     /****** DOESN'T HANDLE INVERSION YET ******/
408     switch (ncomp) {
409 	case 1:		/* gray-scale */
410 	    max_v = dev->color_info.max_gray;
411 	    if (max_v != (1 << depth) - 1)
412 		return 0;
413 	    for (i = 0; i <= max_v; ++i) {
414 		gx_color_value v[3];
415                 v[0] = v[1] = v[2] = CV(i);
416 		if ((*dev_proc(dev, map_rgb_color)) (dev, v) != i)
417 		    return 0;
418 	    }
419 	    return true;
420 	case 3:		/* RGB */
421 	    max_v = dev->color_info.max_color;
422 	    if (depth % 3 != 0 || max_v != (1 << (depth / 3)) - 1)
423 		return false;
424 	    {
425 		const int gs = depth / 3, rs = gs * 2;
426 
427 		for (i = 0; i <= max_v; ++i) {
428 		    gx_color_value red[3];
429                     gx_color_value green[3];
430                     gx_color_value blue[3];
431                     red[0] = CV(i); red[1] = CV0, red[2] = CV0;
432                     green[0] = CV0; green[1] = CV(i); green[2] = CV0;
433                     blue[0] = CV0; blue[1] = CV0; blue[2] = CV(i);
434 		    if ((*dev_proc(dev, map_rgb_color)) (dev, red) !=
435 			i << rs ||
436 			(*dev_proc(dev, map_rgb_color)) (dev, green) !=
437 			i << gs ||
438 			(*dev_proc(dev, map_rgb_color)) (dev, blue) !=
439 			i	/*<< bs */
440 			)
441 			return 0;
442 		}
443 	    }
444 	    return true;
445 	case 4:		/* CMYK */
446 	    max_v = dev->color_info.max_color;
447 	    if ((depth & 3) != 0 || max_v != (1 << (depth / 4)) - 1)
448 		return false;
449 	    {
450 		const int ys = depth / 4, ms = ys * 2, cs = ys * 3;
451 
452 		for (i = 0; i <= max_v; ++i) {
453 
454 		    gx_color_value cyan[4];
455                     gx_color_value magenta[4];
456                     gx_color_value yellow[4];
457                     gx_color_value black[4];
458                     cyan[0] = CV(i); cyan[1] = cyan[2] = cyan[3] = CV0;
459                     magenta[1] = CV(i); magenta[0] = magenta[2] = magenta[3] = CV0;
460                     yellow[2] = CV(i); yellow[0] = yellow[1] = yellow[3] = CV0;
461                     black[3] = CV(i); black[0] = black[1] = black[2] = CV0;
462 		    if ((*dev_proc(dev, map_cmyk_color)) (dev, cyan) !=
463 			i << cs ||
464 			(*dev_proc(dev, map_cmyk_color)) (dev, magenta) !=
465 			i << ms ||
466 			(*dev_proc(dev, map_cmyk_color)) (dev, yellow) !=
467 			i << ys ||
468 			(*dev_proc(dev, map_cmyk_color)) (dev, black) !=
469 			i	/*<< ks */
470 			)
471 			return 0;
472 		}
473 	    }
474 	    return 1;
475 	default:
476 	    return 0;		/* DeviceN */
477     }
478 #undef CV
479 #undef CV0
480 }
481