1 /*
2 * (c) Copyright 2001 Vilson G�rtner, Uwe Steinmann.
3 * (c) Copyright 2002-2004 Uwe Steinmann.
4 * All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22 /* $Id: */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <time.h>
32 #include <math.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #ifndef WIN32
36 #include <strings.h>
37 #include <sys/select.h>
38 #include <unistd.h>
39 #endif
40 #include <ctype.h>
41
42 #ifdef WIN32
43 #include <windows.h>
44 #include <winbase.h>
45 #endif
46
47 #include "ps_intern.h"
48 #include "ps_memory.h"
49 #include "ps_error.h"
50 #include "ps_fontenc.h"
51 #include "ps_inputenc.h"
52
53 #ifdef HAVE_LIBPNG
54 # include "png.h"
55 #endif
56
57 #ifdef HAVE_LIBJPEG
58 # include "jpeglib.h"
59 #endif
60
61 #ifdef HAVE_LIBGIF
62 # include "gif_lib.h"
63 #endif
64
65 #ifdef HAVE_LIBTIFF
66 # include "tiffio.h"
67 #endif
68
69 #ifndef DISABLE_BMP
70 # include "bmp.h"
71 #endif
72
73 /* ps_writeproc_file() {{{
74 * Default output function
75 */
76 static size_t
ps_writeproc_file(PSDoc * p,void * data,size_t size)77 ps_writeproc_file(PSDoc *p, void *data, size_t size)
78 {
79 return fwrite(data, 1, size, p->fp);
80 }
81 /* }}} */
82
83 /* ps_writeproc_buffer() {{{
84 * Default output function for memory
85 */
86 static size_t
ps_writeproc_buffer(PSDoc * p,void * data,size_t size)87 ps_writeproc_buffer(PSDoc *p, void *data, size_t size)
88 {
89 return str_buffer_write(p, p->sb, data, size);
90 }
91 /* }}} */
92
93 /* _ps_delete_font() {{{
94 */
_ps_delete_font(PSDoc * psdoc,PSFont * psfont)95 void _ps_delete_font(PSDoc *psdoc, PSFont *psfont) {
96 if(NULL == psdoc) {
97 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
98 return;
99 }
100 if(psfont == NULL) {
101 ps_error(psdoc, PS_RuntimeError, _("PSFont is null."));
102 return;
103 }
104 if(psfont->psdoc != psdoc) {
105 ps_error(psdoc, PS_RuntimeError, _("This PSFont was created for a different document."));
106 return;
107 }
108
109 /* Free hash table with char info */
110 if(psfont->metrics->gadobechars) {
111 ADOBEINFO *ai;
112 char *p ;
113 ght_iterator_t iterator;
114 for(ai = ght_first(psfont->metrics->gadobechars, &iterator, (void **) &p); ai != NULL; ai = ght_next(psfont->metrics->gadobechars, &iterator, (void **) &p)) {
115 LIG *lig, *ligtmp;
116 KERN *k, *ktmp;
117 PCC *np, *nptmp;
118 lig = ai->ligs;
119 while(lig != NULL) {
120 if(lig->succ)
121 psdoc->free(psdoc, lig->succ);
122 if(lig->sub)
123 psdoc->free(psdoc, lig->sub);
124 ligtmp = lig->next;
125 psdoc->free(psdoc, lig);
126 lig = ligtmp;
127 }
128 /*
129 for (lig=ai->ligs; lig; lig = ligtmp) {
130 if(lig->succ)
131 psdoc->free(psdoc, lig->succ);
132 if(lig->sub)
133 psdoc->free(psdoc, lig->sub);
134 ligtmp = lig->next;
135 psdoc->free(psdoc, lig);
136 }
137 */
138 k = ai->kerns;
139 while(k != NULL) {
140 if(k->succ)
141 psdoc->free(psdoc, k->succ);
142 ktmp = k->next;
143 psdoc->free(psdoc, k);
144 k = ktmp;
145 }
146 for (np=ai->pccs; np; np = nptmp) {
147 if(np->partname)
148 psdoc->free(psdoc, np->partname);
149 nptmp = np->next;
150 psdoc->free(psdoc, np);
151 }
152 if(ai->kern_equivs)
153 psdoc->free(psdoc, ai->kern_equivs);
154 psdoc->free(psdoc, ai->adobename);
155 psdoc->free(psdoc, ai);
156 }
157 ght_finalize(psfont->metrics->gadobechars);
158 }
159
160 if(psfont->metrics->fontenc) {
161 ght_finalize(psfont->metrics->fontenc);
162 }
163
164 if(psfont->metrics->fontname) {
165 psdoc->free(psdoc, psfont->metrics->fontname);
166 }
167
168 if(psfont->metrics->codingscheme) {
169 psdoc->free(psdoc, psfont->metrics->codingscheme);
170 }
171
172 if(psfont->metrics) {
173 psdoc->free(psdoc, psfont->metrics);
174 }
175
176 if(psfont->encoding) {
177 psdoc->free(psdoc, psfont->encoding);
178 }
179
180 /* FIXME: There is much more to free (e.g. the font metrics) than
181 * just the font structure.
182 */
183 psdoc->free(psdoc, psfont);
184 }
185 /* }}} */
186
187 /* _ps_delete_image() {{{
188 */
_ps_delete_image(PSDoc * psdoc,PSImage * psimage)189 void _ps_delete_image(PSDoc *psdoc, PSImage *psimage) {
190 if(NULL == psdoc) {
191 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
192 return;
193 }
194 if(NULL == psimage) {
195 ps_error(psdoc, PS_RuntimeError, _("PSImage is null."));
196 return;
197 }
198
199 if(psimage->type)
200 psdoc->free(psdoc, psimage->type);
201 if(psimage->data)
202 psdoc->free(psdoc, psimage->data);
203 if(psimage->name)
204 psdoc->free(psdoc, psimage->name);
205 if(psimage->palette)
206 psdoc->free(psdoc, psimage->palette);
207 psdoc->free(psdoc, psimage);
208 }
209 /* }}} */
210
211 /* _ps_delete_pattern() {{{
212 */
_ps_delete_pattern(PSDoc * psdoc,PSPattern * pspattern)213 void _ps_delete_pattern(PSDoc *psdoc, PSPattern *pspattern) {
214 if(NULL == psdoc) {
215 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
216 return;
217 }
218 if(NULL == pspattern) {
219 ps_error(psdoc, PS_RuntimeError, _("PSPattern is null."));
220 return;
221 }
222
223 if(pspattern->name)
224 psdoc->free(psdoc, pspattern->name);
225 psdoc->free(psdoc, pspattern);
226 }
227 /* }}} */
228
229 /* _ps_delete_spotcolor() {{{
230 */
_ps_delete_spotcolor(PSDoc * psdoc,PSSpotColor * spotcolor)231 void _ps_delete_spotcolor(PSDoc *psdoc, PSSpotColor *spotcolor) {
232 if(NULL == psdoc) {
233 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
234 return;
235 }
236 if(NULL == spotcolor) {
237 ps_error(psdoc, PS_RuntimeError, _("PSSpotColor is null."));
238 return;
239 }
240
241 if(spotcolor->name)
242 psdoc->free(psdoc, spotcolor->name);
243 psdoc->free(psdoc, spotcolor);
244 }
245 /* }}} */
246
247 /* _ps_delete_shading() {{{
248 */
_ps_delete_shading(PSDoc * psdoc,PSShading * psshading)249 void _ps_delete_shading(PSDoc *psdoc, PSShading *psshading) {
250 if(NULL == psdoc) {
251 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
252 return;
253 }
254 if(NULL == psshading) {
255 ps_error(psdoc, PS_RuntimeError, _("PSShading is null."));
256 return;
257 }
258
259 if(psshading->name)
260 psdoc->free(psdoc, psshading->name);
261 psdoc->free(psdoc, psshading);
262 }
263 /* }}} */
264
265 /* _ps_delete_gstate() {{{
266 */
_ps_delete_gstate(PSDoc * psdoc,PSGState * gstate)267 void _ps_delete_gstate(PSDoc *psdoc, PSGState *gstate) {
268 if(NULL == psdoc) {
269 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
270 return;
271 }
272 if(NULL == gstate) {
273 ps_error(psdoc, PS_RuntimeError, _("PSGState is null."));
274 return;
275 }
276
277 if(gstate->name)
278 psdoc->free(psdoc, gstate->name);
279 psdoc->free(psdoc, gstate);
280 }
281 /* }}} */
282
283 /* _ps_register_font|image|pattern() {{{
284 * Register font, image with PS document
285 * Returns the font, image id which is the index within the
286 * internal font, image
287 * array + 1. Returns 0 in case of an error.
288 */
289 #define PS_REGISTER_RESOURCE(resname, restype) \
290 static int \
291 _ps_register_##resname(PSDoc *p, restype *resname) \
292 { \
293 int i; \
294 \
295 i = 0; \
296 while(i < p->resname##cnt && p->resname##s[i] != NULL) { \
297 i++; \
298 } \
299 if(i >= p->resname##cnt) { \
300 if(NULL == (p->resname##s = p->realloc(p, p->resname##s, (p->resname##cnt+5) * sizeof(restype *), _("Could not enlarge memory for internal resource array.")))) { \
301 return 0; \
302 } \
303 memset((void *)&p->resname##s[p->resname##cnt], 0, 5*sizeof(restype *)); \
304 p->resname##cnt += 5; \
305 } \
306 p->resname##s[i] = resname; \
307 return(i+1); \
308 }
309
310 #define PS_UNREGISTER_RESOURCE(resname, restype) \
311 static void \
312 _ps_unregister_##resname(PSDoc *p, int id) \
313 { \
314 if(id > p->resname##cnt || id < 1) { \
315 ps_error(p, PS_Warning, _("Trying to unregister a resource which does not exist.")); \
316 return; \
317 } \
318 if(p->resname##s[id-1] != NULL) { \
319 _ps_delete_##resname(p, p->resname##s[id-1]); \
320 p->resname##s[id-1] = NULL; \
321 } else { \
322 ps_error(p, PS_Warning, _("Trying to unregister a resource which does not exist.")); \
323 } \
324 }
325
326 #define PS_FIND_RESOURCE(resname, restype) \
327 static int \
328 _ps_find_##resname(PSDoc *p, restype *ptr) \
329 { \
330 int i; \
331 \
332 i = 0; \
333 while(i < p->resname##cnt) { \
334 if(p->resname##s[i] == ptr) \
335 return(i+1); \
336 i++; \
337 } \
338 return(0); \
339 }
340
341 #define PS_FIND_RESOURCE_BY_NAME(resname, restype) \
342 static int \
343 _ps_find_##resname##_by_name(PSDoc *p, const char *name) \
344 { \
345 int i; \
346 \
347 i = 0; \
348 while(i < p->resname##cnt) { \
349 if(p->resname##s[i] && (0 == strcmp(p->resname##s[i]->name, name))) \
350 return(i+1); \
351 i++; \
352 } \
353 return(0); \
354 }
355
356 #define PS_GET_RESOURCE(resname, restype) \
357 static restype * \
358 _ps_get_##resname(PSDoc *p, int id) \
359 { \
360 if(id > p->resname##cnt || id < 1) { \
361 ps_error(p, PS_Warning, _("Trying to get a resource which does not exist.")); \
362 return NULL; \
363 } \
364 return(p->resname##s[id-1]); \
365 }
366
PS_REGISTER_RESOURCE(font,PSFont)367 PS_REGISTER_RESOURCE(font, PSFont)
368 PS_UNREGISTER_RESOURCE(font, PSFont)
369 PS_FIND_RESOURCE(font, PSFont)
370 PS_FIND_RESOURCE_BY_NAME(font, PSFont)
371 PS_GET_RESOURCE(font, PSFont)
372 PS_REGISTER_RESOURCE(image, PSImage)
373 PS_UNREGISTER_RESOURCE(image, PSImage)
374 PS_FIND_RESOURCE(image, PSImage)
375 PS_FIND_RESOURCE_BY_NAME(image, PSImage)
376 PS_GET_RESOURCE(image, PSImage)
377 PS_REGISTER_RESOURCE(pattern, PSPattern)
378 PS_UNREGISTER_RESOURCE(pattern, PSPattern)
379 PS_FIND_RESOURCE(pattern, PSPattern)
380 PS_FIND_RESOURCE_BY_NAME(pattern, PSPattern)
381 PS_GET_RESOURCE(pattern, PSPattern)
382 PS_REGISTER_RESOURCE(shading, PSShading)
383 PS_UNREGISTER_RESOURCE(shading, PSShading)
384 PS_FIND_RESOURCE(shading, PSShading)
385 PS_FIND_RESOURCE_BY_NAME(shading, PSShading)
386 PS_GET_RESOURCE(shading, PSShading)
387 PS_REGISTER_RESOURCE(spotcolor, PSSpotColor)
388 PS_UNREGISTER_RESOURCE(spotcolor, PSSpotColor)
389 PS_FIND_RESOURCE(spotcolor, PSSpotColor)
390 PS_FIND_RESOURCE_BY_NAME(spotcolor, PSSpotColor)
391 PS_GET_RESOURCE(spotcolor, PSSpotColor)
392 PS_REGISTER_RESOURCE(gstate, PSGState)
393 PS_UNREGISTER_RESOURCE(gstate, PSGState)
394 PS_FIND_RESOURCE(gstate, PSGState)
395 PS_FIND_RESOURCE_BY_NAME(gstate, PSGState)
396 PS_GET_RESOURCE(gstate, PSGState)
397 /* }}} */
398
399 /* ps_output_shading_dict() {{{
400 * Outputs a shading dictionary.
401 */
402 static void ps_output_shading_dict(PSDoc *psdoc, PSShading *psshading) {
403 ps_printf(psdoc, "<<\n");
404 ps_printf(psdoc, " /ShadingType %d\n", psshading->type);
405 if(psshading->type == 3)
406 ps_printf(psdoc, " /Coords [%.2f %.2f %.2f %.2f %.2f %.2f]\n", psshading->x0, psshading->y0, psshading->r0, psshading->x1, psshading->y1, psshading->r1);
407 else
408 ps_printf(psdoc, " /Coords [%.2f %.2f %.2f %.2f]\n", psshading->x0, psshading->y0, psshading->x1, psshading->y1);
409 ps_printf(psdoc, " /Extend [ %s %s ]\n", psshading->extend0 ? "true" : "false", psshading->extend1 ? "true" : "false");
410 ps_printf(psdoc, " /AntiAlias %s\n", psshading->antialias ? "true" : "false");
411 switch(psshading->startcolor.colorspace) {
412 case PS_COLORSPACE_GRAY:
413 ps_printf(psdoc, " /ColorSpace /DeviceGray\n");
414 ps_printf(psdoc, " /Function\n");
415 ps_printf(psdoc, " <<\n");
416 ps_printf(psdoc, " /FunctionType 2 /Domain [ 0 1 ]\n");
417 ps_printf(psdoc, " /C0 [ %.4f ]\n", psshading->startcolor.c1);
418 ps_printf(psdoc, " /C1 [ %.4f ]\n", psshading->endcolor.c1);
419 ps_printf(psdoc, " /N %.4f\n", psshading->N);
420 ps_printf(psdoc, " >>\n");
421 break;
422 case PS_COLORSPACE_RGB:
423 ps_printf(psdoc, " /ColorSpace /DeviceRGB\n");
424 ps_printf(psdoc, " /Function\n");
425 ps_printf(psdoc, " <<\n");
426 ps_printf(psdoc, " /FunctionType 2 /Domain [ 0 1 ]\n");
427 ps_printf(psdoc, " /C0 [ %.4f %.4f %.4f ]\n", psshading->startcolor.c1, psshading->startcolor.c2, psshading->startcolor.c3);
428 ps_printf(psdoc, " /C1 [ %.4f %.4f %.4f ]\n", psshading->endcolor.c1, psshading->endcolor.c2, psshading->endcolor.c3);
429 ps_printf(psdoc, " /N %.4f\n", psshading->N);
430 ps_printf(psdoc, " >>\n");
431 break;
432 case PS_COLORSPACE_CMYK:
433 ps_printf(psdoc, " /ColorSpace /DeviceCMYK\n");
434 ps_printf(psdoc, " /Function\n");
435 ps_printf(psdoc, " <<\n");
436 ps_printf(psdoc, " /FunctionType 2 /Domain [ 0 1 ]\n");
437 ps_printf(psdoc, " /C0 [ %.4f %.4f %.4f %.4f ]\n", psshading->startcolor.c1, psshading->startcolor.c2, psshading->startcolor.c3, psshading->startcolor.c4);
438 ps_printf(psdoc, " /C1 [ %.4f %.4f %.4f %.4f ]\n", psshading->endcolor.c1, psshading->endcolor.c2, psshading->endcolor.c3, psshading->endcolor.c4);
439 ps_printf(psdoc, " /N %.4f\n", psshading->N);
440 ps_printf(psdoc, " >>\n");
441 break;
442 case PS_COLORSPACE_SPOT: {
443 PSSpotColor *spotcolor;
444 spotcolor = _ps_get_spotcolor(psdoc, (int) psshading->startcolor.c1);
445 if(!spotcolor) {
446 ps_error(psdoc, PS_RuntimeError, _("Could not find spot color."));
447 return;
448 }
449 ps_printf(psdoc, " /ColorSpace ");
450 ps_printf(psdoc, "[ /Separation (%s)\n", spotcolor->name);
451 switch(spotcolor->colorspace) {
452 case PS_COLORSPACE_GRAY:
453 ps_printf(psdoc, " /DeviceGray { 1 %f sub mul 1 exch sub }\n", spotcolor->c1);
454 break;
455 case PS_COLORSPACE_RGB: {
456 float max;
457 max = (spotcolor->c1 > spotcolor->c2) ? spotcolor->c1 : spotcolor->c2;
458 max = (max > spotcolor->c3) ? max : spotcolor->c3;
459 ps_printf(psdoc, " /DeviceRGB { 1 exch sub dup dup %f exch sub %f mul add exch dup dup %f exch sub %f mul add exch dup %f exch sub %f mul add }\n", max, spotcolor->c1, max, spotcolor->c2, max, spotcolor->c3);
460 break;
461 }
462 case PS_COLORSPACE_CMYK:
463 ps_printf(psdoc, " /DeviceCMYK { dup %f mul exch dup %f mul exch dup %f mul exch %f mul }\n", spotcolor->c1, spotcolor->c2, spotcolor->c3, spotcolor->c4);
464 break;
465 }
466 ps_printf(psdoc, " ]\n");
467 ps_printf(psdoc, " /Function\n");
468 ps_printf(psdoc, " <<\n");
469 ps_printf(psdoc, " /FunctionType 2 /Domain [ 0 1 ]\n");
470 ps_printf(psdoc, " /C0 [ %.4f ]\n", psshading->startcolor.c2);
471 ps_printf(psdoc, " /C1 [ %.4f ]\n", psshading->endcolor.c2);
472 ps_printf(psdoc, " /N %.4f\n", psshading->N);
473 ps_printf(psdoc, " >>\n");
474 break;
475 }
476 }
477 ps_printf(psdoc, ">>\n");
478 }
479 /* }}} */
480
481 /* Start of API functions */
482
483 /* PS_get_majorversion() {{{
484 * Get major version of library
485 */
486 PSLIB_API int PSLIB_CALL
PS_get_majorversion(void)487 PS_get_majorversion(void) {
488 return(LIBPS_MAJOR_VERSION);
489 }
490 /* }}} */
491
492 /* PS_get_minorversion() {{{
493 * Get minor version of library
494 */
495 PSLIB_API int PSLIB_CALL
PS_get_minorversion(void)496 PS_get_minorversion(void) {
497 return(LIBPS_MINOR_VERSION);
498 }
499 /* }}} */
500
501 /* PS_get_subminorversion() {{{
502 * Get minor version of library
503 */
504 PSLIB_API int PSLIB_CALL
PS_get_subminorversion(void)505 PS_get_subminorversion(void) {
506 return(LIBPS_MICRO_VERSION);
507 }
508 /* }}} */
509
510 /* PS_boot() {{{
511 * Will set text domain, once it works
512 */
513 PSLIB_API void PSLIB_CALL
PS_boot(void)514 PS_boot(void) {
515 #ifdef ENABLE_NLS
516 /* do not call textdomain in a library
517 textdomain (GETTEXT_PACKAGE);
518 */
519 // setlocale(LC_MESSAGES, "");
520 // setlocale(LC_TIME, "");
521 // setlocale(LC_CTYPE, "");
522 // setlocale(LC_ALL, "");
523 bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
524 #endif
525 }
526 /* }}} */
527
528 /* PS_shutdown() {{{
529 * Counter part to PS_boot()
530 */
531 PSLIB_API void PSLIB_CALL
PS_shutdown(void)532 PS_shutdown(void) {
533 }
534 /* }}} */
535
536 /* PS_set_info() {{{
537 * Sets several document information will show up as comments in the Header
538 * of the PostScript document
539 */
540 PSLIB_API void PSLIB_CALL
PS_set_info(PSDoc * p,const char * key,const char * val)541 PS_set_info(PSDoc *p, const char *key, const char *val) {
542 char *val_buf;
543 char *key_buf;
544
545 if(NULL == p) {
546 ps_error(p, PS_RuntimeError, _("PSDoc is null."));
547 return;
548 }
549 if(!ps_check_scope(p, PS_SCOPE_OBJECT|PS_SCOPE_DOCUMENT)) {
550 ps_error(p, PS_RuntimeError, _("%s must be called within 'object', or 'document' scope."), __FUNCTION__);
551 return;
552 }
553
554 if (key == NULL || key[0] == '\0' || val == NULL || val[0] == '\0') {
555 ps_error(p, PS_Warning, _("Empty key or value in PS_set_info()."));
556 return;
557 }
558 if(p->headerwritten == ps_true) {
559 ps_error(p, PS_Warning, _("Calling PS_set_info() has no effect because PostScript header is already written."));
560 }
561
562 val_buf = ps_strdup(p, val);
563 key_buf = ps_strdup(p, key);
564 if (0 == strcmp(key_buf, "Keywords")) {
565 p->Keywords = val_buf;
566 } else if (0 == strcmp(key_buf, "Subject")) {
567 p->Subject = val_buf;
568 } else if (0 == strcmp(key_buf, "Title")) {
569 p->Title = val_buf;
570 } else if (0 == strcmp(key_buf, "Creator")) {
571 p->Creator = val_buf;
572 } else if (0 == strcmp(key_buf, "Author")) {
573 p->Author = val_buf;
574 } else if (0 == strcmp(key_buf, "BoundingBox")) {
575 if(p->BoundingBox)
576 p->free(p, p->BoundingBox);
577 p->BoundingBox = val_buf;
578 } else if (0 == strcmp(key_buf, "Orientation")) {
579 p->Orientation = val_buf;
580 }
581 p->free(p, key_buf);
582 }
583 /* }}} */
584
585 /* PS_new2() {{{
586 * Create a new PostScript document. Allows to set memory management
587 * functions and error handler.
588 */
589 PSLIB_API PSDoc * PSLIB_CALL
PS_new2(void (* errorhandler)(PSDoc * p,int type,const char * msg,void * data),void * (* allocproc)(PSDoc * p,size_t size,const char * caller),void * (* reallocproc)(PSDoc * p,void * mem,size_t size,const char * caller),void (* freeproc)(PSDoc * p,void * mem),void * opaque)590 PS_new2(void (*errorhandler)(PSDoc *p, int type, const char *msg, void *data),
591 void* (*allocproc)(PSDoc *p, size_t size, const char *caller),
592 void* (*reallocproc)(PSDoc *p, void *mem, size_t size, const char *caller),
593 void (*freeproc)(PSDoc *p, void *mem),
594 void *opaque) {
595 PSDoc *p;
596
597 if(allocproc == NULL) {
598 allocproc = _ps_malloc;
599 reallocproc = _ps_realloc;
600 freeproc = _ps_free;
601 }
602 if (errorhandler == NULL)
603 errorhandler = _ps_errorhandler;
604
605 if(NULL == (p = (PSDoc *) (* allocproc) (NULL, sizeof(PSDoc), "PS new"))) {
606 (*errorhandler)(NULL, PS_MemoryError, _("Could not allocate memory for new PS document."), opaque);
607 return(NULL);
608 }
609 memset((void *)p, 0, (size_t) sizeof(PSDoc));
610
611 p->errorhandler = errorhandler;
612 p->user_data = opaque;
613 p->malloc = allocproc;
614 p->realloc = reallocproc;
615 p->free = freeproc;
616 p->fp = NULL;
617 p->sb = NULL;
618 p->copies = 1;
619 p->warnings = ps_true;
620 p->inputenc = ps_get_inputencoding("ISO-8859-1"); //&inputencoding;
621 p->hdict = NULL;
622 p->hdictfilename = NULL;
623 p->categories = dlst_init(allocproc, reallocproc, freeproc);
624 p->parameters = dlst_init(allocproc, reallocproc, freeproc);
625 p->values = dlst_init(allocproc, reallocproc, freeproc);
626 p->bookmarks = dlst_init(allocproc, reallocproc, freeproc);
627 p->lastbookmarkid = 0;
628 p->bookmarkdict = NULL;
629 p->bookmarkcnt = 0;
630 p->CreationDate = NULL;
631
632 /* Initialize list of fonts */
633 p->fontcnt = 5;
634 if(NULL == (p->fonts = p->malloc(p, p->fontcnt*sizeof(PSFont *), _("Allocate memory for internal Font list of document.")))) {
635 return(NULL);
636 }
637 memset((void *)p->fonts, 0, p->fontcnt*sizeof(PSFont *));
638
639 /* Initialize list of images */
640 p->imagecnt = 5;
641 if(NULL == (p->images = p->malloc(p, p->imagecnt*sizeof(PSImage *), _("Allocate memory for internal Image list of document.")))) {
642 return(NULL);
643 }
644 memset((void *)p->images, 0, p->imagecnt*sizeof(PSImage *));
645
646 /* Initialize list of patterns */
647 p->patterncnt = 5;
648 if(NULL == (p->patterns = p->malloc(p, p->patterncnt*sizeof(PSPattern *), _("Allocate memory for internal Pattern list of document.")))) {
649 return(NULL);
650 }
651 memset((void *)p->patterns, 0, p->patterncnt*sizeof(PSPattern *));
652
653 /* Initialize list of spot colors */
654 p->spotcolorcnt = 5;
655 if(NULL == (p->spotcolors = p->malloc(p, p->spotcolorcnt*sizeof(PSSpotColor *), _("Allocate memory for internal spot color list of document.")))) {
656 return(NULL);
657 }
658 memset((void *)p->spotcolors, 0, p->spotcolorcnt*sizeof(PSSpotColor *));
659
660 /* Initialize list of shadings */
661 p->shadingcnt = 5;
662 if(NULL == (p->shadings = p->malloc(p, p->shadingcnt*sizeof(PSShading *), _("Allocate memory for internal Shading list of document.")))) {
663 return(NULL);
664 }
665 memset((void *)p->shadings, 0, p->shadingcnt*sizeof(PSShading *));
666
667 /* Initialize list of graphic states*/
668 p->gstatecnt = 5;
669 if(NULL == (p->gstates = p->malloc(p, p->gstatecnt*sizeof(PSGState *), _("Allocate memory for internal graphic state list of document.")))) {
670 return(NULL);
671 }
672 memset((void *)p->gstates, 0, p->gstatecnt*sizeof(PSGState *));
673
674 p->agstate = 0;
675 p->agstates[0].x = 0.0;
676 p->agstates[0].y = 0.0;
677 p->agstates[0].strokecolor.colorspace = PS_COLORSPACE_GRAY;
678 p->agstates[0].strokecolor.c1 = 0.0;
679 p->agstates[0].strokecolorinvalid = ps_false;
680 p->agstates[0].fillcolor.colorspace = PS_COLORSPACE_GRAY;
681 p->agstates[0].fillcolor.c1 = 0.0;
682 p->agstates[0].fillcolorinvalid = ps_false;
683 p->tstate = 0;
684 p->tstates[0].tx = 0.0;
685 p->tstates[0].ty = 0.0;
686 p->tstates[0].cx = 0.0;
687 p->tstates[0].cy = 0.0;
688 p->closefp = ps_false;
689 p->page_open = ps_false;
690 p->doc_open = ps_false;
691 p->scopecount = 0;
692 p->scopes[0] = PS_SCOPE_OBJECT;
693 p->headerwritten = ps_false;
694 p->commentswritten = ps_false;
695 p->beginprologwritten = ps_false;
696 p->endprologwritten = ps_false;
697 p->setupwritten = ps_false;
698 p->border_width = 1.0;
699 p->border_style = PS_BORDER_SOLID;
700 p->border_black = 3.0;
701 p->border_white = 3.0;
702 p->border_red = 0.0;
703 p->border_green = 0.0;
704 p->border_blue = 1.0;
705 p->textrendering = -1;
706
707 return(p);
708 }
709 /* }}} */
710
711 /* PS_new() {{{
712 * Create a new PostScript Document. Use the internal memory management
713 * functions and error handler.
714 */
715 PSLIB_API PSDoc * PSLIB_CALL
PS_new(void)716 PS_new(void) {
717 return(PS_new2(NULL, NULL, NULL, NULL, NULL));
718 }
719 /* }}} */
720
721 /* PS_get_opaque() {{{
722 * Returns the pointer on the user data as it is passed to each call
723 * of the errorhandler.
724 */
725 PSLIB_API void * PSLIB_CALL
PS_get_opaque(PSDoc * psdoc)726 PS_get_opaque(PSDoc *psdoc) {
727 if(NULL == psdoc) {
728 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
729 return(NULL);
730 }
731 return(psdoc->user_data);
732 }
733 /* }}} */
734
735 /* ps_write_ps_comments() {{{ */
ps_write_ps_comments(PSDoc * psdoc)736 static void ps_write_ps_comments(PSDoc *psdoc) {
737 int i;
738 time_t ps_calendar_time;
739 struct tm *ps_local_tm;
740 if(NULL != (psdoc->CreationDate = psdoc->malloc(psdoc, LINEBUFLEN/2, _("Allocate memory for PS header field 'CreationTime'.")))) {
741 ps_calendar_time = time(NULL);
742 if(ps_calendar_time == (time_t)(-1)) {
743 sprintf(psdoc->CreationDate,"%s","20/3/2001 3:30 AM");
744 } else {
745 ps_local_tm = localtime(&ps_calendar_time);
746 strftime(psdoc->CreationDate, LINEBUFLEN/2, "%d/%m/%Y %I:%M %p", ps_local_tm);
747 }
748 } else {
749 ps_error(psdoc, PS_MemoryError, _("Cannot allocate memory for PS header field 'CreationTime'."));
750 }
751
752 ps_printf(psdoc, "%%!PS-Adobe-3.0\n");
753 if(psdoc->Creator)
754 ps_printf(psdoc, "%%%%Creator: %s (%s)\n", psdoc->Creator, "pslib " LIBPS_DOTTED_VERSION);
755 else
756 ps_printf(psdoc, "%%%%Creator: %s\n", "pslib " LIBPS_DOTTED_VERSION);
757 if(psdoc->CreationDate) {
758 ps_printf(psdoc, "%%%%Creation-Date: %s\n", psdoc->CreationDate);
759 }
760 if(psdoc->Title)
761 ps_printf(psdoc, "%%%%Title: %s\n", psdoc->Title);
762 if(psdoc->Author)
763 ps_printf(psdoc, "%%%%Author: %s\n", psdoc->Author);
764 ps_printf(psdoc, "%%%%PageOrder: Ascend\n");
765 ps_printf(psdoc, "%%%%Pages: (atend)\n");
766 if(psdoc->BoundingBox) {
767 ps_printf(psdoc, "%%%%BoundingBox: %s\n", psdoc->BoundingBox);
768 } else {
769 ps_printf(psdoc, "%%%%BoundingBox: (atend)\n");
770 }
771 if(psdoc->Orientation)
772 ps_printf(psdoc, "%%%%Orientation: %s\n", psdoc->Orientation);
773 else
774 ps_printf(psdoc, "%%%%Orientation: (atend)\n");
775 ps_printf(psdoc, "%%%%DocumentProcessColors: Black\n");
776 ps_printf(psdoc, "%%%%DocumentCustomColors: \n");
777 for(i=0; i<psdoc->spotcolorcnt; i++) {
778 PSSpotColor *spotcolor = psdoc->spotcolors[i];
779 if(NULL != spotcolor)
780 ps_printf(psdoc, "%%%%+ (%s)\n", spotcolor->name);
781 }
782 ps_printf(psdoc, "%%%%CMYKCustomColor: \n");
783 for(i=0; i<psdoc->spotcolorcnt; i++) {
784 PSSpotColor *spotcolor = psdoc->spotcolors[i];
785 if(NULL != spotcolor && spotcolor->colorspace == PS_COLORSPACE_CMYK)
786 ps_printf(psdoc, "%%%%+ %f %f %f %f (%s)\n", spotcolor->c1, spotcolor->c2, spotcolor->c3, spotcolor->c4, spotcolor->name);
787 }
788 ps_printf(psdoc, "%%%%RGBCustomColor: \n");
789 for(i=0; i<psdoc->spotcolorcnt; i++) {
790 PSSpotColor *spotcolor = psdoc->spotcolors[i];
791 if(NULL != spotcolor && spotcolor->colorspace == PS_COLORSPACE_RGB)
792 ps_printf(psdoc, "%%%%+ %f %f %f (%s)\n", spotcolor->c1, spotcolor->c2, spotcolor->c3, spotcolor->name);
793 }
794 ps_printf(psdoc, "%%%%EndComments\n");
795 psdoc->commentswritten = ps_true;
796 }
797 /* }}} */
798
799 /* ps_write_ps_beginprolog() {{{ */
ps_write_ps_beginprolog(PSDoc * psdoc)800 static void ps_write_ps_beginprolog(PSDoc *psdoc) {
801 ps_enter_scope(psdoc, PS_SCOPE_PROLOG);
802 ps_printf(psdoc, "%%%%BeginProlog\n");
803 ps_printf(psdoc, "%%%%BeginResource: definicoes\n");
804 ps_printf(psdoc, "%%%%EndResource\n");
805 ps_printf(psdoc, "%%%%BeginProcSet: standard\n");
806
807 ps_printf(psdoc, "/PslibDict 300 dict def PslibDict begin/N{def}def/B{bind def}N\n");
808 ps_printf(psdoc, "/TR{translate}N/vsize 11 72 mul N/hsize 8.5 72 mul N/isls false N\n");
809 ps_printf(psdoc, "/p{show}N/w{0 rmoveto}B/a{moveto}B/l{lineto}B");
810 ps_printf(psdoc, "/qs{currentpoint\n");
811 ps_printf(psdoc, "currentpoint newpath moveto 3 2 roll dup true charpath stroke\n");
812 ps_printf(psdoc, "stringwidth pop 3 2 roll add exch moveto}B");
813 ps_printf(psdoc, "/qf{currentpoint\n");
814 ps_printf(psdoc, "currentpoint newpath moveto 3 2 roll dup true charpath fill\n");
815 ps_printf(psdoc, "stringwidth pop 3 2 roll add exch moveto}B");
816 ps_printf(psdoc, "/qsf{currentpoint\n");
817 ps_printf(psdoc, "currentpoint newpath moveto 3 2 roll dup true charpath gsave stroke grestore fill\n");
818 ps_printf(psdoc, "stringwidth pop 3 2 roll add exch moveto}B");
819 ps_printf(psdoc, "/qc{currentpoint\n");
820 ps_printf(psdoc, "currentpoint newpath moveto 3 2 roll dup true charpath clip\n");
821 ps_printf(psdoc, "stringwidth pop 3 2 roll add exch moveto}B");
822 ps_printf(psdoc, "/qsc{currentpoint\n");
823 ps_printf(psdoc, "currentpoint initclip newpath moveto 3 2 roll dup true charpath clip stroke\n");
824 ps_printf(psdoc, "stringwidth pop 3 2 roll add exch moveto}B");
825 ps_printf(psdoc, "/qfc{currentpoint\n");
826 ps_printf(psdoc, "currentpoint initclip newpath moveto 3 2 roll dup true charpath clip fill\n");
827 ps_printf(psdoc, "stringwidth pop 3 2 roll add exch moveto}B");
828 ps_printf(psdoc, "/qfsc{currentpoint\n");
829 ps_printf(psdoc, "currentpoint initclip newpath moveto 3 2 roll dup true charpath gsave stroke grestore clip fill\n");
830 ps_printf(psdoc, "stringwidth pop 3 2 roll add exch moveto}B");
831 ps_printf(psdoc, "/qi{currentpoint\n");
832 ps_printf(psdoc, "3 2 roll\n");
833 ps_printf(psdoc, "stringwidth pop 3 2 roll add exch moveto}B");
834 ps_printf(psdoc, "/tr{currentpoint currentpoint 5 4 roll add moveto}B");
835 ps_printf(psdoc, "/rt{moveto}B");
836 ps_printf(psdoc, "/#copies{1}B\n");
837 ps_printf(psdoc, "/PslibPageBeginHook{pop pop pop pop pop}B\n");
838 ps_printf(psdoc, "/PslibPageEndHook{pop}B\n");
839 ps_printf(psdoc, "\n");
840
841 ps_printf(psdoc, "/reencdict 12 dict def /ReEncode { reencdict begin\n");
842 ps_printf(psdoc, "/newcodesandnames exch def /newfontname exch def /basefontname exch def\n");
843 ps_printf(psdoc, "/basefontdict basefontname findfont def /newfont basefontdict maxlength dict def\n");
844 ps_printf(psdoc, "basefontdict { exch dup /FID ne { dup /Encoding eq\n");
845 ps_printf(psdoc, "{ exch dup length array copy newfont 3 1 roll put }\n");
846 ps_printf(psdoc, "{ exch newfont 3 1 roll put } ifelse } { pop pop } ifelse } forall\n");
847 ps_printf(psdoc, "newfont /FontName newfontname put newcodesandnames aload pop\n");
848 ps_printf(psdoc, "128 1 255 { newfont /Encoding get exch /.notdef put } for\n");
849 ps_printf(psdoc, "newcodesandnames length 2 idiv { newfont /Encoding get 3 1 roll put } repeat\n");
850 ps_printf(psdoc, "newfontname newfont definefont pop end } def\n");
851 ps_printf(psdoc, "end\n");
852 ps_printf(psdoc, "%%%%EndProcSet\n");
853 ps_printf(psdoc, "%%%%BeginProcSet: colorsep\n");
854 ps_printf(psdoc, "%%!\n");
855 ps_printf(psdoc, "%% Colour separation.\n");
856 ps_printf(psdoc, "%% Ask dvips to do 4 pages. In bop-hook, cycle\n");
857 ps_printf(psdoc, "%% round CMYK color spaces.\n");
858 ps_printf(psdoc, "%%\n");
859 ps_printf(psdoc, "%% Sebastian Rahtz 30.9.93\n");
860 ps_printf(psdoc, "%% checked 7.1.94\n");
861 ps_printf(psdoc, "%% from Green Book, and Kunkel Graphic Design with PostScript\n");
862 ps_printf(psdoc, "%% (Green Book Listing 9-5, on page 153.)\n");
863 ps_printf(psdoc, "%%\n");
864 ps_printf(psdoc, "%% This work is placed in the public domain\n");
865 ps_printf(psdoc, "/seppages 0 def \n");
866 ps_printf(psdoc, "userdict begin\n");
867 ps_printf(psdoc, "/Min {%% 3 items on stack\n");
868 ps_printf(psdoc, "2 copy lt { pop }{ exch pop } ifelse\n");
869 ps_printf(psdoc, "2 copy lt { pop }{ exch pop } ifelse\n");
870 ps_printf(psdoc, "} def\n");
871 ps_printf(psdoc, "/SetGray {\n");
872 ps_printf(psdoc, " 1 exch sub systemdict begin adjustdot setgray end \n");
873 ps_printf(psdoc, "} def\n");
874 ps_printf(psdoc, "/sethsbcolor {systemdict begin\n");
875 ps_printf(psdoc, " sethsbcolor currentrgbcolor end\n");
876 ps_printf(psdoc, " userdict begin setrgbcolor end}def \n");
877 ps_printf(psdoc, "\n");
878 ps_printf(psdoc, "/ToCMYK\n");
879 ps_printf(psdoc, "%% Red book p 305\n");
880 ps_printf(psdoc, " {\n");
881 ps_printf(psdoc, "%% subtract each colour from 1\n");
882 ps_printf(psdoc, " 3 { 1 exch sub 3 1 roll } repeat\n");
883 ps_printf(psdoc, "%% define percent of black undercolor\n");
884 ps_printf(psdoc, "%% find minimum (k)\n");
885 ps_printf(psdoc, " 3 copy Min \n");
886 ps_printf(psdoc, "%% remove undercolor\n");
887 ps_printf(psdoc, " blackUCR sub\n");
888 ps_printf(psdoc, " dup 0 lt {pop 0} if \n");
889 ps_printf(psdoc, " /percent_UCR exch def \n");
890 ps_printf(psdoc, "%%\n");
891 ps_printf(psdoc, "%% subtract that from each colour\n");
892 ps_printf(psdoc, "%%\n");
893 ps_printf(psdoc, " 3 { percent_UCR sub 3 1 roll } repeat \n");
894 ps_printf(psdoc, "%% work out black itself\n");
895 ps_printf(psdoc, " percent_UCR 1.25 mul %% 1 exch sub\n");
896 ps_printf(psdoc, "%% stack should now have C M Y K\n");
897 ps_printf(psdoc, "} def \n");
898 ps_printf(psdoc, "%%\n");
899 ps_printf(psdoc, "%% crop marks\n");
900 ps_printf(psdoc, "%%\n");
901 ps_printf(psdoc, "/cX 18 def \n");
902 ps_printf(psdoc, "/CM{gsave TR 0 cX neg moveto 0 cX lineto stroke\n");
903 ps_printf(psdoc, "cX neg 0 moveto cX 0 lineto stroke grestore}def \n");
904 ps_printf(psdoc, "%%\n");
905 ps_printf(psdoc, "/bop-hook{cX dup TR\n");
906 ps_printf(psdoc, "%%\n");
907 ps_printf(psdoc, "%% which page are we producing\n");
908 ps_printf(psdoc, "%%\n");
909 ps_printf(psdoc, " seppages 1 add \n");
910 ps_printf(psdoc, " /seppages exch def\n");
911 ps_printf(psdoc, " seppages 5 eq { /seppages 1 def } if\n");
912 ps_printf(psdoc, " seppages 1 eq { \n");
913 ps_printf(psdoc, " /ColourName (CYAN) def \n");
914 ps_printf(psdoc, " CYAN setupcolor \n");
915 ps_printf(psdoc, " /WhichColour 3 def } if \n");
916 ps_printf(psdoc, " seppages 2 eq { \n");
917 ps_printf(psdoc, " /ColourName (MAGENTA) def \n");
918 ps_printf(psdoc, " MAGENTA setupcolor \n");
919 ps_printf(psdoc, " /WhichColour 2 def } if\n");
920 ps_printf(psdoc, " seppages 3 eq { \n");
921 ps_printf(psdoc, " /ColourName (YELLOW) def\n");
922 ps_printf(psdoc, " YELLOW setupcolor \n");
923 ps_printf(psdoc, " /WhichColour 1 def } if \n");
924 ps_printf(psdoc, " seppages 4 eq { \n");
925 ps_printf(psdoc, " /ColourName (BLACK) def \n");
926 ps_printf(psdoc, " BLACK setupcolor \n");
927 ps_printf(psdoc, " /WhichColour 0 def } if \n");
928 ps_printf(psdoc, "%%\n");
929 ps_printf(psdoc, "%% crop marks\n");
930 ps_printf(psdoc, "%%\n");
931 ps_printf(psdoc, "gsave .3 setlinewidth \n");
932 ps_printf(psdoc, "3 -7 moveto\n");
933 ps_printf(psdoc, "/Helvetica findfont 6 scalefont setfont\n");
934 ps_printf(psdoc, "ColourName show\n");
935 ps_printf(psdoc, "0 0 CM \n");
936 ps_printf(psdoc, "vsize cX 2 mul sub dup hsize cX 2 mul sub dup isls{4 2 roll}if 0 CM \n");
937 ps_printf(psdoc, "exch CM 0 \n");
938 ps_printf(psdoc, "exch CM \n");
939 ps_printf(psdoc, "grestore 0 cX -2 mul TR isls\n");
940 ps_printf(psdoc, "{cX -2 mul 0 TR}if\n");
941 ps_printf(psdoc, " } def end\n");
942 ps_printf(psdoc, "%% \n");
943 ps_printf(psdoc, "/separations 48 dict def\n");
944 ps_printf(psdoc, "separations begin\n");
945 ps_printf(psdoc, " /cmykprocs [ %%def\n");
946 ps_printf(psdoc, " %% cyan\n");
947 ps_printf(psdoc, " { pop pop pop SetGray }\n");
948 ps_printf(psdoc, " %% magenta\n");
949 ps_printf(psdoc, " { pop pop exch pop SetGray }\n");
950 ps_printf(psdoc, " %% yellow\n");
951 ps_printf(psdoc, " { pop 3 1 roll pop pop SetGray }\n");
952 ps_printf(psdoc, " %% black\n");
953 ps_printf(psdoc, " { 4 1 roll pop pop pop SetGray }\n");
954 ps_printf(psdoc, " ] def\n");
955 ps_printf(psdoc, " /rgbprocs [ %%def\n");
956 ps_printf(psdoc, " %% cyan\n");
957 ps_printf(psdoc, " { ToCMYK pop pop pop SetGray }\n");
958 ps_printf(psdoc, " %% magenta\n");
959 ps_printf(psdoc, " { ToCMYK pop pop exch pop SetGray }\n");
960 ps_printf(psdoc, " %% yellow\n");
961 ps_printf(psdoc, " { ToCMYK pop 3 1 roll pop pop SetGray }\n");
962 ps_printf(psdoc, " %% black\n");
963 ps_printf(psdoc, " { ToCMYK 4 1 roll pop pop pop SetGray }\n");
964 ps_printf(psdoc, " ] def\n");
965 ps_printf(psdoc, " /testprocs [ %%def\n");
966 ps_printf(psdoc, " %% cyan\n");
967 ps_printf(psdoc, " { ToCMYK pop pop pop }\n");
968 ps_printf(psdoc, " %% magenta\n");
969 ps_printf(psdoc, " { ToCMYK pop pop exch pop }\n");
970 ps_printf(psdoc, " %% yellow\n");
971 ps_printf(psdoc, " { ToCMYK pop 3 1 roll pop pop }\n");
972 ps_printf(psdoc, " %% black\n");
973 ps_printf(psdoc, " { ToCMYK 4 1 roll pop pop pop }\n");
974 ps_printf(psdoc, " ] def\n");
975 ps_printf(psdoc, " /screenangles [ %%def\n");
976 ps_printf(psdoc, " 105 %% cyan\n");
977 ps_printf(psdoc, " 75 %% magenta\n");
978 ps_printf(psdoc, " 0 %% yellow\n");
979 ps_printf(psdoc, " 45 %% black\n");
980 ps_printf(psdoc, " ] def\n");
981 ps_printf(psdoc, "end %% separations\n");
982 ps_printf(psdoc, "\n");
983 ps_printf(psdoc, "%% setupcolortakes 0, 1, 2, or 3 as its argument,\n");
984 ps_printf(psdoc, "%% for cyan, magenta, yellow, and black.\n");
985 ps_printf(psdoc, "/CYAN 0 def /MAGENTA 1 def\n");
986 ps_printf(psdoc, "/YELLOW 2 def /BLACK 3 def\n");
987 ps_printf(psdoc, "/setupcolor{ %%def\n");
988 ps_printf(psdoc, " userdict begin\n");
989 ps_printf(psdoc, " dup separations /cmykprocs get exch get\n");
990 ps_printf(psdoc, " /setcmykcolor exch def\n");
991 ps_printf(psdoc, " dup separations /rgbprocs get exch get\n");
992 ps_printf(psdoc, " /setrgbcolor exch def\n");
993 ps_printf(psdoc, " dup separations /testprocs get exch get\n");
994 ps_printf(psdoc, " /testrgbcolor exch def\n");
995 ps_printf(psdoc, " separations /screenangles get exch get\n");
996 ps_printf(psdoc, " currentscreen\n");
997 ps_printf(psdoc, " exch pop 3 -1 roll exch\n");
998 ps_printf(psdoc, " setscreen\n");
999 ps_printf(psdoc, " /setscreen { pop pop pop } def\n");
1000 ps_printf(psdoc, "%%\n");
1001 ps_printf(psdoc, "%% redefine setgray so that it only shows on the black separation\n");
1002 ps_printf(psdoc, "%%\n");
1003 ps_printf(psdoc, " /setgray {\n");
1004 ps_printf(psdoc, " WhichColour 0 eq\n");
1005 ps_printf(psdoc, " {systemdict begin adjustdot setgray end} \n");
1006 ps_printf(psdoc, " {pop systemdict begin 1 setgray end}\n");
1007 ps_printf(psdoc, " ifelse}def \n");
1008 ps_printf(psdoc, " end\n");
1009 ps_printf(psdoc, "} bind def\n");
1010 ps_printf(psdoc, "\n");
1011 ps_printf(psdoc, "%%\n");
1012 ps_printf(psdoc, "%% from Kunkel\n");
1013 ps_printf(psdoc, "%%\n");
1014 ps_printf(psdoc, "/adjustdot { dup 0 eq { } { dup 1 exch sub .1 mul add} ifelse } def\n");
1015 ps_printf(psdoc, "%%\n");
1016 ps_printf(psdoc, "%% redefine existing operators\n");
1017 ps_printf(psdoc, "%%\n");
1018 ps_printf(psdoc, "%% Percent of undercolor removal\n");
1019 ps_printf(psdoc, "/magentaUCR .3 def \n");
1020 ps_printf(psdoc, "/yellowUCR .07 def \n");
1021 ps_printf(psdoc, "/blackUCR .4 def \n");
1022 ps_printf(psdoc, "%%\n");
1023 ps_printf(psdoc, "%% Correct yellow and magenta\n");
1024 ps_printf(psdoc, "/correctMY {rgb2cym\n");
1025 ps_printf(psdoc, " 1 index yellowUCR mul sub 3 1 roll\n");
1026 ps_printf(psdoc, " 1 index magentaUCR mul sub 3 1 roll\n");
1027 ps_printf(psdoc, " 3 1 roll rgb2cym}def\n");
1028 ps_printf(psdoc, "%% \n");
1029 ps_printf(psdoc, "%%(bluely green ) =\n");
1030 ps_printf(psdoc, "%%CYAN setupcolor\n");
1031 ps_printf(psdoc, "%%.1 .4 .5 testrgbcolor =\n");
1032 ps_printf(psdoc, "%%MAGENTA setupcolor\n");
1033 ps_printf(psdoc, "%%.1 .4 .5 testrgbcolor =\n");
1034 ps_printf(psdoc, "%%YELLOW setupcolor\n");
1035 ps_printf(psdoc, "%%.1 .4 .5 testrgbcolor =\n");
1036 ps_printf(psdoc, "%%BLACK setupcolor\n");
1037 ps_printf(psdoc, "%%.1 .4 .5 testrgbcolor =\n");
1038 ps_printf(psdoc, "%%quit\n");
1039 ps_printf(psdoc, "%%%%EndProcSet\n");
1040
1041 /* The fontenc vector is placed outside the PslibDict dictionary */
1042 {
1043 int i, j;
1044 ENCODING *fontenc;
1045 fontenc = &fontencoding[0];
1046 ps_printf(psdoc, "/fontenc-%s [\n", fontenc->name);
1047 for(i=0; i<32; i++) {
1048 for(j=0; j<8; j++) {
1049 if((fontenc->vec[i*8+j] != NULL) && (*(fontenc->vec[i*8+j]) != '\0'))
1050 ps_printf(psdoc, "8#%03o /%s ", i*8+j, fontenc->vec[i*8+j]);
1051 }
1052 ps_printf(psdoc, "\n");
1053 }
1054 ps_printf(psdoc, "] def\n");
1055 }
1056
1057 ps_printf(psdoc, "/pdfmark where {pop} {userdict /pdfmark /cleartomark load put} ifelse\n");
1058 if(psdoc->Creator)
1059 ps_printf(psdoc, "[ /Creator (%s \\(%s\\))\n", psdoc->Creator, "pslib " LIBPS_DOTTED_VERSION);
1060 else
1061 ps_printf(psdoc, "[ /Creator (%s)\n", "pslib " LIBPS_DOTTED_VERSION);
1062 if(psdoc->CreationDate) {
1063 ps_printf(psdoc, " /Creation-Date (%s)\n", psdoc->CreationDate);
1064 }
1065 if(psdoc->Title)
1066 ps_printf(psdoc, " /Title (%s)\n", psdoc->Title);
1067 if(psdoc->Author)
1068 ps_printf(psdoc, " /Author (%s)\n", psdoc->Author);
1069 if(psdoc->Keywords)
1070 ps_printf(psdoc, " /Keywords (%s)\n", psdoc->Keywords);
1071 if(psdoc->Subject)
1072 ps_printf(psdoc, " /Subject (%s)\n", psdoc->Subject);
1073 ps_printf(psdoc, "/DOCINFO pdfmark\n");
1074 psdoc->beginprologwritten = ps_true;
1075 }
1076 /* }}} */
1077
1078 /* ps_write_ps_endprolog() {{{ */
ps_write_ps_endprolog(PSDoc * psdoc)1079 static void ps_write_ps_endprolog(PSDoc *psdoc) {
1080 ps_printf(psdoc, "%%%%EndProlog\n");
1081 ps_leave_scope(psdoc, PS_SCOPE_PROLOG);
1082 psdoc->endprologwritten = ps_true;
1083 }
1084 /* }}} */
1085
1086 /* ps_write_ps_setup() {{{ */
ps_write_ps_setup(PSDoc * psdoc)1087 static void ps_write_ps_setup(PSDoc *psdoc) {
1088 ps_printf(psdoc, "%%%%BeginSetup\n");
1089 ps_printf(psdoc, "PslibDict begin\n");
1090 if(psdoc->copies > 1)
1091 ps_printf(psdoc, "/#copies %d def\n", psdoc->copies);
1092 ps_printf(psdoc, "%%%%EndSetup\n");
1093 psdoc->setupwritten = ps_true;
1094 }
1095 /* }}} */
1096
1097 /* ps_write_ps_header() {{{
1098 * Write the PostScript header
1099 */
ps_write_ps_header(PSDoc * psdoc)1100 static void ps_write_ps_header(PSDoc *psdoc) {
1101 if(psdoc->headerwritten == ps_true)
1102 return;
1103 if(psdoc->commentswritten == ps_false)
1104 ps_write_ps_comments(psdoc);
1105 if(psdoc->beginprologwritten == ps_false)
1106 ps_write_ps_beginprolog(psdoc);
1107 if(psdoc->endprologwritten == ps_false)
1108 ps_write_ps_endprolog(psdoc);
1109 if(psdoc->setupwritten == ps_false)
1110 ps_write_ps_setup(psdoc);
1111 psdoc->headerwritten = ps_true;
1112 }
1113 /* }}} */
1114
1115 /* ps_setcolor() {{{
1116 * Outputs PostScript commands to set the color, but checks before
1117 * if it was already set. whichcolor is either PS_COLORTYPE_FILL
1118 * or PS_COLORTYPE_STROKE. The function only outputs something if
1119 * [fill|stroke]colorinvalid is set. [fill|stroke]colorinvalid is set
1120 * when the color is set by PS_setcolor() or this function has set
1121 * the fill or stroke color.
1122 */
ps_setcolor(PSDoc * psdoc,int whichcolor)1123 static void ps_setcolor(PSDoc *psdoc, int whichcolor) {
1124 PSColor *currentcolor = NULL;
1125
1126 if(ps_check_scope(psdoc, PS_SCOPE_PATTERN)) {
1127 if(psdoc->pattern->painttype == 2) {
1128 ps_error(psdoc, PS_Warning, _("Setting color inside a pattern of PaintType 2 is not allowed."), __FUNCTION__);
1129 return;
1130 }
1131 }
1132
1133 switch(whichcolor) {
1134 case PS_COLORTYPE_FILL:
1135 if(psdoc->agstates[psdoc->agstate].fillcolorinvalid) {
1136 psdoc->agstates[psdoc->agstate].strokecolorinvalid = ps_true;
1137 psdoc->agstates[psdoc->agstate].fillcolorinvalid = ps_false;
1138 currentcolor = &(psdoc->agstates[psdoc->agstate].fillcolor);
1139 }
1140 break;
1141 case PS_COLORTYPE_STROKE:
1142 if(psdoc->agstates[psdoc->agstate].strokecolorinvalid) {
1143 psdoc->agstates[psdoc->agstate].fillcolorinvalid = ps_true;
1144 psdoc->agstates[psdoc->agstate].strokecolorinvalid = ps_false;
1145 currentcolor = &(psdoc->agstates[psdoc->agstate].strokecolor);
1146 }
1147 break;
1148 }
1149 if(currentcolor) {
1150 switch(currentcolor->colorspace) {
1151 case PS_COLORSPACE_GRAY:
1152 ps_printf(psdoc, "%f setgray\n", currentcolor->c1);
1153 break;
1154 case PS_COLORSPACE_RGB:
1155 ps_printf(psdoc, "%.4f %.4f %.4f setrgbcolor\n", currentcolor->c1, currentcolor->c2, currentcolor->c3);
1156 break;
1157 case PS_COLORSPACE_CMYK:
1158 ps_printf(psdoc, "%.4f %.4f %.4f %.4f setcmykcolor\n", currentcolor->c1, currentcolor->c2, currentcolor->c3, currentcolor->c4);
1159 break;
1160 case PS_COLORSPACE_PATTERN: {
1161 PSPattern *pspattern = _ps_get_pattern(psdoc, (int) currentcolor->pattern);
1162 if(NULL == pspattern) {
1163 ps_error(psdoc, PS_RuntimeError, _("PSPattern is null."));
1164 return;
1165 }
1166 if(pspattern->painttype == 1) {
1167 ps_printf(psdoc, "%s setpattern\n", pspattern->name);
1168 } else {
1169 ps_printf(psdoc, "[/Pattern [/");
1170 switch(currentcolor->prevcolorspace) {
1171 case PS_COLORSPACE_GRAY:
1172 ps_printf(psdoc, "DeviceGray]] setcolorspace\n");
1173 ps_printf(psdoc, "%.4f %s setcolor\n", currentcolor->c1, pspattern->name);
1174 break;
1175 case PS_COLORSPACE_CMYK:
1176 ps_printf(psdoc, "DeviceCMYK]] setcolorspace\n");
1177 ps_printf(psdoc, "%.4f %.4f %.4f %.4f %s setcolor\n", currentcolor->c1, currentcolor->c2, currentcolor->c3, currentcolor->c4, pspattern->name);
1178 break;
1179 case PS_COLORSPACE_RGB:
1180 ps_printf(psdoc, "DeviceRGB]] setcolorspace\n");
1181 ps_printf(psdoc, "%.4f %.4f %.4f %s setcolor\n", currentcolor->c1, currentcolor->c2, currentcolor->c3, pspattern->name);
1182 break;
1183 case PS_COLORSPACE_SPOT: {
1184 PSSpotColor *spotcolor;
1185 spotcolor = _ps_get_spotcolor(psdoc, (int) currentcolor->c1);
1186 if(!spotcolor) {
1187 ps_error(psdoc, PS_RuntimeError, _("Could not find spot color."));
1188 return;
1189 }
1190 ps_printf(psdoc, "Separation (%s)\n", spotcolor->name);
1191 switch(spotcolor->colorspace) {
1192 case PS_COLORSPACE_GRAY:
1193 ps_printf(psdoc, " /DeviceGray { 1 %f sub mul 1 exch sub }\n", spotcolor->c1);
1194 break;
1195 case PS_COLORSPACE_RGB: {
1196 float max;
1197 max = (spotcolor->c1 > spotcolor->c2) ? spotcolor->c1 : spotcolor->c2;
1198 max = (max > spotcolor->c3) ? max : spotcolor->c3;
1199 ps_printf(psdoc, " /DeviceRGB { 1 exch sub dup dup %f exch sub %f mul add exch dup dup %f exch sub %f mul add exch dup %f exch sub %f mul add }\n", max, spotcolor->c1, max, spotcolor->c2, max, spotcolor->c3);
1200 break;
1201 }
1202 case PS_COLORSPACE_CMYK:
1203 ps_printf(psdoc, " /DeviceCMYK { dup %f mul exch dup %f mul exch dup %f mul exch %f mul }\n", spotcolor->c1, spotcolor->c2, spotcolor->c3, spotcolor->c4);
1204 break;
1205 }
1206 ps_printf(psdoc, "]] setcolorspace\n");
1207 break;
1208 }
1209 default:
1210 ps_error(psdoc, PS_Warning, _("Current stroke/fill color is not RGB, CMYK, Gray or spot while setting a pattern of paint type 1."));
1211 }
1212 }
1213 break;
1214 }
1215 case PS_COLORSPACE_SPOT: {
1216 PSSpotColor *spotcolor;
1217 spotcolor = _ps_get_spotcolor(psdoc, (int) currentcolor->c1);
1218 if(!spotcolor) {
1219 ps_error(psdoc, PS_RuntimeError, _("Could not find spot color."));
1220 return;
1221 }
1222 ps_printf(psdoc, "[ /Separation (%s)\n", spotcolor->name);
1223 switch(spotcolor->colorspace) {
1224 case PS_COLORSPACE_GRAY:
1225 ps_printf(psdoc, " /DeviceGray { 1 %f sub mul 1 exch sub }\n", spotcolor->c1);
1226 break;
1227 case PS_COLORSPACE_RGB: {
1228 float max;
1229 max = (spotcolor->c1 > spotcolor->c2) ? spotcolor->c1 : spotcolor->c2;
1230 max = (max > spotcolor->c3) ? max : spotcolor->c3;
1231 ps_printf(psdoc, " /DeviceRGB { 1 exch sub dup dup %f exch sub %f mul add exch dup dup %f exch sub %f mul add exch dup %f exch sub %f mul add }\n", max, spotcolor->c1, max, spotcolor->c2, max, spotcolor->c3);
1232 break;
1233 }
1234 case PS_COLORSPACE_CMYK:
1235 ps_printf(psdoc, " /DeviceCMYK { dup %f mul exch dup %f mul exch dup %f mul exch %f mul }\n", spotcolor->c1, spotcolor->c2, spotcolor->c3, spotcolor->c4);
1236 break;
1237 }
1238 ps_printf(psdoc, "] setcolorspace\n");
1239 ps_printf(psdoc, "%f setcolor\n", currentcolor->c2);
1240 break;
1241 }
1242 }
1243 }
1244 }
1245 /* }}} */
1246
1247 /* PS_open_fp() {{{
1248 * Associates an already open file with the PostScript document created
1249 * with PS_new().
1250 */
1251 PSLIB_API int PSLIB_CALL
PS_open_fp(PSDoc * psdoc,FILE * fp)1252 PS_open_fp(PSDoc *psdoc, FILE *fp) {
1253 if(NULL == fp) {
1254 ps_error(psdoc, PS_Warning, _("File pointer is NULL. Use PS_open_mem() to create file in memory."));
1255 return(-1);
1256 }
1257 psdoc->fp = fp;
1258 psdoc->closefp = ps_false;
1259 psdoc->writeproc = ps_writeproc_file;
1260 psdoc->page = 0;
1261 psdoc->doc_open = ps_true;
1262 ps_enter_scope(psdoc, PS_SCOPE_DOCUMENT);
1263
1264 return(0);
1265 }
1266 /* }}} */
1267
1268 /* PS_open_file() {{{
1269 * Associates a file to the PostScript document created with PS_new().
1270 */
1271 PSLIB_API int PSLIB_CALL
PS_open_file(PSDoc * psdoc,const char * filename)1272 PS_open_file(PSDoc *psdoc, const char *filename) {
1273 FILE *fp;
1274
1275 if(filename == NULL || filename[0] == '\0' || (filename[0] == '-' && filename[1] == '\0')) {
1276 PS_open_mem(psdoc, NULL);
1277 return 0;
1278 } else {
1279 fp = fopen(filename, "w");
1280 if(NULL == fp) {
1281 ps_error(psdoc, PS_IOError, _("Could not open file '%s'."), filename);
1282 return -1;
1283 }
1284
1285 if(0 > PS_open_fp(psdoc, fp)) {
1286 fclose(fp);
1287 return(-1);
1288 }
1289 psdoc->closefp = ps_true;
1290 }
1291 return 0;
1292 }
1293 /* }}} */
1294
1295 /* PS_open_mem() {{{
1296 * Create document in memory. Actually you are just passing a write procedure
1297 * which is used instead of the internal procedure.
1298 */
1299 PSLIB_API int PSLIB_CALL
PS_open_mem(PSDoc * p,size_t (* writeproc)(PSDoc * p,void * data,size_t size))1300 PS_open_mem(PSDoc *p, size_t (*writeproc)(PSDoc *p, void *data, size_t size)) {
1301 if (writeproc == NULL) {
1302 p->sb = str_buffer_new(p, 1000);
1303 p->writeproc = ps_writeproc_buffer;
1304 } else {
1305 p->writeproc = writeproc;
1306 }
1307 p->fp = NULL;
1308 p->page = 0;
1309 p->doc_open = ps_true;
1310 ps_enter_scope(p, PS_SCOPE_DOCUMENT);
1311
1312 return 0;
1313 }
1314 /* }}} */
1315
1316 /* _output_bookmarks() {{{
1317 *
1318 */
_output_bookmarks(PSDoc * psdoc,DLIST * bookmarks)1319 void _output_bookmarks(PSDoc *psdoc, DLIST *bookmarks) {
1320 PS_BOOKMARK *bm;
1321 for(bm = dlst_last(bookmarks); bm != NULL; bm = dlst_prev(bm)) {
1322 char *str;
1323 ps_printf(psdoc, "[ /Page %d /Title (", bm->page);
1324 str = bm->text;
1325 while(*str != '\0') {
1326 unsigned char index = (unsigned char) *str;
1327 /* Everything below 32, above 127 and '(' and ')' should be output
1328 * as octal values.
1329 */
1330 if(index < 32 || index > 127 || index == '(' || index == ')' || index == '\\') {
1331 ps_printf(psdoc, "\\%03o", index);
1332 } else {
1333 ps_putc(psdoc, *str);
1334 }
1335 str++;
1336 }
1337 ps_printf(psdoc, ") /Count %d /OUT pdfmark\n", (bm->open == 0) ? bm->children->count : -bm->children->count);
1338 if(bm->children->count)
1339 _output_bookmarks(psdoc, bm->children);
1340 }
1341 }
1342 /* }}} */
1343
1344 /* PS_close() {{{
1345 * Closes a PostScript document. It closes the actual file only if the
1346 * document was opened with PS_open_file(). This function does not
1347 * free resources. Use PS_delete() to do that.
1348 */
1349 PSLIB_API void PSLIB_CALL
PS_close(PSDoc * psdoc)1350 PS_close(PSDoc *psdoc) {
1351 /* End page if it is still open */
1352 if(psdoc->page_open == ps_true) {
1353 ps_error(psdoc, PS_Warning, _("Ending last page of document."));
1354 PS_end_page(psdoc);
1355 }
1356 if(!ps_check_scope(psdoc, PS_SCOPE_DOCUMENT)) {
1357 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'document' scope."), __FUNCTION__);
1358 return;
1359 }
1360
1361 /* Write the trailer if the document was not close before */
1362 if(psdoc->doc_open == ps_true) {
1363 ps_printf(psdoc, "%%%%Trailer\n");
1364 ps_printf(psdoc, "end\n");
1365 if(psdoc->bookmarks->count > 0) {
1366 _output_bookmarks(psdoc, psdoc->bookmarks);
1367 }
1368 ps_printf(psdoc, "%%%%Pages: %d\n", psdoc->page);
1369 ps_printf(psdoc, "%%%%BoundingBox: %s\n", psdoc->BoundingBox);
1370 ps_printf(psdoc, "%%%%Orientation: %s\n", psdoc->Orientation);
1371 ps_printf(psdoc, "%%%%EOF");
1372 ps_leave_scope(psdoc, PS_SCOPE_DOCUMENT);
1373 }
1374
1375 /* FIXME: Need to free the linked lists parameters, categories and values */
1376 if((psdoc->closefp == ps_true) && (NULL != psdoc->fp)) {
1377 fclose(psdoc->fp);
1378 psdoc->fp = NULL;
1379 }
1380
1381 psdoc->doc_open = ps_false;
1382 }
1383 /* }}} */
1384
1385 /* PS_delete() {{{
1386 * Frees all resources of a document. If the document was not closed before,
1387 * it will also be closed.
1388 */
1389 PSLIB_API void PSLIB_CALL
PS_delete(PSDoc * psdoc)1390 PS_delete(PSDoc *psdoc) {
1391 int i;
1392 if(NULL == psdoc) {
1393 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
1394 return;
1395 }
1396
1397 /* Make sure the document is closed */
1398 if(psdoc->doc_open == ps_true) {
1399 PS_close(psdoc);
1400 }
1401
1402 if(psdoc->sb)
1403 str_buffer_delete(psdoc, psdoc->sb);
1404
1405 /* Free the memory */
1406 ps_del_resources(psdoc);
1407 ps_del_parameters(psdoc);
1408 ps_del_values(psdoc);
1409 ps_del_bookmarks(psdoc, psdoc->bookmarks);
1410 psdoc->bookmarks = NULL;
1411
1412 if(psdoc->Author) {
1413 psdoc->free(psdoc, psdoc->Author);
1414 psdoc->Author = NULL;
1415 }
1416 if(psdoc->Keywords) {
1417 psdoc->free(psdoc, psdoc->Keywords);
1418 psdoc->Keywords = NULL;
1419 }
1420 if(psdoc->Subject) {
1421 psdoc->free(psdoc, psdoc->Subject);
1422 psdoc->Subject = NULL;
1423 }
1424 if(psdoc->Title) {
1425 psdoc->free(psdoc, psdoc->Title);
1426 psdoc->Title = NULL;
1427 }
1428 if(psdoc->Creator) {
1429 psdoc->free(psdoc, psdoc->Creator);
1430 psdoc->Creator = NULL;
1431 }
1432 if(psdoc->BoundingBox) {
1433 psdoc->free(psdoc, psdoc->BoundingBox);
1434 psdoc->BoundingBox = NULL;
1435 }
1436 if(psdoc->Orientation) {
1437 psdoc->free(psdoc, psdoc->Orientation);
1438 psdoc->Orientation = NULL;
1439 }
1440 if(psdoc->CreationDate) {
1441 psdoc->free(psdoc, psdoc->CreationDate);
1442 psdoc->CreationDate = NULL;
1443 }
1444
1445 /* Freeing font resources */
1446 i = 0;
1447 while(i < psdoc->fontcnt) {
1448 if(psdoc->fonts[i]) {
1449 _ps_delete_font(psdoc, psdoc->fonts[i]);
1450 }
1451 i++;
1452 }
1453 psdoc->free(psdoc, psdoc->fonts);
1454
1455 /* Freeing image resources */
1456 i = 0;
1457 while(i < psdoc->imagecnt) {
1458 if(psdoc->images[i]) {
1459 _ps_delete_image(psdoc, psdoc->images[i]);
1460 }
1461 i++;
1462 }
1463 psdoc->free(psdoc, psdoc->images);
1464
1465 /* Freeing pattern resources */
1466 i = 0;
1467 while(i < psdoc->patterncnt) {
1468 if(psdoc->patterns[i]) {
1469 _ps_delete_pattern(psdoc, psdoc->patterns[i]);
1470 }
1471 i++;
1472 }
1473 psdoc->free(psdoc, psdoc->patterns);
1474
1475 /* Freeing spotcolor resources */
1476 i = 0;
1477 while(i < psdoc->spotcolorcnt) {
1478 if(psdoc->spotcolors[i]) {
1479 _ps_delete_spotcolor(psdoc, psdoc->spotcolors[i]);
1480 }
1481 i++;
1482 }
1483 psdoc->free(psdoc, psdoc->spotcolors);
1484
1485 /* Freeing shading resources */
1486 i = 0;
1487 while(i < psdoc->shadingcnt) {
1488 if(psdoc->shadings[i]) {
1489 _ps_delete_shading(psdoc, psdoc->shadings[i]);
1490 }
1491 i++;
1492 }
1493 psdoc->free(psdoc, psdoc->shadings);
1494
1495 /* Freeing graphic state resources */
1496 i = 0;
1497 while(i < psdoc->gstatecnt) {
1498 if(psdoc->gstates[i]) {
1499 _ps_delete_gstate(psdoc, psdoc->gstates[i]);
1500 }
1501 i++;
1502 }
1503 psdoc->free(psdoc, psdoc->gstates);
1504
1505 if(psdoc->hdict)
1506 hnj_hyphen_free(psdoc->hdict);
1507 if(psdoc->hdictfilename)
1508 psdoc->free(psdoc, psdoc->hdictfilename);
1509 psdoc->free(psdoc, psdoc);
1510 }
1511 /* }}} */
1512
1513 /* PS_set_parameter() {{{
1514 * Sets all kind of parameters. Parameters are string values as opposed
1515 * to 'values' set by PS_set_value() which are of type float.
1516 * Some parameters change internal variables while other are just
1517 * stored in double linked list. If a value itself is a name value pair,
1518 * then this is called a resource.
1519 */
1520 PSLIB_API void PSLIB_CALL
PS_set_parameter(PSDoc * psdoc,const char * name,const char * value)1521 PS_set_parameter(PSDoc *psdoc, const char *name, const char *value) {
1522 if(NULL == psdoc) {
1523 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
1524 return;
1525 }
1526 if((strcmp(name, "FontAFM") == 0) ||
1527 (strcmp(name, "FontOutline") == 0) ||
1528 (strcmp(name, "FontProtusion") == 0) ||
1529 (strcmp(name, "FontEncoding") == 0) ||
1530 (strcmp(name, "RightMarginKerning") == 0) ||
1531 (strcmp(name, "LeftMarginKerning") == 0)) {
1532 char *res = ps_strdup(psdoc, value);
1533 char *filename;
1534
1535 if ((filename = strchr(res, '=')) == NULL) {
1536 psdoc->free(psdoc, res);
1537 ps_error(psdoc, PS_Warning, _("Invalid resource"));
1538 return;
1539 }
1540 *filename++ = '\0';
1541 if (*filename == '=') {
1542 filename++;
1543 }
1544 if(strcmp(name, "RightMarginKerning") == 0) {
1545 ADOBEINFO *ai;
1546 if(!psdoc->font || !psdoc->font->metrics) {
1547 ps_error(psdoc, PS_RuntimeError, _("RightMarginKerning cannot be set without setting a font before."));
1548 return;
1549 }
1550 ai = gfindadobe(psdoc->font->metrics->gadobechars, res);
1551 if(ai)
1552 ai->rkern = atoi(filename);
1553 } else if(strcmp(name, "LeftMarginKerning") == 0) {
1554 ADOBEINFO *ai;
1555 if(!psdoc->font || !psdoc->font->metrics) {
1556 ps_error(psdoc, PS_RuntimeError, _("LeftMarginKerning cannot be set without setting a font before."));
1557 return;
1558 }
1559 ai = gfindadobe(psdoc->font->metrics->gadobechars, res);
1560 if(ai)
1561 ai->lkern = atoi(filename);
1562 } else {
1563 if(NULL == ps_add_resource(psdoc, name, res, filename, NULL)) {
1564 ps_error(psdoc, PS_RuntimeError, _("Resource '%s' in category '%s' could not be registered."), res, name);
1565 }
1566 }
1567 psdoc->free(psdoc, res);
1568 } else if(strcmp(name, "SearchPath") == 0) {
1569 if(NULL == ps_add_resource(psdoc, name, NULL, value, NULL)) {
1570 ps_error(psdoc, PS_RuntimeError, _("Resource in category '%s' could not be registered."), name);
1571 }
1572 } else if(strcmp(name, "underline") == 0) {
1573 if(strcmp(value, "true") == 0) {
1574 psdoc->underline = ps_true;
1575 } else {
1576 psdoc->underline = ps_false;
1577 }
1578 } else if(strcmp(name, "overline") == 0) {
1579 if(strcmp(value, "true") == 0) {
1580 psdoc->overline = ps_true;
1581 } else {
1582 psdoc->overline = ps_false;
1583 }
1584 } else if(strcmp(name, "strikeout") == 0) {
1585 if(strcmp(value, "true") == 0) {
1586 psdoc->strikeout = ps_true;
1587 } else {
1588 psdoc->strikeout = ps_false;
1589 }
1590 } else if(strcmp(name, "warning") == 0) {
1591 if(strcmp(value, "true") == 0) {
1592 psdoc->warnings = ps_true;
1593 } else {
1594 psdoc->warnings = ps_false;
1595 }
1596 } else if(strcmp(name, "hyphendict") == 0) {
1597 if((psdoc->hdict != NULL) && strcmp(value, psdoc->hdictfilename)) {
1598 hnj_hyphen_free(psdoc->hdict);
1599 psdoc->free(psdoc, psdoc->hdictfilename);
1600 }
1601 psdoc->hdict = hnj_hyphen_load(value);
1602 if(!psdoc->hdict) {
1603 ps_error(psdoc, PS_RuntimeError, _("Could not load hyphenation table '%s', turning hyphenation off."), value);
1604 return;
1605 }
1606 if(psdoc->hdictfilename)
1607 psdoc->free(psdoc, psdoc->hdictfilename);
1608 psdoc->hdictfilename = ps_strdup(psdoc, value);
1609 } else if(strcmp(name, "inputencoding") == 0) {
1610 ENCODING *enc;
1611 if(NULL != (enc = ps_get_inputencoding(value))) {
1612 psdoc->inputenc = enc;
1613 } else {
1614 ps_error(psdoc, PS_Warning, _("Input encoding '%s' could not be set."), value);
1615 }
1616 if(strcmp(value, "true") == 0) {
1617 psdoc->warnings = ps_true;
1618 } else {
1619 psdoc->warnings = ps_false;
1620 }
1621 } else {
1622 PS_PARAMETER *parameter;
1623
1624 /* Check if parameter already exists. If yes, reset it */
1625 for(parameter = dlst_first(psdoc->parameters); parameter != NULL; parameter = dlst_next(parameter)) {
1626 if (0 == strcmp(parameter->name, name)) {
1627 psdoc->free(psdoc, parameter->value);
1628 parameter->value = ps_strdup(psdoc, value);
1629 return;
1630 }
1631 }
1632
1633 /* Add an new parameter */
1634 if(NULL == (parameter = (PS_PARAMETER *) dlst_newnode(psdoc->parameters, (int) sizeof(PS_PARAMETER)))) {
1635 return;
1636 }
1637 parameter->name = ps_strdup(psdoc, name);
1638 parameter->value = ps_strdup(psdoc, value);
1639 dlst_insertafter(psdoc->parameters, parameter, PS_DLST_HEAD(psdoc->parameters));
1640 }
1641 }
1642 /* }}} */
1643
1644 /* PS_get_parameter() {{{
1645 * Returns a parameter. This function cannot return resources set by
1646 * PS_set_parameter().
1647 */
1648 PSLIB_API const char * PSLIB_CALL
PS_get_parameter(PSDoc * psdoc,const char * name,float modifier)1649 PS_get_parameter(PSDoc *psdoc, const char *name, float modifier) {
1650 PS_PARAMETER *param;
1651
1652 if(NULL == psdoc) {
1653 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
1654 return(NULL);
1655 }
1656
1657 if(name == NULL) {
1658 ps_error(psdoc, PS_RuntimeError, _("Do not know which parameter to get since the passed name is NULL."));
1659 return(NULL);
1660 }
1661
1662 if(strcmp(name, "fontname") == 0) {
1663 PSFont *psfont;
1664 if(0 == (int) modifier) {
1665 psfont = psdoc->font;
1666 } else {
1667 if(NULL == (psfont = _ps_get_font(psdoc, (int) modifier)))
1668 return(NULL);
1669 }
1670 if(NULL == psfont || NULL == psfont->metrics) {
1671 ps_error(psdoc, PS_RuntimeError, _("No font set."));
1672 return(NULL);
1673 }
1674 return(psfont->metrics->fontname);
1675 } else if(strcmp(name, "fontencoding") == 0) {
1676 PSFont *psfont;
1677 if(0 == (int) modifier) {
1678 psfont = psdoc->font;
1679 } else {
1680 if(NULL == (psfont = _ps_get_font(psdoc, (int) modifier)))
1681 return(NULL);
1682 }
1683 if(NULL == psfont || NULL == psfont->metrics) {
1684 ps_error(psdoc, PS_RuntimeError, _("No font set."));
1685 return(NULL);
1686 }
1687 return(psfont->metrics->codingscheme);
1688 } else if(strcmp(name, "dottedversion") == 0) {
1689 return(LIBPS_DOTTED_VERSION);
1690 } else if(strcmp(name, "scope") == 0) {
1691 switch(ps_current_scope(psdoc)) {
1692 case PS_SCOPE_OBJECT:
1693 return("object");
1694 case PS_SCOPE_DOCUMENT:
1695 return("document");
1696 case PS_SCOPE_NONE:
1697 return("null");
1698 case PS_SCOPE_PAGE:
1699 return("page");
1700 case PS_SCOPE_PATTERN:
1701 return("pattern");
1702 case PS_SCOPE_PATH:
1703 return("path");
1704 case PS_SCOPE_TEMPLATE:
1705 return("template");
1706 case PS_SCOPE_PROLOG:
1707 return("prolog");
1708 case PS_SCOPE_FONT:
1709 return("font");
1710 case PS_SCOPE_GLYPH:
1711 return("glyph");
1712 }
1713 } else {
1714 for(param = dlst_first(psdoc->parameters); param != NULL; param = dlst_next(param)) {
1715 if (0 == strcmp(param->name, name)) {
1716 return(param->value);
1717 }
1718 }
1719 }
1720 return(NULL);
1721 }
1722 /* }}} */
1723
1724 /* PS_set_value() {{{
1725 * Sets a float value.
1726 */
1727 PSLIB_API void PSLIB_CALL
PS_set_value(PSDoc * psdoc,const char * name,float value)1728 PS_set_value(PSDoc *psdoc, const char *name, float value) {
1729 PS_VALUE *parameter;
1730
1731 if(NULL == psdoc) {
1732 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
1733 return;
1734 }
1735
1736 if(strcmp(name, "wordspacing") == 0) {
1737 ADOBEINFO *ai = NULL;
1738 if(psdoc->font && psdoc->font->metrics != NULL)
1739 ai = gfindadobe(psdoc->font->metrics->gadobechars, "space");
1740 if(ai)
1741 psdoc->font->wordspace = (int) (value * ai->width);
1742 } else if(strcmp(name, "textx") == 0) {
1743 psdoc->tstates[psdoc->tstate].tx = value;
1744 psdoc->tstates[psdoc->tstate].cx = value;
1745 } else if(strcmp(name, "texty") == 0) {
1746 psdoc->tstates[psdoc->tstate].ty = value;
1747 psdoc->tstates[psdoc->tstate].cy = value;
1748 } else if(strcmp(name, "textrendering") == 0) {
1749 psdoc->textrendering = (int) value;
1750 } else {
1751 /* Check if value exists */
1752 for(parameter = dlst_first(psdoc->values); parameter != NULL; parameter = dlst_next(parameter)) {
1753 if(0 == strcmp(parameter->name, name)) {
1754 parameter->value = value;
1755 return;
1756 }
1757 }
1758
1759 /* Doesn't exist, so create a new one */
1760 if(NULL == (parameter = (PS_VALUE *) dlst_newnode(psdoc->values, (int) sizeof(PS_VALUE)))) {
1761 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for new node in value list."));
1762 return;
1763 }
1764 parameter->name = ps_strdup(psdoc, name);
1765 parameter->value = value;
1766 dlst_insertafter(psdoc->values, parameter, PS_DLST_HEAD(psdoc->values));
1767 }
1768
1769 }
1770 /* }}} */
1771
1772 /* PS_get_value() {{{
1773 * Returns a value set with PS_set_value()
1774 * modifier specifies a for which object this value shall be retrieved.
1775 * objects are fonts, images, ...
1776 */
1777 PSLIB_API float PSLIB_CALL
PS_get_value(PSDoc * psdoc,const char * name,float modifier)1778 PS_get_value(PSDoc *psdoc, const char *name, float modifier) {
1779 PS_VALUE *value;
1780
1781 if(name == NULL) {
1782 ps_error(psdoc, PS_RuntimeError, _("Do not know which value to get since the passed name is NULL."));
1783 return(0.0);
1784 }
1785 if(NULL == psdoc) {
1786 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
1787 return(0.0);
1788 }
1789
1790 if(strcmp(name, "fontsize") == 0) {
1791 PSFont *psfont;
1792 if(0 == (int) modifier) {
1793 psfont = psdoc->font;
1794 } else {
1795 if(NULL == (psfont = _ps_get_font(psdoc, (int) modifier)))
1796 return(0.0);
1797 }
1798 if(NULL == psfont) {
1799 ps_error(psdoc, PS_RuntimeError, _("No font set."));
1800 return(0.0);
1801 }
1802 return(psfont->size);
1803 } else if(strcmp(name, "font") == 0) {
1804 return((float) _ps_find_font(psdoc, psdoc->font));
1805 } else if(strcmp(name, "imagewidth") == 0) {
1806 PSImage *psimage = _ps_get_image(psdoc, (int) modifier);
1807 if(!psimage)
1808 return(0.0);
1809 return((float) psimage->width);
1810 } else if(strcmp(name, "imageheight") == 0) {
1811 PSImage *psimage = _ps_get_image(psdoc, (int) modifier);
1812 if(!psimage)
1813 return(0.0);
1814 return((float) psimage->height);
1815 } else if(strcmp(name, "capheight") == 0) {
1816 PSFont *psfont;
1817 if(0 == (int) modifier) {
1818 psfont = psdoc->font;
1819 } else {
1820 if(NULL == (psfont = _ps_get_font(psdoc, (int) modifier)))
1821 return(0.0);
1822 }
1823 if(NULL == psfont || NULL == psfont->metrics) {
1824 ps_error(psdoc, PS_RuntimeError, _("No font set."));
1825 return(0.0);
1826 }
1827 return(psfont->metrics->capheight);
1828 } else if(strcmp(name, "ascender") == 0) {
1829 PSFont *psfont;
1830 if(0 == (int) modifier) {
1831 psfont = psdoc->font;
1832 } else {
1833 if(NULL == (psfont = _ps_get_font(psdoc, (int) modifier)))
1834 return(0.0);
1835 }
1836 if(NULL == psfont || NULL == psfont->metrics) {
1837 ps_error(psdoc, PS_RuntimeError, _("No font set."));
1838 return(0.0);
1839 }
1840 return(psfont->metrics->ascender);
1841 } else if(strcmp(name, "descender") == 0) {
1842 PSFont *psfont;
1843 if(0 == (int) modifier) {
1844 psfont = psdoc->font;
1845 } else {
1846 if(NULL == (psfont = _ps_get_font(psdoc, (int) modifier)))
1847 return(0.0);
1848 }
1849 if(NULL == psfont || NULL == psfont->metrics) {
1850 ps_error(psdoc, PS_RuntimeError, _("No font set."));
1851 return(0.0);
1852 }
1853 return(psfont->metrics->descender);
1854 } else if(strcmp(name, "italicangle") == 0) {
1855 PSFont *psfont;
1856 if(0 == (int) modifier) {
1857 psfont = psdoc->font;
1858 } else {
1859 if(NULL == (psfont = _ps_get_font(psdoc, (int) modifier)))
1860 return(0.0);
1861 }
1862 if(NULL == psfont || NULL == psfont->metrics) {
1863 ps_error(psdoc, PS_RuntimeError, _("No font set."));
1864 return(0.0);
1865 }
1866 return(psfont->metrics->italicangle);
1867 } else if(strcmp(name, "underlineposition") == 0) {
1868 PSFont *psfont;
1869 if(0 == (int) modifier) {
1870 psfont = psdoc->font;
1871 } else {
1872 if(NULL == (psfont = _ps_get_font(psdoc, (int) modifier)))
1873 return(0.0);
1874 }
1875 if(NULL == psfont || NULL == psfont->metrics) {
1876 ps_error(psdoc, PS_RuntimeError, _("No font set."));
1877 return(0.0);
1878 }
1879 return(psfont->metrics->underlineposition);
1880 } else if(strcmp(name, "underlinethickness") == 0) {
1881 PSFont *psfont;
1882 if(0 == (int) modifier) {
1883 psfont = psdoc->font;
1884 } else {
1885 if(NULL == (psfont = _ps_get_font(psdoc, (int) modifier)))
1886 return(0.0);
1887 }
1888 if(NULL == psfont || NULL == psfont->metrics) {
1889 ps_error(psdoc, PS_RuntimeError, _("No font set."));
1890 return(0.0);
1891 }
1892 return(psfont->metrics->underlinethickness);
1893 } else if(strcmp(name, "textx") == 0) {
1894 return(psdoc->tstates[psdoc->tstate].tx);
1895 } else if(strcmp(name, "texty") == 0) {
1896 return(psdoc->tstates[psdoc->tstate].ty);
1897 } else if(strcmp(name, "textrendering") == 0) {
1898 return((float) psdoc->textrendering);
1899 } else if(strcmp(name, "wordspacing") == 0) {
1900 ADOBEINFO *ai = NULL;
1901 if(psdoc->font != NULL && psdoc->font->metrics != NULL)
1902 ai = gfindadobe(psdoc->font->metrics->gadobechars, "space");
1903 if(ai)
1904 return((float) psdoc->font->wordspace / ai->width);
1905 else
1906 return(0.0);
1907 } else if(strcmp(name, "major") == 0) {
1908 return((float) LIBPS_MAJOR_VERSION);
1909 } else if(strcmp(name, "minor") == 0) {
1910 return((float) LIBPS_MINOR_VERSION);
1911 } else if(strcmp(name, "subminor") == 0) {
1912 return((float) LIBPS_MICRO_VERSION);
1913 } else if(strcmp(name, "revision") == 0) {
1914 return((float) LIBPS_MICRO_VERSION);
1915 } else {
1916 for(value = dlst_first(psdoc->values); value != NULL; value = dlst_next(value)) {
1917 if (0 == strcmp(value->name, name)) {
1918 return(value->value);
1919 }
1920 }
1921 }
1922 return(0.0);
1923 }
1924 /* }}} */
1925
1926 /* PS_list_values() {{{
1927 * Outputs a list of all values
1928 */
1929 PSLIB_API void PSLIB_CALL
PS_list_values(PSDoc * psdoc)1930 PS_list_values(PSDoc *psdoc) {
1931 PS_VALUE *value;
1932
1933 if(psdoc == NULL) {
1934 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
1935 return;
1936 }
1937
1938 printf("List of Values\n-----------------------------------\n");
1939 for(value = dlst_first(psdoc->values); value != NULL; value = dlst_next(value)) {
1940 printf("%s = %f\n", value->name, value->value);
1941 }
1942 printf("-------------------------------------\n");
1943 }
1944 /* }}} */
1945
1946 /* PS_list_parameters() {{{
1947 * Outputs a list of all parameters
1948 */
1949 PSLIB_API void PSLIB_CALL
PS_list_parameters(PSDoc * psdoc)1950 PS_list_parameters(PSDoc *psdoc) {
1951 PS_PARAMETER *parameter;
1952
1953 if(psdoc == NULL) {
1954 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
1955 return;
1956 }
1957
1958 printf("List of Parameters\n-----------------------------------\n");
1959 for(parameter = dlst_first(psdoc->parameters); parameter != NULL; parameter = dlst_next(parameter)) {
1960 printf("%s = %s\n", parameter->name, parameter->value);
1961 }
1962 printf("-------------------------------------\n");
1963 }
1964 /* }}} */
1965
1966 /* PS_list_resources() {{{
1967 * Outputs a list of all resources
1968 */
1969 PSLIB_API void PSLIB_CALL
PS_list_resources(PSDoc * psdoc)1970 PS_list_resources(PSDoc *psdoc) {
1971 PS_CATEGORY *cat;
1972 PS_RESOURCE *res;
1973
1974 if(psdoc == NULL) {
1975 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
1976 return;
1977 }
1978
1979 printf("List of Resources\n-----------------------------------\n");
1980 for(cat = dlst_first(psdoc->categories); cat != NULL; cat = dlst_next(cat)) {
1981 for(res = dlst_first(cat->resources); res != NULL; res = dlst_next(res)) {
1982 printf("%s : %s = %s\n", cat->name, res->name, res->value);
1983 }
1984 }
1985 printf("-------------------------------------\n");
1986 }
1987 /* }}} */
1988
1989 /* PS_begin_page() {{{
1990 * starts a new (the next) page
1991 */
1992 PSLIB_API void PSLIB_CALL
PS_begin_page(PSDoc * psdoc,float width,float height)1993 PS_begin_page(PSDoc *psdoc, float width, float height) {
1994 int sepcolor;
1995 if(NULL == psdoc) {
1996 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
1997 return;
1998 }
1999 // if(psdoc->commentswritten == ps_false) {
2000 if(psdoc->page == 0) {
2001 /* Do not overwrite the BoundingBox if it has been set before */
2002 if(width != 0.0 && height != 0.0) {
2003 if(psdoc->BoundingBox == NULL) {
2004 char tmp[30];
2005 #ifdef HAVE_SNPRINTF
2006 snprintf(tmp, 30, "0 0 %.0f %.0f", width, height);
2007 #else
2008 sprintf(tmp, "0 0 %.0f %.0f", width, height);
2009 #endif
2010 psdoc->BoundingBox = ps_strdup(psdoc, tmp);
2011 }
2012 if(psdoc->Orientation == NULL) {
2013 if(width > height)
2014 psdoc->Orientation = ps_strdup(psdoc, "Landscape");
2015 else
2016 psdoc->Orientation = ps_strdup(psdoc, "Portrait");
2017 }
2018 }
2019 }
2020 /* Make sure the rest of the header is written */
2021 ps_write_ps_header(psdoc);
2022 if(!ps_check_scope(psdoc, PS_SCOPE_DOCUMENT)) {
2023 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'document' scope."), __FUNCTION__);
2024 return;
2025 }
2026
2027 (psdoc->page)++;
2028 ps_printf(psdoc, "\n%%%%Page: %i %i\n", psdoc->page, psdoc->page);
2029 ps_printf(psdoc, "%%%%PageBoundingBox: 0 0 %d %d\n", (int) width, (int) height);
2030 ps_printf(psdoc, "%%%%BeginPageSetup\n");
2031 ps_printf(psdoc, "[ /CropBox [0 0 %.2f %.2f] /PAGE pdfmark\n", width, height);
2032 sepcolor = (int) PS_get_value(psdoc, "separationcolor", 0.0);
2033 if(sepcolor > 0) {
2034 ps_printf(psdoc, "userdict 0 %d bop-hook\n", sepcolor-1);
2035 ps_printf(psdoc, "PslibDict begin ");
2036 ps_printf(psdoc, "/vsize %.2f def ", height);
2037 ps_printf(psdoc, "/hsize %.2f def ", width);
2038 ps_printf(psdoc, "end\n");
2039 }
2040 ps_printf(psdoc, "%%%%EndPageSetup\n");
2041 ps_printf(psdoc, "save\n");
2042 ps_printf(psdoc, "0 0 %.2f %.2f ", width, height);
2043 ps_printf(psdoc, "%i PslibPageBeginHook\n", psdoc->page);
2044 ps_printf(psdoc, "restore\n");
2045 ps_printf(psdoc, "save\n");
2046 psdoc->tstates[psdoc->tstate].tx = 100.0;
2047 psdoc->tstates[psdoc->tstate].ty = 100.0;
2048 psdoc->tstates[psdoc->tstate].cx = 100.0;
2049 psdoc->tstates[psdoc->tstate].cy = 100.0;
2050 psdoc->page_open = ps_true;
2051 ps_enter_scope(psdoc, PS_SCOPE_PAGE);
2052 }
2053 /* }}} */
2054
2055 /* PS_end_page() {{{
2056 * ends the page and increments the pagecount by 1
2057 */
2058 PSLIB_API void PSLIB_CALL
PS_end_page(PSDoc * psdoc)2059 PS_end_page(PSDoc *psdoc) {
2060 if(NULL == psdoc) {
2061 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
2062 return;
2063 }
2064 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE)) {
2065 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page' scope."), __FUNCTION__);
2066 return;
2067 }
2068 if(psdoc->agstate > 0) {
2069 ps_error(psdoc, PS_RuntimeError, _("PS_save() has been called more often than PS_restore()."));
2070 return;
2071 }
2072 // ps_printf(psdoc, "end\n");
2073 ps_printf(psdoc, "restore\n");
2074 ps_printf(psdoc, "save\n");
2075 ps_printf(psdoc, "%i PslibPageEndHook\n", psdoc->page);
2076 ps_printf(psdoc, "restore\n");
2077 ps_printf(psdoc, "showpage\n");
2078 psdoc->page_open = ps_false;
2079 /* Set current font to NULL in order to enforce calling PS_set_font().
2080 * PS_set_font() is needed because each page in encapsulated in save/restore
2081 * any setting of a font within page will not be valid after the page.
2082 */
2083 psdoc->font = NULL;
2084 ps_leave_scope(psdoc, PS_SCOPE_PAGE);
2085 }
2086 /* }}} */
2087
2088 /* ps_render_text() {{{
2089 * Prints text on page depending on current text rendering.
2090 * The text passed to this function may not containing any
2091 * kerning pairs, since it relies on the PostScript stringwith
2092 * function which cannot handle kerning (unless you don't want
2093 * kerning to be taken into account).
2094 * The text must be font encoded as it is unmodified written into
2095 * the PostScript file.
2096 */
ps_render_text(PSDoc * psdoc,const char * text)2097 static void ps_render_text(PSDoc *psdoc, const char *text) {
2098 char *str = (char *) text;
2099 float textrise;
2100 if(text == NULL)
2101 return;
2102 textrise = PS_get_value(psdoc, "textrise", 0.0);
2103 if(textrise != 0.0) {
2104 ps_printf(psdoc, "%f tr ", textrise);
2105 }
2106 switch(psdoc->textrendering) {
2107 case -1: /* normal */
2108 case 1: /* stroke */
2109 case 5: /* stroke and clip*/
2110 ps_setcolor(psdoc, PS_COLORTYPE_STROKE);
2111 break;
2112 case 0: /* fill */
2113 case 2: /* stroke and fill */
2114 // FIXME: need to set fill and stroke color
2115 case 4: /* fill and clip*/
2116 case 6: /* fill, stroke and clip*/
2117 ps_setcolor(psdoc, PS_COLORTYPE_FILL);
2118 break;
2119 default:
2120 ps_setcolor(psdoc, PS_COLORTYPE_STROKE);
2121 }
2122 ps_putc(psdoc, '(');
2123 while(*str != '\0') {
2124 unsigned char index = (unsigned char) *str;
2125 /* Everything below 32, above 127 and '(' and ')' should be output
2126 * as octal values.
2127 */
2128 if(index < 32 || index > 127 || index == '(' || index == ')' || index == '\\') {
2129 ps_printf(psdoc, "\\%03o", index);
2130 } else {
2131 ps_putc(psdoc, *str);
2132 }
2133 str++;
2134 }
2135 ps_putc(psdoc, ')');
2136 switch(psdoc->textrendering) {
2137 case -1: /* normal */
2138 ps_puts(psdoc, "p ");
2139 break;
2140 case 0: /* fill */
2141 ps_puts(psdoc, "qf ");
2142 break;
2143 case 1: /* stroke */
2144 ps_puts(psdoc, "qs ");
2145 break;
2146 case 2: /* stroke and fill */
2147 ps_puts(psdoc, "qsf ");
2148 break;
2149 case 3: /* invisible text */
2150 ps_puts(psdoc, "qi ");
2151 break;
2152 case 4: /* fill and clip*/
2153 ps_puts(psdoc, "qfc ");
2154 break;
2155 case 5: /* stroke and clip*/
2156 ps_puts(psdoc, "qsc ");
2157 break;
2158 case 6: /* fill, stroke and clip*/
2159 // FIXME: need to set fill and stroke color
2160 ps_puts(psdoc, "qfsc ");
2161 break;
2162 case 7: /* clip*/
2163 ps_puts(psdoc, "qc ");
2164 break;
2165 default:
2166 ps_puts(psdoc, "p ");
2167 break;
2168 }
2169 if(textrise) {
2170 ps_puts(psdoc, "rt ");
2171 }
2172 }
2173 /* }}} */
2174
2175 /* PS_show2() {{{
2176 * Output text at current position. Do not print more the xlen characters.
2177 */
2178 PSLIB_API void PSLIB_CALL
PS_show2(PSDoc * psdoc,const char * text,int xlen)2179 PS_show2(PSDoc *psdoc, const char *text, int xlen) {
2180 int kernonoff;
2181 int ligonoff;
2182 char ligdischar;
2183 float charspacing;
2184
2185 if(NULL == psdoc) {
2186 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
2187 return;
2188 }
2189 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
2190 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
2191 return;
2192 }
2193 if(NULL == text) {
2194 ps_error(psdoc, PS_RuntimeError, _("Text to display is NULL."));
2195 return;
2196 }
2197
2198 if(NULL == psdoc->font) {
2199 ps_error(psdoc, PS_RuntimeError, _("No font set."));
2200 return;
2201 }
2202
2203 /* Set starting point for text */
2204 ps_printf(psdoc, "%.2f %.2f a\n", psdoc->tstates[psdoc->tstate].tx, psdoc->tstates[psdoc->tstate].ty);
2205
2206 charspacing = PS_get_value(psdoc, "charspacing", 0) * 1000.0 / psdoc->font->size;
2207 kernonoff = ps_get_bool_parameter(psdoc, "kerning", 1);
2208 ligonoff = ps_get_bool_parameter(psdoc, "ligatures", 1);
2209 if(ligonoff) {
2210 const char *tmp = PS_get_parameter(psdoc, "ligaturedisolvechar", 0.0);
2211 if(tmp && tmp[0])
2212 ligdischar = tmp[0];
2213 else
2214 ligdischar = '�';
2215 }
2216
2217 /* Take kerning into account if adobe font metrics has been loaded. */
2218 if(psdoc->font->metrics) {
2219 int i, len, k=0;
2220 float x, y, yy;
2221 ADOBEINFO *prevai = NULL;
2222 char *strbuf;
2223 char *textcpy;
2224 float overallwidth = 0;
2225 float ascender = 0;
2226 float descender = 0;
2227
2228 textcpy = ps_strdup(psdoc, text);
2229 len = strlen(text);
2230 if(xlen != 0)
2231 len = xlen < len ? xlen : len;
2232 strbuf = (char *) psdoc->malloc(psdoc, len+1, _("Allocate temporay space for output string."));
2233 for(i=0; i<len; i++) {
2234 unsigned char c;
2235 char *adobename;
2236 float kern;
2237
2238 c = (unsigned char) textcpy[i];
2239 adobename = ps_inputenc_name(psdoc, c);
2240 if(adobename && adobename[0] != '\0') {
2241 ADOBEINFO *ai;
2242 ai = gfindadobe(psdoc->font->metrics->gadobechars, adobename);
2243 if(ai) {
2244 /* Check if space has ended a string */
2245 if(strcmp(adobename, "space") == 0) {
2246 if((kernonoff == 1) && (NULL != prevai))
2247 kern = (float) calculatekern(prevai, ai);
2248 else
2249 kern = 0.0;
2250 overallwidth += (float) psdoc->font->wordspace + charspacing + kern;
2251 /* first output collected text */
2252 if(k > 0) {
2253 strbuf[k] = '\0';
2254 ps_render_text(psdoc, strbuf);
2255 k = 0;
2256 }
2257 ps_printf(psdoc, "%.2f w ", (psdoc->font->wordspace+charspacing+kern)*psdoc->font->size/1000.0+0.005);
2258 } else {
2259 char *newadobename;
2260 int offset = 0;
2261 /* Check if the current and the next character form a ligature */
2262 if(ligonoff == 1 &&
2263 charspacing == 0.0 &&
2264 ps_check_for_lig(psdoc, psdoc->font->metrics, ai, &textcpy[i+1], ligdischar, &newadobename, &offset)) {
2265 if(ps_fontenc_has_glyph(psdoc, psdoc->font->metrics->fontenc, newadobename)) {
2266 ADOBEINFO *nai = gfindadobe(psdoc->font->metrics->gadobechars, newadobename);
2267 if(nai) {
2268 ai = nai;
2269 i += offset;
2270 } else {
2271 ps_error(psdoc, PS_Warning, _("Font '%s' has no ligature '%s', disolving it."), psdoc->font->metrics->fontname, newadobename);
2272 }
2273 } else {
2274 ps_error(psdoc, PS_Warning, _("Font encoding vector of font '%s' has no ligature '%s', disolving it."), psdoc->font->metrics->fontname, newadobename);
2275 }
2276 }
2277 /* At this point either ai is ligature or the current char */
2278 overallwidth += (float) (ai->width);
2279 descender = min((float) ai->lly, descender);
2280 ascender = max((float) ai->ury, ascender);
2281 if((kernonoff == 1) && (NULL != prevai)) {
2282 kern = (float) calculatekern(prevai, ai);
2283 overallwidth += kern;
2284 } else {
2285 kern = 0.0;
2286 }
2287 if(i < (len-1))
2288 overallwidth += charspacing;
2289 // printf("kern = %f\n", kern);
2290 /* Any space between last and current character? If Yes output the
2291 * collected text first, put the space after it and start a new
2292 * string up to the next space (space is either kerning or extra
2293 * charspace).
2294 */
2295 if((kern != 0.0 || charspacing != 0.0) && (i > 0)) {
2296 if(k > 0) {
2297 strbuf[k] = '\0';
2298 ps_render_text(psdoc, strbuf);
2299 k = 0;
2300 }
2301 ps_printf(psdoc, "%.2f w ", (kern+charspacing)*psdoc->font->size/1000.0+0.005);
2302 }
2303 if(psdoc->font->metrics->fontenc)
2304 strbuf[k++] = ps_fontenc_code(psdoc, psdoc->font->metrics->fontenc, ai->adobename);
2305 else
2306 strbuf[k++] = ai->adobenum;
2307 }
2308 } else { /* glyph not found */
2309 ps_error(psdoc, PS_Warning, _("Glyph '%s' not found in metric file."), adobename);
2310 }
2311 prevai = ai;
2312 } else {
2313 ps_error(psdoc, PS_Warning, _("Character %d not in input encoding vector."), c);
2314 }
2315 }
2316 psdoc->free(psdoc, textcpy);
2317 /* Output rest of line if there is some left */
2318 if(k > 0) {
2319 strbuf[k] = '\0';
2320 ps_render_text(psdoc, strbuf);
2321 k = 0;
2322 }
2323 psdoc->free(psdoc, strbuf);
2324 ps_printf(psdoc, "\n");
2325 x = psdoc->tstates[psdoc->tstate].tx;
2326 yy = psdoc->tstates[psdoc->tstate].ty;
2327 psdoc->tstates[psdoc->tstate].tx += overallwidth*psdoc->font->size/1000.0;
2328 if(psdoc->underline == ps_true) {
2329 // y = yy + (psdoc->font->metrics->descender-2*psdoc->font->metrics->underlinethickness)*psdoc->font->size/1000.0;
2330 y = yy + (descender-2*psdoc->font->metrics->underlinethickness)*psdoc->font->size/1000.0;
2331 PS_save(psdoc);
2332 PS_setdash(psdoc, 0, 0);
2333 PS_setlinewidth(psdoc, psdoc->font->metrics->underlinethickness*psdoc->font->size/1000.0);
2334 PS_moveto(psdoc, x, y);
2335 PS_lineto(psdoc, x + overallwidth*psdoc->font->size/1000.0, y);
2336 PS_stroke(psdoc);
2337 PS_restore(psdoc);
2338 }
2339 if(psdoc->overline == ps_true) {
2340 y = yy + (psdoc->font->metrics->ascender+2*psdoc->font->metrics->underlinethickness)*psdoc->font->size/1000.0;
2341 PS_save(psdoc);
2342 PS_setdash(psdoc, 0, 0);
2343 PS_setlinewidth(psdoc, psdoc->font->metrics->underlinethickness*psdoc->font->size/1000.0);
2344 PS_moveto(psdoc, x, y);
2345 PS_lineto(psdoc, x + overallwidth*psdoc->font->size/1000.0, y);
2346 PS_stroke(psdoc);
2347 PS_restore(psdoc);
2348 }
2349 if(psdoc->strikeout == ps_true) {
2350 y = yy + (psdoc->font->metrics->ascender)/2*psdoc->font->size/1000.0;
2351 PS_save(psdoc);
2352 PS_setdash(psdoc, 0, 0);
2353 PS_setlinewidth(psdoc, psdoc->font->metrics->underlinethickness*psdoc->font->size/1000.0);
2354 PS_moveto(psdoc, x, y);
2355 PS_lineto(psdoc, x + overallwidth*psdoc->font->size/1000.0, y);
2356 PS_stroke(psdoc);
2357 PS_restore(psdoc);
2358 }
2359 } else {
2360 /* FIXME: ps_render_text() expects the text in fontenc */
2361 ps_render_text(psdoc, text);
2362 }
2363 }
2364 /* }}} */
2365
2366 /* PS_show() {{{
2367 * Output null terminated string
2368 */
2369 PSLIB_API void PSLIB_CALL
PS_show(PSDoc * psdoc,const char * text)2370 PS_show(PSDoc *psdoc, const char *text) {
2371 PS_show2(psdoc, text, 0);
2372 }
2373 /* }}} */
2374
2375 /* PS_continue_text() {{{
2376 * Output text one line after the last line outputed. The line spacing
2377 * is taken from the value 'leading'.
2378 */
2379 PSLIB_API void PSLIB_CALL
PS_continue_text(PSDoc * psdoc,const char * text)2380 PS_continue_text(PSDoc *psdoc, const char *text) {
2381 PS_continue_text2(psdoc, text, 0);
2382 }
2383 /* }}} */
2384
2385 /* PS_continue_text2() {{{
2386 * Output text one line after the last line outputed. The line spacing
2387 * is taken from the value 'leading'. Do not output more than len characters.
2388 */
2389 PSLIB_API void PSLIB_CALL
PS_continue_text2(PSDoc * psdoc,const char * text,int len)2390 PS_continue_text2(PSDoc *psdoc, const char *text, int len) {
2391 int y, x;
2392 if(NULL == psdoc) {
2393 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
2394 return;
2395 }
2396 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
2397 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
2398 return;
2399 }
2400 /* Save the current text position and set it to the text position
2401 * for continued text.
2402 */
2403 y = psdoc->tstates[psdoc->tstate].ty;
2404 x = psdoc->tstates[psdoc->tstate].tx;
2405 psdoc->tstates[psdoc->tstate].cy -= PS_get_value(psdoc, "leading", 0.0);
2406 psdoc->tstates[psdoc->tstate].ty = psdoc->tstates[psdoc->tstate].cy;
2407 psdoc->tstates[psdoc->tstate].tx = psdoc->tstates[psdoc->tstate].cx;
2408 PS_show2(psdoc, text, len);
2409 /* Restore the old text position */
2410 psdoc->tstates[psdoc->tstate].ty = y;
2411 psdoc->tstates[psdoc->tstate].tx = x;
2412 }
2413 /* }}} */
2414
2415 //#define MAX_CHARS_IN_LINE 1024
2416
2417 /* PS_show_boxed() {{{
2418 * Outputs text in a box with given dimensions. The text is justified
2419 * as specified in hmode. This function uses several parameters and values
2420 * to format the output. The return value is the number of characters that
2421 * could not be written.
2422 */
2423 PSLIB_API int PSLIB_CALL
PS_show_boxed(PSDoc * psdoc,const char * text,float left,float bottom,float width,float height,const char * hmode,const char * feature)2424 PS_show_boxed(PSDoc *psdoc, const char *text, float left, float bottom, float width, float height, const char *hmode, const char *feature) {
2425 char *str = NULL;
2426 char *textcopy = NULL;
2427 char *linebuf = NULL;
2428 char prevchar = '\0';
2429 int curpos, lastbreak, lastdelim, firstword, spaces, morechars, mode;
2430 int lineend, parend, boxlinecounter, parlinecounter, *linecounter;
2431 int parcounter, parindentskip;
2432 int numindentlines = 0;
2433 int doindent;
2434 const char *linenumbermode;
2435 float hlen, vlen, xpos, ypos, oldypos, leading, old_word_spacing;
2436 float oldhlen = 0.0;
2437 float parindent, parskip, linewidth, linenumberspace;
2438 float linenumbersep = 5.0;
2439 int hyphenationonoff;
2440 int treatcrasspace = 0;
2441 int treatcraspar = 1;
2442 int hyphenminchars = 3;
2443 int blind = 0;
2444 int fontid;
2445
2446 if(NULL == psdoc) {
2447 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
2448 return 0;
2449 }
2450
2451 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
2452 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
2453 return 0;
2454 }
2455
2456 if(NULL == text)
2457 return 0;
2458
2459 if(NULL == hmode || '\0' == *hmode) {
2460 ps_error(psdoc, PS_RuntimeError, _("Must specify a horizontal mode for PS_show_boxed()."));
2461 return 0;
2462 }
2463
2464 if(0 == strcmp(hmode, "fulljustify")) {
2465 mode = PS_TEXT_HMODE_FULLJUSTIFY;
2466 } else if(0 == strcmp(hmode, "justify")) {
2467 mode = PS_TEXT_HMODE_JUSTIFY;
2468 } else if(0 == strcmp(hmode, "right")) {
2469 mode = PS_TEXT_HMODE_RIGHT;
2470 } else if(0 == strcmp(hmode, "center")) {
2471 mode = PS_TEXT_HMODE_CENTER;
2472 } else if(0 == strcmp(hmode, "left")) {
2473 mode = PS_TEXT_HMODE_LEFT;
2474 } else {
2475 ps_error(psdoc, PS_Warning, _("There is no such horizontal mode like '%s'. Using 'left' instead."), hmode);
2476 mode = PS_TEXT_HMODE_LEFT;
2477 }
2478
2479 if(feature != NULL && 0 == strcmp(feature, "blind")) {
2480 blind = 1;
2481 }
2482
2483 if(NULL == psdoc->font) {
2484 ps_error(psdoc, PS_RuntimeError, _("Cannot output text before setting a font."));
2485 return 0;
2486 }
2487
2488 if(NULL == psdoc->font->metrics) {
2489 ps_error(psdoc, PS_RuntimeError, _("No font metrics loaded."));
2490 return 0;
2491 }
2492 if(!(fontid = _ps_find_font(psdoc, psdoc->font))) {
2493 ps_error(psdoc, PS_RuntimeError, _("Could not find font resource."));
2494 return 0;
2495 }
2496
2497 hyphenationonoff = ps_get_bool_parameter(psdoc, "hyphenation", 0);
2498 if(hyphenationonoff) {
2499 if(!psdoc->hdict) {
2500 ps_error(psdoc, PS_Warning, _("No hyphenation table set, turning hyphenation off."));
2501 hyphenationonoff = ps_false;
2502 } else {
2503 if(0 == (hyphenminchars = (int) PS_get_value(psdoc, "hyphenminchars", 0)))
2504 hyphenminchars = 3;
2505 }
2506 }
2507
2508 /* If CR is treated as line break, it may not be treated as
2509 * parbreak as well.
2510 */
2511 treatcrasspace = !ps_get_bool_parameter(psdoc, "linebreak", 0);
2512 if(treatcrasspace)
2513 treatcraspar = ps_get_bool_parameter(psdoc, "parbreak", 1);
2514 else
2515 treatcraspar = 0;
2516
2517 /* Calculate baseline of first line in box */
2518 ypos = bottom + height - psdoc->font->metrics->ascender*psdoc->font->size/1000.0;
2519 textcopy = ps_strdup(psdoc, text);
2520 str = textcopy;
2521 curpos = 0;
2522 lastbreak = 0;
2523 lastdelim = 0;
2524 vlen = 0;
2525 firstword = 1;
2526 boxlinecounter = 0;
2527 parlinecounter = 0;
2528 parcounter = 0;
2529 if((leading = PS_get_value(psdoc, "leading", 0)) <= 0.0)
2530 leading = (psdoc->font->metrics->ascender - psdoc->font->metrics->descender)*psdoc->font->size*1.2/1000.0;
2531 if((parindent = PS_get_value(psdoc, "parindent", 0)) <= 0.0)
2532 parindent = 0.0;
2533 else {
2534 if((numindentlines = (int) PS_get_value(psdoc, "numindentlines", 0.0)) <= 0)
2535 numindentlines = 1;
2536 }
2537 if((parskip = PS_get_value(psdoc, "parskip", 0)) <= 0.0)
2538 parskip = 0.0;
2539 if((parindentskip = (int) PS_get_value(psdoc, "parindentskip", 0.0)) <= 0)
2540 parindentskip = 0;
2541 linecounter = NULL;
2542 if((linenumbermode = PS_get_parameter(psdoc, "linenumbermode", 0.0)) != NULL) {
2543 if(0 == strcmp(linenumbermode, "paragraph"))
2544 linecounter = &parlinecounter;
2545 else if(0 == strcmp(linenumbermode, "box"))
2546 linecounter = &boxlinecounter;
2547 else
2548 ps_error(psdoc, PS_Warning, _("Unknown line number mode '%s'. Turning line numbering off."), linenumbermode);
2549 if(linecounter) {
2550 if((linenumberspace = PS_get_value(psdoc, "linenumberspace", 0.0)) <= 0.0)
2551 linenumberspace = 20;
2552 if((linenumbersep = PS_get_value(psdoc, "linenumbersep", 0.0)) <= 0.0)
2553 linenumbersep = 5;
2554 width -= (linenumberspace+linenumbersep);
2555 left += (linenumberspace+linenumbersep);
2556
2557 }
2558 }
2559 old_word_spacing = ps_get_word_spacing(psdoc, psdoc->font);
2560 oldypos = ypos;
2561 /* Output text until all shown or the box is full */
2562 while(*str != '\0' && (ypos >= bottom || height == 0.0)) {
2563 /* reset length of line */
2564 hlen = 0.0;
2565 /* Set normal word spacing for the current font */
2566 ps_set_word_spacing(psdoc, psdoc->font, 0.0);
2567 spaces = 0;
2568 firstword = 1;
2569 lineend = ps_false;
2570 parend = ps_false;
2571 linewidth = width;
2572 /* Indent only the first n lines of paragraph, but only starting
2573 * with th m'th paragraph
2574 */
2575 doindent = parlinecounter < numindentlines && parcounter >= parindentskip;
2576 if(doindent) {
2577 linewidth -= parindent;
2578 }
2579 /* Collect text until line is full, line has been ended or no more chars */
2580 while(hlen < linewidth && *str != '\0' && lineend == ps_false && parend == ps_false) {
2581 /* Search for next word boundry (delimiter) */
2582 while(*str != ' ' && *str != '-' && *str != '\n' && *str != '\r' && *str != '�' && *str != '\0') {
2583 prevchar = *str;
2584 str++;
2585 curpos++;
2586 }
2587
2588 /* Treat '\n' and '\r' as space */
2589 if(*str == '\n' || *str == '\r') {
2590 if(!treatcrasspace && *str == '\n') {
2591 lineend = ps_true;
2592 }
2593 if(treatcraspar && prevchar == '\n' && *str == '\n') {
2594 parend = ps_true;
2595 }
2596 } else if(*str == '\t') {
2597 *str = ' ';
2598 }
2599
2600 /* a space at the end of the line has to be skipped, but a '-' or hyphen
2601 * must be displayed and taken into account for stringwidth.
2602 * It could be that there are other words in this line and the
2603 * current char will be the last in the line. For that reason morechars
2604 * is set 0 for each new word boundry which isn't a '-' or a hyphen. */
2605 if(parend) {
2606 morechars = -1;
2607 } else if(*str == '-') {
2608 morechars = 1;
2609 } else {
2610 morechars = 0;
2611 }
2612 /* Calculate the width of the complete line from the last break to
2613 * the current position. Save the old len before, just in case
2614 * the line is too long and we need the old value.
2615 */
2616 oldhlen = hlen;
2617 hlen = PS_stringwidth2(psdoc, &textcopy[lastbreak], curpos-lastbreak+morechars, fontid, psdoc->font->size);
2618 //printf("'%s' (%d) ist %f lang\n", &textcopy[lastbreak], curpos-lastbreak+morechars, hlen);
2619 /* Is the line length still smaller or is this the first word which
2620 * always is displayed even if it ecxeeds the line width.
2621 */
2622 if(hlen < linewidth || firstword == 1) {
2623 // printf("%f ist noch kleiner als %f\n", hlen, width);
2624 lastdelim = curpos;
2625 prevchar = *str;
2626
2627 /* CR in the middle of the line will be made to spaces */
2628 if(*str == '\n')
2629 *str = ' ';
2630
2631 /* Count space for later calculation of spacing between words. Will
2632 * be corrected if this is the last space of a line.
2633 */
2634 if(*str == ' ')
2635 spaces++;
2636
2637 /* We have passed the first word */
2638 firstword = 0;
2639
2640 /* If you are not at the end of the string then move to
2641 * the next char and skip the delimiter. We need to do
2642 * that only if the line isn't full yet, otherwise
2643 * we will drop out of the while loop anyway. */
2644 if(*str != '\0') {
2645 str++;
2646 curpos++;
2647 }
2648 }
2649 }
2650 /* We have dropped the while loop because the text ended before the
2651 * line was full, the line was ended by cr or the line is overfilled.
2652 * curpos and str now point to the next delimiter. The line does not
2653 * contain cr anymore. They has been replaced by spaces. */
2654
2655 /* Do not take the last space in a line into account */
2656 if(textcopy[lastdelim] == ' ')
2657 spaces--;
2658
2659 /* morechars may not have the right value, because it has been set for
2660 * the last character read, which may not be the character at index
2661 * lastdelim. This happens if a word does not fit into the line anymore.
2662 */
2663 if(parend) {
2664 morechars = -1;
2665 } else if(textcopy[lastdelim] != ' ' && textcopy[lastdelim] != '\0') {
2666 morechars = 1;
2667 } else {
2668 morechars = 0;
2669 }
2670 // printf("lastdelim-1 = '%c', curpos-1 = '%c', morechars = %d\n", textcopy[lastdelim-1], textcopy[curpos-1], morechars);
2671 // printf("output line '%s' (%d) has %d spaces\n", &textcopy[lastbreak], lastdelim-lastbreak+morechars, spaces);
2672 //
2673 /* The word between lastdelim and curpos should now be hyphenated.
2674 * No need for hyphenation if there is no more text or the line
2675 * has been ended for some reason (e.g. a cr which was not treated
2676 * as space).
2677 */
2678 if(!lineend && !parend && textcopy[lastdelim] != '\0' && hyphenationonoff) {
2679 char *hyphenword = (char *) ps_calloc(psdoc, (curpos-lastdelim+3)*sizeof(char), _("Could not allocated memory for hyphenated word."));
2680 // printf("Remaining space in line is %.2f\n", linewidth-oldhlen);
2681 if(NULL != hyphenword) {
2682 int i, k, lasthp;
2683 float lenhp = 0.0;
2684
2685 /* Just consider the last word in the line. It starts with
2686 * the last delimiter which can be ' ' or '-' or a hyphen and
2687 * ends it the end of the word. Since curpos points to the next
2688 * delimiter we are set.
2689 */
2690 /* Same situation as with morechars before. If the delimiter is
2691 * not a space or '\0' we have to take it into account.
2692 * Actually it doesn't matter if we take a hyphen into account
2693 * or not, but maybe there is a difference between 'word' and
2694 * 'word-' if it is hyphenated.
2695 */
2696 if(textcopy[curpos] != ' ' && textcopy[curpos] != '\n' && textcopy[curpos] != '\0') {
2697 strncpy(hyphenword, &textcopy[lastdelim+1], curpos-lastdelim-morechars+1);
2698 } else {
2699 strncpy(hyphenword, &textcopy[lastdelim+1], curpos-lastdelim-morechars);
2700 }
2701
2702 lasthp = 0;
2703 /* hyphenate only words with at least 2*hyphenminchars chars
2704 * All chars at the beginning of the word which are not alpha
2705 * will be counted and later taken into account.
2706 */
2707 k = 0;
2708 while(hyphenword[k] && !isalpha(hyphenword[k]))
2709 k++;
2710 if((strlen(hyphenword)-k) > 2*hyphenminchars) {
2711 char *buffer;
2712 char buf1[100];
2713 int l;
2714 /* buf1 will be the partial hyphenated word including all not
2715 * alpha chars at the beginning of the word. This string will
2716 * be used to calculate the len of the line.
2717 */
2718 buffer = (char*) psdoc->malloc(psdoc, sizeof(char) * (strlen(hyphenword)+3), _("Could not allocate memory for hyphenation buffer."));
2719 hnj_hyphen_hyphenate(psdoc->hdict, &hyphenword[k], strlen(&hyphenword[k]), buffer);
2720 // printf("Word to hyphenate: '%s'\n", &hyphenword[k]);
2721 // printf(" %s\n", buffer);
2722 buf1[0] = textcopy[lastdelim];
2723 k++;
2724 for(l=1; l<k; l++) {
2725 buf1[l] = textcopy[lastdelim+1];
2726 }
2727 for(i=hyphenminchars-1, hlen=0; (i < strlen(&hyphenword[k-1])-hyphenminchars) && (hlen < (linewidth-oldhlen)); i++) {
2728 // printf("%c", hyphenword[i]);
2729 if(buffer[i] & 1) {
2730 strncpy(&buf1[k], &hyphenword[k-1], i+1);
2731 buf1[i+k+1] = '�';
2732 buf1[i+k+2] = '\0';
2733 // printf("buf1 = %s\n", buf1);
2734 hlen = PS_stringwidth2(psdoc, buf1, -1, fontid, psdoc->font->size);
2735 if(hlen < (linewidth-oldhlen)) {
2736 lasthp = i+k;
2737 lenhp = hlen;
2738 }
2739 // printf("Len of %s (%d) is %.2f (%.2f)\n", buf1, i+1, hlen, linewidth-oldhlen);
2740 // printf("-");
2741 }
2742 }
2743 // printf("Hyphenation at char %d\n", lasthp+1);
2744 if(lasthp > 0) {
2745 if(textcopy[lastdelim] == ' ') {
2746 spaces++;
2747 }
2748 oldhlen += lenhp;
2749 lastdelim += lasthp;
2750 morechars = 1;
2751 }
2752 psdoc->free(psdoc, buffer);
2753 }
2754 /* At this point we know a possible hyphenation postition. The
2755 * next step would be to take the line concat it with the hyphenated
2756 * word, determine its length, correct curpos, lastdelim, oldhlen
2757 * and str
2758 */
2759
2760 psdoc->free(psdoc, hyphenword);
2761
2762 if(NULL != (linebuf = psdoc->malloc(psdoc, lastdelim-lastbreak+morechars+2, _("Could not allocate memory for line buffer.")))) {
2763 strncpy(linebuf, &textcopy[lastbreak], lastdelim-lastbreak+morechars);
2764 if(lasthp > 0)
2765 linebuf[lastdelim-lastbreak+morechars] = '�';
2766 else
2767 linebuf[lastdelim-lastbreak+morechars] = '\0';
2768 linebuf[lastdelim-lastbreak+morechars+1] = '\0';
2769 } else {
2770 return 0;
2771 }
2772 }
2773 } else {
2774 if(NULL != (linebuf = psdoc->malloc(psdoc, lastdelim-lastbreak+morechars+1, _("Could not allocate memory for line buffer.")))) {
2775 strncpy(linebuf, &textcopy[lastbreak], lastdelim-lastbreak+morechars);
2776 linebuf[lastdelim-lastbreak+morechars] = '\0';
2777 } else {
2778 return 0;
2779 }
2780 }
2781
2782 // printf("Complete line: '%s'\n", linebuf);
2783 // printf("Line has %d spaces\n", spaces);
2784 // printf("Line is %f (%f) long\n\n", PS_stringwidth2(psdoc, linebuf, strlen(linebuf), psdoc->font, psdoc->font->size), oldhlen);
2785
2786 if(!blind) {
2787 /* Recalculate the length of the line, althought oldhlen should contain
2788 * the proper length already, it differs from the len calculated by
2789 * the following line FIXME: must be investigated
2790 */
2791 oldhlen = PS_stringwidth2(psdoc, linebuf, -1, fontid, psdoc->font->size);
2792
2793 xpos = 0.0;
2794 switch(mode) {
2795 case PS_TEXT_HMODE_FULLJUSTIFY:
2796 case PS_TEXT_HMODE_JUSTIFY: {
2797 /* If the paragraph was ended e.g. by a cr, we will not care about
2798 * PS_TEXT_HMODE_JUSTIFY. */
2799 if(parend) {
2800 xpos = left;
2801 } else {
2802 float extraleftspace = 0.0;
2803 float extrarightspace = 0.0;
2804 if(spaces != 0 && *str != '\0' && textcopy[lastdelim] != '\n') {
2805 ADOBEINFO *ai;
2806 unsigned char singlechar;
2807
2808 /* check if the last char of the line may protrude into the right
2809 * margin. */
2810 singlechar = (unsigned char) linebuf[strlen(linebuf)-1];
2811 // printf("Last char of line is %c\n", singlechar);
2812 if(NULL != (ai = gfindadobe(psdoc->font->metrics->gadobechars, ps_inputenc_name(psdoc, singlechar)))) {
2813 // printf("RightMarginKerning for '%s' is %d\n", ps_inputenc_name(psdoc, singlechar), ai->rkern);
2814 extrarightspace = ai->width*psdoc->font->size*ai->rkern/1000000.0;
2815 }
2816
2817 /* check if the first char of the line may protrude into the left
2818 * margin. */
2819 singlechar = (unsigned char) linebuf[0];
2820 // printf("First char of line is %c\n", singlechar);
2821 if(NULL != (ai = gfindadobe(psdoc->font->metrics->gadobechars, ps_inputenc_name(psdoc, singlechar)))) {
2822 // printf("RightMarginKerning for '%s' is %d\n", ps_inputenc_name(psdoc, singlechar), ai->rkern);
2823 extraleftspace = ai->width*psdoc->font->size*ai->lkern/1000000.0;
2824 }
2825 // printf("Set word spacing to %f\n", (linewidth-oldhlen)/spaces);
2826 if((mode == PS_TEXT_HMODE_FULLJUSTIFY) || (ypos-leading >= bottom))
2827 ps_add_word_spacing(psdoc, psdoc->font, (linewidth+extraleftspace+extrarightspace-oldhlen)/(float)spaces);
2828 }
2829 /* set oldhlen to ensure texty is set properly */
2830 oldhlen = linewidth;
2831 xpos = left-extraleftspace;
2832 }
2833 if(doindent) {
2834 xpos += parindent;
2835 }
2836 break;
2837 }
2838 case PS_TEXT_HMODE_LEFT:
2839 /* FIXME: consider left margin kerning, see extraleftspace
2840 * as used above */
2841 xpos = left;
2842 if(doindent) {
2843 xpos += parindent;
2844 }
2845 break;
2846 case PS_TEXT_HMODE_RIGHT:
2847 xpos = left + (linewidth-oldhlen);
2848 break;
2849 case PS_TEXT_HMODE_CENTER:
2850 xpos = left + (linewidth-oldhlen)/2;
2851 break;
2852 }
2853
2854 PS_show_xy2(psdoc, linebuf, strlen(linebuf), xpos, ypos);
2855 if(linecounter) {
2856 char linenumstr[11];
2857 #ifdef HAVE_SNPRINTF
2858 snprintf(linenumstr, 10, "%d", *linecounter+1);
2859 #else
2860 sprintf(linenumstr, "%d", *linecounter+1);
2861 #endif
2862 PS_show_xy2(psdoc, linenumstr, strlen(linenumstr), left-linenumbersep-PS_stringwidth2(psdoc, linenumstr, -1, fontid, psdoc->font->size), ypos);
2863 }
2864 }
2865 psdoc->free(psdoc, linebuf);
2866
2867 // printf("lastdelim = %c (%d), lastbreak = %d\n", textcopy[lastdelim], lastdelim, lastbreak);
2868 /* Set the string position to 1 char after the last delimiter */
2869 if(textcopy[lastdelim] != '\0')
2870 curpos = lastdelim+1;
2871 str = &textcopy[curpos];
2872 lastbreak = lastdelim+1;
2873 /* forward one line by leading */
2874 oldypos = ypos;
2875 ypos = ypos - leading;
2876 boxlinecounter++;
2877 if(parend) {
2878 ypos -= parskip;
2879 parlinecounter = 0;
2880 parcounter++;
2881 } else {
2882 parlinecounter++;
2883 }
2884 }
2885 psdoc->free(psdoc, textcopy);
2886
2887 /* Set new text position. textx may not be set, because it has been set by
2888 * PS_show_xy2() already.
2889 */
2890 if(!blind)
2891 psdoc->tstates[psdoc->tstate].ty = oldypos;
2892 PS_set_value(psdoc, "boxheight", (bottom + height) - (oldypos - leading + psdoc->font->metrics->ascender*psdoc->font->size/1000.0));
2893 // printf("Reset word spacing to %f\n", old_word_spacing);
2894 ps_set_word_spacing(psdoc, psdoc->font, old_word_spacing);
2895 if(text[curpos] == '\0')
2896 return 0;
2897 else
2898 return(ps_strlen(text) - curpos);
2899 }
2900 /* }}} */
2901
2902 /* PS_moveto() {{{
2903 * Moves the current position (cursor) to the passed position
2904 * This function starts a new path if it is called in page-scope,
2905 * otherwise it will set the current point and continues with the
2906 * current path.
2907 */
2908 PSLIB_API void PSLIB_CALL
PS_moveto(PSDoc * psdoc,float x,float y)2909 PS_moveto(PSDoc *psdoc, float x, float y) {
2910 if(NULL == psdoc) {
2911 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
2912 return;
2913 }
2914 if(!ps_check_scope(psdoc, PS_SCOPE_PATH | PS_SCOPE_PAGE | PS_SCOPE_TEMPLATE | PS_SCOPE_PATTERN | PS_SCOPE_GLYPH)) {
2915 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'path', 'template', 'pattern', 'glyph' or 'page' scope."), __FUNCTION__);
2916 return;
2917 }
2918 psdoc->agstates[psdoc->agstate].x = x;
2919 psdoc->agstates[psdoc->agstate].y = y;
2920 /* Only set the scope to PS_SCOPE_PATH if we are not already in that
2921 * scope.
2922 */
2923 if(ps_current_scope(psdoc) != PS_SCOPE_PATH) {
2924 ps_enter_scope(psdoc, PS_SCOPE_PATH);
2925 ps_printf(psdoc, "newpath\n");
2926 }
2927 ps_printf(psdoc, "%.2f %.2f a\n", x, y);
2928 }
2929 /* }}} */
2930
2931 /* PS_show_xy() {{{
2932 * Calls PS_moveto and PS_show to print the text on the selected position
2933 */
2934 PSLIB_API void PSLIB_CALL
PS_show_xy(PSDoc * psdoc,const char * text,float x,float y)2935 PS_show_xy(PSDoc *psdoc, const char *text, float x, float y) {
2936 PS_show_xy2(psdoc, text, 0, x, y);
2937 }
2938 /* }}} */
2939
2940 /* PS_show_xy2() {{{
2941 * Calls PS_moveto and PS_show2 to print the text on the selected position
2942 */
2943 PSLIB_API void PSLIB_CALL
PS_show_xy2(PSDoc * psdoc,const char * text,int xlen,float x,float y)2944 PS_show_xy2(PSDoc *psdoc, const char *text, int xlen, float x, float y) {
2945 if(NULL == psdoc) {
2946 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
2947 return;
2948 }
2949 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
2950 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
2951 return;
2952 }
2953 psdoc->tstates[psdoc->tstate].tx = x;
2954 psdoc->tstates[psdoc->tstate].cx = x;
2955 psdoc->tstates[psdoc->tstate].ty = y;
2956 psdoc->tstates[psdoc->tstate].cy = y;
2957 PS_show2(psdoc, text, xlen);
2958 }
2959 /* }}} */
2960
2961 /* PS_lineto() {{{
2962 * Draws a line from the current point to the passed point
2963 */
2964 PSLIB_API void PSLIB_CALL
PS_lineto(PSDoc * psdoc,float x,float y)2965 PS_lineto(PSDoc *psdoc, float x, float y) {
2966 if(NULL == psdoc) {
2967 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
2968 return;
2969 }
2970 if(!ps_check_scope(psdoc, PS_SCOPE_PATH)) {
2971 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'path' scope."), __FUNCTION__);
2972 return;
2973 }
2974 psdoc->agstates[psdoc->agstate].x = x;
2975 psdoc->agstates[psdoc->agstate].y = y;
2976 ps_printf(psdoc, "%.2f %.2f l\n", x, y);
2977 }
2978 /* }}} */
2979
2980 /* PS_set_text_pos() {{{
2981 * Set the coordinates for the next text output.
2982 */
2983 PSLIB_API void PSLIB_CALL
PS_set_text_pos(PSDoc * psdoc,float x,float y)2984 PS_set_text_pos(PSDoc *psdoc, float x, float y) {
2985 if(NULL == psdoc) {
2986 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
2987 return;
2988 }
2989 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
2990 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
2991 return;
2992 }
2993 psdoc->tstates[psdoc->tstate].tx = x;
2994 psdoc->tstates[psdoc->tstate].ty = y;
2995 psdoc->tstates[psdoc->tstate].cx = x;
2996 psdoc->tstates[psdoc->tstate].cy = y;
2997 }
2998 /* }}} */
2999
3000 /* PS_setlinewidth() {{{
3001 * Set the width of a line for all drawing operations.
3002 */
3003 PSLIB_API void PSLIB_CALL
PS_setlinewidth(PSDoc * p,float width)3004 PS_setlinewidth(PSDoc *p, float width) {
3005 if(NULL == p) {
3006 ps_error(p, PS_RuntimeError, _("PSDoc is null."));
3007 return;
3008 }
3009 if(!ps_check_scope(p, PS_SCOPE_PAGE | PS_SCOPE_TEMPLATE | PS_SCOPE_PATTERN | PS_SCOPE_GLYPH)) {
3010 ps_error(p, PS_RuntimeError, _("%s must be called within 'page', 'template', 'glyph', or 'pattern' scope."), __FUNCTION__);
3011 return;
3012 }
3013 ps_printf(p, "%f setlinewidth\n", width);
3014 }
3015 /* }}} */
3016
3017 /* PS_setlinecap() {{{
3018 * Sets the appearance of the line ends.
3019 */
3020 PSLIB_API void PSLIB_CALL
PS_setlinecap(PSDoc * p,int type)3021 PS_setlinecap(PSDoc *p, int type) {
3022 if(NULL == p) {
3023 ps_error(p, PS_RuntimeError, _("PSDoc is null."));
3024 return;
3025 }
3026 if(!ps_check_scope(p, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3027 ps_error(p, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3028 return;
3029 }
3030 if((type > PS_LINECAP_SQUARED) || (type < PS_LINECAP_BUTT)) {
3031 ps_error(p, PS_Warning, _("Type of linecap is out of range."));
3032 return;
3033 }
3034 ps_printf(p, "%d setlinecap\n", type);
3035 }
3036 /* }}} */
3037
3038 /* PS_setlinejoin() {{{
3039 * Sets how lines are joined in a polygon.
3040 */
3041 PSLIB_API void PSLIB_CALL
PS_setlinejoin(PSDoc * p,int type)3042 PS_setlinejoin(PSDoc *p, int type) {
3043 if(NULL == p) {
3044 ps_error(p, PS_RuntimeError, _("PSDoc is null."));
3045 return;
3046 }
3047 if(!ps_check_scope(p, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3048 ps_error(p, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3049 return;
3050 }
3051 if((type > PS_LINEJOIN_BEVEL) || (type < PS_LINEJOIN_MITER)) {
3052 ps_error(p, PS_Warning, _("Type of linejoin is out of range."));
3053 return;
3054 }
3055 ps_printf(p, "%d setlinejoin\n", type);
3056 }
3057 /* }}} */
3058
3059 /* PS_setmiterlimit() {{{
3060 */
3061 PSLIB_API void PSLIB_CALL
PS_setmiterlimit(PSDoc * p,float value)3062 PS_setmiterlimit(PSDoc *p, float value) {
3063 if(NULL == p) {
3064 ps_error(p, PS_RuntimeError, _("PSDoc is null."));
3065 return;
3066 }
3067 if(!ps_check_scope(p, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3068 ps_error(p, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3069 return;
3070 }
3071 if(value < 1) {
3072 ps_error(p, PS_Warning, _("Miter limit is less than 1."));
3073 return;
3074 }
3075 ps_printf(p, "%f setmiterlimit\n", value);
3076 }
3077 /* }}} */
3078
3079 /* PS_setflat() {{{
3080 */
3081 PSLIB_API void PSLIB_CALL
PS_setflat(PSDoc * p,float value)3082 PS_setflat(PSDoc *p, float value) {
3083 if(NULL == p) {
3084 ps_error(p, PS_RuntimeError, _("PSDoc is null."));
3085 return;
3086 }
3087 if(!ps_check_scope(p, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3088 ps_error(p, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3089 return;
3090 }
3091 if(value < 0.2 || value > 100.0) {
3092 ps_error(p, PS_Warning, _("Flat value is less than 0.2 or bigger than 100.0"));
3093 return;
3094 }
3095 ps_printf(p, "%f setflat\n", value);
3096 }
3097 /* }}} */
3098
3099 /* PS_setdash() {{{
3100 * Sets the length of the black and white portions of a dashed line.
3101 */
3102 PSLIB_API void PSLIB_CALL
PS_setdash(PSDoc * p,float on,float off)3103 PS_setdash(PSDoc *p, float on, float off) {
3104 if(NULL == p) {
3105 ps_error(p, PS_RuntimeError, _("PSDoc is null."));
3106 return;
3107 }
3108 if(!ps_check_scope(p, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3109 ps_error(p, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3110 return;
3111 }
3112 if(on == 0.0 && off == 0.0) {
3113 ps_printf(p, "[] 0 setdash\n");
3114 } else {
3115 ps_printf(p, "[%f %f] 0 setdash\n", on, off);
3116 }
3117 }
3118 /* }}} */
3119
3120 /* PS_setpolydash() {{{
3121 * Sets a more complicated dash line with. arr is list of black and white
3122 * portions.
3123 */
3124 PSLIB_API void PSLIB_CALL
PS_setpolydash(PSDoc * p,float * arr,int length)3125 PS_setpolydash(PSDoc *p, float *arr, int length) {
3126 float *dash;
3127 int i;
3128
3129 if(NULL == p) {
3130 ps_error(p, PS_RuntimeError, _("PSDoc is null."));
3131 return;
3132 }
3133 if(!ps_check_scope(p, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3134 ps_error(p, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3135 return;
3136 }
3137 if(NULL == arr) {
3138 ps_error(p, PS_RuntimeError, _("Array for dashes is NULL."));
3139 return;
3140 }
3141
3142 ps_printf(p, "[");
3143 dash = arr;
3144 for(i=0; i<length; i++, dash++) {
3145 ps_printf(p, "%f ", *dash);
3146 }
3147 ps_printf(p, "] 0 setdash\n");
3148 }
3149 /* }}} */
3150
3151 /* PS_setmatrix() {{{
3152 * FIXME: Not implemented
3153 */
3154 PSLIB_API void PSLIB_CALL
PS_setmatrix(PSDoc * p,float a,float b,float c,float d,float e,float f)3155 PS_setmatrix(PSDoc *p, float a, float b, float c, float d, float e, float f) {
3156 if(NULL == p) {
3157 ps_error(p, PS_RuntimeError, _("PSDoc is null."));
3158 return;
3159 }
3160 if(!ps_check_scope(p, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3161 ps_error(p, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3162 return;
3163 }
3164 }
3165 /* }}} */
3166
3167 /* PS_setoverprintmode() {{{
3168 * Sets overprint flag true or false.
3169 */
3170 PSLIB_API void PSLIB_CALL
PS_setoverprintmode(PSDoc * p,int mode)3171 PS_setoverprintmode(PSDoc *p, int mode) {
3172 if(NULL == p) {
3173 ps_error(p, PS_RuntimeError, _("PSDoc is null."));
3174 return;
3175 }
3176 if(!ps_check_scope(p, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3177 ps_error(p, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3178 return;
3179 }
3180 if((mode > 1) || (mode < 0)) {
3181 ps_error(p, PS_Warning, _("Mode for overprint must be either 0 or 1."));
3182 return;
3183 }
3184 ps_printf(p, "%s setoverprint\n", mode == 0 ? "false" : "true");
3185 }
3186 /* }}} */
3187
3188 /* PS_setsmoothness() {{{
3189 * Sets smoothness.
3190 */
3191 PSLIB_API void PSLIB_CALL
PS_setsmoothness(PSDoc * p,float smoothness)3192 PS_setsmoothness(PSDoc *p, float smoothness) {
3193 if(NULL == p) {
3194 ps_error(p, PS_RuntimeError, _("PSDoc is null."));
3195 return;
3196 }
3197 if(!ps_check_scope(p, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3198 ps_error(p, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3199 return;
3200 }
3201 if((smoothness > 1) || (smoothness < 0)) {
3202 ps_error(p, PS_Warning, _("Smoothness value must be between 0 and 1."));
3203 return;
3204 }
3205 ps_printf(p, "%.4f setsmoothness\n", smoothness);
3206 }
3207 /* }}} */
3208
3209 /* PS_rect() {{{
3210 * Draws a rectangle. The rectancle is either added to the current path
3211 * or starts a new one.
3212 */
3213 PSLIB_API void PSLIB_CALL
PS_rect(PSDoc * psdoc,float x,float y,float width,float height)3214 PS_rect(PSDoc *psdoc, float x, float y, float width, float height) {
3215 if(NULL == psdoc) {
3216 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3217 return;
3218 }
3219 if(!ps_check_scope(psdoc, PS_SCOPE_PATH | PS_SCOPE_PAGE | PS_SCOPE_TEMPLATE | PS_SCOPE_PATTERN | PS_SCOPE_GLYPH)) {
3220 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'path', 'template', 'pattern', 'glyph' or 'page' scope."), __FUNCTION__);
3221 return;
3222 }
3223 psdoc->agstates[psdoc->agstate].x = x;
3224 psdoc->agstates[psdoc->agstate].y = y;
3225 if(ps_current_scope(psdoc) != PS_SCOPE_PATH) {
3226 ps_enter_scope(psdoc, PS_SCOPE_PATH);
3227 ps_printf(psdoc, "newpath\n");
3228 }
3229 ps_printf(psdoc, "%.4f %.4f a\n", x, y);
3230 ps_printf(psdoc, "%.4f %.4f l\n", x+width, y);
3231 ps_printf(psdoc, "%.4f %.4f l\n", x+width, y+height);
3232 ps_printf(psdoc, "%.4f %.4f l\n", x, y+height);
3233 ps_printf(psdoc, "closepath\n");
3234 }
3235 /* }}} */
3236
3237 /* PS_circle() {{{
3238 * Draws a circle
3239 */
3240 PSLIB_API void PSLIB_CALL
PS_circle(PSDoc * psdoc,float x,float y,float radius)3241 PS_circle(PSDoc *psdoc, float x, float y, float radius) {
3242 if(NULL == psdoc) {
3243 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3244 return;
3245 }
3246 if(!ps_check_scope(psdoc, PS_SCOPE_PATH | PS_SCOPE_PAGE | PS_SCOPE_TEMPLATE | PS_SCOPE_PATTERN | PS_SCOPE_GLYPH)) {
3247 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'path', 'template', 'pattern', 'glyph' or 'page' scope."), __FUNCTION__);
3248 return;
3249 }
3250 if(radius < 0.0) {
3251 ps_error(psdoc, PS_RuntimeError, _("Radius for circle is less than 0.0."));
3252 return;
3253 }
3254
3255 psdoc->agstates[psdoc->agstate].x = x;
3256 psdoc->agstates[psdoc->agstate].y = y;
3257 if(ps_current_scope(psdoc) != PS_SCOPE_PATH) {
3258 ps_enter_scope(psdoc, PS_SCOPE_PATH);
3259 ps_printf(psdoc, "newpath\n");
3260 }
3261 ps_printf(psdoc, "%.4f %.4f a\n", x+radius, y);
3262 ps_printf(psdoc, "%.4f %.4f %.4f 0 360 arc\n", x, y, radius);
3263 }
3264 /* }}} */
3265
3266 /* PS_arc() {{{
3267 * Draws an arc counterclockwise
3268 */
3269 PSLIB_API void PSLIB_CALL
PS_arc(PSDoc * psdoc,float x,float y,float radius,float alpha,float beta)3270 PS_arc(PSDoc *psdoc, float x, float y, float radius, float alpha, float beta) {
3271 if(NULL == psdoc) {
3272 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3273 return;
3274 }
3275 if(!ps_check_scope(psdoc, PS_SCOPE_PATH | PS_SCOPE_PAGE | PS_SCOPE_TEMPLATE | PS_SCOPE_PATTERN)) {
3276 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'path', 'template', 'pattern' or 'page' scope."), __FUNCTION__);
3277 return;
3278 }
3279 if(radius < 0.0) {
3280 ps_error(psdoc, PS_RuntimeError, _("Radius for arc is less than 0.0."));
3281 return;
3282 }
3283
3284 psdoc->agstates[psdoc->agstate].x = x;
3285 psdoc->agstates[psdoc->agstate].y = y;
3286 if(ps_current_scope(psdoc) != PS_SCOPE_PATH) {
3287 ps_enter_scope(psdoc, PS_SCOPE_PATH);
3288 ps_printf(psdoc, "newpath\n");
3289 }
3290 // ps_printf(psdoc, "%.4f %.4f a\n", x+radius*cos(alpha/180*M_PI), y+radius*sin(alpha/180*M_PI));
3291 ps_printf(psdoc, "%.4f %.4f %.4f %.4f %.4f arc\n", x, y, radius, alpha, beta);
3292 }
3293 /* }}} */
3294
3295 /* PS_arcn() {{{
3296 * Draws an arc clockwise
3297 */
3298 PSLIB_API void PSLIB_CALL
PS_arcn(PSDoc * psdoc,float x,float y,float radius,float alpha,float beta)3299 PS_arcn(PSDoc *psdoc, float x, float y, float radius, float alpha, float beta) {
3300 if(NULL == psdoc) {
3301 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3302 return;
3303 }
3304 if(!ps_check_scope(psdoc, PS_SCOPE_PATH | PS_SCOPE_PAGE | PS_SCOPE_TEMPLATE | PS_SCOPE_PATTERN)) {
3305 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'path', 'template', 'pattern' or 'page' scope."), __FUNCTION__);
3306 return;
3307 }
3308 if(radius < 0.0) {
3309 ps_error(psdoc, PS_RuntimeError, _("Radius for arc is less than 0.0."));
3310 return;
3311 }
3312
3313 psdoc->agstates[psdoc->agstate].x = x;
3314 psdoc->agstates[psdoc->agstate].y = y;
3315 if(ps_current_scope(psdoc) != PS_SCOPE_PATH) {
3316 ps_enter_scope(psdoc, PS_SCOPE_PATH);
3317 ps_printf(psdoc, "newpath\n");
3318 }
3319 // ps_printf(psdoc, "%.4f %.4f a\n", x+radius*cos(beta/180*M_PI), y+radius*sin(beta/180*M_PI));
3320 ps_printf(psdoc, "%.4f %.4f %.4f %.4f %.4f arcn\n", x, y, radius, alpha, beta);
3321 }
3322 /* }}} */
3323
3324 /* PS_curveto() {{{
3325 * Draws a curve
3326 */
3327 PSLIB_API void PSLIB_CALL
PS_curveto(PSDoc * psdoc,float x1,float y1,float x2,float y2,float x3,float y3)3328 PS_curveto(PSDoc *psdoc, float x1, float y1, float x2, float y2, float x3, float y3) {
3329 if(NULL == psdoc) {
3330 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3331 return;
3332 }
3333 if(!ps_check_scope(psdoc, PS_SCOPE_PATH)) {
3334 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'path' scope."), __FUNCTION__);
3335 return;
3336 }
3337 psdoc->agstates[psdoc->agstate].x = x3;
3338 psdoc->agstates[psdoc->agstate].y = y3;
3339 ps_printf(psdoc, "%f %f %f %f %f %f curveto\n", x1, y1, x2, y2, x3, y3);
3340 }
3341 /* }}} */
3342
3343 /* PS_setgray() {{{
3344 * Sets gray value for following line drawing. 0 means black and 1 means white.
3345 */
3346 PSLIB_API void PSLIB_CALL
PS_setgray(PSDoc * psdoc,float gray)3347 PS_setgray(PSDoc *psdoc, float gray) {
3348 if(NULL == psdoc) {
3349 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3350 return;
3351 }
3352 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE)) {
3353 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page' scope."), __FUNCTION__);
3354 return;
3355 }
3356 ps_printf(psdoc, "%f setgray\n", gray);
3357 }
3358 /* }}} */
3359
3360 /* PS_clip() {{{
3361 * Clips drawing to previously created path.
3362 */
3363 PSLIB_API void PSLIB_CALL
PS_clip(PSDoc * psdoc)3364 PS_clip(PSDoc *psdoc) {
3365 if(NULL == psdoc) {
3366 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3367 return;
3368 }
3369 if(!ps_check_scope(psdoc, PS_SCOPE_PATH)) {
3370 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'path' scope."), __FUNCTION__);
3371 return;
3372 }
3373 ps_printf(psdoc, "clip\n");
3374 ps_leave_scope(psdoc, PS_SCOPE_PATH);
3375 }
3376 /* }}} */
3377
3378 /* PS_closepath() {{{
3379 * Closes a path. Connects the last point with the first point.
3380 */
3381 PSLIB_API void PSLIB_CALL
PS_closepath(PSDoc * psdoc)3382 PS_closepath(PSDoc *psdoc) {
3383 if(NULL == psdoc) {
3384 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3385 return;
3386 }
3387 if(!ps_check_scope(psdoc, PS_SCOPE_PATH)) {
3388 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'path' scope."), __FUNCTION__);
3389 return;
3390 }
3391 ps_printf(psdoc, "closepath\n");
3392 }
3393 /* }}} */
3394
3395 /* PS_closepath_stroke() {{{
3396 * Closes path and draws it.
3397 */
3398 PSLIB_API void PSLIB_CALL
PS_closepath_stroke(PSDoc * psdoc)3399 PS_closepath_stroke(PSDoc *psdoc) {
3400 if(NULL == psdoc) {
3401 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3402 return;
3403 }
3404 if(!ps_check_scope(psdoc, PS_SCOPE_PATH)) {
3405 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'path' scope."), __FUNCTION__);
3406 return;
3407 }
3408 ps_printf(psdoc, "closepath\n");
3409 ps_setcolor(psdoc, PS_COLORTYPE_STROKE);
3410 ps_printf(psdoc, "stroke\n");
3411 ps_leave_scope(psdoc, PS_SCOPE_PATH);
3412 }
3413 /* }}} */
3414
3415 /* PS_fill_stroke() {{{
3416 * Fills and draws a path
3417 */
3418 PSLIB_API void PSLIB_CALL
PS_fill_stroke(PSDoc * psdoc)3419 PS_fill_stroke(PSDoc *psdoc) {
3420 if(NULL == psdoc) {
3421 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3422 return;
3423 }
3424 if(!ps_check_scope(psdoc, PS_SCOPE_PATH)) {
3425 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'path' scope."), __FUNCTION__);
3426 return;
3427 }
3428 ps_printf(psdoc, "gsave ");
3429 ps_setcolor(psdoc, PS_COLORTYPE_FILL);
3430 ps_printf(psdoc, "fill grestore\n");
3431 ps_setcolor(psdoc, PS_COLORTYPE_STROKE);
3432 ps_printf(psdoc, "stroke\n");
3433 ps_leave_scope(psdoc, PS_SCOPE_PATH);
3434 }
3435 /* }}} */
3436
3437 /* PS_stroke() {{{
3438 * Draws a path
3439 */
3440 PSLIB_API void PSLIB_CALL
PS_stroke(PSDoc * psdoc)3441 PS_stroke(PSDoc *psdoc) {
3442 if(NULL == psdoc) {
3443 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3444 return;
3445 }
3446 if(!ps_check_scope(psdoc, PS_SCOPE_PATH)) {
3447 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'path' scope."), __FUNCTION__);
3448 return;
3449 }
3450 ps_setcolor(psdoc, PS_COLORTYPE_STROKE);
3451 ps_printf(psdoc, "stroke\n");
3452 ps_leave_scope(psdoc, PS_SCOPE_PATH);
3453 }
3454 /* }}} */
3455
3456 /* PS_fill() {{{
3457 * Fills a path.
3458 */
3459 PSLIB_API void PSLIB_CALL
PS_fill(PSDoc * psdoc)3460 PS_fill(PSDoc *psdoc) {
3461 if(NULL == psdoc) {
3462 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3463 return;
3464 }
3465 if(!ps_check_scope(psdoc, PS_SCOPE_PATH)) {
3466 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'path' scope."), __FUNCTION__);
3467 return;
3468 }
3469 ps_setcolor(psdoc, PS_COLORTYPE_FILL);
3470 ps_printf(psdoc, "fill\n");
3471 ps_leave_scope(psdoc, PS_SCOPE_PATH);
3472 }
3473 /* }}} */
3474
3475 /* PS_shfill() {{{
3476 * Fills a path with a shading.
3477 */
3478 PSLIB_API void PSLIB_CALL
PS_shfill(PSDoc * psdoc,int shading)3479 PS_shfill(PSDoc *psdoc, int shading) {
3480 PSShading *psshading;
3481 if(NULL == psdoc) {
3482 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3483 return;
3484 }
3485 psshading = _ps_get_shading(psdoc, shading);
3486 if(NULL == psshading) {
3487 ps_error(psdoc, PS_RuntimeError, _("PSShading is null."));
3488 return;
3489 }
3490 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3491 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page', 'pattern' or 'template' scope."), __FUNCTION__);
3492 return;
3493 }
3494
3495 ps_output_shading_dict(psdoc, psshading);
3496 ps_printf(psdoc, "shfill\n");
3497 }
3498 /* }}} */
3499
3500 /* PS_save() {{{
3501 * Saves the current context.
3502 */
3503 PSLIB_API void PSLIB_CALL
PS_save(PSDoc * psdoc)3504 PS_save(PSDoc *psdoc) {
3505 if(NULL == psdoc) {
3506 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3507 return;
3508 }
3509 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3510 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3511 return;
3512 }
3513 if(psdoc->agstate >= PS_MAX_GSTATE_LEVELS-1) {
3514 ps_error(psdoc, PS_Warning, _("No more graphic states available."));
3515 return;
3516 }
3517 /* Take over the old graphics state */
3518 psdoc->agstate++;
3519 memcpy(&(psdoc->agstates[psdoc->agstate]), &(psdoc->agstates[psdoc->agstate-1]), sizeof(PSGState));
3520 psdoc->agstates[psdoc->agstate].x = psdoc->agstates[psdoc->agstate-1].x;
3521 psdoc->agstates[psdoc->agstate].y = psdoc->agstates[psdoc->agstate-1].y;
3522
3523 ps_printf(psdoc, "gsave %% start level %d\n", psdoc->agstate);
3524 }
3525 /* }}} */
3526
3527 /* PS_restore() {{{
3528 * Restores a previously save context.
3529 */
3530 PSLIB_API void PSLIB_CALL
PS_restore(PSDoc * psdoc)3531 PS_restore(PSDoc *psdoc) {
3532 if(NULL == psdoc) {
3533 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3534 return;
3535 }
3536 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3537 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3538 return;
3539 }
3540 if(psdoc->agstate <= 0) {
3541 ps_error(psdoc, PS_Warning, _("PS_restore() has been called more often than PS_save()."));
3542 return;
3543 }
3544 ps_printf(psdoc, "grestore %% end level %d\n", psdoc->agstate);
3545 psdoc->agstate--;
3546 }
3547 /* }}} */
3548
3549 /* PS_create_gstate() {{{
3550 * Creates a new graphic state and returns its id.
3551 */
3552 PSLIB_API int PSLIB_CALL
PS_create_gstate(PSDoc * psdoc,const char * optlist)3553 PS_create_gstate(PSDoc *psdoc, const char *optlist) {
3554 ght_hash_table_t *opthash;
3555 PSGState *psgstate;
3556 int gstateid;
3557
3558 if(NULL == psdoc) {
3559 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3560 return(0);
3561 }
3562 if(NULL != optlist && optlist[0] != '\0') {
3563 ps_error(psdoc, PS_RuntimeError, _("Option list may not be empty."));
3564 return(0);
3565 }
3566
3567 if(NULL == (opthash = ps_parse_optlist(psdoc, optlist))) {
3568 ps_error(psdoc, PS_RuntimeError, _("Error while parsing option list."));
3569 return(0);
3570 }
3571
3572 if(NULL == (psgstate = (PSGState *) psdoc->malloc(psdoc, sizeof(PSGState), _("Allocate memory for graphic state.")))) {
3573 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for graphic state."));
3574 return(0);
3575 }
3576 memset(psgstate, 0, sizeof(PSGState));
3577 psgstate->opthash = opthash;
3578 if(0 == (gstateid = _ps_register_gstate(psdoc, psgstate))) {
3579 ps_error(psdoc, PS_MemoryError, _("Could not register gstate."));
3580 psdoc->free(psdoc, psgstate);
3581 return(0);
3582 }
3583
3584 return(gstateid);
3585 }
3586 /* }}} */
3587
3588 /* PS_set_gstate() {{{
3589 * Sets a graphic state.
3590 */
3591 PSLIB_API void PSLIB_CALL
PS_set_gstate(PSDoc * psdoc,int gstate)3592 PS_set_gstate(PSDoc *psdoc, int gstate) {
3593 ght_hash_table_t *opthash;
3594 ght_iterator_t iterator;
3595 PSGState *psgstate;
3596 char *optvalue, *optname;
3597
3598 if(NULL == psdoc) {
3599 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3600 return;
3601 }
3602 psgstate = _ps_get_gstate(psdoc, gstate);
3603 if(NULL == psgstate) {
3604 ps_error(psdoc, PS_RuntimeError, _("PSGState is null."));
3605 return;
3606 }
3607 opthash = psgstate->opthash;
3608 for(optvalue = ght_first(opthash, &iterator, (void **) &optname); optvalue != NULL; optvalue = ght_next(opthash, &iterator, (void **) &optname)) {
3609 if(strcmp(optname, "setsmoothness") == 0) {
3610 float smoothness;
3611 if(0 == (smoothness = get_optlist_element_as_float(psdoc, opthash, "setsmoothness", &smoothness))) {
3612 PS_setsmoothness(psdoc, smoothness);
3613 }
3614 } else if(strcmp(optname, "linewidth") == 0) {
3615 float linewidth;
3616 if(0 == (linewidth = get_optlist_element_as_float(psdoc, opthash, "linewidth", &linewidth))) {
3617 PS_setlinewidth(psdoc, linewidth);
3618 }
3619 } else if(strcmp(optname, "linecap") == 0) {
3620 int linecap;
3621 if(0 == (linecap = get_optlist_element_as_int(psdoc, opthash, "linecap", &linecap))) {
3622 PS_setlinecap(psdoc, linecap);
3623 }
3624 } else if(strcmp(optname, "linejoin") == 0) {
3625 int linejoin;
3626 if(0 == (linejoin = get_optlist_element_as_int(psdoc, opthash, "linejoin", &linejoin))) {
3627 PS_setlinejoin(psdoc, linejoin);
3628 }
3629 } else if(strcmp(optname, "flatness") == 0) {
3630 float flatness;
3631 if(0 == (flatness = get_optlist_element_as_float(psdoc, opthash, "flatness", &flatness))) {
3632 PS_setflat(psdoc, flatness);
3633 }
3634 } else if(strcmp(optname, "miterlimit") == 0) {
3635 float miterlimit;
3636 if(0 == (miterlimit = get_optlist_element_as_float(psdoc, opthash, "miterlimit", &miterlimit))) {
3637 PS_setmiterlimit(psdoc, miterlimit);
3638 }
3639 } else if(strcmp(optname, "overprintmode") == 0) {
3640 int overprintmode;
3641 if(0 == (overprintmode = get_optlist_element_as_int(psdoc, opthash, "overprintmode", &overprintmode))) {
3642 PS_setoverprintmode(psdoc, overprintmode);
3643 }
3644 } else {
3645 ps_error(psdoc, PS_Warning, _("Graphic state contains unknown option."));
3646 }
3647 }
3648 }
3649 /* }}} */
3650
3651 /* PS_rotate() {{{
3652 * Rotates the coordinate system, which will effect all following drawing
3653 * operations.
3654 */
3655 PSLIB_API void PSLIB_CALL
PS_rotate(PSDoc * psdoc,float x)3656 PS_rotate(PSDoc *psdoc, float x) {
3657 if(NULL == psdoc) {
3658 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3659 return;
3660 }
3661 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3662 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3663 return;
3664 }
3665 ps_printf(psdoc, "%f rotate\n", x);
3666 }
3667 /* }}} */
3668
3669 /* PS_translate() {{{
3670 * Translates the coordinate system, which will effect all following drawing
3671 * operations.
3672 */
3673 PSLIB_API void PSLIB_CALL
PS_translate(PSDoc * psdoc,float x,float y)3674 PS_translate(PSDoc *psdoc, float x, float y) {
3675 if(NULL == psdoc) {
3676 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3677 return;
3678 }
3679 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3680 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3681 return;
3682 }
3683 ps_printf(psdoc, "%.2f %.2f translate\n", x, y);
3684 }
3685 /* }}} */
3686
3687 /* PS_skew() {{{
3688 * FIXME: must be implemented
3689 * Skew the coordinate system
3690 */
3691 PSLIB_API void PSLIB_CALL
PS_skew(PSDoc * psdoc,float alpha,float beta)3692 PS_skew(PSDoc *psdoc, float alpha, float beta) {
3693 if(NULL == psdoc) {
3694 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3695 return;
3696 }
3697 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3698 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3699 return;
3700 }
3701 }
3702 /* }}} */
3703
3704 /* PS_concat() {{{
3705 * FIXME: must be implemented
3706 * Concatenate matrix to current transformation matrix
3707 */
3708 PSLIB_API void PSLIB_CALL
PS_concat(PSDoc * psdoc,float a,float b,float c,float d,float e,float f)3709 PS_concat(PSDoc *psdoc, float a, float b, float c, float d, float e, float f) {
3710 if(NULL == psdoc) {
3711 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3712 return;
3713 }
3714 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3715 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3716 return;
3717 }
3718 }
3719 /* }}} */
3720
3721 /* PS_scale() {{{
3722 * Scales the coordinate system, which will effect all following drawing
3723 * operations.
3724 */
3725 PSLIB_API void PSLIB_CALL
PS_scale(PSDoc * psdoc,float x,float y)3726 PS_scale(PSDoc *psdoc, float x, float y) {
3727 if(NULL == psdoc) {
3728 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3729 return;
3730 }
3731 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3732 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3733 return;
3734 }
3735 ps_printf(psdoc, "%f %f scale\n", x, y);
3736 }
3737 /* }}} */
3738
3739 /* PS_setcolor() {{{
3740 * Sets drawing color for all following operations
3741 */
3742 PSLIB_API void PSLIB_CALL
PS_setcolor(PSDoc * psdoc,const char * type,const char * colorspace,float c1,float c2,float c3,float c4)3743 PS_setcolor(PSDoc *psdoc, const char *type, const char *colorspace, float c1, float c2, float c3, float c4) {
3744 int icolorspace = 0;
3745
3746 if(NULL == psdoc) {
3747 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3748 return;
3749 }
3750 /* FIXME: Maybe called in pattern only if painttype = 1 */
3751 if(!ps_check_scope(psdoc, PS_SCOPE_PROLOG|PS_SCOPE_DOCUMENT|PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3752 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'prolog', 'document', 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3753 return;
3754 }
3755 if(!type || !*type) {
3756 ps_error(psdoc, PS_RuntimeError, _("Missing parameter type in PS_setcolor()."));
3757 return;
3758 }
3759 if(0 != strcmp(type, "fill") && 0 != strcmp(type, "stroke") && 0 != strcmp(type, "both") && 0 != strcmp(type, "fillstroke")) {
3760 ps_error(psdoc, PS_RuntimeError, _("Type in PS_setcolor() is none of 'fill', 'stroke' or 'fillstroke'."));
3761 return;
3762 }
3763
3764 if(!colorspace || !*colorspace) {
3765 ps_error(psdoc, PS_RuntimeError, _("Missing paramter colorspace in PS_setcolor()."));
3766 return;
3767 }
3768
3769 if(0 == strcmp(colorspace, "gray")) {
3770 if(c1 > 1.0 || c1 < 0.0) {
3771 ps_error(psdoc, PS_RuntimeError, _("Gray value out of range 0-1."));
3772 return;
3773 }
3774 icolorspace = PS_COLORSPACE_GRAY;
3775 // ps_printf(psdoc, "/DeviceGray setcolorspace %f setcolor\n", c1);
3776 // ps_printf(psdoc, "%f setgray\n", c1);
3777 } else if(0 == strcmp(colorspace, "rgb")) {
3778 if(c1 > 1.0 || c1 < 0.0) {
3779 ps_error(psdoc, PS_RuntimeError, _("Red value out of range 0-1."));
3780 return;
3781 }
3782 if(c2 > 1.0 || c2 < 0.0) {
3783 ps_error(psdoc, PS_RuntimeError, _("Green value out of range 0-1."));
3784 return;
3785 }
3786 if(c3 > 1.0 || c3 < 0.0) {
3787 ps_error(psdoc, PS_RuntimeError, _("Blue value out of range 0-1."));
3788 return;
3789 }
3790 icolorspace = PS_COLORSPACE_RGB;
3791 // ps_printf(psdoc, "/DeviceRGB setcolorspace %.4f %.4f %.4f setcolor\n", c1, c2, c3);
3792 // ps_printf(psdoc, "%.4f %.4f %.4f setrgbcolor\n", c1, c2, c3);
3793 } else if(0 == strcmp(colorspace, "cmyk")) {
3794 if(c1 > 1.0 || c1 < 0.0) {
3795 ps_error(psdoc, PS_RuntimeError, _("Cyan value out of range 0-1."));
3796 return;
3797 }
3798 if(c2 > 1.0 || c2 < 0.0) {
3799 ps_error(psdoc, PS_RuntimeError, _("Magenta value out of range 0-1."));
3800 return;
3801 }
3802 if(c3 > 1.0 || c3 < 0.0) {
3803 ps_error(psdoc, PS_RuntimeError, _("Yellow value out of range 0-1."));
3804 return;
3805 }
3806 if(c4 > 1.0 || c4 < 0.0) {
3807 ps_error(psdoc, PS_RuntimeError, _("Black value out of range 0-1."));
3808 return;
3809 }
3810 icolorspace = PS_COLORSPACE_CMYK;
3811 // ps_printf(psdoc, "/DeviceCMYK setcolorspace %.4f %.4f %.4f %.4f setcolor\n", c1, c2, c3, c4);
3812 // ps_printf(psdoc, "%.4f %.4f %.4f %.4f setcmykcolor\n", c1, c2, c3, c4);
3813 } else if(0 == strcmp(colorspace, "pattern")) {
3814 PSPattern *pspattern = _ps_get_pattern(psdoc, (int) c1);
3815 if(NULL == pspattern) {
3816 ps_error(psdoc, PS_RuntimeError, _("PSPattern is null."));
3817 return;
3818 }
3819 icolorspace = PS_COLORSPACE_PATTERN;
3820 // ps_printf(psdoc, "/Pattern setcolorspace %s setcolor\n", pspattern->name);
3821 // ps_printf(psdoc, "%s setpattern\n", pspattern->name);
3822 } else if(0 == strcmp(colorspace, "spot")) {
3823 PSSpotColor *spotcolor;
3824 spotcolor = _ps_get_spotcolor(psdoc, (int) c1);
3825 if(!spotcolor) {
3826 ps_error(psdoc, PS_RuntimeError, _("Could not find spot color."));
3827 return;
3828 }
3829 if(c2 > 1.0 || c2 < 0.0) {
3830 ps_error(psdoc, PS_RuntimeError, _("Tint value out of range 0-1."));
3831 return;
3832 }
3833 icolorspace = PS_COLORSPACE_SPOT;
3834 } else {
3835 ps_error(psdoc, PS_RuntimeError, _("Colorspace in PS_setcolor() is not in 'gray', 'rgb', 'cmyk', 'spot', or 'pattern'."));
3836 }
3837
3838 if(0 == strcmp(type, "fill") || 0 == strcmp(type, "both") || 0 == strcmp(type, "fillstroke")) {
3839 psdoc->agstates[psdoc->agstate].fillcolor.prevcolorspace = psdoc->agstates[psdoc->agstate].fillcolor.colorspace;
3840 psdoc->agstates[psdoc->agstate].fillcolor.colorspace = icolorspace;
3841 psdoc->agstates[psdoc->agstate].fillcolorinvalid = ps_true;
3842 switch(icolorspace) {
3843 case PS_COLORSPACE_GRAY:
3844 psdoc->agstates[psdoc->agstate].fillcolor.c1 = c1;
3845 psdoc->agstates[psdoc->agstate].fillcolor.c2 = 0;
3846 psdoc->agstates[psdoc->agstate].fillcolor.c3 = 0;
3847 psdoc->agstates[psdoc->agstate].fillcolor.c4 = 0;
3848 break;
3849 case PS_COLORSPACE_RGB:
3850 psdoc->agstates[psdoc->agstate].fillcolor.c1 = c1;
3851 psdoc->agstates[psdoc->agstate].fillcolor.c2 = c2;
3852 psdoc->agstates[psdoc->agstate].fillcolor.c3 = c3;
3853 psdoc->agstates[psdoc->agstate].fillcolor.c4 = 0;
3854 break;
3855 case PS_COLORSPACE_CMYK:
3856 psdoc->agstates[psdoc->agstate].fillcolor.c1 = c1;
3857 psdoc->agstates[psdoc->agstate].fillcolor.c2 = c2;
3858 psdoc->agstates[psdoc->agstate].fillcolor.c3 = c3;
3859 psdoc->agstates[psdoc->agstate].fillcolor.c4 = c4;
3860 break;
3861 case PS_COLORSPACE_SPOT:
3862 psdoc->agstates[psdoc->agstate].fillcolor.c1 = c1;
3863 psdoc->agstates[psdoc->agstate].fillcolor.c2 = c2;
3864 break;
3865 case PS_COLORSPACE_PATTERN:
3866 psdoc->agstates[psdoc->agstate].fillcolor.pattern = c1;
3867 break;
3868 }
3869 }
3870 if(0 == strcmp(type, "stroke") || 0 == strcmp(type, "both") || 0 == strcmp(type, "fillstroke")) {
3871 psdoc->agstates[psdoc->agstate].strokecolor.prevcolorspace = psdoc->agstates[psdoc->agstate].strokecolor.colorspace;
3872 psdoc->agstates[psdoc->agstate].strokecolor.colorspace = icolorspace;
3873 psdoc->agstates[psdoc->agstate].strokecolorinvalid = ps_true;
3874 switch(icolorspace) {
3875 case PS_COLORSPACE_GRAY:
3876 psdoc->agstates[psdoc->agstate].strokecolor.c1 = c1;
3877 psdoc->agstates[psdoc->agstate].strokecolor.c2 = 0;
3878 psdoc->agstates[psdoc->agstate].strokecolor.c3 = 0;
3879 psdoc->agstates[psdoc->agstate].strokecolor.c4 = 0;
3880 break;
3881 case PS_COLORSPACE_RGB:
3882 psdoc->agstates[psdoc->agstate].strokecolor.c1 = c1;
3883 psdoc->agstates[psdoc->agstate].strokecolor.c2 = c2;
3884 psdoc->agstates[psdoc->agstate].strokecolor.c3 = c3;
3885 psdoc->agstates[psdoc->agstate].strokecolor.c4 = 0;
3886 break;
3887 case PS_COLORSPACE_CMYK:
3888 psdoc->agstates[psdoc->agstate].strokecolor.c1 = c1;
3889 psdoc->agstates[psdoc->agstate].strokecolor.c2 = c2;
3890 psdoc->agstates[psdoc->agstate].strokecolor.c3 = c3;
3891 psdoc->agstates[psdoc->agstate].strokecolor.c4 = c4;
3892 break;
3893 case PS_COLORSPACE_SPOT:
3894 psdoc->agstates[psdoc->agstate].strokecolor.c1 = c1;
3895 psdoc->agstates[psdoc->agstate].strokecolor.c2 = c2;
3896 break;
3897 case PS_COLORSPACE_PATTERN:
3898 psdoc->agstates[psdoc->agstate].strokecolor.pattern = c1;
3899 break;
3900 }
3901 }
3902
3903 return;
3904 }
3905 /* }}} */
3906
3907 /* PS_makespotcolor() {{{
3908 * Creates a spot color from the current fill color
3909 */
3910 PSLIB_API int PSLIB_CALL
PS_makespotcolor(PSDoc * psdoc,const char * name,int reserved)3911 PS_makespotcolor(PSDoc *psdoc, const char *name, int reserved) {
3912 PSSpotColor *spotcolor;
3913 int ispotcolor;
3914 int spotcolorid;
3915
3916 if(NULL == psdoc) {
3917 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3918 return(0);
3919 }
3920
3921 if(!ps_check_scope(psdoc, PS_SCOPE_PROLOG|PS_SCOPE_DOCUMENT|PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3922 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'prolog', 'document', 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3923 return(0);
3924 }
3925
3926 if(0 != (ispotcolor = _ps_find_spotcolor_by_name(psdoc, name))) {
3927 return(ispotcolor);
3928 }
3929
3930 if(psdoc->agstates[psdoc->agstate].fillcolor.colorspace != PS_COLORSPACE_GRAY &&
3931 psdoc->agstates[psdoc->agstate].fillcolor.colorspace != PS_COLORSPACE_RGB &&
3932 psdoc->agstates[psdoc->agstate].fillcolor.colorspace != PS_COLORSPACE_CMYK) {
3933 ps_error(psdoc, PS_MemoryError, _("Cannot make a spot color from a spot color or pattern."));
3934 return(0);
3935 }
3936
3937 if(NULL == (spotcolor = (PSSpotColor *) psdoc->malloc(psdoc, sizeof(PSSpotColor), _("Allocate memory for spot color.")))) {
3938 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for spot color."));
3939 return(0);
3940 }
3941 memset(spotcolor, 0, sizeof(PSSpotColor));
3942 if(0 == (spotcolorid = _ps_register_spotcolor(psdoc, spotcolor))) {
3943 ps_error(psdoc, PS_MemoryError, _("Could not register spotcolor."));
3944 psdoc->free(psdoc, spotcolor);
3945 return(0);
3946 }
3947
3948 spotcolor->name = ps_strdup(psdoc, name);
3949 spotcolor->colorspace = psdoc->agstates[psdoc->agstate].fillcolor.colorspace;
3950 spotcolor->c1 = psdoc->agstates[psdoc->agstate].fillcolor.c1;
3951 spotcolor->c2 = psdoc->agstates[psdoc->agstate].fillcolor.c2;
3952 spotcolor->c3 = psdoc->agstates[psdoc->agstate].fillcolor.c3;
3953 spotcolor->c4 = psdoc->agstates[psdoc->agstate].fillcolor.c4;
3954
3955 return(spotcolorid);
3956 }
3957 /* }}} */
3958
3959 /* PS_findfont() {{{
3960 * Finds a font. Actually tries to load an afm file for the given fontname.
3961 * Resource of the font must be freed with PS_delete_font()
3962 */
3963 PSLIB_API int PSLIB_CALL
PS_findfont(PSDoc * psdoc,const char * fontname,const char * encoding,int embed)3964 PS_findfont(PSDoc *psdoc, const char *fontname, const char *encoding, int embed) {
3965 PSFont *psfont;
3966 ADOBEFONTMETRIC *metrics;
3967 char *filename;
3968 const char *myenc;
3969
3970 if(NULL == psdoc) {
3971 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
3972 return(0);
3973 }
3974 /* Check if this function does any output. If it does and we are
3975 * beyond the header already, then issue
3976 * a warning, because if the output goes between pages it will be lost
3977 * when extracting certain pages from the document
3978 */
3979 if(psdoc->headerwritten && (embed || (encoding != NULL && encoding[0] != '\0'))) {
3980 /* If the header has not been written, we do not need to check the
3981 * scope.
3982 */
3983 if(ps_check_scope(psdoc, PS_SCOPE_DOCUMENT)) {
3984 ps_error(psdoc, PS_Warning, _("Calling %s between pages is likely to cause problems when viewing the document. Call in within a page or in the prolog."), __FUNCTION__);
3985 }
3986 }
3987 if(!ps_check_scope(psdoc, PS_SCOPE_PROLOG|PS_SCOPE_PAGE|PS_SCOPE_DOCUMENT|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
3988 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'prolog', 'document', 'page', 'pattern', or 'template' scope."), __FUNCTION__);
3989 return(0);
3990 }
3991
3992 if(NULL == fontname) {
3993 ps_error(psdoc, PS_RuntimeError, _("No font name give to PS_findfont()."));
3994 return(0);
3995 }
3996
3997 if(NULL == (psfont = (PSFont *) psdoc->malloc(psdoc, sizeof(PSFont), _("Allocate memory for font.")))) {
3998 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for font."));
3999 return(0);
4000 }
4001
4002 /* Remember the PSDoc for which the font was loaded. */
4003 psfont->psdoc = psdoc;
4004
4005 filename = ps_find_resource(psdoc, "FontAFM", fontname);
4006 if(NULL == filename) {
4007 if(NULL == (filename = (char *) psdoc->malloc(psdoc, strlen(fontname)+5, _("Could not allocate memory for afm filename.")))) {
4008 return(0);
4009 }
4010 strcpy(filename, fontname);
4011 strcat(filename, ".afm");
4012 metrics = readadobe(psdoc, filename);
4013 psdoc->free(psdoc, filename);
4014 } else {
4015 metrics = readadobe(psdoc, filename);
4016 }
4017
4018 if(metrics == NULL) {
4019 ps_error(psdoc, PS_RuntimeError, _("Font metrics could not be loaded (%s)."), fontname);
4020 psdoc->free(psdoc, psfont);
4021 return(0);
4022 }
4023
4024 myenc = encoding;
4025 if((myenc == NULL || myenc[0] == '\0') && (NULL == (myenc = ps_find_resource(psdoc, "FontEncoding", fontname)))) {
4026 /* The encoding vector for the default encoding is already
4027 * part of the prolog and need not be output.
4028 */
4029 readencoding(psdoc, metrics, NULL);
4030 psfont->encoding = ps_strdup(psdoc, "default");
4031 } else {
4032 if(!strcmp(myenc, "builtin")) {
4033 psfont->encoding = ps_strdup(psdoc, myenc);
4034 metrics->fontenc = ps_build_enc_from_font(psdoc, metrics);
4035 if(metrics->codingscheme)
4036 psdoc->free(psdoc, metrics->codingscheme);
4037 metrics->codingscheme = ps_strdup(psdoc, metrics->fontname);
4038
4039 } else {
4040 if(0 > readencoding(psdoc, metrics, myenc)) {
4041 ps_error(psdoc, PS_RuntimeError, _("Encoding file could not be loaded (%s)."), myenc);
4042 psdoc->free(psdoc, psfont);
4043 return 0;
4044 }
4045 psfont->encoding = ps_strdup(psdoc, myenc);
4046 }
4047
4048 /* If the header is not written, because we are before
4049 * the first page, then output the header first.
4050 */
4051 if(psdoc->beginprologwritten == ps_false) {
4052 ps_write_ps_comments(psdoc);
4053 ps_write_ps_beginprolog(psdoc);
4054 }
4055
4056 /* Output the encoding vector */
4057 {
4058 int i, j;
4059 ENCODING *fontenc;
4060 fontenc = ps_build_enc_vector(psdoc, metrics->fontenc);
4061 ps_printf(psdoc, "/fontenc-%s [\n", metrics->codingscheme);
4062 for(i=0; i<32; i++) {
4063 for(j=0; j<8; j++) {
4064 if((fontenc->vec[i*8+j] != NULL) && (*(fontenc->vec[i*8+j]) != '\0'))
4065 ps_printf(psdoc, "8#%03o /%s ", i*8+j, fontenc->vec[i*8+j]);
4066 }
4067 ps_printf(psdoc, "\n");
4068 }
4069 ps_printf(psdoc, "] def\n");
4070 ps_free_enc_vector(psdoc, fontenc);
4071 }
4072 }
4073
4074 psfont->metrics = metrics;
4075
4076 if(ps_get_bool_parameter(psdoc, "kerning", 0)) {
4077 filename = ps_find_resource(psdoc, "FontProtusion", fontname);
4078 if(NULL == filename) {
4079 if(NULL == (filename = (char *) psdoc->malloc(psdoc, strlen(fontname)+5, _("Could not allocate memory for afm filename.")))) {
4080 return(0);
4081 }
4082 strcpy(filename, fontname);
4083 strcat(filename, ".pro");
4084 if(0 > readprotusion(psdoc, psfont, filename))
4085 ps_error(psdoc, PS_Warning, _("Could not open protusion file: %s"), filename);
4086 psdoc->free(psdoc, filename);
4087 } else {
4088 if(0 > readprotusion(psdoc, psfont, filename))
4089 ps_error(psdoc, PS_Warning, _("Could not open protusion file: %s"), filename);
4090 }
4091 }
4092
4093 ps_set_word_spacing(psdoc, psfont, 0.0);
4094 if(embed) {
4095 FILE *fp;
4096 long fsize;
4097 filename = ps_find_resource(psdoc, "FontOutline", fontname);
4098
4099 if(NULL == filename) {
4100 if(NULL == (filename = (char *) psdoc->malloc(psdoc, strlen(fontname)+5, _("Could not allocate memory for pfb filename.")))) {
4101 return(0);
4102 }
4103 strcpy(filename, fontname);
4104 strcat(filename, ".pfb");
4105 fp = ps_open_file_in_path(psdoc, filename);
4106 psdoc->free(psdoc, filename);
4107 } else {
4108 fp = ps_open_file_in_path(psdoc, filename);
4109 }
4110 if (fp) {
4111 unsigned char *bb;
4112 fseek(fp, 0, SEEK_END);
4113 fsize = ftell(fp);
4114 fseek(fp, 0, SEEK_SET);
4115 if(NULL != (bb = psdoc->malloc(psdoc, fsize, _("Could not allocate memory for content of font outline file.")))) {
4116 int ts = fread(bb, 1, fsize, fp);
4117 if ((bb[0] == (unsigned char) 128) && (bb[1]) == (unsigned char) 1) {
4118 unsigned int ulen, j;
4119 unsigned int posi,cxxc=0;
4120 char linebuf[80];
4121
4122 /* If the header is not written, because we are before
4123 * the first page, then output the header first.
4124 */
4125 if(psdoc->beginprologwritten == ps_false) {
4126 ps_write_ps_comments(psdoc);
4127 ps_write_ps_beginprolog(psdoc);
4128 }
4129
4130 ps_printf(psdoc, "%%BeginFont: %s\n", fontname);
4131 for (posi = 6; posi < fsize; posi++) {
4132 if ((bb[posi] == (unsigned char) 128) && (bb[posi+1] == (unsigned char) 2))
4133 break;
4134 if(bb[posi] != (unsigned char) '\r')
4135 ps_putc(psdoc, bb[posi]);
4136 else if(bb[posi] == (unsigned char) '\r' && bb[posi+1] != (unsigned char) '\n')
4137 ps_putc(psdoc, '\n');
4138 }
4139 ulen = bb[posi+2] & 0xff;
4140 ulen |= (bb[posi+3] << 8) & 0xff00;
4141 ulen |= (bb[posi+4] << 16) & 0xff0000;
4142 ulen |= (bb[posi+5] << 24) & 0xff000000;
4143 if (ulen > fsize)
4144 ulen = fsize-7;
4145 posi += 6;
4146 cxxc=0;
4147 for (j = 0; j < ulen; j++) {
4148 unsigned char u=bb[posi];
4149 linebuf[cxxc]=((u >> 4) & 15) + '0';
4150 if(u>0x9f) linebuf[cxxc]+='a'-':';
4151 ++cxxc;
4152 u&=15; linebuf[cxxc]=u + '0';
4153 if(u>0x9) linebuf[cxxc]+='a'-':';
4154 ++posi;
4155 ++cxxc;
4156 if (cxxc > 72) {
4157 linebuf[cxxc++]='\n';
4158 linebuf[cxxc++]=0;
4159 ps_printf(psdoc, "%s", linebuf);
4160 cxxc = 0;
4161 }
4162 }
4163 linebuf[cxxc]=0;
4164 ps_printf(psdoc, "%s\n", linebuf);
4165 posi += 6;
4166 for (j = posi; j < fsize; j++) {
4167 if ((bb[j] == (unsigned char) 128) && (bb[j+1] == (unsigned char) 3))
4168 break;
4169 if(bb[j]=='\r')
4170 ps_printf(psdoc, "\n");
4171 else
4172 ps_printf(psdoc, "%c", bb[j]);
4173 }
4174 ps_printf(psdoc, "\n");
4175 cxxc = 0;
4176 ps_printf(psdoc, "%%EndFont\n");
4177 } else {
4178 ps_error(psdoc, PS_Warning, _("Outline of font '%s' does not start with 0x80 0x01"), fontname);
4179 }
4180 psdoc->free(psdoc, bb);
4181 } else {
4182 ps_error(psdoc, PS_Warning, _("Problems while reading font outline for '%s'."), fontname);
4183 }
4184 fclose(fp);
4185 } else {
4186 ps_error(psdoc, PS_Warning, _("Font outline could not be loaded for '%s'."), fontname);
4187 }
4188 }
4189 return(_ps_register_font(psdoc, psfont));
4190 }
4191 /* }}} */
4192
4193 /* PS_load_font() {{{
4194 * Finds a font. Actually tries to load an afm file for the given fontname.
4195 * Resource of the font must be freed with PS_delete_font()
4196 */
4197 PSLIB_API int PSLIB_CALL
PS_load_font(PSDoc * psdoc,const char * fontname,int len,const char * encoding,const char * optlist)4198 PS_load_font(PSDoc *psdoc, const char *fontname, int len, const char *encoding, const char *optlist) {
4199 ght_hash_table_t *opthash;
4200 ps_bool optlist_embedding = 0;
4201 /* Read the option list only, if it is non empty. */
4202 if(NULL != optlist && optlist[0] != '\0') {
4203 opthash = ps_parse_optlist(psdoc, optlist);
4204 if(NULL == opthash) {
4205 ps_error(psdoc, PS_RuntimeError, _("Error while parsing option list."));
4206 return(0);
4207 }
4208 /* Issue a warning only if a value is given but cannot be parsed */
4209 if(-2 == get_optlist_element_as_bool(psdoc, opthash, "embedding", &optlist_embedding)) {
4210 ps_error(psdoc, PS_Warning, _("Value of option list element 'embedding' could not be read, using default."));
4211 }
4212 ps_free_optlist(psdoc, opthash);
4213 }
4214 return(PS_findfont(psdoc, fontname, encoding, optlist_embedding));
4215 }
4216 /* }}} */
4217
4218 /* PS_string_geometry() {{{
4219 * Calculates the width of string using the given font.
4220 * If dimension is not NULL it will be filled with the width, descender and
4221 * ascender.
4222 */
4223 PSLIB_API float PSLIB_CALL
PS_string_geometry(PSDoc * psdoc,const char * text,int xlen,int fontid,float size,float * dimension)4224 PS_string_geometry(PSDoc *psdoc, const char *text, int xlen, int fontid, float size, float *dimension) {
4225 PSFont *psfont;
4226 float width = 0.0, ascender = 0.0, descender = 0.0, charspacing;
4227 int i, len;
4228 int ligonoff;
4229 int kernonoff;
4230 char ligdischar;
4231 ADOBEINFO *prevai=NULL;
4232
4233 if(NULL == psdoc) {
4234 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
4235 return(0.0);
4236 }
4237
4238 if(NULL == text)
4239 return(0.0);
4240
4241 if(0 == fontid)
4242 psfont = psdoc->font;
4243 else {
4244 if(NULL == (psfont = _ps_get_font(psdoc, fontid)))
4245 return(0.0);
4246 }
4247
4248 if(NULL == psfont) {
4249 ps_error(psdoc, PS_RuntimeError, _("No font available."));
4250 return(0.0);
4251 }
4252
4253 if(NULL == psfont->metrics) {
4254 ps_error(psdoc, PS_RuntimeError, _("No font metrics available. Cannot calculate width of string."));
4255 return(-1.0);
4256 }
4257
4258 if(0.0 == size)
4259 size = psfont->size;
4260
4261 charspacing = PS_get_value(psdoc, "charspacing", 0) * 1000.0 / size;
4262 kernonoff = ps_get_bool_parameter(psdoc, "kerning", 1);
4263 ligonoff = ps_get_bool_parameter(psdoc, "ligatures", 1);
4264 if(ligonoff) {
4265 const char *tmp = PS_get_parameter(psdoc, "ligaturedisolvechar", 0.0);
4266 if(tmp && tmp[0])
4267 ligdischar = tmp[0];
4268 else
4269 ligdischar = '�';
4270 }
4271
4272 // printf("determine width of %s\n", text);
4273 len = strlen(text);
4274 if(xlen >= 0)
4275 len = xlen < len ? xlen : len;
4276 for(i=0; i<len; i++) {
4277 ADOBEINFO *ai;
4278 unsigned char c;
4279 char *adobename;
4280
4281 c = (unsigned char) text[i];
4282 adobename = ps_inputenc_name(psdoc, c);
4283 if(adobename && adobename[0] != '\0') {
4284 // printf("search width for %s in 0x%X\n", adobename, psfont->metrics->adobechars);
4285 ai = gfindadobe(psfont->metrics->gadobechars, adobename);
4286 if(ai) {
4287 if(strcmp(adobename, "space") == 0) {
4288 width += (float) psfont->wordspace;
4289 } else {
4290 char *newadobename;
4291 int offset = 0;
4292 if(ligonoff == 1 &&
4293 charspacing == 0.0 &&
4294 ps_check_for_lig(psdoc, psfont->metrics, ai, &text[i+1], ligdischar, &newadobename, &offset)) {
4295 if(ps_fontenc_has_glyph(psdoc, psfont->metrics->fontenc, newadobename)) {
4296 ADOBEINFO *nai = gfindadobe(psfont->metrics->gadobechars, newadobename);
4297 if(nai) {
4298 ai = nai;
4299 i += offset;
4300 } else {
4301 ps_error(psdoc, PS_Warning, _("Font '%s' has no ligature '%s', disolving it."), psfont->metrics->fontname, newadobename);
4302 }
4303 } else {
4304 ps_error(psdoc, PS_Warning, _("Font encoding vector of font '%s' has no ligature '%s', disolving it."), psfont->metrics->fontname, newadobename);
4305 }
4306 }
4307 /* At this point either ai is ligature or the current char */
4308 width += (float) (ai->width);
4309 if(i < (len-1))
4310 width += charspacing;
4311 // printf("new width is %f\n", width);
4312 if(kernonoff == 1 && NULL != prevai)
4313 width += (float) calculatekern(prevai, ai);
4314 descender = min((float) ai->lly, descender);
4315 ascender = max((float) ai->ury, ascender);
4316 // printf("new width after adding kern is %f\n", width);
4317 }
4318 } else {
4319 ps_error(psdoc, PS_Warning, _("Glyph '%s' not found in metric file."), adobename);
4320 }
4321 prevai = ai;
4322 } else {
4323 ps_error(psdoc, PS_Warning, _("Character %d not in input encoding vector."), c);
4324 }
4325 }
4326 if(dimension != NULL) {
4327 dimension[0] = width*size/1000.0;
4328 dimension[1] = descender*size/1000.0;
4329 dimension[2] = ascender*size/1000.0;
4330 }
4331 return(width*size/1000.0);
4332 }
4333 /* }}} */
4334
4335 /* PS_stringwidth2() {{{
4336 * Calculates the width of string using the current font.
4337 */
4338 PSLIB_API float PSLIB_CALL
PS_stringwidth2(PSDoc * psdoc,const char * text,int xlen,int fontid,float size)4339 PS_stringwidth2(PSDoc *psdoc, const char *text, int xlen, int fontid, float size) {
4340 return(PS_string_geometry(psdoc, text, xlen, fontid, size, NULL));
4341 }
4342 /* }}} */
4343
4344 /* PS_stringwidth() {{{
4345 * Calculates the width of string using the current font.
4346 */
4347 PSLIB_API float PSLIB_CALL
PS_stringwidth(PSDoc * psdoc,const char * text,int fontid,float size)4348 PS_stringwidth(PSDoc *psdoc, const char *text, int fontid, float size) {
4349 return(PS_string_geometry(psdoc, text, -1, fontid, size, NULL));
4350 }
4351 /* }}} */
4352
4353 /* PS_deletefont() {{{
4354 * frees the memory allocated by a font
4355 */
4356 PSLIB_API void PSLIB_CALL
PS_deletefont(PSDoc * psdoc,int fontid)4357 PS_deletefont(PSDoc *psdoc, int fontid) {
4358 _ps_unregister_font(psdoc, fontid);
4359 }
4360 /* }}} */
4361
4362 /* PS_setfont() {{{
4363 * sets the font for all following text output operations
4364 */
4365 PSLIB_API void PSLIB_CALL
PS_setfont(PSDoc * psdoc,int fontid,float size)4366 PS_setfont(PSDoc *psdoc, int fontid, float size) {
4367 PSFont *psfont;
4368 if(NULL == psdoc) {
4369 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
4370 return;
4371 }
4372 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE|PS_SCOPE_PATTERN|PS_SCOPE_TEMPLATE)) {
4373 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page', 'pattern', or 'template' scope."), __FUNCTION__);
4374 return;
4375 }
4376 psfont = _ps_get_font(psdoc, fontid);
4377 if(NULL == psfont) {
4378 ps_error(psdoc, PS_RuntimeError, _("PSFont is null."));
4379 return;
4380 }
4381 psdoc->font = psfont;
4382 psdoc->font->size = size;
4383 ps_set_word_spacing(psdoc, psdoc->font, 0.0);
4384 PS_set_value(psdoc, "leading", size*1.2);
4385 if(psfont->metrics) {
4386 #ifdef WIN32
4387 if(_stricmp(psfont->metrics->codingscheme, "FontSpecific") == 0) {
4388 #else
4389 if(strcasecmp(psfont->metrics->codingscheme, "FontSpecific") == 0) {
4390 #endif
4391 ps_printf(psdoc, "/%s findfont %f scalefont setfont\n", psfont->metrics->fontname, size);
4392 } else {
4393 ps_printf(psdoc, "/%s /%s-%s fontenc-%s ReEncode\n", psfont->metrics->fontname, psfont->metrics->fontname, psfont->metrics->codingscheme, psfont->metrics->codingscheme);
4394 ps_printf(psdoc, "/%s-%s findfont %f scalefont setfont\n", psfont->metrics->fontname, psfont->metrics->codingscheme, size);
4395 }
4396 }
4397 }
4398 /* }}} */
4399
4400 /* PS_getfont() {{{
4401 * gets the font currently in use
4402 */
4403 PSLIB_API int PSLIB_CALL
4404 PS_getfont(PSDoc *psdoc) {
4405 if(NULL == psdoc) {
4406 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
4407 return(0);
4408 }
4409
4410 return(_ps_find_font(psdoc, psdoc->font));
4411 }
4412 /* }}} */
4413
4414 /* PS_open_image() {{{
4415 * Opens an image which is already in memory
4416 */
4417 PSLIB_API int PSLIB_CALL
4418 PS_open_image(PSDoc *psdoc, const char *type, const char *source, const char *data, long length, int width, int height, int components, int bpc, const char *params) {
4419 PSImage *psimage;
4420 int imageid;
4421 const char *imgreuse;
4422
4423 if(NULL == psdoc) {
4424 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
4425 return(0);
4426 }
4427
4428 imgreuse = PS_get_parameter(psdoc, "imagereuse", 0.0);
4429 if(!imgreuse || strcmp(imgreuse, "true") == 0) {
4430 /* If the header is not written, because we are before
4431 * the first page, then output the header first.
4432 */
4433 if(psdoc->beginprologwritten == ps_false) {
4434 ps_write_ps_comments(psdoc);
4435 ps_write_ps_beginprolog(psdoc);
4436 }
4437
4438 if(ps_check_scope(psdoc, PS_SCOPE_DOCUMENT|PS_SCOPE_PAGE)) {
4439 ps_error(psdoc, PS_Warning, _("Calling %s between pages or on pages for reusable images may cause problems when viewing the document. Call it before the first page."), __FUNCTION__);
4440 }
4441
4442 if(!ps_check_scope(psdoc, PS_SCOPE_DOCUMENT|PS_SCOPE_PAGE|PS_SCOPE_PROLOG)) {
4443 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'document' or 'page' scope."), __FUNCTION__);
4444 return 0;
4445 }
4446 } else {
4447 if(!ps_check_scope(psdoc, PS_SCOPE_DOCUMENT|PS_SCOPE_PAGE)) {
4448 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'document' or 'page' scope."), __FUNCTION__);
4449 return 0;
4450 }
4451 }
4452
4453 if(NULL == (psimage = (PSImage *) psdoc->malloc(psdoc, sizeof(PSImage), _("Allocate memory for image.")))) {
4454 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for image."));
4455 return(0);
4456 }
4457 memset(psimage, 0, sizeof(PSImage));
4458
4459 if(NULL == (psimage->data = (char *) psdoc->malloc(psdoc, length+1, _("Allocate memory for image data.")))) {
4460 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for image data."));
4461 psdoc->free(psdoc, psimage);
4462 return(0);
4463 }
4464
4465 memcpy(psimage->data, data, length);
4466 if(!strcmp(type, "eps")) {
4467 char *bb;
4468 psimage->data[length] = '\0';
4469 bb = strstr(psimage->data, "%%BoundingBox:");
4470 if(bb) {
4471 float x, y, width, height;
4472 bb += 15;
4473 sscanf(bb, "%f %f %f %f", &x, &y, &width, &height);
4474 psimage->width = (int) width;
4475 psimage->height = (int) height;
4476 psimage->length = length;
4477 }
4478 } else {
4479 psimage->length = length;
4480 psimage->width = width;
4481 psimage->height = height;
4482 psimage->components = components;
4483 psimage->bpc = bpc;
4484 switch(psimage->components) {
4485 case 1:
4486 psimage->colorspace = PS_COLORSPACE_GRAY;
4487 break;
4488 case 3:
4489 psimage->colorspace = PS_COLORSPACE_RGB;
4490 break;
4491 case 4:
4492 psimage->colorspace = PS_COLORSPACE_CMYK;
4493 break;
4494 default:
4495 ps_error(psdoc, PS_RuntimeError, _("Image has unknown number of components per pixel."));
4496 psdoc->free(psdoc, psimage->data);
4497 psdoc->free(psdoc, psimage);
4498 return(0);
4499 }
4500 }
4501
4502 psimage->type = ps_strdup(psdoc, type);
4503 if(!imgreuse || strcmp(imgreuse, "true") == 0) {
4504 char buffer[25];
4505 psimage->isreusable = 1;
4506 sprintf(buffer, "Imagedata%d", rand());
4507 psimage->name = ps_strdup(psdoc, buffer);
4508 }
4509
4510 if(0 == (imageid = _ps_register_image(psdoc, psimage))) {
4511 ps_error(psdoc, PS_MemoryError, _("Could not register image."));
4512 psdoc->free(psdoc, psimage->type);
4513 psdoc->free(psdoc, psimage->data);
4514 psdoc->free(psdoc, psimage);
4515 return(0);
4516 }
4517
4518 if(psimage->isreusable) {
4519 if(!strcmp(type, "eps")) {
4520 ps_printf(psdoc, "/%s\n", psimage->name);
4521 ps_printf(psdoc, "currentfile\n");
4522 ps_printf(psdoc, "<< /Filter /SubFileDecode\n");
4523 ps_printf(psdoc, " /DecodeParms << /EODCount 0 /EODString (*EOD*) >>\n");
4524 ps_printf(psdoc, ">> /ReusableStreamDecode filter\n");
4525 ps_write(psdoc, psimage->data, psimage->length);
4526 ps_printf(psdoc, "*EOD*\n");
4527 ps_printf(psdoc, "def\n");
4528 } else {
4529 char *tmpdata;
4530 const char *imgenc;
4531 int reallength, j;
4532
4533 imgenc = PS_get_parameter(psdoc, "imageencoding", 0.0);
4534 ps_printf(psdoc, "/%s\n", psimage->name);
4535 ps_printf(psdoc, "currentfile\n");
4536 ps_printf(psdoc, "<< /Filter /ASCII%sDecode >>\n", (imgenc == NULL || strcmp(imgenc, "hex") != 0) ? "85" : "Hex");
4537 ps_printf(psdoc, "/ReusableStreamDecode filter\n");
4538
4539 if(psimage->components == 4 && psimage->colorspace == PS_COLORSPACE_RGB) {
4540 char *dataptr, *tmpdataptr;
4541 int j;
4542 dataptr = psimage->data;
4543 reallength = psimage->height*psimage->width*3;
4544 tmpdata = tmpdataptr = psdoc->malloc(psdoc, psimage->height*psimage->width*3, _("Allocate memory for temporary image data."));
4545 for(j=0; j<psimage->length; j++) {
4546 *tmpdataptr++ = *dataptr++;
4547 *tmpdataptr++ = *dataptr++;
4548 *tmpdataptr++ = *dataptr++;
4549 dataptr++;
4550 }
4551 } else {
4552 tmpdata = psimage->data;
4553 reallength = psimage->length;
4554 }
4555 if(imgenc == NULL || strcmp(imgenc, "hex") != 0)
4556 ps_ascii85_encode(psdoc, tmpdata, reallength);
4557 else
4558 ps_asciihex_encode(psdoc, tmpdata, reallength);
4559 if(psimage->components == 4 && psimage->colorspace == PS_COLORSPACE_RGB)
4560 psdoc->free(psdoc, tmpdata);
4561
4562 ps_printf(psdoc, "\ndef\n");
4563 }
4564 }
4565
4566 return(imageid);
4567 }
4568 /* }}} */
4569
4570 /* PS_open_image_file() {{{
4571 * Opens an image from a file
4572 */
4573 PSLIB_API int PSLIB_CALL
4574 PS_open_image_file(PSDoc *psdoc, const char *type, const char *filename, const char *stringparam, int intparam) {
4575 PSImage *psimage;
4576 int imageid;
4577 const char *imgreuse;
4578 FILE *fp;
4579
4580 if(NULL == psdoc) {
4581 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
4582 return 0;
4583 }
4584
4585 imgreuse = PS_get_parameter(psdoc, "imagereuse", 0.0);
4586 if(!imgreuse || strcmp(imgreuse, "true") == 0) {
4587 /* If the header is not written, because we are before
4588 * the first page, then output the header first.
4589 */
4590 if(psdoc->beginprologwritten == ps_false) {
4591 ps_write_ps_comments(psdoc);
4592 ps_write_ps_beginprolog(psdoc);
4593 }
4594
4595 if(ps_check_scope(psdoc, PS_SCOPE_DOCUMENT|PS_SCOPE_PAGE)) {
4596 ps_error(psdoc, PS_Warning, _("Calling %s between pages or on pages for reusable images may cause problems when viewing the document. Call it before the first page."), __FUNCTION__);
4597 }
4598
4599 if(!ps_check_scope(psdoc, PS_SCOPE_DOCUMENT|PS_SCOPE_PAGE|PS_SCOPE_PROLOG)) {
4600 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'document' or 'page' scope."), __FUNCTION__);
4601 return 0;
4602 }
4603 } else {
4604 if(!ps_check_scope(psdoc, PS_SCOPE_DOCUMENT|PS_SCOPE_PAGE)) {
4605 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'document' or 'page' scope."), __FUNCTION__);
4606 return 0;
4607 }
4608 }
4609
4610 if(NULL == filename) {
4611 ps_error(psdoc, PS_RuntimeError, _("Filename of images is NULL."));
4612 return 0;
4613 }
4614
4615 if ((fp = fopen(filename, "rb")) == NULL) {
4616 ps_error(psdoc, PS_RuntimeError, _("Could not open image file %s."), filename);
4617 return 0;
4618 }
4619
4620 if(NULL == type) {
4621 ps_error(psdoc, PS_RuntimeError, _("Type of image is NULL."));
4622 return 0;
4623 }
4624
4625 #ifdef HAVE_LIBPNG
4626 if(0 == strncmp("png", type, 3)) {
4627 #define SIG_READ 8
4628 char *dataptr, sig[SIG_READ];
4629 int i;
4630 int color_type, bit_depth;
4631 png_structp png_ptr;
4632 png_infop info_ptr;
4633 png_uint_32 row_bytes;
4634 png_bytep *row_pointers;
4635 // png_bytep row_pointer;
4636
4637 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
4638 // png_voidp user_error_ptr, user_error_fn, user_warning_fn);
4639
4640 if (png_ptr == NULL) {
4641 ps_error(psdoc, PS_RuntimeError, _("Could not create png structure."));
4642 fclose(fp);
4643 return(0);
4644 }
4645
4646 /* Allocate/initialize the memory for image information. REQUIRED. */
4647 info_ptr = png_create_info_struct(png_ptr);
4648 if (info_ptr == NULL) {
4649 ps_error(psdoc, PS_RuntimeError, _("Could not create png info structure."));
4650 fclose(fp);
4651 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
4652 return(0);
4653 }
4654
4655 /* Set error handling if you are using the setjmp/longjmp method (this is
4656 * the normal method of doing things with libpng). REQUIRED unless you
4657 * set up your own error handlers in the png_create_read_struct() earlier.
4658 */
4659 if (setjmp(png_jmpbuf(png_ptr))) {
4660 /* Free all of the memory associated with the png_ptr and info_ptr */
4661 ps_error(psdoc, PS_RuntimeError, _("Could not set error handler for libpng."));
4662 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
4663 fclose(fp);
4664 /* If we get here, we had a problem reading the file */
4665 return (0);
4666 }
4667
4668 if (fread(sig, 1, SIG_READ, fp) == 0 || !png_check_sig(sig, SIG_READ)) {
4669 fclose(fp);
4670 ps_error(psdoc, PS_RuntimeError, "File '%s' is not a PNG file", filename);
4671 return (0);
4672 }
4673
4674 /* Set up the input control if you are using standard C streams */
4675 png_init_io(png_ptr, fp);
4676
4677 /* If we have already read some of the signature */
4678 png_set_sig_bytes(png_ptr, SIG_READ);
4679
4680 /*
4681 * If you have enough memory to read in the entire image at once,
4682 * and you need to specify only transforms that can be controlled
4683 * with one of the PNG_TRANSFORM_* bits (this presently excludes
4684 * dithering, filling, setting background, and doing gamma
4685 * adjustment), then you can read the entire image (including
4686 * pixels) into the info structure with this call:
4687 */
4688 #define mymemory
4689 #ifdef mymemory
4690 png_read_info(png_ptr, info_ptr);
4691 color_type = png_get_color_type(png_ptr, info_ptr);
4692 bit_depth = png_get_bit_depth(png_ptr, info_ptr);
4693 if (bit_depth == 16) {
4694 png_set_strip_16(png_ptr);
4695 }
4696
4697 /* FIXME: Quick fix to circumvent a segm fault in ps_place_image()
4698 * when rgb images with alpha channel are loaded.
4699 */
4700 if (color_type & PNG_COLOR_MASK_ALPHA)
4701 png_set_strip_alpha(png_ptr);
4702
4703 /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
4704 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
4705 #if defined(PNG_1_0_X) || defined (PNG_1_2_X)
4706 png_set_gray_1_2_4_to_8(png_ptr);
4707 #else
4708 png_set_expand_gray_1_2_4_to_8(png_ptr);
4709 #endif
4710
4711 png_read_update_info(png_ptr, info_ptr);
4712 #else
4713 /* Read the entire image */
4714 png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, png_voidp_NULL);
4715 #endif
4716
4717 if(NULL == (psimage = (PSImage *) psdoc->malloc(psdoc, sizeof(PSImage), _("Allocate memory for image.")))) {
4718 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for image."));
4719 fclose(fp);
4720 return(0);
4721 }
4722 memset(psimage, 0, sizeof(PSImage));
4723
4724 if(stringparam != NULL && strcmp(stringparam, "mask") == 0) {
4725 psimage->ismask = ps_true;
4726 }
4727
4728 if(stringparam != NULL && strcmp(stringparam, "masked") == 0) {
4729 PSImage *psmaskimage = _ps_get_image(psdoc, intparam);
4730 if(!psmaskimage) {
4731 ps_error(psdoc, PS_RuntimeError, _("Could not find image mask."));
4732 psdoc->free(psdoc, psimage);
4733
4734 return(0);
4735 }
4736 psimage->imagemask = psmaskimage;
4737 }
4738 psimage->psdoc = psdoc;
4739 psimage->type = ps_strdup(psdoc, type);
4740 psimage->width = png_get_image_width(png_ptr, info_ptr);
4741 psimage->height = png_get_image_height(png_ptr, info_ptr);
4742 psimage->components = png_get_channels(png_ptr, info_ptr);
4743 psimage->bpc = png_get_bit_depth(png_ptr, info_ptr);
4744 switch(png_get_color_type(png_ptr, info_ptr)) {
4745 case PNG_COLOR_TYPE_GRAY:
4746 case PNG_COLOR_TYPE_GRAY_ALPHA:
4747 psimage->colorspace = PS_COLORSPACE_GRAY;
4748 break;
4749 case PNG_COLOR_TYPE_RGB:
4750 case PNG_COLOR_TYPE_RGB_ALPHA:
4751 psimage->colorspace = PS_COLORSPACE_RGB;
4752 break;
4753 case PNG_COLOR_TYPE_PALETTE:
4754 psimage->colorspace = PS_COLORSPACE_INDEXED;
4755 break;
4756 }
4757 if(psimage->colorspace == PS_COLORSPACE_INDEXED) {
4758 int num_palette;
4759 png_colorp palette;
4760 png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
4761 if(NULL == (psimage->palette = psdoc->malloc(psdoc, sizeof(PSColor) * num_palette, _("Allocate memory for color palette.")))) {
4762 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for color palette."));
4763 psdoc->free(psdoc, psimage);
4764 fclose(fp);
4765 return(0);
4766 }
4767 for(i=0; i<num_palette; i++) {
4768 psimage->palette[i].colorspace = PS_COLORSPACE_RGB;
4769 psimage->palette[i].c1 = palette[i].red/255.0;
4770 psimage->palette[i].c2 = palette[i].green/255.0;
4771 psimage->palette[i].c3 = palette[i].blue/255.0;
4772 psimage->palette[i].c4 = 0.0;
4773 }
4774 psimage->numcolors = num_palette;
4775 }
4776
4777 row_bytes = png_get_rowbytes(png_ptr, info_ptr);
4778 psimage->length = row_bytes * psimage->height;
4779 /*
4780 fprintf(stderr, "%dx%d pixel\n", psimage->width, psimage->height);
4781 fprintf(stderr, "%d channels\n", psimage->components);
4782 fprintf(stderr, "%d bits per color\n", psimage->bpc);
4783 fprintf(stderr, "%d bytes per row\n", row_bytes);
4784 */
4785
4786 if(NULL == (psimage->data = psdoc->malloc(psdoc, psimage->height*row_bytes, _("Allocate memory for image data.")))) {
4787 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for image data."));
4788 psdoc->free(psdoc, psimage);
4789 fclose(fp);
4790 return(0);
4791 }
4792
4793 #ifdef mymemory
4794 if(NULL == (row_pointers = psdoc->malloc(psdoc, psimage->height*sizeof(png_bytep), _("Allocate memory for row pointers of png image.")))) {
4795 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for row pointer of png image."));
4796 psdoc->free(psdoc, psimage->data);
4797 psdoc->free(psdoc, psimage);
4798 fclose(fp);
4799 return(0);
4800 }
4801
4802 dataptr = psimage->data;
4803 for(i=0; i<psimage->height; i++) {
4804 row_pointers[i] = dataptr;
4805 // fprintf(stderr, "Reading row %d\n", i);
4806 // png_read_row(png_ptr, dataptr, NULL);
4807 dataptr += row_bytes;
4808 }
4809 png_read_image(png_ptr, row_pointers);
4810 png_read_end(png_ptr, NULL);
4811 psdoc->free(psdoc, row_pointers);
4812 #else
4813 row_pointers = png_get_rows(png_ptr, info_ptr);
4814 if(row_pointers == NULL) {
4815 ps_error(psdoc, PS_MemoryError, _("Could get array of image rows."));
4816 psdoc->free(psdoc, psimage->data);
4817 return(0);
4818 }
4819 dataptr = psimage->data;
4820 for(i=0; i<psimage->height; i++) {
4821 fprintf(stderr, "Copying %d row 0x%X -> 0x%X\n", i, row_pointers[i], dataptr);
4822 memcpy(dataptr, row_pointers[i], row_bytes);
4823 dataptr += row_bytes;
4824 }
4825 #endif
4826 /* clean up after the read, and free any memory allocated - REQUIRED */
4827 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
4828
4829 } else
4830 #endif /* HAVE_LIBPNG */
4831 #ifdef HAVE_LIBJPEG
4832 if(0 == strncmp("jpeg", type, 4)) {
4833 char *dataptr;
4834 struct jpeg_decompress_struct cinfo;
4835 JSAMPARRAY buffer;
4836 int row_stride;
4837 struct jpeg_error_mgr jerr;
4838
4839 cinfo.err = jpeg_std_error(&jerr);
4840 jpeg_create_decompress(&cinfo);
4841 jpeg_stdio_src(&cinfo, fp);
4842 jpeg_read_header(&cinfo, TRUE);
4843 jpeg_start_decompress(&cinfo);
4844 row_stride = cinfo.output_width * cinfo.output_components;
4845
4846 if(NULL == (psimage = (PSImage *) psdoc->malloc(psdoc, sizeof(PSImage), _("Allocate memory for image.")))) {
4847 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for image."));
4848 fclose(fp);
4849 return(0);
4850 }
4851 memset(psimage, 0, sizeof(PSImage));
4852
4853 psimage->psdoc = psdoc;
4854 psimage->type = ps_strdup(psdoc, type);
4855 psimage->width = cinfo.output_width;
4856 psimage->height = cinfo.output_height;
4857 psimage->components = cinfo.output_components;
4858 psimage->bpc = 8;
4859 switch(cinfo.out_color_space) {
4860 case JCS_GRAYSCALE:
4861 psimage->colorspace = PS_COLORSPACE_GRAY;
4862 break;
4863 case JCS_RGB:
4864 psimage->colorspace = PS_COLORSPACE_RGB;
4865 break;
4866 case JCS_CMYK:
4867 psimage->colorspace = PS_COLORSPACE_CMYK;
4868 break;
4869 }
4870
4871 // if(psimage->components == 1)
4872 // psimage->colorspace = PS_COLORSPACE_GRAY;
4873 // else
4874 // psimage->colorspace = PS_COLORSPACE_RGB;
4875 psimage->length = psimage->width * psimage->height * psimage->components;
4876 if(NULL == (psimage->data = psdoc->malloc(psdoc, psimage->length, _("Allocate memory for image data.")))) {
4877 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for image data."));
4878 fclose(fp);
4879 return(0);
4880 }
4881
4882 buffer = (*cinfo.mem->alloc_sarray)
4883 ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
4884 dataptr = psimage->data;
4885 while (cinfo.output_scanline < cinfo.output_height) {
4886 jpeg_read_scanlines(&cinfo, buffer, 1);
4887 memcpy(dataptr, buffer[0], row_stride);
4888 dataptr += row_stride;
4889 }
4890 jpeg_finish_decompress(&cinfo);
4891 jpeg_destroy_decompress(&cinfo);
4892 } else
4893 #endif /* HAVE_LIBJPEG */
4894 #ifdef HAVE_LIBGIF
4895 if(0 == strncmp("gif", type, 3)) {
4896 GifFileType* gft;
4897 int i, numcolors = 0, alphapalette = -1;
4898 ColorMapObject* colormap;
4899 GifColorType c;
4900 unsigned char *dataptr;
4901 #if GIFLIB_MAJOR > 5 || GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1
4902 int error;
4903 #define GIF_OPEN_FILENAME(filename) DGifOpenFileName(filename, &error)
4904 #define GIF_CLOSE_FILE(gif) DGifCloseFile(gif, &error)
4905 #else
4906 #define GIF_OPEN_FILENAME(filename) DGifOpenFileName(filename)
4907 #define GIF_CLOSE_FILE(gif) DGifCloseFile(gif)
4908 #endif
4909
4910 if(NULL == (psimage = (PSImage *) psdoc->malloc(psdoc, sizeof(PSImage), _("Allocate memory for image.")))) {
4911 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for image."));
4912 fclose(fp);
4913 return(0);
4914 }
4915 memset(psimage, 0, sizeof(PSImage));
4916
4917 if ((gft = GIF_OPEN_FILENAME(filename)) == NULL) {
4918 ps_error(psdoc, PS_RuntimeError, _("%s is not a gif file!"), filename);
4919 fclose(fp);
4920 return(0);
4921 }
4922 if (DGifSlurp(gft) != GIF_OK) {
4923 #if GIFLIB_MAJOR > 5 || GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1
4924 ps_error(psdoc, PS_RuntimeError, _("Error %d while reading gif file!"), error);
4925 #else
4926 ps_error(psdoc, PS_RuntimeError, _("Error %d while reading gif file!"), GifLastError());
4927 #endif
4928 fclose(fp);
4929 return(0);
4930 }
4931
4932 psimage->psdoc = psdoc;
4933 psimage->type = ps_strdup(psdoc, type);
4934 psimage->width = gft->SWidth;
4935 psimage->height = gft->SHeight;
4936 psimage->components = 1;
4937 psimage->bpc = 8;
4938 psimage->colorspace = PS_COLORSPACE_INDEXED;
4939
4940 // look for the transparent color extension
4941 for (i = 0; i < gft->SavedImages[0].ExtensionBlockCount; ++i) {
4942 ExtensionBlock* eb = gft->SavedImages[0].ExtensionBlocks + i;
4943 if (eb->Function == GRAPHICS_EXT_FUNC_CODE && eb->ByteCount == 4) {
4944 int has_transparency = ((eb->Bytes[0] & 1) == 1);
4945 if (has_transparency)
4946 alphapalette = eb->Bytes[3];
4947 }
4948 }
4949 colormap = gft->Image.ColorMap ? gft->Image.ColorMap : gft->SColorMap;
4950 numcolors = colormap->ColorCount;
4951
4952 if(NULL == (psimage->palette = psdoc->malloc(psdoc, sizeof(PSColor) * numcolors, _("Allocate memory for color palette.")))) {
4953 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for color palette."));
4954 GIF_CLOSE_FILE(gft);
4955 psdoc->free(psdoc, psimage);
4956 fclose(fp);
4957 return(0);
4958 }
4959
4960 for (i=0; i<numcolors; i++) {
4961 psimage->palette[i].colorspace = PS_COLORSPACE_RGB;
4962 c = colormap->Colors[i];
4963 if (i == alphapalette)
4964 psimage->palette[i].c1 = psimage->palette[i].c2 = psimage->palette[i].c3 = psimage->palette[i].c4 = 1;// Fully transparent
4965 else {
4966 psimage->palette[i].c1 = c.Red/255.0;
4967 psimage->palette[i].c2 = c.Green/255.0;
4968 psimage->palette[i].c3 = c.Blue/255.0;
4969 psimage->palette[i].c4 = 0;
4970 }
4971 }
4972 psimage->numcolors = numcolors;
4973
4974 dataptr = (unsigned char *) gft->SavedImages[0].RasterBits;
4975
4976 psimage->length = psimage->width * psimage->height;
4977 if(NULL == (psimage->data = psdoc->malloc(psdoc, psimage->length, _("Allocate memory for image data.")))) {
4978 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for image data."));
4979 GIF_CLOSE_FILE(gft);
4980 psdoc->free(psdoc, psimage->palette);
4981 psdoc->free(psdoc, psimage);
4982 fclose(fp);
4983 return(0);
4984 }
4985
4986 if(gft->Image.Interlace) {
4987 unsigned char *out;
4988 unsigned int row;
4989 for (row = 0; row < psimage->height; row += 8) {
4990 out = psimage->data + row*psimage->width;
4991 memcpy(out, dataptr, psimage->width);
4992 dataptr += psimage->width;
4993 }
4994 for (row = 4; row < psimage->height; row += 8) {
4995 out = psimage->data + row*psimage->width;
4996 memcpy(out, dataptr, psimage->width);
4997 dataptr += psimage->width;
4998 }
4999 for (row = 2; row < psimage->height; row += 4) {
5000 out = psimage->data + row*psimage->width;
5001 memcpy(out, dataptr, psimage->width);
5002 dataptr += psimage->width;
5003 }
5004 for (row = 1; row < psimage->height; row += 2) {
5005 out = psimage->data + row*psimage->width;
5006 memcpy(out, dataptr, psimage->width);
5007 dataptr += psimage->width;
5008 }
5009 } else {
5010 memcpy(psimage->data, dataptr, psimage->length);
5011 }
5012
5013 GIF_CLOSE_FILE(gft);
5014
5015 } else
5016 #endif /* HAVE_LIBGIF */
5017 #ifdef HAVE_LIBTIFF
5018 if(0 == strncmp("tiff", type, 4)) {
5019 TIFF* tif;
5020 uint32* raster;
5021
5022 if(NULL == (psimage = (PSImage *) psdoc->malloc(psdoc, sizeof(PSImage), _("Allocate memory for image.")))) {
5023 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for image."));
5024 fclose(fp);
5025 return(0);
5026 }
5027 memset(psimage, 0, sizeof(PSImage));
5028
5029 psimage->psdoc = psdoc;
5030 psimage->type = ps_strdup(psdoc, type);
5031 psimage->components = 3;
5032 psimage->bpc = 8;
5033 psimage->colorspace = PS_COLORSPACE_RGB;
5034
5035 if(NULL == (tif = TIFFOpen(filename, "r"))) {
5036 psdoc->free(psdoc, psimage);
5037 fclose(fp);
5038 return(0);
5039 }
5040
5041 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &(psimage->width));
5042 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &(psimage->height));
5043 psimage->length = psimage->width * psimage->height * 3;
5044
5045 raster = (uint32*) _TIFFmalloc(psimage->width * psimage->height * sizeof (uint32));
5046 if (raster != NULL) {
5047 if (TIFFReadRGBAImageOriented(tif, psimage->width, psimage->height, raster, ORIENTATION_TOPLEFT, 0)) {
5048 unsigned char *src, *dst;
5049 int pixel_count = psimage->width * psimage->height;
5050
5051 if(NULL == (psimage->data = psdoc->malloc(psdoc, psimage->length, _("Allocate memory for image data.")))) {
5052 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for image data."));
5053 psdoc->free(psdoc, psimage);
5054 _TIFFfree(raster);
5055 TIFFClose(tif);
5056 fclose(fp);
5057 return(0);
5058 }
5059
5060 dst = psimage->data;
5061 src = (unsigned char *) raster;
5062 while( pixel_count > 0 ) {
5063 /* The raster is in ABGR order */
5064 dst[0] = src[3];
5065 dst[1] = src[2];
5066 dst[2] = src[1];
5067 src += 4;
5068 dst += 3;
5069 pixel_count--;
5070 }
5071 }
5072 _TIFFfree(raster);
5073 }
5074 TIFFClose(tif);
5075 } else
5076 #endif /* HAVE_LIBTIFF */
5077 #ifndef DISABLE_BMP
5078 if(0 == strncmp("bmp", type, 3)) {
5079 int w, h, bps, spp, xres, yres, i;
5080 unsigned char *color_table, *ct;
5081 int color_table_size, color_table_elements;
5082 unsigned char *data;
5083
5084 if(NULL == (psimage = (PSImage *) psdoc->malloc(psdoc, sizeof(PSImage), _("Allocate memory for image.")))) {
5085 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for image."));
5086 fclose(fp);
5087 return(0);
5088 }
5089 memset(psimage, 0, sizeof(PSImage));
5090
5091 psimage->psdoc = psdoc;
5092 psimage->type = ps_strdup(psdoc, type);
5093
5094 if(NULL == (data = read_bmp(psdoc, filename, &w, &h, &bps, &spp, &xres, &yres,
5095 &color_table, &color_table_size, &color_table_elements))) {
5096 ps_error(psdoc, PS_MemoryError, _("Could not read bmp file."));
5097 psdoc->free(psdoc, psimage);
5098 fclose(fp);
5099 return(0);
5100 }
5101 psimage->width = w;
5102 psimage->height = h;
5103 if(NULL != color_table) {
5104 psimage->components = 1;
5105 psimage->bpc = bps;
5106 psimage->colorspace = PS_COLORSPACE_INDEXED;
5107 psimage->length = w * h;
5108
5109 if(NULL == (psimage->palette = psdoc->malloc(psdoc, sizeof(PSColor) * color_table_size, _("Allocate memory for color palette.")))) {
5110 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for color palette."));
5111 psdoc->free(psdoc, psimage);
5112 fclose(fp);
5113 return(0);
5114 }
5115
5116 ct = color_table;
5117 for (i=0; i<color_table_size; i++) {
5118 psimage->palette[i].colorspace = PS_COLORSPACE_RGB;
5119 psimage->palette[i].c3 = *ct++/255.0;
5120 psimage->palette[i].c2 = *ct++/255.0;
5121 psimage->palette[i].c1 = *ct++/255.0;
5122 psimage->palette[i].c4 = *ct++/255.0;
5123 }
5124 psimage->numcolors = color_table_size;
5125 psdoc->free(psdoc, color_table);
5126 } else {
5127 psimage->components = spp;
5128 psimage->bpc = bps;
5129 psimage->colorspace = PS_COLORSPACE_RGB;
5130 psimage->length = w * h * 3;
5131 }
5132 /* data has been allocated in read_bmp() */
5133 psimage->data = data;
5134 } else
5135 #endif
5136 if(0 == strncmp("eps", type, 3)) {
5137 char *bb;
5138 struct stat statbuf;
5139 if(0 > stat(filename, &statbuf)) {
5140 ps_error(psdoc, PS_RuntimeError, _("Could not stat eps file."));
5141 fclose(fp);
5142 return(0);
5143 }
5144 if(NULL == (psimage = (PSImage *) psdoc->malloc(psdoc, sizeof(PSImage), _("Allocate memory for image.")))) {
5145 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for image."));
5146 fclose(fp);
5147 return(0);
5148 }
5149 memset(psimage, 0, sizeof(PSImage));
5150 psimage->type = ps_strdup(psdoc, type);
5151
5152 if(NULL == (psimage->data = psdoc->malloc(psdoc, statbuf.st_size+1, _("Allocate memory for image data.")))) {
5153 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for image data."));
5154 psdoc->free(psdoc, psimage);
5155 fclose(fp);
5156 return(0);
5157 }
5158 psimage->psdoc = psdoc;
5159 psimage->length = statbuf.st_size;
5160
5161 fread(psimage->data, statbuf.st_size, 1, fp);
5162 psimage->data[statbuf.st_size] = '\0';
5163 bb = strstr(psimage->data, "%%BoundingBox:");
5164 if(bb) {
5165 float x, y, width, height;
5166 bb += 15;
5167 sscanf(bb, "%f %f %f %f", &x, &y, &width, &height);
5168 psimage->width = (int) width;
5169 psimage->height = (int) height;
5170 }
5171 } else {
5172 ps_error(psdoc, PS_RuntimeError, _("Images of type '%s' not supported."), type);
5173 fclose(fp);
5174 return(0);
5175 }
5176 /* close the file */
5177 fclose(fp);
5178
5179 /* that's it */
5180
5181 if(!imgreuse || strcmp(imgreuse, "true") == 0) {
5182 char buffer[25];
5183 psimage->isreusable = 1;
5184 sprintf(buffer, "Imagedata%d", rand());
5185 psimage->name = ps_strdup(psdoc, buffer);
5186 }
5187
5188 if(0 == (imageid = _ps_register_image(psdoc, psimage))) {
5189 ps_error(psdoc, PS_MemoryError, _("Could not register image."));
5190 psdoc->free(psdoc, psimage->type);
5191 psdoc->free(psdoc, psimage->data);
5192 psdoc->free(psdoc, psimage);
5193 return(0);
5194 }
5195
5196 if(psimage->isreusable) {
5197 if(!strcmp(type, "eps")) {
5198 ps_printf(psdoc, "/%s\n", psimage->name);
5199 ps_printf(psdoc, "currentfile\n");
5200 ps_printf(psdoc, "<< /Filter /SubFileDecode\n");
5201 ps_printf(psdoc, " /DecodeParms << /EODCount 0 /EODString (*EOD*) >>\n");
5202 ps_printf(psdoc, ">> /ReusableStreamDecode filter\n");
5203 ps_write(psdoc, psimage->data, psimage->length);
5204 ps_printf(psdoc, "*EOD*\n");
5205 ps_printf(psdoc, "def\n");
5206 } else {
5207 char *tmpdata;
5208 const char *imgenc;
5209 int reallength, j;
5210
5211 imgenc = PS_get_parameter(psdoc, "imageencoding", 0.0);
5212 ps_printf(psdoc, "/%s\n", psimage->name);
5213 ps_printf(psdoc, "currentfile\n");
5214 ps_printf(psdoc, "<< /Filter /ASCII%sDecode >>\n", (imgenc == NULL || strcmp(imgenc, "hex") != 0) ? "85" : "Hex");
5215 ps_printf(psdoc, "/ReusableStreamDecode filter\n");
5216
5217 if(psimage->components == 4 && psimage->colorspace == PS_COLORSPACE_RGB) {
5218 char *dataptr, *tmpdataptr;
5219 int j;
5220 dataptr = psimage->data;
5221 reallength = psimage->height*psimage->width*3;
5222 tmpdata = tmpdataptr = psdoc->malloc(psdoc, psimage->height*psimage->width*3, _("Allocate memory for temporary image data."));
5223 for(j=0; j<psimage->length; j++) {
5224 *tmpdataptr++ = *dataptr++;
5225 *tmpdataptr++ = *dataptr++;
5226 *tmpdataptr++ = *dataptr++;
5227 dataptr++;
5228 }
5229 } else {
5230 tmpdata = psimage->data;
5231 reallength = psimage->length;
5232 }
5233 if(imgenc == NULL || strcmp(imgenc, "hex") != 0)
5234 ps_ascii85_encode(psdoc, tmpdata, reallength);
5235 else
5236 ps_asciihex_encode(psdoc, tmpdata, reallength);
5237 if(psimage->components == 4 && psimage->colorspace == PS_COLORSPACE_RGB)
5238 psdoc->free(psdoc, tmpdata);
5239
5240 ps_printf(psdoc, "\ndef\n");
5241 }
5242 }
5243 return(imageid);
5244 }
5245 /* }}} */
5246
5247 /* PS_place_image() {{{
5248 * Place an image on the page
5249 */
5250 PSLIB_API void PSLIB_CALL
5251 PS_place_image(PSDoc *psdoc, int imageid, float x, float y, float scale) {
5252 PSImage *image;
5253 const char *imgreuse;
5254
5255 if(NULL == psdoc) {
5256 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
5257 return;
5258 }
5259 imgreuse = PS_get_parameter(psdoc, "imagereuse", 0.0);
5260 if(!imgreuse || strcmp(imgreuse, "true") == 0) {
5261 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE|PS_SCOPE_TEMPLATE)) {
5262 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page' or 'template' scope."), __FUNCTION__);
5263 return;
5264 }
5265 } else {
5266 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE)) {
5267 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page' scope."), __FUNCTION__);
5268 return;
5269 }
5270 }
5271
5272 if(scale == 0.0) {
5273 ps_error(psdoc, PS_Warning, _("Scaling image to 0.0 will make it disappear."), __FUNCTION__);
5274 }
5275
5276 image = _ps_get_image(psdoc, imageid);
5277 if(NULL == image) {
5278 ps_error(psdoc, PS_RuntimeError, _("PSImage is null."));
5279 return;
5280 }
5281 if(NULL == image->type) {
5282 ps_error(psdoc, PS_RuntimeError, _("Image has no type set."));
5283 return;
5284 }
5285
5286 /* All images must have data, except for templates */
5287 if(NULL == image->data && strcmp(image->type, "template")) {
5288 ps_error(psdoc, PS_RuntimeError, _("Image has no data."));
5289 return;
5290 }
5291
5292 if(
5293 #ifdef HAVE_LIBPNG
5294 0 == strncmp(image->type, "png", 3) ||
5295 #endif
5296 #ifdef HAVE_LIBJPEG
5297 0 == strncmp(image->type, "jpeg", 4) ||
5298 #endif
5299 #ifdef HAVE_LIBGIF
5300 0 == strncmp(image->type, "gif", 3) ||
5301 #endif
5302 #ifdef HAVE_LIBTIFF
5303 0 == strncmp(image->type, "tiff", 4) ||
5304 #endif
5305 #ifndef DISABLE_BMP
5306 0 == strncmp(image->type, "bmp", 3) ||
5307 #endif
5308 0 == strncmp(image->type, "memory", 6) ) {
5309 unsigned char *dataptr, *tmpdata, *tmpdataptr;
5310 const char *imgenc;
5311 int i, j, k, reallength;
5312 ps_printf(psdoc, "gsave\n");
5313 #ifdef LEVEL1
5314 ps_printf(psdoc, "%.2f %.2f scale\n", scale*image->width, scale*image->height);
5315 ps_printf(psdoc, "/readstring { currentfile exch readhexstring pop } bind def\n");
5316 ps_printf(psdoc, "/rpicstr %d string def\n", image->width);
5317 ps_printf(psdoc, "/gpicstr %d string def\n", image->width);
5318 ps_printf(psdoc, "/bpicstr %d string def\n", image->width);
5319 ps_printf(psdoc, "%d %d %d\n", image->width, image->height, image->bpc);
5320 ps_printf(psdoc, "[%d 0 0 %d %f %f]\n", image->width, -image->height, -x/scale, image->height+y/scale);
5321 ps_printf(psdoc, "{ rpicstr readstring }\n");
5322 ps_printf(psdoc, "{ gpicstr readstring }\n");
5323 ps_printf(psdoc, "{ bpicstr readstring }\n");
5324 ps_printf(psdoc, "true %d\n", image->components);
5325 ps_printf(psdoc, "colorimage\n");
5326 rowptr = image->data;
5327 dataptr = image->data;
5328 for(j=0; j<image->height; j++) {
5329 for(k=0; k<image->components; k++) {
5330 dataptr = rowptr+k;
5331 for(i=0; i<image->width; i++) {
5332 ps_printf(psdoc, "%02x", *dataptr);
5333 dataptr += 3;
5334 }
5335 ps_printf(psdoc, "\n");
5336 }
5337 rowptr += image->components*image->width;
5338 }
5339 #else
5340 ps_printf(psdoc, "%.2f %.2f translate\n", x, y);
5341 ps_printf(psdoc, "%.2f %.2f scale\n", scale*image->width, scale*image->height);
5342
5343 imgenc = PS_get_parameter(psdoc, "imageencoding", 0.0);
5344
5345 if(image->isreusable)
5346 ps_printf(psdoc, "%s 0 setfileposition\n", image->name);
5347
5348 if(!image->ismask) {
5349 /* Output the image data */
5350 switch(image->colorspace) {
5351 case PS_COLORSPACE_GRAY:
5352 ps_printf(psdoc, "/DeviceGray setcolorspace\n");
5353 break;
5354 case PS_COLORSPACE_RGB:
5355 ps_printf(psdoc, "/DeviceRGB setcolorspace\n");
5356 break;
5357 case PS_COLORSPACE_CMYK:
5358 ps_printf(psdoc, "/DeviceCMYK setcolorspace\n");
5359 break;
5360 case PS_COLORSPACE_INDEXED: {
5361 int i;
5362 ps_printf(psdoc, "[ /Indexed /DeviceRGB %d <\n", image->numcolors-1);
5363 for(i=0; i<image->numcolors; i++) {
5364 ps_printf(psdoc, "%02X", (int) ((image->palette[i].c1 * 255) + 0.5));
5365 ps_printf(psdoc, "%02X", (int) ((image->palette[i].c2 * 255) + 0.5));
5366 ps_printf(psdoc, "%02X", (int) ((image->palette[i].c3 * 255) + 0.5));
5367 if((i+1)%8 == 0)
5368 ps_printf(psdoc, "\n");
5369 else
5370 ps_printf(psdoc, " ");
5371 }
5372 ps_printf(psdoc, "> ] setcolorspace\n");
5373 break;
5374 }
5375 }
5376 ps_printf(psdoc, "<<\n");
5377 ps_printf(psdoc, " /ImageType 1\n");
5378 ps_printf(psdoc, " /Width %d\n", image->width);
5379 ps_printf(psdoc, " /Height %d\n", image->height);
5380 ps_printf(psdoc, " /BitsPerComponent %d\n", image->bpc);
5381 switch(image->colorspace) {
5382 case PS_COLORSPACE_GRAY:
5383 ps_printf(psdoc, " /Decode [0 1]\n");
5384 break;
5385 case PS_COLORSPACE_RGB:
5386 ps_printf(psdoc, " /Decode [0 1 0 1 0 1]\n");
5387 break;
5388 case PS_COLORSPACE_CMYK:
5389 ps_printf(psdoc, " /Decode [1 0 1 0 1 0 1 0]\n");
5390 break;
5391 case PS_COLORSPACE_INDEXED:
5392 ps_printf(psdoc, " /Decode [0 %d]\n", (int) pow(2,image->bpc)-1);
5393 break;
5394 }
5395 ps_printf(psdoc, " /ImageMatrix [%d 0 0 %d 0 %d]\n", image->width, -image->height, image->height);
5396 if(image->isreusable) {
5397 ps_printf(psdoc, " /DataSource %s\n", image->name);
5398 ps_printf(psdoc, ">> image\n");
5399 } else {
5400 ps_printf(psdoc, " /DataSource currentfile /ASCII%sDecode filter\n", (imgenc == NULL || strcmp(imgenc, "hex") != 0) ? "85" : "Hex");
5401 ps_printf(psdoc, ">> image\n");
5402 if(image->components == 4 && image->colorspace == PS_COLORSPACE_RGB) {
5403 dataptr = image->data;
5404 reallength = image->height*image->width*3;
5405 tmpdata = tmpdataptr = psdoc->malloc(psdoc, image->height*image->width*3, _("Allocate memory for temporary image data."));
5406 for(j=0; j<image->length; j++) {
5407 *tmpdataptr++ = *dataptr++;
5408 *tmpdataptr++ = *dataptr++;
5409 *tmpdataptr++ = *dataptr++;
5410 dataptr++;
5411 }
5412 } else {
5413 tmpdata = image->data;
5414 reallength = image->length;
5415 }
5416 if(imgenc == NULL || strcmp(imgenc, "hex") != 0)
5417 ps_ascii85_encode(psdoc, tmpdata, reallength);
5418 else
5419 ps_asciihex_encode(psdoc, tmpdata, reallength);
5420 if(image->components == 4 && image->colorspace == PS_COLORSPACE_RGB)
5421 psdoc->free(psdoc, tmpdata);
5422 }
5423 } else {
5424 /* Output the image mask */
5425 if(image->components == 4 && image->colorspace == PS_COLORSPACE_RGB) {
5426 ps_printf(psdoc, "<<\n");
5427 ps_printf(psdoc, " /ImageType 1\n");
5428 ps_printf(psdoc, " /Width %d\n", image->width);
5429 ps_printf(psdoc, " /Height %d\n", image->height);
5430 ps_printf(psdoc, " /BitsPerComponent 1\n");
5431 ps_printf(psdoc, " /Decode [0 1]\n");
5432 ps_printf(psdoc, " /ImageMatrix [%d 0 0 %d 0 %d]\n", image->width, -image->height, image->height);
5433 ps_printf(psdoc, " /DataSource currentfile /ASCII%sDecode filter\n", (imgenc == NULL || strcmp(imgenc, "hex") != 0) ? "85" : "Hex");
5434 ps_printf(psdoc, ">> imagemask\n");
5435 dataptr = image->data;
5436 tmpdata = tmpdataptr = psdoc->malloc(psdoc, (image->height*image->width/8)+1, _("Allocate memory for temporary image data."));
5437 i = 0;
5438 k = 0;
5439 *tmpdataptr = 0;
5440 for(j=0; j<image->height*image->width; j++) {
5441 dataptr++; /* skip red */
5442 dataptr++; /* skip green */
5443 dataptr++; /* skip blue */
5444 *tmpdataptr = *tmpdataptr << 1;
5445 if(*dataptr & 0x80) {
5446 *tmpdataptr += 1;
5447 }
5448 dataptr++;
5449 i++;
5450 if(i > 7) {
5451 tmpdataptr++;
5452 *tmpdataptr = 0;
5453 i = 0;
5454 k++;
5455 }
5456 }
5457 if(i < 8 && i > 0) {
5458 *tmpdataptr = *tmpdataptr << (8-i);
5459 k++;
5460 }
5461 if(imgenc == NULL || strcmp(imgenc, "hex") != 0)
5462 ps_ascii85_encode(psdoc, tmpdata, k);
5463 else
5464 ps_asciihex_encode(psdoc, tmpdata, k);
5465 psdoc->free(psdoc, tmpdata);
5466 ps_printf(psdoc, "\n");
5467 }
5468 }
5469
5470 #endif
5471 ps_printf(psdoc, "\n");
5472 ps_printf(psdoc, "grestore\n");
5473 } else if(0 == strncmp(image->type, "eps", 3)) {
5474 PS_save(psdoc);
5475 if(image->isreusable) {
5476 PS_translate(psdoc, x, y);
5477 PS_scale(psdoc, scale, scale);
5478 ps_printf(psdoc, "/showpage{}N/erasepage{}N/copypage{}N\n");
5479 ps_printf(psdoc, "%s 0 setfileposition %s cvx exec\n", image->name, image->name);
5480 } else {
5481 ps_printf(psdoc, "/showpage{}N/erasepage{}N/copypage{}N\n");
5482 PS_translate(psdoc, x, y);
5483 PS_scale(psdoc, scale, scale);
5484 ps_write(psdoc, image->data, image->length);
5485 }
5486 PS_restore(psdoc);
5487 } else if(0 == strcmp(image->type, "template")) {
5488 PS_save(psdoc);
5489 PS_translate(psdoc, x, y);
5490 PS_scale(psdoc, scale, scale);
5491 ps_printf(psdoc, "/%s /Form findresource execform\n", image->name);
5492 // ps_printf(psdoc, "%s\n", image->name);
5493 PS_restore(psdoc);
5494 } else {
5495 ps_error(psdoc, PS_RuntimeError, _("Images of type '%s' not supported."), image->type);
5496 }
5497 return;
5498 }
5499 /* }}} */
5500
5501 /* PS_close_image() {{{
5502 * Free the memory used by an image
5503 */
5504 PSLIB_API void PSLIB_CALL
5505 PS_close_image(PSDoc *psdoc, int imageid) {
5506 if(NULL == psdoc) {
5507 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
5508 return;
5509 }
5510 /*
5511 if(!ps_check_scope(psdoc, PS_SCOPE_DOCUMENT|PS_SCOPE_PAGE)) {
5512 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'document' or 'page' scope."), __FUNCTION__);
5513 return;
5514 }
5515 */
5516
5517 _ps_unregister_image(psdoc, imageid);
5518 }
5519 /* }}} */
5520
5521 /* PS_begin_template() {{{
5522 * starts a new template
5523 */
5524 PSLIB_API int PSLIB_CALL
5525 PS_begin_template(PSDoc *psdoc, float width, float height) {
5526 PSImage *pstemplate;
5527 char buffer[20];
5528 int templateid;
5529
5530 buffer[0] = '\0';
5531 if(NULL == psdoc) {
5532 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
5533 return(0);
5534 }
5535 /* If the header is not written, because we are before
5536 * the first page, then output the header first.
5537 */
5538 if(psdoc->beginprologwritten == ps_false) {
5539 ps_write_ps_comments(psdoc);
5540 ps_write_ps_beginprolog(psdoc);
5541 }
5542 if(ps_check_scope(psdoc, PS_SCOPE_DOCUMENT)) {
5543 ps_error(psdoc, PS_Warning, _("Calling %s between pages is likely to cause problems when viewing the document. Call it before the first page."), __FUNCTION__);
5544 }
5545 if(!ps_check_scope(psdoc, PS_SCOPE_DOCUMENT|PS_SCOPE_PROLOG)) {
5546 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'document' scope."), __FUNCTION__);
5547 return(0);
5548 }
5549
5550 if(NULL == (pstemplate = (PSImage *) psdoc->malloc(psdoc, sizeof(PSImage), _("Allocate memory for template.")))) {
5551 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for template."));
5552 return(0);
5553 }
5554 memset(pstemplate, 0, sizeof(PSImage));
5555 if(0 == (templateid = _ps_register_image(psdoc, pstemplate))) {
5556 ps_error(psdoc, PS_MemoryError, _("Could not register template."));
5557 psdoc->free(psdoc, pstemplate);
5558 return(0);
5559 }
5560
5561 sprintf(buffer, "template%d", templateid);
5562 pstemplate->psdoc = psdoc;
5563 pstemplate->name = ps_strdup(psdoc, buffer);
5564 pstemplate->type = ps_strdup(psdoc, "template");
5565 pstemplate->data = NULL;
5566 pstemplate->width = width;
5567 pstemplate->height = height;
5568
5569 // ps_printf(psdoc, "currentglobal true setglobal\n");
5570 ps_printf(psdoc, "/%s << /FormType 1 ", buffer);
5571 ps_printf(psdoc, "/BBox [0 0 %f %f] ", width, height);
5572 ps_printf(psdoc, "/Matrix [1 0 0 1 0 0] ");
5573 ps_printf(psdoc, "/PaintProc { pop\n");
5574
5575 // ps_printf(psdoc, "/%s {\n", buffer);
5576 ps_enter_scope(psdoc, PS_SCOPE_TEMPLATE);
5577
5578 return(templateid);
5579 }
5580 /* }}} */
5581
5582 /* PS_end_template() {{{
5583 * ends a template
5584 */
5585 PSLIB_API void PSLIB_CALL
5586 PS_end_template(PSDoc *psdoc) {
5587 if(NULL == psdoc) {
5588 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
5589 return;
5590 }
5591 if(!ps_check_scope(psdoc, PS_SCOPE_TEMPLATE)) {
5592 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'template' scope."), __FUNCTION__);
5593 return;
5594 }
5595
5596 ps_printf(psdoc, "} >> /Form defineresource pop %% setglobal\n");
5597 // ps_printf(psdoc, "} B\n");
5598
5599 ps_leave_scope(psdoc, PS_SCOPE_TEMPLATE);
5600 }
5601 /* }}} */
5602
5603 /* PS_begin_pattern() {{{
5604 * starts a new pattern
5605 */
5606 PSLIB_API int PSLIB_CALL
5607 PS_begin_pattern(PSDoc *psdoc, float width, float height, float xstep, float ystep, int painttype) {
5608 PSPattern *pspattern;
5609 char buffer[20];
5610 int patternid;
5611
5612 buffer[0] = '\0';
5613 if(NULL == psdoc) {
5614 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
5615 return(0);
5616 }
5617 if(painttype < 1 || painttype > 2) {
5618 ps_error(psdoc, PS_RuntimeError, _("Painttype must be 1 or 2."));
5619 return(0);
5620 }
5621
5622 /* If the header is not written, because we are before
5623 * the first page, then output the header first.
5624 */
5625 if(psdoc->beginprologwritten == ps_false) {
5626 ps_write_ps_comments(psdoc);
5627 ps_write_ps_beginprolog(psdoc);
5628 }
5629 if(ps_check_scope(psdoc, PS_SCOPE_DOCUMENT)) {
5630 ps_error(psdoc, PS_Warning, _("Calling %s between pages is likely to cause problems when viewing the document. Call it before the first page."), __FUNCTION__);
5631 }
5632 if(!ps_check_scope(psdoc, PS_SCOPE_DOCUMENT|PS_SCOPE_PROLOG)) {
5633 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'document' scope."), __FUNCTION__);
5634 return(0);
5635 }
5636
5637 if(NULL == (pspattern = (PSPattern *) psdoc->malloc(psdoc, sizeof(PSPattern), _("Allocate memory for pattern.")))) {
5638 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for pattern."));
5639 return(0);
5640 }
5641 memset(pspattern, 0, sizeof(PSPattern));
5642 psdoc->pattern = pspattern;
5643 if(0 == (patternid = _ps_register_pattern(psdoc, pspattern))) {
5644 ps_error(psdoc, PS_MemoryError, _("Could not register pattern."));
5645 psdoc->free(psdoc, pspattern);
5646 return(0);
5647 }
5648
5649 sprintf(buffer, "pattern%d", patternid);
5650 pspattern->psdoc = psdoc;
5651 pspattern->name = ps_strdup(psdoc, buffer);
5652 pspattern->painttype = painttype;
5653 pspattern->xstep = xstep;
5654 pspattern->ystep = ystep;
5655 pspattern->width = width;
5656 pspattern->height = height;
5657
5658 ps_printf(psdoc, "<< /PatternType 1 ");
5659 ps_printf(psdoc, "/BBox [0 0 %f %f] ", width, height);
5660 ps_printf(psdoc, "/XStep %f ", xstep);
5661 ps_printf(psdoc, "/YStep %f ", ystep);
5662 ps_printf(psdoc, "/PaintType %d ", painttype);
5663 ps_printf(psdoc, "/TilingType 1 ");
5664 ps_printf(psdoc, "/PaintProc { begin \n");
5665
5666 ps_enter_scope(psdoc, PS_SCOPE_PATTERN);
5667
5668 return(patternid);
5669 }
5670 /* }}} */
5671
5672 /* PS_end_pattern() {{{
5673 * ends a pattern
5674 */
5675 PSLIB_API void PSLIB_CALL
5676 PS_end_pattern(PSDoc *psdoc) {
5677 if(NULL == psdoc) {
5678 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
5679 return;
5680 }
5681 if(!ps_check_scope(psdoc, PS_SCOPE_PATTERN)) {
5682 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'pattern' scope."), __FUNCTION__);
5683 return;
5684 }
5685
5686 ps_printf(psdoc, " end } bind >> matrix makepattern /%s exch def\n", psdoc->pattern->name);
5687
5688 ps_leave_scope(psdoc, PS_SCOPE_PATTERN);
5689 }
5690 /* }}} */
5691
5692 /* PS_shading_pattern() {{{
5693 * Creates a shading pattern
5694 */
5695 PSLIB_API int PSLIB_CALL
5696 PS_shading_pattern(PSDoc *psdoc, int shading, const char *optlist) {
5697 PSPattern *pspattern;
5698 char buffer[20];
5699 int patternid;
5700 PSShading *psshading;
5701
5702 buffer[0] = '\0';
5703 if(NULL == psdoc) {
5704 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
5705 return 0;
5706 }
5707 if(!ps_check_scope(psdoc, PS_SCOPE_DOCUMENT|PS_SCOPE_PAGE)) {
5708 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'document' or 'page' scope."), __FUNCTION__);
5709 return 0;
5710 }
5711 psshading = _ps_get_shading(psdoc, shading);
5712 if(NULL == psshading) {
5713 ps_error(psdoc, PS_RuntimeError, _("PSShading is null."));
5714 return 0;
5715 }
5716 if(NULL == (pspattern = (PSPattern *) psdoc->malloc(psdoc, sizeof(PSPattern), _("Allocate memory for pattern.")))) {
5717 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for pattern."));
5718 return(0);
5719 }
5720 memset(pspattern, 0, sizeof(PSPattern));
5721 psdoc->pattern = pspattern;
5722 if(0 == (patternid = _ps_register_pattern(psdoc, pspattern))) {
5723 ps_error(psdoc, PS_MemoryError, _("Could not register pattern."));
5724 psdoc->free(psdoc, pspattern);
5725 return(0);
5726 }
5727
5728 sprintf(buffer, "pattern%d", patternid);
5729 pspattern->psdoc = psdoc;
5730 pspattern->name = ps_strdup(psdoc, buffer);
5731 pspattern->painttype = 1;
5732
5733 ps_printf(psdoc, "<< /PatternType 2 ", buffer);
5734 ps_printf(psdoc, " /Shading\n", buffer);
5735 ps_output_shading_dict(psdoc, psshading);
5736 ps_printf(psdoc, ">> matrix makepattern /%s exch def\n", pspattern->name);
5737 return(patternid);
5738 }
5739 /* }}} */
5740
5741 /* PS_shading() {{{
5742 * Creates a shading object
5743 */
5744 PSLIB_API int PSLIB_CALL
5745 PS_shading(PSDoc *psdoc, const char *shtype, float x0, float y0, float x1, float y1, float c1, float c2, float c3, float c4, const char *optlist) {
5746 PSShading *psshading;
5747 int shadingid;
5748 float optlist_N = 1.0, optlist_r0 = 0.0, optlist_r1 = 0.0;
5749 ps_bool optlist_extend0 = ps_false, optlist_extend1 = ps_false;
5750 ps_bool optlist_antialias = 0;
5751
5752 if(NULL == psdoc) {
5753 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
5754 return(0);
5755 }
5756 if(!ps_check_scope(psdoc, PS_SCOPE_DOCUMENT|PS_SCOPE_PAGE)) {
5757 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'document' or 'page' scope."), __FUNCTION__);
5758 return(0);
5759 }
5760
5761 if(psdoc->agstates[psdoc->agstate].fillcolor.colorspace == PS_COLORSPACE_PATTERN) {
5762 ps_error(psdoc, PS_RuntimeError, _("Current fill color is a pattern which cannot be used for shading."));
5763 return(0);
5764 }
5765
5766 if(psdoc->agstates[psdoc->agstate].fillcolor.colorspace == PS_COLORSPACE_SPOT &&
5767 psdoc->agstates[psdoc->agstate].fillcolor.c1 != c1) {
5768 ps_error(psdoc, PS_RuntimeError, _("The current fill spot color is not the same color as the one set for shading."));
5769 return(0);
5770 }
5771 // FIXME: There must be some checking, if the passed spot color
5772 // is in the same as the fill color set before.
5773 if(NULL == (psshading = (PSShading *) psdoc->malloc(psdoc, sizeof(PSShading), _("Allocate memory for pattern.")))) {
5774 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for shading."));
5775 return(0);
5776 }
5777 memset(psshading, 0, sizeof(PSShading));
5778
5779 /* Read the option list only, if it is non empty. */
5780 if(NULL != optlist && optlist[0] != '\0') {
5781 ght_hash_table_t *opthash;
5782 opthash = ps_parse_optlist(psdoc, optlist);
5783 if(NULL == opthash) {
5784 ps_error(psdoc, PS_RuntimeError, _("Error while parsing option list."));
5785 return(0);
5786 }
5787 /* Issue a warning only if a value is given but cannot be parsed */
5788 if(-2 == get_optlist_element_as_float(psdoc, opthash, "N", &optlist_N)) {
5789 ps_error(psdoc, PS_Warning, _("Value of option list element 'N' could not be read, using default."));
5790 }
5791 if(-2 == get_optlist_element_as_bool(psdoc, opthash, "extend0", &optlist_extend0)) {
5792 ps_error(psdoc, PS_Warning, _("Value of option list element 'extend0' could not be read, using default."));
5793 }
5794 if(-2 == get_optlist_element_as_bool(psdoc, opthash, "extend1", &optlist_extend1)) {
5795 ps_error(psdoc, PS_Warning, _("Value of option list element 'extend1' could not be read, using default."));
5796 }
5797 if(-2 == get_optlist_element_as_bool(psdoc, opthash, "antialias", &optlist_antialias)) {
5798 ps_error(psdoc, PS_Warning, _("Value of option list element 'antialias' could not be read, using default."));
5799 }
5800 if(strcmp(shtype, "radial") == 0) {
5801 if(0 > get_optlist_element_as_float(psdoc, opthash, "r0", &optlist_r0)) {
5802 ps_error(psdoc, PS_RuntimeError, _("Could not retrieve required parameter 'r0' from option list."));
5803 return(0);
5804 }
5805 if(0 > get_optlist_element_as_float(psdoc, opthash, "r1", &optlist_r1)) {
5806 ps_error(psdoc, PS_RuntimeError, _("Could not retrieve required parameter 'r1' from option list."));
5807 return(0);
5808 }
5809 }
5810 ps_free_optlist(psdoc, opthash);
5811 } else if(strcmp(shtype, "radial") == 0) {
5812 ps_error(psdoc, PS_RuntimeError, _("If type of shading is 'radial' the parameters 'r0' and 'r1' must be set in the option list."));
5813 return(0);
5814 }
5815
5816 if(strcmp(shtype, "axial") == 0) {
5817 psshading->type = 2;
5818 } else if(strcmp(shtype, "radial") == 0) {
5819 psshading->type = 3;
5820 } else {
5821 ps_error(psdoc, PS_RuntimeError, _("Type of shading must be 'radial' or 'axial'."));
5822 return(0);
5823 }
5824 psshading->x0 = x0;
5825 psshading->y0 = y0;
5826 psshading->x1 = x1;
5827 psshading->y1 = y1;
5828 psshading->r0 = optlist_r0;
5829 psshading->r1 = optlist_r1;
5830 psshading->N = optlist_N;
5831 psshading->extend0 = optlist_extend0;
5832 psshading->extend1 = optlist_extend1;
5833 psshading->antialias = optlist_antialias;
5834 psshading->startcolor.colorspace = psdoc->agstates[psdoc->agstate].fillcolor.colorspace;
5835 psshading->startcolor.prevcolorspace = psdoc->agstates[psdoc->agstate].fillcolor.prevcolorspace;
5836 psshading->startcolor.pattern = psdoc->agstates[psdoc->agstate].fillcolor.pattern;
5837 psshading->startcolor.c1 = psdoc->agstates[psdoc->agstate].fillcolor.c1;
5838 psshading->startcolor.c2 = psdoc->agstates[psdoc->agstate].fillcolor.c2;
5839 psshading->startcolor.c3 = psdoc->agstates[psdoc->agstate].fillcolor.c3;
5840 psshading->startcolor.c4 = psdoc->agstates[psdoc->agstate].fillcolor.c4;
5841 psshading->endcolor.colorspace = psshading->startcolor.colorspace;
5842 psshading->endcolor.prevcolorspace = 0;
5843 psshading->endcolor.pattern = 0;
5844 psshading->endcolor.c1 = c1;
5845 psshading->endcolor.c2 = c2;
5846 psshading->endcolor.c3 = c3;
5847 psshading->endcolor.c4 = c4;
5848
5849 if(0 == (shadingid = _ps_register_shading(psdoc, psshading))) {
5850 ps_error(psdoc, PS_MemoryError, _("Could not register shading."));
5851 psdoc->free(psdoc, psshading);
5852 return(0);
5853 }
5854 return(shadingid);
5855 }
5856 /* }}} */
5857
5858 /* PS_begin_font() {{{
5859 * starts a new font
5860 */
5861 PSLIB_API int PSLIB_CALL
5862 PS_begin_font(PSDoc *psdoc, const char *fontname, int reserverd, double a, double b, double c, double d, double e, double f, const char *optlist) {
5863 PSFont *psfont;
5864 ENCODING *fontenc;
5865 ADOBEFONTMETRIC *metrics;
5866 char buffer[20];
5867 int fontid, i;
5868
5869 buffer[0] = '\0';
5870 if(NULL == psdoc) {
5871 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
5872 return(0);
5873 }
5874
5875 /* If the header is not written, because we are before
5876 * the first page, then output the header first.
5877 */
5878 if(psdoc->beginprologwritten == ps_false) {
5879 ps_write_ps_comments(psdoc);
5880 ps_write_ps_beginprolog(psdoc);
5881 }
5882 if(ps_check_scope(psdoc, PS_SCOPE_DOCUMENT)) {
5883 ps_error(psdoc, PS_Warning, _("Calling %s between pages is likely to cause problems when viewing the document. Call it before the first page."), __FUNCTION__);
5884 }
5885 if(!ps_check_scope(psdoc, PS_SCOPE_DOCUMENT|PS_SCOPE_PROLOG)) {
5886 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'document' scope."), __FUNCTION__);
5887 return(0);
5888 }
5889
5890 if(NULL == (psfont = (PSFont *) psdoc->malloc(psdoc, sizeof(PSFont), _("Allocate memory for font.")))) {
5891 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for font."));
5892 return(0);
5893 }
5894 memset(psfont, 0, sizeof(PSFont));
5895
5896 if(NULL == (metrics = (ADOBEFONTMETRIC *) psdoc->malloc(psdoc, sizeof(ADOBEFONTMETRIC), _("Allocate space for font metric.")))) {
5897 return(0);
5898 }
5899 memset(metrics, 0, sizeof(ADOBEFONTMETRIC));
5900 metrics->codingscheme = ps_strdup(psdoc, "FontSpecific");
5901 metrics->fontname = ps_strdup(psdoc, fontname);
5902 metrics->fontenc = NULL;
5903 metrics->gadobechars = ght_create(512);
5904 ght_set_alloc(metrics->gadobechars, ps_ght_malloc, ps_ght_free, psdoc);
5905 readencoding(psdoc, metrics, NULL);
5906 psfont->encoding = ps_strdup(psdoc, "default");
5907 psfont->metrics = metrics;
5908 psdoc->font = psfont;
5909
5910 if(0 == (fontid = _ps_register_font(psdoc, psfont))) {
5911 ps_error(psdoc, PS_MemoryError, _("Could not register font."));
5912 psdoc->free(psdoc, psfont);
5913 return(0);
5914 }
5915
5916 psfont->psdoc = psdoc;
5917
5918 ps_printf(psdoc, "8 dict begin\n");
5919 ps_printf(psdoc, " /FontType 3 def\n");
5920 ps_printf(psdoc, " /FontMatrix [%f %f %f %f %f %f] def\n", a, b, c, d, e, f);
5921 // ps_printf(psdoc, " /FontName %s \n", fontname);
5922 ps_printf(psdoc, " /FontBBox [0 0 750 750] def\n");
5923 ps_printf(psdoc, " /Encoding 256 array def 0 1 255 {Encoding exch /.notdef put} for\n");
5924 fontenc = &fontencoding[0];
5925 for(i=0; i<255; i++) {
5926 if((fontenc->vec[i] != NULL) && (*(fontenc->vec[i]) != '\0')) {
5927 ps_printf(psdoc, " Encoding %d /%s put\n", i, fontenc->vec[i]);
5928 }
5929 }
5930 ps_printf(psdoc, " /BuildGlyph\n");
5931 ps_printf(psdoc, " { %%1000 0\n");
5932 ps_printf(psdoc, " %%0 0 750 750\n");
5933 ps_printf(psdoc, " %%setcachedevice\n");
5934 ps_printf(psdoc, " exch /CharProcs get exch\n");
5935 ps_printf(psdoc, " 2 copy known not { pop /.notdef} if\n");
5936 ps_printf(psdoc, " get exec\n");
5937 ps_printf(psdoc, " } bind def\n");
5938 ps_printf(psdoc, " /BuildChar\n");
5939 ps_printf(psdoc, " { 1 index /Encoding get exch get\n");
5940 ps_printf(psdoc, " 1 index /BuildGlyph get exec\n");
5941 ps_printf(psdoc, " } bind def\n");
5942 // ps_printf(psdoc, " currentdict\n");
5943 ps_printf(psdoc, " /CharProcs 255 dict def\n");
5944 ps_printf(psdoc, " CharProcs begin\n");
5945 ps_printf(psdoc, " /.notdef { } def\n");
5946
5947 ps_enter_scope(psdoc, PS_SCOPE_FONT);
5948
5949 return(fontid);
5950 }
5951 /* }}} */
5952
5953 /* PS_end_font() {{{
5954 * ends a font
5955 */
5956 PSLIB_API void PSLIB_CALL
5957 PS_end_font(PSDoc *psdoc) {
5958 PSFont *psfont;
5959
5960 if(NULL == psdoc) {
5961 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
5962 return;
5963 }
5964 if(!ps_check_scope(psdoc, PS_SCOPE_FONT)) {
5965 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'font' scope."), __FUNCTION__);
5966 return;
5967 }
5968
5969 psfont = psdoc->font;
5970 ps_printf(psdoc, " end\n");
5971 ps_printf(psdoc, " currentdict\n");
5972 ps_printf(psdoc, "end\n");
5973 ps_printf(psdoc, "/%s exch definefont pop\n", psfont->metrics->fontname);
5974
5975 ps_leave_scope(psdoc, PS_SCOPE_FONT);
5976 }
5977 /* }}} */
5978
5979 /* PS_begin_glyph() {{{
5980 * starts a new glyph
5981 */
5982 PSLIB_API int PSLIB_CALL
5983 PS_begin_glyph(PSDoc *psdoc, const char *glyphname, double wx, double llx, double lly, double urx, double ury) {
5984 ADOBEINFO *ai;
5985 PSFont *psfont;
5986
5987 if(NULL == psdoc) {
5988 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
5989 return 0;
5990 }
5991 if(!ps_check_scope(psdoc, PS_SCOPE_FONT)) {
5992 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'font' scope."), __FUNCTION__);
5993 return 0;
5994 }
5995
5996 psfont = psdoc->font;
5997 if(ai = gfindadobe(psfont->metrics->gadobechars, glyphname)) {
5998 ps_error(psdoc, PS_RuntimeError, _("Font already contains glyph with name '%s'."), glyphname);
5999 return 0;
6000 }
6001
6002 ai = (ADOBEINFO *) psdoc->malloc(psdoc, (unsigned long) sizeof(ADOBEINFO), "newchar: allocate memory for new characters") ;
6003 ai->adobenum = -1 ;
6004 ai->texnum = -1 ;
6005 ai->adobename = ps_strdup(psdoc, glyphname);
6006 ai->llx = llx;
6007 ai->lly = lly;
6008 ai->urx = urx;
6009 ai->ury = ury;
6010 ai->lkern = 0;
6011 ai->rkern = 0;
6012 ai->ligs = NULL ;
6013 ai->kerns = NULL ;
6014 ai->kern_equivs = NULL ;
6015 ai->pccs = NULL ;
6016 ai->width = wx;
6017 ght_insert(psfont->metrics->gadobechars, ai, strlen(glyphname)+1, (void *) glyphname);
6018
6019 ps_printf(psdoc, " /%s {\n", glyphname);
6020 ps_printf(psdoc, " %.4f 0 %.4f %.4f %.4f %.4f setcachedevice\n", (float) wx, (float) llx, (float) lly, (float) urx, (float) ury);
6021 ps_enter_scope(psdoc, PS_SCOPE_GLYPH);
6022 return 1;
6023 }
6024 /* }}} */
6025
6026 /* PS_end_glyph() {{{
6027 * ends a glyph
6028 */
6029 PSLIB_API void PSLIB_CALL
6030 PS_end_glyph(PSDoc *psdoc) {
6031 if(NULL == psdoc) {
6032 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6033 return;
6034 }
6035 if(!ps_check_scope(psdoc, PS_SCOPE_GLYPH)) {
6036 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'glyph' scope."), __FUNCTION__);
6037 return;
6038 }
6039
6040 ps_printf(psdoc, " } bind def\n");
6041
6042 ps_leave_scope(psdoc, PS_SCOPE_GLYPH);
6043 }
6044 /* }}} */
6045
6046 /* PS_add_kerning() {{{
6047 * adds kerning for pair of glyphs
6048 */
6049 PSLIB_API void PSLIB_CALL
6050 PS_add_kerning(PSDoc *psdoc, int fontid, const char *glyphname1, const char *glyphname2, int kern) {
6051 ADOBEINFO *ai1, *ai2;
6052 PSFont *psfont;
6053
6054 if(NULL == psdoc) {
6055 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6056 return;
6057 }
6058 if(!ps_check_scope(psdoc, PS_SCOPE_FONT)) {
6059 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'font' scope."), __FUNCTION__);
6060 return;
6061 }
6062
6063 if(0 == fontid)
6064 psfont = psdoc->font;
6065 else {
6066 if(NULL == (psfont = _ps_get_font(psdoc, fontid)))
6067 return;
6068 }
6069
6070 ai1 = gfindadobe(psfont->metrics->gadobechars, glyphname1);
6071 if(!ai1) {
6072 ps_error(psdoc, PS_RuntimeError, _("First glyph '%s' of kerning pair does not exist in font."), glyphname1);
6073 return;
6074 }
6075 ai2 = gfindadobe(psfont->metrics->gadobechars, glyphname2);
6076 if(!ai2) {
6077 ps_error(psdoc, PS_RuntimeError, _("Second glyph '%s' of kerning pair does not exist in font."), glyphname2);
6078 return;
6079 }
6080 if(calculatekern(ai1, ai2) != 0) {
6081 ps_error(psdoc, PS_RuntimeError, _("Kerning pair (%s, %s) already exists in font."), glyphname1, glyphname2);
6082 }
6083 addkern(psdoc, ai1, ai2, kern);
6084 }
6085 /* }}} */
6086
6087 /* PS_add_ligature() {{{
6088 * adds ligature for pair of glyphs
6089 */
6090 PSLIB_API void PSLIB_CALL
6091 PS_add_ligature(PSDoc *psdoc, int fontid, const char *glyphname1, const char *glyphname2, const char *glyphname3) {
6092 ADOBEINFO *ai1, *ai2, *ai3;
6093 PSFont *psfont;
6094
6095 if(NULL == psdoc) {
6096 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6097 return;
6098 }
6099 if(!ps_check_scope(psdoc, PS_SCOPE_FONT)) {
6100 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'font' scope."), __FUNCTION__);
6101 return;
6102 }
6103
6104 if(0 == fontid)
6105 psfont = psdoc->font;
6106 else {
6107 if(NULL == (psfont = _ps_get_font(psdoc, fontid)))
6108 return;
6109 }
6110
6111 ai1 = gfindadobe(psfont->metrics->gadobechars, glyphname1);
6112 if(!ai1) {
6113 ps_error(psdoc, PS_RuntimeError, _("First glyph '%s' of ligature does not exist in font."), glyphname1);
6114 return;
6115 }
6116 ai2 = gfindadobe(psfont->metrics->gadobechars, glyphname2);
6117 if(!ai2) {
6118 ps_error(psdoc, PS_RuntimeError, _("Successor glyph '%s' of ligature does not exist in font."), glyphname2);
6119 return;
6120 }
6121 ai3 = gfindadobe(psfont->metrics->gadobechars, glyphname3);
6122 if(!ai3) {
6123 ps_error(psdoc, PS_RuntimeError, _("Substitute glyph '%s' of ligature does not exist in font."), glyphname3);
6124 return;
6125 }
6126 addligature(psdoc, ai1, ai2, ai3);
6127 }
6128 /* }}} */
6129
6130 /* PS_get_buffer() {{{
6131 * Returns a pointer to the current buffer and sets its size to 0
6132 */
6133 PSLIB_API const char * PSLIB_CALL
6134 PS_get_buffer(PSDoc *psdoc, long *size) {
6135 const char *tmp;
6136 if(NULL == psdoc) {
6137 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6138 return(NULL);
6139 }
6140 if(NULL == psdoc->sb) {
6141 *size = 0;
6142 return(NULL);
6143 }
6144 *size = str_buffer_len(psdoc, psdoc->sb);
6145 tmp = str_buffer_get(psdoc, psdoc->sb);
6146 str_buffer_clear(psdoc, psdoc->sb);
6147 return(tmp);
6148 }
6149 /* }}} */
6150
6151 /* PS_set_border_style() {{{
6152 * Sets style of border for link destination
6153 */
6154 PSLIB_API void PSLIB_CALL
6155 PS_set_border_style(PSDoc *psdoc, const char *style, float width) {
6156 if(NULL == psdoc) {
6157 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6158 return;
6159 }
6160 if(!ps_check_scope(psdoc, PS_SCOPE_DOCUMENT|PS_SCOPE_PAGE)) {
6161 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'document' or 'page' scope."), __FUNCTION__);
6162 return;
6163 }
6164
6165 psdoc->border_width = width;
6166 if(0 == strcmp(style, "solid"))
6167 psdoc->border_style = PS_BORDER_SOLID;
6168 else if(0 == strcmp(style, "dashed")) {
6169 psdoc->border_style = PS_BORDER_DASHED;
6170 psdoc->border_white = psdoc->border_black = 3.0;
6171 } else
6172 ps_error(psdoc, PS_RuntimeError, _("Parameter style of PS_set_border_style() must be 'solid' or 'dashed'\n"));
6173 }
6174 /* }}} */
6175
6176 /* PS_set_border_color() {{{
6177 * Sets color of border for link destination
6178 */
6179 PSLIB_API void PSLIB_CALL
6180 PS_set_border_color(PSDoc *psdoc, float red, float green, float blue) {
6181 if(NULL == psdoc) {
6182 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6183 return;
6184 }
6185 if(!ps_check_scope(psdoc, PS_SCOPE_DOCUMENT|PS_SCOPE_PAGE)) {
6186 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'document' or 'page' scope."), __FUNCTION__);
6187 return;
6188 }
6189
6190 psdoc->border_red = red;
6191 psdoc->border_green = green;
6192 psdoc->border_blue = blue;
6193 }
6194 /* }}} */
6195
6196 /* PS_set_border_dash() {{{
6197 * Sets dash of border for link destination
6198 */
6199 PSLIB_API void PSLIB_CALL
6200 PS_set_border_dash(PSDoc *psdoc, float black, float white) {
6201 if(NULL == psdoc) {
6202 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6203 return;
6204 }
6205 if(!ps_check_scope(psdoc, PS_SCOPE_DOCUMENT|PS_SCOPE_PAGE)) {
6206 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'document' or 'page' scope."), __FUNCTION__);
6207 return;
6208 }
6209
6210 psdoc->border_black = black;
6211 psdoc->border_white = white;
6212 }
6213 /* }}} */
6214
6215 /* _ps_output_anno_border() {{{
6216 *
6217 */
6218 void static
6219 _ps_output_anno_border(PSDoc *psdoc) {
6220 switch(psdoc->border_style) {
6221 case PS_BORDER_SOLID:
6222 ps_printf(psdoc, "/Border [ %f 1 1 ] ", psdoc->border_width);
6223 break;
6224 case PS_BORDER_DASHED:
6225 ps_printf(psdoc, "/Border [ %f %f %f ] ", psdoc->border_black, psdoc->border_white, psdoc->border_width);
6226 break;
6227 }
6228 ps_printf(psdoc, "/Color [ %f %f %f ] ", psdoc->border_red, psdoc->border_green, psdoc->border_blue);
6229 }
6230 /* }}} */
6231
6232 /* PS_add_weblink() {{{
6233 * Adds a link to an external web page
6234 */
6235 PSLIB_API void PSLIB_CALL
6236 PS_add_weblink(PSDoc *psdoc, float llx, float lly, float urx, float ury, const char *url) {
6237 if(NULL == psdoc) {
6238 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6239 return;
6240 }
6241 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE)) {
6242 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page' scope."), __FUNCTION__);
6243 return;
6244 }
6245
6246 ps_printf(psdoc, "[ /Rect [ %f %f %f %f] ", llx, lly, urx, ury);
6247 _ps_output_anno_border(psdoc);
6248 ps_printf(psdoc, "/Action << /Subtype /URI /URI (%s) >> /Subtype /Link /ANN pdfmark\n", url);
6249 }
6250 /* }}} */
6251
6252 /* PS_add_pdflink() {{{
6253 * Adds a link to external pdf document
6254 */
6255 PSLIB_API void PSLIB_CALL
6256 PS_add_pdflink(PSDoc *psdoc, float llx, float lly, float urx, float ury, const char *filename, int page, const char *dest) {
6257 if(NULL == psdoc) {
6258 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6259 return;
6260 }
6261 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE)) {
6262 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page' scope."), __FUNCTION__);
6263 return;
6264 }
6265
6266 ps_printf(psdoc, "[ /Rect [ %f %f %f %f] ", llx, lly, urx, ury);
6267 _ps_output_anno_border(psdoc);
6268 ps_printf(psdoc, "/Page %d ", page);
6269 if(0 == strcmp(dest, "fitpage"))
6270 ps_printf(psdoc, "/View %s ", "[ /Fit ]");
6271 else if(0 == strcmp(dest, "fitwidth"))
6272 ps_printf(psdoc, "/View %s ", "[ /FitH -32768 ]");
6273 else if(0 == strcmp(dest, "fitheight"))
6274 ps_printf(psdoc, "/View %s ", "[ /FitV -32768 ]");
6275 else if(0 == strcmp(dest, "fitbbox"))
6276 ps_printf(psdoc, "/View %s ", "/FitB");
6277 else if(0 != strcmp(dest, "retain"))
6278 ps_error(psdoc, PS_RuntimeError, _("Parameter dest of PS_add_pdflink() must be 'fitpage', 'fitwidth', 'fitheight', 'fitbbox', 'retain'."));
6279 ps_printf(psdoc, "/Action /GoToR /File (%s) /Subtype /Link /ANN pdfmark\n", filename);
6280 }
6281 /* }}} */
6282
6283 /* PS_add_locallink() {{{
6284 * Adds a link within the pdf document
6285 */
6286 PSLIB_API void PSLIB_CALL
6287 PS_add_locallink(PSDoc *psdoc, float llx, float lly, float urx, float ury, const int page, const char *dest) {
6288 if(NULL == psdoc) {
6289 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6290 return;
6291 }
6292 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE)) {
6293 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page' scope."), __FUNCTION__);
6294 return;
6295 }
6296
6297 ps_printf(psdoc, "[ /Rect [ %f %f %f %f] ", llx, lly, urx, ury);
6298 _ps_output_anno_border(psdoc);
6299 if(page == PS_GOTO_NEXT_PAGE)
6300 ps_printf(psdoc, "/Page /Next ");
6301 else if(page == PS_GOTO_PREV_PAGE)
6302 ps_printf(psdoc, "/Page /Prev ");
6303 else
6304 ps_printf(psdoc, "/Page %d ", page);
6305 if(0 == strcmp(dest, "fitpage"))
6306 ps_printf(psdoc, "/View %s ", "[ /Fit ]");
6307 else if(0 == strcmp(dest, "fitwidth"))
6308 ps_printf(psdoc, "/View %s ", "[ /FitH -32768 ]");
6309 else if(0 == strcmp(dest, "fitheight"))
6310 ps_printf(psdoc, "/View %s ", "[ /FitV -32768 ]");
6311 else if(0 == strcmp(dest, "fitbbox"))
6312 ps_printf(psdoc, "/View %s ", "/FitB");
6313 else if(0 != strcmp(dest, "retain"))
6314 ps_error(psdoc, PS_RuntimeError, _("Parameter dest of PS_add_locallink() must be 'fitpage', 'fitwidth', 'fitheight', 'fitbbox', 'retain'."));
6315 ps_printf(psdoc, "/Subtype /Link /ANN pdfmark\n");
6316 }
6317 /* }}} */
6318
6319 /* PS_add_launchlink() {{{
6320 * Adds a link to an external program or file
6321 */
6322 PSLIB_API void PSLIB_CALL
6323 PS_add_launchlink(PSDoc *psdoc, float llx, float lly, float urx, float ury, const char *filename) {
6324 if(NULL == psdoc) {
6325 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6326 return;
6327 }
6328 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE)) {
6329 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page' scope."), __FUNCTION__);
6330 return;
6331 }
6332
6333 ps_printf(psdoc, "[ /Rect [ %f %f %f %f] ", llx, lly, urx, ury);
6334 _ps_output_anno_border(psdoc);
6335 ps_printf(psdoc, "/Action << /S /Launch /F (%s) >> /Subtype /Link /ANN pdfmark\n", filename);
6336 }
6337 /* }}} */
6338
6339 /* PS_add_bookmark() {{{
6340 * Adds a bookmark (nested bookmarks are not yet support)
6341 */
6342 PSLIB_API int PSLIB_CALL
6343 PS_add_bookmark(PSDoc *psdoc, const char *text, int parent, int open) {
6344 PS_BOOKMARK *bookmark, *parentbookmark;
6345 DLIST *bl;
6346
6347 if(NULL == psdoc) {
6348 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6349 return(0);
6350 }
6351 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE)) {
6352 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page' scope."), __FUNCTION__);
6353 return(0);
6354 }
6355
6356 if(parent < 0 || parent > psdoc->lastbookmarkid) {
6357 ps_error(psdoc, PS_RuntimeError, _("Parent bookmark ist out of possible range."));
6358 return(0);
6359 }
6360 if(parent == 0) { /* Add bookmark on first level */
6361 bl = psdoc->bookmarks;
6362 } else {
6363 parentbookmark = psdoc->bookmarkdict[parent-1];
6364 bl = parentbookmark->children;
6365 }
6366 bookmark = (PS_BOOKMARK *) dlst_newnode(bl, sizeof(PS_BOOKMARK));
6367 if(NULL == bookmark) {
6368 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for new bookmark."));
6369 return(0);
6370 }
6371 bookmark->page = psdoc->page;
6372 bookmark->text = ps_strdup(psdoc, text);
6373 bookmark->open = open;
6374 if(psdoc->bookmarkcnt <= psdoc->lastbookmarkid) {
6375 psdoc->bookmarkcnt += 20;
6376 if(NULL == (psdoc->bookmarkdict = psdoc->realloc(psdoc, psdoc->bookmarkdict, psdoc->bookmarkcnt*sizeof(PS_BOOKMARK *), _("Allocate memory for new bookmark lookup table.")))) {
6377 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for larger bookmark lookup table."));
6378 psdoc->bookmarkcnt -= 20;
6379 psdoc->free(psdoc, bookmark->text);
6380 dlst_freenode(bl, bookmark);
6381 return(0);
6382 }
6383 }
6384 psdoc->bookmarkdict[psdoc->lastbookmarkid] = bookmark;
6385 if(NULL == (bookmark->children = dlst_init(psdoc->malloc, psdoc->realloc, psdoc->free))) {
6386 ps_error(psdoc, PS_RuntimeError, _("Could not initialize bookmark list of new bookmark."));
6387 psdoc->free(psdoc, bookmark->text);
6388 dlst_freenode(bl, bookmark);
6389 return(0);
6390 }
6391 psdoc->lastbookmarkid++;
6392 bookmark->id = psdoc->lastbookmarkid;
6393 dlst_insertafter(bl, bookmark, PS_DLST_HEAD(bl));
6394 return(bookmark->id);
6395 }
6396 /* }}} */
6397
6398 /* PS_add_note() {{{
6399 * Adds a note
6400 */
6401 PSLIB_API void PSLIB_CALL
6402 PS_add_note(PSDoc *psdoc, float llx, float lly, float urx, float ury, const char *contents, const char *title, const char *icon, int open) {
6403 if(NULL == psdoc) {
6404 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6405 return;
6406 }
6407 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE)) {
6408 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page' scope."), __FUNCTION__);
6409 return;
6410 }
6411
6412 ps_printf(psdoc, "[ /Rect [ %f %f %f %f] ", llx, lly, urx, ury);
6413 _ps_output_anno_border(psdoc);
6414 if(open)
6415 ps_printf(psdoc, "/Open true ");
6416 if(0 == strcmp(icon, "comment"))
6417 ps_printf(psdoc, "/Name /Comment ");
6418 else if(0 == strcmp(icon, "insert"))
6419 ps_printf(psdoc, "/Name /Insert ");
6420 else if(0 == strcmp(icon, "note"))
6421 ps_printf(psdoc, "/Name /Note ");
6422 else if(0 == strcmp(icon, "paragraph"))
6423 ps_printf(psdoc, "/Name /Paragraph ");
6424 else if(0 == strcmp(icon, "newparagraph"))
6425 ps_printf(psdoc, "/Name /Newparagraph ");
6426 else if(0 == strcmp(icon, "key"))
6427 ps_printf(psdoc, "/Name /Key ");
6428 else if(0 == strcmp(icon, "help"))
6429 ps_printf(psdoc, "/Name /Help ");
6430 ps_printf(psdoc, "/Title (%s) /Contents (%s) /ANN pdfmark\n", title, contents);
6431 }
6432 /* }}} */
6433
6434 /* PS_hyphenate() {{{
6435 * hyphenate a word
6436 */
6437 PSLIB_API int PSLIB_CALL
6438 PS_hyphenate(PSDoc *psdoc, const char *text, char **hyphens) {
6439 char *hyphentext;
6440 int hyphenminchars;
6441
6442 *hyphens[0] = '\0';
6443 if(!psdoc->hdict) {
6444 ps_error(psdoc, PS_Warning, _("No hyphenation table set."));
6445 return -1;
6446 } else {
6447 if(0 == (hyphenminchars = (int) PS_get_value(psdoc, "hyphenminchars", 0)))
6448 hyphenminchars = 3;
6449 }
6450
6451 hyphentext = ps_strdup(psdoc, text);
6452 if(NULL != hyphentext) {
6453 int k;
6454 k = 0;
6455 while(hyphentext[k] && !isalpha(hyphentext[k]))
6456 k++;
6457 if(strlen(hyphentext)-k > 2*hyphenminchars) {
6458 char *buffer;
6459 buffer = (char*) psdoc->malloc(psdoc, sizeof(char) * (strlen(hyphentext)+3), _("Could not allocate memory for hyphenation buffer."));
6460 hnj_hyphen_hyphenate(psdoc->hdict, &hyphentext[k], strlen(&hyphentext[k]), buffer);
6461 memset(*hyphens, '0', k);
6462 memcpy(*hyphens+k, buffer, strlen(hyphentext)+1);
6463 psdoc->free(psdoc, buffer);
6464 } else {
6465 return -1;
6466 }
6467 psdoc->free(psdoc, hyphentext);
6468 return 0;
6469 } else {
6470 return -1;
6471 }
6472 }
6473 /* }}} */
6474
6475 /* Extra functions */
6476
6477 /* PS_symbol() {{{
6478 * Output symbol without taking input encoding into account
6479 */
6480 PSLIB_API void PSLIB_CALL
6481 PS_symbol(PSDoc *psdoc, unsigned char c) {
6482 char text[2];
6483 ENCODING *fontenc;
6484 ADOBEINFO *ai;
6485
6486 if(NULL == psdoc) {
6487 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6488 return;
6489 }
6490 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE)) {
6491 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page' scope."), __FUNCTION__);
6492 return;
6493 }
6494 fontenc = ps_build_enc_vector(psdoc, psdoc->font->metrics->fontenc);
6495 if(NULL == fontenc) {
6496 ps_error(psdoc, PS_RuntimeError, _("Could not build font encoding vector."));
6497 return;
6498 }
6499 ai = gfindadobe(psdoc->font->metrics->gadobechars, fontenc->vec[c]);
6500 if(ai) {
6501 text[0] = c;
6502 text[1] = '\0';
6503 ps_printf(psdoc, "%.2f %.2f a\n", psdoc->tstates[psdoc->tstate].tx, psdoc->tstates[psdoc->tstate].ty);
6504 ps_render_text(psdoc, text);
6505 psdoc->tstates[psdoc->tstate].tx += ai->width*psdoc->font->size/1000.0;
6506 }
6507 ps_free_enc_vector(psdoc, fontenc);
6508
6509 }
6510 /* }}} */
6511
6512 /* PS_glyph_show() {{{
6513 * Output symbol by its name
6514 */
6515 PSLIB_API void PSLIB_CALL
6516 PS_glyph_show(PSDoc *psdoc, const char *name) {
6517 ADOBEINFO *ai;
6518
6519 if(NULL == psdoc) {
6520 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6521 return;
6522 }
6523 if(!ps_check_scope(psdoc, PS_SCOPE_PAGE)) {
6524 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'page' scope."), __FUNCTION__);
6525 return;
6526 }
6527 ai = gfindadobe(psdoc->font->metrics->gadobechars, name);
6528 if(ai) {
6529 ps_printf(psdoc, "%.2f %.2f a\n", psdoc->tstates[psdoc->tstate].tx, psdoc->tstates[psdoc->tstate].ty);
6530 ps_printf(psdoc, "/%s glyphshow\n", name);
6531 psdoc->tstates[psdoc->tstate].tx += ai->width*psdoc->font->size/1000.0;
6532 } else {
6533 ps_error(psdoc, PS_RuntimeError, _("glyph '%s' is not available in current font."), __FUNCTION__);
6534 }
6535 }
6536 /* }}} */
6537
6538 /* PS_glyph_width() {{{
6539 * Return width of a glyph
6540 */
6541 PSLIB_API float PSLIB_CALL
6542 PS_glyph_width(PSDoc *psdoc, const char *glyphname, int fontid, float size) {
6543 ADOBEINFO *ai;
6544 PSFont *psfont;
6545
6546 if(NULL == psdoc) {
6547 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6548 return(0.0);
6549 }
6550
6551 if(0 == fontid)
6552 psfont = psdoc->font;
6553 else {
6554 if(NULL == (psfont = _ps_get_font(psdoc, fontid)))
6555 return(0.0);
6556 }
6557
6558 if(NULL == psfont) {
6559 ps_error(psdoc, PS_RuntimeError, _("No font available."));
6560 return(0.0);
6561 }
6562
6563 if(NULL == psfont->metrics) {
6564 ps_error(psdoc, PS_RuntimeError, _("No font metrics available. Cannot calculate width of string."));
6565 return(0.0);
6566 }
6567
6568 if(0.0 == size)
6569 size = psfont->size;
6570
6571 // fprintf(stderr, "search for %s\n", glyphname);
6572 ai = gfindadobe(psfont->metrics->gadobechars, glyphname);
6573 if(ai) {
6574 // fprintf(stderr, "width = %d, size = %f\n", ai->width, size);
6575 return(ai->width*size/1000.0);
6576 } else {
6577 return(0.0);
6578 }
6579 }
6580 /* }}} */
6581
6582 /* PS_glyph_list() {{{
6583 * Returns list of all glyph names in the font. The list of glyphs must
6584 * be freed with PS_free_glyph_list().
6585 */
6586 PSLIB_API char** PSLIB_CALL
6587 PS_glyph_list(PSDoc *psdoc, int fontid, char ***charlist, int *len) {
6588 ght_iterator_t iterator;
6589 char *p_key;
6590 ADOBEINFO *p_e;
6591 PSFont *psfont;
6592 int i;
6593 char **tmp;
6594
6595 if(NULL == psdoc) {
6596 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6597 return NULL;
6598 }
6599
6600 if(0 == fontid)
6601 psfont = psdoc->font;
6602 else {
6603 if(NULL == (psfont = _ps_get_font(psdoc, fontid)))
6604 return NULL;
6605 }
6606
6607 if(NULL == psfont) {
6608 ps_error(psdoc, PS_RuntimeError, _("No font available."));
6609 return NULL;
6610 }
6611
6612 if(psfont->metrics->gadobechars) {
6613 *len = ght_size(psfont->metrics->gadobechars);
6614 if(NULL == (tmp = psdoc->malloc(psdoc, *len * sizeof(char **), _("Allocate memory for list of glyph names.")))) {
6615 ps_error(psdoc, PS_RuntimeError, _("Could not allocate memory for list of glyph names."));
6616 return NULL;
6617 }
6618 i = 0;
6619 for(p_e = ght_first(psfont->metrics->gadobechars, &iterator, (void **) &p_key); p_e; p_e = ght_next(psfont->metrics->gadobechars, &iterator, (void **) &p_key)) {
6620 tmp[i++] = ps_strdup(psdoc, p_e->adobename);
6621 }
6622 *charlist = tmp;
6623 return tmp;
6624 } else {
6625 ps_error(psdoc, PS_RuntimeError, _("Font does not have list of glyphs."));
6626 return NULL;
6627 }
6628 }
6629 /* }}} */
6630
6631 /* PS_free_glyph_list() {{{
6632 * Frees the memory allocated for a glyph list returned by PS_glyph_list().
6633 */
6634 PSLIB_API void PSLIB_CALL
6635 PS_free_glyph_list(PSDoc *psdoc, char **charlist, int len) {
6636 int i;
6637
6638 if(NULL == psdoc) {
6639 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6640 return;
6641 }
6642
6643 for(i=0; i<len; i++) {
6644 if(charlist[i])
6645 psdoc->free(psdoc, charlist[i]);
6646 }
6647 psdoc->free(psdoc, charlist);
6648 }
6649 /* }}} */
6650
6651 /* PS_symbol_width() {{{
6652 * Return width of a symbol without taking input encoding into account
6653 */
6654 PSLIB_API float PSLIB_CALL
6655 PS_symbol_width(PSDoc *psdoc, unsigned char c, int fontid, float size) {
6656 ENCODING *fontenc;
6657 ADOBEINFO *ai;
6658 PSFont *psfont;
6659
6660 if(NULL == psdoc) {
6661 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6662 return(0.0);
6663 }
6664
6665 if(0 == fontid)
6666 psfont = psdoc->font;
6667 else {
6668 if(NULL == (psfont = _ps_get_font(psdoc, fontid)))
6669 return(0.0);
6670 }
6671
6672 if(NULL == psfont) {
6673 ps_error(psdoc, PS_RuntimeError, _("No font available."));
6674 return(0.0);
6675 }
6676
6677 if(NULL == psfont->metrics) {
6678 ps_error(psdoc, PS_RuntimeError, _("No font metrics available. Cannot calculate width of string."));
6679 return(0.0);
6680 }
6681
6682 if(0.0 == size)
6683 size = psfont->size;
6684
6685 fontenc = ps_build_enc_vector(psdoc, psfont->metrics->fontenc);
6686 if(NULL == fontenc) {
6687 ps_error(psdoc, PS_RuntimeError, _("Could not build font encoding vector."));
6688 return(0.0);
6689 }
6690 ai = gfindadobe(psfont->metrics->gadobechars, fontenc->vec[c]);
6691 ps_free_enc_vector(psdoc, fontenc);
6692 if(ai) {
6693 return(ai->width*size/1000.0);
6694 } else {
6695 return(0.0);
6696 }
6697 }
6698 /* }}} */
6699
6700 /* PS_symbol_name() {{{
6701 * Returns name of symbol
6702 */
6703 PSLIB_API void PSLIB_CALL
6704 PS_symbol_name(PSDoc *psdoc, unsigned char c, int fontid, char *name, int size) {
6705 ENCODING *fontenc;
6706 PSFont *psfont;
6707
6708 if(NULL == psdoc) {
6709 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6710 return;
6711 }
6712
6713 if(0 == fontid)
6714 psfont = psdoc->font;
6715 else {
6716 if(NULL == (psfont = _ps_get_font(psdoc, fontid)))
6717 return;
6718 }
6719
6720 if(NULL == psfont) {
6721 ps_error(psdoc, PS_RuntimeError, _("No font available."));
6722 return;
6723 }
6724
6725 if(NULL == psfont->metrics) {
6726 ps_error(psdoc, PS_RuntimeError, _("No font metrics available. Cannot lookup symbol name."));
6727 return;
6728 }
6729
6730 fontenc = ps_build_enc_vector(psdoc, psfont->metrics->fontenc);
6731 if(fontenc) {
6732 if(fontenc->vec[c]) {
6733 strncpy(name, fontenc->vec[c], size);
6734 } else {
6735 name[0] = '\0';
6736 }
6737 ps_free_enc_vector(psdoc, fontenc);
6738 } else {
6739 name[0] = '\0';
6740 }
6741 return;
6742
6743 }
6744 /* }}} */
6745
6746 /* PS_include_file() {{{
6747 * Includes a file into the output file
6748 */
6749 PSLIB_API int PSLIB_CALL
6750 PS_include_file(PSDoc *psdoc, const char *filename) {
6751 unsigned char *bb;
6752 FILE *fp;
6753 long fsize;
6754
6755 if(NULL == psdoc) {
6756 ps_error(psdoc, PS_RuntimeError, _("PSDoc is null."));
6757 return -1;
6758 }
6759 /* If the header is not written, because we are before
6760 * the first page, then output the header first.
6761 */
6762 if(psdoc->beginprologwritten == ps_false) {
6763 ps_write_ps_comments(psdoc);
6764 ps_write_ps_beginprolog(psdoc);
6765 }
6766 if(!ps_check_scope(psdoc, PS_SCOPE_PROLOG)) {
6767 ps_error(psdoc, PS_RuntimeError, _("%s must be called within 'prolog' scope."), __FUNCTION__);
6768 return -1;
6769 }
6770
6771 if(NULL == filename || filename[0] == '\0') {
6772 ps_error(psdoc, PS_IOError, _("Cannot include file without a name."));
6773 return -1;
6774 }
6775
6776 if(NULL == (fp = ps_open_file_in_path(psdoc, filename))) {
6777 ps_error(psdoc, PS_IOError, _("Could not open include file '%s'."), filename);
6778 return -1;
6779 }
6780
6781 fseek(fp, 0, SEEK_END);
6782 fsize = ftell(fp);
6783 if(fsize <= 0) {
6784 ps_error(psdoc, PS_Warning, _("Include file '%s' is empty"), filename);
6785 fclose(fp);
6786 return 0;
6787 }
6788 fseek(fp, 0, SEEK_SET);
6789 if(NULL != (bb = malloc(fsize))) {
6790 fread(bb, fsize, 1, fp);
6791 ps_printf(psdoc, "PslibDict begin\n");
6792 ps_write(psdoc, bb, fsize);
6793 ps_printf(psdoc, "end\n");
6794 free(bb);
6795 } else {
6796 ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for include file '%s'"), filename);
6797 return -1;
6798 }
6799 fclose(fp);
6800 return 0;
6801 }
6802 /* }}} */
6803
6804 /*
6805 * Local variables:
6806 * tab-width: 4
6807 * c-basic-offset: 4
6808 * End:
6809 * vim600: sw=2 ts=2 fdm=marker
6810 * vim<600: sw=2 ts=2
6811 */
6812