/*
 *   PSFile.cc
 *   
 *   19/06/96
 *
 *   Modification le 01/03/96
 *    - fusion psfile.cc - psdict.cc
 *
 */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>

#include "psfile.h"

//++
// Class	PSFile
// Lib		PI
// include	psfile.h
//
//   	Classe encapsulant un fichier PostScript, fournissant des primitives
//	graphiques produisant du code PostScript.
//--
//++
// Links	Voir aussi
// PIGraphicPS
//--



/* En cm */
#define  MIN_SIZE_IN_PAGE  2.

/*
 *  Dictionnaire PIDict
 *
 *  Contient les fonctions suivantes : 
 *
 *
 */
#define PIDICT_PAR   \
  \
  PI_Landscape, PI_Portrait,\
  \
  PI_ColorFromMap, PI_Black, PI_White, PI_Grey, PI_Red, PI_Blue,\
  PI_Green, PI_Yellow, PI_Magenta, PI_NotDefColor,\
  PI_Cyan, PI_Turquoise, PI_NavyBlue,\
  PI_Orange, PI_SiennaRed, PI_Purple,\
  PI_LimeGreen, PI_Gold,\
  \
  PI_RomanFont, PI_BoldFont, PI_ItalicFont, PI_NotDefFontAtt,\
  PI_SmallSizeFont, PI_NormalSizeFont, PI_BigSizeFont, PI_NotDefFontSize, \
  \
  PI_NormalLine, PI_ThinLine, PI_ThickLine, PI_NotDefLineAtt

#define PIDICT       "\
/$PIDict 50 dict def\n\
$PIDict begin $PIDict /mtrx matrix put /Landscape %d def /Portrait %d def\n\
%% Couleurs et fontes courantes\n\
/C%-2d  {ur    ug    ub    setrgbcolor} bind def %% PI_ColorFromMap\n\
/C%-2d  {0.0   0.0   0.0   setrgbcolor} bind def %% PI_Black\n\
/C%-2d  {0.996 0.996 0.996 setrgbcolor} bind def %% PI_White\n\
/C%-2d  {0.824 0.824 0.824 setrgbcolor} bind def %% PI_Grey\n\
/C%-2d  {0.996 0.0   0.0   setrgbcolor} bind def %% PI_Red\n\
/C%-2d  {0.0   0.0   0.996 setrgbcolor} bind def %% PI_Blue\n\
/C%-2d  {0.0   0.996 0.0   setrgbcolor} bind def %% PI_Green\n\
/C%-2d  {0.996 0.996 0.0   setrgbcolor} bind def %% PI_Yellow\n\
/C%-2d  {0.996 0.0   0.996 setrgbcolor} bind def %% PI_Magenta\n\
/C%-2d  {}                              bind def %% PI_NotDefColor\n\
/C%-2d  {0.0   0.996 0.996 setrgbcolor} bind def %% PI_Cyan\n\
/C%-2d  {0.250 0.875 0.813 setrgbcolor} bind def %% PI_Turquoise\n\
/C%-2d  {0.0   0.0   0.500 setrgbcolor} bind def %% PI_NavyBlue\n\
/C%-2d  {0.996 0.644 0.0   setrgbcolor} bind def %% PI_Orange\n\
/C%-2d  {0.625 0.320 0.176 setrgbcolor} bind def %% PI_SiennaRed\n\
/C%-2d  {0.625 0.125 0.937 setrgbcolor} bind def %% PI_Purple\n\
/C%-2d  {0.195 0.800 0.195 setrgbcolor} bind def %% PI_LimeGreen\n\
/C%-2d  {0.996 0.840 0.0   setrgbcolor} bind def %% PI_Gold\n\
/F%-2d  {/Courier   findfont} bind def       %% PI_RomanFont\n\
/F%-2d  {/Courier-Bold    findfont} bind def       %% PI_BoldFont\n\
/F%-2d  {/Courier-Italic  findfont} bind def       %% PI_ItalicFont\n\
/F%-2d  {}\
                        bind def       %% PI_NotDefFontAtt\n\
/FS {scalefont setfont} bind def\n\
%%/FS%-2d {8  scalefont setfont} bind def          %% PI_SmallSizeFont\n\
%%/FS%-2d {12 scalefont setfont} bind def          %% PI_NormalSizeFont\n\
%%/FS%-2d {16 scalefont setfont} bind def          %% PI_BigSizeFont\n\
/FS%-2d {}                     bind def          %% PI_NotDefFontSize\n\
/L%-2d  {1    slw} bind def                      %% PI_NormalLine\n\
/L%-2d  {0.5  slw} bind def                      %% PI_ThinLine\n\
/L%-2d  {3    slw} bind def                      %% PI_ThickLine\n\
/L%-2d  {}         bind def                      %% PI_NotDefLineAtt\n\
\
%% Conversion\n\
/cm   {28.3 mul}   bind def  %% cm --> points\n\
/Ux   {$Cvrtx mul} bind def  %% Unites utilisateur /x --> points\n\
/Uy   {$Cvrty mul} bind def  %% Unites utilisateur /y --> points\n\
\
%% Pages et Blocs\n\
/newref  {%% Dx Dy Tx Ty X0 Y0 newref\n\
translate 3 -1 roll cm div 28.3 mul /$Cvrty exch def\n\
exch cm div 28.3 mul /$Cvrtx exch def} bind def\n\
/NewPage {%% Dx Dy orientation NewPage\n\
/$PageEnteredState save def 1 -1 scale Portrait eq {w cm h cm 0 h cm neg\n\
newref} { -90 rotate h cm w cm 0 0 newref} ifelse} bind def\n\
/EndPage { %% EndPage\n\
$PageEnteredState restore} bind def\n\
/NewBloc { %% Dx Dy Tx Ty X0 Y0 NewBloc\n\
/$BlocEnteredState save def newref} bind def\n\
/EndBloc { %% EndBloc\n\
$BlocEnteredState restore} bind def\n\
\
%% Trace\n\
/n  {newpath} bind def    /c  {closepath} bind def\n\
/gs {gsave}  bind def     /gr {grestore} bind def\n\
/m  {moveto} bind def     /l  {lineto} bind def\n\
/s  {stroke} bind def     /f  {fill}   bind def\n\
/sc {scale}  bind def     /S  {gs 1 -1 sc show gr} bind def \n\
/slw {setlinewidth} bind def\n\
/ff {findfont} bind def   /sf {setfont} bind def /scf {scalefont} bind def\n\
/rl {rlineto} bind def    /tr {translate} bind def\n\
%% Tx Ty X0 Y0 box\n\
/box {tr 0 3 1 roll neg exch 0 0 3 index neg 0 0 m rl rl rl c} bind def\n\
%% R X0 Y0 circle\n\
/circle {tr dup 0 m 0 0 3 -1 roll 0 380 arc} bind def\n\
%% DrawEllipse pompee sur transfig\n\
/ellipse {/endangle exch def /startangle exch def /yrad exch def\n\
/xrad exch def /y exch def /x exch def /savematrix mtrx currentmatrix def\n\
x y tr xrad yrad sc 0 0 1 startangle endangle arc\n\
closepath savematrix setmatrix } def\n\
\
%% Gestion des images\n\
%% ColorImage, pompee sur xv (qui les avait pompees sur xgrab)\n\
/colorimage where   %% do we know about 'colorimage'?\n\
  { pop }           %% yes: pop off the 'dict' returned\n\
  {                 %% no:  define one\n\
    /colortogray {  %% define an RGB->I function\n\
      /rgbdata exch store    %% call input 'rgbdata'\n\
      rgbdata length 3 idiv\n\
      /npixls exch store\n\
      /rgbindx 0 store\n\
      0 1 npixls 1 sub {\n\
        grays exch\n\
        rgbdata rgbindx       get 20 mul    %% Red\n\
        rgbdata rgbindx 1 add get 32 mul    %% Green\n\
        rgbdata rgbindx 2 add get 12 mul    %% Blue\n\
        add add 64 idiv      %% I = .5G + .31R + .18B\n\
        put\n\
        /rgbindx rgbindx 3 add store\n\
      } for\n\
      grays 0 npixls getinterval\n\
    } bind def\n\
    /mergeprocs { %% def\n\
      dup length 3 -1 roll dup length dup 5 1 roll 3 -1 roll add\n\
      array cvx dup 3 -1 roll 0 exch putinterval dup 4 2 roll\n\
      putinterval } bind def\n\
    /colorimage {\n\
      pop pop     %% remove 'false 3' operands\n\
      {colortogray} mergeprocs image} bind def\n\
  } ifelse          %% end of 'false' case\n\
\
%% GetRGB\n\
/GetRGB { %% ImageStr --> RGBStr\n\
  /ImageData exch store\n\
  %% Pour chaque element de ImageData,\n\
  %% On va chercher les valeurs RGB correspondantes\n\
  0 1 Taille 1 sub {\n\
    /i      exch store  %% On met a jour l'indice de parcours\n\
    ImageData i get     %% Recupere la Indice e val dans la chaine ImData\n\
    ColorMap exch get   %% On recupere la valeur RGB Correspondante\n\
    aload pop           %% On met tout ca dans la pile\n\
    %% Maintenant, on va mettre tout ca dans la chaine RGBStr\n\
    RGBStr i 3 mul 2 add 3 -1 roll put\n\
    RGBStr i 3 mul 1 add 3 -1 roll put\n\
    RGBStr i 3 mul       3 -1 roll put\n\
    } for\n\
  RGBStr 0 Taille 3 mul getinterval %% On renvoie la chaine RGB\n\
} bind def\n\
end\n\
"



/* 
 *  Les PIMarkers sont definis et geres commes des fontes
 *
 *
 */
#define PIMARKERS_PAR  PI_DotMarker, PI_PlusMarker, PI_CrossMarker,\
  PI_CircleMarker, PI_FCircleMarker, PI_BoxMarker, PI_FBoxMarker,\
  PI_TriangleMarker, PI_FTriangleMarker, PI_StarMarker, PI_FStarMarker

#define PIMARKERS  "\
%% Definition de la fonte $PIMarkers\n\
/$PIMarkers 26 dict def\n\
$PIMarkers begin\n\
/FontType 3 def\n\
/FontMatrix [0.001 0 0 0.001 -0.375 -0.375] def\n\
/FontBBox   [0 0 1000 1000] def\n\
/Encoding 256 array def\n\
0 1 255 {Encoding exch /.notdef put} for\n\
Encoding  %d /PIDot       put %% PI_DotMarker\n\
Encoding  %d /PIPlus      put %% PI_PlusMarker\n\
Encoding  %d /PICross     put %% PI_CrossMarker\n\
Encoding  %d /PICircle    put %% PI_CircleMarker\n\
Encoding  %d /PIFCircle   put %% PI_FCircleMarker\n\
Encoding  %d /PIBox       put %% PI_BoxMarker\n\
Encoding  %d /PIFBox      put %% PI_FBoxMarker\n\
Encoding  %d /PITriangle  put %% PI_TriangleMarker\n\
Encoding  %d /PIFTriangle put %% PI_FTriangleMarker\n\
Encoding  %d /PIStar      put %% PI_StarMarker\n\
Encoding  %d /PIFStar     put %% PI_FStarMarker\n\
/CharProcs 26 dict def\n\
$PIDict begin\n\
CharProcs begin\n\
/.notdef     {} def\n\
/PIDot       {100 375 375 circle f} bind def\n\
/PIPlus      {0 375 m 750 375 l 375 0 m 375 750 l s} bind def\n\
/PICross     {0 0 m 750 750 l 750 0 m 0 750 l s} bind def\n\
/PICircle    {375 375 375 circle s} bind def\n\
/PIFCircle   {375 375 375 circle f} bind def\n\
/PIBox       {0 0 m 750 0 l 750 750 l 0 750 l c s} bind def\n\
/PIFBox      {0 0 m 750 0 l 750 750 l 0 750 l c f} bind def\n\
/PITriangle  {0 750 m 375 0 l 750 750 l c s} bind def\n\
/PIFTriangle {0 750 m 375 0 l 750 750 l c f} bind def\n\
/PIStar      {} def\n\
/PIFStar     {} def\n\
end %%$PIDict\n\
end %%$CharProcs\n\
/BuildChar {\n\
1000 0      %% Largeur \n\
0 0 750 750 %% Bounding Box\n\
setcachedevice \n\
exch begin\n\
Encoding exch get\n\
CharProcs exch get\n\
end exec} def\n\
end\n\
/PIMarkers $PIMarkers definefont pop\n\
save\n\
"

/* Dimensions des divers formats */
  struct PaperSize {
      double width ;
      double height ;
  };
struct PaperSize PaperSizeTable[] = {
    { 0.0,  0.0},    /* PI_NotDefFormat */
    {21.0, 29.7},    /* PI_A4 */
    {29.7, 42.0},    /* PI_A3 */
    {14.8, 21.0}     /* PI_A5 ? */
} ;


double cm2pt(double x);


/* Fonction WriteHeader */
#define END_PROLOG_PAR  PAGE_WIDTH, PAGE_HEIGHT
#define END_PROLOG  "/NewFile { %%%% w h NewFile (--> h et w en cm <--)\n\
$PIDict begin /PIMarkers ff 14 scf sf /h exch def /w exch def \n\
/$PIEnteredState save def} bind def\n\
/EndFile {$PIEnteredState restore end} bind def\n\
%%%%EndProlog\n\n\
"

#define HEADER     "\
%%%%Title: %s\n\
%%%%Creator: PSFile\n\
%%%%CreationDate: %s\
%%%%Pages: (atend)\n\
%%%%EndComments\n\n\
"

//++
// Titre	Constructeurs
//--
//++
// PSFile (const char * FileName, double sc = 1.0)
//	Créateur pour fichier Encapsulated Postscript
// PSFile (const char * FileName, PIOrientation orientation, -
//         PIPaperSize paperSize= PI_A4, -
//         double marginX = 5.0, double marginY = 5.0 )
//	Créateur pour fichier Postscript
//--

/* 
 *   PostScript encapsule...
 * 
 *   Attention la bounding Box ne sera specifiee 
 *     qu'au premier NewPage() --> definie dans 
 *     le champ "Trailer" 
 *
 */
PSFile::PSFile(const char * FileName, double sc) 
#if defined(__DECCXX) || defined(__KCC__) || defined(__aCC__)
    : mPSFileName(FileName==NULL? "unnamed.eps" : const_cast<char *>(FileName)),
#else
    : mPSFileName(FileName==NULL? "unnamed.eps" : (char *)(FileName)),
#endif
      Tw (-1.), Th(-1.),         /* Non specifies pour du eps  */
      WMargin (-1), HMargin(-1), /* Non specifiees en eps  */ 
      isEPS(1),
      scale(sc),                 /* Defaut : 1. */
      mPaperSize(PI_NotDefPaperSize), /* Non specifiee en eps */
      PageCounter(0),            /* Fichier vide */
      FileEmpty(1),              /* Fichier vide */
      currentPage(NULL),
      currentBloc(NULL),
      mDrawColor(PI_Black),
      mFillColor(PI_Black),
      mFontAtt(PI_RomanFont),
      mFontSize(PI_NormalSizeFont),
      mLineAtt(PI_NormalLine),
      mMarker(PI_DotMarker),
      setFontDone(true)
{
    char*  date = new (char[64] ) ; 
    time_t timer ; 

    /* Ouverture du fichier en mode w+ */
    if ( (mPSFile = fopen(FileName, "w+")) == NULL){
	  perror (FileName);
	  return;
    }

    /* Ecriture du Header  */
    fprintf(mPSFile, "%%!PS-Adobe-2.0 EPSF-2.0\n");
    fprintf(mPSFile, "%%%%BoundingBox: ");
    /* 
     * Les dimensions de la BB seront notees ici lors du 
     * premier appel a NewPage
     *
     * C'est laid... si qqn a une meilleure idee...
     */
    boundingBox = ftell(mPSFile) ; 
    fprintf(mPSFile, "                       \n");

    time(&timer) ; 
    date = ctime(&timer) ; 
    fprintf(mPSFile, HEADER, mPSFileName, date) ; /* titre, date etc... */
    fprintf(mPSFile, PIDICT, PIDICT_PAR) ;        /* Dictionnaire */
    fprintf(mPSFile, PIMARKERS, PIMARKERS_PAR) ;  /* Fonte "PIMARKERS" */
    //    fprintf(mPSFile, END_PROLOG) ;
    /* Aucun format n'est specifie ici ... */
    fprintf(mPSFile, "$PIDict begin /PIMarkers ff 14 scf sf\n") ;
    fprintf(mPSFile, "/FState save def\n%%%%EndProlog\n\n") ;
}



/*
 *  PostScript simple...
 *
 *
 */
PSFile::PSFile(const char *FileName,
	       PIOrientation orientation,
	       PIPaperSize   paperSize,
	       double marginX, double marginY)
#if defined(__DECCXX) || defined(__KCC__) || defined(__aCC__)
 :  mPSFileName (FileName == NULL ? "unnamed.ps" : const_cast<char *>(FileName)),
#else
 :  mPSFileName (FileName == NULL ? "unnamed.ps" : (char *)(FileName)),
#endif
    Tw(PaperSizeTable[paperSize].width),  /* Format papier utilise */
    Th(PaperSizeTable[paperSize].height), /*                       */
    WMargin(marginX),
    HMargin(marginY),
    isEPS(0),
    scale(0.),
    PageCounter(0),  /* Fichier vide */
    FileEmpty(1),    /*              */
    currentPage(NULL),
    currentBloc(NULL),
    mDrawColor(PI_Black),
    mFillColor(PI_Black),
    mFontAtt(PI_RomanFont),
    mFontSize(PI_NormalSizeFont),
    mLineAtt(PI_NormalLine),
    mMarker(PI_DotMarker), 
    setFontDone(true)
{
    char * date = new(char[64]) ; 
    time_t timer ; 

    /* Ouverture du fichier, en mode w+ (tout est ecrase) */
    if ( (mPSFile = fopen(FileName, "w+")) == NULL){
	  perror (FileName);
	  return;
    }

    /* Format et orientation */

    /* Ecriture du Header  */
    fprintf(mPSFile, "%%!PS-Adobe-2.0\n") ;
    time(&timer) ; 
    date = ctime(&timer) ; 
    fprintf(mPSFile, HEADER, mPSFileName, date) ; /* titre, date etc... */
    fprintf(mPSFile, PIDICT, PIDICT_PAR) ;        /* Dictionnaire */
    fprintf(mPSFile, PIMARKERS, PIMARKERS_PAR) ;  /* Fonte "PIMARKERS" */
    fprintf(mPSFile, "$PIDict begin /PIMarkers ff 14 scf sf\n") ;
    fprintf(mPSFile, "/FState save def\n%%%%EndProlog\n\n") ;
}


/* 
 * Destructeur
 *
 */
PSFile::~PSFile () {

    /* On ferme tout ce qui ne l'est pas */
    if (currentBloc) PSFile::EndBloc();
    if (currentPage) PSFile::EndPage();

    /* Si le fichier est vide, on le detruit */
    if (FileEmpty) remove(mPSFileName);

    /* On ecrit le "Trailer" et on ferme */
    else {
	/* On restore l'etat initial */
	fprintf(mPSFile,"FState restore\n") ;
	fprintf(mPSFile, "%%%%Trailer\n%%%%Pages: %d\n%%%%EOF\n", 
		PageCounter) ;
	fclose (mPSFile);
    }
}


int   PSFile::IsEPS(){

    return(isEPS);
}


const char* PSFile::GetFileName() {

    return(mPSFileName);
}

PIColors PSFile::GetDrawColor() {

    return(mDrawColor);
}

PIColors PSFile::GetFillColor() {

    return(mFillColor);
}

PIFontAtt PSFile::GetFontAtt() {

    return(mFontAtt);
}

PIFontSize PSFile::GetFontSize() {

    return(mFontSize);
}

PILineAtt PSFile::GetLineAtt() {

    return(mLineAtt);
}

PIMarker PSFile::GetMarker() {

    return(mMarker);
}

void  PSFile::NewPage(double Dx, double Dy, PIOrientation orientation) {

double  tw, th; /* largeur & hauteur corrigees des marges */

    /* On ferme ce qui doit l'etre ... */
    if (currentPage) PSFile::EndPage();

    currentPage = new (Page) ; 

    /* Initialisations */
    currentPage->num = ++PageCounter;
    currentPage->BlocCounter = 0;
    currentPage->Dx = Dx;
    currentPage->Dy = Dy;
    currentPage->orientation = orientation ;

    /* Position du debut AVANT D'ECRIRE! */
    currentPage->begin  = ftell(mPSFile);

    /* On ecrit dans le fichier */
    fprintf(mPSFile, "%%%%Page: %d %d\n", PageCounter, PageCounter) ;
    fprintf(mPSFile, "/PState save def 1 -1 scale\n");

    /* 
     *  Si eps : Portrait || Auto == on laisse tel que
     *           Landscape == on tourne de -90 degres
     */
    if(isEPS) {
	if( (orientation == PI_Portrait) || (orientation == PI_Auto) )
	    fprintf(mPSFile,
		    "%.2f %.2f %.2f %.2f %.2f %.2f newref\n",
		    Dx, Dy, Dx*scale, Dy*scale, 0., -Dy*scale);
	else
	    if(orientation==PI_Landscape)
		fprintf(mPSFile, 
			"-90 rotate %.2f %.2f %.2f %.2f %.2f %.2f newref\n",
			Dx, Dy, Dx*scale, Dy*scale, 0., 0.);
	    else
		fprintf(stderr, "Orientation Error ; Page : %d\n",
			currentPage->num) ; 
    /* 
     * On specifie la bb 
     * (Si non encore fait par un appel precedent a NewPage() ) 
     */
	if(boundingBox) {
	    currentPage->tmp = ftell(mPSFile) ;
	    fseek(mPSFile,boundingBox,SEEK_SET) ;
	    if( (orientation == PI_Portrait) || (orientation == PI_Auto) )
		fprintf(mPSFile, "%d %d %d %d", 0, 0, 
			(int)(Dx*scale), (int)(Dy*scale) ) ; 
	    else
		fprintf(mPSFile, "%d %d %d %d", 0, 0, 
			(int)(Dy*scale), (int)(Dx*scale) ) ;
	    fseek(mPSFile,currentPage->tmp,SEEK_SET) ;
	    boundingBox = 0 ; 
	} /* BB */
    } /* EPS */
    /*
     * Si ps : 
     *   - soustraction marges --> rectangle utile.
     *   - Si PI_Auto : On fait au mieux pour minimiser le 
     *      redimensionnement...
     *   - Si PI_Portrait, on ne fait rien, sauf 
     *      peut-etre un redimensionnement pour rentrer dans les marges
     *   - Si PI_Landscape, on tourne de -90 degres.
     */
    else {
        // Si marges <= 0 on les met a 2cm
        if(WMargin<=0) WMargin = 2. ; 
        if(HMargin<=0) HMargin = 2. ; 
	/* Eviter image reduite a un point...ou moins... */
	if((tw = Tw - 2*WMargin) < (Tw/10)) {
	    WMargin = (0.45)*Tw ;
	    tw = Tw/10;
	}
	if((th = Th - 2*HMargin)< (Th/10)) {
	    HMargin = (0.45)*Th ;
	    th = Th/10;
	}
	/* Portrait ou Landscape ? */
	if(orientation == PI_Auto) 
	    if( ((tw < th) && (Dx < 1.2*Dy)) ||
		((tw > th) && (Dx > Dy) )) 
		currentPage->orientation = PI_Portrait ;
	    else 
		currentPage->orientation = PI_Landscape ;

	if(currentPage->orientation == PI_Portrait) {
//	    if( (tw/Dx) < (th/Dy) ) 
//		scale = tw/Dx ;
//                scale = tw/Tw ; 
//	    else 
//		scale = th/Dy;
//                scale = th/Th;
//	    fprintf(mPSFile, 
//		    "%.2f %.2f %.2f cm %.2f cm %.2f cm %.2f cm newref\n",
//		    Dx, Dy, 
//		    Dx*scale, Dy*scale, 
//		    Tw*scale, Th*scale, 
//		    0.5*(Tw-tw), -0.5*(Th+th)) ;
            scale = (tw/Dx)<(th/Dy) ? tw/Dx : th/Dy ; 
            tw = scale*Dx ; th = scale*Dy ; 
	    fprintf(mPSFile, 
		    "%.2f %.2f %.2f cm %.2f cm %.2f cm %.2f cm newref\n",
		    Dx, Dy, 
		    tw, th, 
		    0.5*(Tw-tw), -0.5*(Th+th)) ;
	}
	if(currentPage->orientation == PI_Landscape) {
	    /* Idem avec X<->Y */
//	    if( (th/Dx) < (th/Dy) ) 
//		scale = th/Dx;
//                scale = th/Tw;
//	    else
//		scale = tw/Dy ;
//                scale = tw/Th;
//	    fprintf(mPSFile,
//	       "-90 rotate %.2f %.2f %.2f cm %.2f cm %.2f cm %.2f cm newref\n",
//	       Dx, Dy,
//	       Dx*scale, Dy*scale, 
//	       Th*scale, Tw*scale, 
//	       0.5*(Th-th), 0.5*(Tw-tw));

            scale = (th/Dx)<(tw/Dy) ? th/Dx : tw/Dy ; 
            th = scale*Dx ; tw = scale*Dy ; 
	    fprintf(mPSFile,
	       "-90 rotate %.2f %.2f %.2f cm %.2f cm %.2f cm %.2f cm newref\n",
	       Dx, Dy,
	       th, tw,
	       0.5*(Th-th), 0.5*(Tw-tw));
	}
    } /* End if .ps */
currentPage->tmp = ftell(mPSFile);
}



void  PSFile::EndPage() {

    /* Si rien a fermer, on s'en va */
    if ( ! currentPage ) return;

    /* Si un bloc non ferme, on appelle EndBloc */
    if ( currentBloc ) PSFile::EndBloc();
    
    /* Si la page est vide, on la detruit */
    if (currentPage->tmp == ftell(mPSFile)) {
	fseek(mPSFile, currentPage->begin, SEEK_SET);
	delete(currentPage) ;
	PageCounter--;
    }
    /* Sinon, fin page + empilage */
    else {
	//	it = mPageList.end(); it--;
	fprintf(mPSFile,"PState restore  showpage\n");
	fprintf(mPSFile,"%%>EndPage %d\n\n\n", currentPage->num);
	currentPage->end = ftell(mPSFile);
	mPageList.push_back(*currentPage); /* Pourquoi PageList ? */
	FileEmpty = 0;
    }
    currentPage = NULL;
}


void  PSFile::NewBloc(double x0, double y0, double Tx, double Ty,
			      double Dx, double Dy){

    /* Si pas de page, on s'en va */
    if ( ! currentPage ) return;

    /* On ferme le bloc precedent (Pas de Bloc-gigognes ! ) */
    if (currentBloc) PSFile::EndBloc();

    currentBloc = new (Bloc) ; 
    /* On remplit currentBloc */
    currentBloc->num = ++(currentPage->BlocCounter);
    currentBloc->X0 = x0;
    currentBloc->Y0 = y0;
    currentBloc->Tx = Tx;
    currentBloc->Ty = Ty;
    currentBloc->Dx = Dx;
    currentBloc->Dy = Dy;
    currentBloc->begin = ftell(mPSFile);

    /* On met a jour le fichier */
    fprintf(mPSFile, "%%>BeginBloc %d\n", currentBloc->num);
    fprintf(mPSFile, "%.2f %.2f %.2f Ux %.2f Uy %.2f Ux %.2f Uy NewBloc\n",
	    currentBloc->Dx, currentBloc->Dy,
	    currentBloc->Tx, currentBloc->Ty,
	    currentBloc->X0, currentBloc->Y0);
    currentBloc->tmp = ftell(mPSFile) ;
}


void  PSFile::EndBloc() {

    /* On verifie qu'un bloc ouvert existe bien */
    if ( ! currentBloc ) return;

    /* Si le bloc est vide, on le detruit */
    if (currentBloc->tmp == ftell(mPSFile)) {
	fseek(mPSFile, currentBloc->begin, SEEK_SET) ; 
	currentPage->BlocCounter-- ; 
    }
    /* Sinon, Ok met a jour le fichier */
    else { 
	fprintf(mPSFile, "EndBloc\n"); 
	fprintf(mPSFile, "%%>EndBloc %d\n", currentBloc->num); 
	currentBloc->end = ftell(mPSFile) ; 
	currentPage->mBlocList.push_back(*currentBloc) ; 
	//	PageEmpty = 0; 
    } 
    /* Flags */
    currentBloc = NULL ; 
}

void PSFile::SelForeground(PIColorMap& cmap, int cid)
{
  mDrawColor = PI_ColorFromMap ; 
  PIColor tmp = cmap.GetColor(cid) ; 
  fprintf(mPSFile, "/ur %.3f def /ug %.3f def /ub %.3f def \n", 
          (double)(tmp.red)/65535., 
          (double)(tmp.green)/65535., 
          (double)(tmp.blue)/65535.) ; 
}


void PSFile::SelBackground(PIColorMap& cmap, int cid)
{
  mDrawColor = PI_ColorFromMap ; 
}


void  PSFile::DrawString  (double x,  double y, const char *s, 
			   PIColors DrawColor, 
			   PIFontAtt FontAtt, 
			   int FontSize) {
    int change = 0;

    /* Couleurs */
    if ( (DrawColor != PI_NotDefColor) || (DrawColor != mDrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor) ; 
    }
    /* Choix des fontes */
    if ( (FontAtt != PI_NotDefFontAtt) || (FontAtt != mFontAtt) ) {
	mFontAtt = FontAtt;
	change = 1;}
    if ( (FontSize != PI_NotDefFontSize) || (FontSize != mFontSize) ) {
	mFontSize = (PIFontSize) FontSize;  // $CHECK$ EA ajoute le cast un peu au pif
	change = 1;}
    if (change)
	fprintf(mPSFile, "F%d %d FS ", mFontAtt, FontSize) ; 

    fprintf(mPSFile, "gs %.2f Ux %.2f Uy m (%s) S gr\n", x, y, s) ; 
    setFontDone = true ; 
}


void  PSFile::DrawLine    (double x1, double y1, double x2, double y2, 
		   PIColors DrawColor,
		   PILineAtt LineAtt) {

  int lw = 0 ; 

  switch(LineAtt) {
    case PI_NotDefLineAtt:
      break ; 
    case PI_NormalLine:
      lw = 2. ; 
      break ; 
    case PI_ThinLine:
      lw = 1 ; 
      break ; 
    case PI_ThickLine:
      lw = 4 ;
      break ; 
  } 

    /* Line Att */
    if ( (LineAtt != PI_NotDefLineAtt) || (LineAtt != mLineAtt) ) {
        mLineAtt = LineAtt;
	fprintf(mPSFile, "%d slw ", lw) ; 
    }

    /* Couleurs */
    if ( (DrawColor != PI_NotDefColor) || (DrawColor != mDrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor);
    }

    /* Dessin */
    fprintf(mPSFile, "n %.2f Ux %.2f Uy m %.2f Ux %.2f Uy l s\n",
	    x1, y1, x2, y2) ;
}



void  PSFile::DrawBox(double x0, double y0, double Tx, double Ty, 
		      PIColors  DrawColor,
		      PILineAtt LineAtt) {

    /* Changement couleurs ? */
    if ( (DrawColor != PI_NotDefColor) || (DrawColor != mDrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor) ; 
    }

    /* Line Att */
    if ( (LineAtt != PI_NotDefLineAtt) || (LineAtt != mLineAtt) ) {
        mLineAtt = LineAtt;
	fprintf(mPSFile, "%d slw ", mLineAtt) ; 
    }

    /* On dessine */
    fprintf(mPSFile, "gs n %.2f Ux %.2f Uy %.2f Ux %.2f Uy box s gr\n",
	    Tx, Ty, x0, y0) ; 
}


void  PSFile::DrawFBox(double x0, double y0, double Tx, double Ty, 
		   PIColors DrawColor,
		   PIColors FillColor, 
		   PILineAtt LineAtt) {

    /* Line Att */
    if ( (LineAtt != PI_NotDefLineAtt) || (LineAtt != mLineAtt) ) {
        mLineAtt = LineAtt;
	fprintf(mPSFile, "%d slw ", mLineAtt) ; 
    }

    /* Dessin du fond */
    if ( (FillColor != PI_NotDefColor) || (FillColor != mFillColor) )
	mFillColor = FillColor;
    fprintf(mPSFile, "C%d ", mFillColor) ; 
    fprintf(mPSFile, "gs n %.2f Ux %.2f Uy %.2f Ux %.2f Uy box f gr\n",
	    Tx, Ty, x0, y0) ; 
    
    /* Dessin du contour (s'il y a lieu) */
    if ( (DrawColor != PI_NotDefColor) && (FillColor != DrawColor) )
	mDrawColor = DrawColor;
    fprintf(mPSFile, "C%d ", mDrawColor) ; 
    fprintf(mPSFile, "gs n %.2f Ux %.2f Uy %.2f Ux %.2f Uy box s gr\n",
	    Tx, Ty, x0, y0) ;
}


void  PSFile::DrawCircle  (double x0, double y0, double r, 
			   PIColors DrawColor,
			   PILineAtt LineAtt) {

    /* Couleurs */
    if ( (DrawColor != PI_NotDefColor) || (DrawColor != mDrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor); 
    }

    /* Line Att */
    if ( (LineAtt != PI_NotDefLineAtt) || (LineAtt != mLineAtt) ) {
        mLineAtt = LineAtt;
	fprintf(mPSFile, "%d slw ", mLineAtt); 
    }

    /* Dessin */
    fprintf(mPSFile, "gs n %.2f Ux %.2f Uy %.2f Ux %.2f Uy 0 360 ellipse s gr\n",
	    x0, y0, r, r) ;
}


void  PSFile::DrawFCircle (double x0, double y0, double r,
		   PIColors DrawColor,
		   PIColors FillColor, 
		   PILineAtt LineAtt) {

    /* Line Att */
    if ( (LineAtt != PI_NotDefLineAtt) || (LineAtt != mLineAtt) ) {
        mLineAtt = LineAtt;
	fprintf(mPSFile, "%d slw ", mLineAtt) ; 
    }

    /* Dessin du fond */
    if ( (FillColor != PI_NotDefColor) || (FillColor != mFillColor) ){
	mFillColor = FillColor;
	fprintf(mPSFile, "C%d ", mFillColor) ;
    }
    fprintf(mPSFile, "gs n %.2f Ux %.2f Uy %.2f Ux %.2f Uy \
                      0 360 ellipse f gr\n",
	    x0, y0, r, r);
    fprintf(mPSFile, "C%d ", mDrawColor) ;

    /* Dessin du contour (s'il y a lieu) */
    if ( (DrawColor != PI_NotDefColor) && (FillColor != DrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor); 
	fprintf(mPSFile, "gs n %.2f Ux %.2f Uy %.2f Ux %.2f Uy 0 360 ellipse s gr\n",
		x0, y0, r, r) ;
    }
}


// Les coordonnees sont supposees etre en mode incremental .
void  PSFile::DrawPolygon (double *x, double *y, int n,
		   PIColors DrawColor, 
		   PILineAtt LineAtt, bool cinc) {

    /* Line Att */
    if ( (LineAtt != PI_NotDefLineAtt) || (LineAtt != mLineAtt) ) {
        mLineAtt = LineAtt;
	fprintf(mPSFile, "%d slw ", mLineAtt) ; 
    }

    /* Couleur */
    if ( (DrawColor != PI_NotDefColor) || (DrawColor != mDrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor) ;
    }
    
    /* On dessine ; ici*/
    fprintf(mPSFile, "%.2f Ux %.2f Uy m\n", x[0], y[0]);

    const char* cmd ; 
    if(cinc == true) cmd = "%.2f Ux %.2f Uy rl\n" ; 
    else             cmd = "%.2f Ux %.2f Uy l\n" ; 

    for(int i = 1; i<n; i++) 
      fprintf(mPSFile, cmd, x[i], y[i]);
    fprintf(mPSFile, "c s\n");
}


void  PSFile::DrawFPolygon(double *x, double *y, int n,
		   PIColors DrawColor,
		   PIColors FillColor,
		   PILineAtt LineAtt, bool cinc) {

    /* Line Att */
    if ( (LineAtt != PI_NotDefLineAtt) || (LineAtt != mLineAtt) ) {
        mLineAtt = LineAtt;
	fprintf(mPSFile, "%d slw ", mLineAtt) ; 
    }

    const char* cmd ; 
    if(cinc == true) cmd = "%.2f Ux %.2f Uy rl\n" ; 
    else             cmd = "%.2f Ux %.2f Uy l\n" ; 

    /* Dessin du fond... */
    if ( (FillColor != PI_NotDefColor) || (FillColor != mFillColor) ) 
	mFillColor = FillColor;
    fprintf(mPSFile, "C%d ", mFillColor) ;
    fprintf(mPSFile, "%.2f Ux %.2f Uy m\n", x[0], y[0]);
    int i;
    for(i = 1; i<n; i++) 
	fprintf(mPSFile, cmd, x[i], y[i]);
    fprintf(mPSFile, "c f\n");

    /* ...puis du contour (s'il y a lieu) */
    if ( (DrawColor != PI_NotDefColor) && (DrawColor != FillColor) )
	mDrawColor = DrawColor;
    fprintf(mPSFile, "C%d ", mDrawColor) ;
    fprintf(mPSFile, "%.2f Ux %.2f Uy m\n", x[0], y[0]);
    for(i = 1; i<n; i++) 
      fprintf(mPSFile, cmd, x[i], y[i]);
    fprintf(mPSFile, "c s\n");
}



void  PSFile::DrawMarker  (double x0, double y0,
			   PIMarker MrkType,   
			   PIColors DrawColor,
			   int MarkerSize) {
    /* Couleurs */
    if ( (DrawColor != PI_NotDefColor) || (DrawColor != mDrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor) ; 
    }

    /* Marker */
    if (MrkType != PI_NotDefMarker)
	mMarker = MrkType;

    if(MarkerSize != mMarkerSize || setFontDone) {
	mMarkerSize = MarkerSize ;
	fprintf(mPSFile, "/PIMarkers ff %d scf sf\n", mMarkerSize) ; 
        setFontDone = false ; 
    }
    /* Dessin */
    fprintf(mPSFile, "%.2f Ux %.2f Uy m (\\%#o) show\n", x0, y0, mMarker) ;
}

/*
 * Pas d'options pour specifier la taille des Markers ?
 *
 */
void  PSFile::DrawMarkers (double *x0, double *y0, int n,
			   PIMarker MrkType,
			   PIColors DrawColor,
			   int MarkerSize) {
    /* Couleurs */
    if ( (DrawColor != PI_NotDefColor) || (DrawColor != mDrawColor) ) {
	mDrawColor = DrawColor;
	fprintf(mPSFile, "C%d ", mDrawColor) ; 
    }    

    /* Marker */
    if (MrkType != PI_NotDefMarker)
	mMarker = MrkType;

    if(MarkerSize != mMarkerSize || setFontDone) {
	mMarkerSize = MarkerSize ;
	fprintf(mPSFile, "/PIMarkers ff %d scf sf\n", mMarkerSize) ; 
        setFontDone = false ; 
    }
    /* Dessin */
    for(int i = 0; i<n; i++)
	fprintf(mPSFile, "%.2f Ux %.2f Uy m (\\%#o) show\n", x0[i], y0[i], mMarker) ; 
}

void PSFile::Image(double x0, double y0, double Tx, double Ty,
		   int Nx, int Ny,
		   unsigned char *Pict, 
		   PIColorMap *mMap) {

    int i, j;

    /* Buffers PostScript */
    fprintf(mPSFile, "/Taille %d def\n", Nx);
    fprintf(mPSFile, "/ImStr Taille string def\n");
    fprintf(mPSFile, "/RGBStr Taille 3  mul string def\n");

    /* Ecriture ColorMap */
    fprintf(mPSFile, "/ColorMap %02d array def\n", mMap->NCol() );
    for(i = 0; i < mMap->NCol(); i++) {
	fprintf(mPSFile, "ColorMap %d [16#%02X 16#%02X 16#%02X] put\n",
		i,
		(int)(mMap->GetColor(i).red/256),
		(int)(mMap->GetColor(i).green/256),
		(int)(mMap->GetColor(i).blue/256));
    }
    /* Emplacement de l'image */
    fprintf(mPSFile, "gs %.2f Ux %.2f Uy tr %.2f Ux %.2f Uy sc\n", x0, y0, Tx, Ty);
    /* Nbr pix-X, Nbr pix-Y bits/pixels */
    fprintf(mPSFile, "%d %d 8\n", Nx, Ny);
    /* Matrice de passage */
    fprintf(mPSFile, "[%d 0 0 %d 0 0]", Nx, Ny);
    /* Fonction colorimage */
    fprintf(mPSFile, "{currentfile ImStr readhexstring pop GetRGB}\
false 3 colorimage\n\n");
    /* Data */
    for(i = 0; i < Ny; i++) {
	for(j = 0; j<Nx-1; j++ )
	    fprintf(mPSFile, "%02X", Pict[i*Nx+j]);
    fprintf(mPSFile, "%02X\n", Pict[i*Nx+j]);
    }
    /* Un petit grestore ...*/
    fprintf(mPSFile, "gr\n");
}

/* 
 *  Conversion
 *
 */

double cm2pt(double x) {
    return (x*28.35);
}

