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