{"id":55001117,"date":"2018-02-01T00:00:00","date_gmt":"2020-05-13T21:18:11","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1117"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Mit_HTML5_zeichnen_und_malen","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Mit_HTML5_zeichnen_und_malen\/","title":{"rendered":"Mit HTML5 zeichnen und malen"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg06.met.vgwort.de\/na\/92025f2b463d4388ae40ddda0295ecde\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>Wie Sie mithilfe des Webbrowser-Steuerelements und HTML5 programmgesteuert Grafiken erzeugen k&ouml;nnen, beleuchtete bereits unser Beitrag &#8222;HTML5 als Grafikkomponente&#8220;. Dass sich mit diesem Gespann aber Bilder auch interaktiv anlegen lassen, zeigen wir in diesem zweiten Teil anhand einer kleinen Zeichenanwendung, die ohne externe Komponenten auskommt. <\/b><\/p>\n<h2>Referenz<\/h2>\n<p>Die Ausf&uuml;hrungen dieses Beitrags setzen jene aus dem Artikel <b>HTML5 als Grafikkomponente<\/b> fort. Dort sind die Grundlagen zum Einsatz des <b>Webbrowser-Steuerelements<\/b> im Verein mit <b>HTML5<\/b> beschrieben, auf die hier nicht noch einmal eingegangen wird.<\/p>\n<h2>MS Access als Malprogramm<\/h2>\n<p>Bilder und Grafiken scheinen, wie man den Beitr&auml;gen verschiedener Foren entnehmen kann, f&uuml;r Access-Entwickler ein immer wiederkehrendes Thema zu sein. Sicher ist die Anzeige von Bilddateien in Formularen und Berichten, sei es &uuml;ber das Laden aus dem System, &uuml;ber <b>OLE-Objekte<\/b> oder <b>Anlagefelder<\/b>, eine h&auml;ufige Anforderung. Das reicht vom Logo im Berichtskopf &uuml;ber ein Konterfei im Mitarbeiterdatensatz bis hin zu technischen Zeichnungen. Gerade f&uuml;r letztere eignet sich <b>HTML5<\/b> gut, weil Sie hier eben nicht nur statisch Grafiken aus Dateien laden k&ouml;nnen, sondern in diese per VBA zus&auml;tzliche Elemente einbauen k&ouml;nnen. Oder Sie erstellen die Grafiken komplett neu, wie die Diagramme im Beitrag <b>HTML5 als Grafikkomponente <\/b>zeigen.<\/p>\n<p>Das Problem bei <b>HTML5<\/b> ist allerdings, dass die erzeugten Grafiken gerenderte Bitmaps sind, auf deren Elemente Sie sp&auml;ter keinen Einfluss mehr haben. Ein Undo ist schlecht realisierbar. M&ouml;glich ist aber die sequenzielle Bearbeitung der Grafik, die auch interaktiv geschehen kann. Eben davon macht unser Malprogramm Gebrauch.<\/p>\n<p>Doch wer erstellt unter Access &uuml;berhaupt Gem&auml;lde Ein Beispiel w&auml;ren technische Zeichnungen, die vervollst&auml;ndigt werden. Als Anbieter von Raumausstattungen etwa k&ouml;nnten Sie einen Raum gestalten lassen, indem Sie dessen leere Ansicht laden und in diese interaktiv mit der Maus Elemente hineinziehen und positionieren. <\/p>\n<p>Sie besitzen ein mobiles Ger&auml;t, wie etwa ein Windows-Tablet Dann k&ouml;nnen Sie mit diesem etwa jene Terminals von DHL oder DPD nachbilden und in den Grafikbereich eines Formulars Unterschriften eingeben lassen, um sie in Tabellen abzuspeichern.<\/p>\n<p>G&uuml;nstig sind in diesem Fall jedenfalls Ger&auml;te mit einem Touch-Screen, seien es Tablets oder Laptops. Nat&uuml;rlich erweitert ein Grafiktablett Ihren PC ebenfalls entsprechend.<\/p>\n<h2>Malen im Formular<\/h2>\n<p>Nach dem Start der Beispieldatenbank <b>HTMLImage2.accdb<\/b> finden Sie das Formular <b>frmHTML5Draw<\/b> zur Laufzeit vor, wie in Bild 1. Hier k&ouml;nnen Sie pro Datensatz ein Bild anzeigen lassen oder zeichnen. Ist ein Bild gespeichert, so wird es automatisch aus einer Tabelle geladen, w&auml;hrend bei einem neuen Datensatz ein leeres Blatt auf Sie wartet. Wenden wir uns zun&auml;chst den Funktionen des Formulars und seiner Steuerelemente zu.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/frmDraw.png\" alt=\"So pr&auml;sentiert sich die Malanwendung im Formular frmHTML5Draw der Beispieldatenbank mit einer bereits geladenen Grafik\" width=\"700\" height=\"468,7432\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: So pr&auml;sentiert sich die Malanwendung im Formular frmHTML5Draw der Beispieldatenbank mit einer bereits geladenen Grafik<\/span><\/b><\/p>\n<p>Die Grafikfl&auml;che im Detailbereich besteht aus einem <b>Webbrowser-Steuerelement<\/b>, in dessen Eigenschaft <b>URL<\/b> der String <b>=&#8220;about:blank&#8220;<\/b> hinterlegt ist, damit es keinen Navigationsfehler ausgibt, sondern eine wei&szlig;e Fl&auml;che. Der Zeichnung k&ouml;nnen Sie oben einen Namen geben, der sie eindeutig identifiziert. Zeichnung und Namen gelangen beide in eine Tabelle, an die das Formular gebunden ist. Das Speichern geschieht allerdings nicht automatisch mit Verlassen des Datensatzes, sondern nur mit Klick auf den Button <b>Bild speichern<\/b>. Alternativ kann die Grafik auch in eine Datei exportiert werden, wobei Ihnen die Formate <b>PNG<\/b> und <b>JPG<\/b> zur Auswahl stehen, welche Sie mit den beiden Checkboxen einstellen. &uuml;brigens beeinflusst diese Auswahl auch die interne Speicherung des Bilds in der Tabelle. Das Label rechts oben gibt Auskunft &uuml;ber den daf&uuml;r ben&ouml;tigten Speicherbedarf.<\/p>\n<p>Mit der Maus zeichnen Sie nun in die Grafikfl&auml;che. Die Farbe des Stifts stellen Sie mit Klick auf das Rechteck <b>Malfarbe<\/b> ein, die F&uuml;llung einer Figur mit dem Rechteck <b>F&uuml;llfarbe<\/b> und einen etwaigen Schattenwurf der Linien mit der <b>Schattenfarbe<\/b>. Der Klick auf diese Rechtecke ruft jeweils den Windows-Farbauswahldialog auf (Bild 2). In der Combobox <b>Strichbreite<\/b> w&auml;hlen Sie die gew&uuml;nschte Dicke des Stifts aus und dessen Deckkraft in der Combobox <b>Alpha<\/b>. Stellen Sie <b>Schatten<\/b> auf einen Wert gr&ouml;&szlig;er als <b>0<\/b> ein, so wird die gemalte Linie zus&auml;tzlich mit einem <b>Drop Shadow<\/b> hinterlegt, einem Verlaufsschatten, dessen Radius dem gew&auml;hlten Wert entspricht.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/ColorDialog.png\" alt=\"Farbauswahldialog von Windows zur Einstellung der Farben\" width=\"425\" height=\"303,9735\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Farbauswahldialog von Windows zur Einstellung der Farben<\/span><\/b><\/p>\n<p>Diese Einstellungen wirken sich jeweils auf den n&auml;chsten Zeichenvorgang aus. Malen Sie nun etwa einen Kringel, der nicht unbedingt geschlossen sein muss. Mit Klick auf die Schaltfl&auml;che <b>Figur schlie&szlig;en<\/b> geschieht dies jedoch automatisch. Ein weiterer Klick auf den nun aktivierten Button <b>Figur f&uuml;llen<\/b> versieht die jetzt umrandete Fl&auml;che mit der F&uuml;llfarbe. Sowohl Linien, wie Schatten und F&uuml;llungen ber&uuml;cksichtigen dabei die in <b>Alpha<\/b> eingestellte Transparenz. Sie k&ouml;nnen somit &uuml;berlagernd malen!<\/p>\n<p>Ein Klick auf den <b>Toggle-Button<\/b> <b>Malen<\/b> &auml;ndert dessen Beschriftung in <b>Radieren<\/b>. Nun k&ouml;nnen Sie mit der Maus Teile der Zeichnung ausradieren, was technisch so gel&ouml;st ist, dass einfach mit wei&szlig;er Farbe ohne Transparenz und mit einer Stiftbreite von etwa 10 Pixeln gemalt wird. Ein weiterer Klick auf den Button stellt den vorigen Malmodus wieder her.<\/p>\n<p>Sie k&ouml;nnen auch ein externes Bild in die Grafik laden, indem Sie den Dateiauswahldialog &uuml;ber den Button <b>Ext. Bild laden&#8230;<\/b> aufrufen. Die Position des eingef&uuml;gten Bilds k&ouml;nnen Sie damit allerdings eben so wenig beeinflussen, wie dessen Skalierung. Das h&auml;tte einigen zus&auml;tzlichen Aufwand erfordert, den wir uns erspart haben. Wohl aber beeinflusst wieder der Wert von <b>Alpha<\/b>, wie transparent das Bild eingef&uuml;gt wird.<\/p>\n<p>Dass die Qualit&auml;t der Zeichnung etwas zu w&uuml;nschen &uuml;brig l&auml;sst, k&ouml;nnen Sie der Abbildung entnehmen. Mit der Maus ist das Malen gar nicht so einfach. Zudem kommen die Linien etwas krakelig daher, was weniger an <b>HTML5<\/b> liegt, das <b>Antialiasing<\/b> durchaus unterst&uuml;tzt, sondern am eingesetzten Verfahren. Das wollten wir so einfach halten, wie m&ouml;glich: Bei jeder Mausbewegung wird zwischen den beiden abgetasteten Punkten eine einzelne Linie mit der <b>lineTo<\/b>-Anweisung des <b>HTML5-Canvas<\/b> erzeugt. Deshalb sind B&ouml;gen nicht wirklich rund, sondern weisen an den Punkten Kantenspr&uuml;nge auf, die zu einer vermeintlichen Rasterung f&uuml;hren. Sollte das vermieden werden, so m&uuml;ssten mehrere Abtastpunkte in einer <b>Bezier<\/b>-Linie (<b>bezierCurveTo<\/b>) zusammengef&uuml;hrt werden, was den Aufwand deutlich erh&ouml;ht h&auml;tte.<\/p>\n<h2>Tabelle als Grafikspeicher<\/h2>\n<p>Damit die Zeichnungen nicht nur in Dateien abgespeichert werden k&ouml;nnen, gibt es die Tabelle <b>tblBilderDraw<\/b>, deren Aufbau Bild 3 verdeutlicht. Neben dem Namen der Zeichnung in <b>BildName<\/b> und dem Autowert <b>ID<\/b> gibt es hier nur ein OLE-Feld <b>BildOLE<\/b>, in das indessen keineswegs <b>OLE-Objekte<\/b> hineinkommen, sondern reine Bin&auml;rdaten, die exakt der Datei entsprechen, die Sie auch extern abspeichern w&uuml;rden.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/tblBilderDraw.png\" alt=\"Die Tabelle tblBilderDraw speichert nur die gemalten Grafiken und ihren Namen neben der ID\" width=\"650\" height=\"329,6762\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Die Tabelle tblBilderDraw speichert nur die gemalten Grafiken und ihren Namen neben der ID<\/span><\/b><\/p>\n<p>Im Formular ist lediglich der <b>BildName<\/b> direkt an die entsprechende Textbox gebunden. Das Webbrowser-Steuerelement ist nat&uuml;rlich ungebunden, denn mit den Bin&auml;rdaten kann es nichts anfangen. Das Laden und Schreiben der Browser-Daten m&uuml;ssen VBA-Routinen &uuml;bernehmen.<\/p>\n<h2>Vorg&auml;nge beim Laden und Anzeigen des Formulars<\/h2>\n<p>Ein Teil des gerade einmal 250 Zeilen langen Formular-Codes l&auml;uft beim &ouml;ffnen (<b>Form_Load<\/b>) und im Ereignis <b>Beim Anzeigen<\/b> (<b>Form_Current<\/b>) ab. <b>Form_Load<\/b> stellt lediglich den Formularzeitgeber auf <b>100 ms<\/b> ein:<\/p>\n<pre>Me.TimerInterval = 100<\/pre>\n<p>Denn im Zeitgeberereignis steht die eigentliche Prozedur, die die initialen Vorg&auml;nge vornimmt. Auch <b>Form_Current<\/b> macht nicht viel mehr:<\/p>\n<pre>Me!ctlWeb.Object.Navigate2 \"about:blank\"\r\n...\r\nForm_Timer<\/pre>\n<p>Sie ruft ebenfalls das <b>Timer<\/b>-Ereignis auf. Grund daf&uuml;r ist ein <b>Delay<\/b> des Browsers <b>ctlWeb<\/b> beim Navigieren zu einer neuen <b>URL<\/b>, was asynchron abl&auml;uft und das Formular zuweilen durcheinanderbringt. Zwar ist das Steuerelement im Entwurf auf <b>about:blank<\/b> eingestellt, doch dies wirkt sich nur beim ersten Laden aus, nicht aber beim Ansteuern eines neuen Datensatzes. Hier muss das leere <b>HTML<\/b>-Dokument ausdr&uuml;cklich erneut angelegt werden. Interessant ist damit vor allem die Ereignisprozedur <b>Form_Timer<\/b>. Ihre einzelnen Abschnitte folgen nun.<\/p>\n<pre>Me.TimerInterval = 0\r\n<span style=\"color:blue;\">Do While<\/span> Me!ctlWeb.Object.ReadyState &lt; 3\r\n     DoEvents\r\n<span style=\"color:blue;\">Loop<\/span><\/pre>\n<p>Der Zeitgeber wird hier gleich wieder mit Setzen auf <b>0<\/b> deaktiviert, so dass es zu keinen Wiederholungen kommt. Anschlie&szlig;end wartet eine Schleife ab, bis die Eigenschaft <b>ReadyState<\/b> des Browsers mindestens den Wert 3 (<b>readyStateInteractive<\/b>) angenommen hat. Das dann der Fall, wenn der Browser die aufgerufene Seite fertiggestellt hat. Erst dann haben Sie Zugriff auf dessen <b>HTML-Dokument<\/b>. Das wird in der Folge der Formularvariablen <b>oDoc<\/b> zugewiesen:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> oDoc = Me!ctlWeb.Object.Document\r\noDoc.body.setAttribute \"bgColor\", \"#e0e0e0\"<\/pre>\n<p>Zus&auml;tzlich stellt die Routine hier die Hintergrundfarbe des <b>Dokument-Body<\/b> auf hellgrau ein. Im Kopf des Formularmoduls sind noch einige weitere globale Variablen deklariert, auf die in anderen Prozeduren Bezug genommen wird:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>WithEvents oDoc<span style=\"color:blue;\"> As <\/span>HTMLDocument\r\n<span style=\"color:blue;\">Private <\/span>WithEvents oDiv<span style=\"color:blue;\"> As <\/span>HTMLDivElement\r\n<span style=\"color:blue;\">Private <\/span>oCanvE<span style=\"color:blue;\"> As <\/span>IHTMLCanvasElement\r\n<span style=\"color:blue;\">Private <\/span>CTX<span style=\"color:blue;\"> As <\/span>ICanvasRenderingContext2D<\/pre>\n<p>Das HTML-Dokument steht also in <b>oDoc<\/b>. Der <b>HTML5-Canvas<\/b> kommt in die Elementvariablen <b>oCanvE<\/b>. Allerdings bauen wir das <b>Canvas<\/b>-Element nicht direkt in den <b>Body<\/b> des Dokuments ein, sondern in einen zus&auml;tzlichen <b>DIV<\/b>-Bereich, der gegebenenfalls verschoben werden kann. Die Variable <b>oDiv<\/b> nimmt einen Verweis auf diesen Bereich entgegen und ist au&szlig;erdem mit dem Pr&auml;dikat <b>WithEvents<\/b> versehen, wodurch dieser Ereignisse ausl&ouml;sen kann.<\/p>\n<p>So etwa auch Mausereignisse, die wir sp&auml;ter &#8211; Sie k&ouml;nnen es sich schon denken &#8211; dann zum Zeichnen auswerten werden. Und schlie&szlig;lich speichert die Variable <b>CTX<\/b> noch den Grafikkontext des <b>Canvas<\/b>, auf den erst ja die Zeichenanweisungen ausgef&uuml;hrt werden. Sie kennen das alles bereits aus dem ersten Beitrag zu <b>HTML5<\/b>.<\/p>\n<p>Nun legt die Prozedur die <b>HTML-Elemente<\/b> im Dokument an und nimmt einige Grundeinstellungen f&uuml;r den <b>Style<\/b> des <b>Canvas<\/b> vor (Listing 1). Erst wird das <b>DIV<\/b>-Element erzeugt und dem <b>Body<\/b> hinzugef&uuml;gt (<b>appendChild<\/b>). Dann generiert <b>createElement<\/b> einen neuen Canvas und weist ihn der modulglobalen Variablen <b>oCanvE<\/b> zu. Seine <b>Id<\/b> lautet <b>zeichnung<\/b> und seine Breite und H&ouml;he werden fest auf die Abmessungen <b>600&#215;400 <\/b>festgelegt. Diese Werte f&uuml;r die Zeichenfl&auml;che k&ouml;nnen Sie nat&uuml;rlich nach Belieben modifizieren.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Timer()\r\n     <span style=\"color:blue;\">Dim <\/span>oElement<span style=\"color:blue;\"> As <\/span>IHTMLElement\r\n...\r\n<span style=\"color:blue;\">Set<\/span> oDiv = oDoc.createElement(\"div1\")\r\noDiv.Id = \"div1\"\r\noDoc.body.appendChild oDiv\r\n<span style=\"color:blue;\">Set<\/span> oCanvE = oDoc.createElement(\"canvas\")\r\noCanvE.Id = \"zeichnung\"\r\noCanvE.Width = 600: oCanvE.Height = 400\r\noDiv.appendChild oCanvE\r\n<span style=\"color:blue;\">Set<\/span> CTX = oCanvE.getContext(\"2d\")\r\n<span style=\"color:blue;\">With<\/span> CTX\r\n     .globalAlpha = 1\r\n     .strokeStyle = 0\r\n     .lineWidth = 1\r\n     .FillStyle = \"#ffffff\"\r\n     .fillRect 0, 0, 600, 400\r\n     .strokeRect 0, 0, 600, 400\r\n     .strokeStyle = ColorToStr(rColor.BackColor)\r\n     .FillStyle = ColorToStr(rColorFill.BackColor)\r\n     .shadowBlur = val(cbShadow.Value)\r\n     .shadowColor = ColorToStr(rColorShadow.BackColor)\r\n     .shadowOffsetX = .shadowBlur \/ 2\r\n     .shadowOffsetY = .shadowBlur \/ 2\r\n     .lineWidth = CSng(cbLineWidth.Value)\r\nEnd <span style=\"color:blue;\">With<\/span>\r\n...\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><!--30percent--><\/p>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Die Timer-Prozedur initialisiert den HTML5-Canvas<\/span><\/b><\/p>\n<p>Weiter geht es mit dem &uuml;ber <b>getContext(2D&#8220;)<\/b> ermittelten Grafikkontext des <b>Canvas<\/b>, den die Variable <b>CTX<\/b> entgegennimmt. Im <b>With<\/b>-Block auf sie werden nicht nur einige <b>Style<\/b>-Eigenschaften festgelegt, wie Hintergrund (<b>FillStyle<\/b>), Linienbreite (<b>lineWidth<\/b>) oder Schattenradius (<b>shadowBlur<\/b>), sondern auch gleich ein die Grafik umrahmendes Rechteck mit <b>strokeRect<\/b> gezeichnet.<\/p>\n<p>Die Werte der Eigenschaften kommen dabei teilweise aus den Steuerelementen des Formulars. So entspricht der Schattenradius dem Wert der Combobox <b>cbShadow<\/b> oder die Malfarbe (<b>strokeStyle<\/b>) der Hintergrundfarbe (<b>BackColor<\/b>) des Rechtecksteuerelements <b>rColor<\/b>.<\/p>\n<p>Damit sind unsere HTML5-Objekte fertiggestellt und dem Zeichnen steht nichts mehr im Wege. Der Teil der Prozedur, der eine bereits gespeicherte Grafik l&auml;dt, ist im Listing &uuml;brigens ausgespart. Dazu dann sp&auml;ter mehr.<\/p>\n<h2>Zeichnen mit der Maus<\/h2>\n<p>Ob Sie es glauben oder nicht: Der Code zum Zeichnen umfasst nur 18 Zeilen, aufgeteilt auf drei Ereignisprozeduren! Die werten das Verhalten der linken Maustaste auf den <b>DIV<\/b>-Bereich <b>oDiv<\/b> aus (Listing 2). <\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>oDiv_onmousedown()\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         CTX.beginPath\r\n         CTX.moveTo oEvent.offsetX, oEvent.OffsetY\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>oDiv_onmousemove()\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         CTX.lineTo oEvent.offsetX, oEvent.OffsetY\r\n         CTX.stroke\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>oDiv_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         cmdFill.Enabled = <span style=\"color:blue;\">False<\/span>\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: Auswertung der Ereignisse des HTML-Bereichs oDiv<\/span><\/b><\/p>\n<p>Im Unterschied zu den Mausereignissen, die Sie von Access kennen, liefern diese keinerlei Parameter zur&uuml;ck, wie etwa die x- und y-Koordinaten des Ereignisses. Hier muss auf einen Trick zur&uuml;ckgegriffen werden. Alle Ereignisse eines HTML-Elements werden n&auml;mlich eigentlich von dessen Fenster verarbeitet, nicht vom Element selbst. An dieses Fenster gelangen Sie, indem Sie die Methode <b>parentWindow<\/b> des Dokuments abfragen. Sie erhalten ein Objekt vom Type <b>IHTMLWindow<\/b>. Das wiederum kennt eine Eigenschaft <b>event<\/b>, die sein Ereignisobjekt liefert und hier von der Modulvariablen <b>oEvent<\/b> entgegengenommen wird:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>oEvent<span style=\"color:blue;\"> As <\/span>IHTMLEventObj<\/pre>\n<p>Dieses <b>Event-Objekt<\/b> speichert im Browser global immer das zuletzt eingetretene Ereignis. Dr&uuml;cken Sie die linke Maustaste, so ereignet sich <b>onmousedown<\/b> und das <b>Event-Objekt<\/b> ist jetzt mit den entsprechenden Ereignisparametern best&uuml;ckt. Die Koordinaten stehen etwa in seinen Eigenschaften <b>OffsetX<\/b> und <b>OffsetY<\/b> (Pixel), die Nummer der gedr&uuml;ckten Taste in der Eigenschaft <b>Button<\/b>. Die rechte Maustaste h&auml;tte die Nummer zwei und wird in den Prozeduren &uuml;ber die Bedingung ignoriert.<\/p>\n<p>Beim Dr&uuml;cken der linken Maustaste wird zun&auml;chst eine neue Figur &uuml;ber die Methode <b>beginPath<\/b> im Grafikkontext <b>CTX<\/b> angelegt. Die <b>moveTo<\/b>-Methode bewegt den Stift zu den aus dem <b>Event-Objekt<\/b> ausgelesenen Koordinaten. Bewegen Sie die Maus dann, so tritt <b>onmousemove<\/b> ein und die Anweisung <b>lineTo<\/b> zeichnet eine Line zu den neuen Koordinaten. Die wird allerdings erst sichtbar, wenn Sie <b>stroke<\/b> aufrufen.<\/p>\n<p>Lassen Sie die Maustaste los, so ereignet sich <b>onmouseup<\/b>. Das brauchen Sie eigentlich nicht mehr, denn die Linie ist ja bereits gezeichnet. Hier wird aber zus&auml;tzlich gesteuert, dass die Schaltfl&auml;che zum F&uuml;llen der Figur im Formular (<b>cmdFill<\/b>) deaktiviert wird. Denn die darf erst in Aktion treten, wenn die Figur geschlossen ist, worauf wir gleich zur&uuml;ckkommen.<\/p>\n<p>Wie die Linie gezeichnet wird, bestimmen nur die Einstellungen f&uuml;r den zuvor festgelegten Style des Grafikkontexts CTX. In den Zeichenereignissen selbst muss hier nichts weiter getan werden. Die Stiftbreite etwa regelt die Combobox <b>cbLineWidth<\/b>. &auml;ndern Sie ihren Eintrag, so kommt es zu dieser Prozedur <b>Nach Aktualisieren<\/b>:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cbLineWidth_AfterUpdate()\r\n     CTX.lineWidth = CSng(cbLineWidth.Value)\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Ihr Wert wird also unmittelbar an die <b>Style<\/b>-Eigenschaft <b>lineWidth<\/b> des Grafikkontexts weitergeleitet, wobei allerdings eine Umwandlung in einen <b>Single<\/b>-Datentyp per <b>CSng<\/b> ben&ouml;tigt wird. Auf die erwarteten Parametertypen sollten Sie bei allen <b>HTML5<\/b>-Objekten achten, weil nicht immer automatische Typkonvertierungen geschehen.<\/p>\n<h2>Figur f&uuml;llen<\/h2>\n<p>Nachdem Sie einen Linienzug zeichneten ist er noch nicht abgeschlossen. Denn beim Mausdr&uuml;cken wurde die Anweisung <b>beginPath<\/b> abgesetzt, die dem Grafikkontext sagt, dass folgend eine aus mehreren Schritten bestehende Operation vonstattengehen wird. Ein Klick auf den Button <b>Figur schlie&szlig;en<\/b> &auml;ndert den Zustand:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdClosePath_Click()\r\n     CTX.closePath\r\n     CTX.stroke\r\n     cmdFill.Enabled = <span style=\"color:blue;\">True<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die Methode <b>closePath<\/b> zeichnet automatisch eine Linie von der letzten Koordinate (von <b>lineTo<\/b>) zu der, die bei <b>beginPath<\/b> aktiv war. Sichtbar wird sie wieder erst per <b>stroke<\/b>. Die Schaltfl&auml;che zum F&uuml;llen der Figur (<b>cmdFill<\/b>) kann nun aktiviert werden. Deren <b>Click<\/b>-Prozedur besteht auch nur aus zwei Zeilen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdFill_Click()\r\n     CTX.Fill\r\n     CTX.beginPath\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b>Fill<\/b> f&uuml;llt den letzten automatisch im Kontext gespeicherten Linienpfad mit der unter <b>FillStyle<\/b> angegebenen Farbe und mit der Transparenz aus <b>globalAlpha<\/b>. Damit eventuell nicht noch mehr gemalte Figuren in die Operation einbezogen werden, schlie&szlig;en Sie diesen gespeicherten Pfad ab, indem Sie einfach mit <b>beginPath<\/b> einen neuen anlegen.<\/p>\n<h2>Externe Bilddatei laden<\/h2>\n<p>Bild 4 zeigt eine Zeichnung, in die das Bild einer Tulpe geladen wurde. Das ist nat&uuml;rlich kein eigenes Objekt, sondern schlicht in das <b>HTML5<\/b>-Bitmap gerendert, weshalb es abschlie&szlig;end &uuml;bermalt werden kann. Die Umsetzung dieses Vorgangs bereitete einiges Kopfzerbrechen. Zwar kennt der <b>HTML5<\/b>-Grafikkontext die Methode <b>drawImage<\/b>, die ein bestehendes Bild in den <b>Canvas<\/b> kopiert und dabei auch noch positionieren und skalieren kann, doch als Bildquelle erwartet die Anweisung ein <b>HTML-Bildobjekt<\/b> vom Type <b>HTMLImg<\/b>! Wie erzeugen Sie ein solches aus einer Datei<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/frmDraw2.png\" alt=\"Der zweite Datensatz des Formulars frmHTML5Draw in der Beispieldatenbank zeigt ein geladenes und &uuml;bermaltes externes Bild \" width=\"700\" height=\"468,7432\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Der zweite Datensatz des Formulars frmHTML5Draw in der Beispieldatenbank zeigt ein geladenes und &uuml;bermaltes externes Bild <\/span><\/b><\/p>\n<p>Die Ereignisprozedur beim Klick auf den Button <b>Ext.Bild laden&#8230;<\/b> (<b>cmdLoadPic<\/b>) l&ouml;st das R&auml;tsel. Sie ruft zun&auml;chst den <b>Office-FileDialog<\/b> auf, &uuml;ber den Sie eine Bilddatei ausw&auml;hlen k&ouml;nnen. Dann l&auml;dt sie diese Datei &uuml;ber ein <b>Open-Get-Close<\/b>-Konstrukt im Bin&auml;rmodus in ein Byte-Array <b>bin<\/b>. Der Rest der Prozedur steht in Listing 3.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdLoadPic_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>oImg<span style=\"color:blue;\"> As <\/span>HTMLImg\r\n     <span style=\"color:blue;\">Dim <\/span>W<span style=\"color:blue;\"> As Long<\/span>, H<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>bin()<span style=\"color:blue;\"> As Byte<\/span>\r\n     ...\r\n     <span style=\"color:blue;\">Set<\/span> oImg = oDoc.createElement(\"img\")\r\n     oImg.src = \"data:image\/jpeg;base64,\" & EncodeBase64(bin)\r\n     Do\r\n         DoEvents\r\n     <span style=\"color:blue;\">Loop<\/span> Until oImg.ReadyState = \"complete\"\r\n     W = oImg.Width: H = oImg.Height\r\n     <span style=\"color:blue;\">If <\/span>oImg.Width &gt; 600<span style=\"color:blue;\"> Then<\/span>\r\n         oImg.Height = oImg.Height * 600 \/ oImg.Width\r\n         oImg.Width = 600\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>oImg.Height &gt; 400<span style=\"color:blue;\"> Then<\/span>\r\n         oImg.Width = oImg.Width * 400 \/ oImg.Height\r\n         oImg.Height = 400\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     CTX.drawImage oImg, 0, 0, W, H, 1, 1, oImg.Width, oImg.Height\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Erzeugen eines HTML-Bildobjekts aus externer Datei<\/span><\/b><\/p>\n<p>Ein neues HTML-Bild k&ouml;nnen Sie mithilfe der Methode <b>createElement<\/b> und dem Parameter <b>img<\/b> auf das Dokument <b>oDoc<\/b> anlegen. Die Routine speichert einen Verweis darauf in der Variablen <b>oImg<\/b>. Der Trick ist hierbei, dass dieses Bildobjekt im Dokument gar nicht angezeigt wird, weil es dazu erst dem <b>Body<\/b> oder einem anderen Bereich mit <b>appendChild<\/b> hinzugef&uuml;gt werden m&uuml;sste. Es existiert also nur im Speicher. Nun ben&ouml;tigen wir noch die Quelle des Bildobjekts, die unter HTML &uuml;blicherweise eine Datei darstellt, welche aus dem Dateisystem oder von einem Webserver geladen w&uuml;rde. Tats&auml;chlich k&ouml;nnten Sie die Eigenschaft <b>src<\/b> des Objekts <b>oImg<\/b> direkt mit dem zuvor ausgew&auml;hlten Dateipfad belegen. Leider passiert dann beim Aufruf von <b>drawImage<\/b> rein gar nichts. Denn Microsoft unterbindet aus Sicherheitsgr&uuml;nden solche <b>Cross-References<\/b> zwischen <b>HTML5<\/b> und Dateisystem. <\/p>\n<p>Wenig bekannt aber ist die Tatsache, dass Sie f&uuml;r ein HTML-Bildobjekt statt eines Dateipfads oder einer <b>URL<\/b> auch einen Daten-String angeben k&ouml;nnen! Der muss, wie bereits im Beitrag zu den <b>HTML5<\/b>-Diagrammen erl&auml;utert (siehe Stichwort <b>toURLData<\/b>), in <b>base64<\/b>-Kodierung vorliegen. Dies geschieht in der Zeile, die der Eigenschaft <b>src<\/b> die Daten zuweist. Damit der Browser erkennt, dass es sich um Daten handelt, ist ein <b>Header<\/b> voranzustellen, der sich aus dem Pr&auml;fix <b>data:<\/b> und dem <b>MIME<\/b>-Typ zusammensetzt, gefolgt von der einzig erlaubten Kodierung <b>base64<\/b>. In unserem Beispiel ist, nebenbei erw&auml;hnt, wegen des hier festgelegten <b>MIME<\/b>-Typs <b>image\/jpeg<\/b> nur das Laden von <b>JPG<\/b>-Bilder erlaubt. <\/p>\n<p>Die Konvertierung der Bin&auml;rdaten im Byte-Array <b>bin<\/b> &uuml;bernimmt die Hilfsfunktion <b>EncodeBase64<\/b> im Modul <b>mdlCanvas<\/b>. Das einfache Dekodieren &uuml;ber ein <b>XML<\/b>-Element lernten Sie schon im Vorg&auml;ngerbeitrag kennen. Tats&auml;chlich k&ouml;nnte man die entgegengesetzte Richtung ebenfalls &uuml;ber die <b>XML<\/b>-Bibliothek vornehmen. Performanter ist aber eine <b>API<\/b>-Funktion von Windows (<b>CryptBinaryToString<\/b>), die genauso wenige Code-Zeilen erfordert. Listing 4 stellt die Hilfsfunktion dar, auf deren Aufbau wir an dieser Stelle nicht weiter eingehen. <\/p>\n<pre><span style=\"color:blue;\">Private <\/span>Declare Function CryptBinaryToString Lib \"Crypt32\" Alias \"CryptBinaryToStringA\" (ByRef pbBinary<span style=\"color:blue;\"> As Byte<\/span>, _\r\n     ByVal cbBinary<span style=\"color:blue;\"> As Long<\/span>, ByVal dwFlags<span style=\"color:blue;\"> As Long<\/span>, ByVal pszString<span style=\"color:blue;\"> As Long<\/span>, ByRef pcchString<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As Long<\/span> \r\n<span style=\"color:blue;\">Function <\/span>EncodeBase64(bin()<span style=\"color:blue;\"> As Byte<\/span>)<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>binOut()<span style=\"color:blue;\"> As Byte<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>nSize<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">If <\/span>CryptBinaryToString(bin(0), <span style=\"color:blue;\">UBound<\/span>(bin) + 1, &H40000001, 0&, nSize) &lt;&gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n         nSize = nSize * 2\r\n         ReDim binOut(nSize - 1)\r\n         <span style=\"color:blue;\">If <\/span>CryptBinaryToString(bin(0), <span style=\"color:blue;\">UBound<\/span>(bin) + 1, &H40000001, VarPtr(binOut(0)), nSize) &lt;&gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n             EncodeBase64 = StrConv(binOut, vbUnicode)\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Diese kurze Routine erzeugt aus einem Byte-Array einen base64-kodierten String per API<\/span><\/b><\/p>\n<p>Nachdem dieser Daten-String dem Bildobjekt zugewiesen wurde, muss die Routine noch abwarten, bis es intern fertig gerendert ist, bevor auf das Objekt weitere Methoden angewandt werden. Dass passiert, &auml;hnlich zum Browser, &uuml;ber eine Abfrage des Status in <b>ReadyState<\/b>. Nur setzen Sie hier keine Konstante ein, sondern einen Status-String, der nach Abschluss des Renderns auf <b>complete<\/b> steht.<\/p>\n<p>Die Bildladeroutine liest nun Breite und H&ouml;he des Bilds anhand seiner Eigenschaften <b>Width<\/b> und <b>Height<\/b> in die Variablen <b>W<\/b> und <b>H<\/b> ein. Diese Werte ben&ouml;tigen wir f&uuml;r das folgende <b>drawImage<\/b>, das als Parameter die Quellbreite und -h&ouml;he des Bilds erwartet. Sie k&ouml;nnten ebenso einen Ausschnitt des Bilds transferieren! Da das Bild gr&ouml;&szlig;er sein kann, als der <b>Canvas<\/b> mit seinen <b>600&#215;400<\/b> Pixel, folgt nun im Zweifel &uuml;ber Bedingungen eine Skalierung. Die Eigenschaften <b>Width<\/b> und <b>Height<\/b> des Bildobjekts m&uuml;ssen dazu lediglich auf neue Werte gesetzt werden. <b>drawImage<\/b> &uuml;bergeben Sie schlie&szlig;lich das Bildobjekt <b>oImg<\/b>, die Koordinaten des Quellrechtecks (hier: <b>0,0<\/b>), die Quellausdehnung aus <b>W<\/b> und <b>H<\/b>, die Position, an der das Bild eingef&uuml;gt werden soll (hier:<b> x=1<\/b>,<b> y=1<\/b>), und dann noch die gew&uuml;nschte Breite und H&ouml;he im Ziel. Das tempor&auml;re Bildobjekt <b>oImg<\/b> wird nach dem Verlassen der Prozedur automatisch aus dem Speicher entfernt, weil es keinem <b>HTML-Element<\/b> des Dokuments hinzugef&uuml;gt wurde.<\/p>\n<h2>Abspeichern und Laden der Grafik<\/h2>\n<p>Wie Sie die <b>HTML5<\/b>-Grafik in eine externe Datei exportieren erfuhren Sie im Beitrag <b>HTML5 als Grafikkomponente<\/b>. Hier aber m&ouml;chten wir die Zeichnungen in eine Tabelle abspeichern und auch wieder aus ihr laden, ohne das Dateisystem bem&uuml;hen zu m&uuml;ssen. Das soll m&ouml;glichst platzsparend geschehen. Der Code aus dem Beitrag <b>Datenkompression leicht gemacht<\/b> hilft uns hierbei. Der Klick auf die Formularschaltfl&auml;che <b>cmdSaveDB<\/b> (<b>Bild speichern<\/b>) des Formulars &uuml;berf&uuml;hrt das <b>HTML5<\/b>-Bild in das Feld <b>BildOLE<\/b> der angebundenen Tabelle:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdSaveDB_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>sFormat<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">If <\/span>chkPNG.Value = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n         sFormat = \"image\/png\"\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         sFormat = \"image\/jpeg\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     Me!BildOLE.Value = CanvasPicToByte(oCanvE, sFormat, <span style=\"color:blue;\">True<\/span>)\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Je nach Status der beiden Checkboxen wird <b>sFormat<\/b> auf ein unterschiedliches <b>MIME<\/b>-Format gebracht. Die ausgelagerte Hilfsroutine <b>CanvasPicToByte<\/b> erwartet einen Verweis auf das <b>Canvas-Objekt <\/b>und eine Angabe zum gew&uuml;nschten Format. Der dritte Parameter sagt als Boole-Wert, ob beim Speichern eine Datenkompression stattfinden soll. Die wesentlichen Zeilen der Routine, welche schlie&szlig;lich ein Byte-Array zur&uuml;ckgibt: <\/p>\n<pre><span style=\"color:blue;\">Function <\/span>CanvasPicToByte(oCanv<span style=\"color:blue;\"> As <\/span>IHTMLCanvasElement, _\r\n         <span style=\"color:blue;\">Optional<\/span> sType = \"image\/png\",  _\r\n         <span style=\"color:blue;\">Optional<\/span> Compressed<span style=\"color:blue;\"> As Boolean<\/span> = <span style=\"color:blue;\">True<\/span>)<span style=\"color:blue;\"> As Byte<\/span>() \r\n     <span style=\"color:blue;\">Dim <\/span>sData<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>quality<span style=\"color:blue;\"> As Variant<\/span>\r\n     sData = oCanv.toDataURL(sType, quality)\r\n     <span style=\"color:blue;\">If <\/span>Compressed<span style=\"color:blue;\"> Then<\/span>\r\n         CanvasPicToByte = CompressRTL(StrConv(sData, _\r\n             vbFromUnicode))\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         CanvasPicToByte = StrConv(StrConv(sData, _\r\n             vbUnicode), vbFromUnicode)\r\n     <span style=\"color:blue;\">End If<\/span><\/pre>\n<p>Die Methode <b>toDataURL<\/b> des &uuml;bergebenen Canvas erzeugt wieder einen <b>base64<\/b>-String und speichert ihn in <b>sData<\/b>. Um aus dem String ein Byte-Array zu machen kommt die Funktion <b>StrConv<\/b> zum Einsatz. Dieses kann wiederum, falls Kompression angewiesen wurde, an die Prozedur <b>CompressRTL<\/b> weitergeleitet werden, die exakt jener entspricht, die Sie in der Beispieldatenbank zum Beitrag <b>Datenkompression leicht gemacht<\/b> finden. Soll nicht komprimiert werden, so erreicht ein verdoppeltes <b>StrConv<\/b>, dass aus dem String ein korrektes Byte-Array entsteht, wobei dann abwechselnd die Parameter <b>vbUnicode<\/b> und <b>vbFromUnicode<\/b> eingesetzt werden. Von der Kompression &uuml;ber diese Methode brauchen Sie nicht allzu viel zu erwarten. Aber immerhin reduziert sich der Speicherbedarf mit ihr nach unseren Beobachtungen auf etwa das 1,5-fache.<\/p>\n<p>Das <b>HTML5<\/b>-Bild befindet sich nun in der Tabelle im Feld <b>BildOLE<\/b>. Von dort soll es im Formular auch wieder geladen werden, wenn zu einem Datensatz gesprungen wird. Hier kehren wir zur Ereignisprozedur <b>Form_Current<\/b> zur&uuml;ck, die ihrerseits die <b>Timer<\/b>-Prozedur in <b>Listing 1<\/b> aufruft. Dort haben wir den Teil zum Laden der Grafik aus der Tabelle unterschlagen und geben ihn hier in Listing 5 wieder. Ist das Feld <b>BildOLE<\/b> <b>nicht<\/b> leer, so erzeugt der Code ein tempor&auml;res HTML-Bildobjekt <b>oImg<\/b>, das &uuml;ber <b>drawImage<\/b> in den leeren Canvas geschrieben wird. Der Vorgang ist identisch zu dem, was bereits im Abschnitt <b>Externe Bilddatei laden<\/b> besprochen wurde. Nur kommen die Bin&auml;rdaten hier nicht aus einer Datei, sondern direkt aus der Tabelle. Da sie komprimiert vorliegen, m&uuml;ssen sie &uuml;ber die Hilfsfunktion <b>DecompressRTL<\/b> erst dekomprimiert und per <b>StrConv<\/b> wieder in einen String umgewandelt werden. Danach folgen noch einige Zeilen, die Formularelemente steuern. Das Label <b>lblInfo<\/b> zur Ausgabe des Speicherbedarfs des Bilds wird mit der R&uuml;ckgabe der <b>Len<\/b>-Funktion belegt. In Abh&auml;ngigkeit vom <b>MIME<\/b>-Ausdruck, der im <b>Header<\/b> des <b>Source-Strings<\/b> <b>oImg.src<\/b> steht, werden die beiden Checkboxen zur Auswahl von <b>PNG<\/b> oder <b>JPG<\/b> im Formular eingestellt. Bei Bl&auml;ttern durch die Datens&auml;tze sehen Sie damit nicht nur, wieviel Platz das aktuelle Bild in der Tabelle ben&ouml;tigt, sondern auch, in welchem Format es intern gespeichert wurde.<\/p>\n<pre>...\r\n<span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> IsNull(Me!BildOLE)<span style=\"color:blue;\"> Then<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>bin()<span style=\"color:blue;\"> As Byte<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> oElement = oDoc.createElement(\"img\")\r\n     <span style=\"color:blue;\">Set<\/span> oImg = oElement\r\n     bin = Me!BildOLE.Value\r\n     oImg.src = StrConv(DeCompressRTL(bin), vbUnicode)\r\n     Do\r\n         DoEvents\r\n     <span style=\"color:blue;\">Loop<\/span> Until oImg.ReadyState = \"complete\"\r\n     CTX.drawImage oImg, 0, 0, 600, 400, 0, 0, 600, 400\r\n     Me!LblInfo.Caption = <span style=\"color:blue;\">Len<\/span>(Me!BildOLE.Value) & \" Bytes\"\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Mid<\/span>(oImg.src, 12, 3) = \"png\"<span style=\"color:blue;\"> Then<\/span>\r\n         chkPNG.Value = <span style=\"color:blue;\">True<\/span>\r\n         chkJPG.Value = <span style=\"color:blue;\">False<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         chkPNG.Value = <span style=\"color:blue;\">False<\/span>\r\n         chkJPG.Value = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End If<\/span>\r\n...<\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Erzeugen eines HTML-Bildobjekts<\/span><\/b><\/p>\n<h2>Ausblick<\/h2>\n<p>Wir haben Ihnen nun zwei recht umfangreiche Beitr&auml;ge zum Thema <b>Grafiken mit HTML5 unter Access<\/b> geliefert. Ich finde es jedoch so spannend, dass ein Aspekt nicht unber&uuml;cksichtigt bleiben sollte, der bisher noch keine Erw&auml;hnung fand. Zwar k&ouml;nnen Sie nun interaktiv Grafiken erstellen, bekommen aber etwa keine R&uuml;ckmeldung &uuml;ber die virtuellen Objekte, wenn Sie sich mit der Maus &uuml;ber Grafikelemente bewegen. Mit welchen Tricks jedoch auch das m&ouml;glich ist, erl&auml;utert eine kleine Fortsetzung der Reihe. Dass <b>HTML5<\/b> nur eine M&ouml;glichkeit ist, um unter Access mithilfe des Webbrowser-Steuerelements Grafiken zu generieren, haben wir schon im ersten Teil der Serie deutlich gemacht. S&auml;mtliche dargestellten L&ouml;sungen lassen sich jedoch auch &uuml;ber das <b>SVG<\/b>-Objektmodell des Browsers realisieren! Und <b>SVG<\/b>-Grafiken haben sogar noch einige Vorteile gegen&uuml;ber <b>HTML5<\/b>. Den Umgang mit diesem Modell werden weitere Beitr&auml;ge beleuchten.<\/p>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>HTMLImage2.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/AB2F3A53-6255-4091-B21D-226F3BE4201D\/aiu_1117.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wie Sie mithilfe des Webbrowser-Steuerelements und HTML5 programmgesteuert Grafiken erzeugen k&ouml;nnen, beleuchtete bereits unser Beitrag &#8218;HTML5 als Grafikkomponente&#8216;. Dass sich mit dieses Gespann aber Bilder auch interaktiv anlegen lassen, zeigen wir in diesem zweiten Teil anhand einer kleinen Zeichenanwendung, die ohne externe Komponenten auskommt. <\/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":[66012018,662018,44000026],"tags":[],"class_list":["post-55001117","post","type-post","status-publish","format-standard","hentry","category-66012018","category-662018","category-Interaktiv"],"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>Mit HTML5 zeichnen und malen - 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\/Mit_HTML5_zeichnen_und_malen\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Mit HTML5 zeichnen und malen\" \/>\n<meta property=\"og:description\" content=\"Wie Sie mithilfe des Webbrowser-Steuerelements und HTML5 programmgesteuert Grafiken erzeugen k&ouml;nnen, beleuchtete bereits unser Beitrag &#039;HTML5 als Grafikkomponente&#039;. Dass sich mit dieses Gespann aber Bilder auch interaktiv anlegen lassen, zeigen wir in diesem zweiten Teil anhand einer kleinen Zeichenanwendung, die ohne externe Komponenten auskommt.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Mit_HTML5_zeichnen_und_malen\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2020-05-13T21:18:11+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg06.met.vgwort.de\/na\/92025f2b463d4388ae40ddda0295ecde\" \/>\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\\\/Mit_HTML5_zeichnen_und_malen\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Mit_HTML5_zeichnen_und_malen\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Mit HTML5 zeichnen und malen\",\"datePublished\":\"2020-05-13T21:18:11+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Mit_HTML5_zeichnen_und_malen\\\/\"},\"wordCount\":3803,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Mit_HTML5_zeichnen_und_malen\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/92025f2b463d4388ae40ddda0295ecde\",\"articleSection\":[\"1\\\/2018\",\"2018\",\"Interaktiv\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Mit_HTML5_zeichnen_und_malen\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Mit_HTML5_zeichnen_und_malen\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Mit_HTML5_zeichnen_und_malen\\\/\",\"name\":\"Mit HTML5 zeichnen und malen - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Mit_HTML5_zeichnen_und_malen\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Mit_HTML5_zeichnen_und_malen\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/92025f2b463d4388ae40ddda0295ecde\",\"datePublished\":\"2020-05-13T21:18:11+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Mit_HTML5_zeichnen_und_malen\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Mit_HTML5_zeichnen_und_malen\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Mit_HTML5_zeichnen_und_malen\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/92025f2b463d4388ae40ddda0295ecde\",\"contentUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/92025f2b463d4388ae40ddda0295ecde\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Mit_HTML5_zeichnen_und_malen\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Mit HTML5 zeichnen und malen\"}]},{\"@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":"Mit HTML5 zeichnen und malen - 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\/Mit_HTML5_zeichnen_und_malen\/","og_locale":"de_DE","og_type":"article","og_title":"Mit HTML5 zeichnen und malen","og_description":"Wie Sie mithilfe des Webbrowser-Steuerelements und HTML5 programmgesteuert Grafiken erzeugen k&ouml;nnen, beleuchtete bereits unser Beitrag 'HTML5 als Grafikkomponente'. Dass sich mit dieses Gespann aber Bilder auch interaktiv anlegen lassen, zeigen wir in diesem zweiten Teil anhand einer kleinen Zeichenanwendung, die ohne externe Komponenten auskommt.","og_url":"https:\/\/access-im-unternehmen.de\/Mit_HTML5_zeichnen_und_malen\/","og_site_name":"Access im Unternehmen","article_published_time":"2020-05-13T21:18:11+00:00","og_image":[{"url":"http:\/\/vg06.met.vgwort.de\/na\/92025f2b463d4388ae40ddda0295ecde","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\/Mit_HTML5_zeichnen_und_malen\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Mit_HTML5_zeichnen_und_malen\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Mit HTML5 zeichnen und malen","datePublished":"2020-05-13T21:18:11+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Mit_HTML5_zeichnen_und_malen\/"},"wordCount":3803,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Mit_HTML5_zeichnen_und_malen\/#primaryimage"},"thumbnailUrl":"http:\/\/vg06.met.vgwort.de\/na\/92025f2b463d4388ae40ddda0295ecde","articleSection":["1\/2018","2018","Interaktiv"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Mit_HTML5_zeichnen_und_malen\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Mit_HTML5_zeichnen_und_malen\/","url":"https:\/\/access-im-unternehmen.de\/Mit_HTML5_zeichnen_und_malen\/","name":"Mit HTML5 zeichnen und malen - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Mit_HTML5_zeichnen_und_malen\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Mit_HTML5_zeichnen_und_malen\/#primaryimage"},"thumbnailUrl":"http:\/\/vg06.met.vgwort.de\/na\/92025f2b463d4388ae40ddda0295ecde","datePublished":"2020-05-13T21:18:11+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Mit_HTML5_zeichnen_und_malen\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Mit_HTML5_zeichnen_und_malen\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Mit_HTML5_zeichnen_und_malen\/#primaryimage","url":"http:\/\/vg06.met.vgwort.de\/na\/92025f2b463d4388ae40ddda0295ecde","contentUrl":"http:\/\/vg06.met.vgwort.de\/na\/92025f2b463d4388ae40ddda0295ecde"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Mit_HTML5_zeichnen_und_malen\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Mit HTML5 zeichnen und malen"}]},{"@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\/55001117","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=55001117"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001117\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001117"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001117"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001117"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}