You've already forked lazarus-ccr
Adds a copy of the fpvectorial source code for convenience
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1448 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
234
applications/fpvviewer/fpvectorialsrc/avisocncgcodereader.pas
Normal file
234
applications/fpvviewer/fpvectorialsrc/avisocncgcodereader.pas
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
{
|
||||||
|
Reads AvisoCNC G-Code
|
||||||
|
|
||||||
|
License: The same modified LGPL as the Free Pascal RTL
|
||||||
|
See the file COPYING.modifiedLGPL for more details
|
||||||
|
|
||||||
|
AUTHORS: Felipe Monteiro de Carvalho
|
||||||
|
Pedro Sol Pegorini L de Lima
|
||||||
|
}
|
||||||
|
unit avisocncgcodereader;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils,
|
||||||
|
fpvectorial;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ Used by tcutils.SeparateString }
|
||||||
|
T10Strings = array[0..9] of shortstring;
|
||||||
|
|
||||||
|
{ TvAvisoCNCGCodeReader }
|
||||||
|
|
||||||
|
TvAvisoCNCGCodeReader = class(TvCustomVectorialReader)
|
||||||
|
private
|
||||||
|
LastX, LastY, LastZ: Double;
|
||||||
|
function SeparateString(AString: string; ASeparator: Char): T10Strings;
|
||||||
|
procedure ReadString(AStr: string; AData: TvVectorialDocument);
|
||||||
|
function GetCoordinate(AStr: shortstring): Integer;
|
||||||
|
function GetCoordinateValue(AStr: shortstring): Double;
|
||||||
|
public
|
||||||
|
{ General reading methods }
|
||||||
|
procedure ReadFromStrings(AStrings: TStrings; AData: TvVectorialDocument); override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
const
|
||||||
|
{ Coordinate constants }
|
||||||
|
|
||||||
|
INT_COORDINATE_NONE = 0;
|
||||||
|
INT_COORDINATE_X = 1;
|
||||||
|
INT_COORDINATE_Y = 2;
|
||||||
|
INT_COORDINATE_Z = 3;
|
||||||
|
|
||||||
|
{ GCode constants }
|
||||||
|
|
||||||
|
STR_GCODE_LINEAR_MOVE = 'G01';
|
||||||
|
STR_GCODE_STEPPER_MOVE = 'S01';
|
||||||
|
STR_GCODE_2DBEZIER_MOVE = 'B02';
|
||||||
|
STR_GCODE_3DBEZIER_MOVE = 'B03';
|
||||||
|
STR_GCODE_DRILL_UP = 'P01';
|
||||||
|
STR_GCODE_DRILL_DOWN = 'P02';
|
||||||
|
|
||||||
|
{ TvAvisoCNCGCodeReader }
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Reads a string and separates it in substring
|
||||||
|
using ASeparator to delimite them.
|
||||||
|
|
||||||
|
Limits:
|
||||||
|
|
||||||
|
Number of substrings: 10 (indexed 0 to 9)
|
||||||
|
Length of each substring: 255 (they are shortstrings)
|
||||||
|
}
|
||||||
|
function TvAvisoCNCGCodeReader.SeparateString(AString: string; ASeparator: Char): T10Strings;
|
||||||
|
var
|
||||||
|
i, CurrentPart: Integer;
|
||||||
|
begin
|
||||||
|
CurrentPart := 0;
|
||||||
|
|
||||||
|
{ Clears the result }
|
||||||
|
for i := 0 to 9 do Result[i] := '';
|
||||||
|
|
||||||
|
{ Iterates througth the string, filling strings }
|
||||||
|
for i := 1 to Length(AString) do
|
||||||
|
begin
|
||||||
|
if Copy(AString, i, 1) = ASeparator then
|
||||||
|
begin
|
||||||
|
Inc(CurrentPart);
|
||||||
|
|
||||||
|
{ Verifies if the string capacity wasn't exceeded }
|
||||||
|
if CurrentPart > 9 then Exit;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result[CurrentPart] := Result[CurrentPart] + Copy(AString, i, 1);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvAvisoCNCGCodeReader.ReadString(AStr: string;
|
||||||
|
AData: TvVectorialDocument);
|
||||||
|
var
|
||||||
|
AParams: T10Strings;
|
||||||
|
DestX, DestY, DestZ: Double;
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn('TvAvisoCNCGCodeReader.ReadString ', AStr);
|
||||||
|
{$endif}
|
||||||
|
AParams := SeparateString(AStr, ' ');
|
||||||
|
|
||||||
|
{
|
||||||
|
Format may be:
|
||||||
|
G01 X3
|
||||||
|
G01 X3 Y4
|
||||||
|
G01 X3 Y4 Z2
|
||||||
|
}
|
||||||
|
if AParams[0] = STR_GCODE_DRILL_UP then
|
||||||
|
begin
|
||||||
|
AData.AddLineToPath(LastX, LastY, 0);
|
||||||
|
LastZ := 0;
|
||||||
|
end
|
||||||
|
else if AParams[0] = STR_GCODE_DRILL_DOWN then
|
||||||
|
begin
|
||||||
|
AData.AddLineToPath(LastX, LastY, 50);
|
||||||
|
LastZ := 50;
|
||||||
|
end
|
||||||
|
else if AParams[0] = STR_GCODE_LINEAR_MOVE then
|
||||||
|
begin
|
||||||
|
DestX := LastX;
|
||||||
|
DestY := LastY;
|
||||||
|
DestZ := LastZ;
|
||||||
|
|
||||||
|
for i := 1 to 3 do
|
||||||
|
begin
|
||||||
|
case GetCoordinate(AParams[i]) of
|
||||||
|
INT_COORDINATE_X: DestX := GetCoordinateValue(AParams[i]);
|
||||||
|
INT_COORDINATE_Y: DestY := GetCoordinateValue(AParams[i]);
|
||||||
|
INT_COORDINATE_Z: DestZ := GetCoordinateValue(AParams[i]);
|
||||||
|
else
|
||||||
|
// error
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
AData.AddLineToPath(DestX, DestY, DestZ);
|
||||||
|
|
||||||
|
LastX := DestX;
|
||||||
|
LastY := DestY;
|
||||||
|
LastZ := DestZ;
|
||||||
|
end
|
||||||
|
else if AParams[0] = STR_GCODE_2DBEZIER_MOVE then
|
||||||
|
begin
|
||||||
|
AData.AddBezierToPath(
|
||||||
|
GetCoordinateValue(AParams[1]),
|
||||||
|
GetCoordinateValue(AParams[2]),
|
||||||
|
GetCoordinateValue(AParams[3]),
|
||||||
|
GetCoordinateValue(AParams[4]),
|
||||||
|
GetCoordinateValue(AParams[5]),
|
||||||
|
GetCoordinateValue(AParams[6])
|
||||||
|
);
|
||||||
|
|
||||||
|
LastX := GetCoordinateValue(AParams[5]);
|
||||||
|
LastY := GetCoordinateValue(AParams[6]);
|
||||||
|
end
|
||||||
|
else if AParams[0] = STR_GCODE_3DBEZIER_MOVE then
|
||||||
|
begin
|
||||||
|
AData.AddBezierToPath(
|
||||||
|
GetCoordinateValue(AParams[1]),
|
||||||
|
GetCoordinateValue(AParams[2]),
|
||||||
|
GetCoordinateValue(AParams[3]),
|
||||||
|
GetCoordinateValue(AParams[4]),
|
||||||
|
GetCoordinateValue(AParams[5]),
|
||||||
|
GetCoordinateValue(AParams[6]),
|
||||||
|
GetCoordinateValue(AParams[7]),
|
||||||
|
GetCoordinateValue(AParams[8]),
|
||||||
|
GetCoordinateValue(AParams[9])
|
||||||
|
);
|
||||||
|
|
||||||
|
LastX := GetCoordinateValue(AParams[7]);
|
||||||
|
LastY := GetCoordinateValue(AParams[8]);
|
||||||
|
LastZ := GetCoordinateValue(AParams[9]);
|
||||||
|
end;
|
||||||
|
{else
|
||||||
|
begin
|
||||||
|
Ignore any of these codes:
|
||||||
|
|
||||||
|
STR_GCODE_STEPPER_MOVE
|
||||||
|
|
||||||
|
and anything else
|
||||||
|
end;}
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TvAvisoCNCGCodeReader.GetCoordinate(AStr: shortstring): Integer;
|
||||||
|
begin
|
||||||
|
Result := INT_COORDINATE_NONE;
|
||||||
|
|
||||||
|
if AStr = '' then Exit
|
||||||
|
else if AStr[1] = 'X' then Result := INT_COORDINATE_X
|
||||||
|
else if AStr[1] = 'Y' then Result := INT_COORDINATE_Y
|
||||||
|
else if AStr[1] = 'Z' then Result := INT_COORDINATE_Z;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TvAvisoCNCGCodeReader.GetCoordinateValue(AStr: shortstring): Double;
|
||||||
|
begin
|
||||||
|
Result := 0.0;
|
||||||
|
|
||||||
|
if Length(AStr) <= 1 then Exit;
|
||||||
|
|
||||||
|
Result := StrToFloat(Copy(AStr, 2, Length(AStr) - 1));
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
The information of each separate path is lost in G-Code files
|
||||||
|
Only one path uniting all of them is created when reading G-Code
|
||||||
|
}
|
||||||
|
procedure TvAvisoCNCGCodeReader.ReadFromStrings(AStrings: TStrings;
|
||||||
|
AData: TvVectorialDocument);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn('TvAvisoCNCGCodeReader.ReadFromStrings AStrings = ', PtrInt(AStrings), ' AData = ', PtrInt(AData));
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
AData.StartPath(0, 0);
|
||||||
|
|
||||||
|
for i := 0 to AStrings.Count - 1 do
|
||||||
|
ReadString(AStrings.Strings[i], AData);
|
||||||
|
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn('AData.EndPath');
|
||||||
|
{$endif}
|
||||||
|
AData.EndPath();
|
||||||
|
end;
|
||||||
|
|
||||||
|
initialization
|
||||||
|
|
||||||
|
RegisterVectorialReader(TvAvisoCNCGCodeReader, vfGCodeAvisoCNCPrototipoV5);
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
@ -0,0 +1,87 @@
|
|||||||
|
{
|
||||||
|
Writes AvisoCNC G-Code
|
||||||
|
|
||||||
|
License: The same modified LGPL as the Free Pascal RTL
|
||||||
|
See the file COPYING.modifiedLGPL for more details
|
||||||
|
|
||||||
|
AUTHORS: Felipe Monteiro de Carvalho
|
||||||
|
Pedro Sol Pegorini L de Lima
|
||||||
|
}
|
||||||
|
unit avisocncgcodewriter;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils,
|
||||||
|
fpvectorial;
|
||||||
|
|
||||||
|
type
|
||||||
|
{ TvAvisoCNCGCodeWriter }
|
||||||
|
|
||||||
|
TvAvisoCNCGCodeWriter = class(TvCustomVectorialWriter)
|
||||||
|
public
|
||||||
|
{ General reading methods }
|
||||||
|
procedure WriteToStrings(AStrings: TStrings; AData: TvVectorialDocument); override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{ TvGCodeVectorialWriter }
|
||||||
|
|
||||||
|
procedure TvAvisoCNCGCodeWriter.WriteToStrings(AStrings: TStrings;
|
||||||
|
AData: TvVectorialDocument);
|
||||||
|
var
|
||||||
|
i, j: Integer;
|
||||||
|
Str: string;
|
||||||
|
APath: TPath;
|
||||||
|
begin
|
||||||
|
AStrings.Clear;
|
||||||
|
|
||||||
|
AStrings.Add('M216 // Ligar monitor de carga');
|
||||||
|
AStrings.Add('G28 // Ir rapidamente para posição inicial');
|
||||||
|
AStrings.Add('G00');
|
||||||
|
|
||||||
|
// itera por todos os itens
|
||||||
|
for i := 0 to AData.GetPathCount - 1 do
|
||||||
|
begin
|
||||||
|
APath := AData.GetPath(i);
|
||||||
|
|
||||||
|
// levanta a broca
|
||||||
|
AStrings.Add('P01 // Sobe a cabeça de gravação');
|
||||||
|
// vai para o ponto inicial
|
||||||
|
AStrings.Add(Format('G01 X%f Y%f',
|
||||||
|
[APath.Points[0].X, APath.Points[0].Y]));
|
||||||
|
AStrings.Add('P02 // Abaixa a cabeça de gravação');
|
||||||
|
|
||||||
|
for j := 1 to APath.Len - 1 do
|
||||||
|
begin
|
||||||
|
case APath.Points[j].SegmentType of
|
||||||
|
st2DLine: AStrings.Add(Format('G01 X%f Y%f',
|
||||||
|
[APath.Points[j].X, APath.Points[j].Y]));
|
||||||
|
st3DLine: AStrings.Add(Format('G01 X%f Y%f Z%f',
|
||||||
|
[APath.Points[j].X, APath.Points[j].Y, APath.Points[j].Z]));
|
||||||
|
st2DBezier: AStrings.Add(Format('B02 X%f Y%f X%f Y%f X%f Y%f',
|
||||||
|
[APath.Points[j].X2, APath.Points[j].Y2,
|
||||||
|
APath.Points[j].X3, APath.Points[j].Y3,
|
||||||
|
APath.Points[j].X, APath.Points[j].Y]));
|
||||||
|
st3DBezier: AStrings.Add(Format('B03 X%f Y%f Z%f X%f Y%f Z%f X%f Y%f Z%f',
|
||||||
|
[APath.Points[j].X2, APath.Points[j].Y2, APath.Points[j].Z2,
|
||||||
|
APath.Points[j].X3, APath.Points[j].Y3, APath.Points[j].Z3,
|
||||||
|
APath.Points[j].X, APath.Points[j].Y, APath.Points[j].Z]));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
AStrings.Add('P01 // Sobe a cabeça de gravação');
|
||||||
|
AStrings.Add('M30 // Parar o programa e retornar para posição inicial');
|
||||||
|
AStrings.Add('M215 // Desligar monitor de carga');
|
||||||
|
end;
|
||||||
|
|
||||||
|
initialization
|
||||||
|
|
||||||
|
RegisterVectorialWriter(TvAvisoCNCGCodeWriter, vfGCodeAvisoCNCPrototipoV5);
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
74
applications/fpvviewer/fpvectorialsrc/avisozlib.pas
Normal file
74
applications/fpvviewer/fpvectorialsrc/avisozlib.pas
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
unit avisozlib;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, paszlib;
|
||||||
|
|
||||||
|
type
|
||||||
|
Decode = class
|
||||||
|
public
|
||||||
|
procedure CHECK_ERR(err: Integer; msg: String);
|
||||||
|
procedure EXIT_ERR(const msg: String);
|
||||||
|
function test_inflate(compr: Pointer; comprLen : LongInt;
|
||||||
|
uncompr: Pointer; uncomprLen : LongInt): PChar;
|
||||||
|
constructor Create();
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
procedure Decode.CHECK_ERR(err: Integer; msg: String);
|
||||||
|
begin
|
||||||
|
if err <> Z_OK then
|
||||||
|
begin
|
||||||
|
raise Exception.Create('ERROR: ' + msg);
|
||||||
|
Halt(1);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure Decode.EXIT_ERR(const msg: String);
|
||||||
|
begin
|
||||||
|
raise Exception.Create('ERROR: ' + msg);
|
||||||
|
Halt(1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function Decode.test_inflate(compr: Pointer; comprLen : LongInt;
|
||||||
|
uncompr: Pointer; uncomprLen : LongInt): PChar;
|
||||||
|
var err: Integer;
|
||||||
|
d_stream: TZStream; // decompression stream
|
||||||
|
begin
|
||||||
|
StrCopy(PChar(uncompr), 'garbage');
|
||||||
|
|
||||||
|
d_stream.next_in := compr;
|
||||||
|
d_stream.avail_in := 0;
|
||||||
|
d_stream.next_out := uncompr;
|
||||||
|
|
||||||
|
err := inflateInit(d_stream);
|
||||||
|
CHECK_ERR(err, 'inflateInit');
|
||||||
|
|
||||||
|
while (d_stream.total_out < uncomprLen) and
|
||||||
|
(d_stream.total_in < comprLen) do
|
||||||
|
begin
|
||||||
|
d_stream.avail_out := 1; // force small buffers
|
||||||
|
d_stream.avail_in := 1;
|
||||||
|
err := inflate(d_stream, Z_NO_FLUSH);
|
||||||
|
if err = Z_STREAM_END then
|
||||||
|
break;
|
||||||
|
CHECK_ERR(err, 'inflate');
|
||||||
|
end;
|
||||||
|
|
||||||
|
err := inflateEnd(d_stream);
|
||||||
|
CHECK_ERR(err, 'inflateEnd');
|
||||||
|
|
||||||
|
Result:=PChar(uncompr);
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor Decode.Create();
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
180
applications/fpvviewer/fpvectorialsrc/cdrvectorialreader.pas
Normal file
180
applications/fpvviewer/fpvectorialsrc/cdrvectorialreader.pas
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
{
|
||||||
|
cdrvectorialreader.pas
|
||||||
|
|
||||||
|
Reads a Corel Draw vectorial file
|
||||||
|
|
||||||
|
CDR file format specification obtained from:
|
||||||
|
|
||||||
|
ADOBE SYSTEMS INCORPORATED. PDF Reference: Adobe®
|
||||||
|
Portable Document Format. San Jose, 2006. (Sixth edition).
|
||||||
|
|
||||||
|
AUTHORS: Felipe Monteiro de Carvalho
|
||||||
|
|
||||||
|
License: The same modified LGPL as the Free Pascal RTL
|
||||||
|
See the file COPYING.modifiedLGPL for more details
|
||||||
|
}
|
||||||
|
unit cdrvectorialreader;
|
||||||
|
|
||||||
|
{$ifdef fpc}
|
||||||
|
{$mode delphi}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils,
|
||||||
|
pdfvrlexico, pdfvrsintatico, pdfvrsemantico, avisozlib,
|
||||||
|
fpvectorial;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
TCDRChunk = class
|
||||||
|
Name: array[0..3] of Char;
|
||||||
|
Size: Cardinal;
|
||||||
|
ChildChunks: TFPList;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TCDRChunkClass = class of TCDRChunk;
|
||||||
|
|
||||||
|
TvCDRInternalData = TCDRChunk;
|
||||||
|
|
||||||
|
TCDRChunkVRSN = class(TCDRChunk)
|
||||||
|
VersionStr: string;
|
||||||
|
VersionNum: Integer;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TvCDRVectorialReader }
|
||||||
|
|
||||||
|
TvCDRVectorialReader = class(TvCustomVectorialReader)
|
||||||
|
private
|
||||||
|
procedure ReadVersionChunk(AStream: TStream; var AData: TCDRChunk);
|
||||||
|
function AddNewChunk(var AData: TCDRChunk; AClass: TCDRChunkClass): TCDRChunk;
|
||||||
|
public
|
||||||
|
{ General reading methods }
|
||||||
|
procedure ReadFromStream(AStream: TStream; AData: TvVectorialDocument); override;
|
||||||
|
{ File format exploring methods }
|
||||||
|
procedure ExploreFromFile(AFilename: string; out AData: TvCDRInternalData);
|
||||||
|
procedure ExploreFromStream(AStream: TStream; out AData: TvCDRInternalData);
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{ TvPDFVectorialReader }
|
||||||
|
|
||||||
|
procedure TvCDRVectorialReader.ReadVersionChunk(AStream: TStream;
|
||||||
|
var AData: TCDRChunk);
|
||||||
|
var
|
||||||
|
lDWord: DWord;
|
||||||
|
lChunk: TCDRChunkVRSN absolute AData;
|
||||||
|
lVerBytes: array[0..1] of Byte;
|
||||||
|
begin
|
||||||
|
// Read the Chunk name
|
||||||
|
lDWord := AStream.ReadDWord();
|
||||||
|
|
||||||
|
// Read the Chunk size
|
||||||
|
lDWord := AStream.ReadDWord();
|
||||||
|
|
||||||
|
// Read the version
|
||||||
|
AStream.Read(lVerBytes, 2);
|
||||||
|
|
||||||
|
if (lVerBytes[0] = $BC) and (lVerBytes[1] = $02) then
|
||||||
|
begin
|
||||||
|
lChunk.VersionNum := 7;
|
||||||
|
lChunk.VersionStr := 'CorelDraw 7';
|
||||||
|
end
|
||||||
|
else if (lVerBytes[0] = $20) and (lVerBytes[1] = $03) then
|
||||||
|
begin
|
||||||
|
lChunk.VersionNum := 8;
|
||||||
|
lChunk.VersionStr := 'CorelDraw 8';
|
||||||
|
end
|
||||||
|
else if (lVerBytes[0] = $21) and (lVerBytes[1] = $03) then
|
||||||
|
begin
|
||||||
|
lChunk.VersionNum := 8;
|
||||||
|
lChunk.VersionStr := 'CorelDraw 8bidi';
|
||||||
|
end
|
||||||
|
else if (lVerBytes[0] = $84) and (lVerBytes[1] = $03) then
|
||||||
|
begin
|
||||||
|
lChunk.VersionNum := 9;
|
||||||
|
lChunk.VersionStr := 'CorelDraw 9';
|
||||||
|
end
|
||||||
|
else if (lVerBytes[0] = $E8) and (lVerBytes[1] = $03) then
|
||||||
|
begin
|
||||||
|
lChunk.VersionNum := 10;
|
||||||
|
lChunk.VersionStr := 'CorelDraw 10';
|
||||||
|
end
|
||||||
|
else if (lVerBytes[0] = $4C) and (lVerBytes[1] = $04) then
|
||||||
|
begin
|
||||||
|
lChunk.VersionNum := 11;
|
||||||
|
lChunk.VersionStr := 'CorelDraw 11';
|
||||||
|
end
|
||||||
|
else if (lVerBytes[0] = $B0) and (lVerBytes[1] = $04) then
|
||||||
|
begin
|
||||||
|
lChunk.VersionNum := 12;
|
||||||
|
lChunk.VersionStr := 'CorelDraw 12';
|
||||||
|
end
|
||||||
|
else if (lVerBytes[0] = $14) and (lVerBytes[1] = $05) then
|
||||||
|
begin
|
||||||
|
lChunk.VersionNum := 13;
|
||||||
|
lChunk.VersionStr := 'CorelDraw X3';
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TvCDRVectorialReader.AddNewChunk(var AData: TCDRChunk; AClass: TCDRChunkClass): TCDRChunk;
|
||||||
|
begin
|
||||||
|
if AData.ChildChunks = nil then AData.ChildChunks := TFPList.Create;
|
||||||
|
|
||||||
|
Result := AClass.Create;
|
||||||
|
|
||||||
|
AData.ChildChunks.Add(Result);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvCDRVectorialReader.ReadFromStream(AStream: TStream;
|
||||||
|
AData: TvVectorialDocument);
|
||||||
|
begin
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvCDRVectorialReader.ExploreFromFile(AFilename: string;
|
||||||
|
out AData: TvCDRInternalData);
|
||||||
|
var
|
||||||
|
FileStream: TFileStream;
|
||||||
|
begin
|
||||||
|
FileStream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone);
|
||||||
|
try
|
||||||
|
ExploreFromStream(FileStream, AData);
|
||||||
|
finally
|
||||||
|
FileStream.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvCDRVectorialReader.ExploreFromStream(AStream: TStream;
|
||||||
|
out AData: TvCDRInternalData);
|
||||||
|
var
|
||||||
|
lRIFF: array[0..3] of Char;
|
||||||
|
lDocSize, lDWord: Cardinal;
|
||||||
|
lChild: TCDRChunk;
|
||||||
|
begin
|
||||||
|
// Create the data object
|
||||||
|
AData := TCDRChunk.Create;
|
||||||
|
|
||||||
|
// All CorelDraw files starts with "RIFF"
|
||||||
|
AStream.Read(lRIFF, 4);
|
||||||
|
if lRIFF <> 'RIFF' then
|
||||||
|
raise Exception.Create('[TvCDRVectorialReader.ExploreFromStream] The Corel Draw RIFF file marker wasn''t found.');
|
||||||
|
|
||||||
|
// And then 4 bytes for the document size
|
||||||
|
lDocSize := AStream.ReadDWord();
|
||||||
|
|
||||||
|
// And mroe 4 bytes of other stuff
|
||||||
|
lDWord := AStream.ReadDWord();
|
||||||
|
|
||||||
|
// Now comes the version
|
||||||
|
lChild := AddNewChunk(AData, TCDRChunkVRSN);
|
||||||
|
ReadVersionChunk(AStream, lChild);
|
||||||
|
end;
|
||||||
|
|
||||||
|
initialization
|
||||||
|
|
||||||
|
RegisterVectorialReader(TvCDRVectorialReader, vfCorelDrawCDR);
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
300
applications/fpvviewer/fpvectorialsrc/dxfvectorialreader.pas
Normal file
300
applications/fpvviewer/fpvectorialsrc/dxfvectorialreader.pas
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
{
|
||||||
|
Reads DXF files
|
||||||
|
|
||||||
|
License: The same modified LGPL as the Free Pascal RTL
|
||||||
|
See the file COPYING.modifiedLGPL for more details
|
||||||
|
|
||||||
|
AUTHORS: Felipe Monteiro de Carvalho
|
||||||
|
|
||||||
|
DXF is composed by records written in ASCII with the following structure:
|
||||||
|
|
||||||
|
0
|
||||||
|
SECTION
|
||||||
|
section_number
|
||||||
|
SECTION_NAME
|
||||||
|
<data>
|
||||||
|
0
|
||||||
|
ENDSEC
|
||||||
|
0
|
||||||
|
|
||||||
|
after all section end there is:
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
}
|
||||||
|
unit dxfvectorialreader;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils,
|
||||||
|
fpvectorial;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ Used by tcutils.SeparateString }
|
||||||
|
T10Strings = array[0..9] of shortstring;
|
||||||
|
|
||||||
|
{ TvDXFVectorialReader }
|
||||||
|
|
||||||
|
TvDXFVectorialReader = class(TvCustomVectorialReader)
|
||||||
|
private
|
||||||
|
LineStartX, LineStartY, LineStartZ: Double;
|
||||||
|
LineEndX, LineEndY, LineEndZ: Double;
|
||||||
|
function SeparateString(AString: string; ASeparator: Char): T10Strings;
|
||||||
|
function ReadSection(AStrings: TStrings; var AIndex: Integer; AData: TvVectorialDocument): Boolean;
|
||||||
|
function ReadENTITIES(AStrings: TStrings; var AIndex: Integer; AData: TvVectorialDocument): Boolean;
|
||||||
|
function ReadENTITIES_LINE(AStrings: TStrings; var AIndex: Integer; AData: TvVectorialDocument): Boolean;
|
||||||
|
function GetCoordinate(AStr: shortstring): Integer;
|
||||||
|
function GetCoordinateValue(AStr: shortstring): Double;
|
||||||
|
public
|
||||||
|
{ General reading methods }
|
||||||
|
procedure ReadFromStrings(AStrings: TStrings; AData: TvVectorialDocument); override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{$define FPVECTORIALDEBUG}
|
||||||
|
|
||||||
|
const
|
||||||
|
{ Coordinate constants }
|
||||||
|
|
||||||
|
INT_COORDINATE_NONE = 0;
|
||||||
|
INT_COORDINATE_X = 1;
|
||||||
|
INT_COORDINATE_Y = 2;
|
||||||
|
INT_COORDINATE_Z = 3;
|
||||||
|
|
||||||
|
{ GCode constants }
|
||||||
|
|
||||||
|
STR_GCODE_LINEAR_MOVE = 'G01';
|
||||||
|
STR_GCODE_STEPPER_MOVE = 'S01';
|
||||||
|
STR_GCODE_2DBEZIER_MOVE = 'B02';
|
||||||
|
STR_GCODE_3DBEZIER_MOVE = 'B03';
|
||||||
|
STR_GCODE_DRILL_UP = 'P01';
|
||||||
|
STR_GCODE_DRILL_DOWN = 'P02';
|
||||||
|
|
||||||
|
{ TvAvisoCNCGCodeReader }
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Reads a string and separates it in substring
|
||||||
|
using ASeparator to delimite them.
|
||||||
|
|
||||||
|
Limits:
|
||||||
|
|
||||||
|
Number of substrings: 10 (indexed 0 to 9)
|
||||||
|
Length of each substring: 255 (they are shortstrings)
|
||||||
|
}
|
||||||
|
function TvDXFVectorialReader.SeparateString(AString: string; ASeparator: Char): T10Strings;
|
||||||
|
var
|
||||||
|
i, CurrentPart: Integer;
|
||||||
|
begin
|
||||||
|
CurrentPart := 0;
|
||||||
|
|
||||||
|
{ Clears the result }
|
||||||
|
for i := 0 to 9 do Result[i] := '';
|
||||||
|
|
||||||
|
{ Iterates througth the string, filling strings }
|
||||||
|
for i := 1 to Length(AString) do
|
||||||
|
begin
|
||||||
|
if Copy(AString, i, 1) = ASeparator then
|
||||||
|
begin
|
||||||
|
Inc(CurrentPart);
|
||||||
|
|
||||||
|
{ Verifies if the string capacity wasn't exceeded }
|
||||||
|
if CurrentPart > 9 then Exit;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result[CurrentPart] := Result[CurrentPart] + Copy(AString, i, 1);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
returns If an end of file marker was found
|
||||||
|
}
|
||||||
|
function TvDXFVectorialReader.ReadSection(
|
||||||
|
AStrings: TStrings; var AIndex: Integer; AData: TvVectorialDocument): Boolean;
|
||||||
|
var
|
||||||
|
DestX, DestY, DestZ: Double;
|
||||||
|
StrSectionNum, StrSectionName: string;
|
||||||
|
IntSectionNum, i: Integer;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
|
||||||
|
// Check if there is minimal space for a section
|
||||||
|
if AIndex+5 > AStrings.Count then
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn('Not enough space for a section');
|
||||||
|
{$endif}
|
||||||
|
Exit(True);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Check of the EOF marker
|
||||||
|
StrSectionName := Trim(AStrings.Strings[AIndex+1]);
|
||||||
|
if StrSectionName = 'EOF' then
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn('EOF found');
|
||||||
|
{$endif}
|
||||||
|
Exit(True);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Now read and process the section name
|
||||||
|
StrSectionNum := AStrings.Strings[AIndex+2];
|
||||||
|
IntSectionNum := StrToInt(Trim(StrSectionNum));
|
||||||
|
StrSectionName := AStrings.Strings[AIndex+3];
|
||||||
|
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn('TvDXFVectorialReader.ReadSection ' + StrSectionName);
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
if (StrSectionName = 'HEADER') or
|
||||||
|
(StrSectionName = 'CLASSES') or
|
||||||
|
(StrSectionName = 'TABLES') or
|
||||||
|
(StrSectionName = 'BLOCKS') or
|
||||||
|
(StrSectionName = 'OBJECTS') or
|
||||||
|
(StrSectionName = 'THUMBNAILIMAGE') then
|
||||||
|
begin
|
||||||
|
// We don't care about contents here, so let's just find the last section and get out of here.
|
||||||
|
for i := AIndex + 4 to AStrings.Count - 1 do
|
||||||
|
begin
|
||||||
|
if AStrings.Strings[i] = 'ENDSEC' then
|
||||||
|
begin
|
||||||
|
AIndex := i + 1;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
// If we reached here, the section in incomplete
|
||||||
|
raise Exception.Create('TvDXFVectorialReader.ReadSection: ENDSEC was not found in the SECTION');
|
||||||
|
end
|
||||||
|
else if StrSectionName = 'ENTITIES' then
|
||||||
|
begin
|
||||||
|
AIndex := AIndex + 4;
|
||||||
|
while not ReadENTITIES(AStrings, AIndex, AData) do ;
|
||||||
|
end;
|
||||||
|
{else
|
||||||
|
begin
|
||||||
|
end;}
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TvDXFVectorialReader.ReadENTITIES(AStrings: TStrings;
|
||||||
|
var AIndex: Integer; AData: TvVectorialDocument): Boolean;
|
||||||
|
var
|
||||||
|
StrSectionNum, StrSectionName: string;
|
||||||
|
IntSectionNum, i: Integer;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
|
||||||
|
// Now read and process the item name
|
||||||
|
StrSectionName := AStrings.Strings[AIndex+1];
|
||||||
|
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn('TvDXFVectorialReader.ReadENTITIES ', StrSectionName);
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
if StrSectionName = 'ENDSEC' then
|
||||||
|
begin
|
||||||
|
Inc(AIndex, 2);
|
||||||
|
Exit(True);
|
||||||
|
end
|
||||||
|
else if StrSectionName = 'LINE' then
|
||||||
|
begin
|
||||||
|
// Initial values
|
||||||
|
LineStartX := 0;
|
||||||
|
LineStartY := 0;
|
||||||
|
LineStartZ := 0;
|
||||||
|
LineEndX := 0;
|
||||||
|
LineEndY := 0;
|
||||||
|
LineEndZ := 0;
|
||||||
|
|
||||||
|
// Read the data of the line
|
||||||
|
Inc(AIndex, 2);
|
||||||
|
while not ReadENTITIES_LINE(AStrings, AIndex, AData) do ;
|
||||||
|
|
||||||
|
// And now write it
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(Format('Adding Line from %f,%f to %f,%f', [LineStartX, LineStartY, LineEndX, LineEndY]));
|
||||||
|
{$endif}
|
||||||
|
AData.StartPath(LineStartX, LineStartY);
|
||||||
|
AData.AddLineToPath(LineEndX, LineEndY);
|
||||||
|
AData.EndPath();
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TvDXFVectorialReader.ReadENTITIES_LINE(AStrings: TStrings;
|
||||||
|
var AIndex: Integer; AData: TvVectorialDocument): Boolean;
|
||||||
|
var
|
||||||
|
StrSectionNum, StrSectionValue: string;
|
||||||
|
IntSectionNum: Integer;
|
||||||
|
FloatSectionValue: double;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
|
||||||
|
// Now read and process the item name
|
||||||
|
StrSectionNum := AStrings.Strings[AIndex];
|
||||||
|
StrSectionValue := AStrings.Strings[AIndex+1];
|
||||||
|
|
||||||
|
if (StrSectionValue = 'LINE') or
|
||||||
|
(StrSectionValue = 'ENDSEC') then
|
||||||
|
begin
|
||||||
|
Exit(True);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Inc(AIndex, 2);
|
||||||
|
|
||||||
|
IntSectionNum := StrToInt(Trim(StrSectionNum));
|
||||||
|
FloatSectionValue := StrToFloat(Trim(StrSectionValue));
|
||||||
|
|
||||||
|
case IntSectionNum of
|
||||||
|
10: LineStartX := FloatSectionValue;
|
||||||
|
20: LineStartY := FloatSectionValue;
|
||||||
|
30: LineStartZ := FloatSectionValue;
|
||||||
|
11: LineEndX := FloatSectionValue;
|
||||||
|
21: LineEndY := FloatSectionValue;
|
||||||
|
31: LineEndZ := FloatSectionValue;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TvDXFVectorialReader.GetCoordinate(AStr: shortstring): Integer;
|
||||||
|
begin
|
||||||
|
Result := INT_COORDINATE_NONE;
|
||||||
|
|
||||||
|
if AStr = '' then Exit
|
||||||
|
else if AStr[1] = 'X' then Result := INT_COORDINATE_X
|
||||||
|
else if AStr[1] = 'Y' then Result := INT_COORDINATE_Y
|
||||||
|
else if AStr[1] = 'Z' then Result := INT_COORDINATE_Z;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TvDXFVectorialReader.GetCoordinateValue(AStr: shortstring): Double;
|
||||||
|
begin
|
||||||
|
Result := 0.0;
|
||||||
|
|
||||||
|
if Length(AStr) <= 1 then Exit;
|
||||||
|
|
||||||
|
Result := StrToFloat(Copy(AStr, 2, Length(AStr) - 1));
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
The information of each separate path is lost in G-Code files
|
||||||
|
Only one path uniting all of them is created when reading G-Code
|
||||||
|
}
|
||||||
|
procedure TvDXFVectorialReader.ReadFromStrings(AStrings: TStrings;
|
||||||
|
AData: TvVectorialDocument);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
i := 0;
|
||||||
|
while i < AStrings.Count - 1 do
|
||||||
|
if ReadSection(AStrings, i, AData) then Break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
initialization
|
||||||
|
|
||||||
|
RegisterVectorialReader(TvDXFVectorialReader, vfDXF);
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
10
applications/fpvviewer/fpvectorialsrc/fpvectbuildunit.pas
Normal file
10
applications/fpvviewer/fpvectorialsrc/fpvectbuildunit.pas
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
unit fpvectbuildunit;
|
||||||
|
|
||||||
|
interface
|
||||||
|
Uses
|
||||||
|
avisocncgcodereader,avisocncgcodewriter,avisozlib,fpvectorial,
|
||||||
|
fpvtocanvas,pdfvectorialreader,pdfvrlexico,pdfvrsemantico,pdfvrsintatico,
|
||||||
|
svgvectorialwriter,cdrvectorialreader;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
end.
|
888
applications/fpvviewer/fpvectorialsrc/fpvectorial.pas
Normal file
888
applications/fpvviewer/fpvectorialsrc/fpvectorial.pas
Normal file
@ -0,0 +1,888 @@
|
|||||||
|
{
|
||||||
|
fpvectorial.pas
|
||||||
|
|
||||||
|
Vector graphics document
|
||||||
|
|
||||||
|
License: The same modified LGPL as the Free Pascal RTL
|
||||||
|
See the file COPYING.modifiedLGPL for more details
|
||||||
|
|
||||||
|
AUTHORS: Felipe Monteiro de Carvalho
|
||||||
|
Pedro Sol Pegorini L de Lima
|
||||||
|
}
|
||||||
|
unit fpvectorial;
|
||||||
|
|
||||||
|
{$ifdef fpc}
|
||||||
|
{$mode delphi}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils;
|
||||||
|
|
||||||
|
type
|
||||||
|
TvVectorialFormat = (
|
||||||
|
{ Multi-purpose document formats }
|
||||||
|
vfPDF, vfPostScript, vfSVG, vfCorelDrawCDR, vfWindowsMetafileWMF,
|
||||||
|
{ CAD formats }
|
||||||
|
vfDXF,
|
||||||
|
{ GCode formats }
|
||||||
|
vfGCodeAvisoCNCPrototipoV5, vfGCodeAvisoCNCPrototipoV6);
|
||||||
|
|
||||||
|
const
|
||||||
|
{ Default extensions }
|
||||||
|
{ Multi-purpose document formats }
|
||||||
|
STR_PDF_EXTENSION = '.pdf';
|
||||||
|
STR_POSTSCRIPT_EXTENSION = '.ps';
|
||||||
|
STR_SVG_EXTENSION = '.svg';
|
||||||
|
STR_CORELDRAW_EXTENSION = '.cdr';
|
||||||
|
STR_WINMETAFILE_EXTENSION = '.wmf';
|
||||||
|
|
||||||
|
type
|
||||||
|
TSegmentType = (
|
||||||
|
st2DLine, st2DBezier,
|
||||||
|
st3DLine, st3DBezier, stMoveTo);
|
||||||
|
|
||||||
|
{@@
|
||||||
|
The coordinates in fpvectorial are given in millimiters and
|
||||||
|
the starting point is in the bottom-left corner of the document.
|
||||||
|
The X grows to the right and the Y grows to the top.
|
||||||
|
}
|
||||||
|
{ TPathSegment }
|
||||||
|
|
||||||
|
TPathSegment = class
|
||||||
|
public
|
||||||
|
SegmentType: TSegmentType;
|
||||||
|
// Fields for linking the list
|
||||||
|
Previous: TPathSegment;
|
||||||
|
Next: TPathSegment;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
In a 2D segment, the X and Y coordinates represent usually the
|
||||||
|
final point of the segment, being that it starts where the previous
|
||||||
|
segment ends. The exception is for the first segment of all, which simply
|
||||||
|
holds the starting point for the drawing and should always be of the type
|
||||||
|
stMoveTo.
|
||||||
|
}
|
||||||
|
T2DSegment = class(TPathSegment)
|
||||||
|
public
|
||||||
|
X, Y: Double;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
In Bezier segments, we remain using the X and Y coordinates for the ending point.
|
||||||
|
The starting point is where the previous segment ended, so that the intermediary
|
||||||
|
bezier control points are [X2, Y2] and [X3, Y3].
|
||||||
|
}
|
||||||
|
T2DBezierSegment = class(T2DSegment)
|
||||||
|
public
|
||||||
|
X2, Y2: Double;
|
||||||
|
X3, Y3: Double;
|
||||||
|
end;
|
||||||
|
|
||||||
|
T3DSegment = class(TPathSegment)
|
||||||
|
public
|
||||||
|
{@@
|
||||||
|
Coordinates of the end of the segment.
|
||||||
|
For the first segment, this is the starting point.
|
||||||
|
}
|
||||||
|
X, Y, Z: Double;
|
||||||
|
end;
|
||||||
|
|
||||||
|
T3DBezierSegment = class(T3DSegment)
|
||||||
|
public
|
||||||
|
X2, Y2, Z2: Double;
|
||||||
|
X3, Y3, Z3: Double;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TPath = class
|
||||||
|
Len: Integer;
|
||||||
|
Points: TPathSegment; // Beginning of the double-linked list
|
||||||
|
PointsEnd: TPathSegment; // End of the double-linked list
|
||||||
|
CurPoint: TPathSegment; // Used in PrepareForSequentialReading and Next
|
||||||
|
procedure Assign(APath: TPath);
|
||||||
|
function Count(): TPathSegment;
|
||||||
|
procedure PrepareForSequentialReading;
|
||||||
|
function Next(): TPathSegment;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
TvText represents a text in memory.
|
||||||
|
|
||||||
|
At the moment fonts are unsupported, only simple texts
|
||||||
|
up to 255 chars are supported.
|
||||||
|
}
|
||||||
|
TvText = class
|
||||||
|
public
|
||||||
|
X, Y, Z: Double; // Z is ignored in 2D formats
|
||||||
|
FontSize: integer;
|
||||||
|
FontName: utf8string;
|
||||||
|
Value: utf8string;
|
||||||
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
TvCustomVectorialWriter = class;
|
||||||
|
TvCustomVectorialReader = class;
|
||||||
|
|
||||||
|
{ TvVectorialDocument }
|
||||||
|
|
||||||
|
TvVectorialDocument = class
|
||||||
|
private
|
||||||
|
FPaths: TFPList;
|
||||||
|
FTexts: TFPList;
|
||||||
|
FTmpPath: TPath;
|
||||||
|
FTmpText: TvText;
|
||||||
|
procedure RemoveCallback(data, arg: pointer);
|
||||||
|
function CreateVectorialWriter(AFormat: TvVectorialFormat): TvCustomVectorialWriter;
|
||||||
|
function CreateVectorialReader(AFormat: TvVectorialFormat): TvCustomVectorialReader;
|
||||||
|
procedure ClearTmpPath();
|
||||||
|
procedure AppendSegmentToTmpPath(ASegment: TPathSegment);
|
||||||
|
public
|
||||||
|
Name: string;
|
||||||
|
Width, Height: Double; // in millimeters
|
||||||
|
{ Base methods }
|
||||||
|
constructor Create;
|
||||||
|
destructor Destroy; override;
|
||||||
|
procedure WriteToFile(AFileName: string; AFormat: TvVectorialFormat);
|
||||||
|
procedure WriteToStream(AStream: TStream; AFormat: TvVectorialFormat);
|
||||||
|
procedure WriteToStrings(AStrings: TStrings; AFormat: TvVectorialFormat);
|
||||||
|
procedure ReadFromFile(AFileName: string; AFormat: TvVectorialFormat);
|
||||||
|
procedure ReadFromStream(AStream: TStream; AFormat: TvVectorialFormat);
|
||||||
|
procedure ReadFromStrings(AStrings: TStrings; AFormat: TvVectorialFormat);
|
||||||
|
class function GetFormatFromExtension(AFileName: string): TvVectorialFormat;
|
||||||
|
function GetDetailedFileFormat(): string;
|
||||||
|
{ Data reading methods }
|
||||||
|
function GetPath(ANum: Cardinal): TPath;
|
||||||
|
function GetPathCount: Integer;
|
||||||
|
function GetText(ANum: Cardinal): TvText;
|
||||||
|
function GetTextCount: Integer;
|
||||||
|
{ Data removing methods }
|
||||||
|
procedure Clear;
|
||||||
|
procedure RemoveAllPaths;
|
||||||
|
procedure RemoveAllTexts;
|
||||||
|
{ Data writing methods }
|
||||||
|
procedure AddPath(APath: TPath);
|
||||||
|
procedure StartPath(AX, AY: Double);
|
||||||
|
procedure AddLineToPath(AX, AY: Double); overload;
|
||||||
|
procedure AddLineToPath(AX, AY, AZ: Double); overload;
|
||||||
|
procedure AddBezierToPath(AX1, AY1, AX2, AY2, AX3, AY3: Double); overload;
|
||||||
|
procedure AddBezierToPath(AX1, AY1, AZ1, AX2, AY2, AZ2, AX3, AY3, AZ3: Double); overload;
|
||||||
|
procedure EndPath();
|
||||||
|
procedure AddText(AX, AY, AZ: Double; FontName: string; FontSize: integer; AText: utf8string); overload;
|
||||||
|
procedure AddText(AX, AY, AZ: Double; AStr: utf8string); overload;
|
||||||
|
{ properties }
|
||||||
|
property PathCount: Integer read GetPathCount;
|
||||||
|
property Paths[Index: Cardinal]: TPath read GetPath;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ TvVectorialReader class reference type }
|
||||||
|
|
||||||
|
TvVectorialReaderClass = class of TvCustomVectorialReader;
|
||||||
|
|
||||||
|
{ TvCustomVectorialReader }
|
||||||
|
|
||||||
|
TvCustomVectorialReader = class
|
||||||
|
public
|
||||||
|
{ General reading methods }
|
||||||
|
procedure ReadFromFile(AFileName: string; AData: TvVectorialDocument); virtual;
|
||||||
|
procedure ReadFromStream(AStream: TStream; AData: TvVectorialDocument); virtual;
|
||||||
|
procedure ReadFromStrings(AStrings: TStrings; AData: TvVectorialDocument); virtual;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ TvVectorialWriter class reference type }
|
||||||
|
|
||||||
|
TvVectorialWriterClass = class of TvCustomVectorialWriter;
|
||||||
|
|
||||||
|
{@@ TvCustomVectorialWriter }
|
||||||
|
|
||||||
|
{ TvCustomVectorialWriter }
|
||||||
|
|
||||||
|
TvCustomVectorialWriter = class
|
||||||
|
public
|
||||||
|
{ General writing methods }
|
||||||
|
procedure WriteToFile(AFileName: string; AData: TvVectorialDocument); virtual;
|
||||||
|
procedure WriteToStream(AStream: TStream; AData: TvVectorialDocument); virtual;
|
||||||
|
procedure WriteToStrings(AStrings: TStrings; AData: TvVectorialDocument); virtual;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ List of registered formats }
|
||||||
|
|
||||||
|
TvVectorialFormatData = record
|
||||||
|
ReaderClass: TvVectorialReaderClass;
|
||||||
|
WriterClass: TvVectorialWriterClass;
|
||||||
|
ReaderRegistered: Boolean;
|
||||||
|
WriterRegistered: Boolean;
|
||||||
|
Format: TvVectorialFormat;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
GvVectorialFormats: array of TvVectorialFormatData;
|
||||||
|
|
||||||
|
procedure RegisterVectorialReader(
|
||||||
|
AReaderClass: TvVectorialReaderClass;
|
||||||
|
AFormat: TvVectorialFormat);
|
||||||
|
procedure RegisterVectorialWriter(
|
||||||
|
AWriterClass: TvVectorialWriterClass;
|
||||||
|
AFormat: TvVectorialFormat);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
const
|
||||||
|
Str_Error_Nil_Path = ' The program attempted to add a segment before creating a path';
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Registers a new reader for a format
|
||||||
|
}
|
||||||
|
procedure RegisterVectorialReader(
|
||||||
|
AReaderClass: TvVectorialReaderClass;
|
||||||
|
AFormat: TvVectorialFormat);
|
||||||
|
var
|
||||||
|
i, len: Integer;
|
||||||
|
FormatInTheList: Boolean;
|
||||||
|
begin
|
||||||
|
len := Length(GvVectorialFormats);
|
||||||
|
FormatInTheList := False;
|
||||||
|
|
||||||
|
{ First search for the format in the list }
|
||||||
|
for i := 0 to len - 1 do
|
||||||
|
begin
|
||||||
|
if GvVectorialFormats[i].Format = AFormat then
|
||||||
|
begin
|
||||||
|
if GvVectorialFormats[i].ReaderRegistered then
|
||||||
|
raise Exception.Create('RegisterVectorialReader: Reader class for format ' {+ AFormat} + ' already registered.');
|
||||||
|
|
||||||
|
GvVectorialFormats[i].ReaderRegistered := True;
|
||||||
|
GvVectorialFormats[i].ReaderClass := AReaderClass;
|
||||||
|
|
||||||
|
FormatInTheList := True;
|
||||||
|
Break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ If not already in the list, then add it }
|
||||||
|
if not FormatInTheList then
|
||||||
|
begin
|
||||||
|
SetLength(GvVectorialFormats, len + 1);
|
||||||
|
|
||||||
|
GvVectorialFormats[len].ReaderClass := AReaderClass;
|
||||||
|
GvVectorialFormats[len].WriterClass := nil;
|
||||||
|
GvVectorialFormats[len].ReaderRegistered := True;
|
||||||
|
GvVectorialFormats[len].WriterRegistered := False;
|
||||||
|
GvVectorialFormats[len].Format := AFormat;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Registers a new writer for a format
|
||||||
|
}
|
||||||
|
procedure RegisterVectorialWriter(
|
||||||
|
AWriterClass: TvVectorialWriterClass;
|
||||||
|
AFormat: TvVectorialFormat);
|
||||||
|
var
|
||||||
|
i, len: Integer;
|
||||||
|
FormatInTheList: Boolean;
|
||||||
|
begin
|
||||||
|
len := Length(GvVectorialFormats);
|
||||||
|
FormatInTheList := False;
|
||||||
|
|
||||||
|
{ First search for the format in the list }
|
||||||
|
for i := 0 to len - 1 do
|
||||||
|
begin
|
||||||
|
if GvVectorialFormats[i].Format = AFormat then
|
||||||
|
begin
|
||||||
|
if GvVectorialFormats[i].WriterRegistered then
|
||||||
|
raise Exception.Create('RegisterVectorialWriter: Writer class for format ' + {AFormat +} ' already registered.');
|
||||||
|
|
||||||
|
GvVectorialFormats[i].WriterRegistered := True;
|
||||||
|
GvVectorialFormats[i].WriterClass := AWriterClass;
|
||||||
|
|
||||||
|
FormatInTheList := True;
|
||||||
|
Break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ If not already in the list, then add it }
|
||||||
|
if not FormatInTheList then
|
||||||
|
begin
|
||||||
|
SetLength(GvVectorialFormats, len + 1);
|
||||||
|
|
||||||
|
GvVectorialFormats[len].ReaderClass := nil;
|
||||||
|
GvVectorialFormats[len].WriterClass := AWriterClass;
|
||||||
|
GvVectorialFormats[len].ReaderRegistered := False;
|
||||||
|
GvVectorialFormats[len].WriterRegistered := True;
|
||||||
|
GvVectorialFormats[len].Format := AFormat;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TsWorksheet }
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Helper method for clearing the records in a spreadsheet.
|
||||||
|
}
|
||||||
|
procedure TvVectorialDocument.RemoveCallback(data, arg: pointer);
|
||||||
|
begin
|
||||||
|
{ if data <> nil then
|
||||||
|
begin
|
||||||
|
ldata := PObject(data);
|
||||||
|
ldata^.Free;
|
||||||
|
end;}
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Constructor.
|
||||||
|
}
|
||||||
|
constructor TvVectorialDocument.Create;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
|
||||||
|
FPaths := TFPList.Create;
|
||||||
|
FTexts := TFPList.Create;
|
||||||
|
FTmpPath := TPath.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Destructor.
|
||||||
|
}
|
||||||
|
destructor TvVectorialDocument.Destroy;
|
||||||
|
begin
|
||||||
|
Clear;
|
||||||
|
|
||||||
|
FPaths.Free;
|
||||||
|
FTexts.Free;
|
||||||
|
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Clears the list of Vectors and releases their memory.
|
||||||
|
}
|
||||||
|
procedure TvVectorialDocument.RemoveAllPaths;
|
||||||
|
begin
|
||||||
|
// FPaths.ForEachCall(RemoveCallback, nil);
|
||||||
|
FPaths.Clear;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvVectorialDocument.RemoveAllTexts;
|
||||||
|
begin
|
||||||
|
// FTexts.ForEachCall(RemoveCallback, nil);
|
||||||
|
FTexts.Clear;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvVectorialDocument.AddPath(APath: TPath);
|
||||||
|
var
|
||||||
|
lPath: TPath;
|
||||||
|
Len: Integer;
|
||||||
|
begin
|
||||||
|
lPath := TPath.Create;
|
||||||
|
lPath.Assign(APath);
|
||||||
|
FPaths.Add(Pointer(lPath));
|
||||||
|
//WriteLn(':>TvVectorialDocument.AddPath 1 Len = ', Len);
|
||||||
|
//WriteLn(':>TvVectorialDocument.AddPath 2');
|
||||||
|
//WriteLn(':>TvVectorialDocument.AddPath 3');
|
||||||
|
//WriteLn(':>TvVectorialDocument.AddPath 4');
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Starts writing a Path in multiple steps.
|
||||||
|
Should be followed by zero or more calls to AddPointToPath
|
||||||
|
and by a call to EndPath to effectively add the data.
|
||||||
|
|
||||||
|
@see StartPath, AddPointToPath
|
||||||
|
}
|
||||||
|
procedure TvVectorialDocument.StartPath(AX, AY: Double);
|
||||||
|
var
|
||||||
|
segment: T2DSegment;
|
||||||
|
begin
|
||||||
|
ClearTmpPath();
|
||||||
|
|
||||||
|
FTmpPath.Len := 1;
|
||||||
|
segment := T2DSegment.Create;
|
||||||
|
segment.SegmentType := stMoveTo;
|
||||||
|
segment.X := AX;
|
||||||
|
segment.Y := AY;
|
||||||
|
|
||||||
|
FTmpPath.Points := segment;
|
||||||
|
FTmpPath.PointsEnd := segment;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Adds one more point to the end of a Path being
|
||||||
|
writing in multiple steps.
|
||||||
|
|
||||||
|
Does nothing if not called between StartPath and EndPath.
|
||||||
|
|
||||||
|
Can be called multiple times to add multiple points.
|
||||||
|
|
||||||
|
@see StartPath, EndPath
|
||||||
|
}
|
||||||
|
procedure TvVectorialDocument.AddLineToPath(AX, AY: Double);
|
||||||
|
var
|
||||||
|
segment: T2DSegment;
|
||||||
|
begin
|
||||||
|
segment := T2DSegment.Create;
|
||||||
|
segment.SegmentType := st2DLine;
|
||||||
|
segment.X := AX;
|
||||||
|
segment.Y := AY;
|
||||||
|
|
||||||
|
AppendSegmentToTmpPath(segment);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvVectorialDocument.AddLineToPath(AX, AY, AZ: Double);
|
||||||
|
var
|
||||||
|
segment: T3DSegment;
|
||||||
|
begin
|
||||||
|
segment := T3DSegment.Create;
|
||||||
|
segment.SegmentType := st3DLine;
|
||||||
|
segment.X := AX;
|
||||||
|
segment.Y := AY;
|
||||||
|
segment.Z := AZ;
|
||||||
|
|
||||||
|
AppendSegmentToTmpPath(segment);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Adds a bezier element to the path. It starts where the previous element ended
|
||||||
|
and it goes throw the control points [AX1, AY1] and [AX2, AY2] and ends
|
||||||
|
in [AX3, AY3].
|
||||||
|
}
|
||||||
|
procedure TvVectorialDocument.AddBezierToPath(AX1, AY1, AX2, AY2, AX3,
|
||||||
|
AY3: Double);
|
||||||
|
var
|
||||||
|
segment: T2DBezierSegment;
|
||||||
|
begin
|
||||||
|
segment := T2DBezierSegment.Create;
|
||||||
|
segment.SegmentType := st2DBezier;
|
||||||
|
segment.X := AX3;
|
||||||
|
segment.Y := AY3;
|
||||||
|
segment.X2 := AX1;
|
||||||
|
segment.Y2 := AY1;
|
||||||
|
segment.X3 := AX2;
|
||||||
|
segment.Y3 := AY2;
|
||||||
|
|
||||||
|
AppendSegmentToTmpPath(segment);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvVectorialDocument.AddBezierToPath(AX1, AY1, AZ1, AX2, AY2, AZ2,
|
||||||
|
AX3, AY3, AZ3: Double);
|
||||||
|
var
|
||||||
|
segment: T3DBezierSegment;
|
||||||
|
begin
|
||||||
|
segment := T3DBezierSegment.Create;
|
||||||
|
segment.SegmentType := st3DBezier;
|
||||||
|
segment.X := AX3;
|
||||||
|
segment.Y := AY3;
|
||||||
|
segment.Z := AZ3;
|
||||||
|
segment.X2 := AX1;
|
||||||
|
segment.Y2 := AY1;
|
||||||
|
segment.Z2 := AZ1;
|
||||||
|
segment.X3 := AX2;
|
||||||
|
segment.Y3 := AY2;
|
||||||
|
segment.Z3 := AZ2;
|
||||||
|
|
||||||
|
AppendSegmentToTmpPath(segment);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Finishes writing a Path, which was created in multiple
|
||||||
|
steps using StartPath and AddPointToPath,
|
||||||
|
to the document.
|
||||||
|
|
||||||
|
Does nothing if there wasn't a previous correspondent call to
|
||||||
|
StartPath.
|
||||||
|
|
||||||
|
@see StartPath, AddPointToPath
|
||||||
|
}
|
||||||
|
procedure TvVectorialDocument.EndPath();
|
||||||
|
begin
|
||||||
|
if FTmPPath.Len = 0 then Exit;
|
||||||
|
AddPath(FTmPPath);
|
||||||
|
ClearTmpPath();
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvVectorialDocument.AddText(AX, AY, AZ: Double; FontName: string; FontSize: integer; AText: utf8string);
|
||||||
|
var
|
||||||
|
lText: TvText;
|
||||||
|
begin
|
||||||
|
lText := TvText.Create;
|
||||||
|
lText.Value := AText;
|
||||||
|
lText.X := AX;
|
||||||
|
lText.Y := AY;
|
||||||
|
lText.Z := AZ;
|
||||||
|
lText.FontName := FontName;
|
||||||
|
lText.FontSize := FontSize;
|
||||||
|
FTexts.Add(lText);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvVectorialDocument.AddText(AX, AY, AZ: Double; AStr: utf8string);
|
||||||
|
begin
|
||||||
|
AddText(AX, AY, AZ, '', 10, AStr);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Convenience method which creates the correct
|
||||||
|
writer object for a given vector graphics document format.
|
||||||
|
}
|
||||||
|
function TvVectorialDocument.CreateVectorialWriter(AFormat: TvVectorialFormat): TvCustomVectorialWriter;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
Result := nil;
|
||||||
|
|
||||||
|
for i := 0 to Length(GvVectorialFormats) - 1 do
|
||||||
|
if GvVectorialFormats[i].Format = AFormat then
|
||||||
|
begin
|
||||||
|
Result := GvVectorialFormats[i].WriterClass.Create;
|
||||||
|
|
||||||
|
Break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if Result = nil then raise Exception.Create('Unsuported vector graphics format.');
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Convenience method which creates the correct
|
||||||
|
reader object for a given vector graphics document format.
|
||||||
|
}
|
||||||
|
function TvVectorialDocument.CreateVectorialReader(AFormat: TvVectorialFormat): TvCustomVectorialReader;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
Result := nil;
|
||||||
|
|
||||||
|
for i := 0 to Length(GvVectorialFormats) - 1 do
|
||||||
|
if GvVectorialFormats[i].Format = AFormat then
|
||||||
|
begin
|
||||||
|
Result := GvVectorialFormats[i].ReaderClass.Create;
|
||||||
|
|
||||||
|
Break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if Result = nil then raise Exception.Create('Unsuported vector graphics format.');
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvVectorialDocument.ClearTmpPath();
|
||||||
|
var
|
||||||
|
segment, oldsegment: TPathSegment;
|
||||||
|
begin
|
||||||
|
// segment := FTmpPath.Points;
|
||||||
|
// Don't free segments, because they are used when the path is added
|
||||||
|
// while segment <> nil do
|
||||||
|
// begin
|
||||||
|
// oldsegment := segment;
|
||||||
|
// segment := segment^.Next;
|
||||||
|
// oldsegment^.Free;
|
||||||
|
// end;
|
||||||
|
|
||||||
|
FTmpPath.Points := nil;
|
||||||
|
FTmpPath.PointsEnd := nil;
|
||||||
|
FTmpPath.Len := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvVectorialDocument.AppendSegmentToTmpPath(ASegment: TPathSegment);
|
||||||
|
var
|
||||||
|
L: Integer;
|
||||||
|
begin
|
||||||
|
if FTmpPath.PointsEnd = nil then
|
||||||
|
Exception.Create('[TvVectorialDocument.AppendSegmentToTmpPath]' + Str_Error_Nil_Path);
|
||||||
|
|
||||||
|
L := FTmpPath.Len;
|
||||||
|
Inc(FTmpPath.Len);
|
||||||
|
|
||||||
|
// Adds the element to the end of the list
|
||||||
|
FTmpPath.PointsEnd.Next := ASegment;
|
||||||
|
ASegment.Previous := FTmpPath.PointsEnd;
|
||||||
|
FTmpPath.PointsEnd := ASegment;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Writes the document to a file.
|
||||||
|
|
||||||
|
If the file doesn't exist, it will be created.
|
||||||
|
}
|
||||||
|
procedure TvVectorialDocument.WriteToFile(AFileName: string; AFormat: TvVectorialFormat);
|
||||||
|
var
|
||||||
|
AWriter: TvCustomVectorialWriter;
|
||||||
|
begin
|
||||||
|
AWriter := CreateVectorialWriter(AFormat);
|
||||||
|
|
||||||
|
try
|
||||||
|
AWriter.WriteToFile(AFileName, Self);
|
||||||
|
finally
|
||||||
|
AWriter.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Writes the document to a stream
|
||||||
|
}
|
||||||
|
procedure TvVectorialDocument.WriteToStream(AStream: TStream; AFormat: TvVectorialFormat);
|
||||||
|
var
|
||||||
|
AWriter: TvCustomVectorialWriter;
|
||||||
|
begin
|
||||||
|
AWriter := CreateVectorialWriter(AFormat);
|
||||||
|
|
||||||
|
try
|
||||||
|
AWriter.WriteToStream(AStream, Self);
|
||||||
|
finally
|
||||||
|
AWriter.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvVectorialDocument.WriteToStrings(AStrings: TStrings;
|
||||||
|
AFormat: TvVectorialFormat);
|
||||||
|
var
|
||||||
|
AWriter: TvCustomVectorialWriter;
|
||||||
|
begin
|
||||||
|
AWriter := CreateVectorialWriter(AFormat);
|
||||||
|
|
||||||
|
try
|
||||||
|
AWriter.WriteToStrings(AStrings, Self);
|
||||||
|
finally
|
||||||
|
AWriter.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Reads the document from a file.
|
||||||
|
|
||||||
|
Any current contents will be removed.
|
||||||
|
}
|
||||||
|
procedure TvVectorialDocument.ReadFromFile(AFileName: string;
|
||||||
|
AFormat: TvVectorialFormat);
|
||||||
|
var
|
||||||
|
AReader: TvCustomVectorialReader;
|
||||||
|
begin
|
||||||
|
Self.Clear;
|
||||||
|
|
||||||
|
AReader := CreateVectorialReader(AFormat);
|
||||||
|
try
|
||||||
|
AReader.ReadFromFile(AFileName, Self);
|
||||||
|
finally
|
||||||
|
AReader.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Reads the document from a stream.
|
||||||
|
|
||||||
|
Any current contents will be removed.
|
||||||
|
}
|
||||||
|
procedure TvVectorialDocument.ReadFromStream(AStream: TStream;
|
||||||
|
AFormat: TvVectorialFormat);
|
||||||
|
var
|
||||||
|
AReader: TvCustomVectorialReader;
|
||||||
|
begin
|
||||||
|
Self.Clear;
|
||||||
|
|
||||||
|
AReader := CreateVectorialReader(AFormat);
|
||||||
|
try
|
||||||
|
AReader.ReadFromStream(AStream, Self);
|
||||||
|
finally
|
||||||
|
AReader.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvVectorialDocument.ReadFromStrings(AStrings: TStrings;
|
||||||
|
AFormat: TvVectorialFormat);
|
||||||
|
var
|
||||||
|
AReader: TvCustomVectorialReader;
|
||||||
|
begin
|
||||||
|
Self.Clear;
|
||||||
|
|
||||||
|
AReader := CreateVectorialReader(AFormat);
|
||||||
|
try
|
||||||
|
AReader.ReadFromStrings(AStrings, Self);
|
||||||
|
finally
|
||||||
|
AReader.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TvVectorialDocument.GetFormatFromExtension(AFileName: string
|
||||||
|
): TvVectorialFormat;
|
||||||
|
var
|
||||||
|
lExt: string;
|
||||||
|
begin
|
||||||
|
lExt := ExtractFileExt(AFileName);
|
||||||
|
if AnsiCompareText(lExt, STR_PDF_EXTENSION) = 0 then Result := vfPDF
|
||||||
|
else if AnsiCompareText(lExt, STR_POSTSCRIPT_EXTENSION) = 0 then Result := vfPostScript
|
||||||
|
else if AnsiCompareText(lExt, STR_SVG_EXTENSION) = 0 then Result := vfSVG
|
||||||
|
else if AnsiCompareText(lExt, STR_CORELDRAW_EXTENSION) = 0 then Result := vfCorelDrawCDR
|
||||||
|
else if AnsiCompareText(lExt, STR_WINMETAFILE_EXTENSION) = 0 then Result := vfWindowsMetafileWMF
|
||||||
|
else
|
||||||
|
raise Exception.Create('TvVectorialDocument.GetFormatFromExtension: The extension (' + lExt + ') doesn''t match any supported formats.');
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TvVectorialDocument.GetDetailedFileFormat(): string;
|
||||||
|
begin
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TvVectorialDocument.GetPath(ANum: Cardinal): TPath;
|
||||||
|
begin
|
||||||
|
if ANum >= FPaths.Count then raise Exception.Create('TvVectorialDocument.GetPath: Path number out of bounds');
|
||||||
|
|
||||||
|
if FPaths.Items[ANum] = nil then raise Exception.Create('TvVectorialDocument.GetPath: Invalid Path number');
|
||||||
|
|
||||||
|
Result := TPath(FPaths.Items[ANum]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TvVectorialDocument.GetPathCount: Integer;
|
||||||
|
begin
|
||||||
|
Result := FPaths.Count;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TvVectorialDocument.GetText(ANum: Cardinal): TvText;
|
||||||
|
begin
|
||||||
|
if ANum >= FTexts.Count then raise Exception.Create('TvVectorialDocument.GetText: Text number out of bounds');
|
||||||
|
|
||||||
|
if FTexts.Items[ANum] = nil then raise Exception.Create('TvVectorialDocument.GetText: Invalid Text number');
|
||||||
|
|
||||||
|
Result := TvText(FTexts.Items[ANum]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TvVectorialDocument.GetTextCount: Integer;
|
||||||
|
begin
|
||||||
|
Result := FTexts.Count;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Clears all data in the document
|
||||||
|
}
|
||||||
|
procedure TvVectorialDocument.Clear;
|
||||||
|
begin
|
||||||
|
RemoveAllPaths();
|
||||||
|
RemoveAllTexts();
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TvCustomVectorialReader }
|
||||||
|
|
||||||
|
procedure TvCustomVectorialReader.ReadFromFile(AFileName: string; AData: TvVectorialDocument);
|
||||||
|
var
|
||||||
|
FileStream: TFileStream;
|
||||||
|
begin
|
||||||
|
FileStream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone);
|
||||||
|
try
|
||||||
|
ReadFromStream(FileStream, AData);
|
||||||
|
finally
|
||||||
|
FileStream.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvCustomVectorialReader.ReadFromStream(AStream: TStream;
|
||||||
|
AData: TvVectorialDocument);
|
||||||
|
var
|
||||||
|
AStringStream: TStringStream;
|
||||||
|
AStrings: TStringList;
|
||||||
|
begin
|
||||||
|
AStringStream := TStringStream.Create('');
|
||||||
|
AStrings := TStringList.Create;
|
||||||
|
try
|
||||||
|
AStringStream.CopyFrom(AStream, AStream.Size);
|
||||||
|
AStringStream.Seek(0, soFromBeginning);
|
||||||
|
AStrings.Text := AStringStream.DataString;
|
||||||
|
ReadFromStrings(AStrings, AData);
|
||||||
|
finally
|
||||||
|
AStringStream.Free;
|
||||||
|
AStrings.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvCustomVectorialReader.ReadFromStrings(AStrings: TStrings;
|
||||||
|
AData: TvVectorialDocument);
|
||||||
|
var
|
||||||
|
AStringStream: TStringStream;
|
||||||
|
begin
|
||||||
|
AStringStream := TStringStream.Create('');
|
||||||
|
try
|
||||||
|
AStringStream.WriteString(AStrings.Text);
|
||||||
|
AStringStream.Seek(0, soFromBeginning);
|
||||||
|
ReadFromStream(AStringStream, AData);
|
||||||
|
finally
|
||||||
|
AStringStream.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TsCustomSpreadWriter }
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Default file writting method.
|
||||||
|
|
||||||
|
Opens the file and calls WriteToStream
|
||||||
|
|
||||||
|
@param AFileName The output file name.
|
||||||
|
If the file already exists it will be replaced.
|
||||||
|
@param AData The Workbook to be saved.
|
||||||
|
|
||||||
|
@see TsWorkbook
|
||||||
|
}
|
||||||
|
procedure TvCustomVectorialWriter.WriteToFile(AFileName: string; AData: TvVectorialDocument);
|
||||||
|
var
|
||||||
|
OutputFile: TFileStream;
|
||||||
|
begin
|
||||||
|
OutputFile := TFileStream.Create(AFileName, fmCreate or fmOpenWrite);
|
||||||
|
try
|
||||||
|
WriteToStream(OutputFile, AData);
|
||||||
|
finally
|
||||||
|
OutputFile.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
The default stream writer just uses WriteToStrings
|
||||||
|
}
|
||||||
|
procedure TvCustomVectorialWriter.WriteToStream(AStream: TStream;
|
||||||
|
AData: TvVectorialDocument);
|
||||||
|
var
|
||||||
|
lStringList: TStringList;
|
||||||
|
begin
|
||||||
|
lStringList := TStringList.Create;
|
||||||
|
try
|
||||||
|
WriteToStrings(lStringList, AData);
|
||||||
|
lStringList.SaveToStream(AStream);
|
||||||
|
finally
|
||||||
|
lStringList.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvCustomVectorialWriter.WriteToStrings(AStrings: TStrings;
|
||||||
|
AData: TvVectorialDocument);
|
||||||
|
begin
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TPath }
|
||||||
|
|
||||||
|
procedure TPath.Assign(APath: TPath);
|
||||||
|
begin
|
||||||
|
Len := APath.Len;
|
||||||
|
Points := APath.Points;
|
||||||
|
PointsEnd := APath.PointsEnd;
|
||||||
|
CurPoint := APath.CurPoint;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TPath.Count(): TPathSegment;
|
||||||
|
begin
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TPath.PrepareForSequentialReading;
|
||||||
|
begin
|
||||||
|
CurPoint := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TPath.Next(): TPathSegment;
|
||||||
|
begin
|
||||||
|
if CurPoint = nil then Result := Points
|
||||||
|
else Result := CurPoint.Next;
|
||||||
|
|
||||||
|
CurPoint := Result;
|
||||||
|
end;
|
||||||
|
|
||||||
|
finalization
|
||||||
|
|
||||||
|
SetLength(GvVectorialFormats, 0);
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
109
applications/fpvviewer/fpvectorialsrc/fpvtocanvas.pas
Normal file
109
applications/fpvviewer/fpvectorialsrc/fpvtocanvas.pas
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
unit fpvtocanvas;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils,
|
||||||
|
fpcanvas,
|
||||||
|
fpvectorial;
|
||||||
|
|
||||||
|
procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument; ADest: TFPCustomCanvas;
|
||||||
|
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{@@
|
||||||
|
This function draws a FPVectorial vectorial image to a TFPCustomCanvas
|
||||||
|
descendent, such as TCanvas from the LCL.
|
||||||
|
|
||||||
|
Be careful that by default this routine does not execute coordinate transformations,
|
||||||
|
and that FPVectorial works with a start point in the bottom-left corner, with
|
||||||
|
the X growing to the right and the Y growing to the top. This will result in
|
||||||
|
an image in TFPCustomCanvas mirrored in the Y axis in relation with the document
|
||||||
|
as seen in a PDF viewer, for example. This can be easily changed with the
|
||||||
|
provided parameters. To have the standard view of an image viewer one could
|
||||||
|
use this function like this:
|
||||||
|
|
||||||
|
DrawFPVectorialToCanvas(ASource, ADest, 0, ASource.Height, 1.0, -1.0);
|
||||||
|
}
|
||||||
|
procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument; ADest: TFPCustomCanvas;
|
||||||
|
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
|
||||||
|
var
|
||||||
|
i, j, k: Integer;
|
||||||
|
PosX, PosY: Integer; // Not modified by ADestX, etc
|
||||||
|
CurSegment: TPathSegment;
|
||||||
|
Cur2DSegment: T2DSegment absolute CurSegment;
|
||||||
|
Cur2DBSegment: T2DBezierSegment absolute CurSegment;
|
||||||
|
// For bezier
|
||||||
|
CurX, CurY: Integer; // Not modified by ADestX, etc
|
||||||
|
CurveLength: Integer;
|
||||||
|
t: Double;
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':>DrawFPVectorialToCanvas');
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
PosX := 0;
|
||||||
|
PosY := 0;
|
||||||
|
|
||||||
|
ADest.MoveTo(ADestX, ADestY);
|
||||||
|
|
||||||
|
for i := 0 to ASource.PathCount - 1 do
|
||||||
|
begin
|
||||||
|
//WriteLn('i = ', i);
|
||||||
|
ASource.Paths[i].PrepareForSequentialReading;
|
||||||
|
|
||||||
|
for j := 0 to ASource.Paths[i].Len - 1 do
|
||||||
|
begin
|
||||||
|
//WriteLn('j = ', j);
|
||||||
|
CurSegment := TPathSegment(ASource.Paths[i].Next());
|
||||||
|
|
||||||
|
case CurSegment.SegmentType of
|
||||||
|
stMoveTo:
|
||||||
|
begin
|
||||||
|
ADest.MoveTo(
|
||||||
|
Round(ADestX + AMulX * Cur2DSegment.X),
|
||||||
|
Round(ADestY + AMulY * Cur2DSegment.Y)
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
st2DLine, st3DLine:
|
||||||
|
begin
|
||||||
|
ADest.LineTo(
|
||||||
|
Round(ADestX + AMulX * Cur2DSegment.X),
|
||||||
|
Round(ADestY + AMulY * Cur2DSegment.Y)
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
{ To draw a bezier we need to divide the interval in parts and make
|
||||||
|
lines between this parts }
|
||||||
|
st2DBezier, st3DBezier:
|
||||||
|
begin
|
||||||
|
CurveLength :=
|
||||||
|
Round(sqrt(sqr(Cur2DBSegment.X3 - PosX) + sqr(Cur2DBSegment.Y3 - PosY))) +
|
||||||
|
Round(sqrt(sqr(Cur2DBSegment.X2 - Cur2DBSegment.X3) + sqr(Cur2DBSegment.Y2 - Cur2DBSegment.Y3))) +
|
||||||
|
Round(sqrt(sqr(Cur2DBSegment.X - Cur2DBSegment.X3) + sqr(Cur2DBSegment.Y - Cur2DBSegment.Y3)));
|
||||||
|
|
||||||
|
for k := 1 to CurveLength do
|
||||||
|
begin
|
||||||
|
t := k / CurveLength;
|
||||||
|
CurX := Round(sqr(1 - t) * (1 - t) * PosX + 3 * t * sqr(1 - t) * Cur2DBSegment.X2 + 3 * t * t * (1 - t) * Cur2DBSegment.X3 + t * t * t * Cur2DBSegment.X);
|
||||||
|
CurY := Round(sqr(1 - t) * (1 - t) * PosY + 3 * t * sqr(1 - t) * Cur2DBSegment.Y2 + 3 * t * t * (1 - t) * Cur2DBSegment.Y3 + t * t * t * Cur2DBSegment.Y);
|
||||||
|
ADest.LineTo(
|
||||||
|
Round(ADestX + AMulX * CurX),
|
||||||
|
Round(ADestY + AMulY * CurY));
|
||||||
|
end;
|
||||||
|
PosX := Round(Cur2DBSegment.X);
|
||||||
|
PosY := Round(Cur2DBSegment.Y);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':<DrawFPVectorialToCanvas');
|
||||||
|
{$endif}
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
265
applications/fpvviewer/fpvectorialsrc/pdfvectorialreader.pas
Normal file
265
applications/fpvviewer/fpvectorialsrc/pdfvectorialreader.pas
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
{
|
||||||
|
pdfvectorialreader.pas
|
||||||
|
|
||||||
|
Reads the vectorial information form a PDF file
|
||||||
|
|
||||||
|
PDF file format specification obtained from:
|
||||||
|
|
||||||
|
ADOBE SYSTEMS INCORPORATED. PDF Reference: Adobe®
|
||||||
|
Portable Document Format. San Jose, 2006. (Sixth edition).
|
||||||
|
|
||||||
|
AUTHORS: Felipe Monteiro de Carvalho
|
||||||
|
Pedro Sol Pegorini L de Lima
|
||||||
|
}
|
||||||
|
unit pdfvectorialreader;
|
||||||
|
|
||||||
|
{$ifdef fpc}
|
||||||
|
{$mode delphi}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils,
|
||||||
|
pdfvrlexico, pdfvrsintatico, pdfvrsemantico, avisozlib,
|
||||||
|
fpvectorial;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ TvPDFVectorialReader }
|
||||||
|
|
||||||
|
TvPDFVectorialReader = class(TvCustomVectorialReader)
|
||||||
|
private
|
||||||
|
procedure WriteStringToStream(AStream: TStream; AString: string);
|
||||||
|
public
|
||||||
|
{ public to allow uncompressing PDFs independently }
|
||||||
|
function getFirstPage(AInput: TStream; AOutput: TStream):PageHeader;
|
||||||
|
procedure unzipPage(AInput: TStream; AOutput: TStream);
|
||||||
|
procedure translatePage(AInput: TStream; AData: TvVectorialDocument;
|
||||||
|
APageHeader: PageHeader);
|
||||||
|
{ General reading methods }
|
||||||
|
procedure ReadFromStream(AStream: TStream; AData: TvVectorialDocument); override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{ TvPDFVectorialReader }
|
||||||
|
|
||||||
|
procedure TvPDFVectorialReader.WriteStringToStream(AStream: TStream;
|
||||||
|
AString: string);
|
||||||
|
begin
|
||||||
|
AStream.WriteBuffer(AString[1], Length(AString));
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TvPDFVectorialReader.getFirstPage(AInput: TStream; AOutput: TStream): PageHeader;
|
||||||
|
var
|
||||||
|
mytoken: Token;
|
||||||
|
myAnLexicoPage: AnLexico;
|
||||||
|
myAnLexicoContents: AnLexico;
|
||||||
|
myAnSintaticoPage: AnSintaticoPage;
|
||||||
|
myAnSintaticoContents: AnSintaticoPageContents;
|
||||||
|
AInput2: TStream;
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> TvPDFVectorialReader.getFirstPage');
|
||||||
|
{$endif}
|
||||||
|
AInput2 := TMemoryStream.Create;
|
||||||
|
AInput2.Size := AInput.Size;
|
||||||
|
AInput2.CopyFrom(AInput, AInput.Size);
|
||||||
|
AInput.Seek(0, soFromBeginning);
|
||||||
|
AInput2.Seek(0, soFromBeginning);
|
||||||
|
|
||||||
|
myAnLexicoPage := AnLexico.Create;
|
||||||
|
myAnLexicoPage.Doc := AInput;
|
||||||
|
myAnLexicoPage.bytesRemaining:= myAnLexicoPage.Doc.Size;
|
||||||
|
myAnSintaticoPage := AnSintaticoPage.Create;
|
||||||
|
|
||||||
|
// find first page
|
||||||
|
while ((myAnSintaticoPage.pageFound <> true) and
|
||||||
|
(myAnLexicoPage.bytesRemaining > 0)) do
|
||||||
|
begin
|
||||||
|
mytoken := myAnLexicoPage.getToken();
|
||||||
|
myAnSintaticoPage.automata(mytoken);
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (myAnSintaticoPage.pageFound = false) then
|
||||||
|
begin
|
||||||
|
raise Exception.Create('ERROR: Arquivo corrompido.');
|
||||||
|
Halt(1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
AInput.Seek(0, soFromBeginning);
|
||||||
|
myAnLexicoContents := AnLexico.Create;
|
||||||
|
myAnLexicoContents.Doc := AInput;
|
||||||
|
myAnLexicoContents.bytesRemaining:= myAnLexicoContents.Doc.Size;
|
||||||
|
myAnSintaticoContents := AnSintaticoPageContents.Create;
|
||||||
|
|
||||||
|
// gathering information of the first page
|
||||||
|
myAnSintaticoContents.obj1:=myAnSintaticoPage.obj1;
|
||||||
|
myAnSintaticoContents.obj2:=myAnSintaticoPage.obj2;
|
||||||
|
|
||||||
|
//find first page contents
|
||||||
|
while ((myAnSintaticoContents.contentsFound <> true) and
|
||||||
|
(myAnLexicoContents.bytesRemaining > 0)) do
|
||||||
|
begin
|
||||||
|
mytoken := myAnLexicoContents.getToken();
|
||||||
|
myAnSintaticoContents.automata(mytoken, AInput2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (myAnSintaticoContents.contentsFound = false) then
|
||||||
|
begin
|
||||||
|
raise Exception.Create('ERROR: Arquivo corrompido.');
|
||||||
|
Halt(1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// gathering information of the first page
|
||||||
|
myAnLexicoContents.bytesRemaining:=myAnSintaticoContents.h.page_length;
|
||||||
|
|
||||||
|
// write file with content just from the first page
|
||||||
|
while (myAnLexicoContents.bytesRemaining > 0) do
|
||||||
|
begin
|
||||||
|
mytoken := myAnLexicoContents.getPageToken();
|
||||||
|
WriteStringToStream(AOutput, mytoken.token_string);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result:=myAnSintaticoContents.h;
|
||||||
|
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':< TvPDFVectorialReader.getFirstPage');
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
// AInput2.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvPDFVectorialReader.unzipPage(AInput: TStream; AOutput: TStream);
|
||||||
|
var
|
||||||
|
compr, uncompr: Pbyte;
|
||||||
|
comprLen, uncomprLen: LongInt;
|
||||||
|
myDecode: decode;
|
||||||
|
BufStr: string;
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> TvPDFVectorialReader.unzipPage');
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
myDecode := Decode.Create;
|
||||||
|
|
||||||
|
comprLen := 10000 * SizeOf(Integer); // don't overflow
|
||||||
|
uncomprLen := comprLen;
|
||||||
|
GetMem(compr, comprLen);
|
||||||
|
GetMem(uncompr, uncomprLen);
|
||||||
|
|
||||||
|
if (compr = NIL) or (uncompr = NIL) then
|
||||||
|
myDecode.EXIT_ERR('Out of memory');
|
||||||
|
|
||||||
|
(* compr and uncompr are cleared to avoid reading uninitialized
|
||||||
|
* data and to ensure that uncompr compresses well.
|
||||||
|
*)
|
||||||
|
|
||||||
|
FillChar(compr^, comprLen, 0);
|
||||||
|
FillChar(uncompr^, uncomprLen, 0);
|
||||||
|
|
||||||
|
AInput.Read(compr^, comprLen);
|
||||||
|
|
||||||
|
BufStr := string(myDecode.test_inflate(compr, comprLen, uncompr, uncomprLen));
|
||||||
|
|
||||||
|
WriteStringToStream(AOutput, BufStr);
|
||||||
|
|
||||||
|
FreeMem(compr, comprLen);
|
||||||
|
FreeMem(uncompr, uncomprLen);
|
||||||
|
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':< TvPDFVectorialReader.unzipPage');
|
||||||
|
{$endif}
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvPDFVectorialReader.translatePage(AInput: TStream;
|
||||||
|
AData: TvVectorialDocument; APageHeader: PageHeader);
|
||||||
|
var
|
||||||
|
myAnLexico: AnLexico;
|
||||||
|
myAnSintaticoCommand: AnSintaticoCommand;
|
||||||
|
myAnSemantico: AnSemantico;
|
||||||
|
mytoken: Token;
|
||||||
|
c: Command;
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> TvPDFVectorialReader.translatePage');
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
// initialize data main
|
||||||
|
myAnLexico := AnLexico.Create;
|
||||||
|
myAnLexico.Doc := AInput;
|
||||||
|
myAnLexico.bytesRemaining:= myAnLexico.Doc.Size;
|
||||||
|
myAnSintaticoCommand := AnSintaticoCommand.Create;
|
||||||
|
myAnSemantico := AnSemantico.Create;
|
||||||
|
|
||||||
|
// initialize machine
|
||||||
|
myAnSemantico.startMachine();
|
||||||
|
|
||||||
|
while (myAnLexico.bytesRemaining > 0) do
|
||||||
|
begin
|
||||||
|
mytoken := myAnLexico.getToken();
|
||||||
|
c:=myAnSintaticoCommand.automata(mytoken);
|
||||||
|
if (myAnSintaticoCommand.Codigo = true) then
|
||||||
|
myAnSemantico.generate(c, AData);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// end machine
|
||||||
|
myAnSemantico.endMachine();
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvPDFVectorialReader.ReadFromStream(AStream: TStream;
|
||||||
|
AData: TvVectorialDocument);
|
||||||
|
var
|
||||||
|
APageHeader: PageHeader;
|
||||||
|
APageStream, AUnzipStream: TStream;
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> TvPDFVectorialReader.ReadFromStream');
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
APageStream := TMemoryStream.Create;
|
||||||
|
AUnzipStream := TMemoryStream.Create;
|
||||||
|
|
||||||
|
// get first page
|
||||||
|
APageHeader := getFirstPage(AStream, APageStream);
|
||||||
|
|
||||||
|
// unzip page
|
||||||
|
if (APageHeader.flate_decode = true) then
|
||||||
|
begin
|
||||||
|
APageStream.Seek(0, soFromBeginning);
|
||||||
|
unzipPage(APageStream, AUnzipStream);
|
||||||
|
|
||||||
|
// translate page to doc data
|
||||||
|
AUnzipStream.Seek(0, soFromBeginning);
|
||||||
|
translatePage(AUnzipStream, AData, APageHeader);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
// translate page to doc data
|
||||||
|
APageStream.Seek(0, soFromBeginning);
|
||||||
|
translatePage(APageStream, AData, APageHeader);
|
||||||
|
end;
|
||||||
|
|
||||||
|
APageStream.Free;
|
||||||
|
AUnzipStream.Free;
|
||||||
|
|
||||||
|
//ShowMessage('Sucesso!');
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':< TvPDFVectorialReader.ReadFromStream');
|
||||||
|
WriteLn('Sucesso!');
|
||||||
|
{$endif}
|
||||||
|
end;
|
||||||
|
|
||||||
|
{*******************************************************************
|
||||||
|
* Initialization section
|
||||||
|
*
|
||||||
|
* Registers this reader / writer on fpVectorial
|
||||||
|
*
|
||||||
|
*******************************************************************}
|
||||||
|
initialization
|
||||||
|
|
||||||
|
RegisterVectorialReader(TvPDFVectorialReader, vfPDF);
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
113
applications/fpvviewer/fpvectorialsrc/pdfvrlexico.pas
Normal file
113
applications/fpvviewer/fpvectorialsrc/pdfvrlexico.pas
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
unit pdfvrlexico;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils;
|
||||||
|
|
||||||
|
type
|
||||||
|
Token = record
|
||||||
|
tipo: Int64;
|
||||||
|
token_string: String;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TPDFCommandCode = (cc_NONE, cc_m_START_PATH, cc_l_ADD_LINE_TO_PATH,
|
||||||
|
cc_H_CLOSE_PATH, cc_S_END_PATH, cc_hS_CLOSE_AND_END_PATH,
|
||||||
|
cc_c_BEZIER_TO_X_Y_USING_X2_Y2_AND_X3_Y3,
|
||||||
|
cc_v_BEZIER_TO_X_Y_USING_CURRENT_POS_AND_X2_Y2,
|
||||||
|
cc_y_BEZIER_TO_X_Y_USING_X_Y_AND_X2_Y2,
|
||||||
|
cc_CONCATENATE_MATRIX,cc_RESTORE_MATRIX);
|
||||||
|
|
||||||
|
Command = record
|
||||||
|
cord_x3: String;
|
||||||
|
cord_y3: String;
|
||||||
|
cord_x2: String;
|
||||||
|
cord_y2: String;
|
||||||
|
cord_x: String;
|
||||||
|
cord_y: String;
|
||||||
|
my_operator: String;
|
||||||
|
code: TPDFCommandCode;
|
||||||
|
end;
|
||||||
|
|
||||||
|
PageHeader = record
|
||||||
|
page_length: Int64;
|
||||||
|
flate_decode: Boolean;
|
||||||
|
end;
|
||||||
|
|
||||||
|
AnLexico = class
|
||||||
|
public
|
||||||
|
Doc: TStream;
|
||||||
|
bytesRemaining: Int64;
|
||||||
|
constructor Create();
|
||||||
|
function getToken(): Token;
|
||||||
|
function getPageToken(): Token;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
function AnLexico.getToken(): Token;
|
||||||
|
var
|
||||||
|
t: Byte;
|
||||||
|
mytoken: Token;
|
||||||
|
begin
|
||||||
|
mytoken.tipo := 0;
|
||||||
|
while( bytesRemaining > 0 ) do
|
||||||
|
begin
|
||||||
|
t := Doc.ReadByte();
|
||||||
|
bytesRemaining := bytesRemaining - 1;
|
||||||
|
// numbers or points or minus
|
||||||
|
if((((t >= 48) and (t <= 57)) or (t = 46 ) or (t = 45)) and
|
||||||
|
((mytoken.tipo = 1) or (mytoken.tipo = 0))) then
|
||||||
|
begin
|
||||||
|
mytoken.token_string := mytoken.token_string + char(t);
|
||||||
|
mytoken.tipo:=1;
|
||||||
|
end
|
||||||
|
else if(((t >= 65) and (t <= 90)) or ((t >= 97) and (t <= 122)) // letters
|
||||||
|
or (t = 42) // *
|
||||||
|
and ((mytoken.tipo = 2) or (mytoken.tipo = 0))) then
|
||||||
|
begin
|
||||||
|
mytoken.token_string := mytoken.token_string + char(t);
|
||||||
|
mytoken.tipo:=2;
|
||||||
|
end
|
||||||
|
else // everything else
|
||||||
|
begin
|
||||||
|
if (mytoken.tipo <> 0) then
|
||||||
|
begin
|
||||||
|
// solve CorelDraw problem after "stream"
|
||||||
|
if ((t=13) and (bytesRemaining>0)) then
|
||||||
|
begin
|
||||||
|
t := Doc.ReadByte();
|
||||||
|
bytesRemaining:=bytesRemaining-1;
|
||||||
|
end;
|
||||||
|
Result := mytoken;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Result := mytoken;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function AnLexico.getPageToken(): Token;
|
||||||
|
var
|
||||||
|
t: Byte;
|
||||||
|
mytoken: Token;
|
||||||
|
begin
|
||||||
|
mytoken.tipo := 0;
|
||||||
|
if (bytesRemaining > 0) then
|
||||||
|
begin
|
||||||
|
t := Doc.ReadByte;
|
||||||
|
mytoken.token_string:=char(t);
|
||||||
|
bytesRemaining := bytesRemaining - 1;
|
||||||
|
end;
|
||||||
|
Result := mytoken;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor AnLexico.Create();
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
244
applications/fpvviewer/fpvectorialsrc/pdfvrsemantico.pas
Normal file
244
applications/fpvviewer/fpvectorialsrc/pdfvrsemantico.pas
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
unit pdfvrsemantico;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, pdfvrlexico, fpvectorial;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ AnSemantico }
|
||||||
|
|
||||||
|
AnSemantico = class
|
||||||
|
public
|
||||||
|
FPointSeparator, FCommaSeparator: TFormatSettings;
|
||||||
|
close_path_x: String;
|
||||||
|
close_path_y: String;
|
||||||
|
cm_a, cm_b, cm_c, cm_d, cm_e, cm_f: Real; // coordinate spaces constants
|
||||||
|
function StringToFloat(AStr: string): Double;
|
||||||
|
function generate(c: Command; AData: TvVectorialDocument): String;
|
||||||
|
function convert(x: String; y: String; Axis: Char): String;
|
||||||
|
function startMachine(): String;
|
||||||
|
function endMachine(): String;
|
||||||
|
constructor Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{ PDF doesn't seam very consistent when it comes to using commas or
|
||||||
|
points as decimal separator, so we just try both }
|
||||||
|
function AnSemantico.StringToFloat(AStr: string): Double;
|
||||||
|
begin
|
||||||
|
if Pos('.', AStr) > 0 then Result := StrToFloat(AStr, FPointSeparator)
|
||||||
|
else Result := StrToFloat(AStr, FCommaSeparator);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function AnSemantico.generate(c: Command; AData: TvVectorialDocument): String;
|
||||||
|
var
|
||||||
|
enter_line : String;
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSemantico.generate');
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
enter_line:= LineEnding; //chr(13) + chr(10); // CR and LF
|
||||||
|
|
||||||
|
if ((c.code = cc_H_CLOSE_PATH) or (c.code = cc_hS_CLOSE_AND_END_PATH)) then // command h or s
|
||||||
|
begin
|
||||||
|
c.cord_x:=close_path_x;
|
||||||
|
c.cord_y:=close_path_y;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if ((c.code <> cc_H_CLOSE_PATH) and (c.code <> cc_hS_CLOSE_AND_END_PATH)) then // close path already converted
|
||||||
|
begin
|
||||||
|
if ((c.code = cc_m_START_PATH) or (c.code = cc_l_ADD_LINE_TO_PATH)) then
|
||||||
|
begin
|
||||||
|
//WriteLn(':: anSemantico.generate convert code ', Integer(c.code));
|
||||||
|
c.cord_x := convert(c.cord_x,c.cord_y,'x');
|
||||||
|
c.cord_y := convert(c.cord_x,c.cord_y,'y');
|
||||||
|
end;
|
||||||
|
if ((c.code = cc_c_BEZIER_TO_X_Y_USING_X2_Y2_AND_X3_Y3)) then
|
||||||
|
begin
|
||||||
|
//WriteLn(':: anSemantico.generate convert code ', Integer(c.code));
|
||||||
|
c.cord_x := convert(c.cord_x,c.cord_y,'x');
|
||||||
|
c.cord_y := convert(c.cord_x,c.cord_y,'y');
|
||||||
|
c.cord_x2 := convert(c.cord_x2,c.cord_y2,'x');
|
||||||
|
c.cord_y2 := convert(c.cord_x2,c.cord_y2,'y');
|
||||||
|
c.cord_x3 := convert(c.cord_x3,c.cord_y3,'x');
|
||||||
|
c.cord_y3 := convert(c.cord_x3,c.cord_y3,'y');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
case c.code of
|
||||||
|
cc_m_START_PATH: // command m
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSemantico.generate Estado 1 EndPath StartPath');
|
||||||
|
{$endif}
|
||||||
|
// Result:='G01' + ' ' + 'X' + c.cord_x + ' ' + 'Y' + c.cord_y + enter_line +
|
||||||
|
// 'G01 Z50 // Abaixa a cabeça de gravação';
|
||||||
|
|
||||||
|
// Correcao para programas de desenho que geram um novo inicio no
|
||||||
|
// fim do desenho, terminamos qualquer desenho inacabado
|
||||||
|
AData.EndPath();
|
||||||
|
AData.StartPath(StringToFloat(c.cord_x), StringToFloat(c.cord_y));
|
||||||
|
|
||||||
|
close_path_x:=c.cord_x;
|
||||||
|
close_path_y:=c.cord_y;
|
||||||
|
end;
|
||||||
|
cc_l_ADD_LINE_TO_PATH: // command l
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSemantico.generate Estado 2 AddPointToPath');
|
||||||
|
{$endif}
|
||||||
|
// Result:='G01' + ' ' + 'X' + c.cord_x + ' ' + 'Y' + c.cord_y;
|
||||||
|
|
||||||
|
AData.AddLineToPath(StringToFloat(c.cord_x), StringToFloat(c.cord_y));
|
||||||
|
end;
|
||||||
|
cc_h_CLOSE_PATH: // command h
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSemantico.generate Estado 3 AddPointToPath');
|
||||||
|
{$endif}
|
||||||
|
//Result:='G01' + ' ' + 'X' + c.cord_x + ' ' + 'Y' + c.cord_y;
|
||||||
|
|
||||||
|
AData.AddLineToPath(StringToFloat(c.cord_x), StringToFloat(c.cord_y));
|
||||||
|
end;
|
||||||
|
cc_S_END_PATH: // command S
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSemantico.generate Estado 4 EndPath');
|
||||||
|
{$endif}
|
||||||
|
// Result:='G01 Z0 // Sobe a cabeça de gravação' + enter_line;
|
||||||
|
AData.EndPath();
|
||||||
|
end;
|
||||||
|
cc_hS_CLOSE_AND_END_PATH: // command s
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSemantico.generate Estado 5 AddPoint EndPath');
|
||||||
|
{$endif}
|
||||||
|
//Result:='G01' + ' ' + 'X' + c.cord_x + ' ' + 'Y' + c.cord_y + enter_line
|
||||||
|
// +'G01 Z0 // Sobe a cabeça de gravação' + enter_line;
|
||||||
|
|
||||||
|
AData.AddLineToPath(StringToFloat(c.cord_x), StringToFloat(c.cord_y));
|
||||||
|
AData.EndPath();
|
||||||
|
end;
|
||||||
|
cc_c_BEZIER_TO_X_Y_USING_X2_Y2_AND_X3_Y3: // command c
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSemantico.generate Estado 6 Bezier');
|
||||||
|
{$endif}
|
||||||
|
//Result:='G01' + ' ' + 'X' + c.cord_x + ' ' + 'Y' + c.cord_y + enter_line
|
||||||
|
// +'G01 Z0 // Sobe a cabeça de gravação' + enter_line;
|
||||||
|
|
||||||
|
AData.AddBezierToPath(
|
||||||
|
StringToFloat(c.cord_x3), StringToFloat(c.cord_y3),
|
||||||
|
StringToFloat(c.cord_x2), StringToFloat(c.cord_y2),
|
||||||
|
StringToFloat(c.cord_x), StringToFloat(c.cord_y)
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
cc_CONCATENATE_MATRIX: // command cm
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSemantico.cc_CONCATENATE_MATRIX');
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
cm_a := StringToFloat(c.cord_x3);
|
||||||
|
cm_b := StringToFloat(c.cord_y3);
|
||||||
|
cm_c := StringToFloat(c.cord_x2);
|
||||||
|
cm_d := StringToFloat(c.cord_y2);
|
||||||
|
cm_e := StringToFloat(c.cord_x);
|
||||||
|
cm_f := StringToFloat(c.cord_y);
|
||||||
|
end;
|
||||||
|
cc_RESTORE_MATRIX: // command Q
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSemantico.cc_RESTORE_MATRIX');
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
cm_a:=1;
|
||||||
|
cm_b:=0;
|
||||||
|
cm_c:=0;
|
||||||
|
cm_d:=1;
|
||||||
|
cm_e:=0;
|
||||||
|
cm_f:=0;
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSemantico.generate Estado ELSE');
|
||||||
|
{$endif}
|
||||||
|
Result:=c.my_operator;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function AnSemantico.convert(x: String; y: String; Axis: Char): String;
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSemantico.convert');
|
||||||
|
{$endif}
|
||||||
|
// convert from 1/72 inch to milimeters and change axis if necessary
|
||||||
|
|
||||||
|
if (Axis = 'y') then
|
||||||
|
begin
|
||||||
|
// y' = b * x + d * y + f
|
||||||
|
Result:=FloatToStr((cm_b*StringToFloat(x)+cm_d*StringToFloat(y)+cm_f)*(25.40/72));
|
||||||
|
end
|
||||||
|
else
|
||||||
|
// Axis = 'x'
|
||||||
|
begin
|
||||||
|
// x' = a * x + c * y + e
|
||||||
|
Result:=FloatToStr((cm_a*StringToFloat(x)+cm_c*StringToFloat(y)+cm_e)*(25.40/72));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function AnSemantico.startMachine(): String;
|
||||||
|
var
|
||||||
|
enter_line : String;
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSemantico.startMachine');
|
||||||
|
{$endif}
|
||||||
|
enter_line:=chr(13) + chr(10); // CR and LF
|
||||||
|
|
||||||
|
Result:='M216 // Ligar monitor de carga' + enter_line +
|
||||||
|
'G28 // Ir rapidamente para posição inicial' + enter_line +
|
||||||
|
'G00' + enter_line;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function AnSemantico.endMachine(): String;
|
||||||
|
var
|
||||||
|
enter_line : String;
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSemantico.endMachine');
|
||||||
|
{$endif}
|
||||||
|
enter_line:=chr(13) + chr(10); // CR and LF
|
||||||
|
|
||||||
|
Result:='M30 // Parar o programa e retornar para posição inicial' + enter_line +
|
||||||
|
'M215 // Desligar monitor de carga' + enter_line;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor AnSemantico.Create;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
|
||||||
|
cm_a:=1;
|
||||||
|
cm_b:=0;
|
||||||
|
cm_c:=0;
|
||||||
|
cm_d:=1;
|
||||||
|
cm_e:=0;
|
||||||
|
cm_f:=0;
|
||||||
|
|
||||||
|
// Format seetings to convert a string to a float
|
||||||
|
FPointSeparator := DefaultFormatSettings;
|
||||||
|
FPointSeparator.DecimalSeparator := '.';
|
||||||
|
FPointSeparator.ThousandSeparator := '#';// disable the thousand separator
|
||||||
|
FCommaSeparator := DefaultFormatSettings;
|
||||||
|
FCommaSeparator.DecimalSeparator := ',';
|
||||||
|
FCommaSeparator.ThousandSeparator := '#';// disable the thousand separator
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
628
applications/fpvviewer/fpvectorialsrc/pdfvrsintatico.pas
Normal file
628
applications/fpvviewer/fpvectorialsrc/pdfvrsintatico.pas
Normal file
@ -0,0 +1,628 @@
|
|||||||
|
unit pdfvrsintatico;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, pdfvrlexico;
|
||||||
|
|
||||||
|
type
|
||||||
|
AnSintaticoPage = class
|
||||||
|
public
|
||||||
|
Estado: Int64;
|
||||||
|
obj1,obj2 : String;
|
||||||
|
pageFound: Boolean;
|
||||||
|
constructor Create;
|
||||||
|
procedure automata(t: Token);
|
||||||
|
end;
|
||||||
|
|
||||||
|
AnSintaticoPageContents = class
|
||||||
|
public
|
||||||
|
Estado: Int64;
|
||||||
|
obj1,obj2 : String;
|
||||||
|
len_obj1,len_obj2: String;
|
||||||
|
contentsFound: Boolean;
|
||||||
|
h: PageHeader;
|
||||||
|
constructor Create;
|
||||||
|
procedure automata(t: Token; Input: TStream);
|
||||||
|
end;
|
||||||
|
|
||||||
|
AnSintaticoCommand = class
|
||||||
|
public
|
||||||
|
Estado: Int64;
|
||||||
|
Codigo: Boolean;
|
||||||
|
c: Command;
|
||||||
|
constructor Create;
|
||||||
|
function automata(t: Token):Command;
|
||||||
|
end;
|
||||||
|
|
||||||
|
AnSintaticoLength = class
|
||||||
|
public
|
||||||
|
Estado: Int64;
|
||||||
|
len_obj1,len_obj2: String;
|
||||||
|
page_length : Int64;
|
||||||
|
lenghtFound: Boolean;
|
||||||
|
constructor Create;
|
||||||
|
procedure automata(t: Token);
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
procedure AnSintaticoPage.automata(t: Token);
|
||||||
|
begin
|
||||||
|
case Estado of
|
||||||
|
1:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoPage.automata Estado 1');
|
||||||
|
{$endif}
|
||||||
|
if(t.token_string = 'Type') then
|
||||||
|
begin
|
||||||
|
Estado := 2;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
2:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoPage.automata Estado 2');
|
||||||
|
{$endif}
|
||||||
|
if(t.token_string = 'Page') then
|
||||||
|
begin
|
||||||
|
Estado := 3;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
3:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoPage.automata Estado 3');
|
||||||
|
{$endif}
|
||||||
|
if(t.token_string = 'Contents') then
|
||||||
|
begin
|
||||||
|
Estado := 4;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 3;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
4:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoPage.automata Estado 4');
|
||||||
|
{$endif}
|
||||||
|
if(t.tipo = 1) then // numbers 1
|
||||||
|
begin
|
||||||
|
obj1:=t.token_string;
|
||||||
|
Estado := 5;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
raise Exception.Create('ERROR: Arquivo corrompido.');
|
||||||
|
Halt(1);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
5:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoPage.automata Estado 5');
|
||||||
|
{$endif}
|
||||||
|
if(t.tipo = 1) then // numbers 2
|
||||||
|
begin
|
||||||
|
obj2:=t.token_string;
|
||||||
|
Estado := 6; // symbolic state
|
||||||
|
pageFound := true;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
raise Exception.Create('ERROR: Arquivo corrompido.');
|
||||||
|
Halt(1);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoPage.automata Estado ELSE');
|
||||||
|
{$endif}
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure AnSintaticoPageContents.automata(t: Token; Input: TStream);
|
||||||
|
var
|
||||||
|
myAnLexicoLength: AnLexico;
|
||||||
|
myAnSintaticoLength: AnSintaticoLength;
|
||||||
|
mytokenLength: Token;
|
||||||
|
begin
|
||||||
|
case Estado of
|
||||||
|
1:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoPageContents.automata Estado 1');
|
||||||
|
{$endif}
|
||||||
|
if(t.token_string = obj1) then
|
||||||
|
begin
|
||||||
|
Estado := 2;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
2:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoPageContents.automata Estado 2');
|
||||||
|
{$endif}
|
||||||
|
if(t.token_string = obj2) then
|
||||||
|
begin
|
||||||
|
Estado := 3;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
3:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoPageContents.automata Estado 3');
|
||||||
|
{$endif}
|
||||||
|
if(t.token_string = 'obj') then
|
||||||
|
begin
|
||||||
|
Estado := 4;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
4:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoPageContents.automata Estado 4');
|
||||||
|
{$endif}
|
||||||
|
if(t.token_string = 'Length') then
|
||||||
|
begin
|
||||||
|
Estado := 5;
|
||||||
|
end
|
||||||
|
else if (t.token_string = 'Filter') then
|
||||||
|
begin
|
||||||
|
Estado := 7;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 4;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
5:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoPageContents.automata Estado 5');
|
||||||
|
{$endif}
|
||||||
|
if(t.tipo = 1) then
|
||||||
|
begin
|
||||||
|
h.page_length := StrToInt(t.token_string);
|
||||||
|
len_obj1:=t.token_string;
|
||||||
|
Estado := 6;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
raise Exception.Create('ERROR: Arquivo corrompido.');
|
||||||
|
Halt(1);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
6:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoPageContents.automata Estado 6');
|
||||||
|
{$endif}
|
||||||
|
if(t.token_string = 'Filter') then
|
||||||
|
begin
|
||||||
|
Estado := 7;
|
||||||
|
end
|
||||||
|
else if (t.token_string = 'stream') then
|
||||||
|
begin
|
||||||
|
contentsFound := true;
|
||||||
|
Estado := 9; // symbolic state
|
||||||
|
end
|
||||||
|
else if (t.tipo = 1) then
|
||||||
|
begin
|
||||||
|
len_obj2:=t.token_string;
|
||||||
|
myAnLexicoLength := AnLexico.Create;
|
||||||
|
myAnLexicoLength.Doc := Input;
|
||||||
|
myAnLexicoLength.bytesRemaining:= myAnLexicoLength.Doc.Size;
|
||||||
|
myAnSintaticoLength := AnSintaticoLength.Create;
|
||||||
|
|
||||||
|
myAnSintaticoLength.len_obj1:=len_obj1;
|
||||||
|
myAnSintaticoLength.len_obj2:=len_obj2;
|
||||||
|
|
||||||
|
while ((myAnSintaticoLength.lenghtFound <> true) and
|
||||||
|
(myAnLexicoLength.bytesRemaining > 0)) do
|
||||||
|
begin
|
||||||
|
mytokenLength := myAnLexicoLength.getToken();
|
||||||
|
myAnSintaticoLength.automata(mytokenLength);
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (myAnSintaticoLength.lenghtFound = false) then
|
||||||
|
begin
|
||||||
|
raise Exception.Create('ERROR: Arquivo corrompido.');
|
||||||
|
Halt(1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
h.page_length:=myAnSintaticoLength.page_length;
|
||||||
|
myAnLexicoLength.Doc.Destroy;
|
||||||
|
Estado := 6;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 6;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
7:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoPageContents.automata Estado 7');
|
||||||
|
{$endif}
|
||||||
|
if(t.token_string = 'FlateDecode') then
|
||||||
|
begin
|
||||||
|
h.flate_decode := true;
|
||||||
|
Estado := 8;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
raise Exception.Create('ERROR: Encodificacao nao suportada.');
|
||||||
|
Halt(1);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
8:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoPageContents.automata Estado 8');
|
||||||
|
{$endif}
|
||||||
|
if(t.token_string = 'stream') then
|
||||||
|
begin
|
||||||
|
contentsFound := true;
|
||||||
|
Estado := 9; // symbolic state
|
||||||
|
end
|
||||||
|
else if (t.token_string = 'Length') then
|
||||||
|
begin
|
||||||
|
Estado := 5;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 8;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoPageContents.automata Estado ELSE');
|
||||||
|
{$endif}
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure AnSintaticoLength.automata(t: Token);
|
||||||
|
begin
|
||||||
|
case Estado of
|
||||||
|
1:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoLength.automata Estado 1');
|
||||||
|
{$endif}
|
||||||
|
if(t.token_string = len_obj1) then
|
||||||
|
begin
|
||||||
|
Estado := 2;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
2:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoLength.automata Estado 2');
|
||||||
|
{$endif}
|
||||||
|
if(t.token_string = len_obj2) then
|
||||||
|
begin
|
||||||
|
Estado := 3;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
3:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoLength.automata Estado 3');
|
||||||
|
{$endif}
|
||||||
|
if(t.token_string = 'obj') then
|
||||||
|
begin
|
||||||
|
Estado := 4;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
4:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoLength.automata Estado 4 Length: ', StrToInt(t.token_string));
|
||||||
|
{$endif}
|
||||||
|
if(t.tipo = 1) then
|
||||||
|
begin
|
||||||
|
page_length:=StrToInt(t.token_string);
|
||||||
|
lenghtFound:=true;
|
||||||
|
Estado := 5; // symbolic state
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
raise Exception.Create('ERROR: Arquivo corrompido.');
|
||||||
|
Halt(1);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoLength.automata Estado ELSE');
|
||||||
|
{$endif}
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function AnSintaticoCommand.automata(t: Token):Command;
|
||||||
|
begin
|
||||||
|
c.cord_x3 := c.cord_y3;
|
||||||
|
c.cord_y3 := c.cord_x2;
|
||||||
|
c.cord_x2 := c.cord_y2;
|
||||||
|
c.cord_y2 := c.cord_x;
|
||||||
|
c.cord_x := c.cord_y;
|
||||||
|
c.cord_y := c.my_operator;
|
||||||
|
c.my_operator := t.token_string;
|
||||||
|
c.code := cc_NONE;
|
||||||
|
|
||||||
|
Codigo := false;
|
||||||
|
|
||||||
|
case Estado of
|
||||||
|
1:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoCommand.automata Estado 1');
|
||||||
|
{$endif}
|
||||||
|
if(t.tipo = 1) then // numbers 1
|
||||||
|
begin
|
||||||
|
Estado := 2;
|
||||||
|
end
|
||||||
|
else if( t.token_string = 'h' ) then // command h
|
||||||
|
begin
|
||||||
|
Estado := 9; // symbolic state
|
||||||
|
Estado := 1;
|
||||||
|
Codigo := true;
|
||||||
|
c.code:=cc_H_CLOSE_PATH;
|
||||||
|
Result:=c;
|
||||||
|
end
|
||||||
|
else if( t.token_string = 's' ) then // command s
|
||||||
|
begin
|
||||||
|
Estado := 10; // symbolic state
|
||||||
|
Estado := 1;
|
||||||
|
Codigo := true;
|
||||||
|
c.code:=cc_hS_CLOSE_AND_END_PATH;
|
||||||
|
Result:=c;
|
||||||
|
end
|
||||||
|
else if( t.token_string = 'S' ) then // command S
|
||||||
|
begin
|
||||||
|
Estado := 11; // symbolic state
|
||||||
|
Estado := 1;
|
||||||
|
Codigo := true;
|
||||||
|
c.code:=cc_S_END_PATH;
|
||||||
|
Result:=c;
|
||||||
|
end
|
||||||
|
else if( t.token_string = 'Q' ) then // command Q
|
||||||
|
begin
|
||||||
|
Estado := 21; // symbolic state
|
||||||
|
Estado := 1;
|
||||||
|
Codigo := true;
|
||||||
|
c.code:=cc_RESTORE_MATRIX;
|
||||||
|
Result:=c;
|
||||||
|
end
|
||||||
|
else if ((t.token_string = 'f') or (t.token_string = 'F')
|
||||||
|
or (t.token_string = 'f*') or (t.token_string = 'B')
|
||||||
|
or (t.token_string = 'B*') or (t.token_string = 'b')
|
||||||
|
or (t.token_string = 'b*') or (t.token_string = 'n')) then
|
||||||
|
begin
|
||||||
|
Estado := 12; // symbolic state
|
||||||
|
Estado := 1;
|
||||||
|
Codigo := true;
|
||||||
|
c.code:=cc_hS_CLOSE_AND_END_PATH; // ignore painting..
|
||||||
|
Result:=c;
|
||||||
|
//raise Exception.Create('ERROR: Prenchimento nao eh suportado.');
|
||||||
|
//Halt(1);
|
||||||
|
end
|
||||||
|
else if ((t.token_string = 'W') or (t.token_string = 'W*')) then
|
||||||
|
begin
|
||||||
|
Estado := 13; // symbolic state
|
||||||
|
raise Exception.Create('ERROR: Clipping nao eh suportado.');
|
||||||
|
Halt(1);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
2:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoCommand.automata Estado 2');
|
||||||
|
{$endif}
|
||||||
|
if(t.tipo = 1) then // numbers 2
|
||||||
|
begin
|
||||||
|
Estado := 3;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
3:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoCommand.automata Estado 3');
|
||||||
|
{$endif}
|
||||||
|
if(t.tipo = 1) then // numbers 3
|
||||||
|
begin
|
||||||
|
Estado := 5;
|
||||||
|
end
|
||||||
|
else if(t.token_string = 'l') then // command l
|
||||||
|
begin
|
||||||
|
Estado := 14; // symbolic state
|
||||||
|
Estado := 1;
|
||||||
|
c.code:=cc_l_ADD_LINE_TO_PATH;
|
||||||
|
Codigo := true;
|
||||||
|
Result:=c;
|
||||||
|
end
|
||||||
|
else if(t.token_string = 'm') then // command m
|
||||||
|
begin
|
||||||
|
Estado := 15; // symbolic state
|
||||||
|
Estado := 1;
|
||||||
|
c.code:=cc_m_START_PATH;
|
||||||
|
Codigo := true;
|
||||||
|
Result:=c;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
5:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoCommand.automata Estado 5');
|
||||||
|
{$endif}
|
||||||
|
if(t.tipo = 1) then // numbers 4
|
||||||
|
begin
|
||||||
|
Estado := 6;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
6:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoCommand.automata Estado 6');
|
||||||
|
{$endif}
|
||||||
|
if(t.tipo = 1) then // numbers 5
|
||||||
|
begin
|
||||||
|
Estado := 7;
|
||||||
|
end
|
||||||
|
else if( t.token_string = 'v' ) then // command v
|
||||||
|
begin
|
||||||
|
Estado := 16; // symbolic state
|
||||||
|
raise Exception.Create('ERROR: Curva de bezier nao eh suportada.');
|
||||||
|
Halt(1);
|
||||||
|
end
|
||||||
|
else if( t.token_string = 'y' ) then // command y
|
||||||
|
begin
|
||||||
|
Estado := 17; // symbolic state
|
||||||
|
raise Exception.Create('ERROR: Curva de bezier nao eh suportada.');
|
||||||
|
Halt(1);
|
||||||
|
end
|
||||||
|
else if( t.token_string = 're' ) then // command re
|
||||||
|
begin
|
||||||
|
Estado := 18; // symbolic state
|
||||||
|
raise Exception.Create('ERROR: Comando nao suportado.');
|
||||||
|
Halt(1);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
7:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoCommand.automata Estado 7');
|
||||||
|
{$endif}
|
||||||
|
if(t.tipo = 1) then // numbers 6
|
||||||
|
begin
|
||||||
|
Estado := 8;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
8:
|
||||||
|
begin
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoCommand.automata Estado 8');
|
||||||
|
{$endif}
|
||||||
|
if(t.token_string = 'c') then // commmand c
|
||||||
|
begin
|
||||||
|
Estado := 19; // symbolic state
|
||||||
|
Estado := 1;
|
||||||
|
c.code:=cc_c_BEZIER_TO_X_Y_USING_X2_Y2_AND_X3_Y3;
|
||||||
|
Codigo := true;
|
||||||
|
Result:=c;
|
||||||
|
end
|
||||||
|
else if( t.token_string = 'cm' ) then // command cm
|
||||||
|
begin
|
||||||
|
Estado := 20; // symbolic state
|
||||||
|
Estado := 1;
|
||||||
|
c.code:=cc_CONCATENATE_MATRIX;
|
||||||
|
Codigo := true;
|
||||||
|
Result:=c;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
{$ifdef FPVECTORIALDEBUG}
|
||||||
|
WriteLn(':> AnSintaticoCommand.automata Estado ELSE');
|
||||||
|
{$endif}
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor AnSintaticoCommand.Create;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
Estado := 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor AnSintaticoPage.Create;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
Estado := 1;
|
||||||
|
pageFound := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor AnSintaticoPageContents.Create;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
Estado := 1;
|
||||||
|
contentsFound := false;
|
||||||
|
h.flate_decode := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor AnSintaticoLength.Create;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
Estado := 1;
|
||||||
|
lenghtFound := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
245
applications/fpvviewer/fpvectorialsrc/svgvectorialwriter.pas
Normal file
245
applications/fpvviewer/fpvectorialsrc/svgvectorialwriter.pas
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
{
|
||||||
|
Writes an SVG Document
|
||||||
|
|
||||||
|
License: The same modified LGPL as the Free Pascal RTL
|
||||||
|
See the file COPYING.modifiedLGPL for more details
|
||||||
|
|
||||||
|
AUTHORS: Felipe Monteiro de Carvalho
|
||||||
|
}
|
||||||
|
unit svgvectorialwriter;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, math, fpvectorial;
|
||||||
|
|
||||||
|
type
|
||||||
|
{ TvSVGVectorialWriter }
|
||||||
|
|
||||||
|
TvSVGVectorialWriter = class(TvCustomVectorialWriter)
|
||||||
|
private
|
||||||
|
FPointSeparator, FCommaSeparator: TFormatSettings;
|
||||||
|
procedure WriteDocumentSize(AStrings: TStrings; AData: TvVectorialDocument);
|
||||||
|
procedure WriteDocumentName(AStrings: TStrings; AData: TvVectorialDocument);
|
||||||
|
procedure WritePaths(AStrings: TStrings; AData: TvVectorialDocument);
|
||||||
|
procedure WriteTexts(AStrings: TStrings; AData: TvVectorialDocument);
|
||||||
|
procedure ConvertFPVCoordinatesToSVGCoordinates(
|
||||||
|
const AData: TvVectorialDocument;
|
||||||
|
const ASrcX, ASrcY: Double; var ADestX, ADestY: double);
|
||||||
|
public
|
||||||
|
{ General reading methods }
|
||||||
|
procedure WriteToStrings(AStrings: TStrings; AData: TvVectorialDocument); override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
const
|
||||||
|
// SVG requires hardcoding a DPI value
|
||||||
|
|
||||||
|
// The Opera Browser and Inkscape use 90 DPI, so we follow that
|
||||||
|
|
||||||
|
// 1 Inch = 25.4 milimiters
|
||||||
|
// 90 inches per pixel = (1 / 90) * 25.4 = 0.2822
|
||||||
|
// FLOAT_MILIMETERS_PER_PIXEL = 0.3528; // DPI 72 = 1 / 72 inches per pixel
|
||||||
|
|
||||||
|
FLOAT_MILIMETERS_PER_PIXEL = 0.2822; // DPI 90 = 1 / 90 inches per pixel
|
||||||
|
FLOAT_PIXELS_PER_MILIMETER = 3.5433; // DPI 90 = 1 / 90 inches per pixel
|
||||||
|
|
||||||
|
{ TvSVGVectorialWriter }
|
||||||
|
|
||||||
|
procedure TvSVGVectorialWriter.WriteDocumentSize(AStrings: TStrings; AData: TvVectorialDocument);
|
||||||
|
begin
|
||||||
|
AStrings.Add(' width="' + FloatToStr(AData.Width, FPointSeparator) + 'mm"');
|
||||||
|
AStrings.Add(' height="' + FloatToStr(AData.Height, FPointSeparator) + 'mm"');
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvSVGVectorialWriter.WriteDocumentName(AStrings: TStrings; AData: TvVectorialDocument);
|
||||||
|
begin
|
||||||
|
AStrings.Add(' sodipodi:docname="New document 1">');
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
SVG Coordinate system measures things only in pixels, so that we have to
|
||||||
|
hardcode a DPI value for the screen, which is usually 72.
|
||||||
|
FPVectorial uses only milimeters (mm).
|
||||||
|
|
||||||
|
The initial point in FPVectorial is in the bottom-left corner of the document
|
||||||
|
and it grows to the top and to the right. In SVG, on the other hand, the
|
||||||
|
initial point is in the top-left corner, growing to the bottom and right.
|
||||||
|
Besides that, coordinates in SVG are also lengths in comparison to the
|
||||||
|
previous point and not absolute coordinates.
|
||||||
|
|
||||||
|
SVG uses commas "," to separate the X,Y coordinates, so it always uses points
|
||||||
|
"." as decimal separators and uses no thousand separators
|
||||||
|
}
|
||||||
|
procedure TvSVGVectorialWriter.WritePaths(AStrings: TStrings; AData: TvVectorialDocument);
|
||||||
|
var
|
||||||
|
i, j: Integer;
|
||||||
|
PathStr: string;
|
||||||
|
lPath: TPath;
|
||||||
|
PtX, PtY, OldPtX, OldPtY: double;
|
||||||
|
BezierCP1X, BezierCP1Y, BezierCP2X, BezierCP2Y: double;
|
||||||
|
segment: TPathSegment;
|
||||||
|
l2DSegment: T2DSegment absolute segment;
|
||||||
|
l2DBSegment: T2DBezierSegment absolute segment;
|
||||||
|
begin
|
||||||
|
for i := 0 to AData.GetPathCount() - 1 do
|
||||||
|
begin
|
||||||
|
OldPtX := 0;
|
||||||
|
OldPtY := 0;
|
||||||
|
|
||||||
|
PathStr := '';
|
||||||
|
lPath := AData.GetPath(i);
|
||||||
|
lPath.PrepareForSequentialReading;
|
||||||
|
|
||||||
|
for j := 0 to lPath.Len - 1 do
|
||||||
|
begin
|
||||||
|
segment := TPathSegment(lPath.Next());
|
||||||
|
|
||||||
|
if (segment.SegmentType <> st2DLine)
|
||||||
|
and (segment.SegmentType <> stMoveTo)
|
||||||
|
and (segment.SegmentType <> st2DBezier)
|
||||||
|
then Break; // unsupported line type
|
||||||
|
|
||||||
|
// Coordinate conversion from fpvectorial to SVG
|
||||||
|
ConvertFPVCoordinatesToSVGCoordinates(
|
||||||
|
AData, l2DSegment.X, l2DSegment.Y, PtX, PtY);
|
||||||
|
PtX := PtX - OldPtX;
|
||||||
|
PtY := PtY - OldPtY;
|
||||||
|
|
||||||
|
if (segment.SegmentType = stMoveTo) then
|
||||||
|
begin
|
||||||
|
PathStr := PathStr + 'm '
|
||||||
|
+ FloatToStr(PtX, FPointSeparator) + ','
|
||||||
|
+ FloatToStr(PtY, FPointSeparator) + ' ';
|
||||||
|
end
|
||||||
|
else if (segment.SegmentType = st2DLine) then
|
||||||
|
begin
|
||||||
|
PathStr := PathStr + 'l '
|
||||||
|
+ FloatToStr(PtX, FPointSeparator) + ','
|
||||||
|
+ FloatToStr(PtY, FPointSeparator) + ' ';
|
||||||
|
end
|
||||||
|
else if (segment.SegmentType = st2DBezier) then
|
||||||
|
begin
|
||||||
|
// Converts all coordinates to absolute values
|
||||||
|
ConvertFPVCoordinatesToSVGCoordinates(
|
||||||
|
AData, l2DBSegment.X2, l2DBSegment.Y2, BezierCP1X, BezierCP1Y);
|
||||||
|
ConvertFPVCoordinatesToSVGCoordinates(
|
||||||
|
AData, l2DBSegment.X3, l2DBSegment.Y3, BezierCP2X, BezierCP2Y);
|
||||||
|
|
||||||
|
// Transforms them into values relative to the initial point
|
||||||
|
BezierCP1X := BezierCP1X - OldPtX;
|
||||||
|
BezierCP1Y := BezierCP1Y - OldPtY;
|
||||||
|
BezierCP2X := BezierCP2X - OldPtX;
|
||||||
|
BezierCP2Y := BezierCP2Y - OldPtY;
|
||||||
|
|
||||||
|
// PtX and PtY already contains the destination point
|
||||||
|
|
||||||
|
// Now render our 2D cubic bezier
|
||||||
|
PathStr := PathStr + 'c '
|
||||||
|
+ FloatToStr(BezierCP1X, FPointSeparator) + ','
|
||||||
|
+ FloatToStr(BezierCP1Y, FPointSeparator) + ' '
|
||||||
|
+ FloatToStr(BezierCP2X, FPointSeparator) + ','
|
||||||
|
+ FloatToStr(BezierCP2Y, FPointSeparator) + ' '
|
||||||
|
+ FloatToStr(PtX, FPointSeparator) + ','
|
||||||
|
+ FloatToStr(PtY, FPointSeparator) + ' '
|
||||||
|
;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Store the current position for future points
|
||||||
|
OldPtX := OldPtX + PtX;
|
||||||
|
OldPtY := OldPtY + PtY;
|
||||||
|
end;
|
||||||
|
|
||||||
|
AStrings.Add(' <path');
|
||||||
|
AStrings.Add(' style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"');
|
||||||
|
AStrings.Add(' d="' + PathStr + '"');
|
||||||
|
AStrings.Add(' id="path' + IntToStr(i) + '" />');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvSVGVectorialWriter.ConvertFPVCoordinatesToSVGCoordinates(
|
||||||
|
const AData: TvVectorialDocument; const ASrcX, ASrcY: Double; var ADestX,
|
||||||
|
ADestY: double);
|
||||||
|
begin
|
||||||
|
ADestX := ASrcX / FLOAT_MILIMETERS_PER_PIXEL;
|
||||||
|
ADestY := (AData.Height - ASrcY) / FLOAT_MILIMETERS_PER_PIXEL;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvSVGVectorialWriter.WriteToStrings(AStrings: TStrings;
|
||||||
|
AData: TvVectorialDocument);
|
||||||
|
begin
|
||||||
|
// Format seetings to convert a string to a float
|
||||||
|
FPointSeparator := DefaultFormatSettings;
|
||||||
|
FPointSeparator.DecimalSeparator := '.';
|
||||||
|
FPointSeparator.ThousandSeparator := '#';// disable the thousand separator
|
||||||
|
FCommaSeparator := DefaultFormatSettings;
|
||||||
|
FCommaSeparator.DecimalSeparator := ',';
|
||||||
|
FCommaSeparator.ThousandSeparator := '#';// disable the thousand separator
|
||||||
|
|
||||||
|
// Headers
|
||||||
|
AStrings.Add('<?xml version="1.0" encoding="UTF-8" standalone="no"?>');
|
||||||
|
AStrings.Add('<!-- Created with fpVectorial (http://wiki.lazarus.freepascal.org/fpvectorial) -->');
|
||||||
|
AStrings.Add('');
|
||||||
|
AStrings.Add('<svg');
|
||||||
|
AStrings.Add(' xmlns:dc="http://purl.org/dc/elements/1.1/"');
|
||||||
|
AStrings.Add(' xmlns:cc="http://creativecommons.org/ns#"');
|
||||||
|
AStrings.Add(' xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"');
|
||||||
|
AStrings.Add(' xmlns:svg="http://www.w3.org/2000/svg"');
|
||||||
|
AStrings.Add(' xmlns="http://www.w3.org/2000/svg"');
|
||||||
|
AStrings.Add(' xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"');
|
||||||
|
WriteDocumentSize(AStrings, AData);
|
||||||
|
AStrings.Add(' id="svg2"');
|
||||||
|
AStrings.Add(' version="1.1"');
|
||||||
|
WriteDocumentName(AStrings, AData);
|
||||||
|
|
||||||
|
// Now data
|
||||||
|
AStrings.Add(' <g id="layer1">');
|
||||||
|
WritePaths(AStrings, AData);
|
||||||
|
WriteTexts(AStrings, AData);
|
||||||
|
AStrings.Add(' </g>');
|
||||||
|
|
||||||
|
// finalization
|
||||||
|
AStrings.Add('</svg>');
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvSVGVectorialWriter.WriteTexts(AStrings: TStrings; AData: TvVectorialDocument);
|
||||||
|
var
|
||||||
|
i, j, FontSize: Integer;
|
||||||
|
TextStr, FontName, SVGFontFamily: string;
|
||||||
|
lText: TvText;
|
||||||
|
PtX, PtY: double;
|
||||||
|
begin
|
||||||
|
for i := 0 to AData.GetTextCount() - 1 do
|
||||||
|
begin
|
||||||
|
TextStr := '';
|
||||||
|
lText := AData.GetText(i);
|
||||||
|
|
||||||
|
ConvertFPVCoordinatesToSVGCoordinates(
|
||||||
|
AData, lText.X, lText.Y, PtX, PtY);
|
||||||
|
|
||||||
|
TextStr := lText.Value;
|
||||||
|
FontSize:= ceil(lText.FontSize / FLOAT_MILIMETERS_PER_PIXEL);
|
||||||
|
SVGFontFamily := 'Arial, sans-serif';//lText.FontName;
|
||||||
|
|
||||||
|
AStrings.Add(' <text ');
|
||||||
|
AStrings.Add(' x="' + FloatToStr(PtX, FPointSeparator) + '"');
|
||||||
|
AStrings.Add(' y="' + FloatToStr(PtY, FPointSeparator) + '"');
|
||||||
|
// AStrings.Add(' font-size="' + IntToStr(FontSize) + '"'); Doesn't seam to work, we need to use the tspan
|
||||||
|
AStrings.Add(' font-family="' + SVGFontFamily + '">');
|
||||||
|
AStrings.Add(' <tspan ');
|
||||||
|
AStrings.Add(' style="font-size:' + IntToStr(FontSize) + '" ');
|
||||||
|
// AStrings.Add(' id="tspan2828" ');
|
||||||
|
AStrings.Add(' >');
|
||||||
|
AStrings.Add(TextStr + '</tspan></text>');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
initialization
|
||||||
|
|
||||||
|
RegisterVectorialWriter(TvSVGVectorialWriter, vfSVG);
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
@ -3,11 +3,14 @@
|
|||||||
<ProjectOptions>
|
<ProjectOptions>
|
||||||
<Version Value="9"/>
|
<Version Value="9"/>
|
||||||
<General>
|
<General>
|
||||||
|
<Flags>
|
||||||
|
<AlwaysBuild Value="False"/>
|
||||||
|
</Flags>
|
||||||
|
<SessionStorage Value="InProjectDir"/>
|
||||||
<MainUnit Value="0"/>
|
<MainUnit Value="0"/>
|
||||||
<ResourceType Value="res"/>
|
<ResourceType Value="res"/>
|
||||||
<UseXPManifest Value="True"/>
|
<UseXPManifest Value="True"/>
|
||||||
<Icon Value="0"/>
|
<Icon Value="0"/>
|
||||||
<ActiveWindowIndexAtStart Value="0"/>
|
|
||||||
</General>
|
</General>
|
||||||
<i18n>
|
<i18n>
|
||||||
<EnableI18N LFM="False"/>
|
<EnableI18N LFM="False"/>
|
||||||
@ -15,7 +18,7 @@
|
|||||||
<VersionInfo>
|
<VersionInfo>
|
||||||
<StringTable ProductVersion=""/>
|
<StringTable ProductVersion=""/>
|
||||||
</VersionInfo>
|
</VersionInfo>
|
||||||
<BuildModes Count="1" Active="Default">
|
<BuildModes Count="1">
|
||||||
<Item1 Name="Default" Default="True"/>
|
<Item1 Name="Default" Default="True"/>
|
||||||
</BuildModes>
|
</BuildModes>
|
||||||
<PublishOptions>
|
<PublishOptions>
|
||||||
@ -34,12 +37,11 @@
|
|||||||
<PackageName Value="LCL"/>
|
<PackageName Value="LCL"/>
|
||||||
</Item1>
|
</Item1>
|
||||||
</RequiredPackages>
|
</RequiredPackages>
|
||||||
<Units Count="8">
|
<Units Count="2">
|
||||||
<Unit0>
|
<Unit0>
|
||||||
<Filename Value="fpvviewer.lpr"/>
|
<Filename Value="fpvviewer.lpr"/>
|
||||||
<IsPartOfProject Value="True"/>
|
<IsPartOfProject Value="True"/>
|
||||||
<UnitName Value="fpvviewer"/>
|
<UnitName Value="fpvviewer"/>
|
||||||
<UsageCount Value="21"/>
|
|
||||||
</Unit0>
|
</Unit0>
|
||||||
<Unit1>
|
<Unit1>
|
||||||
<Filename Value="fpvv_mainform.pas"/>
|
<Filename Value="fpvv_mainform.pas"/>
|
||||||
@ -47,194 +49,8 @@
|
|||||||
<ComponentName Value="frmFPVViewer"/>
|
<ComponentName Value="frmFPVViewer"/>
|
||||||
<ResourceBaseClass Value="Form"/>
|
<ResourceBaseClass Value="Form"/>
|
||||||
<UnitName Value="fpvv_mainform"/>
|
<UnitName Value="fpvv_mainform"/>
|
||||||
<IsVisibleTab Value="True"/>
|
|
||||||
<EditorIndex Value="0"/>
|
|
||||||
<WindowIndex Value="0"/>
|
|
||||||
<TopLine Value="26"/>
|
|
||||||
<CursorPos X="80" Y="58"/>
|
|
||||||
<UsageCount Value="21"/>
|
|
||||||
<Loaded Value="True"/>
|
|
||||||
<LoadedDesigner Value="True"/>
|
|
||||||
</Unit1>
|
</Unit1>
|
||||||
<Unit2>
|
|
||||||
<Filename Value="fpvectorial.pas"/>
|
|
||||||
<UnitName Value="fpvectorial"/>
|
|
||||||
<EditorIndex Value="4"/>
|
|
||||||
<WindowIndex Value="0"/>
|
|
||||||
<TopLine Value="23"/>
|
|
||||||
<CursorPos X="35" Y="44"/>
|
|
||||||
<UsageCount Value="11"/>
|
|
||||||
<Loaded Value="True"/>
|
|
||||||
</Unit2>
|
|
||||||
<Unit3>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<UnitName Value="fpvtocanvas"/>
|
|
||||||
<EditorIndex Value="3"/>
|
|
||||||
<WindowIndex Value="0"/>
|
|
||||||
<TopLine Value="54"/>
|
|
||||||
<CursorPos X="1" Y="73"/>
|
|
||||||
<UsageCount Value="11"/>
|
|
||||||
<Loaded Value="True"/>
|
|
||||||
</Unit3>
|
|
||||||
<Unit4>
|
|
||||||
<Filename Value="dxfvectorialreader.pas"/>
|
|
||||||
<UnitName Value="dxfvectorialreader"/>
|
|
||||||
<EditorIndex Value="2"/>
|
|
||||||
<WindowIndex Value="0"/>
|
|
||||||
<TopLine Value="184"/>
|
|
||||||
<CursorPos X="16" Y="221"/>
|
|
||||||
<UsageCount Value="11"/>
|
|
||||||
<Loaded Value="True"/>
|
|
||||||
</Unit4>
|
|
||||||
<Unit5>
|
|
||||||
<Filename Value="../../../lazarus/lcl/include/spinedit.inc"/>
|
|
||||||
<EditorIndex Value="1"/>
|
|
||||||
<WindowIndex Value="0"/>
|
|
||||||
<TopLine Value="118"/>
|
|
||||||
<CursorPos X="1" Y="145"/>
|
|
||||||
<UsageCount Value="10"/>
|
|
||||||
<Loaded Value="True"/>
|
|
||||||
<DefaultSyntaxHighlighter Value="Delphi"/>
|
|
||||||
</Unit5>
|
|
||||||
<Unit6>
|
|
||||||
<Filename Value="../../../lazarus/lcl/include/wincontrol.inc"/>
|
|
||||||
<WindowIndex Value="0"/>
|
|
||||||
<TopLine Value="7144"/>
|
|
||||||
<CursorPos X="1" Y="7165"/>
|
|
||||||
<UsageCount Value="10"/>
|
|
||||||
<DefaultSyntaxHighlighter Value="Delphi"/>
|
|
||||||
</Unit6>
|
|
||||||
<Unit7>
|
|
||||||
<Filename Value="../../../lazarus/lcl/include/customimage.inc"/>
|
|
||||||
<WindowIndex Value="0"/>
|
|
||||||
<TopLine Value="34"/>
|
|
||||||
<CursorPos X="1" Y="66"/>
|
|
||||||
<UsageCount Value="10"/>
|
|
||||||
<DefaultSyntaxHighlighter Value="Delphi"/>
|
|
||||||
</Unit7>
|
|
||||||
</Units>
|
</Units>
|
||||||
<JumpHistory Count="30" HistoryIndex="29">
|
|
||||||
<Position1>
|
|
||||||
<Filename Value="../../../lazarus/lcl/include/spinedit.inc"/>
|
|
||||||
<Caret Line="145" Column="1" TopLine="118"/>
|
|
||||||
</Position1>
|
|
||||||
<Position2>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="48" Column="1" TopLine="28"/>
|
|
||||||
</Position2>
|
|
||||||
<Position3>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="49" Column="1" TopLine="28"/>
|
|
||||||
</Position3>
|
|
||||||
<Position4>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="51" Column="1" TopLine="28"/>
|
|
||||||
</Position4>
|
|
||||||
<Position5>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="53" Column="1" TopLine="28"/>
|
|
||||||
</Position5>
|
|
||||||
<Position6>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="56" Column="1" TopLine="28"/>
|
|
||||||
</Position6>
|
|
||||||
<Position7>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="58" Column="1" TopLine="28"/>
|
|
||||||
</Position7>
|
|
||||||
<Position8>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="61" Column="1" TopLine="29"/>
|
|
||||||
</Position8>
|
|
||||||
<Position9>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="63" Column="1" TopLine="31"/>
|
|
||||||
</Position9>
|
|
||||||
<Position10>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="61" Column="1" TopLine="31"/>
|
|
||||||
</Position10>
|
|
||||||
<Position11>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="63" Column="1" TopLine="31"/>
|
|
||||||
</Position11>
|
|
||||||
<Position12>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="66" Column="1" TopLine="34"/>
|
|
||||||
</Position12>
|
|
||||||
<Position13>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="67" Column="1" TopLine="35"/>
|
|
||||||
</Position13>
|
|
||||||
<Position14>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="70" Column="1" TopLine="38"/>
|
|
||||||
</Position14>
|
|
||||||
<Position15>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="71" Column="1" TopLine="39"/>
|
|
||||||
</Position15>
|
|
||||||
<Position16>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="69" Column="1" TopLine="39"/>
|
|
||||||
</Position16>
|
|
||||||
<Position17>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="56" Column="1" TopLine="39"/>
|
|
||||||
</Position17>
|
|
||||||
<Position18>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="58" Column="1" TopLine="39"/>
|
|
||||||
</Position18>
|
|
||||||
<Position19>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="61" Column="1" TopLine="39"/>
|
|
||||||
</Position19>
|
|
||||||
<Position20>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="63" Column="1" TopLine="39"/>
|
|
||||||
</Position20>
|
|
||||||
<Position21>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="61" Column="1" TopLine="39"/>
|
|
||||||
</Position21>
|
|
||||||
<Position22>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="63" Column="1" TopLine="39"/>
|
|
||||||
</Position22>
|
|
||||||
<Position23>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="66" Column="1" TopLine="39"/>
|
|
||||||
</Position23>
|
|
||||||
<Position24>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="67" Column="1" TopLine="39"/>
|
|
||||||
</Position24>
|
|
||||||
<Position25>
|
|
||||||
<Filename Value="dxfvectorialreader.pas"/>
|
|
||||||
<Caret Line="221" Column="16" TopLine="184"/>
|
|
||||||
</Position25>
|
|
||||||
<Position26>
|
|
||||||
<Filename Value="fpvtocanvas.pas"/>
|
|
||||||
<Caret Line="64" Column="11" TopLine="43"/>
|
|
||||||
</Position26>
|
|
||||||
<Position27>
|
|
||||||
<Filename Value="fpvv_mainform.pas"/>
|
|
||||||
<Caret Line="54" Column="52" TopLine="22"/>
|
|
||||||
</Position27>
|
|
||||||
<Position28>
|
|
||||||
<Filename Value="fpvv_mainform.pas"/>
|
|
||||||
<Caret Line="55" Column="52" TopLine="23"/>
|
|
||||||
</Position28>
|
|
||||||
<Position29>
|
|
||||||
<Filename Value="fpvv_mainform.pas"/>
|
|
||||||
<Caret Line="56" Column="52" TopLine="24"/>
|
|
||||||
</Position29>
|
|
||||||
<Position30>
|
|
||||||
<Filename Value="fpvv_mainform.pas"/>
|
|
||||||
<Caret Line="57" Column="52" TopLine="25"/>
|
|
||||||
</Position30>
|
|
||||||
</JumpHistory>
|
|
||||||
</ProjectOptions>
|
</ProjectOptions>
|
||||||
<CompilerOptions>
|
<CompilerOptions>
|
||||||
<Version Value="9"/>
|
<Version Value="9"/>
|
||||||
@ -243,6 +59,7 @@
|
|||||||
</Target>
|
</Target>
|
||||||
<SearchPaths>
|
<SearchPaths>
|
||||||
<IncludeFiles Value="$(ProjOutDir)"/>
|
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||||
|
<OtherUnitFiles Value="fpvectorialsrc"/>
|
||||||
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
|
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
|
||||||
</SearchPaths>
|
</SearchPaths>
|
||||||
<Linking>
|
<Linking>
|
||||||
@ -253,6 +70,9 @@
|
|||||||
</Options>
|
</Options>
|
||||||
</Linking>
|
</Linking>
|
||||||
<Other>
|
<Other>
|
||||||
|
<CompilerMessages>
|
||||||
|
<UseMsgFile Value="True"/>
|
||||||
|
</CompilerMessages>
|
||||||
<CompilerPath Value="$(CompPath)"/>
|
<CompilerPath Value="$(CompPath)"/>
|
||||||
</Other>
|
</Other>
|
||||||
</CompilerOptions>
|
</CompilerOptions>
|
||||||
|
Reference in New Issue
Block a user