{"id":55001138,"date":"2018-08-01T00:00:00","date_gmt":"2020-05-13T21:11:16","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1138"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Malen_und_Zeichnen_mit_SVG","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/","title":{"rendered":"Malen und Zeichnen mit SVG"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg06.met.vgwort.de\/na\/f7a88e036be3455380555d5fa1887bce\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>Obwohl es sich bei SVG um Vektorgrafiken handelt, k&ouml;nnen Sie diese ebenfalls interaktiv mit der Maus in ein Webbrowser-Steuerelement zeichnen. Das Verfahren hat gegen&uuml;ber den Pixel-Grafiken von HTML5 sogar noch einige Vorz&uuml;ge, die die hier vorgestellte L&ouml;sung anbietet und erl&auml;utert. Mit keiner anderen Methode lassen sich auf so einfache Weise Grafiken erzeugen und in Tabellen abspeichern.<\/b><\/p>\n<h2>Referenz<\/h2>\n<p>Die Ausf&uuml;hrungen dieses Beitrags setzen jene aus dem Artikel <b>SVG als Grafikkomponente<\/b> in dieser Ausgabe fort. Dort sind bereits die Grundlagen zum Einsatz des <b>Webbrowser-Steuerelements<\/b> im Verein mit <b>SVG<\/b> beschrieben.<\/p>\n<h2>SVG-Zeichnen im Unterschied zur Alternative HTML5<\/h2>\n<p>Im Beitrag <b>Malen und Zeichnen mit HTML5<\/b> ver&ouml;ffentlichten wir eine Beispielanwendung, &uuml;ber die Sie mit der Maus oder mit einem Grafiktablett in eine Zeichenfl&auml;che malen k&ouml;nnen. Die dabei entstehende Pixel-Grafik k&ouml;nnen Sie dabei in eine Bilddatei oder direkt bin&auml;r in eine Tabelle abspeichern.<\/p>\n<p>Hier bauen wir diese Anwendung nach und verwenden dabei <b>SVG<\/b> im <b>Webbrowser-Steuerelement<\/b>, wobei der Komfort des Malformulars noch etwas erh&ouml;ht wird. Die Vorteile der <b>SVG<\/b>-L&ouml;sung lassen sich schnell aufz&auml;hlen:<\/p>\n<ul>\n<li><b>HTML5<\/b> erzeugt Pixel-Grafiken, die sich bin&auml;r nur in einem der Standardformate abspeichern lassen. Verlustfreie Speicherung erm&ouml;glichen dabei nur die Formate <b>BMP<\/b>, <b>PNG<\/b>, <b>TIFF<\/b> und <b>GIF<\/b>. Der Speicherbedarf f&auml;llt dabei leider ziemlich hoch aus. Anders bei <b>SVG<\/b>, wo die Zeichnungen nur aus einer Liste von <b>XML<\/b>-Anweisungen bestehen, die erheblich weniger Bytes ben&ouml;tigen. Zudem lassen sich die <b>SVG<\/b>-Bilder beliebig hochskalieren.<\/li>\n<li>Die Elemente der Zeichnung lassen sich in einer <b>HTML5<\/b>-Grafik sp&auml;ter nicht mehr identifizieren. In einer <b>SVG<\/b>-Grafik ist das anders. Einzelne Elemente k&ouml;nnen Sie entfernen oder nachbearbeiten. Die vorliegende Malanwendung erlaubt so etwa ein schrittweises <b>Undo<\/b>.<\/li>\n<li><b>SVG<\/b> bringt von Haus aus Filtereffekte mit, die <b>HTML5<\/b> nicht kennt. Zwar gibt es auch dort einen <b>Shadow<\/b>-Effekt, der einen Schattenwurf der Zeichenelemente zul&auml;sst, doch von den komplexen Filterkombinationen von <b>SVG<\/b> ist das alles weit entfernt.<\/li>\n<\/ul>\n<p>Der einzige Nachteil besteht darin, dass <b>SVG<\/b>-Elemente zur Laufzeit vom Browser gerendert werden. Das beeintr&auml;chtigt nat&uuml;rlich die Performance. Kritzeln Sie mit einem Grafiktablett etwa schnell einige Linien, so hinkt die Darstellung den Bewegungen deutlich nach. Aber Sinn und Zweck dieser L&ouml;sung ist ja auch nicht, unter Access ein vollwertiges Vektorgrafikprogramm zu realisieren &#8211; die Einsatzm&ouml;glichkeiten erw&auml;hnten wir im analogen <b>HTML5<\/b>-Beitrag.<\/p>\n<h2>SVG-Zeichenformular<\/h2>\n<p>Beschreiben wir zun&auml;chst die Bedienung des Zeichenformulars <b>frmSVGDraw<\/b> anhand von Bild 1. Im Zentrum befindet sich die Zeichenfl&auml;che in Gestalt eines Web-browser-Steuerelements, das verankert ist und sich damit bei Gr&ouml;&szlig;en&auml;nderungen des Formulars entsprechend ausdehnt. Die anderen Elemente richten sich dagegen am rechten oder unteren Rand aus. <\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_04\/frmSVGDraw_RT.png\" alt=\"Zur Laufzeit entsteht im Formular beim Malen mit verschiedenen Werkzeugeinstellungen additiv eine speicherbare SVG-Grafik.\" width=\"700\" height=\"430,5584\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Zur Laufzeit entsteht im Formular beim Malen mit verschiedenen Werkzeugeinstellungen additiv eine speicherbare SVG-Grafik.<\/span><\/b><\/p>\n<p>Das Formular ist an eine Tabelle <b>tblBilderDraw<\/b> gebunden, so dass Sie pro Datensatz jeweils eine Zeichnung anfertigen oder darstellen k&ouml;nnen. Das Laden der Grafiken geschieht automatisch beim Wechsel eines Datensatzes. Jedem Bild k&ouml;nnen Sie oben eine <b>Bezeichnung<\/b> vergeben. Mit dem Button <b>Alles l&ouml;schen<\/b> versetzen Sie die Zeichenfl&auml;che in den Ursprungszustand und erhalten eine wei&szlig;e Zeichenfl&auml;che. <b>Bild speichern<\/b> erst transferiert das Gem&auml;lde in die Tabelle, welches ansonsten beim Datensatzwechsel verloren ginge. Sie k&ouml;nnen es zudem wahlweise &uuml;ber <b>In Datei speichern&#8230;<\/b> als <b>JPG<\/b>-Datei oder mit <b>Bild in Zwischenablage <\/b>in selbige exportieren. Der <b>Undo<\/b>-Button mit dem blauen Pfeil macht den letzten Zeichenvorgang oder auch fr&uuml;here r&uuml;ckg&auml;ngig. Sobald Sie die linke Maustaste loslassen, wird intern ein <b>SVG-path<\/b>-Element angelegt, das den gemalten Polygonzug repr&auml;sentiert. Das <b>Undo<\/b> l&ouml;scht dieses Element aus dem <b>SVG-XML<\/b> wieder und setzt einen Z&auml;hler herab. Ein erneutes <b>Undo<\/b> l&ouml;scht dann das Element mit diesem Z&auml;hler.<\/p>\n<p>Rechts k&ouml;nnen Sie die <b>Linienart<\/b> bestimmen, bevor Sie loszeichnen. M&ouml;glich sind durchgezogene Linienz&uuml;ge, gepunktete oder gestrichelte. Die Breite der Linien kann aus der darunterliegenden Optionsgruppe gew&auml;hlt werden. Welche Malfarbe dabei verwendet wird, kann mit Klick auf die Fl&auml;che <b>Linienfarbe<\/b> zugewiesen werden. Das &ouml;ffnet den normalen Windows-Farbauswahldialog. Alternativ haben Sie aber auch die M&ouml;glichkeit, die Farbe aus dem Spektrum rechts auszuw&auml;hlen. &uuml;ber diesem Spektrum befindet sich eine Optionsgruppe, die das Ziel der Farbauswahl angibt. Das <b>L<\/b> bezieht sich auf die <b>Linienfarbe<\/b>, das <b>F<\/b> auf die <b>F&uuml;llfarbe<\/b> und das <b>H<\/b> auf die Hintergrundfarbe.<\/p>\n<p>Neben diesen Elementen k&ouml;nnen Sie mehrere Checkboxen bedienen. Ist <b>F&uuml;llen<\/b> aktiviert, so wird nicht nur ein Linienzug gezeichnet, sondern dieser automatisch geschlossen und mit einer einfarbigen F&uuml;llung versehen. Das geschieht bereits w&auml;hrend des Malens! Die Formen in der Abbildung machen den Vorgang deutlich. Hier wurde der Schieberegler f&uuml;r die <b>Transparenz<\/b> eingesetzt. Befindet der sich ganz links, so werden sowohl Linien als auch wie F&uuml;llungen, opak, w&auml;hrend das Verschieben nach rechts beides immer durchsichtiger macht. Auf diese Weise &uuml;berlagern Sie verschiedene Formen sequenziell.<\/p>\n<p>Ist die Checkbox <b>Weich<\/b> aktiv, so werden Linien und Ecken weichgezeichnet. Die Checkbox <b>Schatten<\/b> aktiviert selbigen, wobei mit dem Schieberegler dessen Ausdehnung geregelt werden kann. Schlie&szlig;lich k&ouml;nnen Sie noch die Checkbox <b>Turbulenz<\/b> aktivieren und mit dem Schieberegler daneben den Grad derselben einstellen. Linien malen Sie damit nicht mehr als Linien, sondern als, sondern als turbulent verzerrte Polygonz&uuml;ge, wie einige Formen in der Abbildung beweisen (siehe auch Bild 2).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_04\/frmDrawTurbulence.png\" alt=\"Linienz&uuml;ge k&ouml;nnen bei aktivierter Turbulenz verzerrt werden.\" width=\"425\" height=\"309,7075\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Linienz&uuml;ge k&ouml;nnen bei aktivierter Turbulenz verzerrt werden.<\/span><\/b><\/p>\n<p>Au&szlig;erdem ist es &uuml;ber den Button <b>Bilddatei einf&uuml;gen&#8230;<\/b> noch m&ouml;glich, &uuml;ber einen Dateiauswahldialog eine <b>JPG<\/b>-Datei in die Zeichnung zu laden. Der Cursor &uuml;ber der Zeichenfl&auml;che &auml;ndert dann seine Gestalt in ein Kreuz, und erst, nachdem Sie nun auf eine Koordinate im Bild klicken, wird das Bild an dieser Stelle eingef&uuml;gt. Ist ein Transparenzwert aktiviert, so wird auch diese Bilddatei transparent eingef&uuml;gt.<\/p>\n<p>Eine ganze Menge Features, die dieses Formular bereith&auml;lt! Da sollte man wohl meinen, dass die Programmierung einen hohen Aufwand erfordert. Tats&auml;chlich kommt die Formularklasse aber mit etwa <b>400<\/b> Zeilen VBA aus, ein Wert, der deutlich macht, wieviel Arbeit der Browser im Verein mit <b>SVG<\/b> uns da abnimmt. Wollten Sie dasselbe etwa mit dem Windows-<b>GDI-API<\/b> erreichen, so k&auml;men Sie sicher auf einige Tausend Zeilen.<\/p>\n<h2>Tabelle zum Speichern<\/h2>\n<p>Die Tabelle <b>tblBilderDraw<\/b>, an die das Formular gebunden ist, hat den sehr einfachen Aufbau aus Bild 3. Genau genommen ist nur das Feld <b>Bildname<\/b> an das Textfeld <b>Bezeichnung<\/b> des Formulars gebunden, w&auml;hrend der Inhalt der Grafik im Feld <b>BildOLE<\/b> per VBA abgespeichert wird. Der Name des Felds ist etwas irref&uuml;hrend, denn die Tabelle wurde schlicht aus der <b>HTML5<\/b>-Version der Malanwendung importiert. Dort kamen die Pixel bin&auml;r tats&auml;chlich in ein <b>OLE-Feld<\/b>. Hier aber haben wir es ja mit <b>XML-Text<\/b> zu tun, f&uuml;r den ein <b>Memo<\/b>-Feld besser passt.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_04\/tblBilderDraw_DS.png\" alt=\"Die Tabelle tblBilderDraw speichert nur die gemalten Grafiken und ihre Namen nebst ID.\" width=\"650\" height=\"349,5606\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Die Tabelle tblBilderDraw speichert nur die gemalten Grafiken und ihre Namen nebst ID.<\/span><\/b><\/p>\n<p>Die mit Beispielen gef&uuml;llte Tabelle in der Datenblattansicht zeigt Bild 4. Sie erkennen sofort, dass es sich beim Inhalt von <b>BildOLE<\/b> um jeweils komplette <b>HTML<\/b>-Dokumente handelt, die sogar <b>JavaScript<\/b> enthalten. Die <b>SVG<\/b>-Anweisungen folgen erst am unteren Rand der Zeilen und leiten sich mit dem <b>Tag<\/b> <b><svg...><\/b> ein. Wenn Sie sich den Inhalt einer solchen Datenblattzelle einmal in einen Texteditor kopieren, so wird folgender Aufbau deutlich: Das <b>HTML<\/b>-Dokument liefert zun&auml;chst Basisdefinitionen, an die sich ein Block <b>JavaScript<\/b> anschlie&szlig;t, welcher Steuerungsfunktionen f&uuml;r die <b>SVG<\/b>-Filter enth&auml;lt. Dann folgt der <b>SVG<\/b>-Teil. Hier gibt es einen Block, der die <b>SVG<\/b>-Filter und -Effekte definiert. Erst dann kommen die eigentlichen Zeichenelemente, bei denen es sich um eine Reihe von <b>polylines<\/b> handelt.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_04\/tblBilderDraw_RT.png\" alt=\"In der Datenblattansicht der Tabelle tblBilderDraw wird deutlich, dass es sich bei den SVG-Grafiken um HTML-Anweisungen handelt.\" width=\"700\" height=\"329,4118\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: In der Datenblattansicht der Tabelle tblBilderDraw wird deutlich, dass es sich bei den SVG-Grafiken um HTML-Anweisungen handelt.<\/span><\/b><\/p>\n<p>Die Gr&ouml;&szlig;e des in <b>Bild 1<\/b> gezeigten Gem&auml;ldes betr&auml;gt im Feld <b>BildOLE<\/b> ungef&auml;hr <b>40 kB<\/b>. Davon entfallen auf den immer gleichen <b>HTML<\/b>-Rumpf <b>3 kB<\/b>. Also nehmen die <b>polyline<\/b>-Elemente den weitaus gr&ouml;&szlig;ten Teil ein. Da es sich hier um Text mit sich h&auml;ufig wiederholenden Zahlen handelt, lie&szlig;e sich das Feld im Bedarfsfall auch gut einer Textkompression unterziehen. Im Beitrag zur <b>RTLCompression<\/b>, die auch in der <b>HTML5<\/b>-Version zum Einsatz kommt, lernten Sie eine solche universelle Kompressionsroutine kennen.<\/p>\n<h2>Formularentwurf<\/h2>\n<p>Ans sich h&auml;lt der Entwurf des Formulars <b>frmSVGDraw<\/b> wenig &uuml;berraschungen bereit. Das ungebundene Webbrowser-Steuerelement <b>ctlIE<\/b> hat den Steuerelementinhalt <b>=&#8220;about:blank&#8220;<\/b>  damit es sich mit leerer Seite &ouml;ffnet und ist auf die <b>Verankerung<\/b> <b>Quer und nach unten dehnen<\/b> eingestellt. Die Verankerung der Button-Reihe steht dagegen auf <b>Unten links<\/b>, die der restlichen Steuerelemente f&uuml;r die Malwerkzeuge auf <b>Oben rechts<\/b>. Bild 5 gibt die Anordnung wieder.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_04\/frmSVGDraw_DS.png\" alt=\"Die Entwurfsansicht der Malanwendung frmSVGDraw zeigt zentral das Webbrowsersteuerelement und rechts die Zeichenwerkzeuge.\" width=\"700\" height=\"432,2948\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Die Entwurfsansicht der Malanwendung frmSVGDraw zeigt zentral das Webbrowsersteuerelement und rechts die Zeichenwerkzeuge.<\/span><\/b><\/p>\n<p>Zwei eingesetzte Steuerelemente bed&uuml;rfen wohl der Erl&auml;uterung. Die horizontalen Schieberegler etwa finden Sie nicht im Umfang von Access selbst. Es handelt sich hier um <b>ActiveX<\/b>-Elemente, horizontale Scrollbars, aus der Sammlung der <b>MSForms<\/b>-Steuerelemente, die grunds&auml;tzlich mit jeder Office-Version installiert werden. Nach dem Einsetzen des <b>ActiveX<\/b>-Steuerelements begeben Sie sich zum Eigenschaftenblatt und stellen unter dem Reiter <b>Andere<\/b> den Eintrag <b>Orientation<\/b> auf den Wert <b>Horizontal<\/b> und die <b>Min\/Max<\/b>-Werte auf <b>0<\/b> bis <b>100<\/b>. Das Bewegen eines Schiebers l&ouml;st das Ereignis <b>Change<\/b> aus, auf das im Formularmodul in der zugeh&ouml;rigen Ereignisprozedur reagiert wird:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>ctlTransparent_Change()\r\n     m_Transparency = 100 - ctlTransparent.Value\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die Modulvariable <b>m_Transparency<\/b> erh&auml;lt nun den negierten Wert, den das Steuerelement <b>ctlTransparent<\/b> zur&uuml;ckgibt. F&uuml;r das Farbspektrum rechts verwenden wir ein <b>MSForms-Image<\/b>-Steuerelement. Das wird beim Laden des Formulars schlicht mit einer vorgefertigten Bilddatei <b>colors.jpg<\/b> versehen. Diese werden Sie im Projektordner indessen vergeblich suchen, denn sie ist tats&auml;chlich in der Systemtabelle <b>MSysResources<\/b> abgespeichert, die f&uuml;r Grafiken auf Steuerelementen vorgesehen ist, aber ebenso manuell mit Dateien best&uuml;ckt werden kann. Ein <b>MSForms-Image<\/b> kann sein Bild allerdings nicht direkt aus dieser Tabelle beziehen. Hier ist etwas Zusatzprogrammierung angesagt. Beim Laden des Formulars wird unter anderen diese Zeile durchlaufen:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> Me!ctlImgColors.Object.Picture = _\r\n                  ArrayToPicture(GetColorTableJPG)<\/pre>\n<p><!--30percent--><\/p>\n<p>Das <b>Picture<\/b>-Objekt f&uuml;r das Steuerelement errechnet sich hier &uuml;ber zwei Hilfsfunktionen. <b>GetColorTableJPG<\/b> entnimmt der Systemtabelle die Bin&auml;rdaten des Bilds und gibt sie als <b>Byte-Array <\/b>zur&uuml;ck:<\/p>\n<pre><span style=\"color:blue;\">Function <\/span>GetColorTableJPG()<span style=\"color:blue;\"> As Byte<\/span>()\r\n     GetColorTableJPG = CurrentDb.OpenRecordset( _\r\n         \"SELECT BLOB FROM MSysResources WHERE Id=4\", _\r\n         dbOpenDynaset)(0).Value\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Aus dem <b>Byte-Array<\/b> nun ein <b>StdPicture<\/b>-Objekt zu machen, ist nat&uuml;rlich eine wesentlich schwierigere Angelegenheit. Hier kommt mit der Funktion <b>ArrayToPicture<\/b> wieder einmal eine <b>GDIPlus-API<\/b>-Routine zum Einsatz, welche sich im Modul <b>mdlGDIPSpecial<\/b> versteckt.<\/p>\n<p>Auf die Funktionsweise des Moduls k&ouml;nnen wir an dieser Stelle nicht eingehen. Der Klick auf einen Punkt im Spektrum-Image l&ouml;st nun das Ereignis <b>MouseDown<\/b> aus. In dieser Ereignisprozedur muss die Farbe unter dem Mauszeiger bestimmt werden. Das l&auml;sst sich mit einer einzigen API-Funktion leichter erledigen, als gedacht:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>ctlImgColors_MouseDown( _\r\n     ByVal Button<span style=\"color:blue;\"> As Integer<\/span>, ByVal Shift<span style=\"color:blue;\"> As Integer<\/span>, _\r\n     ByVal x<span style=\"color:blue;\"> As Single<\/span>, ByVal y<span style=\"color:blue;\"> As Single<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>lColor<span style=\"color:blue;\"> As Long<\/span>\r\n     lColor = GetCursorPixel(x, y)\r\n...\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b>GetCursorPixel<\/b> nimmt die vom Ereignis zur&uuml;ckgegebenen <b>x<\/b>&#8211; und <b>y<\/b>-Koordinaten des Bildschirms entgegen und ermittelt f&uuml;r sie die Pixel-Farbe als <b>RGB-Long-Wert<\/b>.<\/p>\n<p>Nebenbei sein noch erw&auml;hnt, dass Sie sich beim Webbrowser als Grafik-Engine nicht um die Skalierung von Bildern k&uuml;mmern m&uuml;ssen. Sind geladenen oder erzeugte Bilder gr&ouml;&szlig;er, als das Browser-Fenster, so blenden sich automatisch Scroll-Balken ein, mit denen Sie sich in die gew&uuml;nschten Bildteile hineinbewegen k&ouml;nnen, wie Bild 6 demonstriert. Das gilt f&uuml;r geladenen Pixel-Grafiken in gleicher Weise, wie f&uuml;r <b>SVG<\/b>-Vektorgrafiken. Beim Abspeichern der Bilder wird dann aber selbstverst&auml;ndlich die teilweise nicht sichtbare Gesamtfl&auml;che verwendet.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_04\/frmDraw_Scrollbars.png\" alt=\"Um die Einblendung von Scroll-Balken brauchen Sie sich beim Webbrowser-Steuerelement mit SVG-Grafik nicht zu k&uuml;mmern.\" width=\"700\" height=\"409,486\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Um die Einblendung von Scroll-Balken brauchen Sie sich beim Webbrowser-Steuerelement mit SVG-Grafik nicht zu k&uuml;mmern.<\/span><\/b><\/p>\n<h2>Programmierung des Anwendungsformulars<\/h2>\n<p>Beginnen wir chronologisch mit den Ereignisprozeduren des Formulars, von denen die <b>Form_Open<\/b>-Prozedur die erste ist. Sie belegt lediglich einige modulweite <b>Member<\/b>-Variablen mit Vorgabewerten etwa zur Linienbreite oder F&uuml;llfarbe. Mit <b>Form_Load<\/b> geht es dann richtig los. Das Webbrowser-Steuerelement wird angewiesen, ein leeres Dokument zu laden, und in diesem werden, &auml;hnlich wie bei den <b>SVG<\/b>-Diagrammen, ein g&uuml;ltiges <b>head<\/b>&#8211; sowie <b>svg<\/b>-Element angelegt. Die Breite und H&ouml;he der <b>SVG<\/b>-Fl&auml;che werden dabei nicht auf einen fixen Wert eingestellt, sondern auf <b>100%<\/b>, damit sich die Fl&auml;che sp&auml;ter bei Gr&ouml;&szlig;en&auml;nderung des verankerten Webbrowsers entsprechend ausdehnt. Zus&auml;tzlich erh&auml;lt das Dokument einen <b>JavaScript<\/b>-Block:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> oElement = oDoc.createElement(\"script\")\r\n<span style=\"color:blue;\">With<\/span> oElement\r\n     .type = \"text\/javascript\"\r\n     .Text = \"function turbfreq(v){ _\r\n                document.getElementById(''''turbfilter''''). _\r\n                   setAttribute (''''baseFrequency'''', v);} \"\r\n                ...\r\nEnd <span style=\"color:blue;\">With<\/span>\r\noDoc.head.appendChild oElement<\/pre>\n<p>Ein <b>JavaScript<\/b> kann &uuml;ber das Tag <b>script<\/b> dynamisch neu in einem HTML-Dokument erzeugt werden, wobei ihm dessen Code &uuml;ber die Eigenschaft Text des Elements zugewiesen wird. Das Script enth&auml;lt einige Funktionen, &uuml;ber die die Parameter der <b>SVG<\/b>-Filter zur Laufzeit gesteuert werden k&ouml;nnen.<\/p>\n<p>Im Beispiel ist das der Turbulenzeffekt, dessen Parameter <b>baseFrequency<\/b> in Abh&auml;ngigkeit vom &uuml;bergebenen Wert in <b>v<\/b> belegt wird. Die <b>JavaScript<\/b>-Funktion k&ouml;nnen Sie direkt aus VBA heraus aufrufen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>ctlTurb_Change()\r\n     oDoc.parentWindow.execScript CStr(\"turbfreq(\" & _\r\n           <span style=\"color:blue;\">Replace<\/span>(CStr(Me!ctlTurb.Value \/ 1000), _\r\n           \",\", \".\") & \")\")\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Das ist die Ereignisprozedur, die ausgel&ouml;st wird, wenn Sie den Slider f&uuml;r die Turbulenz verschieben. Der Wert des ActiveX-Steuerelements (<b>Value<\/b>) wird verwendet, um etwa diese Zeile zu generieren, wenn er <b>55<\/b> betr&auml;gt:<\/p>\n<pre>turbfreq(0.055);<\/pre>\n<p>Die Methode <b>execScript<\/b> eines <b>HTMLWindow<\/b>-Objekts, welches aus dem Dokument <b>oDoc<\/b> ermittelt wird, ruft diese Zeile schlie&szlig;lich auf.<\/p>\n<p>Dieses Gemisch aus VBA und <b>JavaScript<\/b> mag etwas verwirrend sein, demonstriert jedoch, wie beide Sprachen kombiniert werden k&ouml;nnen, wenn eine allein nicht reicht. Das ist hier der Fall, weil es nicht gelang, den Turbulenz-Parameter direkt &uuml;ber VBA und ein <b>SVG-Effekt<\/b>-Objekt zu setzen.<\/p>\n<p>Die <b>SVG<\/b>-Filter und ihre Effekte selbst werden in einer gesonderten Routine <b>CreateFilterGroup<\/b> angelegt. Wie das geht, erfuhren Sie bereits im Betrag zu den <b>SVG<\/b>-Diagrammen, wo f&uuml;r die Texte des Tortendiagramms ein <b>Dropshadow<\/b>-Effekt generiert wurde. Hier funktioniert das auf &auml;hnliche Weise, nur sind es hier eben wesentlich mehr Filter, die dem Weichzeichnen der Linien und der Turbulenz dienen, weshalb der Umfang der Prozedur so gro&szlig; wurde, dass wir sie hier nicht abbilden. Alle Filter werden hier &uuml;brigens in einer <b>SVG-Elementgruppe<\/b> zusammengefasst, die Sie &uuml;ber das <b>Tag<\/b> <b>g<\/b> erzeugen k&ouml;nnen. Dieses Gruppenobjekt wird schlie&szlig;lich als Kindelement dem allgemeinen <b>SVG<\/b>-Objekt angeh&auml;ngt.<\/p>\n<p>Bevor es mit dem Zeichnen losgehen kann, tritt noch das Ereignis <b>Beim Anzeigen<\/b> f&uuml;r den aktuellen Datensatz auf den Plan. Enth&auml;lt dieser bereits ein zuvor gemaltes Bild im Feld <b>BildOLE<\/b>, so soll dieses geladen werden. Andernfalls soll eine leere Zeichenfl&auml;che entstehen. Das ermittelt die Prozedur anhand der L&auml;nge (<b>Len<\/b>) des Feldinhalts (siehe Listing 1). Ist diese <b>0<\/b>, so liest sie den <b>HTML<\/b>-Text aus dem Feld aus und schreibt ihn &uuml;ber die VBA-Methode <b>CallByName<\/b> in das Dokument. Das ist deshalb n&ouml;tig, weil die <b>write<\/b>-Methode eines <b>HTMLDocument<\/b>-Objekts leider einen zu VBA inkompatiblen Datentyp als Parameter erwartet, weshalb beim Kompilieren ein Fehler auftr&auml;te. Die abschlie&szlig;end aufgerufene Hilfsroutine <b>SetPathCounter<\/b> setzt den <b>SVG<\/b>-Elementz&auml;hler, welcher sich in der Modulvariablen <b>pathcounter<\/b> repr&auml;sentiert, auf die Zahl der <b>SVG<\/b>-Elemente, welche sich bereits in der Grafik befinden:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Current()\r\n     Form_Load\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(Me!BildOLE.Value) &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n         CallByName Me!ctlIE.Object.Document, _\r\n             \"write\", VbMethod, Me!BildOLE.Value\r\n         <span style=\"color:blue;\">Set<\/span> oDoc = Me!ctlIE.Object.Document\r\n         DoEvents\r\n         SetPathCounter\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Anzeigen einer bestehenden SVG-Grafik in Form_Current<\/span><\/b><\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>SetPathCounter()\r\n     <span style=\"color:blue;\">Dim <\/span>i<span style=\"color:blue;\"> As Long<\/span>\r\n         \r\n     <span style=\"color:blue;\">Set<\/span> oSVG = oDoc.getElementById(\"zeichnung\")\r\n     i = oSVG.getElementsByTagName(\"polyline\").Length\r\n     i = i + oSVG.getElementsByTagName(\"polygon\").Length\r\n     pathcounter = i + 1\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Das Objekt <b>oSVG<\/b> wird aus der SVG-Fl&auml;che, die die <b>id zeichnung<\/b> besitzt, erhalten. Die Zahl der <b>polyline<\/b>-Elemente kann dann ganz einfach &uuml;ber die Eigenschaft <b>length<\/b> auf die Auflistung erhalten werden, die <b>getElementsByTagName<\/b> zur&uuml;ckgibt. Da die Zeichnung au&szlig;erdem <b>polygon<\/b>-Elemente enthalten kann, muss deren Zahl hinzuaddiert werden. <b>pathcounter<\/b> ist n&auml;mlich ein Z&auml;hler, der f&uuml;r neue <b>SVG<\/b>-Elemente beim Zeichnen benutzt wird, um deren <b>id<\/b> zu generieren. Das erste Zeichenelement bekommt die <b>ID draw1<\/b>, das zweite die <b>ID draw2<\/b>, und so weiter. Damit k&ouml;nnen alle Elemente sp&auml;ter eindeutig identifiziert werden. Enth&auml;lt eine vorliegende Zeichnung etwa bereits <b>38<\/b> Polygonz&uuml;ge, so stellt sich mit <b>SetPathCounter<\/b> der Z&auml;hler auf <b>39<\/b> ein, so dass das n&auml;chste Element die <b>ID draw39 <\/b>bekommt. Eine bestehende Grafik kann so also problemlos weiterbearbeitet werden. Zus&auml;tzlich kann das letzte Element per <b>Undo<\/b>-Button gel&ouml;scht werden, indem der <b>pathcounter<\/b> um eins zur&uuml;ckgesetzt wird:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdUndo_Click()\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     oSVG.getElementById(\"draw\" & _\r\n              CStr(pathcounter - 1)).removeNode\r\n     <span style=\"color:blue;\">If <\/span>Err.Number = 0<span style=\"color:blue;\"> Then<\/span> pathcounter = pathcounter - 1\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Hier wird zur Sicherheit noch ermittelt, ob es ein Element mit der betreffenden <b>id<\/b> &uuml;berhaupt gibt. <b>Err.Number<\/b> hat sonst einen Wert abweichend von <b>0<\/b>, und nur im Erfolgsfall wird <b>pathcounter<\/b> herabgesetzt.<\/p>\n<h2>Zeichenroutinen<\/h2>\n<p>Es gibt zwei Ereignisse, die beim Malen mit der Maus verwendet werden. Das mit <b>WithEvents<\/b> deklarierte <b>SVG<\/b>-Element <b>oSVG<\/b> l&ouml;st diese aus. Es handelt sich um <b>onmousemove<\/b> beim Bewegen des Mauszeigers und um <b>onmouseup<\/b> beim Loslassen der Maustaste.<\/p>\n<p>Die auf das Wesentliche gek&uuml;rzte Prozedur f&uuml;r <b>onmousemove<\/b> zeigt Listing 2. Hier wird wieder die linke Maustaste &uuml;ber das <b>Event<\/b>-Objekt identifiziert, wenn dessen Eigenschaft <b>Button<\/b> den Wert <b>1<\/b> hat. Dann kommt der <b>pathcounter<\/b> ins Spiel. Das zu dessen Wert im Verein mit <b>draw<\/b> geh&ouml;rige Element wir der Variablen <b>oSVGElement<\/b> zugewiesen. Gibt es ein solches Element noch nicht, was der Test auf <b>Nothing<\/b> entscheidet, so wird ein neues Element mit dieser <b>id<\/b> angelegt.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>oSVG_onmousemove()\r\n     <span style=\"color:blue;\">Dim <\/span>oSVGElement<span style=\"color:blue;\"> As <\/span>SVGElement\r\n     <span style=\"color:blue;\">Dim <\/span>oPoint<span style=\"color:blue;\"> As <\/span>SVGPoint\r\n         \r\n     <span style=\"color:blue;\">Set<\/span> oEvent = oDoc.parentWindow.event\r\n     <span style=\"color:blue;\">If <\/span>oEvent.Button = 1<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">Set<\/span> oSVGElement = oDoc.getElementById(\"draw\" & CStr(pathcounter))\r\n         <span style=\"color:blue;\">If <\/span>oSVGElement Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">Set<\/span> oSVGElement = oDoc.createElementNS( _\r\n                     \"http:\/\/www.w3.org\/2000\/svg\", IIf(m_Fill, \"polygon\", \"polyline\")\r\n             oSVGElement.setAttribute \"id\", \"draw\" & CStr(pathcounter)\r\n             <span style=\"color:blue;\">With<\/span> oSVGElement.Style\r\n                 .setAttribute \"stroke\", ColorToStr(m_Color)\r\n                 .setAttribute \"stroke-width\", CStr(m_LineWidth)\r\n                 <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> m_Fill<span style=\"color:blue;\"> Then<\/span> .setAttribute \"fill\", \"none\" _\r\n                               <span style=\"color:blue;\">Else<\/span> .setAttribute \"fill\", ColorToStr(m_FillColor)\r\n                 Select Case m_LineType\r\n                 <span style=\"color:blue;\">Case <\/span>2: .setAttribute \"stroke-dasharray\", \"2,2\"\r\n                 <span style=\"color:blue;\">Case <\/span>3: .setAttribute \"stroke-dasharray\", \"5,3\"\r\n                 <span style=\"color:blue;\">End Select<\/span>\r\n                 .setAttribute \"opacity\", <span style=\"color:blue;\">Replace<\/span>(CStr(m_Transparency \/ 100), \",\", \".\")\r\n                 <span style=\"color:blue;\">If <\/span>m_Shadow<span style=\"color:blue;\"> Then<\/span> .setAttribute \"filter\", \"url(#shadow)\"\r\n                 <span style=\"color:blue;\">If <\/span>m_Soft<span style=\"color:blue;\"> Then<\/span> .setAttribute \"filter\", \"url(#blur)\"\r\n                 <span style=\"color:blue;\">If <\/span>m_Turbulence<span style=\"color:blue;\"> Then<\/span> .setAttribute \"filter\", \"url(#turb)\"\r\n             End <span style=\"color:blue;\">With<\/span>\r\n             <span style=\"color:blue;\">Set<\/span> oPoint = oSVG.createSVGPoint\r\n             oPoint.x = oEvent.offsetX: oPoint.y = oEvent.OffsetY\r\n             oSVGElement.Points.appendItem oPoint\r\n             oSVG.appendChild oSVGElement\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             <span style=\"color:blue;\">Set<\/span> oPoint = oSVG.createSVGPoint\r\n             oPoint.x = oEvent.offsetX: oPoint.y = oEvent.OffsetY\r\n             oSVGElement.Points.appendItem oPoint\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         oDoc.releaseCapture\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Beim Bewegen des Mauszeigers &uuml;ber die SVG-Fl&auml;che generiert diese Prozedur die Polygone.<\/span><\/b><\/p>\n<p>Dabei kommt es darauf an, ob die Checkbox <b>F&uuml;llen<\/b> des Formulars aktiviert ist. Die Member-Variable <b>m_Fill<\/b> steht dann auf <b>True<\/b>. Dann n&auml;mlich muss ein <b>polygon<\/b>-Element erzeugt werden, im anderen Fall ein <b>polyline<\/b>-Element, weil letzteres, da nicht geschlossen, keine F&uuml;llung aufweisen kann.<\/p>\n<p>Anschlie&szlig;end werden mehrere Attribute des Elements gesetzt, wie die Malfarbe &uuml;ber die <b>Style<\/b>-Eigenschaft <b>stroke<\/b>, oder die Linienbreite per <b>stroke-width<\/b>. Die Linienart steht in <b>stroke-dasharray<\/b>, die Transparenz in <b>opacity<\/b>. Die Werte all dieser Attribute leitet sich von den Steuerelementen des Formulars ab, deren Einstellungen wiederum <b>Member<\/b>-Variablen zugewiesen sind. Ob ein Filter auf einen Polygonzug angewandt wird, entscheiden die drei folgenden Bedingungen, die, falls zutreffend, das Attribut <b>filter<\/b> des Elements auf einen der zuvor definierten globalen Effekte setzt.<\/p>\n<p>Ganz egal, ob das Element nun schon existierte oder neu angelegt wurde, das Bewegen der Maus muss eine neue Koordinate am Punkt der Mausbewegung erzeugen. Das geschieht &uuml;ber die Methode <b>createSVGPoint<\/b>, die hier ausnahmsweise <b>createSVGElementNS<\/b> ersetzt. Die <b>x<\/b>&#8211; und <b>y<\/b>-Werte des Punkts <b>oPoint<\/b> leiten sich aus der Koordinate des <b>Event<\/b>-Objekts (<b>OffsetX<\/b>, <b>OffsetY<\/b>) ab. Der Punkt wird der Auflistung <b>Points<\/b> des <b>SVG<\/b>-Elements per <b>appendItem<\/b> hinzugef&uuml;gt, was bei <b>polyline<\/b>-, wie <b>polygon<\/b>-Elementen, gleicherma&szlig;en funktioniert. Das abschlie&szlig;ende <b>releaseCapture<\/b> auf das <b>HTML<\/b>-Dokument ist zwingend erforderlich, damit das Browser-Fenster neue Events entgegennehmen und damit neue Mausbewegungen abfangen kann.<\/p>\n<p>Wird die linke Maustaste losgelassen, so kommt es zum Ereignis <b>onmouseup<\/b>. Dann soll der Polygonzug beendet werden:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>oSVG_onmouseup()\r\n     <span style=\"color:blue;\">Set<\/span> oEvent = oDoc.parentWindow.event\r\n     <span style=\"color:blue;\">If <\/span>oEvent.Button = 1<span style=\"color:blue;\"> Then<\/span>\r\n         pathcounter = pathcounter + 1\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Tats&auml;chlich passiert hier weiter nichts, als dass der Z&auml;hler <b>pathcounter<\/b> um eins erh&ouml;ht wird &#8211; das <b>SVG<\/b>-Element ist ja bereits erzeugt. Beim n&auml;chsten Bewegen der Maus mit gedr&uuml;ckter linker Maustaste wird die <b>onmousemove<\/b>-Prozedur aber erkennen, dass das Element mit der zum neuen <b>pathcounter<\/b>-Wert geh&ouml;rigen <b>id<\/b> noch nicht existiert und ein neues anlegen.<\/p>\n<p>Unglaublich, aber wahr: Das ist imgrunde auch schon alles, was f&uuml;r das Zeichnen der Figuren ben&ouml;tigt wird. Ein Polygonzug pr&auml;sentiert sich im fertigen Dokument dann etwa dergestalt:<\/p>\n<pre>&lt;polyline id=\"draw16\" style=\"opacity: 1; fill: none; stroke: #000000; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1;\" points=\"153,108 153,108 153,109 155,112 155,114 155,117\" \/&gt;<\/pre>\n<p>Die Koordinaten sind durch Leerzeichen getrennt und die <b>x\/y<\/b>-Werte durch Kommas.<\/p>\n<p>Bliebe noch die Integration von Bilddateien in das <b>SVG<\/b>-Dokument, wie in Bild 7. Nach dem Laden einer <b>JPG<\/b>-Datei &uuml;ber den Button <b>Bild einf&uuml;gen&#8230;<\/b> kann die Grafik beliebig weiterverarbeitet werden. In der Abbildung wurden einige Schlangenlinien &uuml;ber das Bild gelegt. Der Button l&ouml;st die Ereignisprozedur in Listing 3 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_04\/frmDraw_LoadImage.png\" alt=\"Auch Bilddateien k&ouml;nnen in die SVG-Grafik geladen und mit dem Zeichenwerkzeug weiterverarbeitet und &uuml;bermalt werden.\" width=\"700\" height=\"455,3152\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Auch Bilddateien k&ouml;nnen in die SVG-Grafik geladen und mit dem Zeichenwerkzeug weiterverarbeitet und &uuml;bermalt werden.<\/span><\/b><\/p>\n<p>&uuml;ber die Hilfsfunktion <b>GetOpenFileDialog<\/b> des Moduls <b>mdlHelper<\/b>, die einen <b>Datei &ouml;ffnen<\/b>-Dialog l&auml;dt, k&ouml;nnen Sie eine <b>JPG<\/b>-Datei ausw&auml;hlen. Die <b>Picture<\/b>-Variable <b>oPic<\/b> wird dann zun&auml;chst &uuml;ber die Funktion <b>LoadPicture<\/b> erzeugt, wobei diese tempor&auml;r nur daf&uuml;r verwendet wird, um die Abmessungen des Bilds &uuml;ber <b>Width<\/b> und <b>Height<\/b> zu ermitteln. Hier ist allerdings eine Umrechnung von der Einheit <b>OLEHiMetric<\/b> in <b>Pixel<\/b> vorzunehmen, was ungef&auml;hr &uuml;ber den Faktor <b>0.0378<\/b> geschieht.<\/p>\n<p>Der Inhalt der Datei kommt nun &uuml;ber <b>Open-Get <\/b>in ein Byte-Array <b>bin<\/b>. Und dann wird ein <b>SVG<\/b>-Bildelement (<b>image<\/b>) erzeugt und ihm das Byte-Array <b>base64<\/b>-kodiert als Hexadezimal-String im Attribut <b>href<\/b> verabreicht, wie dies auch schon bei den <b>SVG<\/b>-Diagrammen erl&auml;utert wurde.<\/p>\n<p>Bevor es weitergehen kann, muss noch abgewartet werden, bis das Bild im Browser fertig gerendert ist. Das l&auml;sst sich mit der Eigenschaft <b>ReadyState<\/b> abfragen, die auf <b>complete<\/b> stehen muss. Anschlie&szlig;end k&ouml;nnen weitere Attribute auf das Bildobjekt abgesetzt werden, wie dessen Transparenz &uuml;ber das <b>Style<\/b>-Attribut <b>opacity<\/b>.<\/p>\n<p>Im Prinzip w&auml;ren wir damit fertig, doch in das Klassenmodul ist noch ein zus&auml;tzliches Feature eingebaut: Das Bild soll an einer durch die Maus bestimmten Koordinate abgelegt werden. Die Modulvariable <b>clickwait<\/b> wird dazu auf den Wert <b>True<\/b> gesetzt und der Maus-Cursor mit <b>style.cursor<\/b> in ein Kreuz verwandelt. Die folgende Schleife mit ihrem <b>DoEvents<\/b> l&auml;uft anschlie&szlig;end so lange, bis <b>clickwait<\/b> den Wert False besitzt. Diese &auml;nderung geschieht n&auml;mlich dann, wenn die Maustaste losgelassen wird, was wir in der obigen Version der Ereignisprozedur <b>onmouseup<\/b> unterschlagen hatten:<\/p>\n<pre>...\r\n     <span style=\"color:blue;\">If <\/span>clickwait<span style=\"color:blue;\"> Then<\/span>\r\n         m_x = oEvent.offsetX: m_y = oEvent.OffsetY\r\n         clickwait = <span style=\"color:blue;\">False<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         pathcounter = pathcounter + 1\r\n     <span style=\"color:blue;\">End If<\/span>\r\n...<\/pre>\n<p>Die Member-Variablen <b>m_x<\/b> und <b>m_y<\/b> stellen sich hier auf die vom <b>Event<\/b>-Objekt erhaltene Koordinate ein und <b>clickwait<\/b> wird zur&uuml;ckgesetzt. Dadurch wird die Schleife in <b>Listing 3<\/b> verlassen. Nun kann die Position des Bilds im Dokument durch Setzen der Attribute <b>x<\/b> und <b>y<\/b> auf die Werte in <b>m_x<\/b> und <b>m_y<\/b> eingestellt werden.<\/p>\n<h2>Abspeichern und Exportieren der Grafik<\/h2>\n<p>Das Abspeichern des Dokuments in die Tabelle <b>tblBilderDraw<\/b> ist schnell erledigt, da es sich nicht um eine Pixel-Grafik handelt:<\/p>\n<pre>Me!BildOLE.Value = oDoc.all(0).outerHTML<\/pre>\n<p>Hiermit erhalten Sie den kompletten <b>HTML<\/b>-Text.<\/p>\n<p>Schwieriger wird es hingegen mit dem Export in eine Bilddatei. Dieses Problem hatten wird bereits bei den <b>SVG<\/b>-Diagrammen. Hier greifen wir zur gleichen Methode, wie dort, und verwenden die API-Funktion <b>OleDraw<\/b>, die von der Prozedur <b>SaveOLEToImageFile<\/b> im Modul <b>mdlGDIPSpecial<\/b> verwendet wird. Sie wird auch beim Abspeichern in die Zwischenablage &uuml;ber den entsprechenden Button im Formular aufgerufen.<\/p>\n<p>Wie es sich mit dem Speicherbedarf f&uuml;r die Grafiken verh&auml;lt, demonstriert die Abfrage in Bild 8, die &uuml;ber die <b>Len<\/b>-Funktion die Byte-L&auml;nge des Felds <b>BildOLE<\/b> der Tabelle in der Spalte <b>Size<\/b> ausgibt. Sie erkennen, dass das Urwald-Bild mit dem eingebetteten Bitmap (siehe oben) mit Abstand am gr&ouml;&szlig;ten ist.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_04\/qry_SVGBildgroessen_RT.png\" alt=\"Dies Abfrage zeigt die Gr&ouml;&szlig;e der gespeicherten SVG-Grafiken.\" width=\"425\" height=\"188,8889\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Dies Abfrage zeigt die Gr&ouml;&szlig;e der gespeicherten SVG-Grafiken.<\/span><\/b><\/p>\n<h2>Zusammenfassung<\/h2>\n<p>Wir konnten unsere <b>SVG<\/b>-Zeichenanwendung hier nur ziemlich komprimiert beschreiben. F&uuml;r das Verst&auml;ndnis ben&ouml;tigen Sie nicht nur gute VBA-Kenntnisse, sondern sollten sich zus&auml;tzlich mit dem <b>MSHTML<\/b>-Objektmodell auskennen, dem Webbrowser-Steuerelement, rudiment&auml;r mit <b>JavaScript<\/b> und schlie&szlig;lich mit <b>SVG<\/b> selbst. Dies alles l&auml;sst sich nun mal nicht in einem einzigen Beitrag vermitteln. Der begleitende Artikel zu <b>SVG<\/b>-Diagrammen erl&auml;utert aber zus&auml;tzlich so einiges, genauso, wie unsere beiden Beitr&auml;ge zu <b>HTML5 als Grafikkomponente<\/b>.<\/p>\n<p>&uuml;brigens ist die Anwendung noch verbesserungsw&uuml;rdig. Statt <b>polyline<\/b> und <b>polygon<\/b> w&auml;re das Element <b>path<\/b> zum Zeichnen an sich besser geeignet, weil sich mit diesem <b>Bezier<\/b>-Kurven anlegen lassen, die die Linienz&uuml;ge abrunden w&uuml;rden. Der Aufwand f&uuml;r das Erzeugen derselben w&auml;re aber nochmals etwas h&ouml;her gewesen.<\/p>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>europa.svg<\/p>\n<p>SVGImageII.accdb<\/p>\n<p>tulpe.jpg<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/CF0983BA-DFF9-49AA-A3C9-AB778A7CDA18\/aiu_1138.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Obwohl es sich bei SVG um Vektorgrafiken handelt, k&ouml;nnen Sie diese ebenfalls interaktiv mit der Maus in ein Webbrowser-Steuerelement zeichnen. Das Verfahren hat gegen&uuml;ber den Pixel-Grafiken von HTML5 sogar noch einige Vorz&uuml;ge, die die hier vorgestellte L&ouml;sung anbietet und erl&auml;utert. Mit keiner anderen Methode lassen sich auf so einfache Weise Grafiken erzeugen und in Tabellen abspeichern.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[662018,66042018,44000023],"tags":[],"class_list":["post-55001138","post","type-post","status-publish","format-standard","hentry","category-662018","category-66042018","category-Mit_Formularen_arbeiten"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Malen und Zeichnen mit SVG - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Malen und Zeichnen mit SVG\" \/>\n<meta property=\"og:description\" content=\"Obwohl es sich bei SVG um Vektorgrafiken handelt, k&ouml;nnen Sie diese ebenfalls interaktiv mit der Maus in ein Webbrowser-Steuerelement zeichnen. Das Verfahren hat gegen&uuml;ber den Pixel-Grafiken von HTML5 sogar noch einige Vorz&uuml;ge, die die hier vorgestellte L&ouml;sung anbietet und erl&auml;utert. Mit keiner anderen Methode lassen sich auf so einfache Weise Grafiken erzeugen und in Tabellen abspeichern.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2020-05-13T21:11:16+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg06.met.vgwort.de\/na\/f7a88e036be3455380555d5fa1887bce\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"22\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Malen_und_Zeichnen_mit_SVG\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Malen_und_Zeichnen_mit_SVG\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Malen und Zeichnen mit SVG\",\"datePublished\":\"2020-05-13T21:11:16+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Malen_und_Zeichnen_mit_SVG\\\/\"},\"wordCount\":3944,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Malen_und_Zeichnen_mit_SVG\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/f7a88e036be3455380555d5fa1887bce\",\"articleSection\":[\"2018\",\"4\\\/2018\",\"Mit Formularen arbeiten\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Malen_und_Zeichnen_mit_SVG\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Malen_und_Zeichnen_mit_SVG\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Malen_und_Zeichnen_mit_SVG\\\/\",\"name\":\"Malen und Zeichnen mit SVG - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Malen_und_Zeichnen_mit_SVG\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Malen_und_Zeichnen_mit_SVG\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/f7a88e036be3455380555d5fa1887bce\",\"datePublished\":\"2020-05-13T21:11:16+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Malen_und_Zeichnen_mit_SVG\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Malen_und_Zeichnen_mit_SVG\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Malen_und_Zeichnen_mit_SVG\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/f7a88e036be3455380555d5fa1887bce\",\"contentUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/f7a88e036be3455380555d5fa1887bce\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Malen_und_Zeichnen_mit_SVG\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Malen und Zeichnen mit SVG\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Malen und Zeichnen mit SVG - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/","og_locale":"de_DE","og_type":"article","og_title":"Malen und Zeichnen mit SVG","og_description":"Obwohl es sich bei SVG um Vektorgrafiken handelt, k&ouml;nnen Sie diese ebenfalls interaktiv mit der Maus in ein Webbrowser-Steuerelement zeichnen. Das Verfahren hat gegen&uuml;ber den Pixel-Grafiken von HTML5 sogar noch einige Vorz&uuml;ge, die die hier vorgestellte L&ouml;sung anbietet und erl&auml;utert. Mit keiner anderen Methode lassen sich auf so einfache Weise Grafiken erzeugen und in Tabellen abspeichern.","og_url":"https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/","og_site_name":"Access im Unternehmen","article_published_time":"2020-05-13T21:11:16+00:00","og_image":[{"url":"http:\/\/vg06.met.vgwort.de\/na\/f7a88e036be3455380555d5fa1887bce","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"22\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Malen und Zeichnen mit SVG","datePublished":"2020-05-13T21:11:16+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/"},"wordCount":3944,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/#primaryimage"},"thumbnailUrl":"http:\/\/vg06.met.vgwort.de\/na\/f7a88e036be3455380555d5fa1887bce","articleSection":["2018","4\/2018","Mit Formularen arbeiten"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/","url":"https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/","name":"Malen und Zeichnen mit SVG - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/#primaryimage"},"thumbnailUrl":"http:\/\/vg06.met.vgwort.de\/na\/f7a88e036be3455380555d5fa1887bce","datePublished":"2020-05-13T21:11:16+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/#primaryimage","url":"http:\/\/vg06.met.vgwort.de\/na\/f7a88e036be3455380555d5fa1887bce","contentUrl":"http:\/\/vg06.met.vgwort.de\/na\/f7a88e036be3455380555d5fa1887bce"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Malen_und_Zeichnen_mit_SVG\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Malen und Zeichnen mit SVG"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001138","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55001138"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001138\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001138"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001138"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001138"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}