diff options
| author | sekelsenmat <sekelsenmat@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2010-08-13 14:56:40 +0000 |
|---|---|---|
| committer | sekelsenmat <sekelsenmat@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2010-08-13 14:56:40 +0000 |
| commit | 37673c6306f946288b0638275f9ca29100b3d37b (patch) | |
| tree | 372c4530c19fab97a645ab20bc332525d7609f91 /packages/fpvectorial/src | |
| parent | ae46f170027155df1b81b8f76259aa2646570c47 (diff) | |
| download | fpc-37673c6306f946288b0638275f9ca29100b3d37b.tar.gz | |
Starts implementing svg writer and improves test app and pdf reader
git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@15799 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'packages/fpvectorial/src')
| -rw-r--r-- | packages/fpvectorial/src/fpvectorial.pas | 18 | ||||
| -rw-r--r-- | packages/fpvectorial/src/fpvtocanvas.pas | 12 | ||||
| -rw-r--r-- | packages/fpvectorial/src/pdfvrsemantico.pas | 53 | ||||
| -rw-r--r-- | packages/fpvectorial/src/svgvectorialwriter.pas | 87 |
4 files changed, 146 insertions, 24 deletions
diff --git a/packages/fpvectorial/src/fpvectorial.pas b/packages/fpvectorial/src/fpvectorial.pas index 0b18f768d5..d2a50a2a9d 100644 --- a/packages/fpvectorial/src/fpvectorial.pas +++ b/packages/fpvectorial/src/fpvectorial.pas @@ -38,6 +38,11 @@ type st2DLine, st2DBezier, st3DLine, st3DBezier); + {@ + The coordinates in fpvectorial are given in millimiters and + the starting point is in the top-left corner of the document + and it grows to the bottom and to the right. + } TPathSegment = record SegmentType: TSegmentType; X, Y, Z: Double; // Z is ignored in 2D segments @@ -617,10 +622,21 @@ begin end; end; +{@@ + The default stream writer just uses WriteToStrings +} procedure TvCustomVectorialWriter.WriteToStream(AStream: TStream; AData: TvVectorialDocument); +var + lStringList: TStringList; begin - + lStringList := TStringList.Create; + try + WriteToStrings(lStringList, AData); + lStringList.SaveToStream(AStream); + finally + lStringList.Free; + end; end; procedure TvCustomVectorialWriter.WriteToStrings(AStrings: TStrings; diff --git a/packages/fpvectorial/src/fpvtocanvas.pas b/packages/fpvectorial/src/fpvtocanvas.pas index c7b5ff1a4a..a75c7dc8bf 100644 --- a/packages/fpvectorial/src/fpvtocanvas.pas +++ b/packages/fpvectorial/src/fpvtocanvas.pas @@ -10,12 +10,12 @@ uses fpvectorial; procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument; ADest: TFPCustomCanvas; - ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Integer = 1; AMulY: Integer = 1); + ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0); implementation procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument; ADest: TFPCustomCanvas; - ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Integer = 1; AMulY: Integer = 1); + ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0); var i, j, k: Integer; PosX, PosY: Integer; // Not modified by ADestX, etc @@ -47,8 +47,8 @@ begin PosX := Round(CurSegment.X); PosY := Round(CurSegment.Y); ADest.LineTo( - ADestX + AMulX * PosX, - ADestY + AMulY * PosY + Round(ADestX + AMulX * PosX), + Round(ADestY + AMulY * PosY) ); end; { To draw a bezier we need to divide the interval in parts and make @@ -66,8 +66,8 @@ begin CurX := Round(sqr(1 - t) * (1 - t) * PosX + 3 * t * sqr(1 - t) * CurSegment.X2 + 3 * t * t * (1 - t) * CurSegment.X3 + t * t * t * CurSegment.X); CurY := Round(sqr(1 - t) * (1 - t) * PosY + 3 * t * sqr(1 - t) * CurSegment.Y2 + 3 * t * t * (1 - t) * CurSegment.Y3 + t * t * t * CurSegment.Y); ADest.LineTo( - ADestX + AMulX * CurX, - ADestY + AMulY * CurY); + Round(ADestX + AMulX * CurX), + Round(ADestY + AMulY * CurY)); end; PosX := Round(CurSegment.X); PosY := Round(CurSegment.Y); diff --git a/packages/fpvectorial/src/pdfvrsemantico.pas b/packages/fpvectorial/src/pdfvrsemantico.pas index 421e0d6175..bf2c80edfe 100644 --- a/packages/fpvectorial/src/pdfvrsemantico.pas +++ b/packages/fpvectorial/src/pdfvrsemantico.pas @@ -8,11 +8,16 @@ uses Classes, SysUtils, pdfvrlexico, fpvectorial; type + + { AnSemantico } + AnSemantico = class public + FPointSeparator, FCommaSeparator: TFormatSettings; close_path_x: String; close_path_y: String; cm_a, cm_b, cm_c, cm_d, cm_e, cm_f: Real; // coordinate spaces constants + function StringToFloat(AStr: string): Double; function generate(c: Command; AData: TvVectorialDocument): String; function convert(x: String; y: String; Axis: Char): String; function startMachine(): String; @@ -22,6 +27,14 @@ type implementation +{ PDF doesn't seam very consistent when it comes to using commas or + points as decimal separator, so we just try both } +function AnSemantico.StringToFloat(AStr: string): Double; +begin + if Pos('.', AStr) > 0 then Result := StrToFloat(AStr, FPointSeparator) + else Result := StrToFloat(AStr, FCommaSeparator); +end; + function AnSemantico.generate(c: Command; AData: TvVectorialDocument): String; var enter_line : String; @@ -29,6 +42,7 @@ begin {$ifdef FPVECTORIALDEBUG} WriteLn(':> AnSemantico.generate'); {$endif} + enter_line:= LineEnding; //chr(13) + chr(10); // CR and LF if ((c.code = cc_H_CLOSE_PATH) or (c.code = cc_hS_CLOSE_AND_END_PATH)) then // command h or s @@ -69,7 +83,7 @@ begin // Correcao para programas de desenho que geram um novo inicio no // fim do desenho, terminamos qualquer desenho inacabado AData.EndPath(); - AData.StartPath(StrToFloat(c.cord_x), StrToFloat(c.cord_y)); + AData.StartPath(StringToFloat(c.cord_x), StringToFloat(c.cord_y)); close_path_x:=c.cord_x; close_path_y:=c.cord_y; @@ -81,7 +95,7 @@ begin {$endif} // Result:='G01' + ' ' + 'X' + c.cord_x + ' ' + 'Y' + c.cord_y; - AData.AddLineToPath(StrToFloat(c.cord_x), StrToFloat(c.cord_y)); + AData.AddLineToPath(StringToFloat(c.cord_x), StringToFloat(c.cord_y)); end; cc_h_CLOSE_PATH: // command h begin @@ -90,7 +104,7 @@ begin {$endif} //Result:='G01' + ' ' + 'X' + c.cord_x + ' ' + 'Y' + c.cord_y; - AData.AddLineToPath(StrToFloat(c.cord_x), StrToFloat(c.cord_y)); + AData.AddLineToPath(StringToFloat(c.cord_x), StringToFloat(c.cord_y)); end; cc_S_END_PATH: // command S begin @@ -108,7 +122,7 @@ begin //Result:='G01' + ' ' + 'X' + c.cord_x + ' ' + 'Y' + c.cord_y + enter_line // +'G01 Z0 // Sobe a cabeça de gravação' + enter_line; - AData.AddLineToPath(StrToFloat(c.cord_x), StrToFloat(c.cord_y)); + AData.AddLineToPath(StringToFloat(c.cord_x), StringToFloat(c.cord_y)); AData.EndPath(); end; cc_c_BEZIER_TO_X_Y_USING_X2_Y2_AND_X3_Y3: // command c @@ -120,9 +134,9 @@ begin // +'G01 Z0 // Sobe a cabeça de gravação' + enter_line; AData.AddBezierToPath( - StrToFloat(c.cord_x3), StrToFloat(c.cord_y3), - StrToFloat(c.cord_x2), StrToFloat(c.cord_y2), - StrToFloat(c.cord_x), StrToFloat(c.cord_y) + StringToFloat(c.cord_x3), StringToFloat(c.cord_y3), + StringToFloat(c.cord_x2), StringToFloat(c.cord_y2), + StringToFloat(c.cord_x), StringToFloat(c.cord_y) ); end; cc_CONCATENATE_MATRIX: // command cm @@ -131,12 +145,12 @@ begin WriteLn(':> AnSemantico.cc_CONCATENATE_MATRIX'); {$endif} - cm_a := StrToFloat(c.cord_x3); - cm_b := StrToFloat(c.cord_y3); - cm_c := StrToFloat(c.cord_x2); - cm_d := StrToFloat(c.cord_y2); - cm_e := StrToFloat(c.cord_x); - cm_f := StrToFloat(c.cord_y); + cm_a := StringToFloat(c.cord_x3); + cm_b := StringToFloat(c.cord_y3); + cm_c := StringToFloat(c.cord_x2); + cm_d := StringToFloat(c.cord_y2); + cm_e := StringToFloat(c.cord_x); + cm_f := StringToFloat(c.cord_y); end; cc_RESTORE_MATRIX: // command Q begin @@ -169,13 +183,13 @@ begin if (Axis = 'y') then begin // y' = b * x + d * y + f - Result:=FloatToStr((cm_b*StrToFloat(x)+cm_d*StrToFloat(y)+cm_f)*(25.40/72)); + Result:=FloatToStr((cm_b*StringToFloat(x)+cm_d*StringToFloat(y)+cm_f)*(25.40/72)); end else // Axis = 'x' begin // x' = a * x + c * y + e - Result:=FloatToStr((cm_a*StrToFloat(x)+cm_c*StrToFloat(y)+cm_e)*(25.40/72)); + Result:=FloatToStr((cm_a*StringToFloat(x)+cm_c*StringToFloat(y)+cm_e)*(25.40/72)); end; end; @@ -209,12 +223,21 @@ end; constructor AnSemantico.Create; begin inherited Create; + cm_a:=1; cm_b:=0; cm_c:=0; cm_d:=1; cm_e:=0; cm_f:=0; + + // Format seetings to convert a string to a float + FPointSeparator := DefaultFormatSettings; + FPointSeparator.DecimalSeparator := '.'; + FPointSeparator.ThousandSeparator := '#';// disable the thousand separator + FCommaSeparator := DefaultFormatSettings; + FCommaSeparator.DecimalSeparator := ','; + FCommaSeparator.ThousandSeparator := '#';// disable the thousand separator end; end. diff --git a/packages/fpvectorial/src/svgvectorialwriter.pas b/packages/fpvectorial/src/svgvectorialwriter.pas index cafd26c782..782590afe6 100644 --- a/packages/fpvectorial/src/svgvectorialwriter.pas +++ b/packages/fpvectorial/src/svgvectorialwriter.pas @@ -20,19 +20,102 @@ type { TvSVGVectorialWriter } TvSVGVectorialWriter = class(TvCustomVectorialWriter) + private + FPointSeparator, FCommaSeparator: TFormatSettings; + procedure WriteDocumentSize(AStrings: TStrings; AData: TvVectorialDocument); + procedure WriteDocumentName(AStrings: TStrings; AData: TvVectorialDocument); + procedure WritePaths(AStrings: TStrings; AData: TvVectorialDocument); public { General reading methods } - procedure WriteToStream(AStream: TStream; AData: TvVectorialDocument); virtual; + procedure WriteToStrings(AStrings: TStrings; AData: TvVectorialDocument); override; end; implementation { TvSVGVectorialWriter } -procedure TvSVGVectorialWriter.WriteToStream(AStream: TStream; +procedure TvSVGVectorialWriter.WriteDocumentSize(AStrings: TStrings; AData: TvVectorialDocument); +begin + AStrings.Add(' width="744.09448819"'); + AStrings.Add(' height="1052.3622047"'); +end; + +procedure TvSVGVectorialWriter.WriteDocumentName(AStrings: TStrings; AData: TvVectorialDocument); +begin + AStrings.Add(' sodipodi:docname="New document 1">'); +end; + +{@@ + SVG Coordinate system measures things in millimiters. + The initial point is in the bottom-left corner of the document and it grows + to the top and to the right. + + 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); +var + i, j: Integer; + PathStr: string; + lPath: TPath; + PtX, PtY: double; +begin + for i := 0 to AData.GetPathCount() - 1 do + begin + PathStr := 'm '; + lPath := AData.GetPath(i); + for j := 0 to lPath.Len - 1 do + begin + if lPath.Points[j].SegmentType <> st2DLine then Break; // unsupported line type + + PtX := lPath.Points[j].X; + PtY := lPath.Points[j].Y; + PtY := AData.Height - PtY; + PathStr := PathStr + FloatToStr(PtX, FPointSeparator) + ',' + + FloatToStr(PtY, FPointSeparator) + ' '; + 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="path' + IntToStr(i) + '" />'); + end; +end; + +procedure TvSVGVectorialWriter.WriteToStrings(AStrings: TStrings; AData: TvVectorialDocument); begin + // Format seetings to convert a string to a float + FPointSeparator := DefaultFormatSettings; + FPointSeparator.DecimalSeparator := '.'; + FPointSeparator.ThousandSeparator := '#';// disable the thousand separator + FCommaSeparator := DefaultFormatSettings; + FCommaSeparator.DecimalSeparator := ','; + FCommaSeparator.ThousandSeparator := '#';// disable the thousand separator + + // Headers + AStrings.Add('<?xml version="1.0" encoding="UTF-8" standalone="no"?>'); + AStrings.Add('<!-- Created with fpVectorial (http://wiki.lazarus.freepascal.org/fpvectorial) -->'); + AStrings.Add(''); + AStrings.Add('<svg'); + AStrings.Add(' xmlns:dc="http://purl.org/dc/elements/1.1/"'); + AStrings.Add(' xmlns:cc="http://creativecommons.org/ns#"'); + AStrings.Add(' xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"'); + AStrings.Add(' xmlns:svg="http://www.w3.org/2000/svg"'); + AStrings.Add(' xmlns="http://www.w3.org/2000/svg"'); + AStrings.Add(' xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"'); + WriteDocumentSize(AStrings, AData); + AStrings.Add(' id="svg2"'); + AStrings.Add(' version="1.1"'); + WriteDocumentName(AStrings, AData); + + // Now data + AStrings.Add(' <g id="layer1">'); + WritePaths(AStrings, AData); + AStrings.Add(' </g>'); + // finalization + AStrings.Add('</svg>'); end; initialization |
