fpvectorial: Fixes some bugs in the PostScript interpreter, previously it didnt run some procedures, and adds more commands to it

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1743 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
sekelsenmat
2011-07-15 10:17:44 +00:00
parent 8608497d12
commit b1dffdca6a
2 changed files with 111 additions and 12 deletions

View File

@ -15,6 +15,7 @@ unit epsvectorialreader;
{.$define FPVECTORIALDEBUG_PATHS} {.$define FPVECTORIALDEBUG_PATHS}
{.$define FPVECTORIALDEBUG_COLORS} {.$define FPVECTORIALDEBUG_COLORS}
{.$define FPVECTORIALDEBUG_ROLL} {.$define FPVECTORIALDEBUG_ROLL}
{.$define FPVECTORIALDEBUG_CODEFLOW}
interface interface
@ -96,6 +97,8 @@ type
ExitCalled: Boolean; ExitCalled: Boolean;
CurrentGraphicState: TGraphicState; CurrentGraphicState: TGraphicState;
// //
procedure DebugStack();
//
procedure RunPostScript(ATokens: TPsTokens; AData: TvVectorialDocument); procedure RunPostScript(ATokens: TPsTokens; AData: TvVectorialDocument);
// //
procedure ExecuteProcedureToken(AToken: TProcedureToken; AData: TvVectorialDocument); procedure ExecuteProcedureToken(AToken: TProcedureToken; AData: TvVectorialDocument);
@ -114,7 +117,7 @@ type
function ExecuteStringOperator(AToken: TExpressionToken; AData: TvVectorialDocument): Boolean; function ExecuteStringOperator(AToken: TExpressionToken; AData: TvVectorialDocument): Boolean;
// //
procedure PostScriptCoordsToFPVectorialCoords(AParam1, AParam2: TPSToken; var APosX, APosY: Double); procedure PostScriptCoordsToFPVectorialCoords(AParam1, AParam2: TPSToken; var APosX, APosY: Double);
procedure DictionarySubstituteOperator(ADictionary: TStringList; var ACurToken: TPSToken); function DictionarySubstituteOperator(ADictionary: TStringList; var ACurToken: TPSToken): Boolean;
public public
{ General reading methods } { General reading methods }
Tokenizer: TPSTokenizer; Tokenizer: TPSTokenizer;
@ -125,6 +128,10 @@ type
implementation implementation
type
TStackAccess = class(TObjectStack)
end;
var var
FPointSeparator: TFormatSettings; FPointSeparator: TFormatSettings;
@ -257,6 +264,7 @@ begin
begin begin
ExpressionToken := TExpressionToken.Create; ExpressionToken := TExpressionToken.Create;
ExpressionToken.Line := CurLine; ExpressionToken.Line := CurLine;
ExpressionToken.StrValue := '';
if CurChar = '/' then if CurChar = '/' then
ExpressionToken.ETType := ettNamedElement ExpressionToken.ETType := ettNamedElement
else else
@ -301,9 +309,17 @@ begin
Tokens.Add(ProcedureToken); Tokens.Add(ProcedureToken);
State := ssSearchingToken; State := ssSearchingToken;
end end
else
begin
// Don't add line ends, because they cause problems when outputing the debug info
// but in this case we need to add spaces to compensate, or else items separates only
// by line end might get glued together
if CurChar in [#10, #13] then
ProcedureToken.StrValue := ProcedureToken.StrValue + ' '
else else
ProcedureToken.StrValue := ProcedureToken.StrValue + CurChar; ProcedureToken.StrValue := ProcedureToken.StrValue + CurChar;
end; end;
end;
// Goes until a space comes, or { // Goes until a space comes, or {
ssInExpressionElement: ssInExpressionElement:
@ -403,10 +419,26 @@ end;
{ TvEPSVectorialReader } { TvEPSVectorialReader }
procedure TvEPSVectorialReader.DebugStack();
var
i: Integer;
lToken: TPSToken;
begin
WriteLn('====================');
WriteLn('Stack dump');
WriteLn('====================');
for i := 0 to TStackAccess(Stack).List.Count - 1 do
begin
lToken := TPSToken(TStackAccess(Stack).List.Items[i]);
WriteLn(Format('Stack #%d : %s', [i, lToken.StrValue]));
end;
end;
procedure TvEPSVectorialReader.RunPostScript(ATokens: TPsTokens; procedure TvEPSVectorialReader.RunPostScript(ATokens: TPsTokens;
AData: TvVectorialDocument); AData: TvVectorialDocument);
var var
i: Integer; i: Integer;
lSubstituted: Boolean;
CurToken: TPSToken; CurToken: TPSToken;
begin begin
{$ifdef FPVECTORIALDEBUG_CODEFLOW} {$ifdef FPVECTORIALDEBUG_CODEFLOW}
@ -423,6 +455,11 @@ begin
begin begin
CurToken := TPSToken(ATokens.Items[i]); CurToken := TPSToken(ATokens.Items[i]);
{ if CurToken.StrValue = 'J' then
begin
DebugStack();
end;}
if CurToken is TCommentToken then if CurToken is TCommentToken then
begin begin
{$ifdef FPVECTORIALDEBUG_CODEFLOW} {$ifdef FPVECTORIALDEBUG_CODEFLOW}
@ -447,14 +484,22 @@ begin
WriteLn(Format('[TvEPSVectorialReader.RunPostScript] Type: TExpressionToken Token: %s', [CurToken.StrValue])); WriteLn(Format('[TvEPSVectorialReader.RunPostScript] Type: TExpressionToken Token: %s', [CurToken.StrValue]));
{$endif} {$endif}
if TExpressionToken(CurToken).ETType <> ettOperator then if TExpressionToken(CurToken).ETType = ettOperand then
begin begin
Stack.Push(CurToken); Stack.Push(CurToken);
Continue; Continue;
end; end;
// Now we need to verify if the operator should be substituted in the dictionary // Now we need to verify if the operator should be substituted in the dictionary
DictionarySubstituteOperator(Dictionary, CurToken); lSubstituted := DictionarySubstituteOperator(Dictionary, CurToken);
// Check if this is the first time that a named element appears, if yes, don't try to execute it
// just put it into the stack
if (not lSubstituted) and (TExpressionToken(CurToken).ETType = ettNamedElement) then
begin
Stack.Push(CurToken);
Continue;
end;
if CurToken is TProcedureToken then ExecuteProcedureToken(TProcedureToken(CurToken), AData) if CurToken is TProcedureToken then ExecuteProcedureToken(TProcedureToken(CurToken), AData)
else ExecuteOperatorToken(TExpressionToken(CurToken), AData); else ExecuteOperatorToken(TExpressionToken(CurToken), AData);
@ -1069,7 +1114,7 @@ begin
if AToken.StrValue = 'eofill' then if AToken.StrValue = 'eofill' then
begin begin
AData.SetBrushStyle(bsDiagCross); AData.SetBrushStyle(bsSolid);
Exit(True); Exit(True);
end; end;
@ -1483,6 +1528,19 @@ begin
AData.AddBezierToPath(BaseX + PosX, BaseY + PosY, BaseX + PosX2, BaseY + PosY2, BaseX + PosX3, BaseY + PosY3); AData.AddBezierToPath(BaseX + PosX, BaseY + PosY, BaseX + PosX2, BaseY + PosY2, BaseX + PosX3, BaseY + PosY3);
Exit(True); Exit(True);
end; end;
//
if AToken.StrValue = 'closepath' then
begin
{$ifdef FPVECTORIALDEBUG_PATHS}
WriteLn('[TvEPSVectorialReader.ExecutePathConstructionOperator] closepath');
{$endif}
AData.EndPath();
AData.StartPath();
AData.SetPenColor(CurrentGraphicState.Color);
Exit(True);
end;
// x y r angle1 angle2 arc – Append counterclockwise arc // x y r angle1 angle2 arc – Append counterclockwise arc
if AToken.StrValue = 'arc' then if AToken.StrValue = 'arc' then
begin begin
@ -1594,6 +1652,12 @@ begin
Exit(True); Exit(True);
end; end;
// //
if AToken.StrValue = 'setlinecap' then
begin
Param1 := TPSToken(Stack.Pop);
Exit(True);
end;
//
if AToken.StrValue = 'setlinejoin' then if AToken.StrValue = 'setlinejoin' then
begin begin
Param1 := TPSToken(Stack.Pop); Param1 := TPSToken(Stack.Pop);
@ -1846,15 +1910,19 @@ begin
APosY := AParam1.FloatValue; APosY := AParam1.FloatValue;
end; end;
procedure TvEPSVectorialReader.DictionarySubstituteOperator( // Returns true if a dictionary substitution was executed
ADictionary: TStringList; var ACurToken: TPSToken); function TvEPSVectorialReader.DictionarySubstituteOperator(
ADictionary: TStringList; var ACurToken: TPSToken): Boolean;
var var
lIndex: Integer; lIndex: Integer;
SubstituteToken, NewToken: TPSToken; SubstituteToken, NewToken: TPSToken;
begin begin
Result := False;
lIndex := ADictionary.IndexOf(ACurToken.StrValue); lIndex := ADictionary.IndexOf(ACurToken.StrValue);
if lIndex >= 0 then if lIndex >= 0 then
begin begin
Result := True;
SubstituteToken := TPSToken(ADictionary.Objects[lIndex]); SubstituteToken := TPSToken(ADictionary.Objects[lIndex]);
if SubstituteToken is TExpressionToken then if SubstituteToken is TExpressionToken then
@ -1882,6 +1950,7 @@ begin
Stack := TObjectStack.Create; Stack := TObjectStack.Create;
GraphicStateStack := TObjectStack.Create; GraphicStateStack := TObjectStack.Create;
Dictionary := TStringList.Create; Dictionary := TStringList.Create;
Dictionary.CaseSensitive := True;
CurrentGraphicState := TGraphicState.Create; CurrentGraphicState := TGraphicState.Create;
end; end;

View File

@ -4,7 +4,7 @@ unit fpvtocanvas;
interface interface
{$define USE_LCL_CANVAS} {.$define USE_LCL_CANVAS}
uses uses
Classes, SysUtils, Math, Classes, SysUtils, Math,
@ -153,6 +153,8 @@ var
CurX, CurY: Integer; // Not modified by ADestX, etc CurX, CurY: Integer; // Not modified by ADestX, etc
CurveLength: Integer; CurveLength: Integer;
t: Double; t: Double;
// For polygons
Points: array of TPoint;
begin begin
PosX := 0; PosX := 0;
PosY := 0; PosY := 0;
@ -165,10 +167,38 @@ begin
// Set the path Pen and Brush options // Set the path Pen and Brush options
ADest.Pen.Style := CurPath.Pen.Style; ADest.Pen.Style := CurPath.Pen.Style;
ADest.Pen.Width := CurPath.Pen.Width; ADest.Pen.Width := CurPath.Pen.Width;
ADest.Brush.Style := CurPath.Brush.Style;
ADest.Pen.FPColor := CurPath.Pen.Color; ADest.Pen.FPColor := CurPath.Pen.Color;
ADest.Brush.FPColor := CurPath.Brush.Color; ADest.Brush.FPColor := CurPath.Brush.Color;
//
// For solid paths, draw a polygon instead
//
if CurPath.Brush.Style = bsSolid then
begin
ADest.Brush.Style := CurPath.Brush.Style;
SetLength(Points, CurPath.Len);
for j := 0 to CurPath.Len - 1 do
begin
//WriteLn('j = ', j);
CurSegment := TPathSegment(CurPath.Next());
CoordX := CoordToCanvasX(Cur2DSegment.X);
CoordY := CoordToCanvasY(Cur2DSegment.Y);
Points[j].X := CoordX;
Points[j].Y := CoordY;
end;
ADest.Polygon(Points);
Exit;
end;
//
// For other paths, draw more carefully
//
for j := 0 to CurPath.Len - 1 do for j := 0 to CurPath.Len - 1 do
begin begin
//WriteLn('j = ', j); //WriteLn('j = ', j);