1 /*
2 * Raster3D V3.0
3 * local.c
4 *
5 * Output from render.f is performed by calls to routine LOCAL.
6 *
7 * This version of local.c supports 6 output modes, 5 of which
8 * are controlled by conditional compilation directives.
9 *
10 * mode 0 AVS image file sent to stdout
11 * (2 integer header followed by AlphaRGB bytes)
12 * Alpha byte is set to 255 if no explicit alpha
13 * values are passed from the caller
14 *
15 * mode 1 original, long-obsolete, private format
16 *
17 * mode 2 #ifdef LIBIMAGE_SUPPORT
18 * calls to the libimage library if LIBIMAGE_SUPPORT is defined
19 * (probably only makes sense on an SGI machine)
20 *
21 * mode 3 #ifdef TIFF_SUPPORT
22 * calls to the TIFF library if TIFF_SUPPORT is defined
23 *
24 * mode 4 #ifdef GD_SUPPORT
25 * JPEG image output to file (defaults to stdout)
26 *
27 * mode 5 #ifdef GD_SUPPORT
28 * libgd PNG image output to file (defaults to stdout)
29 *
30 * Command line switches other than output file format handled elsewhere
31 * here we recognize
32 * -invert invert y coordinate axis
33 * -jpeg [filename] for jpeg output
34 * -png [filename] for png output
35 * -avs [filename] for AVS output
36 * -sgi [filename] SGI libimage format output
37 * -tiff [filename] TIFF output format
38 */
39
40 #include <stdio.h>
41 #include <fcntl.h>
42 #include <string.h>
43 #include <ctype.h>
44 #include <time.h>
45 #include <stdlib.h>
46 #ifdef NETWORKBYTEORDER
47 #include <netinet/in.h>
48 #endif
49
50 #ifdef LIBIMAGE_SUPPORT
51 #include <gl/image.h>
52 #endif
53
54 #ifdef TIFF_SUPPORT
55 #include <tiff.h>
56 #include <tiffio.h>
57 #if defined(LINUX) || defined(OSX)
58 #include <signal.h>
59 #endif
60 #endif /* TIFF_SUPPORT */
61
62 #if defined GD_SUPPORT
63 #include "gd.h"
64 #endif
65
66 /* Pick up version number from same include file used by Makefile */
67 char *
68 #include "VERSION"
69 ;
70
71 /* Define bits in returned status */
72 #define ANTIALIAS 007
73 #define INVERT 010
74 #define DEBUGGING 020
75
76 /* Define bits passed in 3rd parameter of mode 1 */
77 #define ALPHACHANNEL 040
78
79 int alpha_channel = 0;
80
81 /* Loaded by mode 5; used to initialize image file by mode 1 */
82 static int bkg_r = 0, bkg_g = 0, bkg_b = 0;
83
84 /* Define bits to be pass to both the local_() and addlabel_() functions */
85 static int xsize = 0, ysize = 0;
86 static int mode = -1; /* this is needed by goth local_() and addlabel_() */
87 #if defined GD_SUPPORT
88 /* For -png OR -jpeg (using libgd) output option only */
89 static gdImagePtr molecule_img = NULL;
90 static gdImagePtr label_img = NULL;
91 #endif
92
93 /* HPUX lacks Fortran intrinsic functions AND and OR for some reason, */
94 /* so I put a copy here. On the other hand HPUX has an unusually sane */
95 /* calling convention for Fortran subroutine names. */
96 #if defined(__hpux)
97 #define local_ local
and(i,j)98 int and(i,j) int *i,*j; {return (*i & *j);}
or(i,j)99 int or(i,j) int *i,*j; {return (*i | *j);}
100 #endif
101
102 #if defined(gfortran)
and_(i,j)103 int and_(i,j) int *i,*j; {return (*i & *j);}
or_(i,j)104 int or_(i,j) int *i,*j; {return (*i | *j);}
105 #endif
106
107 size_t trimwhitespace(char *out, size_t len, const char *str);
108
local_(option,buffer1,buffer2,buffer3,buffer4)109 int local_(option,buffer1,buffer2,buffer3,buffer4)
110 int *option;
111 short *buffer1, *buffer2, *buffer3, *buffer4;
112 {
113
114 /* Everyone needs these */
115 int i;
116 static char *ofile;
117 int status = 0;
118 int invert = 0;
119 int bits;
120 static int quality = 90;
121
122 static time_t start_time, end_time;
123 static char program_name[20] = "Raster3D G";
124
125 /* For -original output mode only */
126 static int header[8] = { 3, 1, 1, 0, 0, 0, 0, 0 };
127 char *c = (void *)header;
128
129 #ifdef LIBIMAGE_SUPPORT
130 /* For -sgi output mode only */
131 static IMAGE *image;
132 static int row=0;
133 #endif
134
135 #ifdef TIFF_SUPPORT
136 /* For -tiff output option only */
137 static TIFF *tfile;
138 static unsigned char *scanline;
139 unsigned short rows_per_strip;
140 void my_write_tiff();
141 #endif
142
143
144 /****************************************************************/
145 /* The action taken by this subroutine is determined by the */
146 /* option parameter. The first call (option=0) determines the */
147 /* output mode. */
148 /* As of V2.2.1 multiple bits may be set in the value returned. */
149 /****************************************************************/
150 if (*option == 0)
151 {
152 strncpy( &program_name[9], VERSION, strlen(VERSION)+1 );
153
154 if (strncmp( (char *)buffer1, "-invert", 7) ==0)
155 {
156 invert = !invert;
157 buffer1 = buffer2; buffer2 = buffer3; buffer3 = buffer4;
158 }
159
160 if (strncmp( (char *)buffer1, "-tiff", 5) == 0)
161 {
162 #ifdef TIFF_SUPPORT
163 mode = 3;
164 ofile = (char *)buffer2;
165 #else
166 fprintf(stderr,
167 "\n This copy of render was not built with tiff support\n");
168 exit(-1);
169 #endif
170 #ifndef TIFF_INVERT
171 invert = !invert;
172 #endif
173 }
174
175 /* Version 2.7a - AVS used to be the default, but no longer */
176 else if (strncmp( (char *)buffer1, "-avs" , 4) == 0) {
177 mode = 0;
178 }
179
180 else if (strncmp( (char *)buffer1, "-sgi" , 4) == 0)
181 {
182 #ifdef LIBIMAGE_SUPPORT
183 mode = 2;
184 ofile = (char *)buffer2;
185 invert = !invert;
186 #else
187 fprintf(stderr,
188 "\n This copy of render was not built with sgi libimage support\n");
189 exit(-1);
190 #endif
191 }
192
193 else if (strncmp( (char *)buffer1, "-jpeg" , 5) == 0)
194 {
195 #ifdef GD_SUPPORT /* JPEG */
196 mode = 4;
197 ofile = (char *)buffer2;
198 #else
199 fprintf(stderr,
200 "\n This copy of render was not built with libgd jpeg support\n");
201 exit(-1);
202 #endif
203 }
204
205 else if (strncmp( (char *)buffer1, "-png" , 4) == 0)
206 {
207 #ifdef GD_SUPPORT /* PNG */
208 mode = 5;
209 ofile = (char *)buffer2;
210 #else
211 fprintf(stderr,
212 "\n This copy of render was not built with libgd png support\n");
213 exit(-1);
214 #endif
215 }
216
217 /* This option is long since deprecated */
218 else if (strncmp( (char *)buffer1, "-orig", 5) == 0)
219 {
220 mode = 1;
221 invert = !invert;
222 }
223 else if (strncmp( (char *)buffer1, " ", 2) != 0)
224 {
225 fprintf(stderr, "\n%s",program_name);
226 if (strncmp( (char *)buffer1, "-help", 5) != 0)
227 fprintf(stderr, "\n Unfamiliar switch: %12.12s", (char *)buffer1);
228 fprintf(stderr, "\n\n Usage:");
229 fprintf(stderr, "\n input from stdin; output mode controlled from command line \n");
230 fprintf(stderr,
231 "\n render [-png [outfile]] PNG image to stdout (default) or file");
232 fprintf(stderr,
233 "\n render -jpeg [outfile] JPEG image to stdout (default) or file");
234 fprintf(stderr,
235 "\n render -avs AVS image to stdout");
236 #ifdef LIBIMAGE_SUPPORT
237 fprintf(stderr,
238 "\n render -sgi [outfile] output to SGI libimage file (defaults to render.rgb)");
239 #endif
240 #ifdef TIFF_SUPPORT
241 fprintf(stderr,
242 "\n render -tiff [outfile] output to TIFF file (defaults to render.tif)");
243 #endif
244 fprintf(stderr,"\n");
245 fprintf(stderr,"\n Options:");
246 fprintf(stderr,"\n these over-ride contents of input stream header records \n");
247 fprintf(stderr,"\n -aa anti-aliasing (SCHEME 4)");
248 fprintf(stderr,"\n -alpha alpha channel in output image (SCHEME 0)");
249 fprintf(stderr,"\n -bg white|black|<col> set background color (<col> is hex #RRGGBB)");
250 fprintf(stderr,"\n -debug verbose output while running");
251 fprintf(stderr,"\n -draft no anti-aliasing (SCHEME 1)");
252 fprintf(stderr,"\n -fontscale FF multiplier for libgd font size [default 1.0]");
253 fprintf(stderr,"\n -gamma GG gamma correction applied to output image");
254 fprintf(stderr,"\n -invert invert y axis");
255 fprintf(stderr,"\n -labels pass labels to libgd to composite with molecular image");
256 fprintf(stderr,"\n -quality QQ 0 < QQ < 95 jpeg compression [default 90]");
257 fprintf(stderr,"\n -[no]shadow enable or disable shadowing");
258 fprintf(stderr,"\n -size HHHxVVV specify size of output image in pixels");
259 fprintf(stderr,"\n -transparent same as -alpha (SCHEME 0)");
260 fprintf(stderr,"\n -zoom ZZ[%%] rescale image by ZZ ");
261 fprintf(stderr,"\n");
262 exit(-1);
263 }
264
265 else /* default to png */
266 {
267 #ifdef GD_SUPPORT /* PNG */
268 mode = 5;
269 ofile = (char *)buffer2;
270 #else
271 fprintf(stderr,
272 "\n This copy of render was not built with libgd png support\n");
273 fprintf(stderr,
274 "Defaulting to AVS instead\n");
275 mode = 0;
276 #endif
277 }
278
279
280 if (invert) status |= INVERT;
281
282 return( status );
283 }
284
285 /****************************************************************/
286 /* Subsequent calls are treated differently depending on mode */
287 /****************************************************************/
288 if (mode < 0)
289 {
290 fprintf(stderr,"\n Output mode not set before output request\n");
291 exit(-1);
292 }
293
294 /****************************************************************/
295 /* Open output file and initialize image descriptor information */
296 /****************************************************************/
297 else if (*option == 1)
298 {
299 xsize = *(int *)buffer1;
300 ysize = *(int *)buffer2;
301 bits = *(int *)buffer3;
302 quality = *(int *)buffer4;
303
304 if (bits & ALPHACHANNEL) alpha_channel = 1;
305
306 if (mode == 0) /* avs */
307 {
308 #ifdef NETWORKBYTEORDER
309 putw( htonl(xsize), stdout );
310 putw( htonl(ysize), stdout );
311 #else
312 putw( xsize, stdout );
313 putw( ysize, stdout );
314 #endif
315 }
316
317 if (mode == 1) /* original */
318 {
319 header[3] = xsize;
320 header[4] = ysize;
321 for (i=0; i<sizeof(header); i++)
322 putchar(*c++);
323 }
324 else
325
326 #ifdef LIBIMAGE_SUPPORT
327 if (mode == 2) /* sgi rgb mode */
328 {
329 if (*ofile != ' ')
330 ofile = strtok( ofile, " " );
331 else
332 ofile = "render.rgb";
333 image = iopen(ofile,"w",RLE(1),3,xsize,ysize,alpha_channel?4:3);
334 }
335 else
336 #endif
337
338 #ifdef TIFF_SUPPORT
339 #define TIFFSET(A,B,C) if (!(TIFFSetField(A,B,C))) fprintf(stderr,"TIFF library error\n");
340 if (mode == 3) /* tiff */
341 {
342 if (*ofile != ' ')
343 ofile = strtok( ofile, " " );
344 else
345 ofile = "render.tiff";
346 tfile=TIFFOpen(ofile,"w");
347 if (!tfile) exit(-1);
348 TIFFSET(tfile,TIFFTAG_DOCUMENTNAME,ofile);
349 TIFFSET(tfile,TIFFTAG_SOFTWARE,program_name);
350 TIFFSET(tfile,TIFFTAG_BITSPERSAMPLE,8);
351 TIFFSET(tfile,TIFFTAG_SAMPLESPERPIXEL,(alpha_channel ? 4 : 3));
352 TIFFSET(tfile,TIFFTAG_PHOTOMETRIC,PHOTOMETRIC_RGB);
353 TIFFSET(tfile,TIFFTAG_IMAGEWIDTH,xsize);
354 TIFFSET(tfile,TIFFTAG_IMAGELENGTH,ysize);
355 TIFFSET(tfile,TIFFTAG_RESOLUTIONUNIT,2);
356 TIFFSET(tfile,TIFFTAG_XRESOLUTION,300.);
357 TIFFSET(tfile,TIFFTAG_YRESOLUTION,300.);
358 #ifdef __alpha
359 TIFFSET(tfile,TIFFTAG_FILLORDER,FILLORDER_MSB2LSB);
360 #endif
361 #ifdef TIFF_INVERT
362 TIFFSET(tfile,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT);
363 #else
364 TIFFSET(tfile,TIFFTAG_ORIENTATION,ORIENTATION_BOTLEFT);
365 #endif
366 TIFFSET(tfile,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
367 TIFFSET(tfile,TIFFTAG_COMPRESSION,COMPRESSION_LZW);
368 rows_per_strip = ysize;
369 TIFFSET(tfile,TIFFTAG_ROWSPERSTRIP,rows_per_strip);
370 if (alpha_channel)
371 {
372 uint16 extra_samples, sample_info[1];
373 extra_samples=1;
374 sample_info[0]=EXTRASAMPLE_ASSOCALPHA;
375 TIFFSetField(tfile,TIFFTAG_EXTRASAMPLES,extra_samples,&sample_info[0]);
376 }
377 scanline=(unsigned char *) malloc(TIFFScanlineSize(tfile));
378 if (scanline == (unsigned char *) NULL)
379 {
380 fprintf(stderr,"\nMemory allocation error\n");
381 return(-1);
382 }
383 }
384 else
385 #endif
386
387 #ifdef GD_SUPPORT /* JPEG + PNG */
388 if (mode == 4 || mode == 5) {
389 int transparent;
390 molecule_img = gdImageCreateTrueColor(xsize, ysize);
391 label_img = gdImageCreateTrueColor(xsize, ysize);
392 gdImageAlphaBlending(label_img, 0);
393 /*
394 if (!molecule_img)
395 {
396 fprintf(stderr,"PNG initialization failed - die\n");
397 exit(-1);
398 }
399 */
400
401 /* Signal that all freetype font calls in this program will receive
402 * fontconfig patterns rather than filenames of font files */
403 gdFTUseFontConfig(1);
404
405 transparent = gdImageColorResolve(label_img, bkg_r, bkg_g, bkg_b);
406 gdImageColorTransparent(label_img, transparent);
407 gdImageFilledRectangle(label_img,0,0,xsize,ysize,transparent);
408
409 ofile = strtok( ofile, " " );
410 }
411 else
412 #endif
413
414 /* NOP */ ;
415 start_time = time(NULL);
416 return(1);
417 }
418
419 /****************************************************************/
420 /* Write out a single row of output pixels */
421 /****************************************************************/
422 else if (*option == 2)
423 {
424
425 if (mode == 0) /* AVS image file (AlphaRGB) bytes */
426 {
427 if (alpha_channel)
428 for (i=0; i<xsize; i++)
429 {
430 putchar( buffer4[i] );
431 putchar( buffer1[i] );
432 putchar( buffer2[i] );
433 putchar( buffer3[i] );
434 }
435 else
436 for (i=0; i<xsize; i++)
437 {
438 putchar( 255 );
439 putchar( buffer1[i] );
440 putchar( buffer2[i] );
441 putchar( buffer3[i] );
442 }
443 }
444 else
445
446 if (mode == 1) /* original RGB bytes */
447 {
448 for (i=0; i<xsize; i++)
449 {
450 putchar( buffer1[i] );
451 putchar( buffer2[i] );
452 putchar( buffer3[i] );
453 }
454 }
455 else
456
457 #ifdef LIBIMAGE_SUPPORT
458 if (mode == 2) /* -sgi option (libimage format) */
459 {
460 putrow(image,buffer1,row,0);
461 putrow(image,buffer2,row,1);
462 putrow(image,buffer3,row,2);
463 if (alpha_channel)
464 putrow(image,buffer4,row,3);
465 row++;
466 }
467 else
468 #endif
469
470 #ifdef TIFF_SUPPORT
471 if (mode == 3)
472 {
473 my_write_tiff(tfile,buffer1,buffer2,buffer3,buffer4,xsize,scanline);
474 }
475 else
476 #endif
477
478 #ifdef GD_SUPPORT /* JPEG + PNG */
479 if (mode == 4 || mode == 5)
480 {
481 /* TODO: Speed up using full-line-at-a-time copy instead of pixel-by-pixel */
482 int pixel_color;
483 static int j = 0;
484 int transparent;
485
486 if (alpha_channel)
487 #if 1
488 for (i=0; i<xsize; i++) {
489 pixel_color = gdImageColorResolveAlpha(molecule_img,
490 buffer1[i], buffer2[i], buffer3[i],
491 (255-buffer4[i])>>1); /* inverse bitwise shift */
492 gdImageSetPixel(molecule_img, i, j, pixel_color);
493 }
494
495 /* TODO: Check the following to see if it is faster than the above. */
496 #else
497 for (i=0; i<xsize; i++) {
498 molecule_img->tpixels[j][i] = gdTrueColorAlpha(
499 buffer1[i], buffer2[i], buffer3[i],
500 (255-buffer4[i])>>1);
501 }
502 #endif
503 else
504 for (i=0; i<xsize; i++) {
505 pixel_color = gdImageColorResolve(molecule_img,
506 buffer1[i], buffer2[i], buffer3[i]);
507 gdImageSetPixel(molecule_img, i, j, pixel_color);
508 }
509
510 if (alpha_channel) {
511 transparent = gdImageColorResolveAlpha(molecule_img, 0, 0, 0, 127);
512 gdImageColorTransparent(molecule_img, transparent);
513 }
514
515 j++;
516 }
517 else
518 #endif
519
520 if (mode >= 7)
521 {
522 fprintf(stderr,"\n local.c: illegal output mode\n");
523 exit(-1);
524 }
525
526 return(1);
527 }
528
529 /****************************************************************/
530 /* Close output file if necessary */
531 /****************************************************************/
532 else if (*option == 3)
533 {
534
535 #ifdef LIBIMAGE_SUPPORT
536 if (mode == 2)
537 iclose(image);
538 else
539 #endif
540
541 #ifdef TIFF_SUPPORT
542 if (mode == 3)
543 {
544 (void) TIFFFlushData(tfile);
545 #if defined(LINUX) || defined(OSX)
546 signal( SIGSEGV, SIG_IGN );
547 #endif /* LINUX */
548 (void) TIFFClose(tfile);
549 }
550 else
551 #endif
552
553 #ifdef GD_SUPPORT /* JPEG + PNG */
554 if (mode == 4 || mode == 5) {
555
556 if (label_img) {
557 /*
558 gdImageAlphaBlending(molecule_img, 0);
559 gdImageSaveAlpha(molecule_img, 1);
560 */
561 gdImageSetTile(molecule_img, label_img);
562 gdImageFilledRectangle(molecule_img, 0, 0, xsize, ysize, gdTiled);
563 }
564
565 /*if (*ofile != ' ' && *ofile != '-')*/
566 if (ofile) {
567 FILE *fd = fopen(ofile,"wb");
568 if (!fd) {
569 fprintf(stderr,"Could not open output file %s\n",ofile);
570 exit(-1);
571 }
572 if (mode == 4)
573 gdImageJpeg(molecule_img, fd, quality);
574 else
575 gdImagePng(molecule_img, fd);
576 fclose(fd);
577
578 if (label_img) {
579 gdImageDestroy(label_img);
580 }
581 }
582 else
583 if (mode == 4)
584 gdImageJpeg(molecule_img, stdout, quality);
585 else
586 gdImagePng(molecule_img, stdout);
587 gdImageDestroy(molecule_img);
588 }
589 else
590 #endif
591
592 /* NOP */ ;
593 end_time = time(NULL);
594 fprintf(stderr,"rendering time - %5d sec\n",(int)(end_time-start_time));
595
596 return(1);
597 }
598
599 /****************************************************************/
600 /* Add title to image file */
601 /****************************************************************/
602 else if (*option == 4)
603 {
604
605 #ifdef LIBIMAGE_SUPPORT
606 if (mode == 2)
607 isetname(image,buffer1);
608 else
609 #endif
610
611 #ifdef TIFF_SUPPORT
612 if (mode == 3)
613 TIFFSetField(tfile,TIFFTAG_IMAGEDESCRIPTION,buffer1);
614 else
615 #endif
616
617 /* NOP */ ;
618 return(1);
619 }
620
621 /****************************************************************/
622 /* Load background color to local storage */
623 /****************************************************************/
624 else if (*option == 5)
625 {
626
627 bkg_r = *buffer1;
628 bkg_g = *buffer2;
629 bkg_b = *buffer3;
630 /*
631 fprintf(stderr,"Loading background color %d %d %d\n", bkg_r, bkg_g, bkg_b);
632 */
633 return(1);
634 }
635
636 return 0;
637 }
638
639 #ifdef TIFF_SUPPORT
my_write_tiff(fp,buf1,buf2,buf3,buf4,size,scanline)640 void my_write_tiff(fp, buf1, buf2, buf3, buf4, size, scanline)
641 TIFF *fp;
642 short buf1[], buf2[], buf3[], buf4[];
643 int size;
644 unsigned char scanline[];
645 {
646 static int row=0;
647 int i;
648 int j = 0;
649
650 if (alpha_channel)
651 for (i=0; i<size; i++) {
652 scanline[j++] = buf1[i];
653 scanline[j++] = buf2[i];
654 scanline[j++] = buf3[i];
655 scanline[j++] = buf4[i];
656 }
657 else
658 for (i=0; i<size; i++) {
659 scanline[j++] = buf1[i];
660 scanline[j++] = buf2[i];
661 scanline[j++] = buf3[i];
662 }
663
664 if (TIFFWriteScanline(fp,scanline,row,0) < 0)
665 fprintf (stderr, "\nBad return code from TIFF write\n");
666
667 row++;
668 }
669 #endif
670
671 /*===========================================================================*/
672 /*
673 * _addlabel()
674 */
addlabel_(fontname,fontsize,fontscale,fontalign,xp,yp,zp,red,grn,blu,labelstring,font_len,label_len)675 int addlabel_(fontname, fontsize, fontscale, fontalign, xp, yp, zp, red, grn, blu,
676 labelstring, font_len, label_len)
677 int *fontalign;
678 float *fontsize, *fontscale, *xp, *yp, *zp, *red, *grn, *blu;
679 char *fontname, *labelstring;
680 long int font_len, label_len;
681 {
682 #ifdef GD_SUPPORT
683 static double last_x = 0.0, last_y = 0.0, last_z = 0.0;
684
685 double x = *xp, y = *yp, z = *zp;
686 float angle = 0.0;
687 int brect[8], font_color;
688 char *err, font[128], instring[128], *justify;
689 size_t out_size; /* out_size is just a dummy variable */
690 char *string;
691
692 if (mode != 4 && mode != 5)
693 return 0;
694
695 /* TODO: If FONTNAME does not exist in the GDFONTPATH, fail gracefully */
696 out_size = trimwhitespace(font, 128, fontname);
697 out_size = trimwhitespace(instring, 128, labelstring);
698 string = instring;
699
700 (void)out_size; /* prevents compiler complaints */
701 (void)last_z; /* about unused variables */
702 (void)justify;
703
704 /* Allocate colours */
705 /* FIXME: how to pass non-zero alpha value? */
706 font_color = gdImageColorAllocateAlpha(label_img,
707 (double)*red*255.0, (double)*grn*255.0, (double)*blu*255.0, 0);
708
709 /* Draw once with a NULL image to get the bounding rectangle */
710 err = gdImageStringFT(NULL, &brect[0], font_color,
711 font, (double)*fontsize*(double)*fontscale, angle, 0, 0, string);
712 if (err)
713 fprintf(stderr,"gdImageStringFT: %s while printing string %s with font %s\n",
714 err, string, font);
715
716 /* Align the string */
717 if ((int)*fontalign == 1) {
718 /* Justify string center */
719 justify = "Center";
720 x -= (brect[2]-brect[0]) / 2.;
721 y += (brect[3]-brect[1]) / 2.;
722 }
723 else if ((int)*fontalign == 2) {
724 /* Justify string right */
725 justify = "Right";
726 x -= (brect[2]-brect[0]);
727 y += (brect[3]-brect[1]);
728 }
729 else if ((int)*fontalign == 3) {
730 justify = "Offset";
731 x += last_x;
732 y += last_y;
733 }
734 else {
735 /* Do nothing (default) */
736 justify = "Left";
737 }
738
739 /* TODO: Process super/subscripts */
740 while (strpbrk(string, "{}^_")) {
741 char *mark = strpbrk(string, "{}^_");
742 char save_mark = *mark;
743
744 /* dump up to the first special character */
745 *mark = '\0';
746 err = gdImageStringFT(label_img, &brect[0], font_color,
747 font, (double)*fontsize*(double)*fontscale, angle, x, y, string);
748 x += (brect[2] - brect[0]);
749 string = mark+1;
750
751 /* start sub/superscript placement */
752 last_y = y;
753 if (save_mark == '^')
754 y -= 0.5 * (*fontsize) * (*fontscale);
755 else if (save_mark == '_')
756 y += 0.5 * (*fontsize) * (*fontscale);
757 /* dump either a single character (careful: UTF-8!) */
758 /* or the string enclosed by {} */
759 if (*string == '{') {
760 string++;
761 if ((mark = strchr(string,'}')) != NULL) {
762 *mark = '\0';
763 err = gdImageStringFT(label_img, &brect[0], font_color,
764 font, (double)*fontsize*(double)*fontscale, angle, x, y, string);
765 x += (brect[2] - brect[0]);
766 y = last_y;
767 string = mark+1;
768 } else {
769 /* No closing '}', just print the rest of the string */
770 }
771
772 } else {
773 /* FIXME: check if it's not really UTF-8 */
774 char utf8[6] = {0,0,0,0,0,0};
775 char *u = utf8;
776 *u = *string++;
777 if ((*u & 0xC0) == 0xC0) { /* Start of a UTF-8 sequence */
778 *++u = *string++;
779 if ((*string & 0xc0) == 0x80)
780 *++u = *string++;
781 if ((*string & 0xc0) == 0x80)
782 *++u = *string++;
783 if ((*string & 0xc0) == 0x80)
784 *++u = *string++;
785 }
786 err = gdImageStringFT(label_img, &brect[0], font_color,
787 font, (double)*fontsize*(double)*fontscale, angle, x, y, utf8);
788 x += (brect[2] - brect[0]);
789 y = last_y;
790 }
791
792 }
793
794 /* Now render the remaining string, if any */
795 err = gdImageStringFT(label_img, &brect[0], font_color,
796 font, (double)*fontsize*(double)*fontscale, angle, x, y, string);
797 if (err)
798 fprintf(stderr,"gdImageStringFT: %s while printing string %s with font %s\n",
799 err, string, font);
800
801 last_x = x + (brect[2] - brect[0]);
802 last_y = y;
803 last_z = z;
804
805 #endif
806 return 0;
807 }
808
trimwhitespace(char * out,size_t len,const char * str)809 size_t trimwhitespace(char *out, size_t len, const char *str)
810 {
811 /* A simple function to trim the whitespace from the right-side of
812 * a string.
813 */
814
815 const char *end;
816 size_t out_size;
817
818 /* Trim leading space */
819 /*while(isspace(*str)) str++;*/
820
821 /* Trim trailing space */
822 end = str + strlen(str) - 1;
823 while(end > str && isspace(*end)) end--;
824 end++;
825
826 /* Set output size to minimum of trimmed string length and buffer size
827 * minus 1 */
828 out_size = (end - str) < len-1 ? (end - str) : len-1;
829
830 /* Copy trimmed string and add null terminator */
831 memcpy(out, str, out_size);
832 out[out_size] = 0;
833
834 return out_size;
835 }
836