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