123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 2003 by the Free Pascal development team
- TPostScriptCanvas implementation.
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program 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.
- **********************************************************************}
- { ---------------------------------------------------------------------
- This code is heavily based on Tony Maro's initial TPostScriptCanvas
- implementation in the LCL, but was adapted to work with the custom
- canvas code and to work with streams instead of strings.
- ---------------------------------------------------------------------}
- {$mode objfpc}
- {$H+}
- unit pscanvas;
- interface
- uses
- Classes, SysUtils,fpimage,fpcanvas;
- type
- TPostScript = class;
- TPSPaintType = (ptColored, ptUncolored);
- TPSTileType = (ttConstant, ttNoDistortion, ttFast);
- TPostScriptCanvas = class; // forward reference
- {Remember, modifying a pattern affects that pattern for the ENTIRE document!}
- TPSPattern = class(TFPCanvasHelper)
- private
- FStream : TMemoryStream;
- FPatternCanvas : TPostScriptCanvas;
- FOldName: String;
- FOnChange: TNotifyEvent;
- FBBox: TRect;
- FName: String;
- FPaintType: TPSPaintType;
- FPostScript: TStringList;
- FTilingType: TPSTileType;
- FXStep: Real;
- FYStep: Real;
- function GetpostScript: TStringList;
- procedure SetBBox(const AValue: TRect);
- procedure SetName(const AValue: String);
- procedure SetPaintType(const AValue: TPSPaintType);
- procedure SetTilingType(const AValue: TPSTileType);
- procedure SetXStep(const AValue: Real);
- procedure SetYStep(const AValue: Real);
- protected
- public
- constructor Create;
- destructor Destroy; override;
- procedure Changed;
- property BBox: TRect read FBBox write SetBBox;
- property PaintType: TPSPaintType read FPaintType write SetPaintType;
- property TilingType: TPSTileType read FTilingType write SetTilingType;
- property XStep: Real read FXStep write SetXStep;
- property YStep: Real read FYStep write SetYStep;
- property Name: String read FName write SetName;
- property GetPS: TStringList read GetPostscript;
- property OldName: string read FOldName write FOldName; // used when notifying that name changed
- property OnChange: TNotifyEvent read FOnChange write FOnChange;
- Property PatternCanvas : TPostScriptCanvas Read FPatternCanvas;
- end;
- PPSPattern = ^TPSPattern; // used for array
- { Pen and brush object both right now...}
- TPSPen = class(TFPCustomPen)
- private
- FPattern: TPSPattern;
- procedure SetPattern(const AValue: TPSPattern);
- public
- destructor Destroy; override;
- property Pattern: TPSPattern read FPattern write SetPattern;
- function AsString: String;
- end;
- TPSBrush = Class(TFPCustomBrush)
- Private
- Function GetAsString : String;
- Public
- Property AsString : String Read GetAsString;
- end;
- TPSFont = Class(TFPCustomFont)
- end;
- { Custom canvas-like object that handles postscript code }
- TPostScriptCanvas = class(TFPCustomCanvas)
- private
- FHeight,FWidth : Integer;
- FStream : TStream;
- FLineSpacing: Integer;
- LastX: Integer;
- LastY: Integer;
- function TranslateY(Ycoord: Integer): Integer; // Y axis is backwards in postscript
- procedure AddFill;
- procedure ResetPos; // reset back to last moveto location
- procedure SetWidth (AValue : integer); override;
- function GetWidth : integer; override;
- procedure SetHeight (AValue : integer); override;
- function GetHeight : integer; override;
- Protected
- Procedure WritePS(Const Cmd : String);
- Procedure WritePS(Const Fmt : String; Args : Array of Const);
- procedure DrawRectangle(const Bounds: TRect; DoFill : Boolean);
- procedure DrawEllipse(const Bounds: TRect; DoFill : Boolean);
- public
- constructor Create(AStream : TStream);
- destructor Destroy; override;
- function DoCreateDefaultFont : TFPCustomFont; override;
- function DoCreateDefaultPen : TFPCustomPen; override;
- function DoCreateDefaultBrush : TFPCustomBrush; override;
- property LineSpacing: Integer read FLineSpacing write FLineSpacing;
- Procedure DoMoveTo(X1,Y1 : Integer); override;
- Procedure DoLineTo(X1,Y1 : Integer); override;
- Procedure DoLine(X1,Y1,X2,Y2 : Integer); override;
- Procedure DoRectangle(Const Bounds : TRect); override;
- Procedure DoRectangleFill(Const Bounds : TRect); override;
- procedure DoPolyline(Const Points: Array of TPoint); override;
- procedure DoEllipse(const Bounds: TRect); override;
- procedure DoEllipseFill(const Bounds: TRect); override;
- procedure DoPie(x,y,awidth,aheight,angle1,angle2 : Integer);
- //procedure Pie(x,y,width,height,SX,SY,EX,EY : Integer);
- procedure Writeln(AString: String);
- procedure TextOut(X,Y: Integer; const Text: String);
- //procedure Chord(x,y,width,height,angle1,angle2 : Integer);
- //procedure Chord(x,y,width,height,SX,SY,EX,EY : Integer);
- //procedure PolyBezier(Points: PPoint; NumPts: Integer;
- // Filled: boolean{$IFDEF VER1_1} = False{$ENDIF};
- // Continuous: boolean{$IFDEF VER1_1} = False{$ENDIF});
- //procedure PolyBezier(const Points: array of TPoint;
- // Filled: boolean{$IFDEF VER1_1} = False{$ENDIF};
- // Continuous: boolean{$IFDEF VER1_1} = False{$ENDIF});
- //procedure PolyBezier(const Points: array of TPoint);
- //procedure Polygon(const Points: array of TPoint;
- // Winding: Boolean{$IFDEF VER1_1} = False{$ENDIF};
- // StartIndex: Integer{$IFDEF VER1_1} = 0{$ENDIF};
- // NumPts: Integer {$IFDEF VER1_1} = -1{$ENDIF});
- //procedure Polygon(Points: PPoint; NumPts: Integer;
- // Winding: boolean{$IFDEF VER1_1} = False{$ENDIF});
- //Procedure Polygon(const Points: array of TPoint);
- //Procedure FillRect(const Rect : TRect);
- //procedure FloodFill(X, Y: Integer; FillColor: TFPColor; FillStyle: TFillStyle);
- //Procedure RoundRect(X1, Y1, X2, Y2: Integer; RX,RY : Integer);
- //Procedure RoundRect(const Rect : TRect; RX,RY : Integer);
- Property Stream : TStream read FStream;
- end;
- { Encapsulates ALL the postscript and uses the TPostScriptCanvas object for a single page }
- TPostScript = class(TComponent)
- private
- FDocStarted : Boolean;
- FCreator : String;
- FStream : TStream;
- FCanvas: TPostScriptCanvas;
- FHeight: Integer;
- FLineSpacing: Integer;
- FPageNumber: Integer;
- FTitle: String;
- FWidth: Integer;
- FPatterns: TList; // array of pointers to pattern objects
- procedure SetHeight(const AValue: Integer);
- procedure SetLineSpacing(const AValue: Integer);
- procedure SetWidth(const AValue: Integer);
- procedure UpdateBoundingBox;
- procedure PatternChanged(Sender: TObject);
- procedure InsertPattern(APattern: TPSPattern); // adds the pattern to the postscript
- Procedure SetStream (Value : TStream);
- Function GetCreator : String;
- Protected
- Procedure WritePS(Const Cmd : String);
- Procedure WritePS(Const Fmt : String; Args : Array of Const);
- Procedure WriteDocumentHeader; virtual;
- Procedure WriteStandardFont; virtual;
- Procedure WritePage; virtual;
- Procedure FreePatterns;
- Procedure CheckStream;
- public
- Constructor Create(AOwner : TComponent);
- destructor Destroy; override;
- procedure AddPattern(APSPattern: TPSPattern);
- function FindPattern(AName: String): TPSPattern;
- function DelPattern(AName: String): Boolean;
- function NewPattern(AName: String): TPSPattern;
- property Canvas: TPostScriptCanvas read FCanvas;
- property Height: Integer read FHeight write SetHeight;
- property Width: Integer read FWidth write SetWidth;
- property PageNumber: Integer read FPageNumber;
- property Title: String read FTitle write FTitle;
- property LineSpacing: Integer read FLineSpacing write SetLineSpacing;
- procedure BeginDoc;
- procedure NewPage;
- procedure EndDoc;
- Property Stream : TStream Read FStream Write SetStream;
- Property Creator : String Read GetCreator Write FCreator;
- end;
- implementation
- Resourcestring
- SErrNoStreamAssigned = 'Invalid operation: No stream assigned';
- SErrDocumentAlreadyStarted = 'Cannot start document twice.';
- { TPostScriptCanvas ----------------------------------------------------------}
- Procedure TPostScriptCanvas.WritePS(const Cmd : String);
- var
- ss : shortstring;
- begin
- If length(Cmd)>0 then
- FStream.Write(Cmd[1],Length(Cmd));
- ss:=LineEnding;
- FStream.Write(ss[1],Length(ss));
- end;
- Procedure TPostScriptCanvas.WritePS(Const Fmt : String; Args : Array of Const);
- begin
- WritePS(Format(Fmt,Args));
- end;
- { Y coords in postscript are backwards... }
- function TPostScriptCanvas.TranslateY(Ycoord: Integer): Integer;
- begin
- Result:=Height-Ycoord;
- end;
- { Adds a fill finishing line to any path we desire to fill }
- procedure TPostScriptCanvas.AddFill;
- begin
- WritePs('gsave '+(Brush as TPSBrush).AsString+' fill grestore');
- end;
- { Return to last moveto location }
- procedure TPostScriptCanvas.ResetPos;
- begin
- WritePS(inttostr(LastX)+' '+inttostr(TranslateY(LastY))+' moveto');
- end;
- constructor TPostScriptCanvas.Create(AStream : TStream);
- begin
- inherited create;
- FStream:=AStream;
- Height := 792; // length of page in points at 72 ppi
- { // Choose a standard font in case the user doesn't
- FFontFace := 'AvantGarde-Book';
- SetFontSize(10);
- FLineSpacing := MPostScript.LineSpacing;
- end;
- FPen := TPSPen.Create;
- FPen.Width := 1;
- FPen.FPColor := 0;
- FPen.OnChange := @PenChanged;
- FBrush := TPSPen.Create;
- FBrush.Width := 1;
- FBrush.FPColor := -1;
- // don't notify us that the brush changed...
- }
- end;
- destructor TPostScriptCanvas.Destroy;
- begin
- {
- FPostScript.Free;
- FPen.Free;
- FBrush.Free;
- }
- inherited Destroy;
- end;
- procedure TPostScriptCanvas.SetWidth (AValue : integer);
- begin
- FWidth:=AValue;
- end;
- function TPostScriptCanvas.GetWidth : integer;
- begin
- Result:=FWidth;
- end;
- procedure TPostScriptCanvas.SetHeight (AValue : integer);
- begin
- FHeight:=AValue;
- end;
- function TPostScriptCanvas.GetHeight : integer;
- begin
- Result:=FHeight;
- end;
- { Move draw location }
- procedure TPostScriptCanvas.DoMoveTo(X1, Y1: Integer);
- var
- Y: Integer;
- begin
- Y := TranslateY(Y1);
- WritePS(inttostr(X1)+' '+inttostr(Y)+' moveto');
- LastX := X1;
- LastY := Y1;
- end;
- { Draw a line from current location to these coords }
- procedure TPostScriptCanvas.DoLineTo(X1, Y1: Integer);
- var
- Y: Integer;
- begin
- Y := TranslateY(Y1);
- WritePS(inttostr(X1)+' '+inttostr(Y)+' lineto');
- LastX := X1;
- LastY := Y1;
- end;
- procedure TPostScriptCanvas.DoLine(X1, Y1, X2, Y2: Integer);
- var
- Y12, Y22: Integer;
- begin
- Y12 := TranslateY(Y1);
- Y22 := TranslateY(Y2);
- WritePS('newpath '+inttostr(X1)+' '+inttostr(Y12)+' moveto '+
- inttostr(X2)+' '+inttostr(Y22)+' lineto closepath stroke');
- // go back to last moveto position
- ResetPos;
- end;
- { Draw a rectangle }
- procedure TPostScriptCanvas.DoRectangleFill(const Bounds: TRect);
- begin
- DrawRectangle(Bounds,true)
- end;
- procedure TPostScriptCanvas.DoRectangle(const Bounds: TRect);
- begin
- DrawRectangle(Bounds,False);
- end;
- procedure TPostScriptCanvas.DrawRectangle(const Bounds: TRect; DoFill : Boolean);
- var
- Y12, Y22: Integer;
- begin
- Y12 := TranslateY(Bounds.Top);
- Y22 := TranslateY(Bounds.Bottom);
- WritePS('stroke newpath');
- With Bounds do
- begin
- WritePS(inttostr(Left)+' '+inttostr(Y12)+' moveto');
- WritePS(inttostr(Right)+' '+inttostr(Y12)+' lineto');
- WritePS(inttostr(Right)+' '+inttostr(Y22)+' lineto');
- WritePS(inttostr(Left)+' '+inttostr(Y22)+' lineto');
- end;
- WritePS('closepath');
- If DoFill and (Brush.Style<>bsClear) then
- AddFill;
- WritePS('stroke');
- ResetPos;
- end;
- { Draw a series of lines }
- procedure TPostScriptCanvas.DoPolyline(Const Points: Array of TPoint);
- var
- i : Longint;
- begin
- MoveTo(Points[0].X, Points[0].Y);
- For i := 1 to High(Points) do
- LineTo(Points[i].X, Points[i].Y);
- ResetPos;
- end;
- { This was a pain to figure out... }
- procedure TPostScriptCanvas.DoEllipse(Const Bounds : TRect);
- begin
- DrawEllipse(Bounds,False);
- end;
- procedure TPostScriptCanvas.DoEllipseFill(Const Bounds : TRect);
- begin
- DrawEllipse(Bounds,true);
- end;
- procedure TPostScriptCanvas.DrawEllipse(Const Bounds : TRect; DoFill : Boolean);
- var
- radius: Integer;
- YRatio: Real;
- centerX, centerY: Integer;
- begin
- // set radius to half the width
- With Bounds do
- begin
- radius := (Right-Left) div 2;
- if radius <1 then
- exit;
- YRatio := (Bottom - Top) / (Right-Left);
- // find center
- CenterX := (Right+Left) div 2;
- CenterY := (Top+Bottom) div 2;
- end;
- WritePS('newpath '+inttostr(CenterX)+' '+inttostr(TranslateY(CenterY))+' translate');
- // move to edge
- WritePS(inttostr(radius)+' 0 moveto');
- // now draw it
- WritePS('gsave 1 '+format('%.3f',[YRatio])+' scale');
- WritePS('0 0 '+inttostr(radius)+' 0 360 arc');
- if DoFill and (Brush.Style<>bsClear) then
- AddFill;
- // reset scale for drawing line thickness so it doesn't warp
- YRatio := 1 / YRatio;
- WritePS('1 '+format('%.2f',[YRatio])+' scale stroke grestore');
- // move origin back
- WritePS(inttostr(-CenterX)+' '+inttostr(-TranslateY(CenterY))+' translate closepath stroke');
- ResetPos;
- end;
- procedure TPostScriptCanvas.DoPie(x, y, AWidth, AHeight, angle1, angle2: Integer);
- begin
- // set zero at center
- WritePS('newpath '+inttostr(X)+' '+inttostr(TranslateY(Y))+' translate');
- // scale it
- WritePS('gsave '+inttostr(AWidth)+' '+inttostr(Aheight)+' scale');
- //WritePS('gsave 1 1 scale');
- // draw line to edge
- WritePS('0 0 moveto');
- WritePS('0 0 1 '+inttostr(angle1)+' '+inttostr(angle2)+' arc closepath');
- if Brush.Style<>bsClear then
- AddFill;
- // reset scale so we don't change the line thickness
- // adding 0.01 to compensate for scaling error - there may be a deeper problem here...
- WritePS(format('%.6f',[(real(1) / X)+0.01])+' '+format('%.6f',[(real(1) / Y)+0.01])+' scale stroke grestore');
- // close out and return origin
- WritePS(inttostr(-X)+' '+inttostr(-TranslateY(Y))+' translate closepath stroke');
- resetpos;
- end;
- { Writes text with a carriage return }
- procedure TPostScriptCanvas.Writeln(AString: String);
- begin
- TextOut(LastX, LastY, AString);
- LastY := LastY+Font.Size+FLineSpacing;
- MoveTo(LastX, LastY);
- end;
- { Output text, restoring draw location }
- procedure TPostScriptCanvas.TextOut(X, Y: Integer; const Text: String);
- var
- Y1: Integer;
- begin
- Y1 := TranslateY(Y);
- WritePS(inttostr(X)+' '+inttostr(Y1)+' moveto');
- WritePS('('+Text+') show');
- ResetPos; // move back to last moveto location
- end;
- function TPostScriptCanvas.DoCreateDefaultFont : TFPCustomFont;
- begin
- Result:=TPSFont.Create;
- end;
- function TPostScriptCanvas.DoCreateDefaultPen : TFPCustomPen;
- begin
- Result:=TPSPen.Create;
- end;
- function TPostScriptCanvas.DoCreateDefaultBrush : TFPCustomBrush;
- begin
- Result:=TPSBrush.Create;
- end;
- { TPostScript -------------------------------------------------------------- }
- procedure TPostScript.SetHeight(const AValue: Integer);
- begin
- if FHeight=AValue then exit;
- FHeight:=AValue;
- UpdateBoundingBox;
- // filter down to the canvas height property
- if assigned(FCanvas) then
- FCanvas.Height := FHeight;
- end;
- procedure TPostScript.SetLineSpacing(const AValue: Integer);
- begin
- if FLineSpacing=AValue then exit;
- FLineSpacing:=AValue;
- // filter down to the canvas
- if assigned(FCanvas) then FCanvas.LineSpacing := AValue;
- end;
- procedure TPostScript.SetWidth(const AValue: Integer);
- begin
- if FWidth=AValue then exit;
- FWidth:=AValue;
- UpdateBoundingBox;
- end;
- { Take our sizes and change the boundingbox line }
- procedure TPostScript.UpdateBoundingBox;
- begin
- {
- // need to not hard-link this to line 1
- FDocument[1] := '%%BoundingBox: 0 0 '+inttostr(FWidth)+' '+inttostr(FHeight);
- }
- end;
- { Pattern changed so update the postscript code }
- procedure TPostScript.PatternChanged(Sender: TObject);
- begin
- // called anytime a pattern changes. Update the postscript code.
- // look for and delete the current postscript code for this pattern
- // then paste the pattern back into the code before the first page
- InsertPattern(Sender As TPSPattern);
- end;
- { Places a pattern definition into the bottom of the header in postscript }
- procedure TPostScript.InsertPattern(APattern: TPSPattern);
- var
- I, J: Integer;
- MyStrings: TStringList;
- begin
- { I := 0;
- if FDocument.Count < 1 then begin
- // added pattern when no postscript exists - this shouldn't happen
- raise exception.create('Pattern inserted with no postscript existing');
- exit;
- end;
- for I := 0 to FDocument.count - 1 do begin
- if (FDocument[I] = '%%Page: 1 1') then begin
- // found it!
- // insert into just before that
- MyStrings := APattern.GetPS;
- for J := 0 to MyStrings.Count - 1 do begin
- FDocument.Insert(I-1+J, MyStrings[j]);
- end;
- exit;
- end;
- end;
- }
- end;
- constructor TPostScript.Create(AOwner : TComponent);
- begin
- inherited create(AOwner);
- // Set some defaults
- FHeight := 792; // 11 inches at 72 dpi
- FWidth := 612; // 8 1/2 inches at 72 dpi
- end;
- Procedure TPostScript.WritePS(const Cmd : String);
- var
- ss : shortstring;
- begin
- If length(Cmd)>0 then
- FStream.Write(Cmd[1],Length(Cmd));
- ss:=LineEnding;
- FStream.Write(ss[1],Length(ss));
- end;
- Procedure TPostScript.WritePS(Const Fmt : String; Args : Array of Const);
- begin
- WritePS(Format(Fmt,Args));
- end;
- Procedure TPostScript.WriteDocumentHeader;
- begin
- WritePS('%!PS-Adobe-3.0');
- WritePS('%%BoundingBox: 0 0 612 792');
- WritePS('%%Creator: '+Creator);
- WritePS('%%Title: '+FTitle);
- WritePS('%%Pages: (atend)');
- WritePS('%%PageOrder: Ascend');
- WriteStandardFont;
- end;
- Procedure TPostScript.WriteStandardFont;
- begin
- // Choose a standard font in case the user doesn't
- WritePS('/AvantGarde-Book findfont');
- WritePS('10 scalefont');
- WritePS('setfont');
- end;
- Procedure TPostScript.FreePatterns;
- Var
- i : Integer;
- begin
- If Assigned(FPatterns) then
- begin
- For I:=0 to FPatterns.Count-1 do
- TObject(FPatterns[i]).Free;
- FreeAndNil(FPatterns);
- end;
- end;
- destructor TPostScript.Destroy;
- begin
- Stream:=Nil;
- FreePatterns;
- inherited Destroy;
- end;
- { add a pattern to the array }
- procedure TPostScript.AddPattern(APSPattern: TPSPattern);
- begin
- If Not Assigned(FPatterns) then
- FPatterns:=Tlist.Create;
- FPatterns.Add(APSPattern);
- end;
- { Find a pattern object by it's name }
- function TPostScript.FindPattern(AName: String): TPSPattern;
- var
- I: Integer;
- begin
- Result := nil;
- If Assigned(FPatterns) then
- begin
- I:=Fpatterns.Count-1;
- While (Result=Nil) and (I>=0) do
- if TPSPattern(FPatterns[I]).Name = AName then
- result := TPSPattern(FPatterns[i])
- else
- Dec(i)
- end;
- end;
- function TPostScript.DelPattern(AName: String): Boolean;
- begin
- // can't do that yet...
- Result:=false;
- end;
- { Create a new pattern and inserts it into the array for safe keeping }
- function TPostScript.NewPattern(AName: String): TPSPattern;
- var
- MyPattern: TPSPattern;
- begin
- MyPattern := TPSPattern.Create;
- AddPattern(MyPattern);
- MyPattern.Name := AName;
- MyPattern.OnChange := @PatternChanged;
- MyPattern.OldName := '';
- // add this to the postscript now...
- InsertPattern(MyPattern);
- result := MyPattern;
- end;
- { Start a new document }
- procedure TPostScript.BeginDoc;
- var
- I: Integer;
- begin
- CheckStream;
- If FDocStarted then
- Raise Exception.Create(SErrDocumentAlreadyStarted);
- FCanvas:=TPostScriptCanvas.Create(FStream);
- FCanvas.Height:=Self.Height;
- FCanvas.Width:=Self.width;
- FreePatterns;
- WriteDocumentHeader;
- // start our first page
- FPageNumber := 1;
- WritePage;
- UpdateBoundingBox;
- end;
- Procedure TPostScript.WritePage;
- begin
- WritePS('%%Page: '+inttostr(FPageNumber)+' '+inttostr(FPageNumber));
- WritePS('newpath');
- end;
- { Copy current page into the postscript and start a new one }
- procedure TPostScript.NewPage;
- begin
- // dump the current page into our postscript first
- // put end page definition...
- WritePS('stroke');
- WritePS('showpage');
- FPageNumber := FPageNumber+1;
- WritePage;
- end;
- { Finish off the document }
- procedure TPostScript.EndDoc;
- begin
- // Start printing the document after closing out the pages
- WritePS('stroke');
- WritePS('showpage');
- WritePS('%%Pages: '+inttostr(FPageNumber));
- // okay, the postscript is all ready, so dump it to the text file
- // or to the printer
- FDocStarted:=False;
- FreeAndNil(FCanvas);
- end;
- Function TPostScript.GetCreator : String;
- begin
- If (FCreator='') then
- Result:=ClassName
- else
- Result:=FCreator;
- end;
- Procedure TPostScript.SetStream (Value : TStream);
- begin
- if (FStream<>Value) then
- begin
- If (FStream<>Nil) and FDocStarted then
- EndDoc;
- FStream:=Value;
- FDocStarted:=False;
- end;
- end;
- Procedure TPostScript.CheckStream;
- begin
- If Not Assigned(FStream) then
- Raise Exception.Create(SErrNoStreamAssigned);
- end;
- { TPSPen }
- procedure TPSPen.SetPattern(const AValue: TPSPattern);
- begin
- if FPattern<>AValue then
- begin
- FPattern:=AValue;
- // NotifyCanvas;
- end;
- end;
- destructor TPSPen.Destroy;
- begin
- // Do NOT free the pattern object from here...
- inherited Destroy;
- end;
- { Return the pen definition as a postscript string }
- function TPSPen.AsString: String;
- begin
- Result:='';
- if FPattern <> nil then
- begin
- if FPattern.PaintType = ptColored then
- Result:='/Pattern setcolorspace '+FPattern.Name+' setcolor '
- else
- begin
- Result:='[/Pattern /DeviceRGB] setcolorspace '+inttostr(FPColor.Red)+' '+inttostr(FPColor.Green)+' '+
- inttostr(FPColor.Blue)+' '+FPattern.Name+' setcolor ';
- end;
- end
- else // no pattern do this:
- Result:=inttostr(FPColor.Red)+' '+inttostr(FPColor.Green)+' '+
- inttostr(FPColor.Blue)+' setrgbcolor ';
- Result := Result + format('%f',[Width])+' setlinewidth ';
- end;
- { TPSPattern }
- { Returns the pattern definition as postscript }
- function TPSPattern.GetpostScript: TStringList;
- var
- I: Integer;
- S : String;
- begin
- // If nothing in the canvas, error
- if FStream.Size=0 then
- raise exception.create('Empty pattern');
- FPostScript.Clear;
- With FPostScript do
- begin
- add('%% PATTERN '+FName);
- add('/'+FName+'proto 12 dict def '+FName+'proto begin');
- add('/PatternType 1 def');
- add(Format('/PaintType %d def',[ord(FPaintType)+1]));
- add(Format('/TilingType %d def',[ord(FTilingType)+1]));
- add('/BBox ['+inttostr(FBBox.Left)+' '+inttostr(FBBox.Top)+' '+inttostr(FBBox.Right)+' '+inttostr(FBBox.Bottom)+'] def');
- add('/XStep '+format('%f',[FXStep])+' def');
- add('/YStep '+format('%f',[FYstep])+' def');
- add('/PaintProc { begin');
- // insert the canvas
- SetLength(S,FStream.Size);
- FStream.Seek(0,soFromBeginning);
- FStream.Read(S[1],FStream.Size);
- Add(S);
- // add support for custom matrix later
- add('end } def end '+FName+'proto [1 0 0 1 0 0] makepattern /'+FName+' exch def');
- add('%% END PATTERN '+FName);
- end;
- Result := FPostScript;
- end;
- procedure TPSPattern.SetBBox(const AValue: TRect);
- begin
- { if FBBox<>AValue then
- begin
- FBBox:=AValue;
- FPatternCanvas.Height := FBBox.Bottom - FBBox.Top;
- // NotifyCanvas;
- end;
- }
- end;
- procedure TPSPattern.SetName(const AValue: String);
- begin
- FOldName := FName;
- if (FName<>AValue) then
- begin
- FName:=AValue;
- // NotifyCanvas;
- end;
- end;
- procedure TPSPattern.Changed;
- begin
- if Assigned(FOnChange) then FOnChange(Self);
- end;
- procedure TPSPattern.SetPaintType(const AValue: TPSPaintType);
- begin
- if FPaintType=AValue then exit;
- FPaintType:=AValue;
- changed;
- end;
- procedure TPSPattern.SetTilingType(const AValue: TPSTileType);
- begin
- if FTilingType=AValue then exit;
- FTilingType:=AValue;
- changed;
- end;
- procedure TPSPattern.SetXStep(const AValue: Real);
- begin
- if FXStep=AValue then exit;
- FXStep:=AValue;
- changed;
- end;
- procedure TPSPattern.SetYStep(const AValue: Real);
- begin
- if FYStep=AValue then exit;
- FYStep:=AValue;
- changed;
- end;
- constructor TPSPattern.Create;
- begin
- FPostScript := TStringList.Create;
- FPaintType := ptColored;
- FTilingType := ttConstant;
- FStream:=TmemoryStream.Create;
- FPatternCanvas := TPostScriptCanvas.Create(FStream);
- FName := 'Pattern1';
- end;
- destructor TPSPattern.Destroy;
- begin
- FPostScript.Free;
- FPatternCanvas.Free;
- FStream.Free;
- inherited Destroy;
- end;
- { ---------------------------------------------------------------------
- TPSBrush
- ---------------------------------------------------------------------}
- Function TPSBrush.GetAsString : String;
- begin
- Result:='';
- end;
- end.
|