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