Malen und Zeichnen mit SVG

Lies diesen Artikel und viele weitere mit einem kostenlosen, einwöchigen Testzugang.

Obwohl es sich bei SVG um Vektorgrafiken handelt, können Sie diese ebenfalls interaktiv mit der Maus in ein Webbrowser-Steuerelement zeichnen. Das Verfahren hat gegenüber den Pixel-Grafiken von HTML5 sogar noch einige Vorzüge, die die hier vorgestellte Lösung anbietet und erläutert. Mit keiner anderen Methode lassen sich auf so einfache Weise Grafiken erzeugen und in Tabellen abspeichern.

Referenz

Die Ausführungen dieses Beitrags setzen jene aus dem Artikel SVG als Grafikkomponente in dieser Ausgabe fort. Dort sind bereits die Grundlagen zum Einsatz des Webbrowser-Steuerelements im Verein mit SVG beschrieben.

SVG-Zeichnen im Unterschied zur Alternative HTML5

Im Beitrag Malen und Zeichnen mit HTML5 veröffentlichten wir eine Beispielanwendung, über die Sie mit der Maus oder mit einem Grafiktablett in eine Zeichenfläche malen können. Die dabei entstehende Pixel-Grafik können Sie dabei in eine Bilddatei oder direkt binär in eine Tabelle abspeichern.

Hier bauen wir diese Anwendung nach und verwenden dabei SVG im Webbrowser-Steuerelement, wobei der Komfort des Malformulars noch etwas erhöht wird. Die Vorteile der SVG-Lösung lassen sich schnell aufzählen:

  • HTML5 erzeugt Pixel-Grafiken, die sich binär nur in einem der Standardformate abspeichern lassen. Verlustfreie Speicherung ermöglichen dabei nur die Formate BMP, PNG, TIFF und GIF. Der Speicherbedarf fällt dabei leider ziemlich hoch aus. Anders bei SVG, wo die Zeichnungen nur aus einer Liste von XML-Anweisungen bestehen, die erheblich weniger Bytes benötigen. Zudem lassen sich die SVG-Bilder beliebig hochskalieren.
  • Die Elemente der Zeichnung lassen sich in einer HTML5-Grafik später nicht mehr identifizieren. In einer SVG-Grafik ist das anders. Einzelne Elemente können Sie entfernen oder nachbearbeiten. Die vorliegende Malanwendung erlaubt so etwa ein schrittweises Undo.
  • SVG bringt von Haus aus Filtereffekte mit, die HTML5 nicht kennt. Zwar gibt es auch dort einen Shadow-Effekt, der einen Schattenwurf der Zeichenelemente zulässt, doch von den komplexen Filterkombinationen von SVG ist das alles weit entfernt.

Der einzige Nachteil besteht darin, dass SVG-Elemente zur Laufzeit vom Browser gerendert werden. Das beeinträchtigt natü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ösung ist ja auch nicht, unter Access ein vollwertiges Vektorgrafikprogramm zu realisieren – die Einsatzmöglichkeiten erwähnten wir im analogen HTML5-Beitrag.

SVG-Zeichenformular

Beschreiben wir zunächst die Bedienung des Zeichenformulars frmSVGDraw anhand von Bild 1. Im Zentrum befindet sich die Zeichenfläche in Gestalt eines Web-browser-Steuerelements, das verankert ist und sich damit bei Größenänderungen des Formulars entsprechend ausdehnt. Die anderen Elemente richten sich dagegen am rechten oder unteren Rand aus.

Zur Laufzeit entsteht im Formular beim Malen mit verschiedenen Werkzeugeinstellungen additiv eine speicherbare SVG-Grafik.

Bild 1: Zur Laufzeit entsteht im Formular beim Malen mit verschiedenen Werkzeugeinstellungen additiv eine speicherbare SVG-Grafik.

Das Formular ist an eine Tabelle tblBilderDraw gebunden, so dass Sie pro Datensatz jeweils eine Zeichnung anfertigen oder darstellen können. Das Laden der Grafiken geschieht automatisch beim Wechsel eines Datensatzes. Jedem Bild können Sie oben eine Bezeichnung vergeben. Mit dem Button Alles löschen versetzen Sie die Zeichenfläche in den Ursprungszustand und erhalten eine weiße Zeichenfläche. Bild speichern erst transferiert das Gemälde in die Tabelle, welches ansonsten beim Datensatzwechsel verloren ginge. Sie können es zudem wahlweise über In Datei speichern… als JPG-Datei oder mit Bild in Zwischenablage in selbige exportieren. Der Undo-Button mit dem blauen Pfeil macht den letzten Zeichenvorgang oder auch frühere rückgängig. Sobald Sie die linke Maustaste loslassen, wird intern ein SVG-path-Element angelegt, das den gemalten Polygonzug repräsentiert. Das Undo löscht dieses Element aus dem SVG-XML wieder und setzt einen Zähler herab. Ein erneutes Undo löscht dann das Element mit diesem Zähler.

Rechts können Sie die Linienart bestimmen, bevor Sie loszeichnen. Möglich sind durchgezogene Linienzüge, gepunktete oder gestrichelte. Die Breite der Linien kann aus der darunterliegenden Optionsgruppe gewählt werden. Welche Malfarbe dabei verwendet wird, kann mit Klick auf die Fläche Linienfarbe zugewiesen werden. Das öffnet den normalen Windows-Farbauswahldialog. Alternativ haben Sie aber auch die Möglichkeit, die Farbe aus dem Spektrum rechts auszuwählen. über diesem Spektrum befindet sich eine Optionsgruppe, die das Ziel der Farbauswahl angibt. Das L bezieht sich auf die Linienfarbe, das F auf die Füllfarbe und das H auf die Hintergrundfarbe.

Neben diesen Elementen können Sie mehrere Checkboxen bedienen. Ist Füllen aktiviert, so wird nicht nur ein Linienzug gezeichnet, sondern dieser automatisch geschlossen und mit einer einfarbigen Füllung versehen. Das geschieht bereits während des Malens! Die Formen in der Abbildung machen den Vorgang deutlich. Hier wurde der Schieberegler für die Transparenz eingesetzt. Befindet der sich ganz links, so werden sowohl Linien als auch wie Füllungen, opak, während das Verschieben nach rechts beides immer durchsichtiger macht. Auf diese Weise überlagern Sie verschiedene Formen sequenziell.

Ist die Checkbox Weich aktiv, so werden Linien und Ecken weichgezeichnet. Die Checkbox Schatten aktiviert selbigen, wobei mit dem Schieberegler dessen Ausdehnung geregelt werden kann. Schließlich können Sie noch die Checkbox Turbulenz 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üge, wie einige Formen in der Abbildung beweisen (siehe auch Bild 2).

Linienzüge können bei aktivierter Turbulenz verzerrt werden.

Bild 2: Linienzüge können bei aktivierter Turbulenz verzerrt werden.

Außerdem ist es über den Button Bilddatei einfügen… noch möglich, über einen Dateiauswahldialog eine JPG-Datei in die Zeichnung zu laden. Der Cursor über der Zeichenfläche ä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ügt. Ist ein Transparenzwert aktiviert, so wird auch diese Bilddatei transparent eingefügt.

Eine ganze Menge Features, die dieses Formular bereithält! Da sollte man wohl meinen, dass die Programmierung einen hohen Aufwand erfordert. Tatsächlich kommt die Formularklasse aber mit etwa 400 Zeilen VBA aus, ein Wert, der deutlich macht, wieviel Arbeit der Browser im Verein mit SVG uns da abnimmt. Wollten Sie dasselbe etwa mit dem Windows-GDI-API erreichen, so kämen Sie sicher auf einige Tausend Zeilen.

Tabelle zum Speichern

Die Tabelle tblBilderDraw, an die das Formular gebunden ist, hat den sehr einfachen Aufbau aus Bild 3. Genau genommen ist nur das Feld Bildname an das Textfeld Bezeichnung des Formulars gebunden, während der Inhalt der Grafik im Feld BildOLE per VBA abgespeichert wird. Der Name des Felds ist etwas irreführend, denn die Tabelle wurde schlicht aus der HTML5-Version der Malanwendung importiert. Dort kamen die Pixel binär tatsächlich in ein OLE-Feld. Hier aber haben wir es ja mit XML-Text zu tun, für den ein Memo-Feld besser passt.

Die Tabelle tblBilderDraw speichert nur die gemalten Grafiken und ihre Namen nebst ID.

Bild 3: Die Tabelle tblBilderDraw speichert nur die gemalten Grafiken und ihre Namen nebst ID.

Die mit Beispielen gefüllte Tabelle in der Datenblattansicht zeigt Bild 4. Sie erkennen sofort, dass es sich beim Inhalt von BildOLE um jeweils komplette HTML-Dokumente handelt, die sogar JavaScript enthalten. Die SVG-Anweisungen folgen erst am unteren Rand der Zeilen und leiten sich mit dem Tag ein. Wenn Sie sich den Inhalt einer solchen Datenblattzelle einmal in einen Texteditor kopieren, so wird folgender Aufbau deutlich: Das HTML-Dokument liefert zunächst Basisdefinitionen, an die sich ein Block JavaScript anschließt, welcher Steuerungsfunktionen für die SVG-Filter enthält. Dann folgt der SVG-Teil. Hier gibt es einen Block, der die SVG-Filter und -Effekte definiert. Erst dann kommen die eigentlichen Zeichenelemente, bei denen es sich um eine Reihe von polylines handelt.

In der Datenblattansicht der Tabelle tblBilderDraw wird deutlich, dass es sich bei den SVG-Grafiken um HTML-Anweisungen handelt.

Bild 4: In der Datenblattansicht der Tabelle tblBilderDraw wird deutlich, dass es sich bei den SVG-Grafiken um HTML-Anweisungen handelt.

Die Größe des in Bild 1 gezeigten Gemäldes beträgt im Feld BildOLE ungefähr 40 kB. Davon entfallen auf den immer gleichen HTML-Rumpf 3 kB. Also nehmen die polyline-Elemente den weitaus größten Teil ein. Da es sich hier um Text mit sich häufig wiederholenden Zahlen handelt, ließe sich das Feld im Bedarfsfall auch gut einer Textkompression unterziehen. Im Beitrag zur RTLCompression, die auch in der HTML5-Version zum Einsatz kommt, lernten Sie eine solche universelle Kompressionsroutine kennen.

Formularentwurf

Ans sich hält der Entwurf des Formulars frmSVGDraw wenig überraschungen bereit. Das ungebundene Webbrowser-Steuerelement ctlIE hat den Steuerelementinhalt =”about:blank” damit es sich mit leerer Seite öffnet und ist auf die Verankerung Quer und nach unten dehnen eingestellt. Die Verankerung der Button-Reihe steht dagegen auf Unten links, die der restlichen Steuerelemente für die Malwerkzeuge auf Oben rechts. Bild 5 gibt die Anordnung wieder.

Die Entwurfsansicht der Malanwendung frmSVGDraw zeigt zentral das Webbrowsersteuerelement und rechts die Zeichenwerkzeuge.

Bild 5: Die Entwurfsansicht der Malanwendung frmSVGDraw zeigt zentral das Webbrowsersteuerelement und rechts die Zeichenwerkzeuge.

Zwei eingesetzte Steuerelemente bedürfen wohl der Erläuterung. Die horizontalen Schieberegler etwa finden Sie nicht im Umfang von Access selbst. Es handelt sich hier um ActiveX-Elemente, horizontale Scrollbars, aus der Sammlung der MSForms-Steuerelemente, die grundsätzlich mit jeder Office-Version installiert werden. Nach dem Einsetzen des ActiveX-Steuerelements begeben Sie sich zum Eigenschaftenblatt und stellen unter dem Reiter Andere den Eintrag Orientation auf den Wert Horizontal und die Min/Max-Werte auf 0 bis 100. Das Bewegen eines Schiebers löst das Ereignis Change aus, auf das im Formularmodul in der zugehörigen Ereignisprozedur reagiert wird:

Private Sub ctlTransparent_Change()
     m_Transparency = 100 - ctlTransparent.Value
End Sub

Die Modulvariable m_Transparency erhält nun den negierten Wert, den das Steuerelement ctlTransparent zurückgibt. Für das Farbspektrum rechts verwenden wir ein MSForms-Image-Steuerelement. Das wird beim Laden des Formulars schlicht mit einer vorgefertigten Bilddatei colors.jpg versehen. Diese werden Sie im Projektordner indessen vergeblich suchen, denn sie ist tatsächlich in der Systemtabelle MSysResources abgespeichert, die für Grafiken auf Steuerelementen vorgesehen ist, aber ebenso manuell mit Dateien bestückt werden kann. Ein MSForms-Image 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:

Set Me!ctlImgColors.Object.Picture = _
                  ArrayToPicture(GetColorTableJPG)

Das Picture-Objekt für das Steuerelement errechnet sich hier über zwei Hilfsfunktionen. GetColorTableJPG entnimmt der Systemtabelle die Binärdaten des Bilds und gibt sie als Byte-Array zurück:

Function GetColorTableJPG() As Byte()
     GetColorTableJPG = CurrentDb.OpenRecordset( _
         "SELECT BLOB FROM MSysResources WHERE Id=4", _
         dbOpenDynaset)(0).Value
End Function

Aus dem Byte-Array nun ein StdPicture-Objekt zu machen, ist natürlich eine wesentlich schwierigere Angelegenheit. Hier kommt mit der Funktion ArrayToPicture wieder einmal eine GDIPlus-API-Routine zum Einsatz, welche sich im Modul mdlGDIPSpecial versteckt.

Auf die Funktionsweise des Moduls können wir an dieser Stelle nicht eingehen. Der Klick auf einen Punkt im Spektrum-Image löst nun das Ereignis MouseDown aus. In dieser Ereignisprozedur muss die Farbe unter dem Mauszeiger bestimmt werden. Das lässt sich mit einer einzigen API-Funktion leichter erledigen, als gedacht:

Private Sub ctlImgColors_MouseDown( _
     ByVal Button As Integer, ByVal Shift As Integer, _
     ByVal x As Single, ByVal y As Single)
     Dim lColor As Long
     lColor = GetCursorPixel(x, y)
...
End Sub

GetCursorPixel nimmt die vom Ereignis zurückgegebenen x– und y-Koordinaten des Bildschirms entgegen und ermittelt für sie die Pixel-Farbe als RGB-Long-Wert.

Nebenbei sein noch erwähnt, dass Sie sich beim Webbrowser als Grafik-Engine nicht um die Skalierung von Bildern kümmern müssen. Sind geladenen oder erzeugte Bilder größer, als das Browser-Fenster, so blenden sich automatisch Scroll-Balken ein, mit denen Sie sich in die gewünschten Bildteile hineinbewegen können, wie Bild 6 demonstriert. Das gilt für geladenen Pixel-Grafiken in gleicher Weise, wie für SVG-Vektorgrafiken. Beim Abspeichern der Bilder wird dann aber selbstverständlich die teilweise nicht sichtbare Gesamtfläche verwendet.

Um die Einblendung von Scroll-Balken brauchen Sie sich beim Webbrowser-Steuerelement mit SVG-Grafik nicht zu kümmern.

Bild 6: Um die Einblendung von Scroll-Balken brauchen Sie sich beim Webbrowser-Steuerelement mit SVG-Grafik nicht zu kümmern.

Programmierung des Anwendungsformulars

Beginnen wir chronologisch mit den Ereignisprozeduren des Formulars, von denen die Form_Open-Prozedur die erste ist. Sie belegt lediglich einige modulweite Member-Variablen mit Vorgabewerten etwa zur Linienbreite oder Füllfarbe. Mit Form_Load geht es dann richtig los. Das Webbrowser-Steuerelement wird angewiesen, ein leeres Dokument zu laden, und in diesem werden, ähnlich wie bei den SVG-Diagrammen, ein gültiges head– sowie svg-Element angelegt. Die Breite und Höhe der SVG-Fläche werden dabei nicht auf einen fixen Wert eingestellt, sondern auf 100%, damit sich die Fläche später bei Größenänderung des verankerten Webbrowsers entsprechend ausdehnt. Zusätzlich erhält das Dokument einen JavaScript-Block:

Set oElement = oDoc.createElement("script")
With oElement
     .type = "text/javascript"
     .Text = "function turbfreq(v){ _
                document.getElementById(''''turbfilter''''). _
                   setAttribute (''''baseFrequency'''', v);} "
                ...
End With
oDoc.head.appendChild oElement

Ein JavaScript kann über das Tag script dynamisch neu in einem HTML-Dokument erzeugt werden, wobei ihm dessen Code über die Eigenschaft Text des Elements zugewiesen wird. Das Script enthält einige Funktionen, über die die Parameter der SVG-Filter zur Laufzeit gesteuert werden können.

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

Testzugang

eine Woche kostenlosen Zugriff auf diesen und mehr als 1.000 weitere Artikel

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar