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