Browse Source

Starts implementing svg writer and improves test app and pdf reader

git-svn-id: trunk@15799 -
sekelsenmat 15 years ago
parent
commit
6403d462d2

+ 23 - 7
packages/fpvectorial/examples/cdr2svg_mainform.lfm

@@ -1,10 +1,11 @@
-object Form1: TForm1
+object formCDR2SVG: TformCDR2SVG
   Left = 216
   Left = 216
-  Height = 240
+  Height = 439
   Top = 192
   Top = 192
   Width = 240
   Width = 240
+  BorderStyle = bsSingle
   Caption = 'cdr2svg'
   Caption = 'cdr2svg'
-  ClientHeight = 240
+  ClientHeight = 439
   ClientWidth = 240
   ClientWidth = 240
   LCLVersion = '0.9.29'
   LCLVersion = '0.9.29'
   object Label1: TLabel
   object Label1: TLabel
@@ -60,21 +61,36 @@ object Form1: TForm1
     TabOrder = 1
     TabOrder = 1
   end
   end
   object buttonConvert: TButton
   object buttonConvert: TButton
-    Left = 32
+    Left = 87
     Height = 25
     Height = 25
     Top = 200
     Top = 200
-    Width = 75
+    Width = 67
     Caption = 'Convert'
     Caption = 'Convert'
     OnClick = buttonConvertClick
     OnClick = buttonConvertClick
     TabOrder = 2
     TabOrder = 2
   end
   end
   object buttonQuit: TButton
   object buttonQuit: TButton
-    Left = 136
+    Left = 176
     Height = 25
     Height = 25
     Top = 200
     Top = 200
-    Width = 75
+    Width = 59
     Caption = 'Quit'
     Caption = 'Quit'
     OnClick = buttonQuitClick
     OnClick = buttonQuitClick
     TabOrder = 3
     TabOrder = 3
   end
   end
+  object imagePreview: TImage
+    Left = 8
+    Height = 202
+    Top = 232
+    Width = 224
+  end
+  object buttonVisualize: TButton
+    Left = 8
+    Height = 25
+    Top = 200
+    Width = 59
+    Caption = 'Visualize'
+    OnClick = buttonVisualizeClick
+    TabOrder = 4
+  end
 end
 end

+ 37 - 9
packages/fpvectorial/examples/cdr2svg_mainform.pas

@@ -6,57 +6,85 @@ interface
 
 
 uses
 uses
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
-  EditBtn;
+  EditBtn, ExtCtrls;
 
 
 type
 type
 
 
-  { TForm1 }
+  { TformCDR2SVG }
 
 
-  TForm1 = class(TForm)
+  TformCDR2SVG = class(TForm)
+    buttonVisualize: TButton;
     buttonConvert: TButton;
     buttonConvert: TButton;
     buttonQuit: TButton;
     buttonQuit: TButton;
     editInput: TFileNameEdit;
     editInput: TFileNameEdit;
     editOutput: TFileNameEdit;
     editOutput: TFileNameEdit;
+    imagePreview: TImage;
     Label1: TLabel;
     Label1: TLabel;
     Label2: TLabel;
     Label2: TLabel;
     Label3: TLabel;
     Label3: TLabel;
     procedure buttonConvertClick(Sender: TObject);
     procedure buttonConvertClick(Sender: TObject);
     procedure buttonQuitClick(Sender: TObject);
     procedure buttonQuitClick(Sender: TObject);
+    procedure buttonVisualizeClick(Sender: TObject);
   private
   private
     { private declarations }
     { private declarations }
+    function CheckInput(): Boolean;
   public
   public
     { public declarations }
     { public declarations }
   end; 
   end; 
 
 
 var
 var
-  Form1: TForm1; 
+  formCDR2SVG: TformCDR2SVG;
 
 
 implementation
 implementation
 
 
 uses
 uses
-  fpvectorial, cdrvectorialreader, svgvectorialwriter;
+  fpvectorial, cdrvectorialreader, svgvectorialwriter, pdfvectorialreader,
+  fpvtocanvas;
 
 
 {$R *.lfm}
 {$R *.lfm}
 
 
-{ TForm1 }
+{ TformCDR2SVG }
 
 
-procedure TForm1.buttonQuitClick(Sender: TObject);
+procedure TformCDR2SVG.buttonQuitClick(Sender: TObject);
 begin
 begin
   Close;
   Close;
 end;
 end;
 
 
-procedure TForm1.buttonConvertClick(Sender: TObject);
+procedure TformCDR2SVG.buttonVisualizeClick(Sender: TObject);
 var
 var
   Vec: TvVectorialDocument;
   Vec: TvVectorialDocument;
 begin
 begin
   // First check the in input
   // First check the in input
+  if not CheckInput() then Exit;
+
+  Vec := TvVectorialDocument.Create;
+  try
+    Vec.ReadFromFile(editInput.FileName, vfPDF);
+    imagePreview.Canvas.Brush.Color := clWhite;
+    imagePreview.Canvas.FillRect(0, 0, imagePreview.Width, imagePreview.Height);
+    DrawFPVectorialToCanvas(Vec, imagePreview.Canvas, 0, 0, 0.25, 0.25);
+  finally
+    Vec.Free;
+  end;
+end;
+
+function TformCDR2SVG.CheckInput(): Boolean;
+begin
   // todo...
   // todo...
+end;
+
+procedure TformCDR2SVG.buttonConvertClick(Sender: TObject);
+var
+  Vec: TvVectorialDocument;
+begin
+  // First check the in input
+  if not CheckInput() then Exit;
 
 
   // Now convert
   // Now convert
   Vec := TvVectorialDocument.Create;
   Vec := TvVectorialDocument.Create;
   try
   try
     Vec.ReadFromFile(editInput.FileName, vfPDF);
     Vec.ReadFromFile(editInput.FileName, vfPDF);
-    Vec.WriteToFile(editOutPut.FileName, vfGCodeAvisoCNCPrototipoV5);
+    Vec.WriteToFile(editOutPut.FileName, vfSVG);
   finally
   finally
     Vec.Free;
     Vec.Free;
   end;
   end;

+ 8 - 2
packages/fpvectorial/examples/cdr2svg_visual.lpi

@@ -4,6 +4,9 @@
     <Version Value="9"/>
     <Version Value="9"/>
     <PathDelim Value="\"/>
     <PathDelim Value="\"/>
     <General>
     <General>
+      <Flags>
+        <AlwaysBuild Value="False"/>
+      </Flags>
       <SessionStorage Value="InProjectDir"/>
       <SessionStorage Value="InProjectDir"/>
       <Title Value="cdr2svg_visual"/>
       <Title Value="cdr2svg_visual"/>
       <UseXPManifest Value="True"/>
       <UseXPManifest Value="True"/>
@@ -39,7 +42,7 @@
       <Unit1>
       <Unit1>
         <Filename Value="cdr2svg_mainform.pas"/>
         <Filename Value="cdr2svg_mainform.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="Form1"/>
+        <ComponentName Value="formCDR2SVG"/>
         <ResourceBaseClass Value="Form"/>
         <ResourceBaseClass Value="Form"/>
         <UnitName Value="cdr2svg_mainform"/>
         <UnitName Value="cdr2svg_mainform"/>
       </Unit1>
       </Unit1>
@@ -70,7 +73,7 @@
     </Other>
     </Other>
   </CompilerOptions>
   </CompilerOptions>
   <Debugging>
   <Debugging>
-    <Exceptions Count="3">
+    <Exceptions Count="4">
       <Item1>
       <Item1>
         <Name Value="EAbort"/>
         <Name Value="EAbort"/>
       </Item1>
       </Item1>
@@ -80,6 +83,9 @@
       <Item3>
       <Item3>
         <Name Value="EFOpenError"/>
         <Name Value="EFOpenError"/>
       </Item3>
       </Item3>
+      <Item4>
+        <Name Value="EConvertError"/>
+      </Item4>
     </Exceptions>
     </Exceptions>
   </Debugging>
   </Debugging>
 </CONFIG>
 </CONFIG>

+ 1 - 1
packages/fpvectorial/examples/cdr2svg_visual.lpr

@@ -14,7 +14,7 @@ uses
 
 
 begin
 begin
   Application.Initialize;
   Application.Initialize;
-  Application.CreateForm(TForm1, Form1);
+  Application.CreateForm(TformCDR2SVG, formCDR2SVG);
   Application.Run;
   Application.Run;
 end.
 end.
 
 

+ 17 - 1
packages/fpvectorial/src/fpvectorial.pas

@@ -38,6 +38,11 @@ type
     st2DLine, st2DBezier,
     st2DLine, st2DBezier,
     st3DLine, st3DBezier);
     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
   TPathSegment = record
     SegmentType: TSegmentType;
     SegmentType: TSegmentType;
     X, Y, Z: Double; // Z is ignored in 2D segments
     X, Y, Z: Double; // Z is ignored in 2D segments
@@ -617,10 +622,21 @@ begin
   end;
   end;
 end;
 end;
 
 
+{@@
+  The default stream writer just uses WriteToStrings
+}
 procedure TvCustomVectorialWriter.WriteToStream(AStream: TStream;
 procedure TvCustomVectorialWriter.WriteToStream(AStream: TStream;
   AData: TvVectorialDocument);
   AData: TvVectorialDocument);
+var
+  lStringList: TStringList;
 begin
 begin
-
+  lStringList := TStringList.Create;
+  try
+    WriteToStrings(lStringList, AData);
+    lStringList.SaveToStream(AStream);
+  finally
+    lStringList.Free;
+  end;
 end;
 end;
 
 
 procedure TvCustomVectorialWriter.WriteToStrings(AStrings: TStrings;
 procedure TvCustomVectorialWriter.WriteToStrings(AStrings: TStrings;

+ 6 - 6
packages/fpvectorial/src/fpvtocanvas.pas

@@ -10,12 +10,12 @@ uses
   fpvectorial;
   fpvectorial;
 
 
 procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument; ADest: TFPCustomCanvas;
 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
 implementation
 
 
 procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument; ADest: TFPCustomCanvas;
 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
 var
   i, j, k: Integer;
   i, j, k: Integer;
   PosX, PosY: Integer; // Not modified by ADestX, etc
   PosX, PosY: Integer; // Not modified by ADestX, etc
@@ -47,8 +47,8 @@ begin
         PosX := Round(CurSegment.X);
         PosX := Round(CurSegment.X);
         PosY := Round(CurSegment.Y);
         PosY := Round(CurSegment.Y);
         ADest.LineTo(
         ADest.LineTo(
-          ADestX + AMulX * PosX,
-          ADestY + AMulY * PosY
+          Round(ADestX + AMulX * PosX),
+          Round(ADestY + AMulY * PosY)
           );
           );
       end;
       end;
       { To draw a bezier we need to divide the interval in parts and make
       { 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);
           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);
           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(
           ADest.LineTo(
-            ADestX + AMulX * CurX,
-            ADestY + AMulY * CurY);
+            Round(ADestX + AMulX * CurX),
+            Round(ADestY + AMulY * CurY));
         end;
         end;
         PosX := Round(CurSegment.X);
         PosX := Round(CurSegment.X);
         PosY := Round(CurSegment.Y);
         PosY := Round(CurSegment.Y);

+ 38 - 15
packages/fpvectorial/src/pdfvrsemantico.pas

@@ -8,11 +8,16 @@ uses
   Classes, SysUtils, pdfvrlexico, fpvectorial;
   Classes, SysUtils, pdfvrlexico, fpvectorial;
 
 
 type
 type
+
+  { AnSemantico }
+
   AnSemantico = class
   AnSemantico = class
   public
   public
+    FPointSeparator, FCommaSeparator: TFormatSettings;
     close_path_x: String;
     close_path_x: String;
     close_path_y: String;
     close_path_y: String;
     cm_a, cm_b, cm_c, cm_d, cm_e, cm_f: Real; // coordinate spaces constants
     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 generate(c: Command; AData: TvVectorialDocument): String;
     function convert(x: String; y: String; Axis: Char): String;
     function convert(x: String; y: String; Axis: Char): String;
     function startMachine(): String;
     function startMachine(): String;
@@ -22,6 +27,14 @@ type
 
 
 implementation
 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;
 function AnSemantico.generate(c: Command; AData: TvVectorialDocument): String;
 var
 var
   enter_line : String;
   enter_line : String;
@@ -29,6 +42,7 @@ begin
   {$ifdef FPVECTORIALDEBUG}
   {$ifdef FPVECTORIALDEBUG}
   WriteLn(':> AnSemantico.generate');
   WriteLn(':> AnSemantico.generate');
   {$endif}
   {$endif}
+
   enter_line:= LineEnding; //chr(13) + chr(10); // CR and LF
   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
   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
     // Correcao para programas de desenho que geram um novo inicio no
     // fim do desenho, terminamos qualquer desenho inacabado
     // fim do desenho, terminamos qualquer desenho inacabado
     AData.EndPath();
     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_x:=c.cord_x;
     close_path_y:=c.cord_y;
     close_path_y:=c.cord_y;
@@ -81,7 +95,7 @@ begin
     {$endif}
     {$endif}
     // Result:='G01' + ' ' + 'X' + c.cord_x + ' ' +  'Y' + c.cord_y;
     // 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;
   end;
   cc_h_CLOSE_PATH: // command h
   cc_h_CLOSE_PATH: // command h
   begin
   begin
@@ -90,7 +104,7 @@ begin
     {$endif}
     {$endif}
     //Result:='G01' + ' ' + 'X' + c.cord_x + ' ' +  'Y' + c.cord_y;
     //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;
   end;
   cc_S_END_PATH: // command S
   cc_S_END_PATH: // command S
   begin
   begin
@@ -108,7 +122,7 @@ begin
     //Result:='G01' + ' ' + 'X' + c.cord_x + ' ' +  'Y' + c.cord_y + enter_line
     //Result:='G01' + ' ' + 'X' + c.cord_x + ' ' +  'Y' + c.cord_y + enter_line
     //       +'G01 Z0 // Sobe a cabeça de gravação' + 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();
     AData.EndPath();
   end;
   end;
   cc_c_BEZIER_TO_X_Y_USING_X2_Y2_AND_X3_Y3: // command c
   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;
     //       +'G01 Z0 // Sobe a cabeça de gravação' + enter_line;
 
 
     AData.AddBezierToPath(
     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;
   end;
   cc_CONCATENATE_MATRIX: // command cm
   cc_CONCATENATE_MATRIX: // command cm
@@ -131,12 +145,12 @@ begin
     WriteLn(':> AnSemantico.cc_CONCATENATE_MATRIX');
     WriteLn(':> AnSemantico.cc_CONCATENATE_MATRIX');
     {$endif}
     {$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;
   end;
   cc_RESTORE_MATRIX: // command Q
   cc_RESTORE_MATRIX: // command Q
   begin
   begin
@@ -169,13 +183,13 @@ begin
   if (Axis = 'y') then
   if (Axis = 'y') then
   begin
   begin
        // y' = b * x + d * y + f
        // 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
   end
   else
   else
   // Axis = 'x'
   // Axis = 'x'
   begin
   begin
        // x' = a * x + c * y + e
        // 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;
 end;
 end;
 
 
@@ -209,12 +223,21 @@ end;
 constructor AnSemantico.Create;
 constructor AnSemantico.Create;
 begin
 begin
   inherited Create;
   inherited Create;
+
   cm_a:=1;
   cm_a:=1;
   cm_b:=0;
   cm_b:=0;
   cm_c:=0;
   cm_c:=0;
   cm_d:=1;
   cm_d:=1;
   cm_e:=0;
   cm_e:=0;
   cm_f:=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;
 
 
 end.
 end.

+ 85 - 2
packages/fpvectorial/src/svgvectorialwriter.pas

@@ -20,19 +20,102 @@ type
   { TvSVGVectorialWriter }
   { TvSVGVectorialWriter }
 
 
   TvSVGVectorialWriter = class(TvCustomVectorialWriter)
   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
   public
     { General reading methods }
     { General reading methods }
-    procedure WriteToStream(AStream: TStream; AData: TvVectorialDocument); virtual;
+    procedure WriteToStrings(AStrings: TStrings; AData: TvVectorialDocument); override;
   end;
   end;
 
 
 implementation
 implementation
 
 
 { TvSVGVectorialWriter }
 { 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);
   AData: TvVectorialDocument);
 begin
 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;
 end;
 
 
 initialization
 initialization