--- packages/fpvectorial/src/svgvectorialwriter.pas 2011/01/14 14:45:03 16765 +++ packages/fpvectorial/src/svgvectorialwriter.pas 2011/06/17 09:52:19 17765 @@ -13,7 +13,7 @@ interface uses - Classes, SysUtils, math, fpvectorial; + Classes, SysUtils, math, fpvectorial, fpvutils, fpcanvas; type { TvSVGVectorialWriter } @@ -23,8 +23,9 @@ FPointSeparator, FCommaSeparator: TFormatSettings; 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 WritePath(AIndex: Integer; APath: TPath; AStrings: TStrings; AData: TvVectorialDocument); + procedure WriteText(AStrings: TStrings; lText: TvText; AData: TvVectorialDocument); + procedure WriteEntities(AStrings: TStrings; AData: TvVectorialDocument); procedure ConvertFPVCoordinatesToSVGCoordinates( const AData: TvVectorialDocument; const ASrcX, ASrcY: Double; var ADestX, ADestY: double); @@ -74,90 +75,106 @@ SVG uses commas "," to separate the X,Y coordinates, so it always uses points "." 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 - i, j: Integer; + j: Integer; PathStr: string; - lPath: TPath; PtX, PtY, OldPtX, OldPtY: double; BezierCP1X, BezierCP1Y, BezierCP2X, BezierCP2Y: double; segment: TPathSegment; l2DSegment: T2DSegment absolute segment; l2DBSegment: T2DBezierSegment absolute segment; + // Pen properties + lPenWidth: Integer; + lPenColor: string; + // Brush properties + lFillColor: string; begin - for i := 0 to AData.GetPathCount() - 1 do - begin - OldPtX := 0; - OldPtY := 0; + OldPtX := 0; + OldPtY := 0; + PathStr := ''; - PathStr := ''; - lPath := AData.GetPath(i); - lPath.PrepareForSequentialReading; + APath.PrepareForSequentialReading(); - for j := 0 to lPath.Len - 1 do - begin - segment := TPathSegment(lPath.Next()); + for j := 0 to APath.Len - 1 do + begin + segment := TPathSegment(APath.Next()); + + if (segment.SegmentType <> st2DLine) + and (segment.SegmentType <> stMoveTo) + and (segment.SegmentType <> st2DBezier) + then Break; // unsupported line type - if (segment.SegmentType <> st2DLine) - and (segment.SegmentType <> stMoveTo) - and (segment.SegmentType <> st2DBezier) - then Break; // unsupported line type + // Coordinate conversion from fpvectorial to SVG + ConvertFPVCoordinatesToSVGCoordinates( + AData, l2DSegment.X, l2DSegment.Y, PtX, PtY); + PtX := PtX - OldPtX; + PtY := PtY - OldPtY; - // Coordinate conversion from fpvectorial to SVG + if (segment.SegmentType = stMoveTo) then + begin + PathStr := PathStr + 'm ' + + FloatToStr(PtX, FPointSeparator) + ',' + + FloatToStr(PtY, FPointSeparator) + ' '; + 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, l2DSegment.X, l2DSegment.Y, PtX, PtY); - PtX := PtX - OldPtX; - PtY := PtY - OldPtY; - - if (segment.SegmentType = stMoveTo) then - begin - PathStr := PathStr + 'm ' - + FloatToStr(PtX, FPointSeparator) + ',' - + FloatToStr(PtY, FPointSeparator) + ' '; - 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 - 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 ' - + FloatToStr(BezierCP1X, FPointSeparator) + ',' - + FloatToStr(BezierCP1Y, FPointSeparator) + ' ' - + FloatToStr(BezierCP2X, FPointSeparator) + ',' - + FloatToStr(BezierCP2Y, FPointSeparator) + ' ' - + FloatToStr(PtX, FPointSeparator) + ',' - + FloatToStr(PtY, FPointSeparator) + ' ' - ; - end; - - // Store the current position for future points - OldPtX := OldPtX + PtX; - OldPtY := OldPtY + PtY; + AData, l2DBSegment.X2, l2DBSegment.Y2, BezierCP1X, BezierCP1Y); + ConvertFPVCoordinatesToSVGCoordinates( + AData, l2DBSegment.X3, l2DBSegment.Y3, BezierCP2X, BezierCP2Y); + + // Transforms them into values relative to the initial 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 ' + + FloatToStr(BezierCP1X, FPointSeparator) + ',' + + FloatToStr(BezierCP1Y, FPointSeparator) + ' ' + + FloatToStr(BezierCP2X, FPointSeparator) + ',' + + FloatToStr(BezierCP2Y, FPointSeparator) + ' ' + + FloatToStr(PtX, FPointSeparator) + ',' + + FloatToStr(PtY, FPointSeparator) + ' ' + ; end; - AStrings.Add(' '); + // Store the current position for future points + OldPtX := OldPtX + PtX; + OldPtY := OldPtY + PtY; end; + + // Get the Pen Width + if APath.Pen.Width >= 1 then lPenWidth := APath.Pen.Width + else lPenWidth := 1; + + // Get the Pen Color and Style + if APath.Pen.Style = psClear then lPenColor := 'none' + else lPenColor := '#' + FPColorToRGBHexString(APath.Pen.Color); + + // Get the Brush color and style + if APath.Brush.Style = bsClear then lFillColor := 'none' + else lFillColor := '#' + FPColorToRGBHexString(APath.Brush.Color); + + // Now effectively write the path + AStrings.Add(' '); end; procedure TvSVGVectorialWriter.ConvertFPVCoordinatesToSVGCoordinates( @@ -197,43 +214,52 @@ // Now data AStrings.Add(' '); - WritePaths(AStrings, AData); - WriteTexts(AStrings, AData); + WriteEntities(AStrings, AData); AStrings.Add(' '); // finalization AStrings.Add(''); end; -procedure TvSVGVectorialWriter.WriteTexts(AStrings: TStrings; AData: TvVectorialDocument); +procedure TvSVGVectorialWriter.WriteText(AStrings: TStrings; lText: TvText; AData: TvVectorialDocument); var i, j, FontSize: Integer; TextStr, FontName, SVGFontFamily: string; - lText: TvText; PtX, PtY: double; begin - for i := 0 to AData.GetTextCount() - 1 do - begin - TextStr := ''; - lText := AData.GetText(i); + TextStr := ''; - ConvertFPVCoordinatesToSVGCoordinates( - AData, lText.X, lText.Y, PtX, PtY); + ConvertFPVCoordinatesToSVGCoordinates( + AData, lText.X, lText.Y, PtX, PtY); - TextStr := lText.Value; - FontSize:= ceil(lText.FontSize / FLOAT_MILIMETERS_PER_PIXEL); - SVGFontFamily := 'Arial, sans-serif';//lText.FontName; - - AStrings.Add(' '); - AStrings.Add(' '); + AStrings.Add(' '); - AStrings.Add(TextStr + ''); + AStrings.Add(' >'); + AStrings.Add(TextStr + ''); +end; + +procedure TvSVGVectorialWriter.WriteEntities(AStrings: TStrings; + AData: TvVectorialDocument); +var + lEntity: TvEntity; + i: Integer; +begin + for i := 0 to AData.GetEntitiesCount() - 1 do + begin + lEntity := AData.GetEntity(i); + + if lEntity is TPath then WritePath(i, TPath(lEntity), AStrings, AData) + else if lEntity is TvText then WriteText(AStrings, TvText(lEntity), AData); end; end;