{********************************************}
{ TeeChart Pro PS Canvas and Exporting       }
{ Copyright (c) 2002-2020 by Marjan Slatinek }
{ and Steema Software                        }
{ All Rights Reserved                        }
{********************************************}
unit TeePSCanvas;
{$I TeeDefs.inc}

interface

uses {$IFNDEF LINUX}
     {$IFNDEF FMX}
     Windows,
     {$ENDIF}
     {$ENDIF}
     Classes,

     {$IFDEF D16}
     System.UITypes,
     {$ENDIF}

     {$IFDEF FMX}
     FMX.Types, System.Types,

     {$IFDEF D17}
     System.UIConsts,
     {$ENDIF}

     {$IFDEF D19}
     FMX.Graphics,
     {$ENDIF}

     {$ELSE}
     Graphics, Forms,
     {$IFDEF D9}
     Types,
     {$ENDIF}
     {$ENDIF}

     {$IFDEF FMX}
     FMXTee.Procs, FMXTee.Canvas, FMXTee.Editor.Export,
     {$ELSE}
     TeCanvas, TeeProcs, TeeExport,
     {$ENDIF}
     Math;

type
  TEPSCanvas = class(TTeeNeutralCanvas)
  private
    { Private declarations }
    FStrings : TStrings;

    FX, FY   : TCoordinate;

    Procedure Add(Const S:String);
    Function BrushProperties(const Brush: TBrush): String;
    Procedure InternalRect(Const Rect:TRect; UsePen,IsRound:Boolean);
    Procedure InternalArc(X1, Y1, X2, Y2, X3, Y3, X4, Y4: Integer; Pie: Boolean);
    Function PenProperties(const Pen: TTeePen): String;
    Function PointToStr(X,Y:TCoordinate):String;
    Function SetPenStyle(PenStyle: TPenStyle): String;
    Function TextToPSText(AText:String): String;
    Procedure TranslateVertCoord(var Y: TCoordinate);
  protected
    { Protected declarations }

    { 2d }
    procedure SetPixel(X, Y: Integer; Value: TColor); override;

    { 3d }
    procedure SetPixel3D(X,Y,Z:Integer; Value: TColor); override;
  public
    { Public declarations }
    Constructor CreateText(const AStrings:TStrings);

    Function InitWindow( const DestCanvas:TCanvas;
                         const A3DOptions:TView3DOptions;
                         ABackColor:TColor;
                         Is3D:Boolean;
                         Const UserRect:TRect):TRect; override;

    procedure Arc(const Left, Top, Right, Bottom, StartX, StartY, EndX, EndY: Integer); override;
    procedure Draw(X, Y: Integer; const Graphic: TGraphic); override;
    procedure FillRect(const Rect: TRect); override;
    procedure Ellipse(const X1, Y1, X2, Y2: TCoordinate); override;
    procedure LineTo(const X,Y:TCoordinate); override;
    procedure MoveTo(const X,Y:TCoordinate); override;
    procedure Pie(X1, Y1, X2, Y2, X3, Y3, X4, Y4: Integer); override;
    procedure Rectangle(const X0,Y0,X1,Y1:TCoordinate); override;
    procedure RoundRect(X1, Y1, X2, Y2, X3, Y3: Integer); override;
    procedure StretchDraw(const Rect: TRect; const Graphic: TGraphic); override;
    Procedure TextOut({$IFDEF FMX}const{$ENDIF} X,Y:TCoordinate; const Text:String); override;

    procedure ClipRectangle(Const Rect:TRect); override;
    procedure UnClipRectangle; override;

    Procedure GradientFill( Const Rect:TRect;
                            StartColor,EndColor:TColor;
                            Direction:TGradientDirection;
                            Balance:Integer=50;
                            RadialX:Integer=0;
                            RadialY:Integer=0); override;

    procedure RotateLabel(x,y:Integer; Const St:String; RotDegree:Double;
                          AllowHTML:Boolean=False); override;
    procedure RotateLabel3D(x,y,z:Integer;
                            Const St:String; RotDegree:Double;
                            AllowHTML:Boolean=False); override;
    Procedure Polygon({$IFDEF D6}const{$ENDIF} Points: array of TPoint); override;

    { 3d }
    Procedure ShowImage(const DestCanvas,DefaultCanvas:TCanvas; Const UserRect:TRect); override;
    procedure EllipseWithZ(const X1, Y1, X2, Y2:TCoordinate;
                           const Z:Integer); override;
    Procedure TextOut3D(X,Y,Z:Integer; const Text:String; AllowHTML:Boolean=False); override;
  end;

  TEPSExportFormat=class(TTeeExportFormat)
  private
  protected
    Procedure DoCopyToClipboard; override;
  public
    function Description:String; override;
    function FileExtension:String; override;
    class function FileFilter:String; override;
    Function EPSList:TStringList;
    Procedure SaveToStream(Stream:TStream); override;
  end;


procedure TeeSaveToPSFile( const APanel:TCustomTeePanel; const FileName: {$IFDEF D18}String{$ELSE}WideString{$ENDIF};
                           AWidth:Integer=0;
                           AHeight: Integer=0);

implementation

Uses {$IFDEF FMX}
     FMX.Platform,
     {$ELSE}
     Clipbrd,
     {$ENDIF}

     {$IFDEF FMX}
     FMXTee.Constants,
     {$ELSE}
     TeeConst,
     {$ENDIF}
     SysUtils;

{ Convert , to . }
procedure FixSeparator(var St: String);
begin
  while Pos(',', St) > 0 do
    St[Pos(',', St)] := '.';
end;

procedure StringToPSString(var St: String);
begin
end;

Function PSColor(AColor:TColor):String;
begin
  Result:= FormatFloat('0.00',GetRVAlue(Cardinal(AColor))/255) + ' ' +
           FormatFloat('0.00',GetGVAlue(Cardinal(AColor))/255) + ' ' +
           FormatFloat('0.00',GetBVAlue(Cardinal(AColor))/255) + ' rgb';

  FixSeparator(Result);
end;

{ TPSCanvas }
Constructor TEPSCanvas.CreateText(const AStrings:TStrings);
begin
  Create;

  BackMode:=cbmTransparent;
  FStrings:=AStrings;
  UseBuffer:=False;
end;

Procedure TEPSCanvas.ShowImage(const DestCanvas,DefaultCanvas:TCanvas; Const UserRect:TRect);
begin
  Add('gr');
end;

Procedure TEPSCanvas.Add(Const S:String);
begin
  FStrings.Add(S);
end;


procedure TEPSCanvas.Rectangle(const X0,Y0,X1,Y1:TCoordinate);
begin
  InternalRect(TeeRect(X0,Y0,X1,Y1),True,False);
end;

procedure TEPSCanvas.MoveTo(const X, Y: TCoordinate);
begin
  FX := X;
  FY := Y;
end;

procedure TEPSCanvas.LineTo(const X, Y: TCoordinate);
var tmpStr: String;
begin
  tmpStr := 'gs ' + PenProperties(Pen) + ' ' +
            PointToStr(FX,FY)+' m '+
            PointToStr(X,Y)+' l st gr ';
  Add(tmpStr);
  FX := X;
  FY := Y;
end;

function ToStr(const Value:TCoordinate):String;
begin
  {$IFDEF FMX}
  result:=IntToStr(Round(Value));
  {$ELSE}
  result:=IntToStr(Value);
  {$ENDIF}
end;

procedure TEPSCanvas.ClipRectangle(Const Rect:TRect);
var tmpB: TCoordinate;
    tmpStr: String;
begin
  tmpB := Rect.Bottom;
  TranslateVertCoord(tmpB);
  tmpStr :='clipsave ' +
            ToStr(Rect.Left) + ' ' + ToStr(tmpB) + ' ' +
            ToStr(Rect.Right - Rect.Left) + ' ' +
            ToStr(Rect.Bottom - Rect.Top) + ' rectclip';
  Add(tmpStr);
end;

procedure TEPSCanvas.UnClipRectangle;
begin
  Add('cliprestore');
end;

procedure TEPSCanvas.StretchDraw(const Rect: TRect; const Graphic: TGraphic);
begin
  { Not implemented }
end;

procedure TEPSCanvas.Draw(X, Y: Integer; const Graphic: TGraphic);
begin
  { Not implemented }
end;

Function TEPSCanvas.PointToStr(X,Y:TCoordinate):String;
begin
  TranslateVertCoord(Y);
  result:=ToStr(X)+' '+ToStr(Y);
end;

Procedure TEPSCanvas.GradientFill( Const Rect:TRect;
                                  StartColor,EndColor:TColor;
                                  Direction:TGradientDirection;
                                  Balance:Integer=50;
                                  RadialX:Integer=0;
                                  RadialY:Integer=0);
begin
  { Not implemented }
end;

procedure TEPSCanvas.FillRect(const Rect: TRect);
begin
  InternalRect(Rect,False,False);
end;

Procedure TEPSCanvas.InternalRect(Const Rect:TRect; UsePen, IsRound:Boolean);
var tmpB: TCoordinate;
    tmpStr: String;
begin
  if (Brush.Style<>bsClear) or (UsePen and (Pen.Style<>psClear)) then
  begin
    tmpB := Rect.Bottom;
    TranslateVertCoord(tmpB);

    if Brush.Style<>bsClear then
    begin
      tmpStr := 'gs '+ PsColor(Brush.Color);
      tmpStr := tmpStr + ' ' +ToStr(Rect.Left) + ' ' + ToStr(tmpB) + ' ' +
                ToStr(Rect.Right - Rect.Left) + ' ' +
                ToStr(Rect.Bottom - Rect.Top) + ' rectfill gr';
      Add(tmpStr);
    end;

    if UsePen and (Pen.Style<>psClear) then
    begin
      tmpStr := 'gs '+ PenProperties(Pen);
      tmpStr := tmpStr + ' ' + ToStr(Rect.Left) + ' ' + ToStr(tmpB) + ' ' +
                ToStr(Rect.Right - Rect.Left) + ' ' +
                ToStr(Rect.Bottom - Rect.Top) + ' rectstroke gr';
      Add(tmpStr);
    end;
  end;
end;

procedure TEPSCanvas.Ellipse(const X1, Y1, X2, Y2: TCoordinate);
begin
  EllipseWithZ(X1,Y1,X2,Y2,0);
end;

procedure TEPSCanvas.EllipseWithZ(const X1, Y1, X2, Y2:TCoordinate; const Z: Integer);
var CenterX,
    CenterY: TCoordinate;
    Ra,Rb: String;

    procedure DrawEllipse;
    begin
      Add(ToStr(CenterX) + ' '+ToStr(CenterY) + ' ' +
          Ra + ' ' + Rb + ' 0 360 ellipse') ;
    end;

var P1, P2 : TPoint;
begin
  if (Brush.Style<>bsClear) or (Pen.Style<>psClear) then
  begin
    Calc3DPoint(P1,X1,Y1,Z);
    Calc3DPoint(P2,X2,Y2,Z);

    CenterX := (P1.X + P2.X) {$IFDEF FMX}*0.5{$ELSE}div 2{$ENDIF};
    CenterY := (P1.Y + P2.Y) {$IFDEF FMX}*0.5{$ELSE}div 2{$ENDIF};
    TranslateVertCoord(CenterY);

    { radius }
    Ra := FormatFloat('0.00',(P2.X-P1.X)*0.5);
    FixSeparator(Ra);
    Rb := FormatFloat('0.00',(P2.Y-P1.Y)*0.5);
    FixSeparator(Rb);

    if (Brush.Style<>bsClear) then
    begin
      Add('gs ' + BrushProperties(Brush));
      DrawEllipse;
      Add('fi gr');
    end;

    if (Pen.Style<>psClear) then
    begin
      Add('gs ' + PenProperties(Pen));
      DrawEllipse;
      Add('st gr');
    end;
  end;
end;

procedure TEPSCanvas.SetPixel3D(X,Y,Z:Integer; Value: TColor);
begin
  if Pen.Style<>psClear then
  begin
    Calc3DPos(x,y,z);
    Pen.Color:=Value;
    MoveTo(x,y);
    LineTo(x,y);
  end;
end;

procedure TEPSCanvas.SetPixel(X, Y: Integer; Value: TColor);
begin
  if Pen.Style<>psClear then
  begin
    Pen.Color:=Value;
    MoveTo(x,y);
    LineTo(x,y);
  end;
end;

procedure TEPSCanvas.Arc(const Left, Top, Right, Bottom, StartX, StartY, EndX, EndY: Integer);
begin
  InternalArc(Left,Top,Right,Bottom,StartX,StartY,EndX,EndY, False);
end;

procedure TEPSCanvas.Pie(X1, Y1, X2, Y2, X3, Y3, X4, Y4: Integer);
begin
  InternalArc(X1, Y1, X2, Y2, X3, Y3, X4, Y4, True);
end;

procedure TEPSCanvas.RoundRect(X1, Y1, X2, Y2, X3, Y3: Integer);
begin
  InternalRect(TeeRect(X1,Y1,X2,Y2),True,True);
end;

Procedure TEPSCanvas.TextOut3D(X,Y,Z:Integer; const Text:String; AllowHTML:Boolean=False);

  Function FontSize:String;
  begin
    //if Assigned(IFont) then
       result:=FloatToStr(Font.SizeFloat)
    {else
       result:=ToStr(Font.Size)}
       ;
  end;

  Procedure DoText(AX,AY:Integer);
  var tmpStr: String;
      tmpName: String;
  begin
    Inc(AY,TextHeight(Text) div 2);

    tmpName:=Font.{$IFDEF FMX}Family{$ELSE}Name{$ENDIF};
    tmpStr := PsColor(Font.Color);

    if StringContains(' ',tmpName) <> 0 then
      tmpName:=StringReplace(tmpName, ' ', '-', [rfReplaceAll]);

    tmpStr := tmpStr +
              ' /' + tmpName + ' findfont ' + FontSize + ' scalefont setfont';

    Add(tmpStr);
    Add(PointToStR(AX,AY) + ' m');

    if (TextAlign and TA_CENTER)=TA_CENTER then
      Add('(' + TextToPSText(Text) + ') ctext')
    else
    if (TextAlign and TA_RIGHT)=TA_RIGHT then
      Add('(' + TextToPSText(Text) + ') rtext')
    else
      Add('(' + TextToPSText(Text) + ') ltext')

  end;

Var tmpX : Integer;
    tmpY : Integer;
begin
  Calc3DPos(x,y,z);

  //if Assigned(IFont) then
  With Font.Shadow do
  if (HorizSize<>0) or (VertSize<>0) then
  begin
    if HorizSize<0 then
    begin
      tmpX:=X;
      X:=X-HorizSize;
    end
    else tmpX:=X+HorizSize;

    if VertSize<0 then
    begin
      tmpY:=Y;
      Y:=Y-VertSize;
    end
    else tmpY:=Y+VertSize;

    DoText(tmpX,tmpY)
  end;

  DoText(X,Y);
end;

Procedure TEPSCanvas.TextOut({$IFDEF FMX}const{$ENDIF} X,Y:TCoordinate; const Text:String);
begin
  TextOut3D({$IFDEF FMX}Round{$ENDIF}(x),
            {$IFDEF FMX}Round{$ENDIF}(y),0,Text);
end;

procedure TEPSCanvas.RotateLabel3D(x,y,z:Integer; Const St:String; RotDegree:Double;
                                   AllowHTML:Boolean=False);
begin
  Calc3DPos(x,y,z);
  Add('gs '+PointToStr(x,y) + ' tr ' + IntToStr(Round(RotDegree))+ ' rot');
  TextOut(0,Self.Bounds.Bottom,St);
  Add('gr');
end;

procedure TEPSCanvas.RotateLabel(x,y:Integer; Const St:String; RotDegree:Double;
                                 AllowHTML:Boolean=False);
begin
  RotateLabel3D(x,y,0,St,RotDegree,AllowHTML);
end;

Procedure TEPSCanvas.Polygon({$IFDEF D6}const{$ENDIF} Points: Array of TPoint);

  Procedure AddPoly;
  var t : Integer;
  begin
    Add('np '+ PointToStr(Points[0].X,Points[0].Y)+' m');

    for t:=1 to High(Points) do
        Add(PointToStr(Points[t].X,Points[t].Y)+' l');
        
    Add('cp');
  end;

var tmpStr: String;
begin
  if (Brush.Style<>bsClear) or (Pen.Style<>psClear) then
  begin
    if (Brush.Style<>bsClear) then
    begin
      Add('gs ' +BrushProperties(Brush));
      AddPoly;
      Add('fi gr');
    end;

    if (Pen.Style<>psClear) then
    begin
      tmpStr :='gs '+ PenProperties(Pen);
      Add(tmpStr);
      AddPoly;
      Add('st gr');
    end;
  end;
end;

function TEPSCanvas.InitWindow(const DestCanvas: TCanvas;
  const A3DOptions: TView3DOptions; ABackColor: TColor; Is3D: Boolean;
  const UserRect: TRect): TRect;

  Function TheBounds:String;
  var IWidth, IHeight: TCoordinate;
  begin
    IWidth := Bounds.Right - Bounds.Left;
    IHeight := Bounds.Bottom - Bounds.Top;
    Result:='%%BoundingBox: 0 0 ' + ToStr(IWidth) + ' ' + ToStr(IHeight);
  end;

begin
  result:=inherited InitWindow(DestCanvas,A3DOptions,ABackColor,Is3D,UserRect);
  Add('%!PS-Adobe-3.0 EPSF-3.0');
  Add(TheBounds); { bounding box }
  Add('%%Creator: '+TeeMsg_Version);
  Add('%%LanguageLevel: 1');
  Add('%%EndComments');
  Add('/bd{bind def} bind def /ld{load def}bd /ed{exch def}bd /xd{cvx def}bd');
  Add('/np/newpath ld /cp/closepath ld /m/moveto ld /l/lineto ld /rm/rmoveto ld'
      + '/rl/rlineto ld');
  Add('/rot/rotate ld /sc/scale ld /tr/translate ld');
  Add('/cpt/currentpoint ld');
  Add('/sw/setlinewidth ld /sd/setdash ld /rgb/setrgbcolor ld');
  Add('/gs/gsave ld /gr/grestore ld');
  Add('/st/stroke ld /fi/fill ld /s/show ld');
  Add('/ltext{cpt st m s}def ');
  Add('/rtext{cpt st m dup stringwidth pop neg 0 rm s} def');
  Add('/ctext{cpt st m dup stringwidth pop -2 div 0 rm s} def');
  Add('/ellipsedict 8 dict def');
  Add('ellipsedict /mtrx matrix put');
  Add('/ellipse');
  Add('{ ellipsedict begin');
  Add('  np');
  Add('   /endangle exch def');
  Add('   /startangle exch def');
  Add('   /yrad exch def');
  Add('   /xrad exch def');
  Add('   /y exch def');
  Add('   /x exch def');
  Add('  /savematrix mtrx currentmatrix def');
  Add('  x y tr xrad yrad sc');
  Add('  0 0 1 startangle endangle arc');
  Add('  savematrix setmatrix');
  Add('  end');
  Add('} def');
  Add('/piedict 8 dict def');
  Add('piedict /mtrx matrix put');
  Add('/pie');
  Add('{ piedict begin');
  Add('  np');
  Add('   /endangle exch def');
  Add('   /startangle exch def');
  Add('   /yrad exch def');
  Add('   /xrad exch def');
  Add('   /y exch def');
  Add('   /x exch def');
  Add('  /savematrix mtrx currentmatrix def');
  Add('  x y tr xrad yrad sc');
  Add('  newpath');
  Add('  0 0 m');
  Add('  0 0 1 startangle endangle arc');
  Add('  closepath');
  Add('  savematrix setmatrix');
  Add('  end');
  Add('} def');
  Add('%%EndProlog');
  Add('gs');
  Add('np');
end;

{ TEPSExportFormat }
function TEPSExportFormat.Description: String;
begin
  result:=TeeMsg_AsPS;
end;

procedure TEPSExportFormat.DoCopyToClipboard;
begin
  with EPsList do
  try
    TeeCopyClipboard(Text);
  finally
    Free;
  end;
end;

function TEPSExportFormat.FileExtension: String;
begin
  result:='eps';
end;

class function TEPSExportFormat.FileFilter: String;
begin
  result:=TeeMsg_PSFilter;
end;

procedure TEPSExportFormat.SaveToStream(Stream: TStream);
begin
  with EPSList do
  try
    SaveToStream(Stream);
  finally
    Free;
  end;
end;

type
  TTeePanelAccess=class(TCustomTeePanel);

// return a panel or chart in PS format into a StringList }
function TEPSExportFormat.EPSList: TStringList;
var tmp : TCanvas3D;
begin
  CheckSize;

  result:=TStringList.Create;

  Panel.AutoRepaint:=False;
  try

    // Protected across assemblies
    tmp:=TTeePanelAccess(Panel).InternalCanvas;
    TTeePanelAccess(Panel).InternalCanvas:=nil;

    Panel.Canvas:=TEPSCanvas.CreateText(Result);

    if not Assigned(Panel.Parent) then
       Panel.BufferedDisplay:=True;

    try
      Panel.Draw(Panel.Canvas.ReferenceCanvas,TeeRect(Width,Height));
    finally
      Panel.Canvas:=tmp;
    end;
  finally
    Panel.AutoRepaint:=True;
  end;
end;

procedure TeeSaveToPSFile( const APanel:TCustomTeePanel; const FileName: {$IFDEF D18}String{$ELSE}WideString{$ENDIF};
                           AWidth:Integer=0;
                           AHeight: Integer=0);
begin { save panel or chart to filename in EPS (PostScript) format }
  with TEPSExportFormat.Create do
  try
    Panel:=APanel;
    Height:=AHeight;
    Width:=AWidth;
    SaveToFile(FileName);
  finally
    Free;
  end;
end;

procedure TEPSCanvas.TranslateVertCoord(var Y: TCoordinate);
begin
  { vertical coordinate is reversed in PS !! }
  Y := (Self.Bounds.Bottom - Self.Bounds.Top)  - Y;
end;

function TEPSCanvas.SetPenStyle(PenStyle: TPenStyle): String;
begin
  case PenStyle of
    psSolid : Result := '[] 0 sd';
    psDash : Result := '[3] 0 sd';
    psDot : Result := '[2] 1 sd';
    {
    psDashDot : Result :=
    psDashDotDot : Result :=
    }
   else Result := '';
  end;
end;

procedure TEPSCanvas.InternalArc(X1, Y1, X2, Y2, X3, Y3, X4, Y4: Integer;
  Pie: Boolean);

var CenterX, CenterY: TCoordinate;
    StartAngle, EndAngle: String;
    Ra,Rb: String;

    procedure DrawPie;
    begin
      Add(ToStr(CenterX) + ' '+ToStr(CenterY) + ' ' +
          Ra + ' ' + Rb + ' '+StartAngle+' ' +
          EndAngle+' pie') ;
    end;

    procedure DrawArc;
    begin
      Add(ToStr(CenterX) + ' '+ToStr(CenterY) + ' ' +
          Ra + ' ' + Rb + ' '+StartAngle+' ' +
          EndAngle+' ellipse') ;
    end;

var Theta: double;
const HalfDivPi = 57.29577951;

begin
  if ((Brush.Style<>bsClear) or (Pen.Style<>psClear)) then
  begin
    CenterX := (X1 + X2) div 2;
    CenterY := (Y1 + Y2) div 2;

    { StartAngle }
    Theta := Math.ArcTan2(CenterY-Y3, X3 - CenterX);
    if Theta<0 then Theta:=2.0*Pi+Theta;
    Theta := Theta*HalfDivPi;
    StartAngle := FloatToStr(Theta);
    FixSeparator(StartAngle);

    { EndAngle }
    Theta := Math.ArcTan2(CenterY-Y4, X4 - CenterX);
    if Theta<0 then Theta:=2.0*Pi+Theta;
    Theta := Theta*HalfDivPi;
    if Theta=0 then Theta:=361;
    EndAngle := FloatToStr(Theta);
    FixSeparator(EndAngle);
    TranslateVertCoord(CenterY);

    { radius }
    Ra := FormatFloat('0.00',(X2-X1)*0.5);
    FixSeparator(Ra);
    Rb := FormatFloat('0.00',(Y2-Y1)*0.5);
    FixSeparator(Rb);

    if Pie then
    begin
      if (Brush.Style<>bsClear) then
      begin
        Add('gs ' + BrushProperties(Brush));
        DrawPie;
        Add('fi gr');
      end;

      if (Pen.Style<>psClear) then
      begin
        Add('gs ' + PenProperties(Pen));
        DrawPie;
        Add('st gr');
      end;
    end 
    else 
    if (Pen.Style<>psClear) then
    begin
      Add('gs ' + PenProperties(Pen));
      DrawArc;
      Add('st gr');
    end;
  end;
end;

function TEPSCanvas.PenProperties(const Pen: TTeePen): String;
begin
  result := PSColor(Pen.Color) + ' ' + SetPenStyle(Pen.Style)
            + ' ' + ToStr(Pen.Width)+' sw';
end;

function TEPSCanvas.BrushProperties(const Brush: TBrush): String;
begin
  result:=PsColor(Brush.Color);
end;

function TEPSCanvas.TextToPSText(AText: String): String;
begin
  AText := StringReplace(AText,'\','\\',[rfReplaceAll,rfIgnoreCase]);
  AText := StringReplace(AText,'(','\(',[rfReplaceAll,rfIgnoreCase]);
  AText := StringReplace(AText,')','\)',[rfReplaceAll,rfIgnoreCase]);
  Result := AText;
end;

initialization
  {$IFDEF FMX}
  TTeeExportFormats.RegisterFormat(TEPSExportFormat);
  {$ELSE}
  RegisterTeeExportFormat(TEPSExportFormat);
  {$ENDIF}
finalization
  {$IFDEF FMX}
  TTeeExportFormats.UnRegisterFormat(TEPSExportFormat);
  {$ELSE}
  UnRegisterTeeExportFormat(TEPSExportFormat);
  {$ENDIF}
end.

