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, ¶ms);
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, ¶ms);
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