1 /* Copyright (C) 2009 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: zpdfops.c 10099 2009-09-28 22:07:08Z alexcher $ */
15 /* Custom operators for PDF interpreter */
16
17 #include "ghost.h"
18 #include "oper.h"
19 #include "igstate.h"
20 #include "istack.h"
21 #include "iutil.h"
22 #include "gspath.h"
23 #include "math_.h"
24
25 /* Construct a smooth path passing though a number of points on the stack */
26 /* for PDF ink annotations. The program is based on a very simple method of */
27 /* smoothing polygons by Maxim Shemanarev. */
28 /* http://www.antigrain.com/research/bezier_interpolation/ */
29 /* <mark> <x0> <y0> ... <xn> <yn> .pdfinkpath - */
30 int
zpdfinkpath(i_ctx_t * i_ctx_p)31 zpdfinkpath(i_ctx_t *i_ctx_p)
32 {
33 os_ptr optr, op = osp;
34 uint count = ref_stack_counttomark(&o_stack);
35
36 uint i, ocount;
37 int code;
38 double x0, y0, x1, y1, x2, y2, x3, y3, xc1, yc1, xc2, yc2, xc3, yc3;
39 double len1, len2, len3, k1, k2, xm1, ym1, xm2, ym2;
40 double ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y;
41 const double smooth_value = 1; /* from 0..1 range */
42
43 if (count == 0)
44 return_error(e_unmatchedmark);
45 if ((count & 1) == 0 || count < 3)
46 return_error(e_rangecheck);
47
48 ocount = count - 1;
49 optr = op - ocount + 1;
50
51 if ((code = real_param(optr, &x1)) < 0)
52 return code;
53 if ((code = real_param(optr + 1, &y1)) < 0)
54 return code;
55 if ((code = gs_moveto(igs, x1, y1)) < 0)
56 return code;
57 if (ocount == 2)
58 goto pop;
59
60 if ((code = real_param(optr + 2, &x2)) < 0)
61 return code;
62 if ((code = real_param(optr + 3, &y2)) < 0)
63 return code;
64 if (ocount == 4) {
65 if((code = gs_lineto(igs, x2, y2)) < 0)
66 return code;
67 goto pop;
68 }
69 x0 = 2*x1 - x2;
70 y0 = 2*y1 - y2;
71
72 for (i = 4; i <= ocount; i += 2) {
73 if (i < ocount) {
74 if ((code = real_param(optr + i, &x3)) < 0)
75 return code;
76 if ((code = real_param(optr + i + 1, &y3)) < 0)
77 return code;
78 } else {
79 x3 = 2*x2 - x1;
80 y3 = 2*y2 - y1;
81 }
82
83 xc1 = (x0 + x1) / 2.0;
84 yc1 = (y0 + y1) / 2.0;
85 xc2 = (x1 + x2) / 2.0;
86 yc2 = (y1 + y2) / 2.0;
87 xc3 = (x2 + x3) / 2.0;
88 yc3 = (y2 + y3) / 2.0;
89
90 len1 = hypot(x1 - x0, y1 - y0);
91 len2 = hypot(x2 - x1, y2 - y1);
92 len3 = hypot(x3 - x2, y3 - y2);
93
94 k1 = len1 / (len1 + len2);
95 k2 = len2 / (len2 + len3);
96
97 xm1 = xc1 + (xc2 - xc1) * k1;
98 ym1 = yc1 + (yc2 - yc1) * k1;
99
100 xm2 = xc2 + (xc3 - xc2) * k2;
101 ym2 = yc2 + (yc3 - yc2) * k2;
102
103 ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + x1 - xm1;
104 ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + y1 - ym1;
105
106 ctrl2_x = xm2 + (xc2 - xm2) * smooth_value + x2 - xm2;
107 ctrl2_y = ym2 + (yc2 - ym2) * smooth_value + y2 - ym2;
108
109 code = gs_curveto(igs, ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y, x2, y2);
110 if (code < 0)
111 return code;
112 x0 = x1, x1 = x2, x2 = x3;
113 y0 = y1, y1 = y2, y2 = y3;
114 }
115 pop:
116 ref_stack_pop(&o_stack, count);
117 return 0;
118 }
119
120 /* ------ Initialization procedure ------ */
121
122 const op_def zpdfops_op_defs[] =
123 {
124 {"0.pdfinkpath", zpdfinkpath},
125 op_def_end(0)
126 };
127