summaryrefslogtreecommitdiff
path: root/packages/fpvectorial/src
diff options
context:
space:
mode:
authorsekelsenmat <sekelsenmat@3ad0048d-3df7-0310-abae-a5850022a9f2>2010-08-13 14:56:40 +0000
committersekelsenmat <sekelsenmat@3ad0048d-3df7-0310-abae-a5850022a9f2>2010-08-13 14:56:40 +0000
commit37673c6306f946288b0638275f9ca29100b3d37b (patch)
tree372c4530c19fab97a645ab20bc332525d7609f91 /packages/fpvectorial/src
parentae46f170027155df1b81b8f76259aa2646570c47 (diff)
downloadfpc-37673c6306f946288b0638275f9ca29100b3d37b.tar.gz
Starts implementing svg writer and improves test app and pdf reader
git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@15799 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'packages/fpvectorial/src')
-rw-r--r--packages/fpvectorial/src/fpvectorial.pas18
-rw-r--r--packages/fpvectorial/src/fpvtocanvas.pas12
-rw-r--r--packages/fpvectorial/src/pdfvrsemantico.pas53
-rw-r--r--packages/fpvectorial/src/svgvectorialwriter.pas87
4 files changed, 146 insertions, 24 deletions
diff --git a/packages/fpvectorial/src/fpvectorial.pas b/packages/fpvectorial/src/fpvectorial.pas
index 0b18f768d5..d2a50a2a9d 100644
--- a/packages/fpvectorial/src/fpvectorial.pas
+++ b/packages/fpvectorial/src/fpvectorial.pas
@@ -38,6 +38,11 @@ type
st2DLine, st2DBezier,
st3DLine, st3DBezier);
+ {@
+ The coordinates in fpvectorial are given in millimiters and
+ the starting point is in the top-left corner of the document
+ and it grows to the bottom and to the right.
+ }
TPathSegment = record
SegmentType: TSegmentType;
X, Y, Z: Double; // Z is ignored in 2D segments
@@ -617,10 +622,21 @@ begin
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;
diff --git a/packages/fpvectorial/src/fpvtocanvas.pas b/packages/fpvectorial/src/fpvtocanvas.pas
index c7b5ff1a4a..a75c7dc8bf 100644
--- a/packages/fpvectorial/src/fpvtocanvas.pas
+++ b/packages/fpvectorial/src/fpvtocanvas.pas
@@ -10,12 +10,12 @@ uses
fpvectorial;
procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument; ADest: TFPCustomCanvas;
- ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Integer = 1; AMulY: Integer = 1);
+ ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
implementation
procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument; ADest: TFPCustomCanvas;
- ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Integer = 1; AMulY: Integer = 1);
+ 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
@@ -47,8 +47,8 @@ begin
PosX := Round(CurSegment.X);
PosY := Round(CurSegment.Y);
ADest.LineTo(
- ADestX + AMulX * PosX,
- ADestY + AMulY * PosY
+ Round(ADestX + AMulX * PosX),
+ Round(ADestY + AMulY * PosY)
);
end;
{ To draw a bezier we need to divide the interval in parts and make
@@ -66,8 +66,8 @@ begin
CurX := Round(sqr(1 - t) * (1 - t) * PosX + 3 * t * sqr(1 - t) * CurSegment.X2 + 3 * t * t * (1 - t) * CurSegment.X3 + t * t * t * CurSegment.X);
CurY := Round(sqr(1 - t) * (1 - t) * PosY + 3 * t * sqr(1 - t) * CurSegment.Y2 + 3 * t * t * (1 - t) * CurSegment.Y3 + t * t * t * CurSegment.Y);
ADest.LineTo(
- ADestX + AMulX * CurX,
- ADestY + AMulY * CurY);
+ Round(ADestX + AMulX * CurX),
+ Round(ADestY + AMulY * CurY));
end;
PosX := Round(CurSegment.X);
PosY := Round(CurSegment.Y);
diff --git a/packages/fpvectorial/src/pdfvrsemantico.pas b/packages/fpvectorial/src/pdfvrsemantico.pas
index 421e0d6175..bf2c80edfe 100644
--- a/packages/fpvectorial/src/pdfvrsemantico.pas
+++ b/packages/fpvectorial/src/pdfvrsemantico.pas
@@ -8,11 +8,16 @@ 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;
@@ -22,6 +27,14 @@ type
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;
@@ -29,6 +42,7 @@ 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
@@ -69,7 +83,7 @@ begin
// Correcao para programas de desenho que geram um novo inicio no
// fim do desenho, terminamos qualquer desenho inacabado
AData.EndPath();
- AData.StartPath(StrToFloat(c.cord_x), StrToFloat(c.cord_y));
+ AData.StartPath(StringToFloat(c.cord_x), StringToFloat(c.cord_y));
close_path_x:=c.cord_x;
close_path_y:=c.cord_y;
@@ -81,7 +95,7 @@ begin
{$endif}
// Result:='G01' + ' ' + 'X' + c.cord_x + ' ' + 'Y' + c.cord_y;
- AData.AddLineToPath(StrToFloat(c.cord_x), StrToFloat(c.cord_y));
+ AData.AddLineToPath(StringToFloat(c.cord_x), StringToFloat(c.cord_y));
end;
cc_h_CLOSE_PATH: // command h
begin
@@ -90,7 +104,7 @@ begin
{$endif}
//Result:='G01' + ' ' + 'X' + c.cord_x + ' ' + 'Y' + c.cord_y;
- AData.AddLineToPath(StrToFloat(c.cord_x), StrToFloat(c.cord_y));
+ AData.AddLineToPath(StringToFloat(c.cord_x), StringToFloat(c.cord_y));
end;
cc_S_END_PATH: // command S
begin
@@ -108,7 +122,7 @@ begin
//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(StrToFloat(c.cord_x), StrToFloat(c.cord_y));
+ 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
@@ -120,9 +134,9 @@ begin
// +'G01 Z0 // Sobe a cabeça de gravação' + enter_line;
AData.AddBezierToPath(
- StrToFloat(c.cord_x3), StrToFloat(c.cord_y3),
- StrToFloat(c.cord_x2), StrToFloat(c.cord_y2),
- StrToFloat(c.cord_x), StrToFloat(c.cord_y)
+ 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
@@ -131,12 +145,12 @@ begin
WriteLn(':> AnSemantico.cc_CONCATENATE_MATRIX');
{$endif}
- cm_a := StrToFloat(c.cord_x3);
- cm_b := StrToFloat(c.cord_y3);
- cm_c := StrToFloat(c.cord_x2);
- cm_d := StrToFloat(c.cord_y2);
- cm_e := StrToFloat(c.cord_x);
- cm_f := StrToFloat(c.cord_y);
+ 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
@@ -169,13 +183,13 @@ begin
if (Axis = 'y') then
begin
// y' = b * x + d * y + f
- Result:=FloatToStr((cm_b*StrToFloat(x)+cm_d*StrToFloat(y)+cm_f)*(25.40/72));
+ 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*StrToFloat(x)+cm_c*StrToFloat(y)+cm_e)*(25.40/72));
+ Result:=FloatToStr((cm_a*StringToFloat(x)+cm_c*StringToFloat(y)+cm_e)*(25.40/72));
end;
end;
@@ -209,12 +223,21 @@ 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.
diff --git a/packages/fpvectorial/src/svgvectorialwriter.pas b/packages/fpvectorial/src/svgvectorialwriter.pas
index cafd26c782..782590afe6 100644
--- a/packages/fpvectorial/src/svgvectorialwriter.pas
+++ b/packages/fpvectorial/src/svgvectorialwriter.pas
@@ -20,19 +20,102 @@ 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);
public
{ General reading methods }
- procedure WriteToStream(AStream: TStream; AData: TvVectorialDocument); virtual;
+ procedure WriteToStrings(AStrings: TStrings; AData: TvVectorialDocument); override;
end;
implementation
{ TvSVGVectorialWriter }
-procedure TvSVGVectorialWriter.WriteToStream(AStream: TStream;
+procedure TvSVGVectorialWriter.WriteDocumentSize(AStrings: TStrings; AData: TvVectorialDocument);
+begin
+ AStrings.Add(' width="744.09448819"');
+ AStrings.Add(' height="1052.3622047"');
+end;
+
+procedure TvSVGVectorialWriter.WriteDocumentName(AStrings: TStrings; AData: TvVectorialDocument);
+begin
+ AStrings.Add(' sodipodi:docname="New document 1">');
+end;
+
+{@@
+ SVG Coordinate system measures things in millimiters.
+ The initial point is in the bottom-left corner of the document and it grows
+ to the top and to the right.
+
+ 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: double;
+begin
+ for i := 0 to AData.GetPathCount() - 1 do
+ begin
+ PathStr := 'm ';
+ lPath := AData.GetPath(i);
+ for j := 0 to lPath.Len - 1 do
+ begin
+ if lPath.Points[j].SegmentType <> st2DLine then Break; // unsupported line type
+
+ PtX := lPath.Points[j].X;
+ PtY := lPath.Points[j].Y;
+ PtY := AData.Height - PtY;
+ PathStr := PathStr + FloatToStr(PtX, FPointSeparator) + ','
+ + FloatToStr(PtY, FPointSeparator) + ' ';
+ 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.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);
+ AStrings.Add(' </g>');
+ // finalization
+ AStrings.Add('</svg>');
end;
initialization