/*
 *
 *  This file is part of the XForms library package.
 *
 * XForms is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1, or
 * (at your option) any later version.
 *
 * XForms is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with XForms; see the file COPYING.  If not, write to
 * the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA.
 *
 */


/*
 * $Id: image_postscript.c,v 1.11 2008/05/09 12:32:59 jtt Exp $
 *
 *.
 *  This file is part of the XForms library package.
 *  Copyright (c) 1993, 1998-2002  By T.C. Zhao
 *  All rights reserved.
 *.
 *
 *  PostScript support.
 *
 * Do we want to integrate the stuff from ps_core.c, ps_draw.c and
 * postscript.c to consolidate ps support ?
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "include/forms.h"
#include "flinternal.h"
#include "flimage.h"
#include "flimage_int.h"
#include "private/flsnprintf.h"

#ifndef FLPS_H
#include "flps.h"
#endif

#include "private/pflps.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

typedef FLPSInfo SPEC;


/***************************************
 ***************************************/

FLPS_CONTROL *
flimage_ps_options( void )
{
    static SPEC *sp;

    if ( ! sp )
    {
		extern float fli_dpi;	/* I don't like this and will change it */

		sp = fl_calloc( 1, sizeof *sp );
		sp->orientation = FLPS_AUTO;
		sp->paper_w = 8.5;
		sp->paper_h = 11.0;
		sp->auto_fit = 1;
		sp->xdpi = sp->ydpi = fli_dpi;
		sp->printer_dpi = 300;
		sp->vm = sp->hm = 0.3;
		sp->xscale = sp->yscale = 1.0;
		sp->tmpdir = "/tmp";
		sp->gamma = 1.0;
		sp->verbose = 0;
		sp->comment = 0;
		sp->pack = 0;
		sp->lastr = -1;
		sp->ps_color = 1;
		/* cache */
		sp->cur_color = FLIMAGE_BADCOLOR;
		sp->cur_style = sp->cur_size = sp->cur_lw = -1;
    }

    return ( FLPS_CONTROL * ) sp;
}


/***************************************
 ***************************************/

static int
PS_identify( FILE * fp )
{
    char buf[ 2 ];

    fread( buf, 1, 2, fp );
    rewind( fp );
    return buf[ 0 ] == '%' && buf[ 1 ] == '!';
}


/***************************************
 * this is a fake to get past the driver
 ***************************************/

static int
PS_description( FL_IMAGE * im )
{
    im->extra_io_info = fl_malloc( sizeof( SPEC ) );
    memcpy( im->extra_io_info, flimage_ps_options( ), sizeof( SPEC ) );
    im->w = im->h = 1;
    im->type = FL_IMAGE_RGB;
    return 0;
}


#define GS_DEVICE   "ppmraw"
#define FL_FILE     "ppm"
#define GS_OPTION   "-q -DNOPAUSE"


/***************************************
 * load a specific page
 ***************************************/

static int
load_page( FL_IMAGE * im,
		   int        pageNo )
{
    char name[ 1024 ],
		 tmpf[ 1024 ];
    SPEC *sp = im->extra_io_info;
    FLIMAGE_IO *fileIO;
    int status, n;

    fl_snprintf( name, sizeof name, "%s/%s_%d",
				 sp->tmpdir, sp->prefix, pageNo );

    if ( sp->verbose )
		M_err( "LoadPage", "loading %s", name );

    if ( ! ( n = flimage_is_supported( name ) ) )
    {
		M_err( "LoadPage", "internal error. %s unknown", name );
		return -1;
    }

    fclose( im->fpin );
    im->fpin = fopen( name, "rb" );
    strcpy( tmpf, im->infile );
    strcpy( im->infile, name );

    im->completed = pageNo;
    im->visual_cue( im, "Loading PostScript" );

    /* re-direct the io handling */

    im->image_io = fileIO = &flimage_io[ n - 1 ];
    im->type = fileIO->type;

    fileIO->identify( im->fpin );

    if ( ( status = fileIO->read_description( im ) ) >= 0 )
		status = flimage_getmem( im );

    if ( status >= 0 )
		status = fileIO->read_pixels( im );

    strcpy( im->infile, tmpf );
    return status;
}


/***************************************
 * delete all temporary files
 ***************************************/

static void
PS_cleanup( FL_IMAGE * im )
{
    int i,
		n = im->total_frames >= 1 ? im->total_frames : 1;
    SPEC *sp = im->extra_io_info;
    char name[ 1024 ];

    if ( ! sp )
		return;

    for ( i = 1; i <= n; i++ )
    {
		fl_snprintf( name, sizeof name, "%s/%s_%d", sp->tmpdir, sp->prefix, i );
		if ( sp->verbose )
			M_err( "Cleanup", "deleting %s", name );
		remove( name );
    }

    fl_free( sp->prefix );
    fl_free( sp );
    im->extra_io_info = 0;
}


/***************************************
 ***************************************/

static const char *
file_tail( char *s )
{
    char *p = strrchr( s, '/' );
    return p ? ( p + 1 ) : s;
}


/***************************************
 ***************************************/

static int
PS_read_pixels( FL_IMAGE * im )
{
    char cmd[ 1024 ];
    int npages,
		status;
    SPEC *sp = im->extra_io_info;
    FL_Dirlist *dirlist;
    const FL_Dirlist *dls,
		             *dl;
    char prefix[ 1024 ];
    int old_sort;

    /* the tmp file pattern will be /tmp/gs_$InputFile_$pid_pageNO */

    fl_snprintf( prefix, sizeof prefix,
				 "gs_%s_%d", file_tail( im->infile ), ( int ) fli_getpid( ) );

    sp->prefix = strdup( prefix );

    if ( sp->verbose )
		M_err( "LoadPS", "prefix=%s", sp->prefix );

    fl_snprintf( cmd, sizeof cmd,
				 "gs -sDEVICE=%s %s -r%dx%d -sOutputFile=%s/%s_%%d -- %s %s",
				 GS_DEVICE, GS_OPTION, (int) sp->xdpi, ( int ) sp->ydpi,
				 sp->tmpdir, sp->prefix, im->infile,
				 sp->first_page_only ?
				 "/showpage { systemdict begin showpage quit end} def" : "" );

    if ( sp->verbose )
		M_err( "LoadPS", "executing %s\n", cmd );
    else
		strcat( cmd, " 2 > /dev/null" );

    im->completed = -1;		/* indicate infinite/unknown */
    im->visual_cue( im, "Converting PS ..." );

    if ( ( status = system( cmd ) ) )
    {
		M_err( "ReadPS", " status=%d", status );
		flimage_error( im, "ReadPS failed. Status=%d", status );

		/* return -1; */
    }

    im->completed = 1;
    im->visual_cue( im, "Loading PostScript" );

    /* we really do not need the current image stuff */

    flimage_freemem( im );

    /* find out how many pages we have. Turn off sorting, much faster */

    old_sort = fl_set_dirlist_sort( FL_NONE );
    dl = fl_get_dirlist( sp->tmpdir, strcat( prefix, "*" ), &npages, 1 );
    fl_set_dirlist_sort( old_sort );

    if ( ! ( dirlist = ( FL_Dirlist * ) dl ) )
    {
		PS_cleanup( im );
		return -1;
    }

    /* remove directories from the list */

    for ( dls = dl + npages; dl < dls; dl++ )
		if ( dl->type == FT_DIR )
			npages--;

    fl_free_dirlist( dirlist );

    if ( sp->verbose )
		M_err( "LoadPS", "Total %d pages", npages );

    if ( npages <= 0 )
    {
		PS_cleanup( im );
		flimage_error( im, "LoadPS: no page written!" );
		return -1;
    }

    im->total_frames = npages;

    if ( ! sp->first_page_only )
    {
		im->more = npages > 1;
		im->random_frame = load_page;
		im->cleanup = PS_cleanup;
    }

    im->total = im->total_frames;

    /* construct the filename and load it */

    status = load_page( im, 1 );

    /* need to cleanup the file if single page. For multipage, the driver
       will cleanup */

    if ( ! im->more || status < 0 )
		PS_cleanup( im );

    return status;
}

/***************************************************************************
 * Output routine
 **************************************************************************/

/***************************************
 ***************************************/

static void
PS_push( void )
{
    flps_output( "gsave\n" );
}


/***************************************
 ***************************************/

static void
PS_pop( void )
{
    flps_output( "grestore\n" );
}


/***************************************
 ***************************************/

static void
PS_trailer( SPEC *sp )
{
    PS_pop( );
    flps_output( 0 );
    fputs( "%%Trailer\n", sp->fp );
}


/***************************************
 ***************************************/

static int
auto_scale( float pagew,
			float pageh,
			float w,
			float h,
			int   landscape )
{
    float sx,
		  sy;
    int i = 0;

    if (    ( ! landscape && ( pagew < w || pageh < h ) )
		 || ( landscape && ( pagew < h || pageh < w ) ) )
    {
		if ( ! landscape )
		{
			sx = ( pagew - 2.0 ) / w;
			sy = ( pageh - 2.0 ) / h;
		}
		else
		{
			sx = ( pagew - 2.0 ) / h;
			sy = ( pageh - 2.0 ) / w;
		}
		
		i = 100.0 * FL_min( sx, sy );
    }

    return i;
}


/***************************************
 ***************************************/

static void
PS_start_image( FL_IMAGE * im  FL_UNUSED_ARG )
{
    PS_push( );
}


/***************************************
 ***************************************/

static void
PS_end_image( FL_IMAGE * im  FL_UNUSED_ARG )
{
    PS_pop( );
}


#define LEFT    '('
#define RIGHT   ')'

static void PS_annotation_init( FL_IMAGE * );
static void PS_annotation( FL_IMAGE * im );

/***************************************
 ***************************************/

static void
PS_write_header( FL_IMAGE * im )
{
    FILE *fp = im->fpout;
    SPEC *sp = im->extra_io_info;
    float pagew = sp->paper_w - 2.0 * sp->hm;
    float pageh = sp->paper_h - 2.0 * sp->vm;
    float hm = sp->hm,
		  vm = sp->vm;
    float s2px,
		  s2py;
    float xscale = sp->xscale,
		  yscale = sp->yscale;
    int xo,
		yo;
    int w = im->w,
		h = im->h;
    int orientation;
    int rescale;

    sp->fp = fp;

    /* check the size and orientation */

    pagew *= 72.0;
    pageh *= 72.0;
    hm *= 72.0;
    vm *= 72.0;

    sp->s2px = s2px = 72.0 / sp->xdpi;
    sp->s2py = s2py = 72.0 / sp->ydpi;
    w *= xscale * s2px;
    h *= yscale * s2py;

    if ( ( orientation = sp->orientation ) == FLPS_AUTO )
    {
		/* pick the orientation so even margin results */

		int plm,
			pbm,
			llm,
			lbm;

		plm = ( pagew - w ) / 2;
		pbm = ( pageh - h ) / 2;
		llm = ( pagew - h ) / 2;
		lbm = ( pageh - w ) / 2;
		orientation = ( FL_abs( lbm - llm ) < FL_abs( pbm - plm ) ) ?
			            FLPS_LANDSCAPE : FLPS_PORTRAIT;
    }

    sp->landscape = orientation == FLPS_LANDSCAPE;

    /* always make the image fit on the page */

    if (    ( rescale = auto_scale( pagew, pageh, w, h, sp->landscape ) )
		 && sp->auto_fit)
    {
		xscale *= rescale * 0.01;
		yscale *= rescale * 0.01;
		w *= rescale * 0.01;
		h *= rescale * 0.01;
    }

    /* update */

    sp->final_xscale = xscale;
    sp->final_yscale = yscale;

    /* get the origin of the system. For BoundingBox only. Actual PS output
       computes these on the fly */

    xo = hm + ( pagew - ( sp->landscape ? h : w ) ) * 0.5;
    yo = vm + ( pageh - ( sp->landscape ? w : h ) ) * 0.5;

    xo -= ( sp->landscape ? sp->miscb : sp->miscl ) * xscale * s2px;
    yo -= ( sp->landscape ? sp->miscl : sp->miscb ) * xscale * s2py;

    w += ( sp->miscr + sp->miscl ) * xscale * s2px;
    h += ( sp->misct + sp->miscb ) * yscale * s2py;

    /* write header */

    flps_emit_header( file_tail( im->infile ), im->total_frames,
					  xo - 1, yo - 1, xo + w + 1, yo + h + 1 );

    /* Prolog. Basic defines. */

    fputs( "/inch { 72 mul } def /D {def} def /BD {bind def} def\n", fp );
    fputs( "% Beginning of modifiable parameters\n", fp );
    fprintf( fp, "/pagew {%.2g inch} BD\t%% page width\n", sp->paper_w );
    fprintf( fp, "/pageh {%.2g inch} BD \t%% page height\n", sp->paper_h );
    fprintf( fp, "/lm {%.2g inch} BD \t%% Left margin\n", sp->hm );
    fprintf( fp, "/bm {%.2g inch} BD \t%% Bottom margin\n", sp->vm );
    fprintf( fp, "/xscale %g D /yscale %g D\t %% DPIScale %g SizeScale %g\n",
			 s2px * xscale, s2py * yscale,
			 (s2px + s2py) * 0.5, rescale * 0.01 );
    fputs( "% End of modifiable parameters\n", fp );

    fprintf( fp, "/pw { pagew lm 2 mul sub } BD \t%% writable width\n" );
    fprintf( fp, "/ph { pageh bm 2 mul sub } BD \t%% writable height\n" );

    /* instead of emitting numbers, the actual calculation is output so that
     * both scale and margin can be adjusted in PS */

    flps_output( "/xo pw xscale div %d sub 2 div def\n",
				 sp->landscape ? im->h : im->w );
    flps_output( "/yo ph yscale div %d sub 2 div def\n",
				 sp->landscape ? im->w : im->h );

    PS_annotation_init( im );

    flps_output( 0 );
    fputs( "%%EndProlog\n", fp );

    if ( sp->comment )
		fprintf( sp->fp, "%%OverallStateSave{\n" );

    PS_push( );

    /* honor the margin request */

    flps_output( "lm bm translate\n" );
}


static const char *hexdigits = "0123456789abcdef";

#define OutPixel( c )                                 \
          do {                                        \
               putc( hexdigits[ ( c ) >> 4 ], fp );   \
               putc( hexdigits[ ( c ) & 15 ], fp );   \
          } while ( 0 )


/***************************************
 * pixel data only
 ***************************************/

static int
PS_write_pixels( FL_IMAGE * im )
{
    FILE *fp = im->fpout;
    int ok = 1,
		j,
		k;

    im->total = im->h;
    im->completed = 0;

    if ( FL_IsRGB( im ) )
    {
		unsigned char *pc,
			          *ss;

		im->visual_cue( im, "Writing ColorPS" );
		for ( j = 0, k = 1; ok && j < im->h; j++, im->completed++ )
		{
			for ( pc = im->red[ j ], ss = pc + im->w; pc < ss; pc++, k++ )
			{
				OutPixel( *pc );
				if ( k % 37 == 0 )
					putc( '\n', fp );
			}
			for ( pc = im->green[ j ], ss = pc + im->w; pc < ss; pc++, k++ )
			{
				OutPixel( *pc );
				if ( k % 37 == 0 )
					putc( '\n', fp );
			}
			for ( pc = im->blue[ j ], ss = pc + im->w; pc < ss; pc++, k++ )
			{
				OutPixel( *pc );
				if ( k % 37 == 0 )
					putc( '\n', fp );
			}

			if ( ! ( im->completed & FLIMAGE_REPFREQ ) )
			{
				im->visual_cue( im, "Writing PS" );
				ok = ! ferror( fp );
			}
		}
    }
    else
    {
		unsigned short *pc,
			           *ss;
		unsigned char g;

		im->visual_cue( im, "Writing GrayPS" );
		for ( j = 0, k = 1; ok && j < im->h; j++, im->completed++ )
		{
			for ( pc = im->gray[ j ], ss = pc + im->w; pc < ss; pc++, k++ )
			{
				g = *pc & 0xff;
				OutPixel( g );
				if ( k % 37 == 0 )
					putc( '\n', fp );
			}
			if ( ! ( im->completed & FLIMAGE_REPFREQ ) )
			{
				im->visual_cue( im, "Writing PS" );
				ok = ! ferror( fp );
			}
		}
    }

    putc( '\n', fp );

    return ok ? 1 : -1;
}


/***************************************
 ***************************************/

static void
make_raster_command( FL_IMAGE * im,
					 char       pscmd[ ] )
{
    int rgb = FL_IsRGB( im );

    sprintf( pscmd, "StartRaster" );

    if ( ! rgb )
    {
		flps_output( "/graystring %d string def\n", im->w );
		flps_output( "/%s\n", pscmd );
		flps_output( "  {%d %d %d [ %d 0 0 -%d 0 %d]\n",
					 im->w, im->h, FL_PCBITS, im->w, im->h, im->h );
		flps_output( "  {currentfile graystring readhexstring pop}\n" );
		flps_output( "  imag`e\n} bind def\n" );
    }
    else
    {
		flps_output( "/redstring %d string def\n", im->w );
		flps_output( "/grnstring %d string def\n", im->w );
		flps_output( "/blustring %d string def\n", im->w );
		flps_output( "/%s\n", pscmd );
		flps_output( "  {%d %d %d [ %d 0 0 -%d 0 %d]\n",
					im->w, im->h, FL_PCBITS, im->w, im->h, im->h );
		flps_output( "  {currentfile redstring readhexstring pop}\n" );
		flps_output( "  {currentfile grnstring readhexstring pop}\n" );
		flps_output( "  {currentfile blustring readhexstring pop}\n" );
		flps_output( "  true 3 colorimage\n} bind def\n");
    }
}


/***************************************
 ***************************************/

static int
PS_write_image( FL_IMAGE * sim )
{
    SPEC *sp = sim->extra_io_info;
    char pscmd[ 512 ];
    FL_IMAGE *im = sim;
    int err,
		npage;

    if ( ! sp )
    {
		sp = sim->extra_io_info = fl_calloc( 1, sizeof *sp );
		memcpy( sp, flimage_ps_options( ), sizeof *sp );
    }

    sp->fp = sim->fpout;

    flps_switch_flps( sp );
    PS_write_header( sim );

    fprintf( sp->fp, sp->comment ? " %%StartOfMultiImage {\n" : "" );
    PS_push( );

    for ( err = 0, npage = 1, im = sim; !err && im; im = im->next, npage++ )
    {
		im->fpout = sim->fpout;
		flps_output( 0 );
		fprintf( im->fpout, "%%%%Page: %d %d\n", npage, sim->total_frames );

		/* the origin of the image (xo,yo) and annotation */

		flps_output( "xscale yscale scale xo yo translate\n" );

		if ( sp->landscape )
		{
			flps_output( "%d %d translate\n", sim->h, 0 );
			flps_output( " 90 rotate\n" );
		}

		PS_start_image( im );
		make_raster_command( im, pscmd );
		flps_output( "%d %d scale %s\n", im->w, im->h, pscmd );
		flps_output( 0 );
		err = PS_write_pixels( im ) < 0;
		PS_end_image( im );
		PS_annotation( im );
		flps_output( "showpage\n" );
    }

    if ( sp->comment )
		fprintf (sp->fp, " %%EndOfMultiImage}\n" );

    PS_pop( );

    PS_trailer( sp );
    fflush( sim->fpout );

    flps_reset_cache( );
    flps_restore_flps( );

    fl_free( sim->extra_io_info );
    sim->extra_io_info = 0;

    return err ? -1 : 1;
}


void
flimage_enable_ps( void )
{
    flimage_add_format( "PostScript", "ps", "ps",
						FL_IMAGE_RGB | FL_IMAGE_GRAY,
						PS_identify, PS_description,
						PS_read_pixels, PS_write_image );
}


/***************************************
 * Marker output
 *  M-moveto  LT-lineto L
 ***************************************/

#define MBUFLEN 10

static void
PS_annotation_init( FL_IMAGE * im )
{
    const char *mbuf[ MBUFLEN ];
    int i,
		j,
		k,
		out;
    FLIMAGE_MARKER *m;

    if ( ! im->nmarkers && !im->ntext )
		return;

    flps_output( "/M {moveto} BD /G {setgray} BD /RGB {setrgbcolor} BD\n" );
    flps_output( "/LT {lineto} BD /L {M LT} BD /S {stroke} BD /F {fill} BD\n" );
    flps_output( "/L {M LT} BD /S {stroke} BD /F {fill} BD\n" );
    flps_output( "/LW {setlinewidth} BD /C {closepath} BD\n" );

	memset( mbuf, 0, MBUFLEN );

    if ( im->nmarkers )
    {
		flps_output( "%%marker defs: t w h angle xo yo\n" );
		flps_output( 0 );
		flps_output( "/DTD {[5 4 1 4] 0 setdash} BD\n" );		/* dot-dash */
		flps_output( "/DT {[1 3] 0 setdash} BD\n" );	        /* dot   */
		flps_output( "/LD {[8 5] 0 setdash} BD\n" );	        /* long dash */
		flps_output( "/DS {[4 4] 0 setdash} BD\n" );	        /* dash */
		flps_output( "/SL {[] 0 setdash} BD\n" );		        /* solid */
		flps_output( "/NP {newpath} BD\n" );	                /* solid */

		flps_output( "/BM {gsave} D /EM {grestore} D\n" );
		flps_output( "/MK {newpath translate rotate scale LW} BD\n" );

		/* define primitives (-1 to +1) */

		for ( k = 0, m = im->marker, i = 0; i < im->nmarkers; i++, m++ )
		{
			for ( j = out = 0; ! out && j < MBUFLEN; j++ )
				out = m->name == mbuf[ j ];
			if ( ! out )
			{
				mbuf[ k++ ] = m->name;
				flps_output( "/%s {%s %s} D\n", m->name, "MK", m->psdraw );
			}
		}
    }

    if ( im->ntext )
    {
		/* do we want to scale the font ? */

		flps_output( "/point {xscale yscale add 2 div div} BD\n" );
		flps_output( "/SetFont {findfont exch scalefont setfont} BD\n" );
		flps_output( "/CP {currentpoint} BD /SW {stringwidth} BD\n" );
		flps_output( "/Lshow {show} BD\n" );
		flps_output( "/Cshow {dup SW pop -2 div 0 rmoveto show} BD\n" );
		flps_output( "/Rshow {dup SW pop neg 0 rmoveto show} BD\n" );
    }
}


/***************************************
 ***************************************/

#if 0
static void
switch_to_ISOLatin1( FILE * fp )
{
    /***** usage: newfontname oldfontname SwitchISO ******/

    flps_output( 0 );
    flps_output( "% Switch to ISOLatin1 to get special characters" );
    flps_output( 0 );
    flps_output( "/languagelevel where\n" );
    flps_output( "   {pop languagelevel} {1} ifelse\n" );
    flps_output( "   2 lt {/BitEncoding /StandardEncoding load def}\n" );
    flps_output( "        {/BitEncoding /ISOLatin1Encoding load def}\n" );
    flps_output( "   ifelse\n" );
    flps_output( "/SwitchToISO {\n" );
    flps_output( "   findfont dup length\n   dict begin {1 index /FID ne {def} "
				 "{pop pop} ifelse} forall\n" );
    flps_output( "   /Encoding BitEncoding def " );
    flps_output( " currentdict end\n   definefont pop\n} bind def\n" );
}
#endif


/***************************************
 ***************************************/

static void
PS_annotation( FL_IMAGE * im )
{
    FLIMAGE_MARKER *m = im->marker;
    FLIMAGE_TEXT *t = im->text;
    int r,
		g,
		b,
		i,
		thickness;
    SPEC *sp = im->extra_io_info;

    for ( i = 0; i < im->nmarkers; i++, m++ )
    {
		thickness = m->thickness + (m->thickness == 0);
		FL_UNPACK( m->color, r, g, b );
		flps_rgbcolor( r, g, b );
		flps_linestyle( m->style );
		flps_output( "BM %.3g %g %g %g %d %d %s",
					 2.0 * thickness / ( m->w + m->h ), 0.5 * m->w,
					 0.5 * m->h, m->angle * 0.1, m->x, im->h - m->y, m->name );
		flps_output( " %c EM\n", "SF"[ m->fill ] );
    }

    /* we make use of the ps_text.c */

    sp->isRGBColor = 1;
    for ( i = 0; i < im->ntext; i++, t++ )
    {
		sp->rotation = t->angle;
		flps_draw_text( t->align, t->x - 1, im->h - t->y - 1, 2, 2,
						t->color, t->style, t->size, t->str );
    }

    sp->rotation = 0;
    sp->isRGBColor = 0;
}
