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

git-svn-id: trunk@15923 -
This commit is contained in:
sekelsenmat 2010-08-31 09:48:27 +00:00
parent 0083fc3e3d
commit c2270697a8
2 changed files with 163 additions and 20 deletions

View File

@ -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;
{@@

View File

@ -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);