Statistics
| Revision:

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