4
License: The same modified LGPL as the Free Pascal RTL
5
See the file COPYING.modifiedLGPL for more details
7
AUTHORS: Felipe Monteiro de Carvalho
9
Documentation: http://www.tailrecursive.org/postscript/postscript.html
11
Good reference: http://atrey.karlin.mff.cuni.cz/~milanek/PostScript/Reference/PSL2e.html
13
unit epsvectorialreader;
17
{.$define FPVECTORIALDEBUG_PATHS}
18
{.$define FPVECTORIALDEBUG_COLORS}
19
{.$define FPVECTORIALDEBUG_ROLL}
20
{.$define FPVECTORIALDEBUG_CODEFLOW}
21
{.$define FPVECTORIALDEBUG_INDEX}
22
{.$define FPVECTORIALDEBUG_DICTIONARY}
23
{.$define FPVECTORIALDEBUG_CONTROL}
24
{.$define FPVECTORIALDEBUG_ARITHMETIC}
25
{.$define FPVECTORIALDEBUG_CLIP_REGION}
30
Classes, SysUtils, Math, contnrs,
32
fpvectorial, fpvutils;
35
TPSTokenType = (ttComment, ttFloat);
37
TPSTokens = TFPList;// TPSToken;
44
Line: Integer; // To help debugging
45
function Duplicate: TPSToken; virtual;
48
TCommentToken = class(TPSToken)
53
TProcedureToken = class(TPSToken)
54
Levels: Integer; // Used to count groups inside groups and find the end of a top-level group
58
destructor Destroy; override;
61
TETType = (ettNamedElement, ettOperand, ettOperator, ettDictionary);
65
TExpressionToken = class(TPSToken)
68
function IsExpressionOperand: Boolean;
69
procedure PrepareFloatValue;
70
function Duplicate: TPSToken; override;
73
TPostScriptScannerState = (ssSearchingToken, ssInComment, ssInDefinition, ssInGroup, ssInExpressionElement);
80
TranslateX, TranslateY: Double;
81
ScaleX, ScaleY: Double; // not used currently
84
OverPrint: Boolean; // not used currently
88
function Duplicate: TGraphicState;
97
constructor Create(ACurLine: Integer = -1);
98
destructor Destroy; override;
99
procedure ReadFromStream(AStream: TStream);
100
procedure DebugOut();
101
function IsValidPostScriptChar(AChar: Byte): Boolean;
102
function IsPostScriptSpace(AChar: Byte): Boolean;
103
function IsEndOfLine(ACurChar: Byte; AStream: TStream): Boolean;
106
{ TvEPSVectorialReader }
108
TvEPSVectorialReader = class(TvCustomVectorialReader)
111
GraphicStateStack: TObjectStack; // TGraphicState
112
Dictionary: TStringList;
114
CurrentGraphicState: TGraphicState;
116
procedure DebugStack();
118
procedure RunPostScript(ATokens: TPsTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument);
120
procedure ExecuteProcedureToken(AToken: TProcedureToken; AData: TvVectorialPage; ADoc: TvVectorialDocument);
121
procedure ExecuteOperatorToken(AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument);
122
function ExecuteArithmeticAndMathOperator(AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
123
function ExecutePathConstructionOperator(AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
124
function ExecuteGraphicStateOperatorsDI(AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
125
function ExecuteGraphicStateOperatorsDD(AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
126
function ExecuteDictionaryOperators(AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
127
function ExecuteMiscellaneousOperators(AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
128
function ExecuteStackManipulationOperator(AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
129
function ExecuteControlOperator(AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
130
function ExecutePaintingOperator(AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
131
function ExecuteDeviceSetupAndOutputOperator(AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
132
function ExecuteArrayOperator(AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
133
function ExecuteStringOperator(AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
135
procedure PostScriptCoordsToFPVectorialCoords(AParam1, AParam2: TPSToken; var APosX, APosY: Double);
136
function DictionarySubstituteOperator(ADictionary: TStringList; var ACurToken: TPSToken): Boolean;
138
{ General reading methods }
139
Tokenizer: TPSTokenizer;
140
constructor Create; override;
141
Destructor Destroy; override;
142
procedure ReadFromStream(AStream: TStream; AData: TvVectorialDocument); override;
148
TStackAccess = class(TObjectStack)
152
FPointSeparator: TFormatSettings;
156
function TGraphicState.Duplicate: TGraphicState;
158
Result := TGraphicState(Self.ClassType.Create);
159
Result.Color := Color;
160
Result.TranslateX := TranslateX;
161
Result.TranslateY := TranslateY;
162
Result.ScaleX := ScaleX;
163
Result.ScaleY := ScaleY;
164
Result.ClipPath := ClipPath;
165
Result.ClipMode := ClipMode;
166
Result.OverPrint := OverPrint;
167
Result.PenWidth := PenWidth;
172
function TPSToken.Duplicate: TPSToken;
174
Result := TPSToken(Self.ClassType.Create);
175
Result.StrValue := StrValue;
176
Result.FloatValue := FloatValue;
177
Result.IntValue := IntValue;
183
constructor TProcedureToken.Create;
187
Childs := TPSTokens.Create;
190
destructor TProcedureToken.Destroy;
199
function TExpressionToken.IsExpressionOperand: Boolean;
201
if StrValue = '' then Exit(False);
202
Result := StrValue[1] in ['0'..'9','-'];
205
procedure TExpressionToken.PrepareFloatValue;
207
//if not IsExpressionOperand() then Exit;
208
if ETType <> ettOperand then Exit; // faster, because this field should already be filled
210
FloatValue := StrToFloat(StrValue, FPointSeparator);
213
function TExpressionToken.Duplicate: TPSToken;
215
Result:=inherited Duplicate;
216
TExpressionToken(Result).ETType := ETType;
219
{$DEFINE FPVECTORIALDEBUG}
223
// ACurLine < 0 indicates that we should use the line of this list of strings
224
// else we use ACurLine
225
constructor TPSTokenizer.Create(ACurLine: Integer);
228
Tokens := TPSTokens.Create;
229
FCurLine := ACurLine;
232
destructor TPSTokenizer.Destroy;
238
{@@ Rules for parsing PostScript files:
240
* Coments go from the first occurence of % outside a line to the next new line
241
* The only accepted characters are printable ASCII ones, plus spacing ASCII chars
242
See IsValidPostScriptChar about that
244
procedure TPSTokenizer.ReadFromStream(AStream: TStream);
248
CurLine: Integer = 1;
249
State: TPostScriptScannerState = ssSearchingToken;
250
CommentToken: TCommentToken;
251
ProcedureToken: TProcedureToken;
252
ExpressionToken: TExpressionToken;
254
lIsEndOfLine: Boolean;
256
while AStream.Position < AStream.Size do
258
CurChar := Char(AStream.ReadByte());
259
// {$ifdef FPVECTORIALDEBUG}
260
// WriteLn(Format('Obtained token %s', [CurChar]));
262
if not IsValidPostScriptChar(Byte(CurChar)) then
263
raise Exception.Create('[TPSTokenizer.ReadFromStream] Invalid char: ' + IntToHex(Byte(CurChar), 2));
265
lIsEndOfLine := IsEndOfLine(Byte(CurChar), AStream);
266
if lIsEndOfLine then Inc(CurLine);
267
if FCurLine >= 0 then CurLine := FCurLine;
270
{ Searching for a token }
273
if CurChar = '%' then
275
CommentToken := TCommentToken.Create;
276
CommentToken.Line := CurLine;
277
State := ssInComment;
278
// {$ifdef FPVECTORIALDEBUG}
279
// WriteLn(Format('Starting Comment at Line %d', [CurLine]));
282
else if CurChar = '{' then
284
ProcedureToken := TProcedureToken.Create;
285
ProcedureToken.Levels := 1;
286
ProcedureToken.Line := CurLine;
289
else if CurChar in ['a'..'z','A'..'Z','0'..'9','-','/'] then
291
ExpressionToken := TExpressionToken.Create;
292
ExpressionToken.Line := CurLine;
293
ExpressionToken.StrValue := '';
294
if CurChar = '/' then
295
ExpressionToken.ETType := ettNamedElement
298
ExpressionToken.StrValue := CurChar;
299
if ExpressionToken.IsExpressionOperand() then
300
ExpressionToken.ETType := ettOperand
302
ExpressionToken.ETType := ettOperator;
304
State := ssInExpressionElement;
306
else if lIsEndOfLine then Continue
307
else if IsPostScriptSpace(Byte(CurChar)) then Continue
309
raise Exception.Create(Format('[TPSTokenizer.ReadFromStream] Unexpected char while searching for token: $%s in Line %d',
310
[IntToHex(Byte(CurChar), 2), CurLine]));
313
{ Passing by comments }
316
CommentToken.StrValue := CommentToken.StrValue + CurChar;
319
Tokens.Add(CommentToken);
320
State := ssSearchingToken;
321
// {$ifdef FPVECTORIALDEBUG}
322
// WriteLn(Format('Adding Comment "%s" at Line %d', [CommentToken.StrValue, CurLine]));
327
// Starts at { and ends in }, passing over nested groups
330
if (CurChar = '{') then ProcedureToken.Levels := ProcedureToken.Levels + 1;
331
if (CurChar = '}') then ProcedureToken.Levels := ProcedureToken.Levels - 1;
333
if ProcedureToken.Levels = 0 then
335
Tokens.Add(ProcedureToken);
336
State := ssSearchingToken;
340
// Don't add line ends, because they cause problems when outputing the debug info
341
// but in this case we need to add spaces to compensate, or else items separates only
342
// by line end might get glued together
343
if CurChar in [#10, #13] then
344
ProcedureToken.StrValue := ProcedureToken.StrValue + ' '
346
ProcedureToken.StrValue := ProcedureToken.StrValue + CurChar;
350
// Goes until a space comes, or {
351
ssInExpressionElement:
353
if IsPostScriptSpace(Byte(CurChar)) or (CurChar = '{') then
355
ExpressionToken.PrepareFloatValue();
356
Tokens.Add(ExpressionToken);
357
State := ssSearchingToken;
358
if (CurChar = '{') then AStream.Seek(-1, soFromCurrent);
361
ExpressionToken.StrValue := ExpressionToken.StrValue + CurChar;
367
// If the stream finished, there might be a token still being built
369
if State = ssInExpressionElement then
371
Tokens.Add(ExpressionToken);
375
procedure TPSTokenizer.DebugOut();
380
for i := 0 to Tokens.Count - 1 do
382
Token := TPSToken(Tokens.Items[i]);
384
if Token is TCommentToken then
386
WriteLn(Format('TCommentToken StrValue=%s', [Token.StrValue]));
388
else if Token is TProcedureToken then
390
WriteLn(Format('TProcedureToken StrValue=%s', [Token.StrValue]));
392
else if Token is TExpressionToken then
394
WriteLn(Format('TExpressionToken StrValue=%s', [Token.StrValue]));
399
{@@ Valid PostScript Chars:
401
All printable ASCII: a..zA..Z0..9 plus punctuation
403
Plus the following white spaces
406
012 0A 10 Line feed (LF)
407
014 0C 12 Form feed (FF)
408
015 0D 13 Carriage return (CR)
411
function TPSTokenizer.IsValidPostScriptChar(AChar: Byte): Boolean;
413
Result := ((AChar > 32) and (AChar < 127)) or (AChar in [0, 9, 10, 12, 13, 32]);
416
function TPSTokenizer.IsPostScriptSpace(AChar: Byte): Boolean;
418
Result := AChar in [0, 9, 10, 12, 13, 32];
421
function TPSTokenizer.IsEndOfLine(ACurChar: Byte; AStream: TStream): Boolean;
423
HasNextChar: Boolean = False;
428
if ACurChar = 13 then
430
if AStream.Position < AStream.Size then
433
NextChar := AStream.ReadByte();
434
if NextChar <> 10 then AStream.Seek(-1, soFromCurrent); // Go back if it wasnt a #13#10
439
if ACurChar = 10 then Result := True;
443
{$define FPVECTORIALDEBUG}
446
{ TvEPSVectorialReader }
448
procedure TvEPSVectorialReader.DebugStack();
453
WriteLn('====================');
454
WriteLn('Stack dump');
455
WriteLn('====================');
456
for i := 0 to TStackAccess(Stack).List.Count - 1 do
458
lToken := TPSToken(TStackAccess(Stack).List.Items[i]);
459
WriteLn(Format('Stack #%d : %s', [i, lToken.StrValue]));
463
procedure TvEPSVectorialReader.RunPostScript(ATokens: TPsTokens;
464
AData: TvVectorialPage; ADoc: TvVectorialDocument);
467
lSubstituted: Boolean;
470
{$ifdef FPVECTORIALDEBUG_CODEFLOW}
471
WriteLn('[TvEPSVectorialReader.RunPostScript] START');
475
{$ifdef FPVECTORIALDEBUG_CODEFLOW}
476
WriteLn('[TvEPSVectorialReader.RunPostScript] ExitCalled');
480
for i := 0 to ATokens.Count - 1 do
482
CurToken := TPSToken(ATokens.Items[i]);
484
{ if CurToken.StrValue = 'setrgbcolor' then
486
WriteLn('===================');
488
WriteLn('===================');
492
if CurToken is TCommentToken then
494
{$ifdef FPVECTORIALDEBUG_CODEFLOW}
495
WriteLn(Format('[TvEPSVectorialReader.RunPostScript] Type: TCommentToken Token: %s', [CurToken.StrValue]));
497
// ProcessCommentToken(CurToken as TCommentToken, AData);
501
if CurToken is TProcedureToken then
503
{$ifdef FPVECTORIALDEBUG_CODEFLOW}
504
WriteLn(Format('[TvEPSVectorialReader.RunPostScript] Type: TProcedureToken Token: %s', [CurToken.StrValue]));
506
Stack.Push(CurToken);
510
if CurToken is TExpressionToken then
512
{$ifdef FPVECTORIALDEBUG_CODEFLOW}
513
WriteLn(Format('[TvEPSVectorialReader.RunPostScript] Type: TExpressionToken Token: %s', [CurToken.StrValue]));
516
if TExpressionToken(CurToken).ETType = ettOperand then
518
Stack.Push(CurToken);
522
// Now we need to verify if the operator should be substituted in the dictionary
523
lSubstituted := DictionarySubstituteOperator(Dictionary, CurToken);
525
// Check if this is the first time that a named element appears, if yes, don't try to execute it
526
// just put it into the stack
527
if (not lSubstituted) and (TExpressionToken(CurToken).ETType = ettNamedElement) then
529
Stack.Push(CurToken);
533
if CurToken is TProcedureToken then ExecuteProcedureToken(TProcedureToken(CurToken), AData, ADoc)
534
else ExecuteOperatorToken(TExpressionToken(CurToken), AData, ADoc);
536
if ExitCalled then Break;
539
{$ifdef FPVECTORIALDEBUG_CODEFLOW}
540
WriteLn('[TvEPSVectorialReader.RunPostScript] END');
544
procedure TvEPSVectorialReader.ExecuteProcedureToken(AToken: TProcedureToken;
545
AData: TvVectorialPage; ADoc: TvVectorialDocument);
547
ProcTokenizer: TPSTokenizer;
548
lStream: TMemoryStream;
549
lOldTokens: TPSTokens;
552
{$ifdef FPVECTORIALDEBUG_CODEFLOW}
553
WriteLn('[TvEPSVectorialReader.ExecuteProcedureToken] START');
557
{$ifdef FPVECTORIALDEBUG_CODEFLOW}
558
WriteLn('[TvEPSVectorialReader.ExecuteProcedureToken] ExitCalled');
563
if not AToken.Parsed then
565
ProcTokenizer := TPSTokenizer.Create(AToken.Line);
566
lStream := TMemoryStream.Create;
568
// Copy the string to a Stream
569
for i := 1 to Length(AToken.StrValue) do
570
lStream.WriteByte(Byte(AToken.StrValue[i]));
572
// Change the Tokens so that it writes directly to AToken.Childs
573
lOldTokens := ProcTokenizer.Tokens;
574
ProcTokenizer.Tokens := AToken.Childs;
576
// Now parse the procedure code
577
lStream.Position := 0;
578
ProcTokenizer.ReadFromStream(lStream);
580
// Recover the old tokens for usage in .Free
581
ProcTokenizer.Tokens := lOldTokens;
587
AToken.Parsed := True;
590
// Now run the procedure
591
RunPostScript(AToken.Childs, AData, ADoc);
592
{$ifdef FPVECTORIALDEBUG_CODEFLOW}
593
WriteLn('[TvEPSVectorialReader.ExecuteProcedureToken] END');
597
procedure TvEPSVectorialReader.ExecuteOperatorToken(AToken: TExpressionToken;
598
AData: TvVectorialPage; ADoc: TvVectorialDocument);
600
Param1, Param2: TPSToken;
602
if AToken.StrValue = '' then raise Exception.Create('[TvEPSVectorialReader.ProcessExpressionToken] Empty operator');
604
if ExecuteDictionaryOperators(AToken, AData, ADoc) then Exit;
606
if ExecuteArithmeticAndMathOperator(AToken, AData, ADoc) then Exit;
608
if ExecutePathConstructionOperator(AToken, AData, ADoc) then Exit;
610
if ExecuteGraphicStateOperatorsDI(AToken, AData, ADoc) then Exit;
612
if ExecuteGraphicStateOperatorsDD(AToken, AData, ADoc) then Exit;
614
if ExecuteControlOperator(AToken, AData, ADoc) then Exit;
616
if ExecuteStackManipulationOperator(AToken, AData, ADoc) then Exit;
618
if ExecuteMiscellaneousOperators(AToken, AData, ADoc) then Exit;
620
if ExecutePaintingOperator(AToken, AData, ADoc) then Exit;
622
if ExecuteDeviceSetupAndOutputOperator(AToken, AData, ADoc) then Exit;
624
if ExecuteArrayOperator(AToken, AData, ADoc) then Exit;
626
if ExecuteStringOperator(AToken, AData, ADoc) then Exit;
628
// If we got here, there the command not yet implemented
629
raise Exception.Create(Format('[TvEPSVectorialReader.ProcessExpressionToken] Unknown PostScript Command "%s" in Line %d',
630
[AToken.StrValue, AToken.Line]));
634
filename access file file Open named file with specified access
636
param1 … paramn filtername filter file Establish filtered file
637
file closefile – Close file
638
file read int true Read one character from file
640
file int write – Write one character to file
641
file string readhexstring substring bool Read hexadecimal numbers from file into
643
file string writehexstring – Write string to file as hexadecimal
644
file string readstring substring bool Read string from file
645
file string writestring – Write string to file
646
file string readline substring bool Read line from file into string
647
file token any true Read token from file
649
file bytesavailable int Return number of bytes available to read
650
– flush – Send buffered data to standard output file
651
file flushfile – Send buffered data or read to EOF
652
file resetfile – Discard buffered characters
653
file status bool Return status of file (true = valid)
654
filename status pages bytes referenced created true
655
or false Return information about named file
656
filename run – Execute contents of named file
657
– currentfile file Return file currently being executed
658
filename deletefile – Delete named file
659
filename1 filename2 renamefile – Rename file filename1 to filename2
660
template proc scratch filenameforall – Execute proc for each file name matching
662
file position setfileposition – Set file to specified position
663
file fileposition position Return current position in file
664
string print – Write string to standard output file
665
any = – Write text representation of any to standard
667
any == – Write syntactic representation of any to
669
any1 … anyn stack any1 … anyn Print stack nondestructively using =
670
any1 … anyn pstack any1 … anyn Print stack nondestructively using ==
671
obj tag printobject – Write binary object to standard output file,
673
file obj tag writeobject – Write binary object to file, using tag
674
int setobjectformat – Set binary object format (0 = disable,
675
1 = IEEE high, 2 = IEEE low, 3 = native
676
high, 4 = native low)
677
– currentobjectformat int Return binary object format
681
key instance category defineresource instance Register named resource instance in category
682
key category undefineresource – Remove resource registration
683
key category findresource instance Return resource instance identified by key in
685
renderingintent findcolorrendering name bool Select CIE-based color rendering dictionary
687
key category resourcestatus status size true Return status of resource instance
689
template proc scratch category resourceforall – Enumerate resource instances in category
691
{ Virtual Memory Operators
693
– save save Create VM snapshot
694
save restore – Restore VM snapshot
695
bool setglobal – Set VM allocation mode (false = local,
697
– currentglobal bool Return current VM allocation mode
698
any gcheck bool Return true if any is simple or in global VM,
700
bool1 password startjob bool2 Start new job that will alter initial VM if
702
index any defineuserobject – Define user object associated with index
703
index execuserobject – Execute user object associated with index
704
index undefineuserobject – Remove user object associated with index
705
– UserObjects array Return current UserObjects array defined in
710
configurationerror setpagedevice or setdevparams request
712
dictfull No more room in dictionary
713
dictstackoverflow Too many begin operators
714
dictstackunderflow Too many end operators
715
execstackoverflow Executive stack nesting too deep
716
handleerror Called to report error information
717
interrupt External interrupt request (for example,
719
invalidaccess Attempt to violate access attribute
720
invalidexit exit not in loop
721
invalidfileaccess Unacceptable access string
722
invalidfont Invalid Font resource name or font or
724
invalidrestore Improper restore
725
ioerror Input/output error
726
limitcheck Implementation limit exceeded
727
nocurrentpoint Current point undefined
728
rangecheck Operand out of bounds
729
stackoverflow Operand stack overflow
730
stackunderflow Operand stack underflow
731
syntaxerror PostScript language syntax error
732
timeout Time limit exceeded
733
typecheck Operand of wrong type
734
undefined Name not known
735
undefinedfilename File not found
736
undefinedresource Resource instance not found
737
undefinedresult Overflow, underflow, or meaningless result
738
unmatchedmark Expected mark not on stack
739
unregistered Internal error
740
VMerror Virtual memory exhausted
744
{ Operand Stack Manipulation Operators
746
any pop – Discard top element
747
any1 any2 exch ==> any2 any1 Exchange top two elements
748
any dup ==> any any Duplicate top element
749
any1 … anyn n copy any1 … anyn any1 … anyn
750
Duplicate top n elements
751
anyn … any0 n index anyn … any0 anyn
752
Duplicate arbitrary element
753
anyn-1 … any0 n j roll any(j-1) mod n … any0 anyn-1 … anyj mod n
754
Roll n elements up j times
755
any1 … anyn clear Discard all elements
756
any1 … anyn count any1 … anyn n
757
Count elements on stack
758
– mark mark Push mark on stack
759
mark obj1 … objn cleartomark –
760
Discard elements down through mark
761
mark obj1 … objn counttomark mark obj1 … objn n
762
Count elements down to mark
764
function TvEPSVectorialReader.ExecuteStackManipulationOperator(
765
AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
767
Param1, Param2, NewToken: TPSToken;
768
lIndexN, lIndexJ: Integer;
769
lTokens: array of TPSToken;
774
// Discard top element
775
if AToken.StrValue = 'pop' then
777
Param1 := TPSToken(Stack.Pop);
780
// Exchange top two elements
781
if AToken.StrValue = 'exch' then
783
Param1 := TPSToken(Stack.Pop);
784
Param2 := TPSToken(Stack.Pop);
789
// Duplicate top element
790
if AToken.StrValue = 'dup' then
792
Param1 := TPSToken(Stack.Pop);
793
NewToken := Param1.Duplicate();
795
Stack.Push(NewToken);
798
// anyn … any0 n index anyn … any0 anyn
799
// Duplicate arbitrary element
800
if AToken.StrValue = 'index' then
802
{$ifdef FPVECTORIALDEBUG_INDEX}
803
WriteLn('[TvEPSVectorialReader.ExecuteStackManipulationOperator] index');
807
Param1 := TPSToken(Stack.Pop);
808
lIndexN := Round(Param1.FloatValue);
809
SetLength(lTokens, lIndexN+1);
811
if lIndexN < 0 then raise Exception.Create('[TvEPSVectorialReader.ExecuteStackManipulationOperator] index operator: n must be positive or zero');
813
// Unroll all elements necessary
815
for i := 0 to lIndexN do
817
lTokens[i] := TPSToken(Stack.Pop);
818
Param2 := lTokens[i];
821
raise Exception.Create(Format('[TvEPSVectorialReader.ExecuteStackManipulationOperator] Stack underflow in operation "index". Error at line %d', [AToken.Line]));
825
// Duplicate the disired token
827
NewToken := lTokens[lIndexN].Duplicate();
831
for i := lIndexN downto 0 do
833
Stack.Push(lTokens[i]);
836
// Roll the duplicated element too
838
Stack.Push(NewToken);
842
// anyn-1 … any0 n j roll any(j-1) mod n … any0 anyn-1 … anyj mod n
844
// performs a circular shift of the objects anyn-1 through any0 on the operand stack
845
// by the amount j. Positive j indicates upward motion on the stack, whereas negative
846
// j indicates downward motion.
847
// n must be a nonnegative integer and j must be an integer. roll first removes these
848
// operands from the stack; there must be at least n additional elements. It then performs
849
// a circular shift of these n elements by j positions.
850
// If j is positive, each shift consists of removing an element from the top of the stack
851
// and inserting it between element n - 1 and element n of the stack, moving all in8.2
852
// tervening elements one level higher on the stack. If j is negative, each shift consists
853
// of removing element n - 1 of the stack and pushing it on the top of the stack,
854
// moving all intervening elements one level lower on the stack.
857
// (a) (b) (c) 3 -1 roll => (b) (c) (a)
858
// (a) (b) (c) 3 1 roll => (c) (a) (b)
859
// (a) (b) (c) 3 0 roll => (a) (b) (c)
860
if AToken.StrValue = 'roll' then
862
Param1 := TPSToken(Stack.Pop);
863
Param2 := TPSToken(Stack.Pop);
864
lIndexJ := Round(Param1.FloatValue);
865
lIndexN := Round(Param2.FloatValue);
867
{$ifdef FPVECTORIALDEBUG_ROLL}
868
WriteLn(Format('[TvEPSVectorialReader] roll: N=%d J=%d', [lIndexN, lIndexJ]));
871
if lIndexN < 0 then raise Exception.Create('[TvEPSVectorialReader.ExecuteStackManipulationOperator] rool operator: n must be positive or zero');
873
if lIndexJ = 0 then Exit;
875
SetLength(lTokens, lIndexN);
877
// Unroll all elements necessary
879
for i := 0 to lIndexN-1 do
881
lTokens[i] := TPSToken(Stack.Pop());
882
Param2 := lTokens[i];
885
raise Exception.Create('[TvEPSVectorialReader.ExecuteStackManipulationOperator] nil element poped in operator index');
894
for i := lIndexJ-1 downto 0 do
896
Stack.Push(lTokens[i]);
898
for i := lIndexN-1 downto lIndexJ do
900
Stack.Push(lTokens[i]);
907
for i := lIndexN-lIndexJ-1 downto 0 do
909
Stack.Push(lTokens[i]);
911
for i := lIndexN-1 downto lIndexN-lIndexJ do
913
Stack.Push(lTokens[i]);
923
any exec – Execute arbitrary object
924
bool proc if – Execute proc if bool is true
925
bool proc1 proc2 ifelse –
926
Execute proc1 if bool is true, proc2 if false
927
initial increment limit proc for –
928
Execute proc with values from initial by steps
929
of increment to limit
930
int proc repeat – Execute proc int times
931
proc loop – Execute proc an indefinite number of times
932
– exit – Exit innermost active loop
933
– stop – Terminate stopped context
934
any stopped bool Establish context for catching stop
935
– countexecstack int Count elements on execution stack
936
array execstack subarray Copy execution stack into array
937
– quit – Terminate interpreter
938
– start – Executed at interpreter startup
939
Type, Attribute, and Conversion Operators
940
any type name Return type of any
941
any cvlit any Make object literal
942
any cvx any Make object executable
943
any xcheck bool Test executable attribute
944
array|packedarray|file|string executeonly array|packedarray|file|string
945
Reduce access to execute-only
946
array|packedarray|dict|file|string noaccess array|packedarray|dict|file|string
948
array|packedarray|dict|file|string readonly array|packedarray|dict|file|string
949
Reduce access to read-only
950
array|packedarray|dict|file|string rcheck bool Test read access
951
array|packedarray|dict|file|string wcheck bool Test write access
952
num|string cvi int Convert to integer
953
string cvn name Convert to name
954
num|string cvr real Convert to real
955
num radix string cvrs substring Convert with radix to string
956
any string cvs substring Convert to string
958
function TvEPSVectorialReader.ExecuteControlOperator(AToken: TExpressionToken;
959
AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
961
Param1, Param2, Param3, Param4, CounterToken: TPSToken;
962
NewToken: TExpressionToken;
963
FloatCounter: Double;
967
// Execute proc if bool is true
968
if AToken.StrValue = 'if' then
970
Param1 := TPSToken(Stack.Pop); // proc
971
Param2 := TPSToken(Stack.Pop); // bool
973
if not (Param1 is TProcedureToken) then
974
raise Exception.Create(Format('[TvEPSVectorialReader.ExecuteControlOperator] The operator if requires a procedure. Error at line %d', [AToken.Line]));
976
if Param2.BoolValue then ExecuteProcedureToken(TProcedureToken(Param1), AData, ADoc);
980
// Execute proc1 if bool is true, proc2 if false
981
if AToken.StrValue = 'ifelse' then
983
Param1 := TPSToken(Stack.Pop); // proc2
984
Param2 := TPSToken(Stack.Pop); // proc1
985
Param3 := TPSToken(Stack.Pop); // bool
987
if not (Param1 is TProcedureToken) then
988
raise Exception.Create(Format('[TvEPSVectorialReader.ExecuteControlOperator] The operator ifelse requires a procedure. Error at line %d', [AToken.Line]));
989
if not (Param2 is TProcedureToken) then
990
raise Exception.Create(Format('[TvEPSVectorialReader.ExecuteControlOperator] The operator ifelse requires a procedure. Error at line %d', [AToken.Line]));
992
if Param3.BoolValue then ExecuteProcedureToken(TProcedureToken(Param2), AData, ADoc)
993
else ExecuteProcedureToken(TProcedureToken(Param1), AData, ADoc);
997
// Exit innermost active loop
998
if AToken.StrValue = 'exit' then
1005
Establish context for catching stop
1007
executes any, which is typically, but not necessarily, a procedure, executable file,
1008
or executable string object. If any runs to completion normally, stopped returns false on the operand stack.
1010
If any terminates prematurely as a result of executing stop, stopped returns
1011
true on the operand stack. Regardless of the outcome, the interpreter resumes execution at the next object in normal sequence after stopped.
1012
This mechanism provides an effective way for a PostScript language program
1013
to "catch" errors or other premature terminations, retain control, and perhaps perform its own error recovery.
1016
{ ... } stopped {handleerror} if
1018
If execution of the procedure {...} causes an error,
1019
the default error-reporting procedure is invoked (by handleerror).
1020
In any event, normal execution continues at the token following the if.
1022
ERRORS: stackunderflow
1024
if AToken.StrValue = 'stopped' then
1026
{$ifdef FPVECTORIALDEBUG_CONTROL}
1027
WriteLn('[TvEPSVectorialReader.ExecuteControlOperator] stopped');
1031
Param1 := TPSToken(Stack.Pop);
1033
if not (Param1 is TProcedureToken) then
1034
raise Exception.Create(Format('[TvEPSVectorialReader.ExecuteControlOperator] The operator stopped requires a procedure. Error at line %d', [AToken.Line]));
1036
ExecuteProcedureToken(TProcedureToken(Param1), AData, ADoc);
1038
NewToken := TExpressionToken.Create;
1039
NewToken.ETType := ettOperand;
1040
NewToken.BoolValue := False;
1041
NewToken.StrValue := 'false';
1042
Stack.Push(NewToken);
1046
// Execute proc an indefinite number of times
1047
if AToken.StrValue = 'loop' then
1049
Param1 := TPSToken(Stack.Pop);
1051
if not (Param1 is TProcedureToken) then
1052
raise Exception.Create(Format('[TvEPSVectorialReader.ExecuteControlOperator] The operator loop requires a procedure. Error at line %d', [AToken.Line]));
1056
ExecuteProcedureToken(TProcedureToken(Param1), AData, ADoc);
1060
ExitCalled := False;
1067
{ initial increment limit proc for -
1069
executes proc repeatedly, passing it a sequence of values from initial
1070
by steps of increment to limit. The for operator expects initial, increment,
1071
and limit to be numbers. It maintains a temporary internal variable, known as
1072
the control variable, which it first sets to initial. Then, before each
1073
repetition, it compares the control variable with the termination value limit.
1074
If limit has not been exceeded, it pushes the control variable on the operand
1075
stack, executes proc, and adds increment to the control variable.
1077
The termination condition depends on whether increment is positive or negative.
1078
If increment is positive, for terminates when the control variable becomes
1079
greater than limit. If increment is negative, for terminates when the control
1080
variable becomes less than limit. If initial meets the termination condition,
1081
for does not execute proc at all. If proc executes the exit operator,
1082
for terminates prematurely.
1084
Usually, proc will use the value on the operand stack for some purpose.
1085
However, if proc does not remove the value, it will remain there.
1086
Successive executions of proc will cause successive values of the control
1087
variable to accumulate on the operand stack.
1090
0 1 1 4 {add} for -> 10
1091
1 2 6 { } for -> 1 3 5
1092
3 -.5 1 {-> } for -> 3.0 2.5 2.0 1.5 1.0
1094
In the first example, the value of the control variable is added to whatever
1095
is on the stack, so 1, 2, 3, and 4 are added in turn to a running sum whose
1096
initial value is 0. The second example has an empty procedure, so the
1097
successive values of the control variable are left on the stack. The
1098
last example counts backward from 3 to 1 by halves, leaving the successive
1099
values on the stack.
1101
Beware of using reals instead of integers for any of the first three operands.
1102
Most real numbers are not represented exactly. This can cause an error to
1103
accumulate in the value of the control variable, with possibly surprising results.
1104
In particular, if the difference between initial and limit is a multiple of
1105
increment, as in the third line of the example, the control variable may not
1106
achieve the limit value.
1108
ERRORS: stackoverflow stackunderflow, typecheck
1110
SEE ALSO: repeat, loop, forall, exit
1112
if AToken.StrValue = 'for' then
1114
Param1 := TPSToken(Stack.Pop);
1115
Param2 := TPSToken(Stack.Pop);
1116
Param3 := TPSToken(Stack.Pop);
1117
Param4 := TPSToken(Stack.Pop);
1119
if not (Param1 is TProcedureToken) then
1120
raise Exception.Create(Format('[TvEPSVectorialReader.ExecuteControlOperator] The operator for requires a procedure. Error at line %d', [AToken.Line]));
1122
FloatCounter := Param4.FloatValue;
1123
while FloatCounter < Param2.FloatValue do
1125
CounterToken := Param4.Duplicate();
1126
CounterToken.FloatValue := FloatCounter;
1127
Stack.Push(CounterToken);
1129
ExecuteProcedureToken(TProcedureToken(Param1), AData, ADoc);
1131
FloatCounter := FloatCounter + Param3.FloatValue;
1135
ExitCalled := False;
1142
// tests whether the operand has the executable or the literal attribute, returning true
1143
// if it is executable or false if it is literal
1144
if AToken.StrValue = 'xcheck' then
1146
// {$ifdef FPVECTORIALDEBUG_CONTROL}
1147
// WriteLn('[TvEPSVectorialReader.ExecuteControlOperator] xcheck');
1151
Param1 := TPSToken(Stack.Pop);
1153
NewToken := TExpressionToken.Create;
1154
NewToken.ETType := ettOperand;
1155
NewToken.BoolValue := (Param1 is TProcedureToken) or
1156
((Param1 is TExpressionToken) and (TExpressionToken(Param1).ETType = ettOperator));
1157
if NewToken.BoolValue then NewToken.StrValue := 'true'
1158
else NewToken.StrValue := 'false';
1159
Stack.Push(NewToken);
1165
{ Painting Operators
1167
– erasepage – Paint current page white
1168
– stroke – Draw line along current path
1169
– fill – Fill current path with current color
1170
– eofill – Fill using even-odd rule
1171
x y width height rectstroke – Define rectangular path and stroke
1172
x y width height matrix rectstroke – Define rectangular path, concatenate matrix,
1174
numarray|numstring rectstroke – Define rectangular paths and stroke
1175
numarray|numstring matrix rectstroke – Define rectangular paths, concatenate
1177
x y width height rectfill – Fill rectangular path
1178
numarray|numstring rectfill – Fill rectangular paths
1179
userpath ustroke – Interpret and stroke userpath
1180
userpath matrix ustroke – Interpret userpath, concatenate matrix, and
1182
userpath ufill – Interpret and fill userpath
1183
userpath ueofill – Fill userpath using even-odd rule
1184
dict shfill – Fill area defined by shading pattern
1185
dict image – Paint any sampled image
1186
width height bits/sample matrix datasrc image – Paint monochrome sampled image
1187
width height bits/comp matrix
1188
datasrc0 … datasrcncomp-1 multi ncomp colorimage – Paint color sampled image
1189
dict imagemask – Paint current color through mask
1190
width height polarity matrix datasrc imagemask – Paint current color through mask
1191
Insideness-Testing Operators
1192
x y infill bool Test whether (x, y) would be painted by fill
1193
userpath infill bool Test whether pixels in userpath would be
1195
x y ineofill bool Test whether (x, y) would be painted by eofill
1196
userpath ineofill bool Test whether pixels in userpath would be
1198
x y userpath inufill bool Test whether (x, y) would be painted by ufill
1200
userpath1 userpath2 inufill bool Test whether pixels in userpath1 would be
1201
painted by ufill of userpath2
1202
x y userpath inueofill bool Test whether (x, y) would be painted by
1204
userpath1 userpath2 inueofill bool Test whether pixels in userpath1 would be
1205
painted by ueofill of userpath2
1206
x y instroke bool Test whether (x, y) would be painted by
1208
x y userpath inustroke bool Test whether (x, y) would be painted by
1210
x y userpath matrix inustroke bool Test whether (x, y) would be painted by
1212
userpath1 userpath2 inustroke bool Test whether pixels in userpath1 would be
1213
painted by ustroke of userpath2
1214
userpath1 userpath2 matrix inustroke bool Test whether pixels in userpath1 would be
1215
painted by ustroke of userpath2
1216
Form and Pattern Operators
1217
pattern matrix makepattern pattern’ Create pattern instance from prototype
1218
pattern setpattern – Install pattern as current color
1219
comp1 … compn pattern setpattern – Install pattern as current color
1220
form execform – Paint form
1222
function TvEPSVectorialReader.ExecutePaintingOperator(AToken: TExpressionToken;
1223
AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
1225
Param1, Param2: TPSToken;
1229
if AToken.StrValue = 'stroke' then
1231
{$ifdef FPVECTORIALDEBUG_PATHS}
1232
WriteLn('[TvEPSVectorialReader.ExecutePaintingOperator] stroke');
1234
AData.SetPenStyle(psSolid);
1235
AData.SetBrushStyle(bsClear);
1236
AData.SetPenColor(CurrentGraphicState.Color);
1237
AData.SetClipPath(CurrentGraphicState.ClipPath, CurrentGraphicState.ClipMode);
1238
AData.SetPenWidth(CurrentGraphicState.PenWidth);
1243
if AToken.StrValue = 'eofill' then
1245
{$ifdef FPVECTORIALDEBUG_PATHS}
1246
WriteLn('[TvEPSVectorialReader.ExecutePaintingOperator] eofill');
1248
AData.SetBrushStyle(bsSolid);
1249
AData.SetPenStyle(psSolid);
1250
AData.SetClipPath(CurrentGraphicState.ClipPath, CurrentGraphicState.ClipMode);
1251
AData.SetPenWidth(CurrentGraphicState.PenWidth);
1258
{ Device Setup and Output Operators
1260
– showpage – Transmit and reset current page
1261
– copypage – Transmit current page
1262
dict setpagedevice – Install page-oriented output device
1263
– currentpagedevice dict Return current page device parameters
1264
– nulldevice – Install no-output device
1265
Glyph and Font Operators
1266
key font|cidfont definefont font|cidfont Register font|cidfont in Font resource
1268
key name|string|dict array composefont font Register composite font dictionary created
1269
from CMap and array of CIDFonts or fonts
1270
key undefinefont – Remove Font resource registration
1271
key findfont font|cidfont Return Font resource instance identified by
1273
font|cidfont scale scalefont font¢|cidfont¢ Scale font|cidfont by scale to produce
1275
font|cidfont matrix makefont font¢|cidfont¢ Transform font|cidfont by matrix to produce
1277
font|cidfont setfont – Set font or CIDFont in graphics state
1278
– rootfont font|cidfont Return last set font or CIDFont
1279
– currentfont font|cidfont Return current font or CIDFont, possibly a
1280
descendant of rootfont
1281
key scale|matrix selectfont – Set font or CIDFont given name and
1283
string show – Paint glyphs for string in current font
1284
ax ay string ashow – Add (ax , ay) to width of each glyph while
1286
cx cy char string widthshow – Add (cx , cy) to width of glyph for char while
1288
cx cy char ax ay string awidthshow – Combine effects of ashow and widthshow
1289
string numarray|numstring xshow – Paint glyphs for string using x widths in
1291
string numarray|numstring xyshow – Paint glyphs for string using x and y widths
1292
in numarray|numstring
1293
string numarray|numstring yshow – Paint glyphs for string using y widths in
1295
name|cid glyphshow – Paint glyph for character identified by
1297
string stringwidth wx wy Return width of glyphs for string in current
1299
proc string cshow – Invoke character mapping algorithm and
1301
proc string kshow – Execute proc between characters shown from
1303
– FontDirectory dict Return dictionary of Font resource instances
1304
– GlobalFontDirectory dict Return dictionary of Font resource instances
1306
– StandardEncoding array Return Adobe standard font encoding vector
1307
– ISOLatin1Encoding array Return ISO Latin-1 font encoding vector
1308
key findencoding array Find encoding vector
1309
wx wy llx lly urx ury setcachedevice – Declare cached glyph metrics
1310
w0x w0y llx lly urx ury
1311
w1x w1y vx vy setcachedevice2 – Declare cached glyph metrics
1312
wx wy setcharwidth – Declare uncached glyph metrics
1313
Interpreter Parameter Operators
1314
dict setsystemparams – Set systemwide interpreter parameters
1315
– currentsystemparams dict Return systemwide interpreter parameters
1316
dict setuserparams – Set per-context interpreter parameters
1317
– currentuserparams dict Return per-context interpreter parameters
1318
string dict setdevparams – Set parameters for input/output device
1319
string currentdevparams dict Return device parameters
1320
int vmreclaim – Control garbage collector
1321
int setvmthreshold – Control garbage collector
1322
– vmstatus level used maximum
1324
– cachestatus bsize bmax msize mmax csize cmax blimit
1325
Return font cache status and parameters
1326
int setcachelimit – Set maximum bytes in cached glyph
1327
mark size lower upper setcacheparams – Set font cache parameters
1328
– currentcacheparams mark size lower upper
1329
Return current font cache parameters
1330
mark blimit setucacheparams – Set user path cache parameters
1331
– ucachestatus mark bsize bmax rsize rmax blimit
1332
Return user path cache status and
1335
function TvEPSVectorialReader.ExecuteDeviceSetupAndOutputOperator(
1336
AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
1338
Param1, Param2: TPSToken;
1342
if AToken.StrValue = 'showpage' then
1350
int array array Create array of length int
1351
– [ mark Start array construction
1352
mark obj0 … objn-1 ] array End array construction
1353
array length int Return number of elements in array
1354
array index get any Return array element indexed by index
1355
array index any put – Put any into array at index
1356
array index count getinterval subarray Return subarray of array starting at index for
1358
array1 index array2|packedarray2 putinterval – Replace subarray of array1 starting at index
1359
by array2|packedarray2
1360
any0 … anyn-1 array astore array Pop elements from stack into array
1361
array aload any0 … anyn-1 array Push all elements of array on stack
1362
array1 array2 copy subarray2 Copy elements of array1 to initial subarray of
1364
array proc forall – Execute proc for each element of array
1365
Packed Array Operators
1366
any0 … anyn-1 n packedarray packedarray Create packed array consisting of n elements
1368
bool setpacking – Set array packing mode for { … } syntax
1369
(true = packed array)
1370
– currentpacking bool Return array packing mode
1371
packedarray length int Return number of elements in packedarray
1372
packedarray index get any Return packedarray element indexed by index
1373
packedarray index count getinterval subarray Return subarray of packedarray starting at
1374
index for count elements
1375
packedarray aload any0 … anyn-1 packedarray
1376
Push all elements of packedarray on stack
1377
packedarray1 array2 copy subarray2 Copy elements of packedarray1 to initial
1379
packedarray proc forall – Execute proc for each element of packedarray
1381
function TvEPSVectorialReader.ExecuteArrayOperator(AToken: TExpressionToken;
1382
AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
1390
int string string Create string of length int
1391
string length int Return number of elements in string
1392
string index get int Return string element indexed by index
1393
string index int put – Put int into string at index
1394
string index count getinterval substring Return substring of string starting at index
1396
string1 index string2 putinterval – Replace substring of string1 starting at index
1398
string1 string2 copy substring2 Copy elements of string1 to initial substring
1400
string proc forall – Execute proc for each element of string
1401
string seek anchorsearch post match true Search for seek at start of string
1403
string seek search post match pre true Search for seek in string
1405
string token post any true Read token from start of string
1407
Relational, Boolean, and Bitwise Operators
1408
any1 any2 eq bool Test equal
1409
any1 any2 ne bool Test not equal
1410
num1|str1 num2|str2 ge bool Test greater than or equal
1411
num1|str1 num2|str2 gt bool Test greater than
1412
num1|str1 num2|str2 le bool Test less than or equal
1413
num1|str1 num2|str2 lt bool Test less than
1414
bool1|int1 bool2|int2 and bool3|int3 Perform logical|bitwise and
1415
bool1|int1 not bool2|int2 Perform logical|bitwise not
1416
bool1|int1 bool2|int2 or bool3|int3 Perform logical|bitwise inclusive or
1417
bool1|int1 bool2|int2 xor bool3|int3 Perform logical|bitwise exclusive or
1418
– true true Return boolean value true
1419
– false false Return boolean value false
1420
int1 shift bitshift int2 Perform bitwise shift of int1 (positive is left)
1422
function TvEPSVectorialReader.ExecuteStringOperator(AToken: TExpressionToken;
1423
AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
1425
Param1, Param2: TPSToken;
1426
NewToken: TExpressionToken;
1430
// any1 any2 ne bool Test not equal
1431
if AToken.StrValue = 'ne' then
1433
Param1 := TPSToken(Stack.Pop);
1434
Param2 := TPSToken(Stack.Pop);
1436
NewToken := TExpressionToken.Create;
1437
NewToken.ETType := ettOperand;
1438
NewToken.BoolValue := Param1.StrValue = Param2.StrValue;
1439
if NewToken.BoolValue then NewToken.StrValue := 'true'
1440
else NewToken.StrValue := 'false';
1441
Stack.Push(NewToken);
1445
// num1 num2 lt bool
1446
// string1 string2 lt bool
1447
// pops two objects from the operand stack and pushes true if the first operand is less
1448
// than the second, or false otherwise. If both operands are numbers, lt compares
1449
// their mathematical values. If both operands are strings, lt compares them element
1450
// by element, treating the elements as integers in the range 0 to 255, to determine
1451
// whether the first string is lexically less than the second. If the operands are of
1452
// other types or one is a string and the other is a number, a typecheck error occurs.
1453
if AToken.StrValue = 'lt' then
1455
Param1 := TPSToken(Stack.Pop);
1456
Param2 := TPSToken(Stack.Pop);
1458
NewToken := TExpressionToken.Create;
1459
NewToken.ETType := ettOperand;
1460
NewToken.BoolValue := Param1.FloatValue > Param2.FloatValue;
1461
if NewToken.BoolValue then NewToken.StrValue := 'true'
1462
else NewToken.StrValue := 'false';
1463
Stack.Push(NewToken);
1469
{ Arithmetic and Math Operators
1471
num1 num2 add sum Return num1 plus num2
1472
num1 num2 div quotient Return num1 divided by num2
1473
int1 int2 idiv quotient Return int1 divided by int2
1474
int1 int2 mod remainder Return remainder after dividing int1 by int2
1475
num1 num2 mul product Return num1 times num2
1476
num1 num2 sub difference Return num1 minus num2
1477
num1 abs num2 Return absolute value of num1
1478
num1 neg num2 Return negative of num1
1479
num1 ceiling num2 Return ceiling of num1
1480
num1 floor num2 Return floor of num1
1481
num1 round num2 Round num1 to nearest integer
1482
num1 truncate num2 Remove fractional part of num1
1483
num sqrt real Return square root of num
1484
num den atan angle Return arctangent of num/den in degrees
1485
angle cos real Return cosine of angle degrees
1486
angle sin real Return sine of angle degrees
1487
base exponent exp real Raise base to exponent power
1488
num ln real Return natural logarithm (base e)
1489
num log real Return common logarithm (base 10)
1490
– rand int Generate pseudo-random integer
1491
int srand – Set random number seed
1492
– rrand int Return random number seed
1494
function TvEPSVectorialReader.ExecuteArithmeticAndMathOperator(
1495
AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
1497
Param1, Param2: TPSToken;
1498
NewToken: TExpressionToken;
1503
// Param2 Param1 div ==> (Param2 div Param1)
1504
if AToken.StrValue = 'div' then
1506
Param1 := TPSToken(Stack.Pop);
1507
Param2 := TPSToken(Stack.Pop);
1508
NewToken := TExpressionToken.Create;
1509
NewToken.ETType := ettOperand;
1510
NewToken.FloatValue := Param2.FloatValue / Param1.FloatValue;
1511
NewToken.StrValue := FloatToStr(NewToken.FloatValue);
1512
Stack.Push(NewToken);
1513
{$ifdef FPVECTORIALDEBUG_ARITHMETIC}
1514
WriteLn(Format('[TvEPSVectorialReader.ExecuteArithmeticAndMathOperator] %f %f div %f', [Param2.FloatValue, Param1.FloatValue, NewToken.FloatValue]));
1519
// Param2 Param1 mul ==> (Param2 mul Param1)
1520
if AToken.StrValue = 'mul' then
1522
Param1 := TPSToken(Stack.Pop);
1523
Param2 := TPSToken(Stack.Pop);
1524
NewToken := TExpressionToken.Create;
1525
NewToken.ETType := ettOperand;
1526
NewToken.FloatValue := Param2.FloatValue * Param1.FloatValue;
1527
NewToken.StrValue := FloatToStr(NewToken.FloatValue);
1528
Stack.Push(NewToken);
1531
// num1 num2 sub difference Return num1 minus num2
1532
if AToken.StrValue = 'sub' then
1534
NewToken := TExpressionToken.Create;
1535
NewToken.ETType := ettOperand;
1536
Param1 := TPSToken(Stack.Pop); // num2
1537
Param2 := TPSToken(Stack.Pop); // num1
1538
NewToken.FloatValue := Param2.FloatValue - Param1.FloatValue;
1539
NewToken.StrValue := FloatToStr(NewToken.FloatValue);
1540
Stack.Push(NewToken);
1545
{ Path Construction Operators
1547
– newpath – Initialize current path to be empty
1548
– currentpoint x y Return current point coordinates
1549
x y moveto – Set current point to (x, y)
1550
dx dy rmoveto – Perform relative moveto
1551
x y lineto – Append straight line to (x, y)
1552
dx dy rlineto – Perform relative lineto
1553
x y r angle1 angle2 arc – Append counterclockwise arc
1554
x y r angle1 angle2 arcn – Append clockwise arc
1555
x1 y1 x2 y2 r arct – Append tangent arc
1556
x1 y1 x2 y2 r arcto xt1 yt1 xt2 yt2 Append tangent arc
1557
x1 y1 x2 y2 x3 y3 curveto – Append Bézier cubic section
1558
dx1 dy1 dx2 dy2 dx3 dy3 rcurveto – Perform relative curveto
1559
– closepath – Connect subpath back to its starting point
1560
– flattenpath – Convert curves to sequences of straight lines
1561
– reversepath – Reverse direction of current path
1562
– strokepath – Compute outline of stroked path
1563
userpath ustrokepath – Compute outline of stroked userpath
1564
userpath matrix ustrokepath – Compute outline of stroked userpath
1565
string bool charpath – Append glyph outline to current path
1566
userpath uappend – Interpret userpath and append to current
1568
– clippath – Set current path to clipping path
1569
llx lly urx ury setbbox – Set bounding box for current path
1570
– pathbbox llx lly urx ury Return bounding box of current path
1571
move line curve close pathforall – Enumerate current path
1572
bool upath userpath Create userpath for current path; include
1573
ucache if bool is true
1574
– initclip – Set clipping path to device default
1575
– clip – Clip using nonzero winding number rule
1576
– eoclip – Clip using even-odd rule
1577
x y width height rectclip – Clip with rectangular path
1578
numarray|numstring rectclip – Clip with rectangular paths
1579
– ucache – Declare that user path is to be cached
1581
function TvEPSVectorialReader.ExecutePathConstructionOperator(
1582
AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
1584
Param1, Param2, Param3, Param4, Param5, Param6: TPSToken;
1585
PosX, PosY, PosX2, PosY2, PosX3, PosY3, BaseX, BaseY: Double;
1587
P1, P2, P3, P4: T3DPoint;
1588
startAngle, endAngle: Double;
1592
// – newpath – Initialize current path to be empty
1593
if AToken.StrValue = 'newpath' then
1595
{$ifdef FPVECTORIALDEBUG_PATHS}
1596
WriteLn('[TvEPSVectorialReader.ExecutePathConstructionOperator] newpath');
1598
// AData.SetClipPath(CurrentGraphicState.ClipPath, CurrentGraphicState.ClipMode);
1599
// AData.SetPenWidth(CurrentGraphicState.PenWidth);
1600
// AData.SetClipPath(CurrentGraphicState.ClipPath, CurrentGraphicState.ClipMode);
1601
AData.SetBrushStyle(bsClear);
1602
AData.SetPenStyle(psClear);
1606
AData.SetPenColor(CurrentGraphicState.Color);
1607
AData.SetBrushColor(CurrentGraphicState.Color);
1608
AData.SetPenStyle(psClear);
1612
// Param2 Param1 moveto - ===> moveto(X=Param2, Y=Param1);
1613
if AToken.StrValue = 'moveto' then
1615
Param1 := TPSToken(Stack.Pop);
1616
Param2 := TPSToken(Stack.Pop);
1617
PostScriptCoordsToFPVectorialCoords(Param1, Param2, PosX, PosY);
1618
PosX2 := PosX + CurrentGraphicState.TranslateX;
1619
PosY2 := PosY + CurrentGraphicState.TranslateY;
1620
{$ifdef FPVECTORIALDEBUG_PATHS}
1621
WriteLn(Format('[TvEPSVectorialReader.ExecutePathConstructionOperator] moveto %f, %f CurrentGraphicState.Translate %f, %f Resulting Value %f, %f',
1622
[PosX, PosY, CurrentGraphicState.TranslateX, CurrentGraphicState.TranslateY, PosX2, PosY2]));
1624
AData.AddMoveToPath(PosX2, PosY2);
1628
// x y lineto – Append straight line to (x, y)
1629
if AToken.StrValue = 'lineto' then
1631
Param1 := TPSToken(Stack.Pop);
1632
Param2 := TPSToken(Stack.Pop);
1633
PostScriptCoordsToFPVectorialCoords(Param1, Param2, PosX, PosY);
1634
PosX2 := PosX + CurrentGraphicState.TranslateX;
1635
PosY2 := PosY + CurrentGraphicState.TranslateY;
1636
{$ifdef FPVECTORIALDEBUG_PATHS}
1637
WriteLn(Format('[TvEPSVectorialReader.ExecutePathConstructionOperator] lineto %f, %f Resulting value %f, %f', [PosX, PosY, PosX2, PosY2]));
1639
AData.AddLineToPath(PosX2, PosY2);
1643
// dx dy rlineto – Perform relative lineto
1644
if AToken.StrValue = 'rlineto' then
1646
Param1 := TPSToken(Stack.Pop);
1647
Param2 := TPSToken(Stack.Pop);
1648
PostScriptCoordsToFPVectorialCoords(Param1, Param2, PosX, PosY);
1649
AData.GetCurrentPathPenPos(BaseX, BaseY);
1650
PosX2 := PosX + BaseX;
1651
PosY2 := PosY + BaseY;
1652
{$ifdef FPVECTORIALDEBUG_PATHS}
1653
WriteLn(Format('[TvEPSVectorialReader.ExecutePathConstructionOperator] rlineto %f, %f Base %f, %f Resulting %f, %f',
1654
[PosX, PosY, BaseX, BaseY, PosX2, PosY2]));
1656
AData.AddLineToPath(PosX2, PosY2);
1659
// dx1 dy1 dx2 dy2 dx3 dy3 rcurveto –
1660
// (relative curveto) appends a section of a cubic Bézier curve to the current path in
1661
// the same manner as curveto. However, the operands are interpreted as relative
1662
// displacements from the current point rather than as absolute coordinates. That is,
1663
// rcurveto constructs a curve between the current point (x0, y0) and the endpoint
1664
// (x0 + dx3, y0 + dy3), using (x0 + dx1, y0 + dy1) and (x0 + dx2, y0 + dy2) as the Bézier
1665
// control points. In all other respects, the behavior of rcurveto is identical to that of
1667
if AToken.StrValue = 'rcurveto' then
1669
Param1 := TPSToken(Stack.Pop); // dy3
1670
Param2 := TPSToken(Stack.Pop); // dx3
1671
Param3 := TPSToken(Stack.Pop); // dy2
1672
Param4 := TPSToken(Stack.Pop); // dx2
1673
Param5 := TPSToken(Stack.Pop); // dy1
1674
Param6 := TPSToken(Stack.Pop); // dx1
1675
PostScriptCoordsToFPVectorialCoords(Param5, Param6, PosX, PosY);
1676
PostScriptCoordsToFPVectorialCoords(Param3, Param4, PosX2, PosY2);
1677
PostScriptCoordsToFPVectorialCoords(Param1, Param2, PosX3, PosY3);
1678
AData.GetCurrentPathPenPos(BaseX, BaseY);
1679
// First move to the start of the arc
1680
// BaseX := BaseX + CurrentGraphicState.TranslateX;
1681
// BaseY := BaseY + CurrentGraphicState.TranslateY;
1682
{$ifdef FPVECTORIALDEBUG_PATHS}
1683
WriteLn(Format('[TvEPSVectorialReader.ExecutePathConstructionOperator] rcurveto translate %f, %f',
1684
[CurrentGraphicState.TranslateX, CurrentGraphicState.TranslateY]));
1685
WriteLn(Format('[TvEPSVectorialReader.ExecutePathConstructionOperator] rcurveto from %f, %f via %f, %f %f, %f to %f, %f',
1686
[BaseX, BaseY, BaseX + PosX, BaseY + PosY, BaseX + PosX2, BaseY + PosY2, BaseX + PosX3, BaseY + PosY3]));
1688
AData.AddBezierToPath(BaseX + PosX, BaseY + PosY, BaseX + PosX2, BaseY + PosY2, BaseX + PosX3, BaseY + PosY3);
1693
// Don't do anything, because a stroke or fill might come after closepath
1694
// and newpath will be called after stroke and fill anyway
1696
if AToken.StrValue = 'closepath' then
1698
{$ifdef FPVECTORIALDEBUG_PATHS}
1699
WriteLn('[TvEPSVectorialReader.ExecutePathConstructionOperator] closepath');
1705
x y r angle1 angle2 arc – Append counterclockwise arc
1707
Arcs in PostScript are described by a center (x, y), a radius r and
1708
two angles, angle1 for the start and angle2 for the end. These two
1709
angles are relative to the X axis growing to the right (positive direction).
1712
if AToken.StrValue = 'arc' then
1714
Param1 := TPSToken(Stack.Pop); // angle2
1715
Param2 := TPSToken(Stack.Pop); // angle1
1716
Param3 := TPSToken(Stack.Pop); // r
1717
Param4 := TPSToken(Stack.Pop); // y
1718
Param5 := TPSToken(Stack.Pop); // x
1719
PostScriptCoordsToFPVectorialCoords(Param4, Param5, PosX, PosY);
1720
PosX := PosX + CurrentGraphicState.TranslateX;
1721
PosY := PosY + CurrentGraphicState.TranslateY;
1722
startAngle := Param2.FloatValue * Pi / 180;
1723
endAngle := Param1.FloatValue * Pi / 180;
1725
// If the angle is too big we need to use two beziers
1726
if endAngle - startAngle > Pi then
1728
CircularArcToBezier(PosX, PosY, Param3.FloatValue, startAngle, endAngle - Pi, P1, P2, P3, P4);
1729
AData.AddMoveToPath(P1.X, P1.Y);
1730
AData.AddBezierToPath(P2.X, P2.Y, P3.X, P3.Y, P4.X, P4.Y);
1732
CircularArcToBezier(PosX, PosY, Param3.FloatValue, startAngle + Pi, endAngle, P1, P2, P3, P4);
1733
AData.AddMoveToPath(P1.X, P1.Y);
1734
AData.AddBezierToPath(P2.X, P2.Y, P3.X, P3.Y, P4.X, P4.Y);
1738
CircularArcToBezier(PosX, PosY, Param3.FloatValue, startAngle, endAngle, P1, P2, P3, P4);
1739
AData.AddMoveToPath(P1.X, P1.Y);
1740
AData.AddBezierToPath(P2.X, P2.Y, P3.X, P3.Y, P4.X, P4.Y);
1742
{$ifdef FPVECTORIALDEBUG_PATHS}
1743
WriteLn(Format('[TvEPSVectorialReader.ExecutePathConstructionOperator] arc X,Y=%f, %f Resulting X,Y=%f, %f R=%f Angles Start,End=%f,%f',
1744
[Param5.FloatValue, Param4.FloatValue, PosX, PosY, Param3.FloatValue, Param2.FloatValue, Param1.FloatValue]));
1748
// – eoclip – Clip using even-odd rule
1750
// intersects the inside of the current clipping path with the inside
1751
// of the current path to produce a new, smaller current clipping path.
1752
// The inside of the current path is determined by the even-odd rule,
1753
// while the inside of the current clipping path is determined by whatever
1754
// rule was used at the time that path was created.
1756
// Except for the choice of insideness rule, the behavior of eoclip is identical to that of clip.
1758
// ERRORS: limitcheck
1760
if AToken.StrValue = 'eoclip' then
1762
{$ifdef FPVECTORIALDEBUG_PATHS}
1763
WriteLn('[TvEPSVectorialReader.ExecutePathConstructionOperator] eoclip');
1765
{$ifndef FPVECTORIALDEBUG_CLIP_REGION}
1766
AData.SetPenStyle(psClear);
1768
AData.SetBrushStyle(bsClear);
1770
CurrentGraphicState.ClipPath := AData.GetEntity(AData.GetEntitiesCount()-1) as TPath;
1771
CurrentGraphicState.ClipMode := vcmEvenOddRule;
1776
{ Graphics State Operators (Device-Independent)
1778
– gsave – Push graphics state
1779
– grestore – Pop graphics state
1780
– clipsave – Push clipping path
1781
– cliprestore – Pop clipping path
1782
– grestoreall – Pop to bottommost graphics state
1783
– initgraphics – Reset graphics state parameters
1784
– gstate gstate Create graphics state object
1785
gstate setgstate – Set graphics state from gstate
1786
gstate currentgstate gstate Copy current graphics state into gstate
1787
num setlinewidth – Set line width
1788
– currentlinewidth num Return current line width
1789
int setlinecap – Set shape of line ends for stroke (0 = butt,
1790
1 = round, 2 = square)
1791
– currentlinecap int Return current line cap
1792
int setlinejoin – Set shape of corners for stroke (0 = miter,
1793
1 = round, 2 = bevel)
1794
– currentlinejoin int Return current line join
1795
num setmiterlimit – Set miter length limit
1796
– currentmiterlimit num Return current miter limit
1797
bool setstrokeadjust – Set stroke adjustment (false = disable,
1799
– currentstrokeadjust bool Return current stroke adjustment
1800
array offset setdash – Set dash pattern for stroking
1801
– currentdash array offset Return current dash pattern
1802
array|name setcolorspace – Set color space
1803
– currentcolorspace array Return current color space
1804
comp1 … compn setcolor – Set color components
1805
pattern setcolor – Set colored tiling pattern as current color
1806
comp1 … compn pattern setcolor – Set uncolored tiling pattern as current color
1807
– currentcolor comp1 … compn Return current color components
1808
num setgray – Set color space to DeviceGray and color to
1809
specified gray value (0 = black, 1 = white)
1810
– currentgray num Return current color as gray value
1811
hue saturation brightness sethsbcolor – Set color space to DeviceRGB and color to
1812
specified hue, saturation, brightness
1813
– currenthsbcolor hue saturation brightness
1814
Return current color as hue, saturation,
1816
red green blue setrgbcolor – Set color space to DeviceRGB and color to
1817
specified red, green, blue
1818
– currentrgbcolor red green blue Return current color as red, green, blue
1819
cyan magenta yellow black setcmykcolor – Set color space to DeviceCMYK and color to
1820
specified cyan, magenta, yellow, black
1821
– currentcmykcolor cyan magenta yellow black
1822
Return current color as cyan, magenta,
1825
function TvEPSVectorialReader.ExecuteGraphicStateOperatorsDI(
1826
AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
1828
Param1, Param2, Param3: TPSToken;
1829
lRed, lGreen, lBlue: Double;
1830
lGraphicState: TGraphicState;
1834
// – gsave – Push graphics state
1835
if AToken.StrValue = 'gsave' then
1837
GraphicStateStack.Push(CurrentGraphicState.Duplicate());
1838
{$ifdef FPVECTORIALDEBUG_PATHS}
1839
WriteLn('[TvEPSVectorialReader.ExecuteGraphicStateOperatorsDI] gsave');
1843
// – grestore - Pop graphics state
1844
if AToken.StrValue = 'grestore' then
1846
lGraphicState := TGraphicState(GraphicStateStack.Pop());
1847
if lGraphicState = nil then raise Exception.Create('[TvEPSVectorialReader.ExecuteGraphicStateOperatorsDI] grestore: call to grestore without corresponding gsave');
1848
CurrentGraphicState.Free;
1849
CurrentGraphicState := lGraphicState;
1850
{$ifdef FPVECTORIALDEBUG_PATHS}
1851
WriteLn('[TvEPSVectorialReader.ExecuteGraphicStateOperatorsDI] grestore');
1855
// num setlinewidth – Set line width
1856
if AToken.StrValue = 'setlinewidth' then
1858
Param1 := TPSToken(Stack.Pop);
1859
CurrentGraphicState.PenWidth := Round(Param1.FloatValue);
1862
// int setlinecap – Set shape of line ends for stroke (0 = butt,
1863
// 1 = round, 2 = square)
1864
if AToken.StrValue = 'setlinecap' then
1866
Param1 := TPSToken(Stack.Pop);
1869
// int setlinejoin – Set shape of corners for stroke (0 = miter,
1870
// 1 = round, 2 = bevel)
1871
if AToken.StrValue = 'setlinejoin' then
1873
Param1 := TPSToken(Stack.Pop);
1876
// red green blue setrgbcolor –
1877
// sets the current color space in the graphics state to DeviceRGB and the current color
1878
// to the component values specified by red, green, and blue. Each component
1879
// must be a number in the range 0.0 to 1.0. If any of the operands is outside this
1880
// range, the nearest valid value is substituted without error indication.
1881
if AToken.StrValue = 'setrgbcolor' then
1883
Param1 := TPSToken(Stack.Pop);
1884
Param2 := TPSToken(Stack.Pop);
1885
Param3 := TPSToken(Stack.Pop);
1887
lRed := EnsureRange(Param3.FloatValue, 0, 1);
1888
lGreen := EnsureRange(Param2.FloatValue, 0, 1);
1889
lBlue := EnsureRange(Param1.FloatValue, 0, 1);
1891
CurrentGraphicState.Color.Red := Round(lRed * $FFFF);
1892
CurrentGraphicState.Color.Green := Round(lGreen * $FFFF);
1893
CurrentGraphicState.Color.Blue := Round(lBlue * $FFFF);
1894
CurrentGraphicState.Color.alpha := alphaOpaque;
1896
AData.SetPenColor(CurrentGraphicState.Color);
1898
{$ifdef FPVECTORIALDEBUG_COLORS}
1899
WriteLn(Format('[TvEPSVectorialReader.ExecuteGraphicStateOperatorsDI] setrgbcolor r=%f g=%f b=%f',
1900
[Param3.FloatValue, Param2.FloatValue, Param1.FloatValue]));
1907
{ Graphics State Operators (Device-Dependent)
1909
halftone sethalftone – Set halftone dictionary
1910
– currenthalftone halftone
1911
Return current halftone dictionary
1912
frequency angle proc setscreen – Set gray halftone screen by frequency, angle,
1914
frequency angle halftone setscreen – Set gray halftone screen from halftone
1916
– currentscreen frequency angle proc|halftone
1917
Return current gray halftone screen
1918
redfreq redang redproc|redhalftone
1919
greenfreq greenang greenproc|greenhalftone
1920
bluefreq blueang blueproc|bluehalftone
1921
grayfreq grayang grayproc|grayhalftone setcolorscreen – Set all four halftone screens
1922
– currentcolorscreen redfreq redang redproc|redhalftone
1923
greenfreq greenang greenproc|greenhalftone
1924
bluefreq blueang blueproc|bluehalftone
1925
grayfreq grayang grayproc|grayhalftone
1926
Return all four halftone screens
1927
proc settransfer – Set gray transfer function
1928
– currenttransfer proc
1929
Return current gray transfer function
1930
redproc greenproc blueproc grayproc setcolortransfer – Set all four transfer functions
1931
– currentcolortransfer redproc greenproc blueproc grayproc
1932
Return current transfer functions
1933
proc setblackgeneration – Set black-generation function
1934
– currentblackgeneration proc
1935
Return current black-generation function
1936
proc setundercolorremoval – Set undercolor-removal function
1937
– currentundercolorremoval proc
1938
Return current undercolor-removal
1940
dict setcolorrendering – Set CIE-based color rendering dictionary
1941
– currentcolorrendering dict
1942
Return current CIE-based color rendering
1944
num setflat – Set flatness tolerance
1945
– currentflat num Return current flatness
1946
bool setoverprint – Set overprint parameter
1947
– currentoverprint bool Return current overprint parameter
1948
num setsmoothness – Set smoothness parameter
1949
– currentsmoothness num Return current smoothness parameter
1950
Coordinate System and Matrix Operators
1951
– matrix matrix Create identity matrix
1952
– initmatrix – Set CTM to device default
1953
matrix identmatrix matrix Fill matrix with identity transform
1954
matrix defaultmatrix matrix Fill matrix with device default matrix
1955
matrix currentmatrix matrix Fill matrix with CTM
1956
matrix setmatrix – Replace CTM by matrix
1957
tx ty translate – Translate user space by (tx , ty)
1958
tx ty matrix translate matrix Define translation by (tx , ty)
1959
sx sy scale – Scale user space by sx and sy
1960
sx sy matrix scale matrix Define scaling by sx and sy
1961
angle rotate – Rotate user space by angle degrees
1962
angle matrix rotate matrix Define rotation by angle degrees
1963
matrix concat – Replace CTM by matrix ´ CTM
1964
matrix1 matrix2 matrix3 concatmatrix matrix3 Fill matrix3 with matrix1 ´ matrix2
1965
x y transform x¢ y¢ Transform (x, y) by CTM
1966
x y matrix transform x¢ y¢ Transform (x, y) by matrix
1967
dx dy dtransform dx¢ dy¢ Transform distance (dx, dy) by CTM
1968
dx dy matrix dtransform dx¢ dy¢ Transform distance (dx, dy) by matrix
1969
x¢ y¢ itransform x y Perform inverse transform of (x¢, y¢) by
1971
x¢ y¢ matrix itransform x y Perform inverse transform of (x¢, y¢) by
1973
dx¢ dy¢ idtransform dx dy Perform inverse transform of distance
1975
dx¢ dy¢ matrix idtransform dx dy Perform inverse transform of distance
1976
(dx¢, dy¢) by matrix
1977
matrix1 matrix2 invertmatrix matrix2 Fill matrix2 with inverse of matrix1
1979
function TvEPSVectorialReader.ExecuteGraphicStateOperatorsDD(
1980
AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
1982
Param1, Param2: TPSToken;
1986
// bool setoverprint – Set overprint parameter
1987
if AToken.StrValue = 'setoverprint' then
1989
Param1 := TPSToken(Stack.Pop);
1991
CurrentGraphicState.OverPrint := Param1.BoolValue;
1995
// sx sy scale – Scale user space by sx and sy
1996
if AToken.StrValue = 'scale' then
1998
Param1 := TPSToken(Stack.Pop);
1999
Param2 := TPSToken(Stack.Pop);
2001
if Param2 = nil then
2006
CurrentGraphicState.ScaleX := Param2.FloatValue;
2007
CurrentGraphicState.ScaleY := Param1.FloatValue;
2008
{$ifdef FPVECTORIALDEBUG_PATHS}
2009
WriteLn(Format('[TvEPSVectorialReader.ExecuteGraphicStateOperatorsDI] scale %f %f',
2010
[CurrentGraphicState.ScaleX, CurrentGraphicState.ScaleY]));
2016
translate tx ty translate
2017
- tx ty matrix translate matrix
2019
With no matrix operand, translate builds a temporary matrix and concatenates
2020
this matrix with the current transformation matrix (CTM). Precisely, translate
2021
replaces the CTM by T x CTM. The effect of this is to move the origin of the
2022
user coordinate system by tx units in the x direction and ty units in the y
2023
direction relative to the former user coordinate system. The sizes of the x
2024
and y units and the orientation of the axes are unchanged.
2026
If the matrix operand is supplied, translate replaces the value of matrix by
2027
T and pushes the modified matrix back on the operand stack.
2028
In this case, translate does not affect the CTM.
2030
if AToken.StrValue = 'translate' then
2032
Param1 := TPSToken(Stack.Pop); // ty
2033
Param2 := TPSToken(Stack.Pop); // tx
2035
if Param2 = nil then
2037
raise Exception.Create('[TvEPSVectorialReader.ExecuteGraphicStateOperatorsDI] Stack underflow in operator "translate"');
2040
{$ifdef FPVECTORIALDEBUG_PATHS}
2041
WriteLn(Format('[TvEPSVectorialReader.ExecuteGraphicStateOperatorsDI] translate %f, %f CurrentGraphicState.Translate %f %f',
2042
[Param2.FloatValue, Param1.FloatValue, CurrentGraphicState.TranslateX, CurrentGraphicState.TranslateY]));
2045
CurrentGraphicState.TranslateX := CurrentGraphicState.TranslateX + Param2.FloatValue;
2046
CurrentGraphicState.TranslateY := CurrentGraphicState.TranslateY + Param1.FloatValue;
2050
// angle rotate – Rotate user space by angle degrees
2051
if AToken.StrValue = 'rotate' then
2053
Param1 := TPSToken(Stack.Pop);
2055
{$ifdef FPVECTORIALDEBUG_PATHS}
2056
WriteLn(Format('[TvEPSVectorialReader.ExecuteGraphicStateOperatorsDI] rotate angle=%f', [Param1.FloatValue]));
2064
{ Dictionary Operators
2066
int dict dict Create dictionary with capacity for int
2068
– << mark Start dictionary construction
2069
mark key1 value1 … keyn valuen >> dict
2070
End dictionary construction
2071
dict length int Return number of entries in dict
2072
dict maxlength int Return current capacity of dict
2073
dict begin – Push dict on dictionary stack
2074
– end – Pop current dictionary off dictionary stack
2075
key value def – Associate key and value in current dictionary
2076
key load value Search dictionary stack for key and return
2078
key value store – Replace topmost definition of key
2079
dict key get any Return value associated with key in dict
2080
dict key value put – Associate key with value in dict
2081
dict key undef – Remove key and its value from dict
2082
dict key known bool Test whether key is in dict
2083
key where dict true Find dictionary in which key is defined
2085
dict1 dict2 copy dict2 Copy contents of dict1 to dict2
2086
dict proc forall – Execute proc for each entry in dict
2087
– currentdict dict Return current dictionary
2088
– errordict dict Return error handler dictionary
2089
– $error dict Return error control and status dictionary
2090
– systemdict dict Return system dictionary
2091
– userdict dict Return writeable dictionary in local VM
2092
– globaldict dict Return writeable dictionary in global VM
2093
– statusdict dict Return product-dependent dictionary
2094
– countdictstack int Count elements on dictionary stack
2095
array dictstack subarray Copy dictionary stack into array
2096
– cleardictstack – Pop all nonpermanent dictionaries off
2099
function TvEPSVectorialReader.ExecuteDictionaryOperators(
2100
AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
2102
Param1, Param2: TPSToken;
2103
NewToken: TExpressionToken;
2107
// Adds a dictionary definition
2108
// key value def – Associate key and value in current dictionary
2109
if AToken.StrValue = 'def' then
2111
Param1 := TPSToken(Stack.Pop);
2112
Param2 := TPSToken(Stack.Pop);
2113
Dictionary.AddObject(Param2.StrValue, Param1);
2117
// Can be ignored, because in the files found it only loads
2118
// standard routines, like /moveto ...
2120
// key load value Search dictionary stack for key and return
2122
if AToken.StrValue = 'load' then
2124
// {$ifdef FPVECTORIALDEBUG_DICTIONARY}
2125
// WriteLn('[TvEPSVectorialReader.ExecuteDictionaryOperators] load');
2132
// Find dictionary in which key is defined
2133
//key where dict true Find dictionary in which key is defined
2135
if AToken.StrValue = 'where' then
2137
{$ifdef FPVECTORIALDEBUG_DICTIONARY}
2138
WriteLn('[TvEPSVectorialReader.ExecuteDictionaryOperators] where');
2142
Param1 := TPSToken(Stack.Pop);
2144
if Dictionary.IndexOf(Param1.StrValue) >= 0 then
2146
// We use only 1 dictionary, so this is just a representation of our single dictionary
2147
NewToken := TExpressionToken.Create;
2148
NewToken.ETType := ettDictionary;
2149
Stack.Push(NewToken);
2151
NewToken := TExpressionToken.Create;
2152
NewToken.ETType := ettOperand;
2153
NewToken.BoolValue := True;
2154
Stack.Push(NewToken);
2156
{$ifdef FPVECTORIALDEBUG_DICTIONARY}
2157
WriteLn('[TvEPSVectorialReader.ExecuteDictionaryOperators] where True');
2162
NewToken := TExpressionToken.Create;
2163
NewToken.ETType := ettOperand;
2164
NewToken.BoolValue := False;
2165
Stack.Push(NewToken);
2167
{$ifdef FPVECTORIALDEBUG_DICTIONARY}
2168
WriteLn('[TvEPSVectorialReader.ExecuteDictionaryOperators] where False');
2176
{ Miscellaneous Operators
2178
proc bind proc Replace operator names in proc with
2179
operators; perform idiom recognition
2180
– null null Push null on stack
2181
– version string Return interpreter version
2182
– realtime int Return real time in milliseconds
2183
– usertime int Return execution time in milliseconds
2184
– languagelevel int Return LanguageLevel
2185
– product string Return product name
2186
– revision int Return product revision level
2187
– serialnumber int Return machine serial number
2188
– executive – Invoke interactive executive
2189
bool echo – Turn echoing on or off
2190
– prompt – Executed when ready for interactive input
2192
function TvEPSVectorialReader.ExecuteMiscellaneousOperators(
2193
AToken: TExpressionToken; AData: TvVectorialPage; ADoc: TvVectorialDocument): Boolean;
2197
// Just a hint for more efficient parsing, we can ignore
2199
// proc bind proc Replace operator names in proc with
2200
// operators; perform idiom recognition
2201
if AToken.StrValue = 'bind' then
2203
{$ifdef FPVECTORIALDEBUG_CONTROL}
2204
WriteLn('[TvEPSVectorialReader.ExecuteControlOperator] bind');
2212
procedure TvEPSVectorialReader.PostScriptCoordsToFPVectorialCoords(AParam1,
2213
AParam2: TPSToken; var APosX, APosY: Double);
2215
APosX := AParam2.FloatValue;
2216
APosY := AParam1.FloatValue;
2219
// Returns true if a dictionary substitution was executed
2220
function TvEPSVectorialReader.DictionarySubstituteOperator(
2221
ADictionary: TStringList; var ACurToken: TPSToken): Boolean;
2224
SubstituteToken, NewToken: TPSToken;
2227
lIndex := ADictionary.IndexOf(ACurToken.StrValue);
2232
SubstituteToken := TPSToken(ADictionary.Objects[lIndex]);
2234
if SubstituteToken is TExpressionToken then
2236
ACurToken.StrValue := SubstituteToken.StrValue;
2237
ACurToken.FloatValue := SubstituteToken.FloatValue;
2239
else if SubstituteToken is TProcedureToken then
2241
ACurToken := SubstituteToken;
2243
if ACurToken.StrValue = '' then raise Exception.Create('[TvEPSVectorialReader.DictionarySubstituteOperator] The Dictionary substitution resulted in an empty value');
2247
constructor TvEPSVectorialReader.Create;
2251
FPointSeparator := SysUtils.DefaultFormatSettings;
2252
FPointSeparator.DecimalSeparator := '.';
2253
FPointSeparator.ThousandSeparator := ',';
2255
Tokenizer := TPSTokenizer.Create(-1);
2256
Stack := TObjectStack.Create;
2257
GraphicStateStack := TObjectStack.Create;
2258
Dictionary := TStringList.Create;
2259
Dictionary.CaseSensitive := True;
2260
CurrentGraphicState := TGraphicState.Create;
2263
destructor TvEPSVectorialReader.Destroy;
2267
GraphicStateStack.Free;
2269
CurrentGraphicState.Free;
2274
procedure TvEPSVectorialReader.ReadFromStream(AStream: TStream;
2275
AData: TvVectorialDocument);
2277
lPage: TvVectorialPage;
2279
Tokenizer.ReadFromStream(AStream);
2280
// Tokenizer.DebugOut();
2282
// Make sure we have at least one path
2283
lPage := AData.AddPage();
2286
RunPostScript(Tokenizer.Tokens, lPage, AData);
2288
// Make sure we have at least one path
2291
// PostScript has no document size information, so lets calculate it ourselves
2292
AData.GuessDocumentSize();
2293
AData.GuessGoodZoomLevel()
2298
RegisterVectorialReader(TvEPSVectorialReader, vfEncapsulatedPostScript);