Batik: Inhalt JComponent to SVG?

blz

Bekanntes Mitglied
Hallo,
ich finde zwar viel Content im Web, aber letztlich nicht die Antwort auf meine Frage:
Wie kann ich möglichst einfach den Inhalt einer JComponent als SVG file speichern?
Ich möchte einerseits in die JComponent hineinzeichnen und die Zeichnung im Programm angezegit bekommen, und andererseits über einen Speichern-Button das Ganze als SVG speichern können.
Ich habe es hinbekommen, wenn ich bei jedem Zeichenvorgang einerseits auf das Graphics-Objekt male und andererseits dasselbe nochmal auf das SVGGraphics-Objekt von Batik zeichne.
Aber es muss doch auch einfacher möglich sein, nämlich so, dass ich beliebig viel in Java zeichne und dann, wenn ich speichern drücke, der gesamte Inhalt der Komponente als SVG gespeichert wird?!
 

Robert Zenz

Top Contributor
Ohne jetzt zu wissen was genau du da machst, aber ich denke dass Problem das du hierbei uebersiehst ist der Unterschied zwischen Pixel- und Vektor-Grafiken. Wenn du jetzt in deiner JComponent zeichnest, malst du "nur" Pixel an, fuer ein SVG musst du das alles aber als (quasi) Vektoren haben. Damit gibt es hier nur zwei Moeglichkeiten:
  1. Du ueberlegst dir eine Umwandlung von der JComponent auf Vektor-Grafik.
  2. Du malst beides gleichzeitig.
So oder so, wird es gefuehlt Unterschiede zwischen beiden geben, weil das nicht eins-zu-eins uebersetzbar ist, nicht direkt zumindest.

Ich meine, wenn alles versagt kannst du eine Bitmap im SVG einbetten, aber das ist irgendwie Sinnfrei.

Was ist denn dein genauer Anwendungsfall? Was wird da gezeichnet dass du es dann als SVG brauchst?
 

Oneixee5

Top Contributor
Es gibt die Klassen
org.apache.batik.svggen.SVGGraphics2D;
org.apache.batik.swing.JSVGCanvas;
Damit kannst du direkt ein SVG-XML-Doc wie ein normales java.awt.Canvas verwenden. Den XML-DOM behältst du einfach im Speicher, wenn nötig speicherst du dann einfach als SVG.
Ich hebe mal, auf die Schnelle ein hässliches 10-Minuten-Beispiel gemacht. Also nicht kopieren, es geht nur ums Prinzip:

Java:
package swing;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.WindowConstants;

import org.apache.batik.anim.dom.SVGDOMImplementation;
import org.apache.batik.svggen.SVGGraphics2D;
import org.apache.batik.swing.JSVGCanvas;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Element;
import org.w3c.dom.svg.SVGDocument;

public class SvgPaint extends JFrame {

    private final List<Rectangle> rectangles = new ArrayList<>();

    private JSVGCanvas canvas = null;

    public SvgPaint() {
        this.canvas = new JSVGCanvas();
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        final GridBagLayout layout = new GridBagLayout();
        getContentPane().setLayout(layout);
        final JButton buttonSave = new JButton("Speichern");
        buttonSave.addActionListener(e -> drawPoints(false));

        final GridBagConstraints gridBagConstraintsButton = new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
                GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0);
        getContentPane().add(buttonSave, gridBagConstraintsButton);

        final GridBagConstraints gridBagConstraintsSVG = new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0,
                GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0);
        getContentPane().add(this.canvas, gridBagConstraintsSVG);

        this.canvas.addMouseListener(new MouseAdapter() {

            private int startX = -1;
            private int startY = -1;

            @Override
            public void mousePressed(MouseEvent e) {
                this.startX = e.getX();
                this.startY = e.getY();
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                int intX = e.getX();
                int intY = e.getY();
                int intWidth = intX - this.startX;
                if (intX < this.startX) {
                    intWidth = -1 * intWidth;
                    final int intTemp = intX;
                    intX = this.startX;
                    this.startX = intTemp;
                }
                int intHeight = intY - this.startY;
                if (intY < this.startY) {
                    intHeight = -1 * intHeight;
                    final int intTemp = intY;
                    intY = this.startY;
                    this.startY = intTemp;
                }

                final Rectangle rect = new Rectangle(this.startX, this.startY,
                        intWidth, intHeight);
                SvgPaint.this.rectangles.add(rect);

                drawPoints(true);
            }
        });

    }

    private void drawPoints(boolean drawOrSave) {

        final DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
        final String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
        final SVGDocument doc = (SVGDocument) impl.createDocument(svgNS, "svg", null);
        final SVGGraphics2D g = new SVGGraphics2D(doc);

        for (final Rectangle rectCurrent : this.rectangles) {
            final Shape circle =
                    new Ellipse2D.Double(rectCurrent.x, rectCurrent.y, rectCurrent.width, rectCurrent.height);
            g.setPaint(Color.red);
            g.draw(circle);
        }

        if (drawOrSave == true) {
            final Element root = doc.getDocumentElement();
            g.getRoot(root);
            this.canvas.setSVGDocument(doc);
        } else {
            try (FileWriter fileWriter = new FileWriter("test.svg")) {
                g.stream(fileWriter, false);
            } catch (final IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        final SvgPaint form = new SvgPaint();
        form.pack();
        form.setVisible(true);
    }

}
 

blz

Bekanntes Mitglied
Vielen Dank, das ist sehr nett und glaube ich auch genau das, was ich brauche.
Ich spezifiziere noch einmal meine Anforderungen:
Ich habe ein Programm zum Zeichnen von Diagrammen geschrieben. Ich habe ein JLayeredPane, das mehrere durchsichtige JPanels enthält, die sich z. T. auch überlappen. Auf den einzelnen JPanels zeichne ich Rechtecke, Linien und habe JTextareas.
Bisher habe ich das alles unter Swing als Pixelgrafik gezeichnet und mir eine eigene Zoomroutine geschrieben, da mir der Gedanke, dass ich das auch als Vektorgrafik speichern könnte, erst gar nicht gekommen ist.

Nun, da er mir gekommen ist, war mein erster Gedanke, vllt. gibt es ja eine Methode, die all die Inhalte automatisch in eine Vektorgrafik transcodiert. Quasi so, dass ich beim Speichern-Button nur schreiben muss: Speichere die Inahlte der Kinder des JLayeredPane alle als SVG. fertig.
Aber das scheint es ja nicht zu geben.

Alle Inhalte parallel in Pixel- und Vektorgrafik zu malen wäre machbar. Da aber meine eigene Zoomroutine nicht ganz perfekt ist, favorisiere ich nun den Gedanken, alles von vornherein als Vektorgrafik zu erstellen. Dann gibt es vermutlich eine native Zoomfunktion, die man nutzen kann.

Ich fasse die Erklärungen von Oneixee5 noch mal in eigenen Worten zusammen, um sicherzugehen, dass ich das richtig verstanden habe:
Mit "ein SVG-XML-Doc wie ein normales java.awt.Canvas verwenden" meinst du, ich zeichne letztlich vom Vorgehen her genauso wie in Swing auf mein JPanel, allerdings wird keine Pixelgrafik erstellt, sondern eben eine Vektorgrafik, ein SVG-XML-Document. Wenn ich dann speichern will, habe ich Zugriff auf die XML-Dokumentenstruktur und kann ganz einfach als XML speichern (und vermutlich auch als Pixelgrafik exportieren.)

Das Beispiel bringe ich leider nicht zum Laufen, da der letzte Import nicht funktioniert:
The import org.w3c.dom.svg.SVGDocument cannot be resolved
Ich nehme an, es ist ein Versionenproblem?! Bisher konnte ich es nicht lösen...
 

Oneixee5

Top Contributor
Wie gesagt, das ist nur so auf die Schnelle zusammengeschustert, das geht bestimmt noch sauberer - die Abhängigkeiten:

XML:
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-swing</artifactId>
    <version>1.14</version>
    <exclusions>
        <exclusion>
            <artifactId>xml-apis</artifactId>
            <groupId>xml-apis</groupId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-svggen</artifactId>
    <version>1.14</version>
    <exclusions>
        <exclusion>
            <artifactId>xml-apis</artifactId>
            <groupId>xml-apis</groupId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-util</artifactId>
    <version>1.14</version>
</dependency>
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-constants</artifactId>
    <version>1.14</version>
</dependency>
 

Oneixee5

Top Contributor
Ich fasse die Erklärungen von Oneixee5 noch mal in eigenen Worten zusammen, um sicherzugehen, dass ich das richtig verstanden habe:
Mit "ein SVG-XML-Doc wie ein normales java.awt.Canvas verwenden" meinst du, ich zeichne letztlich vom Vorgehen her genauso wie in Swing auf mein JPanel, allerdings wird keine Pixelgrafik erstellt, sondern eben eine Vektorgrafik, ein SVG-XML-Document. Wenn ich dann speichern will, habe ich Zugriff auf die XML-Dokumentenstruktur und kann ganz einfach als XML speichern (und vermutlich auch als Pixelgrafik exportieren.)
Nein, s. Beispiel:

Java:
        final SVGDocument doc = (SVGDocument) impl.createDocument(svgNS, "svg", null);
        final SVGGraphics2D g = new SVGGraphics2D(doc);

        for (final Rectangle rectCurrent : this.rectangles) {
            final Shape circle =
                    new Ellipse2D.Double(rectCurrent.x, rectCurrent.y, rectCurrent.width, rectCurrent.height);
            g.setPaint(Color.red);
            g.draw(circle);
        }
Du zeichnest deine Vektoren in das SVG/XML und SVGGraphics2D/JSVGCanvas übernimmt das Darstellen. SVG ist keine Pixelgrafik!

Java:
final Element root = doc.getDocumentElement();
g.getRoot(root);
this.canvas.setSVGDocument(doc);

Eine Zoomfunktion ist quasi überflüssig, da es sich um eine Vektorgrafik handelt. Es ist für SVG sozusagen eine Grundfunktion, verlustfrei zoombar zu sein.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
FrittenFritze Batik und AffineTransform AWT, Swing, JavaFX & SWT 2
S svg Icon für Button (Batik Problem?) AWT, Swing, JavaFX & SWT 3
B Vektorgrafik mittels Batik Tool anzeigen AWT, Swing, JavaFX & SWT 3
H AWT Dialog Größe ändern - Schwarzer Inhalt beim groß ziehen AWT, Swing, JavaFX & SWT 1
Fragerjava Frame inhalt komplett löschen AWT, Swing, JavaFX & SWT 4
_user_q Wie den Inhalt vom Spinner auf Integer überprüfen? AWT, Swing, JavaFX & SWT 15
izoards JavaFX TableView mit Array Inhalt füllen AWT, Swing, JavaFX & SWT 1
B JavaFX TableView-Zellen sollen automatisch so groß wie der größte Inhalt sein AWT, Swing, JavaFX & SWT 6
B JavaFX TextInputDialog: Focus auf Eingabefeldinhalt setzen und nach OK Inhalt leeren AWT, Swing, JavaFX & SWT 5
H JTabel Inhalt löschen AWT, Swing, JavaFX & SWT 1
L JDialog hat manchmal keinen Inhalt AWT, Swing, JavaFX & SWT 2
A Swing Datei lässt sich zwar speichern, aber nicht laden (Inhalt im JTextField anzeigen) AWT, Swing, JavaFX & SWT 18
ZH1896ZH JavaFX Wie kann ich die Fenstergrösse entsprechend dem Inhalt vergrössern/verkleinern AWT, Swing, JavaFX & SWT 2
K JavaFX Component Größe an Inhalt anpassen AWT, Swing, JavaFX & SWT 11
L JavaFX Pane inklusive Inhalt der Bildschirm Auflösung anpassen AWT, Swing, JavaFX & SWT 13
Hatsi09 JTextArea Inhalt verlinken AWT, Swing, JavaFX & SWT 4
L JPanel zeigt keinen Inhalt AWT, Swing, JavaFX & SWT 1
A Inhalt wechseln bei Klick auf Label AWT, Swing, JavaFX & SWT 8
C JTextField Inhalt mit Maus selektieren wenn disabled AWT, Swing, JavaFX & SWT 2
C JavaFX ProGuard -> TableView kein Inhalt AWT, Swing, JavaFX & SWT 7
D Inhalt von JTextField in MySQL speichern. Wie ? AWT, Swing, JavaFX & SWT 1
C JavaFX Inhalt eines SplitPane's durch Menü-Auswahl ändern? AWT, Swing, JavaFX & SWT 13
MaxG. JavaFX Inhalt in Tableview wird nicht angezeigt AWT, Swing, JavaFX & SWT 11
T [Neuling] Textfeld Inhalt überprüfen und falsche Stellen als msg Ausgeben AWT, Swing, JavaFX & SWT 1
Kanda Sorata Inhalt einer .txt Datei einlesen und in ein Label einfügen (JavaFX) AWT, Swing, JavaFX & SWT 2
gamillton Swing JComboBox mit extra Inhalt + breiteres Popupmenü AWT, Swing, JavaFX & SWT 0
M Swing Inhalt meines JTables wird falsch dargestellt AWT, Swing, JavaFX & SWT 8
P TreeView automatisch an große von Inhalt anpassen AWT, Swing, JavaFX & SWT 3
U Swing Inhalt vom Fenster wird erst durch Hovern oder Klicken sichtbar AWT, Swing, JavaFX & SWT 3
G Menübar anklicken und Inhalt entsprechend wechseln AWT, Swing, JavaFX & SWT 4
A Nach klick auf Button neuen Inhalt im gleichen Fenster AWT, Swing, JavaFX & SWT 3
Z Swing Frame wird geöffnet, aber ist ohne Inhalt AWT, Swing, JavaFX & SWT 0
A JavaFX Von Klasse auf Controller Inhalt zugreifen AWT, Swing, JavaFX & SWT 9
V JScrollBar soll weiterscrollen, wenn Inhalt von JTextArea erweitert wird AWT, Swing, JavaFX & SWT 7
K Swing Inhalt eines JPanels lesen AWT, Swing, JavaFX & SWT 3
Tausendsassa Frame öffnet aber zeigt keinen Inhalt... AWT, Swing, JavaFX & SWT 10
A BorderLayout "Center" Inhalt wechseln AWT, Swing, JavaFX & SWT 1
D Swing JTable mit Inhalt aus XML-File AWT, Swing, JavaFX & SWT 3
A JFace/SWT: ListViewer Inhalt nach Selection in zweitem List Viewer aktualisieren! AWT, Swing, JavaFX & SWT 5
S Swing Nur den sichtbaren Bereich eines TextPane mit Inhalt darstellem AWT, Swing, JavaFX & SWT 0
E JavaFX JavaFX - MenuItem erstellen aus dem Inhalt einer HashMap AWT, Swing, JavaFX & SWT 1
Z JavaFX Inhalt einer ViewTable durch Aktion einer Menubar ändern welche in einer anderen fxml ist AWT, Swing, JavaFX & SWT 4
M ausgewählte Inhalt von ListItem inn ComboBox in der Tabelle speichern AWT, Swing, JavaFX & SWT 0
E JavaFX Sehr viel und unterschiedlich Großen Inhalt auf einer "Fläche" ... Umsetzbar ? AWT, Swing, JavaFX & SWT 3
D 2D-Grafik Inhalt eines Graphics in anderes Graphics zeichnen.... AWT, Swing, JavaFX & SWT 3
JAVAnnik JavaFX Inhalt der TreeCell nicht einrücken AWT, Swing, JavaFX & SWT 1
F AWT Drucken verschluckt inhalt AWT, Swing, JavaFX & SWT 1
S Inhalt der Java-Konsole in die JTextArea AWT, Swing, JavaFX & SWT 3
TheJavaKid JTextField: Reine Domain herausfiltern, sonst Inhalt löschen AWT, Swing, JavaFX & SWT 1
A Swing JLabel/JTextField Inhalt mit JSlider verändern AWT, Swing, JavaFX & SWT 12
OnDemand Inhalt des Frames ändern AWT, Swing, JavaFX & SWT 4
S SWT TableCell mit Composite als Inhalt / Höhe der Cell/Row AWT, Swing, JavaFX & SWT 5
3 Swing JList-Inhalt als verschlüsselte Datei schreiben und lesen AWT, Swing, JavaFX & SWT 1
C Swing Anzeigeproblem mit TableModels abhängig von deren Inhalt AWT, Swing, JavaFX & SWT 10
H Swing JScrollPane mit "viel Inhalt" scrollt zu langsam (inkl. See-For-Yourself.jar :D) AWT, Swing, JavaFX & SWT 2
I JTable Spalten automatisch dem Inhalt anpassen! AWT, Swing, JavaFX & SWT 6
P Swing Dialog zeigt keinen Inhalt in Verbindung mit JFrame AWT, Swing, JavaFX & SWT 18
0 JTable Spaltenbreite automatisch an Inhalt anpassne geht nicht AWT, Swing, JavaFX & SWT 3
M EditorPane Inhalt anders als er soll! AWT, Swing, JavaFX & SWT 2
S Swing JFormattedTextField - bei nicht korrekter Eingabe Inhalt überschreiben AWT, Swing, JavaFX & SWT 5
S Swing JFormattedTextfield markiert nicht gesamten Inhalt AWT, Swing, JavaFX & SWT 4
A 2D-Grafik Panel inhalt löschen AWT, Swing, JavaFX & SWT 5
H JCombobox inhalt löschen AWT, Swing, JavaFX & SWT 17
N Swing JCombobox - PopupMenu-Inhalt mit KSKB AWT, Swing, JavaFX & SWT 2
N Swing KomponentenHöhe an html-Inhalt anpassen AWT, Swing, JavaFX & SWT 4
S Inhalt einer JComboBox aktualisieren AWT, Swing, JavaFX & SWT 6
Nicklas2751 Table View zeigt keinen Inhalt nur leere Zeilen AWT, Swing, JavaFX & SWT 2
A JComboBox-Inhalt durch neues Array ersetzen AWT, Swing, JavaFX & SWT 2
D LayoutManager JScrollPane mit dynamischem Inhalt AWT, Swing, JavaFX & SWT 8
N Fehler Inhalt von JTable wird gelöscht AWT, Swing, JavaFX & SWT 5
C SWT Wie greife ich auf den Inhalt einer bestimmten Zeile zu? (TableViewer) AWT, Swing, JavaFX & SWT 7
H JFrame Inhalt neu aufbauen? AWT, Swing, JavaFX & SWT 8
M Beim Start von TableEditor Inhalt der Zelle markieren. AWT, Swing, JavaFX & SWT 2
T Inhalt von einem Tab an JTabbedPane größe ausrichten? AWT, Swing, JavaFX & SWT 2
TheWhiteShadow JList-Inhalt nach Änderung weg AWT, Swing, JavaFX & SWT 3
P Swing JScrollPane-Inhalt: Grösse anpassen AWT, Swing, JavaFX & SWT 6
0 JFrame zeigt Inhalt erst nach vergrößern an AWT, Swing, JavaFX & SWT 3
P AWT Wie kann mein listener den Inhalt eines anderen Textfelds ändern? AWT, Swing, JavaFX & SWT 10
L JFrame an Paint-Inhalt anpassen AWT, Swing, JavaFX & SWT 6
A Swing JScrollPane zeigt keinerlei Inhalt an AWT, Swing, JavaFX & SWT 2
H Swing JPanel Inhalt wird bei verwenden von JPopup gelöscht AWT, Swing, JavaFX & SWT 5
C SWT Textfeld mit festem und variablen Inhalt AWT, Swing, JavaFX & SWT 13
X Swing JTable stets mit gleichem Inhalt öffnen AWT, Swing, JavaFX & SWT 3
O JTable mit Inhalt drucken AWT, Swing, JavaFX & SWT 3
L Inhalt einer table löschen AWT, Swing, JavaFX & SWT 2
C Swing Inhalt einer JTable aktualisieren und filten nach Feldern die nicht in der Tabelle sind AWT, Swing, JavaFX & SWT 3
lumo SWT ScrolledComposite maximierter inhalt AWT, Swing, JavaFX & SWT 2
K Tabellen Inhalt ( Zelle ) Modifizieren AWT, Swing, JavaFX & SWT 2
H Swing HTML in einem JEditorPane zeilenweise hinzufügen ohne Inhalt jedes Mal neu zu laden AWT, Swing, JavaFX & SWT 4
D Transparentes JFrame mit inhalt AWT, Swing, JavaFX & SWT 7
S Swing JTabbedPane: Inhalt soll oben links anfangen AWT, Swing, JavaFX & SWT 6
O Swing Inhalt des JFrames wird nicht angezeigt AWT, Swing, JavaFX & SWT 3
0 2D-Grafik Screenshot von ScrollBar-Inhalt AWT, Swing, JavaFX & SWT 2
B JTextPane formatierten Inhalt speichern AWT, Swing, JavaFX & SWT 2
C Swing JTable zeigt in jeder Zelle einer Reihe denselben Inhalt AWT, Swing, JavaFX & SWT 2
B Inhalt eines ScrolledComposite ändern AWT, Swing, JavaFX & SWT 5
M Swing jList Inhalt neu anzeigen AWT, Swing, JavaFX & SWT 6
S Swing Inhalt eines Fenster bei Größenänderung anpassen (GroupLayout) AWT, Swing, JavaFX & SWT 2
C Swing Inhalt eines JPanels ermitteln & bearbeiten AWT, Swing, JavaFX & SWT 5
G LayoutManager per Button GridBagLayout + Inhalt ändern AWT, Swing, JavaFX & SWT 2

Ähnliche Java Themen

Neue Themen


Oben