fpvectorial: Merging improvements to svg output from fpc trunk

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1602 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
sekelsenmat
2011-04-29 11:32:53 +00:00
parent e9d6964f96
commit b158b15f34
4 changed files with 143 additions and 74 deletions

View File

@ -1130,6 +1130,8 @@ begin
Points := APath.Points; Points := APath.Points;
PointsEnd := APath.PointsEnd; PointsEnd := APath.PointsEnd;
CurPoint := APath.CurPoint; CurPoint := APath.CurPoint;
Pen := APath.Pen;
Brush := APath.Brush;
end; end;
function TPath.Count(): TPathSegment; function TPath.Count(): TPathSegment;

View File

@ -42,14 +42,6 @@ begin
end; end;
{$endif} {$endif}
function VColorToFPColor(AVColor: TvColor): TFPColor; inline;
begin
Result.Red := AVColor.Red;
Result.Green := AVColor.Green;
Result.Blue := AVColor.Blue;
Result.Alpha := AVColor.Alpha;
end;
function Rotate2DPoint(P,Fix :TPoint; alpha:double): TPoint; function Rotate2DPoint(P,Fix :TPoint; alpha:double): TPoint;
var var
sinus, cosinus : Extended; sinus, cosinus : Extended;

View File

@ -0,0 +1,53 @@
{
fpvutils.pas
Vector graphics document
License: The same modified LGPL as the Free Pascal RTL
See the file COPYING.modifiedLGPL for more details
AUTHORS: Felipe Monteiro de Carvalho
Pedro Sol Pegorini L de Lima
}
unit fpvutils;
{$ifdef fpc}
{$mode delphi}
{$endif}
interface
uses
Classes, SysUtils, Math,
fpvectorial, fpimage;
// Color Conversion routines
function VColorToFPColor(AVColor: TvColor): TFPColor; inline;
function VColorToRGBHexString(AVColor: TvColor): string;
function RGBToVColor(AR, AG, AB: Byte): TvColor; inline;
implementation
function VColorToFPColor(AVColor: TvColor): TFPColor; inline;
begin
Result.Red := AVColor.Red;
Result.Green := AVColor.Green;
Result.Blue := AVColor.Blue;
Result.Alpha := AVColor.Alpha;
end;
function VColorToRGBHexString(AVColor: TvColor): string;
begin
Result := Format('%.2x%.2x%.2x', [AVColor.Red, AVColor.Green, AVColor.Blue]);
end;
function RGBToVColor(AR, AG, AB: Byte): TvColor; inline;
begin
Result.Red := AR;
Result.Green := AG;
Result.Blue := AB;
Result.Alpha := 255;
end;
end.

View File

@ -13,7 +13,7 @@ unit svgvectorialwriter;
interface interface
uses uses
Classes, SysUtils, math, fpvectorial; Classes, SysUtils, math, fpvectorial, fpvutils;
type type
{ TvSVGVectorialWriter } { TvSVGVectorialWriter }
@ -24,6 +24,7 @@ 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 WritePath(AIndex: Integer; APath: TPath; AStrings: TStrings; AData: TvVectorialDocument);
procedure WriteTexts(AStrings: TStrings; AData: TvVectorialDocument); procedure WriteTexts(AStrings: TStrings; AData: TvVectorialDocument);
procedure ConvertFPVCoordinatesToSVGCoordinates( procedure ConvertFPVCoordinatesToSVGCoordinates(
const AData: TvVectorialDocument; const AData: TvVectorialDocument;
@ -60,6 +61,19 @@ begin
AStrings.Add(' sodipodi:docname="New document 1">'); AStrings.Add(' sodipodi:docname="New document 1">');
end; end;
procedure TvSVGVectorialWriter.WritePaths(AStrings: TStrings; AData: TvVectorialDocument);
var
i: Integer;
lPath: TPath;
begin
for i := 0 to AData.GetPathCount() - 1 do
begin
lPath := AData.GetPath(i);
lPath.PrepareForSequentialReading;
WritePath(i ,lPath, AStrings, AData);
end;
end;
{@@ {@@
SVG Coordinate system measures things only in pixels, so that we have to SVG Coordinate system measures things only in pixels, so that we have to
hardcode a DPI value for the screen, which is usually 72. hardcode a DPI value for the screen, which is usually 72.
@ -74,90 +88,98 @@ end;
SVG uses commas "," to separate the X,Y coordinates, so it always uses points SVG uses commas "," to separate the X,Y coordinates, so it always uses points
"." as decimal separators and uses no thousand separators "." as decimal separators and uses no thousand separators
} }
procedure TvSVGVectorialWriter.WritePaths(AStrings: TStrings; AData: TvVectorialDocument); procedure TvSVGVectorialWriter.WritePath(AIndex: Integer; APath: TPath; AStrings: TStrings;
AData: TvVectorialDocument);
var var
i, j: Integer; j: Integer;
PathStr: string; PathStr: string;
lPath: TPath;
PtX, PtY, OldPtX, OldPtY: double; PtX, PtY, OldPtX, OldPtY: double;
BezierCP1X, BezierCP1Y, BezierCP2X, BezierCP2Y: double; BezierCP1X, BezierCP1Y, BezierCP2X, BezierCP2Y: double;
segment: TPathSegment; segment: TPathSegment;
l2DSegment: T2DSegment absolute segment; l2DSegment: T2DSegment absolute segment;
l2DBSegment: T2DBezierSegment absolute segment; l2DBSegment: T2DBezierSegment absolute segment;
// Pen properties
lPenWidth: Integer;
lPenColor: string;
begin begin
for i := 0 to AData.GetPathCount() - 1 do OldPtX := 0;
OldPtY := 0;
PathStr := '';
APath.PrepareForSequentialReading();
for j := 0 to APath.Len - 1 do
begin begin
OldPtX := 0; segment := TPathSegment(APath.Next());
OldPtY := 0;
PathStr := ''; if (segment.SegmentType <> st2DLine)
lPath := AData.GetPath(i); and (segment.SegmentType <> stMoveTo)
lPath.PrepareForSequentialReading; and (segment.SegmentType <> st2DBezier)
then Break; // unsupported line type
for j := 0 to lPath.Len - 1 do // Coordinate conversion from fpvectorial to SVG
ConvertFPVCoordinatesToSVGCoordinates(
AData, l2DSegment.X, l2DSegment.Y, PtX, PtY);
PtX := PtX - OldPtX;
PtY := PtY - OldPtY;
if (segment.SegmentType = stMoveTo) then
begin begin
segment := TPathSegment(lPath.Next()); PathStr := PathStr + 'm '
+ FloatToStr(PtX, FPointSeparator) + ','
if (segment.SegmentType <> st2DLine) + FloatToStr(PtY, FPointSeparator) + ' ';
and (segment.SegmentType <> stMoveTo) end
and (segment.SegmentType <> st2DBezier) else if (segment.SegmentType = st2DLine) then
then Break; // unsupported line type begin
PathStr := PathStr + 'l '
// Coordinate conversion from fpvectorial to SVG + FloatToStr(PtX, FPointSeparator) + ','
+ FloatToStr(PtY, FPointSeparator) + ' ';
end
else if (segment.SegmentType = st2DBezier) then
begin
// Converts all coordinates to absolute values
ConvertFPVCoordinatesToSVGCoordinates( ConvertFPVCoordinatesToSVGCoordinates(
AData, l2DSegment.X, l2DSegment.Y, PtX, PtY); AData, l2DBSegment.X2, l2DBSegment.Y2, BezierCP1X, BezierCP1Y);
PtX := PtX - OldPtX; ConvertFPVCoordinatesToSVGCoordinates(
PtY := PtY - OldPtY; AData, l2DBSegment.X3, l2DBSegment.Y3, BezierCP2X, BezierCP2Y);
if (segment.SegmentType = stMoveTo) then // Transforms them into values relative to the initial point
begin BezierCP1X := BezierCP1X - OldPtX;
PathStr := PathStr + 'm ' BezierCP1Y := BezierCP1Y - OldPtY;
+ FloatToStr(PtX, FPointSeparator) + ',' BezierCP2X := BezierCP2X - OldPtX;
+ FloatToStr(PtY, FPointSeparator) + ' '; BezierCP2Y := BezierCP2Y - OldPtY;
end
else if (segment.SegmentType = st2DLine) then
begin
PathStr := PathStr + 'l '
+ FloatToStr(PtX, FPointSeparator) + ','
+ FloatToStr(PtY, FPointSeparator) + ' ';
end
else if (segment.SegmentType = st2DBezier) then
begin
// Converts all coordinates to absolute values
ConvertFPVCoordinatesToSVGCoordinates(
AData, l2DBSegment.X2, l2DBSegment.Y2, BezierCP1X, BezierCP1Y);
ConvertFPVCoordinatesToSVGCoordinates(
AData, l2DBSegment.X3, l2DBSegment.Y3, BezierCP2X, BezierCP2Y);
// Transforms them into values relative to the initial point // PtX and PtY already contains the destination point
BezierCP1X := BezierCP1X - OldPtX;
BezierCP1Y := BezierCP1Y - OldPtY;
BezierCP2X := BezierCP2X - OldPtX;
BezierCP2Y := BezierCP2Y - OldPtY;
// PtX and PtY already contains the destination point // Now render our 2D cubic bezier
PathStr := PathStr + 'c '
// Now render our 2D cubic bezier + FloatToStr(BezierCP1X, FPointSeparator) + ','
PathStr := PathStr + 'c ' + FloatToStr(BezierCP1Y, FPointSeparator) + ' '
+ FloatToStr(BezierCP1X, FPointSeparator) + ',' + FloatToStr(BezierCP2X, FPointSeparator) + ','
+ FloatToStr(BezierCP1Y, FPointSeparator) + ' ' + FloatToStr(BezierCP2Y, FPointSeparator) + ' '
+ FloatToStr(BezierCP2X, FPointSeparator) + ',' + FloatToStr(PtX, FPointSeparator) + ','
+ FloatToStr(BezierCP2Y, FPointSeparator) + ' ' + FloatToStr(PtY, FPointSeparator) + ' '
+ FloatToStr(PtX, FPointSeparator) + ',' ;
+ FloatToStr(PtY, FPointSeparator) + ' '
;
end;
// Store the current position for future points
OldPtX := OldPtX + PtX;
OldPtY := OldPtY + PtY;
end; end;
AStrings.Add(' <path'); // Store the current position for future points
AStrings.Add(' style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"'); OldPtX := OldPtX + PtX;
AStrings.Add(' d="' + PathStr + '"'); OldPtY := OldPtY + PtY;
AStrings.Add(' id="path' + IntToStr(i) + '" />');
end; end;
// Get the Pen Width
if APath.Pen.Width >= 1 then lPenWidth := APath.Pen.Width
else lPenWidth := 1;
// Get the Pen Color
lPenColor := VColorToRGBHexString(APath.Pen.Color);
AStrings.Add(' <path');
AStrings.Add(Format(' style="fill:none;stroke:#%s;stroke-width:%dpx;'
+ 'stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"',
[lPenColor, lPenWidth]));
AStrings.Add(' d="' + PathStr + '"');
AStrings.Add(' id="path' + IntToStr(AIndex) + '" />');
end; end;
procedure TvSVGVectorialWriter.ConvertFPVCoordinatesToSVGCoordinates( procedure TvSVGVectorialWriter.ConvertFPVCoordinatesToSVGCoordinates(