Browse Source

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

git-svn-id: trunk@15923 -
sekelsenmat 15 years ago
parent
commit
c2270697a8

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

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

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

@@ -13,8 +13,7 @@ unit svgvectorialwriter;
 interface
 interface
 
 
 uses
 uses
-  Classes, SysUtils,
-  fpvectorial;
+  Classes, SysUtils, math, fpvectorial;
 
 
 type
 type
   { TvSVGVectorialWriter }
   { TvSVGVectorialWriter }
@@ -25,6 +24,8 @@ type
     procedure WriteDocumentSize(AStrings: TStrings; AData: TvVectorialDocument);
     procedure WriteDocumentSize(AStrings: TStrings; AData: TvVectorialDocument);
     procedure WriteDocumentName(AStrings: TStrings; AData: TvVectorialDocument);
     procedure WriteDocumentName(AStrings: TStrings; AData: TvVectorialDocument);
     procedure WritePaths(AStrings: TStrings; AData: TvVectorialDocument);
     procedure WritePaths(AStrings: TStrings; AData: TvVectorialDocument);
+    procedure WriteTexts(AStrings: TStrings; AData: TvVectorialDocument);
+    procedure WriteBeziers(AStrings: TStrings; AData: TvVectorialDocument);
     procedure ConvertFPVCoordinatesToSVGCoordinates(
     procedure ConvertFPVCoordinatesToSVGCoordinates(
       const AData: TvVectorialDocument;
       const AData: TvVectorialDocument;
       const ASrcX, ASrcY: Double; var ADestX, ADestY: double);
       const ASrcX, ASrcY: Double; var ADestX, ADestY: double);
@@ -81,8 +82,13 @@ begin
     lPath := AData.GetPath(i);
     lPath := AData.GetPath(i);
     for j := 0 to lPath.Len - 1 do
     for j := 0 to lPath.Len - 1 do
     begin
     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
       // Coordinate conversion from fpvectorial to SVG
       ConvertFPVCoordinatesToSVGCoordinates(
       ConvertFPVCoordinatesToSVGCoordinates(
         AData, lPath.Points[j].X, lPath.Points[j].Y, PtX, PtY);
         AData, lPath.Points[j].X, lPath.Points[j].Y, PtX, PtY);
@@ -142,12 +148,128 @@ begin
   // Now data
   // Now data
   AStrings.Add('  <g id="layer1">');
   AStrings.Add('  <g id="layer1">');
   WritePaths(AStrings, AData);
   WritePaths(AStrings, AData);
+  WriteTexts(AStrings, AData);
+  WriteBeziers(AStrings, AData);
   AStrings.Add('  </g>');
   AStrings.Add('  </g>');
 
 
   // finalization
   // finalization
   AStrings.Add('</svg>');
   AStrings.Add('</svg>');
 end;
 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
 initialization
 
 
   RegisterVectorialWriter(TvSVGVectorialWriter, vfSVG);
   RegisterVectorialWriter(TvSVGVectorialWriter, vfSVG);