gvsig-raster / libjni-potrace / trunk / libjni-potrace / resources / potrace-1.8 / src / backend_pdf.c @ 1780
History | View | Annotate | Download (8.89 KB)
1 |
/* Copyright (C) 2001-2007 Peter Selinger.
|
---|---|
2 |
This file is part of Potrace. It is free software and it is covered
|
3 |
by the GNU General Public License. See the file COPYING for details. */
|
4 |
|
5 |
/* $Id: backend_pdf.c 147 2007-04-09 00:44:09Z selinger $ */
|
6 |
|
7 |
/* The PDF backend of Potrace. Stream compression is optionally
|
8 |
supplied via the functions in flate.c. */
|
9 |
|
10 |
#include <stdio.h> |
11 |
#include <stdarg.h> |
12 |
#include <string.h> |
13 |
#include <math.h> |
14 |
#include <stdlib.h> |
15 |
|
16 |
#include "main.h" |
17 |
#include "backend_pdf.h" |
18 |
#include "flate.h" |
19 |
#include "lists.h" |
20 |
#include "potracelib.h" |
21 |
#include "auxiliary.h" |
22 |
|
23 |
#ifdef HAVE_CONFIG_H
|
24 |
#include "config.h" |
25 |
#endif
|
26 |
|
27 |
typedef int color_t; |
28 |
|
29 |
#define black 0x000000 |
30 |
#define red 0xff0000 |
31 |
#define green 0x008000 |
32 |
#define blue 0x0000ff |
33 |
|
34 |
/* ---------------------------------------------------------------------- */
|
35 |
/* auxiliary: growing arrays */
|
36 |
|
37 |
struct intarray_s {
|
38 |
int size;
|
39 |
int *data;
|
40 |
}; |
41 |
typedef struct intarray_s intarray_t; |
42 |
|
43 |
static inline void intarray_init(intarray_t *ar) { |
44 |
ar->size = 0;
|
45 |
ar->data = NULL;
|
46 |
} |
47 |
|
48 |
static inline void intarray_term(intarray_t *ar) { |
49 |
free(ar->data); |
50 |
ar->size = 0;
|
51 |
ar->data = NULL;
|
52 |
} |
53 |
|
54 |
/* Set ar[n]=val. Expects n>=0. Grows array if necessary. Return 0 on
|
55 |
success and -1 on error with errno set. */
|
56 |
static inline int intarray_set(intarray_t *ar, int n, int val) { |
57 |
int *p;
|
58 |
int s;
|
59 |
|
60 |
if (n >= ar->size) {
|
61 |
s = n+1024;
|
62 |
p = (int *)realloc(ar->data, s * sizeof(int)); |
63 |
if (!p) {
|
64 |
return -1; |
65 |
} |
66 |
ar->data = p; |
67 |
ar->size = s; |
68 |
} |
69 |
ar->data[n] = val; |
70 |
return 0; |
71 |
} |
72 |
|
73 |
/* ---------------------------------------------------------------------- */
|
74 |
/* some global variables */
|
75 |
|
76 |
static intarray_t xref;
|
77 |
static int nxref = 0; |
78 |
static intarray_t pages;
|
79 |
static int npages; |
80 |
static int streamofs; |
81 |
static size_t outcount; /* output file position */ |
82 |
|
83 |
/* ---------------------------------------------------------------------- */
|
84 |
/* functions for interfacing with compression backend */
|
85 |
|
86 |
/* xship: callback function that must be initialized before calling
|
87 |
any other functions of the "ship" family. xship_file must be
|
88 |
initialized too. */
|
89 |
|
90 |
/* print the token to f, but filtered through a compression
|
91 |
filter in case filter!=0 */
|
92 |
static int (*xship)(FILE *f, int filter, char *s, int len); |
93 |
static FILE *xship_file;
|
94 |
|
95 |
/* ship PDF code, filtered */
|
96 |
static int ship(const char *fmt, ...) { |
97 |
va_list args; |
98 |
static char buf[4096]; /* static string limit is okay here because |
99 |
we only use constant format strings - for
|
100 |
the same reason, it is okay to use
|
101 |
vsprintf instead of vsnprintf below. */
|
102 |
va_start(args, fmt); |
103 |
vsprintf(buf, fmt, args); |
104 |
buf[4095] = 0; |
105 |
va_end(args); |
106 |
|
107 |
outcount += xship(xship_file, 1, buf, strlen(buf));
|
108 |
return 0; |
109 |
} |
110 |
|
111 |
/* ship PDF code, unfiltered */
|
112 |
static int shipclear(char *fmt, ...) { |
113 |
static char buf[4096]; |
114 |
va_list args; |
115 |
|
116 |
va_start(args, fmt); |
117 |
vsprintf(buf, fmt, args); |
118 |
buf[4095] = 0; |
119 |
va_end(args); |
120 |
|
121 |
outcount += xship(xship_file, 0, buf, strlen(buf));
|
122 |
return 0; |
123 |
} |
124 |
|
125 |
/* set all callback functions */
|
126 |
static void pdf_callbacks(FILE *fout) { |
127 |
|
128 |
if (info.compress) {
|
129 |
xship = pdf_xship; |
130 |
} else {
|
131 |
xship = dummy_xship; |
132 |
} |
133 |
xship_file = fout; |
134 |
} |
135 |
|
136 |
/* ---------------------------------------------------------------------- */
|
137 |
/* PDF path-drawing auxiliary functions */
|
138 |
|
139 |
/* coordinate quantization */
|
140 |
static inline point_t unit(dpoint_t p) { |
141 |
point_t q; |
142 |
|
143 |
q.x = (long)(floor(p.x*info.unit+.5)); |
144 |
q.y = (long)(floor(p.y*info.unit+.5)); |
145 |
return q;
|
146 |
} |
147 |
|
148 |
static void pdf_coords(dpoint_t p) { |
149 |
point_t cur = unit(p); |
150 |
ship("%ld %ld ", cur.x, cur.y);
|
151 |
} |
152 |
|
153 |
static void pdf_moveto(dpoint_t p) { |
154 |
pdf_coords(p); |
155 |
ship("m\n");
|
156 |
} |
157 |
|
158 |
static void pdf_lineto(dpoint_t p) { |
159 |
pdf_coords(p); |
160 |
ship("l\n");
|
161 |
} |
162 |
|
163 |
static void pdf_curveto(dpoint_t p1, dpoint_t p2, dpoint_t p3) { |
164 |
point_t q1, q2, q3; |
165 |
|
166 |
q1 = unit(p1); |
167 |
q2 = unit(p2); |
168 |
q3 = unit(p3); |
169 |
|
170 |
ship("%ld %ld %ld %ld %ld %ld c\n", q1.x, q1.y, q2.x, q2.y, q3.x, q3.y);
|
171 |
} |
172 |
|
173 |
/* this procedure returns a statically allocated string */
|
174 |
static char *pdf_colorstring(const color_t col) { |
175 |
double r, g, b;
|
176 |
static char buf[100]; |
177 |
|
178 |
r = (col & 0xff0000) >> 16; |
179 |
g = (col & 0x00ff00) >> 8; |
180 |
b = (col & 0x0000ff) >> 0; |
181 |
|
182 |
if (r==0 && g==0 && b==0) { |
183 |
return "0 g"; |
184 |
} else if (r==255 && g==255 && b==255) { |
185 |
return "1 g"; |
186 |
} else if (r == g && g == b) { |
187 |
sprintf(buf, "%.3f g", r/255.0); |
188 |
return buf;
|
189 |
} else {
|
190 |
sprintf(buf, "%.3f %.3f %.3f rg", r/255.0, g/255.0, b/255.0); |
191 |
return buf;
|
192 |
} |
193 |
} |
194 |
|
195 |
static color_t pdf_color = -1; |
196 |
static double pdf_width = -1; |
197 |
|
198 |
static void pdf_setcolor(const color_t col) { |
199 |
if (col == pdf_color) {
|
200 |
return;
|
201 |
} |
202 |
pdf_color = col; |
203 |
|
204 |
ship("%s\n", pdf_colorstring(col));
|
205 |
} |
206 |
|
207 |
/* explicit encoding, does not use special macros */
|
208 |
static int pdf_path(potrace_curve_t *curve) { |
209 |
int i;
|
210 |
dpoint_t *c; |
211 |
int m = curve->n;
|
212 |
|
213 |
c = curve->c[m-1];
|
214 |
pdf_moveto(c[2]);
|
215 |
|
216 |
for (i=0; i<m; i++) { |
217 |
c = curve->c[i]; |
218 |
switch (curve->tag[i]) {
|
219 |
case POTRACE_CORNER:
|
220 |
pdf_lineto(c[1]);
|
221 |
pdf_lineto(c[2]);
|
222 |
break;
|
223 |
case POTRACE_CURVETO:
|
224 |
pdf_curveto(c[0], c[1], c[2]); |
225 |
break;
|
226 |
} |
227 |
} |
228 |
return 0; |
229 |
} |
230 |
|
231 |
/* ---------------------------------------------------------------------- */
|
232 |
/* Backends for various types of output. */
|
233 |
|
234 |
/* Normal output: black on transparent */
|
235 |
static int render0(potrace_path_t *plist) { |
236 |
potrace_path_t *p; |
237 |
|
238 |
pdf_setcolor(info.color); |
239 |
list_forall (p, plist) { |
240 |
pdf_path(&p->curve); |
241 |
ship("h\n");
|
242 |
if (p->next == NULL || p->next->sign == '+') { |
243 |
ship("f\n");
|
244 |
} |
245 |
} |
246 |
return 0; |
247 |
} |
248 |
|
249 |
/* Opaque output: alternating black and white */
|
250 |
static int render0_opaque(potrace_path_t *plist) { |
251 |
potrace_path_t *p; |
252 |
|
253 |
list_forall (p, plist) { |
254 |
pdf_path(&p->curve); |
255 |
ship("h\n");
|
256 |
pdf_setcolor(p->sign=='+' ? info.color : info.fillcolor);
|
257 |
ship("f\n");
|
258 |
} |
259 |
return 0; |
260 |
} |
261 |
|
262 |
/* select the appropriate rendering function from above */
|
263 |
static int pdf_render(potrace_path_t *plist) |
264 |
{ |
265 |
if (info.opaque) {
|
266 |
return render0_opaque(plist);
|
267 |
} |
268 |
return render0(plist);
|
269 |
} |
270 |
|
271 |
/* ---------------------------------------------------------------------- */
|
272 |
/* PDF header and footer */
|
273 |
|
274 |
int init_pdf(FILE *fout)
|
275 |
{ |
276 |
intarray_init(&xref); |
277 |
intarray_init(&pages); |
278 |
nxref = 0;
|
279 |
npages = 0;
|
280 |
|
281 |
/* set callback functions for shipping routines */
|
282 |
pdf_callbacks(fout); |
283 |
outcount = 0;
|
284 |
|
285 |
shipclear("%%PDF-1.3\n");
|
286 |
|
287 |
intarray_set(&xref, nxref++, outcount); |
288 |
shipclear("1 0 obj\n<</Type/Catalog/Pages 3 0 R>>\nendobj\n");
|
289 |
|
290 |
intarray_set(&xref, nxref++, outcount); |
291 |
shipclear("2 0 obj\n"
|
292 |
"<</Creator"
|
293 |
"(\"POTRACE\" \"VERSION\", written by Peter Selinger 2001-2007)>>\n"
|
294 |
"endobj\n");
|
295 |
|
296 |
/* delay obj #3 (pages) until end */
|
297 |
nxref++; |
298 |
|
299 |
fflush(fout); |
300 |
return 0; |
301 |
} |
302 |
|
303 |
int term_pdf(FILE *fout)
|
304 |
{ |
305 |
int startxref;
|
306 |
int i;
|
307 |
|
308 |
pdf_callbacks(fout); |
309 |
|
310 |
intarray_set(&xref, 2, outcount);
|
311 |
shipclear("3 0 obj\n"
|
312 |
"<</Type/Pages/Count %d/Kids[\n", npages);
|
313 |
for (i = 0; i < npages; i++) |
314 |
shipclear("%d 0 R\n", pages.data[i]);
|
315 |
shipclear("]>>\nendobj\n");
|
316 |
|
317 |
startxref = outcount; |
318 |
|
319 |
shipclear("xref\n0 %d\n", nxref + 1); |
320 |
shipclear("0000000000 65535 f \n");
|
321 |
for (i = 0; i < nxref; i++) |
322 |
shipclear("%0.10d 00000 n \n", xref.data[i]);
|
323 |
|
324 |
shipclear("trailer\n<</Size %d/Root 1 0 R/Info 2 0 R>>\n", nxref + 1); |
325 |
shipclear("startxref\n%d\n%%%%EOF\n", startxref);
|
326 |
|
327 |
fflush(fout); |
328 |
intarray_term(&xref); |
329 |
intarray_term(&pages); |
330 |
return 0; |
331 |
} |
332 |
|
333 |
static void pdf_pageinit(imginfo_t *imginfo) |
334 |
{ |
335 |
double s, c;
|
336 |
|
337 |
double origx = imginfo->trans.orig[0] + imginfo->lmar; |
338 |
double origy = imginfo->trans.orig[1] + imginfo->bmar; |
339 |
double scalex = imginfo->width / imginfo->pixwidth / info.unit;
|
340 |
double scaley = imginfo->height / imginfo->pixheight / info.unit;
|
341 |
int pagew = (int)ceil(imginfo->trans.bb[0]+imginfo->lmar+imginfo->rmar); |
342 |
int pageh = (int)ceil(imginfo->trans.bb[1]+imginfo->tmar+imginfo->bmar); |
343 |
|
344 |
pdf_color = -1;
|
345 |
pdf_width = -1;
|
346 |
|
347 |
intarray_set(&xref, nxref++, outcount); |
348 |
shipclear("%d 0 obj\n", nxref);
|
349 |
shipclear("<</Type/Page/Parent 3 0 R/Resources<</ProcSet[/PDF]>>");
|
350 |
shipclear("/MediaBox[0 0 %d %d]", pagew, pageh);
|
351 |
shipclear("/Contents %d 0 R>>\n", nxref + 1); |
352 |
shipclear("endobj\n");
|
353 |
|
354 |
intarray_set(&pages, npages++, nxref); |
355 |
|
356 |
intarray_set(&xref, nxref++, outcount); |
357 |
shipclear("%d 0 obj\n", nxref);
|
358 |
if (info.compress)
|
359 |
shipclear("<</Filter/FlateDecode/Length %d 0 R>>\n", nxref + 1); |
360 |
else
|
361 |
shipclear("<</Length %d 0 R>>\n", nxref + 1); |
362 |
shipclear("stream\n");
|
363 |
|
364 |
streamofs = outcount; |
365 |
|
366 |
s = sin(info.angle * M_PI / 180.0); |
367 |
c = cos(info.angle * M_PI / 180.0); |
368 |
|
369 |
ship("%f %f %f %f %.0f %.0f cm\n", scalex*c, scalex*s, -scaley*s, scaley*c, origx, origy);
|
370 |
} |
371 |
|
372 |
static void pdf_pageterm(void) |
373 |
{ |
374 |
int streamlen;
|
375 |
|
376 |
shipclear("");
|
377 |
|
378 |
streamlen = outcount - streamofs; |
379 |
shipclear("endstream\nendobj\n");
|
380 |
|
381 |
intarray_set(&xref, nxref++, outcount); |
382 |
shipclear("%d 0 obj\n%d\nendobj\n", nxref, streamlen);
|
383 |
} |
384 |
|
385 |
int page_pdf(FILE *fout, potrace_path_t *plist, imginfo_t *imginfo)
|
386 |
{ |
387 |
int r;
|
388 |
|
389 |
pdf_callbacks(fout); |
390 |
|
391 |
pdf_pageinit(imginfo); |
392 |
|
393 |
r = pdf_render(plist); |
394 |
if (r) {
|
395 |
return r;
|
396 |
} |
397 |
|
398 |
pdf_pageterm(); |
399 |
|
400 |
fflush(fout); |
401 |
|
402 |
return 0; |
403 |
} |
404 |
|