I was looking for a way to easily create a simple rendering of a multi-octave piano keyboard.
If anyone is interested, here's how I filled a TFNCImage with an svg at run time...
Drop a TFNCImage on a form.
Set Anchors to Left, top, right, bottom.
Set Stretch to true, center to true.
Add a TStringList to form private section and create/free in Form create/destroy.
FPianoKBD: TStringList;
Drop a button on the form.
Add two procedures to Form:
The first one adds a single octave to the SVG data.
procedure TForm2.AddAnOctave;
begin
FPianoKBD.Add('<!-- White keys -->');
FPianoKBD.Add('<rect style="fill:white;stroke:black" x= "0" y="0" width="23" height="120" />');
FPianoKBD.Add('<rect style="fill:white;stroke:black" x= "23" y="0" width="23" height="120" />');
FPianoKBD.Add('<rect style="fill:white;stroke:black" x= "46" y="0" width="23" height="120" />');
FPianoKBD.Add('<rect style="fill:white;stroke:black" x= "69" y="0" width="23" height="120" />');
FPianoKBD.Add('<rect style="fill:white;stroke:black" x= "92" y="0" width="23" height="120" />');
FPianoKBD.Add('<rect style="fill:white;stroke:black" x="115" y="0" width="23" height="120" />');
FPianoKBD.Add('<rect style="fill:white;stroke:black" x="138" y="0" width="23" height="120" />');
FPianoKBD.Add('');
FPianoKBD.Add('<!-- Black keys (overlap with the white keys) -->');
FPianoKBD.Add('<rect style="fill:black;stroke:black" x="14.33333" y="0" width="13" height="80" />');
FPianoKBD.Add('<rect style="fill:black;stroke:black" x="41.66666" y="0" width="13" height="80" />');
FPianoKBD.Add('<rect style="fill:black;stroke:black" x="82.25" y="0" width="13" height="80" />');
FPianoKBD.Add('<rect style="fill:black;stroke:black" x="108.25" y="0" width="13" height="80" />');
FPianoKBD.Add('<rect style="fill:black;stroke:black" x="134.75" y="0" width="13" height="80" />');
end;
The second one adds an octave, sets a "translate" to offset x coordinates, then adds another octave at that new offset.
procedure TForm2.BuildKbdSVG;
{ original svg at
https://commons.wikimedia.org/wiki/File:PianoKeyboard.svg
}
begin
FPianoKBD.Clear;
FPianoKBD.Add('');
FPianoKBD.Add('<svg xml:space="preserve" preserveAspectRatio="xMinYMid meet" width="483px" height="120" viewBox="0 0 483 120">');
FPianoKBD.Add('<!--');
FPianoKBD.Add(' Copyright (c) 2005 Lauri Kaila.');
FPianoKBD.Add(' Permission is granted to copy, distribute and/or modify this document');
FPianoKBD.Add(' under the terms of the GNU Free Documentation License, Version 1.2');
FPianoKBD.Add(' or any later version published by the Free Software Foundation;');
FPianoKBD.Add(' with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.');
FPianoKBD.Add(' A copy of the license is included in the section entitled "GNU');
FPianoKBD.Add(' Free Documentation License".');
FPianoKBD.Add('');
FPianoKBD.Add(' Intented to create a keyboard where key widths are');
FPianoKBD.Add(' accurately in position.');
FPianoKBD.Add('');
FPianoKBD.Add(' See http://www.mathpages.com/home/kmath043.htm');
FPianoKBD.Add(' for the math.');
FPianoKBD.Add('');
FPianoKBD.Add(' This keyboard has following properties (x=octave width).');
FPianoKBD.Add(' 1. All white keys have equal width in front (W=x/7).');
FPianoKBD.Add(' 2. All black keys have equal width (B=x/12).');
FPianoKBD.Add(' 3. The narrow part of white keys C, D and E is W - B*2/3');
FPianoKBD.Add(' 4. The narrow part of white keys F, G, A, and B is W - B*3/4');
FPianoKBD.Add('');
FPianoKBD.Add('-->');
FPianoKBD.Add('');
FPianoKBD.Add('<g id="octave-1">');
AddAnOctave;
FPianoKBD.Add('</g>');
FPianoKBD.Add('<g id="octave-2" transform="translate(161.000000, 0.000000)">');
AddAnOctave;
FPianoKBD.Add('</g>');
FPianoKBD.Add('<g id="octave-3" transform="translate(322.000000, 0.000000)">');
AddAnOctave;
FPianoKBD.Add('</g>');
FPianoKBD.Add('');
FPianoKBD.Add('</svg>');
end;
And the TButton OnClick builds the svg, saves it to a MemoryStream, then loads the MemoryStream into the TMSFNCImage.
procedure TForm2.btnGenerateClick(Sender: TObject);
var
ms: TMemoryStream;
begin
BuildKbdSVG; // clear stringlist and add svg definition
ms:=TMemoryStream.Create;
try
FPianoKBD.SaveToStream(ms); // copy svg content in stringlitst to stream
ms.Position:=0;
TMSFNCImage2.Bitmap.LoadFromStream(ms);
finally
ms.Free;
end;
end;
This is my first work with SVG - so there may be somewhat more clever ways of preparing the actual svg data - but hopefully this saves someone time...
Cheers,
EdB