Gibt es für tkinter Vektorgrafik Bibliotheken?

Fragen zu Tkinter.
BlackJack

@Alfons Mittelmeyer: LibreOffice ist nicht unbedingt das beste Programm um SVG-Grafiken zu bearbeiten weil das Grafik-Format von LibreOffice, und damit auch der Editor, nicht den vollen SVG-Umfang unterstützt. Inkscape ist da beispielsweise wesentlich besser geeignet. Das verwendet auch intern SVG als Format.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@BlackJack Ich will ja auch keine SVG Grafiken bearbeiten. Ich wollte nur darauf hinweisen, dass SVG nicht ganz so einfach ist, wie mancher vielleicht es sich vorstellt. Direkt SVG automatisch nach tkinter konvertieren geht nicht, da SVG sich etwas anders verhält, als mancher vielleicht denkt.

Was geschieht etwa, wenn man eine Fläche gezeichnet hat und eine größere Fläche in anderer Farbe darüber legt?
Die darübergelegte Fläche sollte die darunter verdecken, möchte man meinen.
Aber nein in SVG ist es so nicht. Die darübergelegte Fläche endet an der bereits vorhandenen und bildet so eine Umrahmung derselben.
Tja, das geht in tkinter nicht. Also muss man die Reihenfolge vertauschen und erst die größere Fläche zeichnen und danach erst die darin.

Was geschieht etwa, wenn man einen Teil einer Fläche in anderen Farbe übermalt hat, etwa den schwarzen Rock eines Pinguins mit einem weißem Gesicht und weißem Bauch.

Was geschieht, wenn man noch zusätzlich mit weiß darauf malt? Das wirkt dann wie ein Radiergummi und löscht dann das Weiß auf dem schwarzen Rock wieder weg, sodaß dort der schwarze Rock wieder durchschaut.

Um das dann richtig zu machen, muß man dort die richtige Farbe einstellen, also schwarz statt weiß. Mitunter auch die Hintergrundfarbe des Canvas (etwa Elefant).
BlackJack

@Alfons Mittelmeyer: Oh man, Du solltest echt weniger rumschwafeln und vielleicht mal die Spezifikation von SVG lesen statt es durch Versuch und Irrtum zu solch ausschweifenden und teilweise irreführenden Beschreibungen zu kommen. SVG verhält sich nicht anders als ”mancher” sich das denkt, sondern anscheinend hauptsächlich wie *Du* dir das wohl gedacht hast.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@BlackJack Wenn Du anscheinend so gescheit bist, vielleicht kannst ja Du dann erklären, wie die Löcher in den Käse kommen.

Also eine Scheibe Käse zeichnen und Löcher herausschneiden sieht gleich aus. Die Frage ist da, wann zeichnet man eine Scheibe Käse und wann schneidet man da Löcher heraus.

Die Regel nach der Spezifikation bei fill-rule evenodd ist folgende:

evenodd
This rule determines the "insideness" of a point on the canvas by drawing a ray from that point to infinity in any direction and counting the number of path segments from the given shape that the ray crosses. If this number is odd, the point is inside; if even, the point is outside.

Vielleicht magst Du das ja näher erklären?

PS:
Und dass ein Loch in einer Wand etwas anderes ist, wie wenn man ein Viereck auf eine Wand malt, sollte auch klar sein. Denn das eine ist ein Fenster, durch das man durchschauen kann. Und mit tkinter ein Viereck auf eine Wand malen ergibt nicht den selben Effekt.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Jedenfalls, wenn man innerhalb eines shapes innerhalb einer gefülltem Fläche nochmals eine Fläche zeichnet, zählt diese bei fill-rule evenodd als Loch. Bei fill-rule nonzero käme es noch darauf an, ob man den Pfad dann im oder entgegen dem Uhrzeigersinn angibt.

Wenn hinter dem Loch nur einfarbiger Hintergrund liegt, kann man statt Loch diese Fläche in dieser Hintergrundfarbe zeichnen. Wenn hinter dem Loch aber bereits ein Objekt ist, dieses das Loch aber nicht überschneidet, kann man die Reihenfolge tauschen. Wenn das Objekt aber größer als das Loch ist, hat man eventuell Pech gehabt.
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: man kann auch höflich fragen, wenn man etwas nicht versteht. In der Art: "SVG hat da sowas wie die evenodd-Füllmethode und Objekte, die aus mehreren Pfaden bestehen und gefüllt werden. Leider verstehe ich nicht, wie das gemeint ist."

Und da denkst Du Dir am besten einen Stift, der über den Bildschirm von links nach rechts fährt. Übertritt er eine Linie des Polygons, Stift an, übertritt er die nächste Linie, Stift aus, usw.
Das unterstützt TK nicht und das nachzubilden bedarf der Aufteilung des Polygons mit Löchern in Teile ohne Loch, statt einfach mit irgendeiner anderen Farbe drüberzupinseln.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Alfons:
Du wirst nicht umhin kommen, die SVG-Spec genau zu studieren und das dann in einem eigenen Objektmodell (DOM?) zu implementieren, wenn Du SVG umsetzen willst. Diese Objekte kennen dann ihre Lage im Raum/Fläche, Farbe, Form und Positionen/Überdeckungen zueinander. Das Canvas kannst Du dann nutzen, um eine Ausgabe dafür zu haben.
Die Frage ist dann Javascript oder nicht. Willst Du den vollen Standard umsetzen, gehört es dazu, dann aber bitte auch SMIL und andere nifty Transformationsmethoden nicht vergessen. Mit Javascript an Board hättest Du gleich drei Möglichkeiten, das Interface schlussendlich als SVG-Editor interaktiv zu gestalten: Tcl, Python, Javascript (+ ein bisschen C für die Transformationen) Das ist garantiert ein Projekt für viele Jahre ;)
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@jerch Ein eigenes GUI Framework auf SVG Basis will ich sicher nicht machen. Es ging um die Fragestellung, ob man SVG Grafiken nach tkinter konvertieren kann. Man kann, aber nicht vollautomatisch für alle Grafiken. Sogar einfache Grafiken, wie der Pinguin nutzen die Lochmethode.

Beim Pinguin ist ein Shape der Schwarze Rock. Der zweite Shape ist das weiße Gesicht und der weiße Bauch, wo man dann gleich im Anschlusss die Augen und den Schnabel als Löcher reinzeichnet.

Der Löwe ist noch etwas komplizierter. Zuerst der Löwenörper. Der nächste Shape die tiefbraunen Stellen, wie Augen, Nase und Maul.
Darauf setzt man dann die überdeckende Mähne und schneidet ein Loch für das Gesicht hinein.

Das muss man dann umordnen. Zuerst der Löwenkörper. Darauf kommt dann die Mähne. Dann statt Loch den Gesichtsausschnitt in der Löwenhintergrundfarbe und dann kann man den Shape mit Augen, Nase und Maul setzen.

Also vollautomatische Konvertierung klappt nur bei ganz einfachen Grafiken (etwa dem Vogel). Bei vielen Grafiken muss die Farbgebung für die Löcher geändert werden und eventuell die Reihenfolge auch getauscht werden. Manches geht auch nicht, wie der Schweizer Käse, der von einer Maus dahinter gehalten wird, und bei dem Teile der Maus durch die Löcher sichtbar sind.

Was machbar wäre: Konvertierung von SVG Grafiken in tkinter Code. Nacheditieren dieses Codes durch Farbgebung für Löcher setzen und eventuell Reihenfolge tauschen.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Alfons:
Irgendwie zäumst Du das Pferd von hinten auf - um verlässlich "SVG-Importe" machen zu können, MUSST Du das Format implementieren. Das Canvas ist nur eine Zeichenoberfläche, SVG nur ein Beschreibungsformat. Da fehlen die Zwischenschritte Layout-Engine (Beschreibung --> DOM) und Render-Engine (DOM --> Canvas).
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: Nochmal anschaulich. Statt irgendetwas umzusortieren oder drüberzumalen, mußt Du das "Polygon mit Loch" in zwei Polygone ohne Loch aufteilen:
1. man suche den Mittelpunkt eines Lochs.
2. Lege durch diesen Punkt eine horizontale Gerade.
3. Berechne alle Schnittpunkte dieser Geraden mit allen Polygonen.
4. Nimm alle Punkte, die oberhalb der Geraden liegen, und alle Schnittpunkte und bilde daraus ein neues Polygon, ohne Loch
5. Nimm alle Punkte, die unterhalb der Geraden liegen, und alle Schnittpunkte und bilde daraus ein neues Polygon, ohne Loch
6. Zeichen die Polygone.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@Jerch Ja wenn man statt tkinter Vektorfgrafik eine andere Vektorgrafik macht, etwa so etwas wie tkzinc, läßt sich das Format importieren. Wenn es aber tkinter Vektorgrafik bleiben soll, dann gehen eben keine durchsichtigen Löcher auf einfache Art. Es sei denn, man flickt dann einen Schweizer Käse aus Einzelteilen so zusammen, dass dann dazwischen Löcher bleiben. Oder man biegt ein Hufeisen in eine Ringform, wenn es ein Ring sein soll.

Aber warum sollte ich mir so etwas antun, so etwas zusammenprogrammieren zu wollen? Konvertierung mit etwas zusätzlichem manuellen Aufwand ist bei vielen SVG Vektorgrafiken möglich. Das haben wir herausgefunden.

Will jemand das Thema weiter verfolgen? Soll man über eine Vektorgrafik Library nachdenken? Ob da die Grafiken aus SVG kommen oder nicht, kann sein oder auch nicht oder auch bunt gemischt.

Nochmal ein nettes Beispiel aus SVG. Das ließe sich automatisch konvertieren. Ob man smooth setzt oder nicht und wobei oder nicht, sollte man allerdings entscheiden. Hier war smooth generell gut:

Code: Alles auswählen

import tkinter as tk
 
class Curve(object):
    def __init__(self, x,y, precision=30):
        self.coordinates = [x,y]
        self.precision = precision
 
    def __iter__(self):
        return iter(self.coordinates)
 
    def line_to(self, *coords):
        self.coordinates.extend(coords)
 
    def becier(self, *coords):
        coords = iter(coords)
        px0, py0 = self.coordinates[-2:]
        for px1, py1, px2, py2, px3, py3 in zip(*[coords]*6):
            # B(t) = (1-t)^3 * P0  + 3t * (1-t)^2 * P1 + 3 t^2 * (1-t) * P2 + t^3 * P3
            for T in range(1,self.precision-1):
                t = T/self.precision
                Bx = (1-t)*(1-t)*(1-t)*px0 + 3*t*(1-t)*(1-t)*px1+3*t*t*(1-t)*px2+t*t*t*px3
                By = (1-t)*(1-t)*(1-t)*py0 + 3*t*(1-t)*(1-t)*py1+3*t*t*(1-t)*py2+t*t*t*py3
                self.coordinates.extend((Bx, By))
            px0, py0 = px3, py3
            self.coordinates.extend((px0,py0))

def main():

    root = tk.Tk()
    canvas = tk.Canvas(root,width=400,height=350)
    canvas.pack()
 
    scale = 0.03

    c = Curve(6993,5862)
    c.becier(4946,5697,4904,8018,3685,8018,2639,8018,2755,6895,2810,6574,2931,6565,3092,6521,3290,6397,3819,6065,3498,5420,3498,5420,3488,5646,3188,5666,3188,5666,2628,5693,2564,6131,2546,6365,2472,6191,2296,5873,2004,5900,1609,5936,1691,6093,1268,5875,1268,5875,1202,6505,1857,6665,2027,6707,2162,6705,2266,6683,2227,10048,5458,10817,7447,9970,9739,8994,9039,6026,6993,5862)
    canvas.create_polygon(*c,tags="img", fill='#64c3a3',smooth=1)

    c = Curve(7032,5479)
    c.becier(7097,5345,7551,4413,8384,4628,10223,5103,9898,2685,8448,3059,7312,3351,6970,5400,6942,5584,6942,5584,6939,5609,6949,5614,6988,5635,7032,5479,7032,5479)
    canvas.create_polygon(*c,tags="img", fill='#64c3a3',smooth=1)

    c = Curve(6969,4281)
    c.becier(7050,3944,6639,1184,8227,1598,9030,1807,8820,3057,8000,3086,7230,3112,7168,3950,7046,4274,7046,4274,7030,4327,7000,4324,7000,4324,6960,4321,6969,4281)
    canvas.create_polygon(*c,tags="img", fill='#64c3a3',smooth=1)

    c = Curve(6892,5586)
    c.becier(6892,5586,7148,44,4249,1229,4249,1229,2910,1850,3749,3232,4078,3774,4834,3773,5395,3673,5395,3673,5875,3568,6197,3953,6520,4338,6763,5492,6807,5578,6856,5674,6892,5586,6892,5586)
    canvas.create_polygon(*c,tags="img", fill='#64c3a3',smooth=1)

    c = Curve(6910,7636)
    c.becier(7003,7765,7143,7800,7223,7714,7302,7629,7290,7455,7197,7327,7104,7198,6964,7163,6885,7249,6806,7334,6817,7508,6910,7636)
    canvas.create_polygon(*c,tags="img", fill='#085877',smooth=1)

    c = Curve(8373,9170)
    c.becier(8373,9170,7274,9561,6985,8468,6985,8468,6965,8432,6991,8413,7023,8389,7071,8417,7071,8417,7324,9482,8348,9080,8348,9080,8348,9080,8397,9091,8405,9110,8413,9129,8404,9166,8373,9170)
    canvas.create_polygon(*c,tags="img", fill='#085877',smooth=1)

    c = Curve(7032,5479)
    c.becier(7097,5345,7551,4413,8384,4628,10223,5103,9898,2685,8448,3059,7312,3351,6970,5400,6942,5584,6942,5584,6939,5609,6949,5614,6988,5635,7032,5479,7032,5479)
    canvas.create_polygon(*c,tags="img", fill='#085877',smooth=1)

    c = Curve(6892,5586)
    c.becier(6892,5586,7148,44,4249,1229,4249,1229,2910,1850,3749,3232,4078,3774,4834,3773,5395,3673,5395,3673,5875,3568,6197,3953,6520,4338,6763,5492,6807,5578,6856,5674,6892,5586,6892,5586)
    canvas.create_polygon(*c,tags="img", fill='#085877',smooth=1)
    
    canvas.scale("img",0,0,scale,scale)
 
    root.mainloop()
 
if __name__ == '__main__':
    main()
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:@Alfons Mittelmeyer: Nochmal anschaulich. Statt irgendetwas umzusortieren oder drüberzumalen, mußt Du das "Polygon mit Loch" in zwei Polygone ohne Loch aufteilen:
...
6. Zeichen die Polygone.
Ja natürlich kann man das machen. Es gibt drei Möglichkeiten für so etwas:

Bild

Man begnügt sich beim Freiraum zwischen Ohr und Rüssel mit Canvas Background Farbe.
Wenn sagt sich, nein diese Grafik nehme ich nicht, denn Background Farbe stört, wenn man den Elefant verschiebt über etwas anderes.
Man ist ganz versessen darauf und will das unbedingt mit Loch haben. Dann kann man den Elefant nochmals nachzeichnen mit einem geeigneten Grafik Programm ohne das linke Ohr, sodass man den Freiraum hat und das linke Ohr kann man ja dann dransetzen.

Dann kommt es nur noch darauf an, wie das Grafikprogamm das speichert. Arbeitet es in Layers, die man bestimmen kann, oder speichert es das, wie es zuvor schon war, nämlich wieder mit herausgeschnittenem Loch?
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: würdest Du endlich mal die Dokumentation lesen, statt nur herumzuraten, wüßtest Du, dass smooth auch nichts anderes macht, als Du mit Deiner bezier-Methode. Nur dass TK die Kontrollpunkte rät und damit immer etwas anderes macht als beabsichtigt.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Alfons:
Deine Aufzählung ist witzig, hat aber leider rein gar nichts mit einer sinnvollen und strukturierten Annäherung an das Problem zu tun. Weiter oben fielen schonmal die Stichwörter "mathematische Grundlagen" und Spezifikation. Das wären vllt. geeignetere Startpositionen. Dein derzeitiges Stochern im "Wie könnte das gehen" erinnert eher an das blinde Huhn auf der Suche nach dem Korn.
Alfons Mittelmeyer hat geschrieben:... Aber warum sollte ich mir so etwas antun, so etwas zusammenprogrammieren zu wollen? ...]
Das frage ich mich allerdings auch.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@Sirius3 Wenn ich ein Objekt habe, das aus Rundungen besteht, kann ich bei einer Becierkurve, wenn es nicht gut kommt, die Precision erhöhen. Wenn ein Objekt aus 100 Punkten mit smooth gut kommt, während ich bei einer hohen Precision 1000 Punkte brauche, dann brauche ich mehr Platz zum Abspeichern oder mehr Berechnungszeit, wenn ich es rotieren lassen will. Warum soll ich dann nicht bei geeigneten Polygonen smooth nehmen?

Ich will es ja nicht im Regelfall nehmen. Aber warum nicht dort, wo es vorteilhaft ist?
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@jerch Das Problem ist doch längst gelöst. Nämlich Übernahme von geeigneten SVG Grafiken nach tkinter mit einfachen Mitteln. Einen Renderer schreiben habe ich keineswegs im Sinn. Man könnte etwa statt von einem Polygon von einer geschlossenen Polyline ausgehen und von dort aus nach innen den Raum mit Polygonen füllen, wobei bereits darin befindlich als geschlossene Polyline markierte Löcher ausgespart werden.

Solche mathematischen Lösungen sind jederzeit machbar, nur habe ich so etwas nicht im Sinn. Wozu auch? Wenn jemand gerne so etwas tun möchte, etwa Du jerch, dann tue Dir keinen Zwang an.

Also offensichtlich gibt es noch keine Vektor Grafik Bibliotheken für tkinter, aber man braucht für Vektor Grafik Bibliotheken für tkinter nicht alles neu zeichnen, sondern kann SVG Grafiken übernehmen. Das ist das Ergebnis dieses Threads.
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: was meinst Du jetzt schon wieder mit "Vektorgraphikbibliothek"? Canvas hat ein paar Zeichenprimitive, dass es keine Graphikprogramme gibt, die das explizit Exportieren können, liegt zum einen daran, dass sie in der landläufigen Bedeutung tatsächlich ziemlich primitiv sind, zum anderen, dass niemand bisher den Bedarf hatte, mit Canvas Zootiere darzustellen.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@Sirius3 Es geht nicht darum, aus tkinter ein Zeichenprogramm zu machen, wie etwa LibreOffice Draw, das aber zum Zeichnen auch nicht besonders viel bietet. Also, so etwas wäre schon möglich. Libre Office Draw kann aber verschiedene Formate lesen und exportieren. tkinter bietet nur postscript rendering für die Druckausgabe. Ein vernünftiges Format zum Datenaustausch wäre nicht schlecht.

Vielmehr geht es um ansprechende GUI. Professionelle Programme verwenden zur schönen Gestaltung Grafiken. Der Vorteil skalierbarer Grafiken ist, dass man sie nicht erst mit einem Bildbearbeitungsprogramm wie Gimp auf die gewünschte Größe skalieren muss, sondern man kann die Skalierung an Ort und Stelle vornehmen.

Außerdem, wenn Images klein sind, dann muss man sie so nehmen wie sie sind, denn Skaliereung bringt da nur verschlechterte Darstellung.

Und unter einer Vektorgrafikbibliothek stelle ich mir Files vor, die eine Sammlung von Vektorgrafiken beinhalten. Folgende Funktionen sollen dabei zur Verfügung stehen:

- Name der Sammlung
- Kurzbeschreibung
- Anzahl der Objekte
- Liste der Objekte (tags)
- abfragbar xmin,ymin,xmax,ymax pro Objekt
- Objekt laden in gewünschter Höhe an gewünsche Position in einen Canvas

Nice to Have:
- Objekte aus der Sammlung löschen
- Objekte aus einem Canvas in der Sammlung speichern

Außerdem:
- Übersicht der Objekte in Miniaturansicht mit Namen (tag)
- sowie auch Großansicht einzelner Objekte

PS: Dass man Zootiere verwenden soll für seine GUI, davon war nicht die Rede.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Alfons:
Das kennst Du oder? Zumindest kann der Vorgänger tkpath laut Screenshot/Beschreibung auch Löcher mittels evenodd malen. Einen separaten Download scheint es nicht zu geben, wahrscheinlich versteckt sich der Rohdiamant im Applikationscode.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@jerch Dass man ein Loch ausschneidet bzw. eine Fläche füllt, die auch nach innen eine Begrenzung hat, ist ganz normal. Das kann auch jeder Plotter und sollte auch jedes Grafikprogramm können. Tk gibt es seit 1991, da wundert man sich doch sehr, was es bis heute noch alles nicht kann. Schläft man da? Und auch dass man nur nach Postscript rendern kann, ist ein Witz. Grundlegende Funktionen, die man sich ja auch leicht selber implementieren kann, wie etwa Drehen werden nicht angeboten.

Eventuell würde tk ja sogar solche Löcher beherrschen. Wenn Du mein Pentagrammbeispiel angesehen hast, dann siehst Du dass es innen ein Loch hat. Das zeigt, dass tk nach der evenodd Regel füllt.

Eventuell scheitert es nur daran: dass ein Item hinter einem anderen ist, kann man angeben, dass es vor einem anderen ist, kann man auch angeben, aber dass es auf gleicher Ebene im gleichen Layer ist, kann man nicht angeben und damit auch nicht machen.
Antworten