Explorar o código

Patch from JiXian, advances the implementation of text rendering and bezier drawing for the svg writer in fpvectorial

git-svn-id: trunk@15923 -
sekelsenmat %!s(int64=15) %!d(string=hai) anos
pai
achega
c2270697a8

+ 37 - 16
packages/fpvectorial/src/fpvectorial.pas

@@ -41,7 +41,7 @@ const
 type
   TSegmentType = (
     st2DLine, st2DBezier,
-    st3DLine, st3DBezier);
+    st3DLine, st3DBezier, stMoveTo);
 
   {@@
     The coordinates in fpvectorial are given in millimiters and
@@ -69,8 +69,12 @@ type
     At the moment fonts are unsupported, only simple texts
     up to 255 chars are supported.
   }
+
   TvText = record
-    Value: array[0..255] of Char;
+    X, Y, Z: Double; // Z is ignored in 2D formats
+    FontSize: integer;
+    FontName: utf8string;
+    Value: utf8string;
   end;
 
   PText = ^TvText;
@@ -87,6 +91,7 @@ type
     FPaths: TFPList;
     FTexts: TFPList;
     FTmpPath: TPath;
+    FTmpText: TvText;
     procedure RemoveCallback(data, arg: pointer);
     function CreateVectorialWriter(AFormat: TvVectorialFormat): TvCustomVectorialWriter;
     function CreateVectorialReader(AFormat: TvVectorialFormat): TvCustomVectorialReader;
@@ -121,8 +126,8 @@ type
     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(AText: TvText); overload;
-    procedure AddText(AStr: utf8string); overload;
+    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;
@@ -338,7 +343,7 @@ end;
 procedure TvVectorialDocument.StartPath(AX, AY: Double);
 begin
   FTmpPath.Len := 1;
-  FTmpPath.Points[0].SegmentType := st2DLine;
+  FTmpPath.Points[0].SegmentType := stMoveTo;
   FTmpPath.Points[0].X := AX;
   FTmpPath.Points[0].Y := AY;
 end;
@@ -394,8 +399,21 @@ end;
 
 procedure TvVectorialDocument.AddBezierToPath(AX1, AY1, AZ1, AX2, AY2, AZ2,
   AX3, AY3, AZ3: Double);
+var
+  L: Integer;
 begin
-
+  L := FTmPPath.Len;
+  Inc(FTmPPath.Len);
+  FTmPPath.Points[L].SegmentType := st3DBezier;
+  FTmPPath.Points[L].X := AX3;
+  FTmPPath.Points[L].Y := AY3;
+  FTmPPath.Points[L].Z := AZ3;
+  FTmPPath.Points[L].X2 := AX1;
+  FTmPPath.Points[L].Y2 := AY1;
+  FTmPPath.Points[L].Z2 := AZ1;
+  FTmPPath.Points[L].X3 := AX2;
+  FTmPPath.Points[L].Y3 := AY2;
+  FTmPPath.Points[L].Z3 := AZ2;
 end;
 
 {@@
@@ -415,23 +433,26 @@ begin
   FTmPPath.Len := 0;
 end;
 
-procedure TvVectorialDocument.AddText(AText: TvText);
+procedure TvVectorialDocument.AddText(AX, AY, AZ: Double; FontName: string; FontSize: integer; AText: utf8string);
 var
   lText: PText;
-  Len: Integer;
 begin
-  Len := SizeOf(TvText);
-  lText := GetMem(Len);
-  Move(AText, lText^, Len);
+  lText := GetMem(SizeOf(TvText));
+  SetLength(lText.Value, Length(AText));
+  Move(AText[1], lText.Value[1], Length(AText));
+  lText.X:=AX;
+  lText.Y:=AY;
+  lText.Z:=AZ;
+  //lText.FontName:=FontName;
+  SetLength(lText.FontName, Length(FontName));
+  Move(FontName[1], lText.FontName[1], Length(FontName));
+  lText.FontSize:=FontSize;
   FTexts.Add(lText);
 end;
 
-procedure TvVectorialDocument.AddText(AStr: utf8string);
-var
-  lText: TvText;
+procedure TvVectorialDocument.AddText(AX, AY, AZ: Double; AStr: utf8string);
 begin
-  lText.Value := AStr;
-  AddText(lText);
+  AddText(AX, AY, AZ, 'Arial', 10, AStr);
 end;
 
 {@@

+ 126 - 4
packages/fpvectorial/src/svgvectorialwriter.pas

@@ -13,8 +13,7 @@ unit svgvectorialwriter;
 interface
 
 uses
-  Classes, SysUtils,
-  fpvectorial;
+  Classes, SysUtils, math, fpvectorial;
 
 type
   { TvSVGVectorialWriter }
@@ -25,6 +24,8 @@ type
     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 WriteBeziers(AStrings: TStrings; AData: TvVectorialDocument);
     procedure ConvertFPVCoordinatesToSVGCoordinates(
       const AData: TvVectorialDocument;
       const ASrcX, ASrcY: Double; var ADestX, ADestY: double);
@@ -81,8 +82,13 @@ begin
     lPath := AData.GetPath(i);
     for j := 0 to lPath.Len - 1 do
     begin
-      if lPath.Points[j].SegmentType <> st2DLine then Break; // unsupported line type
-
+      if (lPath.Points[j].SegmentType <> st2DLine)
+        and (lPath.Points[j].SegmentType <> stMoveTo)
+        then Break; // unsupported line type
+//      PtX := lPath.Points[j].X;
+//      PtY := lPath.Points[j].Y;
+//      PathStr := PathStr + FloatToStr(PtX, FPointSeparator) + ','  // + 'mm,'
+//        + FloatToStr(PtY, FPointSeparator) + ' '; // + 'mm ';
       // Coordinate conversion from fpvectorial to SVG
       ConvertFPVCoordinatesToSVGCoordinates(
         AData, lPath.Points[j].X, lPath.Points[j].Y, PtX, PtY);
@@ -142,12 +148,128 @@ begin
   // Now data
   AStrings.Add('  <g id="layer1">');
   WritePaths(AStrings, AData);
+  WriteTexts(AStrings, AData);
+  WriteBeziers(AStrings, AData);
   AStrings.Add('  </g>');
 
   // finalization
   AStrings.Add('</svg>');
 end;
 
+procedure TvSVGVectorialWriter.WriteTexts(AStrings: TStrings; AData: TvVectorialDocument);
+var
+  i, j, FontSize: Integer;
+  TextStr, FontName: string;
+  ltest: TvText;
+  PtX, PtY: double;
+begin
+  for i := 0 to AData.GetTextCount() - 1 do
+  begin
+    TextStr := '';
+    ltest := AData.GetText(i);
+    //PtX := ltest.X;
+    //PtY := ltest.Y;
+    ConvertFPVCoordinatesToSVGCoordinates(
+        AData, ltest.X, ltest.Y, PtX, PtY);
+    TextStr := ltest.Value;
+    FontSize:= ceil(ltest.FontSize / FLOAT_MILIMETERS_PER_PIXEL);
+    FontName:=ltest.FontName;
+    AStrings.Add('  <text');
+    AStrings.Add('    style="font-size:'
+    +IntToStr(FontSize)+'px;font-style:normal;font-weight:normal;line-height:125%;'
+    +'letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;'
+    +'font-family:'+FontName+'"><tspan');
+    AStrings.Add('     x="' + FloatToStr(PtX, FPointSeparator) + '"');
+    AStrings.Add('     y="' + FloatToStr(PtY, FPointSeparator) + '"');
+    AStrings.Add('     id="tspan3071">' + TextStr + '</tspan></text>');
+  end;
+end;
+
+procedure TvSVGVectorialWriter.WriteBeziers(AStrings: TStrings; AData: TvVectorialDocument);
+var
+  i, j: Integer;
+  PathStr: string;
+  lPath: TPath;
+  PtX, PtY, OldPtX, OldPtY, PtX2, PtY2, OldPtX2, OldPtY2,
+    PtX3, PtY3, OldPtX3, OldPtY3: double;
+  BezierType: TSegmentType;
+begin
+  for i := 0 to AData.GetPathCount() - 1 do
+  begin
+    OldPtX  := 0;
+    OldPtY  := 0;
+    OldPtX2 := 0;
+    OldPtY2 := 0;
+    OldPtX3 := 0;
+    OldPtY3 := 0;
+
+    PathStr := 'm ';
+    lPath   := AData.GetPath(i);
+    for j := 0 to lPath.Len - 1 do
+    begin
+      BezierType := lPath.Points[j].SegmentType;
+      if j>0 then
+      if (BezierType <> st2DBezier) and (BezierType <> st3DBezier)
+        and (BezierType<> st2DLine)
+      then Break; // unsupported Bezier type
+
+      //ConvertFPVCoordinatesToSVGCoordinates(
+      //  AData, lPath.Points[j].X, lPath.Points[j].Y, PtX, PtY);
+
+      if (BezierType = st2DBezier) or (BezierType = stMoveTo) then
+      begin
+      PtX  := lPath.Points[j].X / FLOAT_MILIMETERS_PER_PIXEL;
+      PtY  := (AData.Height - lPath.Points[j].Y) / FLOAT_MILIMETERS_PER_PIXEL;
+      PtX2 := lPath.Points[j].X2 / FLOAT_MILIMETERS_PER_PIXEL;
+      PtY2 := (AData.Height - lPath.Points[j].Y2) / FLOAT_MILIMETERS_PER_PIXEL;
+      PtX3 := lPath.Points[j].X3 / FLOAT_MILIMETERS_PER_PIXEL;
+      PtY3 := (AData.Height - lPath.Points[j].Y3) / FLOAT_MILIMETERS_PER_PIXEL;
+
+      PtX  := PtX - OldPtX;
+      PtY  := PtY - OldPtY;
+      PtX2 := PtX2 - OldPtX2;
+      PtY2 := PtY2 - OldPtY2;
+      PtX3 := PtX3 - OldPtX3;
+      PtY3 := PtY3 - OldPtY3;
+
+      if j = 0 then
+        PathStr := PathStr + FloatToStr(PtX, FPointSeparator) + ','
+          + FloatToStr(PtY, FPointSeparator) + ' ';
+
+      if j = 0 then
+      begin
+ //       if BezierType = st2DBezier then
+          PathStr := PathStr + 'q';
+        if BezierType = st3DBezier then
+          PathStr := PathStr + 'c';
+      end;
+
+      if j > 0 then
+        PathStr := PathStr + FloatToStr(PtX, FPointSeparator) + ','
+          + FloatToStr(PtY, FPointSeparator) + ' '
+          + FloatToStr(PtX2, FPointSeparator) + ','
+          + FloatToStr(PtY2, FPointSeparator) + ' '
+          + FloatToStr(PtX3, FPointSeparator) + ','
+          + FloatToStr(PtY3, FPointSeparator) + ' ';
+
+      // Store the current position for future points
+      OldPtX  := OldPtX + PtX;
+      OldPtY  := OldPtY + PtY;
+      OldPtX2 := OldPtX2 + PtX2;
+      OldPtY2 := OldPtY2 + PtY2;
+      OldPtX3 := OldPtX3 + PtX3;
+      OldPtY3 := OldPtY3 + PtY3;
+    end;
+
+    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="Bezier' + IntToStr(i) + '" />');
+  end;
+end;
+
 initialization
 
   RegisterVectorialWriter(TvSVGVectorialWriter, vfSVG);