# Java2D and SVG vs PNG



## tuedel (11. Jul 2012)

Grüße an alle!

Ich wollte mich im Forum erkundigen, ob jemand Erfahrungen mit der Performance von svg grafiken in Java gemacht hat. Im Speziellen mit der svgSalamander library. Ich bevorzuge Salamander, da meine Applikation ein Applet ist, dass mit dem lib Umfang der Batik API schlichtweg zu groß wird. 

Im speziellen geht es darum, die SVG Grafiken auf den Screen zu rendern. Einerseits für bewegende Objekte, die ihre Koordinaten 25x pro Sekunde ändern, als auch statischem Content, der nur sehr selten während der Laufzeit verändert wird. 

In der Theorie würde ich annehmen, dass wenn die Objekte der SVG File in Shapeobjekte - Java2D vektor Grafik überführt werden, ich diese schneller zeichnen könnte, als BufferedImages. Gleichzeitig weiß ich aber auch nicht genau, wie Salamander das Rendern der SVG Objekte intern durchführt. Daher war auch mein Gedanke, die XML Tags selbst auszulesen und in Shape Objekte umzuwandeln, um dann bspw. zur Laufzeit nur die Koordinate im Renderprozess anzupassen.

Weiterhin bot sich die Verwendung von SVGIcon der Salamander Bibliothek als Swing Element an, dass (so vermute ich zZ leider nur) die Tags in einer Swing Komponente instanziert und ich quasi nicht die Tags in der SVG File für Anpassungen anfassen muss.

Hat jemand Erfahrungen gemacht, oder könnte meine Vermutungen stützen/verneinen?
Auch theoretische Diskussionen würden mich brennend interessieren. Letztlich geht es mir darum, ob es sich lohnen würde, statt png files auf svg files für mein Applet umzusteigen (Buttons, UI, Objektrendering).

Herzlichen Dank.
LG tuedel


I would like to ask, if anybody has experienced the performance of using svg files with batik/svgSalamander instead of common image file formats like png? On the one hand for dynamic objects, which need to become transformed 25 times per second and on the other hand with static images, which rarely change.

I was thinking about if its worth it performance wise, having Java2D shape objects, instanced out of svg input, instead of BufferedImages.

Thanks for your help!! Best regards.


----------



## Spacerat (11. Jul 2012)

Also dynamische Vectorgrafiken und PNGs sind schon ein himmelweiter Unterschied. SVG-Libs machen ja im Prinzip nichts anderes, als die Vectoren in SVG-Dateien in einen anzeigbaren Puffer (Rendered- bzw. BufferedImage) zu überführen. Für statische Hintergrundgrafiken eignen sich PNGs hervorragend. Für Animationen bzw. dynamischen Inhalt aber würdest du ganze Bildfolgen von PNGs benötigen. Deswegen sind dafür eher GIFs oder halt SVGs besser geeignet. GIFs speichern allerdings auch ganze Bildpuffer gerenderter Bilder und das ist u.U. schon sehr speicherintensiv. SVGs aber können mit besagten Libs oder direkt mit SAX (oder einen XML-Parser deiner Wahl) und Java2D zur Laufzeit verändert werden und belegen dabei nur einen Bildpuffer. Vorstellbar, dass SVGs auch schneller sind, weil während des Rendervorgangs eines Bildes nur ein Teil des Bildpufferspeeichers verändert werden muß. Bei SVGs z.B. zeichnet man mehrere Linien, bei PNGs und GIFs kopiert man ganze Einzelbilder.


----------



## tuedel (11. Jul 2012)

Danke für die schnelle Antwort. Für statischen Kontext war der Gedanke für die Verwendung von SVG Dateien, dass ich auf die SVG Elements am liebsten Mouseevents lege, um sehr pixelgenau Teile einer Grafik mit Funktionalität zu versehen, wobei ich mir noch nicht ganz sicher bin, ob ich da mit SVG wirklich in die richtige Richtung gehe. 

Für die dynamischen Objekte ändernt sich lediglich die Position, die Rotation und Skalierung. Derzeit habe ich die Skalierung auf die Zoomstufen gecached und nur die png files rotiert, bzw. skaliert. Der Gedanke für SVG war der, dass ich vermutet habe, dass man Rechenzeiten bei den Transformationen sparen könnte und gleichzeitig qualitativ bleibe. Daher auch mein Gedanke die SVG Files in Java2D zu überführen und dann mit neuen Rotations und Skalierungsparamatern im Renderprozess zu zeichnen. 

Eventuell macht die Verwendung von SVG (Wobei mir pixelgenaue Funktionalität schon wichtig wäre) an gar keiner Stelle Sinn und ich bin schon auf einem recht gangbarem Weg, dass würde ich halt nur gern etwas genauer erörtern. Was meinst du / ihr dazu?

Danke!!


----------



## Spacerat (11. Jul 2012)

Anders herum. Für dynamischen Kontext SVG, für statischen PNG. Wenn du aber nur PNGs per SVG drehen, skalieren oder verzerren willst, dann bleib besser bei Java2D. SVGs machen nur Sinn, wenn du damit Polygone oder ähnliches zeichnest. Für Capcha-Bilder z.B. ist SVG hervorragend geeignet. PNGs wellenförmig verzerren, bekommt man auch mit Java2D hin.


----------



## tuedel (11. Jul 2012)

Demnach wäre also ein guter Weg, die sich rotierenden und bewegenden Objekte im "Design" als SVG zu importieren und per Parser in Java2D code umzusetzen und anhschließend nach Bedarf zu transformieren? Das klingt für mich jetzt jedenfalls ganz annehmbar. 

Wie ist das mit statischem Kontext, der Funktionalität erhalten soll? Bspw. Teile einer Grafik mit Mouseevents zu versehen. Relative Pixelkoordinaten aus PNG Files empfinde ich als unelegant und ist bei Kurvenverläufen ohnehin schonwieder anders. Man könnte ja bspw. eine SVG File für statischen Kontext ebenfalls in Java2D code überführen und dann die einzelnen Instanzen mit Mousevents versehen? Oder geht das ohnehin viel eleganter und ich weiß es schlichtweg nicht : )?


----------



## Spacerat (11. Jul 2012)

Ich weis nicht, wie du statischen Kontext mit SVG verbindest. Statischer Kontext und Funktionalität?
Warum hat ein Kontext Funktionalität? Evtl. weil er dynamisch ist? (Die Frage ist rein rhetorisch. )
In SVGs stehen Vektoren, Beziers, Schriftzüge usw. Alles in GeneralPath-Manier, und genau in solche Instanzen solltest du ein SVG einlesen. Dann erstellst du ein BufferedImage in gewünschter Grösse und gewünschem Typ, besorgst dir davon ein Graphics2D-Objekt und zeichnest dort die GPs der SVGs rein. Und das widerholst du bei jedem Renderdurchlauf. Mit den MouseEvents bewegst du nur einzelne Punkte in den GP-Instanzen. Das ist dynamischer Kontext.


----------



## tuedel (12. Jul 2012)

Guten Morgen : ).

Was das mit dem "dynamisch - statischen" Kontext auf sich hat, sollte ich vllt besser erklären.
An sich geht es mir darum, dass ich Grafiken habe, die wie bei einer Imagemap "pixelgenau" auf Mouseevents Inhalte der Grafik ändern sollen. Sodass ich in der Lage bin Teile der Grafik zu highlighten.

Deswegen kam mir der Gedanke SVG zu verwenden, um zum einen den Style in die SVG auszulagern und dann über Java2D Objekte den Style in der SVG anzupassen, wenn der Mouseclick bspw. innerhalb einer Shape liegt. Was mir da halt bisher begegnet ist, sind die Möglichkeiten über Pixelfarben oder halt von vornherein Java2D Objekte vorzuhalten und mit der besagten Funktionalität zu versehen. Vielleicht gibt es auch noch eine elegantere Methode?!

Was mich halt an der SVG File für die Rotation und Skalierung immernoch stört ist, dass ich mir vorstellen kann, dass ich weniger performant bin, wenn ich immerzu die SVG Tags ändere, dann rotiere/skaliere und anschließend in eine BufferedImage painte und das Ganze render. Es sind halt auch kleine Bilder, wo die Rotation nicht zuuu viel kosten sollte, auch bei normalen Images. Mich reizt halt die Qualität, aber die Frage ist halt wieviel Performanz mich das kosten würde.

LG


----------



## Spacerat (12. Jul 2012)

Das soll also so eine Art Malprogramm werden. In diesem Fall hättest du ja nun beides. Ein PNG (original) und ein SVG welches sozusagen als Protokolldatei dient. In diesem Fall würde ich aber weniger zu einem SVG raten, sondern Serializable der GeneralPath Klassen nutzen, also die Manipulationen per ObjectStream speichern / laden. Wenn das Bild dann fertig manipuliert ist, kann man auch das aus beiden erstellte BufferedImage per ImageIO speichern und auch wieder laden.
Du kannst aber auch die SVG weiter als Protokolldatei verwenden, musst dann deine Manipulationen (GP-Klassen) in einer Objektliste halten, zur Laufzeit mit dieser arbeiten und erst am Ende wieder als SVG speichern. es ist auf jeden Fall sehr unperformant, wenn man nach jedem Schritt die Protokolldatei speichert.


----------



## tuedel (13. Jul 2012)

Guten Morgen :  ).

Naja ein Malprogramm ist es nicht : ). Ich möchte die Ergebnisse der Manipulation auch nicht speichern. Das Ding ist, dass ich das komplette styling der UI auslagern möchte, sodass man in Zukunft abstrakt eine neue SVG definiert und diese dann die bisherige UI einfach ersetzen kann. Im Grunde geht es dabei nur um Grafikelemente, die "unförmige" - sagen wir eine GP Struktur aufweisen. Bspw. ein Button der Teil einer umfangreicheren Grafik ist. Nun will ich zur Laufzeit mit einem Mouseevent auf den besagten Button dessen Aussehen verändern, ohne wie in normalen Bilddateien in Pixeloperationen gehen zu müssen. Schließlich soll ein Button ja auch so wirken, als wäre er einer, statt nur ein Bild. Daher möchte ich lediglich für eine Geometry den Style tag in der SVG anpassen/auswählen und neu in eine BufferedImage zeichnen und cachen. Damit wären meine Mousevents pixelgenau und das Styling komplett ausgelagert. 

Wenn man damit jetzt umfangreiche Grafiken z.B. für Header, Footer etc in SVG definiert, müsste man nur sicherstellen, dass man eindeutige Bezeichner für die ID's eines bestimmten UI elementes verwendet und könnte den Rest sehr abstrakt implementieren, den Zeichenprozess quasi. Ich hatte mir beispielhaft folgendendes Format dafür überlegt: 

[XML]<svg width="400" height="400">
    <defaultContext>  // Mit Styles - das soll statischer, sich nicht ändernder Grafikteil sein. Keine ID notwendig
		<circle/>
		<rectangle/>
		<GeneralPath/>
	</defaultContext>
	<defaultGeometry>  // Nur Geometry - das soll die Vergleichsinstanz werden, damit ich Mouseinteraktionen identifizieren kann
		<circle id="x"/>
		<rectangle id="y"/>
		<generalPath id="z"/>
	</defaultGeometry>

	// Hier die einzelnen Mouseinteraktionen. Wenn ich eine Koordinatenübereinstimmung habe, kann ich anhand der id, die Geometry mitsamt des styles aus dem jeweiligen Mousetag holen und zeichnen.
	// Hier müssen Styles also mit rein.
	<mouseMoved>
		<circle id="x"/>
		<rectangle id="y"/>
		<generalPath id="z"/>
	</mouseMoved>
	<mouseReleased>
		<circle id="x"/>
		<rectangle id="y"/>
		<generalPath id="z"/>
	</mouseReleased>
	<mousePressed>
		<circle id="x"/>
		<rectangle id="y"/>
		<generalPath id="z"/>
	</mousePressed>
	<mouseHovered>
		<circle id="x"/>
		<rectangle id="y"/>
		<generalPath id="z"/>
	</mouseHovered>
</svg>[/XML]

Ich kann im Moment noch nicht wirklich behaupten, dass das eine notwendige und lohnenswerte Implementierung ist, aber objektorientierte Grafikprogrammierung empfinde ich an sich erstmal elegant und leichter nachvollziehbar. Wieviel ImageMap SVG's ich am Ende bräuchte hängt von dem Designvorschlag ab, bzw. wie stark man davon Gebrauch machen kann. Die Geometry Redundanz in der SVG habe ich derzeit drin, da ich in der javadoc vom salamander noch keine Methode finden konnte, womit ich den kompletten style aus einem tag für ein anderes tag setzen kann.

An sich könnte man natürlich auch die "Hot spots" als separate Grafiken vorhalten und dessen "Modifikationen" ebenfalls. Diese dann relativ zur "Parentimage" zeichnen. Allerdings bräucht ich die Image dann wieder in einem Container, um die Mouseevents zu setzen. 

Für die sich bewegenden Objekte könnte man ebenfalls SVG verwenden, aber da müsste man halt wirklich wissen, ob das performant bleibt. Man könnte an sich auch die Geometrien rausziehen, transformieren, in eine BufferedImage Instanz zeichnen und anschließend rendern. Nur weiß ich nicht, ob sich der Aufwand lohnt, wenn ich am Ende vielleicht langsamer werde und nur einen akzeptablen Qualitätsschub feststellen könnte.

Herzlichen Dank.
LG tuedel


----------



## Spacerat (13. Jul 2012)

Geht's also nur um um Rollover Effekte einzelner Buttons? Wozu dann 'ne ImageMap? Solche Effekte bekommt man mit GIF's und ImageReady viel leichter und auch performanter hin. Vllt. machst du mal ein Beispielbild mit div. Effekten, was du dir wie vorstellst. SVG und GeneralPath halte ich dafür zumindest für gründlich überzogen.


----------



## tuedel (13. Jul 2012)

Alles klar. Das wollt ich wissen : ). 

Mir war das auch suspekt, da für eigentlich sehr einfache Rollover Effekte da ne recht umfangreiche Umsetzung iwie Overload ist. An sich gefiel mir nur die Arbeit mit den Objektidentitäten, die man da hätte. Ich hatte lediglich gehofft, dass man vielleicht auf die ein oder andere Idee kommt, was man damit nettes machen könnte. Allerdings hat auch keiner meiner Bekannten eine so einfache Umsetzung vorgeschlagen, keine Ahnung. Von ImageReady hatte ich bisher jedenfalls nicht gehört : ).

Damit ist das ja ad acta. Hälst du es denn für möglich, dass sich der Einsatz von SVG für Transformationen lohnen könnte? Ehrlich gesagt kann ich es mir nicht vorstellen, aber eine zweite entschiedene Meinung zu haben, beruhigt mich irgendwie : ).

LG


----------



## tuedel (13. Jul 2012)

Sind dann Grafiken, die mit ImageReady erstellt worden sind, sensitiv auf die jeweiligen MouseEvents, ohne zusätzlichen Code in java?


----------



## Spacerat (13. Jul 2012)

Also ImageReady erstellt dir webfertige Grafiken. Für diese Buttongeschichte erstellt es pro Rollover eine Gif-Datei und für den gesamten Effekt ein JavaScript. In Java kann das Ganze dann per Rhino und ImageIO zusammengefügt werden.
Also ausser das SVGs verlustfrei skalierbar sind bieten sie für statisches nicht wirklich viel. Rollovereffekte funktionieren zwar damit, aber wenn es nicht bei Pseudo-3D-Umrandungen bleiben soll, dann gehts doch besser mit Images. Runde Schaltflächen abfragen fällt auch mit SVGs aus, es sei denn, du planst ganze GUIs als ImageMap (OMG nicht so was). Nicht dass Vektorielles komplett für die Tonne ist, aber Qualität und Performance kann man damit nicht zusammen bekommen.


----------

