Output to Scalable Vector Graphics (SVG) File

We show you how to install the fpVectorial component and to use it to create a vector graphic and save it in a new .svg file. Some of the code is derived from the supplied example fpvwritetest. These instructions include the installation of the package fpvectorialpkg (which you might have already installed in order to write to a new .docx file). The component has been described as a "pre-alpha" version but it is fine for demonstrating the ability to generate scalable images from Pascal code.

Alternatively, you can:
  • use a graphics application such as Inkscape to create your own SVG files by dropping and dragging shapes;
  • create and/or edit a .svg file (such as the one produced by this demo) in a text editor;
  • embed SVG code in an HTML5 file; the code between svg tags is easy to read and write.
  1. Select menu item Package > Install/Uninstall Package ... and select from the right panel fpvectorialpkg 0.0.
  2. Click the "Install selection" button and then the "Save and rebuild IDE" button and accept the invitation to continue.
    Lazarus will close and then reopen with the newly installed component.
  3. Select menu item Project > New Project and create a new simple program.
  4. Select menu item File > Save As ... and save the project as SVG_Demo.
  5. Select menu item Project > Project Inspector and click on the Add (+) icon.
  6. In the Project Inspector, select the New Requirement tab and then select fpvectorialpkg from the drop-down list.
  7. Click on the "Create New Requirement" button and then paste this code to replace the existing code in the editor.
    program SVG_Demo;
    
    {$mode objfpc}{$H+}
    
    uses
      fpvectorial, svgvectorialwriter, fpvutils, fpvectorialpkg, fpCanvas;
    const
      TextYOffset = -12;
      TextXOffset = -1;
    var
      Vec: TvVectorialDocument;
      Page: TvVectorialPage;
      LastCircle, NewCircle: tvCircle;
      NewRect: TvRectangle;
      LastPath: TPath;
      i: integer;
    begin
      Vec := TvVectorialDocument.Create;
      try
        Vec.Width := 120;
        Vec.Height := 110;
        Page := Vec.AddPage;
        with Page do
          begin
            Height := Vec.Height;
            Width := Vec.Width;
            StartPath;
            AddMoveToPath(0, 0);
            AddLineToPath(0, 100);
            AddMoveToPath(0, 0);
            AddLineToPath(100, 0);
            SetPenWidth(2);
            SetPenColor(RGBToFPColor(0, 0, 0));
            EndPath;
            // Y axis
            AddText(0, 20 + TextYOffset, 0, '', 8, '_20');
            AddText(0, 40 + TextYOffset, 0, '', 8, '_40');
            AddText(0, 60 + TextYOffset, 0, '', 8, '_60');
            AddText(0, 80 + TextYOffset, 0, '', 8, '_80');
            // X axis
            StartPath;
            for i := 1 to 5 do
              begin
                AddMoveToPath(20 * i, -2);
                AddLineToPath(20 * i, 2);
              end;
            SetPenWidth(1);
            SetPenColor(RGBToFPColor(0, 0, 0));
            EndPath;
            AddText(0 + TextXOffset, -9 + TextYOffset, 0, '', 8, '0');
            AddText(20 + TextXOffset, -9 + TextYOffset, 0, '', 8, '20');
            AddText(40 + TextXOffset, -9 + TextYOffset, 0, '', 8, '40');
            AddText(60 + TextXOffset, -9 + TextYOffset, 0, '', 8, '60');
            AddText(80 + TextXOffset, -9 + TextYOffset, 0, '', 8, '80');
            AddText(100 + TextXOffset, -9 + TextYOffset, 0, '', 8, '100');
            AddCircle(50, 50, 30);
            // Modify properties of added circle
            LastCircle := tvCircle(GetLastEntity);
            LastCircle.Pen.Color := RGBToFPColor(255, 50, 50);
            LastCircle.Pen.Width := 3;
            // Create new circle and assign properties
            NewCircle := tvCircle.Create(Page);
            NewCircle.X := 30;
            NewCircle.Y := 30;
            NewCircle.Radius := 13;
            NewCircle.Brush.Style:= bsSolid; // necessary to enable fill
            NewCircle.Brush.Color := RGBToFPColor(100, 255, 100);
            NewCircle.Pen.Color := RGBToFPColor(0, 0, 255);
            AddEntity(NewCircle);
            // Draw pentagon (irregular)
            StartPath;
            AddMoveToPath(60, 70);
            AddLineToPath(60, 80);
            AddLineToPath(67.5, 90);
            AddLineToPath(75, 80);
            AddLineToPath(75, 70);
            AddLineToPath(60, 70);
            SetPenWidth(2);
            SetPenColor(RGBToFPColor(0, 250, 0));
            EndPath;
            // Change properties of pentagon
            LastPath := TPath(GetLastEntity);
            LastPath.Brush.Style := bsSolid;
            LastPath.Brush.Color := RGBToFPColor(240, 250, 0);
          end;
        Vec.WriteToFile('svgdemo.svg', vfSVG);
      finally
        Vec.Free;
      end;
    end.
    
    The text in the resultant SVG file follows. Note the following points.
    • Coordinates supplied in mm with y increasing up the page have been converted to pixels with y increasing downwards. Procedure ConvertFPVCoordinatesToSVGCoordinates in the svgvectorialwriter unit divides values by the number of mm per pixel (0.2822) so that 100 mm converts to 100/0.2833 = 354.358610914245 pixels. This matches the dots per inch (DPI) used by Opera and Inkscape.
    • The initial m is for relative move and l is for line to relative position.
    • Colours given as RGB values in denary are converted to hex, so that, for example LastCircle.Pen.Color := RGBToFPColor(255, 50, 50); translates to stroke="#FF3232".
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <!-- Created with fpVectorial (http://wiki.lazarus.freepascal.org/fpvectorial) -->
    
    <svg
      xmlns:dc="http://purl.org/dc/elements/1.1/"
      xmlns:cc="http://creativecommons.org/ns#"
      xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
      xmlns:svg="http://www.w3.org/2000/svg"
      xmlns="http://www.w3.org/2000/svg"
      xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
      width="120mm"
      height="110mm"
      id="svg2"
      version="1.1"
      sodipodi:docname="New document 1">
      <g id="layer1">
      <path
        style="fill:none;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
        d="m 0,389.79447200567 l 0,-354.358610914245 m 0,354.358610914245 l 354.358610914245,0 "
      id="path0" />
      <text 
        x="4"
        y="313.44578313253"
        font-family="Arial, sans-serif">
        <tspan 
          style="font-size:29" 
          fill="#000000" 
        >
    _20
    </tspan></text>
      <text 
        x="4"
        y="242.574060949681"
        font-family="Arial, sans-serif">
        <tspan 
          style="font-size:29" 
          fill="#000000" 
        >
    _40
    </tspan></text>
      <text 
        x="4"
        y="171.702338766832"
        font-family="Arial, sans-serif">
        <tspan 
          style="font-size:29" 
          fill="#000000" 
        >
    _60
    </tspan></text>
      <text 
        x="4"
        y="100.830616583983"
        font-family="Arial, sans-serif">
        <tspan 
          style="font-size:29" 
          fill="#000000" 
        >
    _80
    </tspan></text>
      <path
        style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
        d="m 70.871722182849,396.881644223955 l 0,-14.1743444365698 m 70.871722182849,14.1743444365698 l 0,-14.1743444365698 m 70.8717221828491,14.1743444365698 l 0,-14.1743444365698 m 70.871722182849,14.1743444365698 l 0,-14.1743444365698 m 70.8717221828491,14.1743444365698 l 0,-14.1743444365698 "
      id="path5" />
      <text 
        x="0.456413890857548"
        y="416.209780297661"
        font-family="Arial, sans-serif">
        <tspan 
          style="font-size:29" 
          fill="#000000" 
        >
    0
    </tspan></text>
      <text 
        x="71.3281360737066"
        y="416.209780297661"
        font-family="Arial, sans-serif">
        <tspan 
          style="font-size:29" 
          fill="#000000" 
        >
    20
    </tspan></text>
      <text 
        x="142.199858256556"
        y="416.209780297661"
        font-family="Arial, sans-serif">
        <tspan 
          style="font-size:29" 
          fill="#000000" 
        >
    40
    </tspan></text>
      <text 
        x="213.071580439405"
        y="416.209780297661"
        font-family="Arial, sans-serif">
        <tspan 
          style="font-size:29" 
          fill="#000000" 
        >
    60
    </tspan></text>
      <text 
        x="283.943302622254"
        y="416.209780297661"
        font-family="Arial, sans-serif">
        <tspan 
          style="font-size:29" 
          fill="#000000" 
        >
    80
    </tspan></text>
      <text 
        x="354.815024805103"
        y="416.209780297661"
        font-family="Arial, sans-serif">
        <tspan 
          style="font-size:29" 
          fill="#000000" 
        >
    100
    </tspan></text>
    <circle cx="177.179305457123" cy="212.615166548547" r="106.307583274274" stroke="#FF3232" stroke-width="3" fill="none"/>
    <circle cx="106.307583274274" cy="283.486888731396" r="46.0666194188519" stroke="#0000FF" stroke-width="1" fill="#64FF64"/>
      <path
        style="fill:#F0FA00;stroke:#00FA00;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
        d="m 212.615166548547,141.743444365698 l 0,-35.4358610914245 l 26.5768958185684,-35.4358610914245 l 26.5768958185684,35.4358610914245 l 0,35.4358610914245 l -53.1537916371368,0 "
      id="path14" />
      </g>
    </svg>
    
    
  8. Execute the program and open svgdemo.svg (which should be in your program folder) with an application such as Opera, Chrome, Firefox, Internet Explorer or Inkscape.
    You should see something like this image (now viewed in your current browser):
    svgdemo.svg

    svgdemo.svg

    The generated image shows the input coordinate system with the circle centres at the points 30, 30 and 50, 50.

Programming - a skill for life!

Vector Graphics using the CRT, Graph and WinGraph units and output to SVG file