View Issue Details

IDProjectCategoryView StatusLast Update
0027321LazarusPackagespublic2015-09-01 14:30
Reporterwp Assigned Towp  
PrioritynormalSeverityminorReproducibilityhave not tried
Status closedResolutionfixed 
Product Version1.5 (SVN) 
Summary0027321: [Patch] Improved svgwriter for fpvectorial
DescriptionThe svg writer of the fpvectorial package contains some bugs and missing features which become apparent when the fpvectorial drawing backend of TAChart is used.

These bugs are fixed by the attached patch:

- Font name respected (i.e. all fonts of the system can be used)
- Font color respected
- Font styles (bold, italic, underlined, strikethrough) respected
- Text rotation by any angle
- Text anchors (left, center, right)

It also fixes the missing assignment of page size in TvVectorialDocument.AddPage which caused the drawing to be off-page in Firefox.

Fix typo: millimeters instead of milimeters.
Additional InformationThe zip file contains a simple demo showing the improvements. The svg output of the demo was inspected with Inkscape (Windows), Firefox (Windows, Ubuntu) and the svg viewer of Ubuntu.
TagsNo tags attached.
Fixed in Revision
LazTarget-
WidgetsetWin32/Win64
Attached Files

Activities

wp

2015-01-16 23:40

developer  

wp

2015-01-16 23:41

developer  

fpvectorial.patch (6,938 bytes)   
Index: fpvectorial.pas
===================================================================
--- fpvectorial.pas	(revision 47402)
+++ fpvectorial.pas	(working copy)
@@ -807,8 +807,8 @@
     AdjacentFormula: TvFormula;
   public
     Top, Left, Width, Height: Double;
-    function CalculateHeight(ADest: TFPCustomCanvas): Double; // in milimeters
-    function CalculateWidth(ADest: TFPCustomCanvas): Double; // in milimeters
+    function CalculateHeight(ADest: TFPCustomCanvas): Double; // in millimeters
+    function CalculateWidth(ADest: TFPCustomCanvas): Double; // in millimeters
     function AsText: string;
     procedure PositionSubparts(ADest: TFPCustomCanvas; ABaseX, ABaseY: Double);
     procedure Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
@@ -843,8 +843,8 @@
     function  CalculateRPNFormulaValue: Double;
     procedure Clear; override;
     //
-    function CalculateHeight(ADest: TFPCustomCanvas): Double; virtual; // in milimeters
-    function CalculateWidth(ADest: TFPCustomCanvas): Double; virtual; // in milimeters
+    function CalculateHeight(ADest: TFPCustomCanvas): Double; virtual; // in millimeters
+    function CalculateWidth(ADest: TFPCustomCanvas): Double; virtual; // in millimeters
     procedure PositionSubparts(ADest: TFPCustomCanvas; ABaseX, ABaseY: Double); override;
     procedure CalculateBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double); override;
     procedure Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
@@ -856,8 +856,8 @@
 
   TvVerticalFormulaStack = class(TvFormula)
   public
-    function CalculateHeight(ADest: TFPCustomCanvas): Double; override; // in milimeters
-    function CalculateWidth(ADest: TFPCustomCanvas): Double; override; // in milimeters
+    function CalculateHeight(ADest: TFPCustomCanvas): Double; override; // in millimeters
+    function CalculateWidth(ADest: TFPCustomCanvas): Double; override; // in millimeters
     procedure PositionSubparts(ADest: TFPCustomCanvas; ABaseX, ABaseY: Double); override;
     procedure CalculateBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double); override;
     procedure Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
@@ -7038,6 +7038,8 @@
 function TvVectorialDocument.AddPage: TvVectorialPage;
 begin
   Result := TvVectorialPage.Create(Self);
+  Result.Width := Width;
+  Result.Height := Height;
   FPages.Add(Result);
   if FCurrentPageIndex < 0 then FCurrentPageIndex := FPages.Count-1;
 end;
Index: svgvectorialwriter.pas
===================================================================
--- svgvectorialwriter.pas	(revision 47402)
+++ svgvectorialwriter.pas	(working copy)
@@ -46,10 +46,10 @@
 
   // 1 Inch = 25.4 milimiters
   // 90 inches per pixel = (1 / 90) * 25.4 = 0.2822
-  // FLOAT_MILIMETERS_PER_PIXEL = 0.3528; // DPI 72 = 1 / 72 inches per pixel
+  // FLOAT_MILLIMETERS_PER_PIXEL = 0.3528; // DPI 72 = 1 / 72 inches per pixel
 
-  FLOAT_MILIMETERS_PER_PIXEL = 0.2822; // DPI 90 = 1 / 90 inches per pixel
-  FLOAT_PIXELS_PER_MILIMETER = 3.5433; // DPI 90 = 1 / 90 inches per pixel
+  FLOAT_MILLIMETERS_PER_PIXEL = 0.2822; // DPI 90 = 1 / 90 inches per pixel
+  FLOAT_PIXELS_PER_MILLIMETER = 3.5433; // DPI 90 = 1 / 90 inches per pixel
 
 { TvSVGVectorialWriter }
 
@@ -67,7 +67,7 @@
 {@@
   SVG Coordinate system measures things only in pixels, so that we have to
   hardcode a DPI value for the screen, which is usually 72.
-  FPVectorial uses only milimeters (mm).
+  FPVectorial uses only millimeters (mm).
 
   The initial point in FPVectorial is in the bottom-left corner of the document
   and it grows to the top and to the right. In SVG, on the other hand, the
@@ -196,8 +196,8 @@
   const AData: TvVectorialPage; const ASrcX, ASrcY: Double; var ADestX,
   ADestY: double);
 begin
-  ADestX := ASrcX / FLOAT_MILIMETERS_PER_PIXEL;
-  ADestY := (AData.Height - ASrcY) / FLOAT_MILIMETERS_PER_PIXEL;
+  ADestX := ASrcX / FLOAT_MILLIMETERS_PER_PIXEL;
+  ADestY := (AData.Height - ASrcY) / FLOAT_MILLIMETERS_PER_PIXEL;
 end;
 
 procedure TvSVGVectorialWriter.WriteToStrings(AStrings: TStrings;
@@ -241,19 +241,17 @@
 
 procedure TvSVGVectorialWriter.WriteText(AStrings: TStrings; lText: TvText;
   AData: TvVectorialPage; ADoc: TvVectorialDocument);
+const
+  TEXT_ANCHORS: array[TvTextAnchor] of string = ('start', 'middle', 'end');
+  TEXT_DECO: array[0..3] of string = ('none', 'underline', 'line-through', 'line-through,underline');
 var
   i, j, FontSize: Integer;
-  TextStr, FontName, SVGFontFamily: string;
+  TextStr: String;
   PtX, PtY: double;
 begin
-  TextStr := '';
-
-  ConvertFPVCoordinatesToSVGCoordinates(
-      AData, lText.X, lText.Y, PtX, PtY);
-
+  ConvertFPVCoordinatesToSVGCoordinates(AData, lText.X, lText.Y, PtX, PtY);
   TextStr := lText.Value.Text;
-  FontSize:= ceil(lText.Font.Size / FLOAT_MILIMETERS_PER_PIXEL);
-  SVGFontFamily := 'Arial, sans-serif';//lText.FontName;
+  FontSize:= ceil(lText.Font.Size / FLOAT_MILLIMETERS_PER_PIXEL);
 
   AStrings.Add('  <text ');
   // Discussion about this offset in bugs 22091 and 26817
@@ -264,16 +262,36 @@
   AStrings.Add('    x="' + FloatToStr(PtX, FPointSeparator) + '"');
   AStrings.Add('    y="' + FloatToStr(PtY, FPointSeparator) + '"');
   {$ENDIF}
-//    AStrings.Add('    font-size="' + IntToStr(FontSize) + '"'); Doesn't seam to work, we need to use the tspan
-  AStrings.Add('    font-family="' + SVGFontFamily + '">');
-  AStrings.Add('    <tspan ');
-  AStrings.Add('      style="font-size:' + IntToStr(FontSize) + '" ');
-// Does not support fill="none"
-  AStrings.Add('      fill="' +
-               '#' + FPColorToRGBHexString(lText.Font.Color) + '" ');
-  //    AStrings.Add('      id="tspan2828" ');
-  AStrings.Add('    >');
-  AStrings.Add(TextStr + '</tspan></text>');
+
+  if lText.TextAnchor <> vtaStart then AStrings.Add(
+        Format('    text-anchor="%s"', [TEXT_ANCHORS[lText.TextAnchor]]));
+
+  if lText.Font.Bold then
+  AStrings.Add('    font-weight="bold"');
+
+  if lText.Font.Italic then
+  AStrings.Add('    font-style="oblique"');
+
+  if lText.Font.Underline or lText.Font.Strikethrough then
+    AStrings.Add(
+        Format('    text-decoration="%s"', [TEXT_DECO[ord(lText.Font.UnderLine)+2*ord(lText.Font.StrikeThrough)]]));
+
+  if lText.Font.Orientation <> 0 then
+    AStrings.Add(
+        Format('    transform="rotate(%g,%g,%g)"', [-lText.Font.Orientation, PtX, PtY], FPointSeparator));
+
+  AStrings.Add(
+        Format('    font-family="%s"', [lText.Font.Name]));
+
+  AStrings.Add(
+        Format('    font-size="%d"', [FontSize]));
+
+  AStrings.Add(
+        Format('    fill="#%s"', [FPColorToRGBHexString(lText.Font.Color)]));
+
+  AStrings.Add('  >');
+  AStrings.Add(TextStr);
+  AStrings.Add('  </text>');
 end;
 
 procedure TvSVGVectorialWriter.WriteCircle(circle: TvCircle;
fpvectorial.patch (6,938 bytes)   

wp

2015-02-05 13:20

developer   ~0080804

Could somebody please take care of this patch? I need it done because a bug in the fpvectorial drawing frontend of TAChart depends on it.

Juha Manninen

2015-02-06 07:44

developer   ~0080812

Why the assignment for Felipe was removed? I think you should have commit rights to fpvectorial, did you discuss it with Felipe?
I can apply this if nobody else will.

wp

2015-02-06 10:44

developer   ~0080814

>Why the assignment for Felipe was removed?
I thought an unassigned report would catch more attention of developers in general.

>I think you should have commit rights to fpvectorial
Not, as far as I know

>did you discuss it with Felipe?
No, but I'll contact him by mail (I did not want to bother him with this issue because he seems to be very busy).

Issue History

Date Modified Username Field Change
2015-01-16 23:40 wp New Issue
2015-01-16 23:40 wp File Added: fpvectorial-svgwritetest.zip
2015-01-16 23:41 wp File Added: fpvectorial.patch
2015-01-25 12:24 wp Assigned To => Felipe Monteiro de Carvalho
2015-01-25 12:24 wp Status new => assigned
2015-02-05 13:18 wp Assigned To Felipe Monteiro de Carvalho => wp
2015-02-05 13:19 wp Assigned To wp =>
2015-02-05 13:20 wp Note Added: 0080804
2015-02-06 07:44 Juha Manninen Note Added: 0080812
2015-02-06 10:44 wp Note Added: 0080814
2015-02-09 18:17 Maxim Ganetsky Assigned To => wp
2015-02-09 19:57 wp Status assigned => resolved
2015-02-09 19:57 wp Resolution open => fixed
2015-09-01 14:30 wp Status resolved => closed