mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-10 09:29:13 +02:00
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:
parent
0083fc3e3d
commit
c2270697a8
@ -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;
|
||||
|
||||
{@@
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user