unit lbc_svg;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils,
  zint;

procedure svg_plot(AStream: TStream; ASymbol: PointerTo_zint_symbol); 


implementation

{ Writes the symbol to a stream.
  To avoid duplication of the bar calculation, the coordinates are taken from 
  the rendered data, i.e. the coordinates are in pixels. We want to draw in mm
  --> we must divide by GL_CONST. }
procedure svg_plot(AStream: TStream; ASymbol: PointerTo_zint_symbol); 
const
  factor = 1.0/GL_CONST;
var
  line: PointerTo_zint_render_line;
  str: PointerTo_zint_render_string;
  fs: TFormatSettings;
  L: TStrings;
  w, h: Single;
  fgcolor, bgcolor: String;
begin
  if (ASymbol = nil) then
    raise Exception.Create('[svg_plot] Symbol is nil');
  if (ASymbol^.rendered = nil) then
    raise Exception.Create('[svg_plot] Barcode has not yet been rendered.');
    
  // rendered size in mm
  w := ASymbol^.rendered^.exact_width*factor;
  h := ASymbol^.rendered^.height*factor;
  
  // Make sure that floats are written with point as decimal separator
  fs := FormatSettings;
  fs.DecimalSeparator := '.';
  
  bgcolor := StrPas(ASymbol^.bgColour);
  fgcolor := StrPas(ASymbol^.fgColour);
  
  L := TStringList.Create;
  try
    L.Add(
      '<?xml version="1.0" standalone="no"?>'
    );
    L.Add(
      '<!DOCTYPE svg PUBLIC "-//W3C/DTD SVG 1.1/EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'
    );
    L.Add(Format(
      '<svg width="%.3fmm" height="%.3fmm" version="1.1" xmlns="http://www.w3.org/2000/svg">', [w, h], fs));
    
    if system.strlen(PChar(@ASymbol^.text[0])) <> 0 then
      L.Add('  <desc>%s</desc>', [PChar(@ASymbol^.text[0])])
    else
      L.Add('  <desc>Symbol generated by Zint and LazBarcodes</desc>');
    L.Add(Format(
      '  <rect width="100%%" height="100%%" fill="#%s"/>', [bgcolor]));
    L.Add(
      '  <g id="barcode">'); 
    
    line := ASymbol^.rendered^.lines;
    while Assigned(line) do
    begin
      L.Add(Format(
        '    <rect x="%.3fmm" y="%.3fmm" width="%.3fmm" height="%.3fmm" fill="#%s" />', [
        line^.x*factor, line^.y*factor, 
        line^.width*factor, line^.length*factor, 
        fgcolor
      ], fs));
      line := line^.next;
    end;
    
    str := ASymbol^.rendered^.strings;
    while Assigned(str) do
    begin
      L.Add(Format(
        '    <text x="%.3fmm" y="%.3fmm" text-anchor="middle" font-family="Helvetica" font-size="%.1f" fill="#%s">%s</text>', [
        str^.x*factor, (str^.y + ASymbol^.font_height)*factor, 1.0*ASymbol^.font_height, 
        fgcolor, 
        PChar(@ASymbol^.text[0])
        ], fs));
      str := str^.next;
    end;
    
    // to do: Add support of rings and hexagons
    
    L.Add('  </g>');
    L.Add('</svg>');
    
    L.SaveToStream(AStream);
  finally
    L.Free;
  end;
end;

end.

