PDA

Vollständige Version anzeigen : python und GIMP Datentyp IMAGE


MichaJo
08.01.2008, 12:00
Ich hab' mir jetzt schon die Finger wundgegoogelt...
Mit z.B. num_images, image_ids = pdb.gimp_image_list() bekomme ich die Anzahl der offenen Bilder und die id's dieser Bilder (in einem array).
Ich möchte mit num_layers, layer_ids = pdb.gimp_image_get_layers(image) nun die Liste der layers eines der offenen Bilder bekommen.
(Die sehe ich ja in der Liste, z.B. 1, 2, 3....)
Der Parameter image ist dabei vom Typ IMAGE.
Ich hab' so einige Möglichkeiten ausprobiert, um diesen Parameter entsprechend zu setzen, bekomme aber immer einen TypeError.
Im Procedure Browser werden natürlich auch (mir) bekannte Datentypen wie INT, INT32ARRAY, STRING etc. angezeigt,
aber wie IMAGE, DRAWABLE oder LAYER definiert sind, habe ich nirgends gefunden.


Gruß

Micha

TheGrudge
08.01.2008, 12:56
Was meinst du nun genau? Der Datentyp bzw. die Klasse Image ist im gimp-Paket. Suchst du nun die Attribute und Methoden dieser Klasse? Dann kannst du ja in der Python-Console nach schauen:

import gimp
import gimpplugin

dir(gimp.Image)


Dann siehst du die ganzen Methoden.
Oder du tippst

help(gimp.Image)

ein, dann bekommst du die Doku der Klasse angezeigt und kannst auch sehen wie der Konstruktor zu benutzen ist.

MichaJo
08.01.2008, 13:48
gimp_image_list() ist folgendermaßen beschrieben:
gimp_image_list
Input: none
Returns:INT32 num_images The number of images currently open
INT32ARRAY image_ids The list of images currently open
This procedure returns the list of images currently open in the GIMP.

Ich bekomme danach also einen array der image_ids. Ich habe drei Bilder offen, bekomme danach als ids: 1, 2, 3

Mit gimp_image_get_layers möchte ich die Ebenen eines dieser Bilder bekommen.
gimp_image_get_layers ist folgendermaßen beschrieben:
gimp_image_get_layers
Input:
IMAGE image The image
Returns:INT32 num_layers The number of layers contained in the image
INT32ARRAY layer_ids The list of layers contained in the image
This procedure returns the list of layers contained in the specified image.
The order of layers is from topmost to bottommost.

Wenn ich jetzt in der python-console eine der ids als image übergebe, bekomme ich den TypeError.
Ob als numerischen Wert, in Hochkomma, als Variable, oder wie auch immer...



Gruß

Micha

TheGrudge
08.01.2008, 15:34
Ich habe ganz andere Funktionen wie du, ich nutze Gimp 2.4.3

Ich frage die Ebenen eines Bildes zum Beispiel so ab:

gimp.image_list()[0].layers

Also das erste Bild aus der Liste und dann davon die Layer anzeigen. Bei mir liefert image_list() auch nur eine Liste, nicht zwei, und diese enthält als ID den Namen des Bildes.

TheGrudge
08.01.2008, 15:40
Du scheinst nicht die Klassen der Python-API zu nutzen, sondern die Funktionen aus dem Procedure Browser. Viele von denen sind aber als Klassenmethoden implementiert, normalerweise nutze ich diese Funktionen nur um Filter aufzurufen.

MichaJo
08.01.2008, 15:49
Du scheinst nicht die Klassen der Python-API zu nutzen, sondern die Funktionen aus dem Procedure Browser. Viele von denen sind aber als Klassenmethoden implementiert, normalerweise nutze ich diese Funktionen nur um Filter aufzurufen.
Stimmt. Woher soll ich wissen, was ich benutzen soll?
Ist halt mein einziger Weg, nach Möglichkeiten zu suchen, irgendwas mit Python in GIMP zu tun,
indem ich nämlich mit dem Prozedurenbrowser nach mir logisch erscheinenden Begriffen suche (wie list, layers, usw.),
und dann die Gefundenen anzuwenden versuche.
Leider ist eben nirgendwo beschrieben, wie IMAGE auszusehen hat.
Ich bekomme durch die vorige Funktion numerisch aussehende Werte (image-ids),
die ich aber scheinbar so nicht verwenden kann.
Zweck der ganzen Übung soweit ist, festzustellen, welche Bilder offen sind, und diese dann dem User in einer Auswahlliste namentlich zur Verfügung zu stellen.
Mal sehen, scheint so, dass es auf Deine Weise funktioniert.
Kannst Du mir noch 'nen Tipp geben, wie ich auch andere Klassen der Python-API finde, die in GIMP verwendet werden sollten/könnten?
(Bevor ich mich wieder im Prozeduren-Browser totsuche, und dann doch nix Gescheites finde...)


Gruß

Micha

TheGrudge
08.01.2008, 15:55
Die Python-Console in Gimp öffnen, das gimp-Paket importieren und dann mit dir(gimp) schauen was dort alles installiert ist.

import gimp
dir(gimp)

Nun kannst du sehen das dort zum Beispiel Image oder Drawable existieren. Die Konsole kann Autovervollständigung. Wenn du nun gimp.Image tippst, danach einen Punkt und dann TAB, siehst du alle Methoden und Attribute (oder wieder dir(gimp.Image)).

MichaJo
08.01.2008, 16:09
Okay, schönen Dank!


Gruß

Micha

MichaJo
08.01.2008, 16:53
Doch noch 'ne Zusatzfrage: Wie hätte ich denn zum Beispiel gimp.image_list()[0].layers als Möglichkeit gefunden?
Ich kann das nicht nachvollziehen.

Oder die Entsprechung für gimp-image-remove-layer inklusive der hiefür notwendigen Übergabeparameter und Erklärung der Rückgabewerte?
Ich habe da zum Beispiel gimp.Image.remove_layer gefunden, bekomme aber bei
help (gimp.Image.remove_layer) nur:
Help on method_descriptor:

remove_layer(...)


Ich hab' zwar früher berufsmäßig programmiert, aber das ist knapp 15 Jahre her...(prozedurale Sprachen).
Also, wenn Du noch 'nen Tipp hättest. Ich frag' dann auch nicht mehr :cool:

Gruß

Micha

TheGrudge
08.01.2008, 17:07
Tja wie soll ich denn das beantworten? Ich kenne mich mit Python aus und deswegen war mir das klar.
Dadurch das gimp.image_list() eine Liste liefert, kann ich ja direkt auf die Elemente zugreifen, man kann natürlich auch schreiben:

import gimp
my_image_list = gimp.image_list()
the_image = my_image_list[0]
the_image.layers

Aber so ist es halt kürzer:

gimp.image_list()[0].layers

Das hat nichts spezielles mit der Python Gimp-API zu tun, das ist einfach der Stil von Python.
Man kann auch kompliziertere Sachen basteln wie

all_layers = [layer for layer in [image.layers for image in gimp.image_list()]]

Das würde alle Ebenen aller Bilder in einer Liste speichern.
Nicht das es sinnvoll wäre, aber naja...

Wie gesagt über die Python-Console kann man schon einiges herausfinden, aber die docstrings sind wohl unvollständig, man bekommt nicht allzu viele Infos über die Paramter in den Funktionen. Irgendwo war aber auch eine Beschreibung im Web mit Tutorial usw über die Python-GIMP-API...

MichaJo
08.01.2008, 17:18
Hmmm...vom Prinzip her ist mir das schon klar, nur was diese Liste beinhaltet,
dass ich zum Beispiel auch layers geliefert bekomme...keine Ahnung, wo ich das feststellen kann.
Und wie gesagt, ich habe noch nicht gefunden, wie ich beispielsweise gimp.Image.remove_layer anwende...welche Parameter in welcher Form benötigt werden.
Ich bin jetzt seit einiger Zeit am googeln, um vielleicht ein plugin zu finden,
in dem das verwendet wurde,
um dann per Rückschritt zu finden, was benötigt wird...

Okay, aber nochmal Dank für Deine Hilfe.


Gruß


Micha

TheGrudge
08.01.2008, 17:21
Naja layers bekommst du weil es eben ein Image-Objekt ist das in der Liste gespeichert ist. Und in der Python-Console kann man ja alle Methoden von der Klasse Image, wie vorhin beschrieben, einsehen. Obwohl layers ist keine Methode aber auch egal...

TheGrudge
08.01.2008, 17:27
Also entfernen würde so gehen:

the_image.remove_layer(the_image.layers[0])

Ist aber irgendwie eine doofe Notation, finde ich, logischer wäre einfach die ID zu übergeben.

MichaJo
08.01.2008, 19:49
Danke für Deine Mühe. War "früher" halt einfacher :cool:.
Da gab's Handbücher, Referenz-Manuale, User-Guides, cookbooks, cross-reference-lists, etc.
Da hat man halt nur alphabetisch oder semantisch nach einer Funktion gesucht und dann jeweils Beschreibung, Übergabe-Parameter, Rückgabewerte, syntaktische Erklärungen, und oft auch Beispiele bekommen.
Aber wie, nach welcher Klasse, Methode, Objekt, etc. ich schauen muss,
um in GIMP mit Python einfach nur den Namen eines layers zu bekommen,
und den dann auch noch weiterverwenden kann....
Naja, ich probiers's.


Gruß

Micha

TheGrudge
08.01.2008, 20:14
Generell gibt es für Python tausende Manuals, Bücher, Cookbooks usw... hier im Schrank stehen ein paar von O'Reilly :D
Die Python-API in GIMP muss halt von Freiwilligen dokumentiert werden, und Python macht das eigentlich automatisch durch Docstrings. Wenn diese aber nicht immer konsequent gesetzt wurden, dann liefert help(bla) halt nichts oder wenig informatives.
Ich sehe es ja auch bei meinem Programmierprojekten, sei es C++, Ruby, Python oder Java. Dokumentieren macht keinen Spaß und meist weiß man ja selber was man dort tut. Sobald aber ein Projekt bekannter wird oder einfach mehr Leute dran arbeiten müssen, dann fängt man mit der Doku erst richtig an.
Ich weiß nicht ob das vielleicht bei der Python-API in GIMP auch so ist, aber bis jetzt wurde ja mehr in ScriptFU entwickelt und nicht so sehr in Python. Deswegen ist vielleicht einfach die Doku noch nicht so dolle.
Wie gesagt ist das Tolle bei Python ja die Introspection in der interaktiven Shell. Du kannst eine Klasse immer mit dir(class) untersuchen, im Notfall musst du halt die Pythonpakete selber einsehen, da sieht man auf jeden Fall die Parameter einer Funktion, wie bei C++ und den Headerdateien.
Ich bin immer noch am suchen, ich hatte mal eine tolle Doku zum Python-GIMP-API-Gedöhns, aber ich glaube den Bookmark habe ich auf der Arbeit.

TheGrudge
08.01.2008, 20:18
Äh was ist denn hiermit: http://www.gimp.org/docs/python/index.html
Das war das erste Ergebnis in Google und hat doch alle Funktionen drin?

Ravetracer
08.01.2008, 20:32
Man kann doch auch einfach den PDB-Browser in GIMP benutzen. Da sind auch die Parameter aufgelistet. Ich nehme dann oft eben auch die pdb.-Funktionen.

TheGrudge
08.01.2008, 20:40
Ja aber die PDB-Funktionen sind nicht immer so dolle für Python-Programmierung, finde ich. Ich meine in Python hast du die Image-Klasse, die alle benötigten Funktionen beinhaltet. So Listcomprehensions usw in Python sind damit einfacher umzusetzen. Ich für meinen Teil möchte halt lieber die Methoden der Klassen nutzen als diese Funktionen, sonst kann ich auch ScriptFu coden. Jeder wie er mag.
Wie genau die Python-API in GIMP funktioniert weiß ich auch nicht, aber ich glaube die wrappen einige PDB-Funktionen entsprechend. Sowas wie

img = gimp.Image(width, height, RGB)

ruft bestimmt einige der PDB-Funktionen auf, aber so ist es schneller und auch "python-like"... Die richtige Erfahrung habe ich damit ja auch nicht, den Unterschied zwischen den PDB und Python-API Calls kann ich manchmal auch nicht ganz verstehen, denke halt das die Python-API es einfach nach außen hin noch einmal mehr vereinfacht und PDB-Calls sehr vereinfacht.

TheGrudge
08.01.2008, 20:54
Nochmal aus der Doku:

"Another point of difference between GIMP-Python and Script-Fu is that GIMP-Python stores images, layers, channels and other types as objects rather than just storing their ID. This allows better type checking that is missing from Script-Fu, and allows those types to act as objects, complete with attributes and methods.

Also, GIMP-Python is not limited to just calling procedures from the PDB. It also implements the rest of libgimp , including tiles and pixel regions, and access to other lower level functions."

Wie gesagt der Vorteil ist einfach das richtige Python-Objekte abgelegt werden, was beim Einsatz von PDB alleine wohl nicht der Fall ist und somit, jedenfalls für mich, keine schöne Pythonprogrammierung ist.

Ach Leutz ick weez es ja ooch nidd! :D
Jedenfalls denke ich das die Verwendung der Objekte einfacher ist...

Ich bin ja endlich wieder von C++ weg, und arbeite mich endlich mal in das Skripten von Blender mit Python ein... das wollte ich schon immer mal machen.

MichaJo
08.01.2008, 22:12
Man kann doch auch einfach den PDB-Browser in GIMP benutzen. Da sind auch die Parameter aufgelistet. Ich nehme dann oft eben auch die pdb.-Funktionen.

Die hatte ich ja zuerst auch durchsucht, und bin dabei unter anderem auf das Problem gestoßen, mit dem ich diesen thread eröffnet hatte. (Wie muss IMAGE aussehen...)

Auf dieser Seite ( http://www.gimp.org/docs/python/index.html ) war ich natürlich auch schon. (Bin durch das clothify.py darauf gestossen, was ich ich rein vom Aufbau her schon wesentlich sympathischer finde, als das script-fu - Pendant).

Leider sind da die jeweiligen Parameter eben auch nicht spezifiziert, Beispiel:
image.add_layer_mask(layer, mask) Adds the mask mask to layer.

Und ob das nun die selben sind, wie in der PDB....wahrscheinlich ja, aber wie vorhin zu sehen, nicht in jedem Fall.

Ich möchte - angeregt durch Plugins in Python - und zwar richtig (http://www.gimpforum.de/showthread.php?t=9287) - aber gerne Python plugins schreiben, und zwar eben richtig :D

Ist vielleicht etwas mühselig (auch für Euch Antworter...), aber vielleicht ja lohnend.
Nochmal Danke.


Gruß

Micha

houz
09.01.2008, 12:32
Ich bekomme danach also einen array der image_ids. Ich habe drei Bilder offen, bekomme danach als ids: 1, 2, 3
Sicher, dass das nicht 0, 1, 2 ist?

MichaJo
09.01.2008, 13:42
Also genau ist es so:
>>> num_images, image_ids = pdb.gimp_image_list()
>>> print image_ids
(3, 2, 1)
>>> num_layers, layer_ids = pdb.gimp_image_get_layers(image)Und egal, was ich jetzt anstatt image einsetze, bekomme ich den TypeError:wrong parameter type



Gruß

Micha

TheGrudge
09.01.2008, 14:00
Also ich kann nur sagen das ich die pdb-Funktionen nur für Filter und Plugins nutze, der Rest sind die puren Pythonklassen.
Wenn du eine Zahl einsetzt, ist es natürlich ein Integer und kein Image. Ich denke einfach diese Funktionen gehen nicht richtig mit Python? Wozu hat man sonst diese PyGIMP-API? Aber sind nur Vermutungen, ich weiß es auch nicht. Wie gesagt ich finde es eh vorteilhafter mit den Objekten direkt zu arbeiten, aber da ich heute kaum was zu tun habe gucke ich auch mal wie man das mit den pdb-Funktionen lösen kann.

TheGrudge
09.01.2008, 14:11
So ich habe es versucht, aber es geht einfach nicht. Ich denke man muss die Objekte nutzen, denn diese IDs sind einfach nicht anwendbar.
Nur im Falle das eine Funktion nicht an ein Objekt gebunden ist, kann man dann auf die pdb zugreifen.


>>> a, b = pdb.gimp_image_list()
>>> type(a)
<type 'int'>
>>> type(b)
<type 'tuple'>
>>> type(b[0])
<type 'int'>

Wie man sieht sind es einfach nur Integers, keine Strukturen oder Klassen (Objekte). Ich denke mal das es einfach so nicht funktioniert. Die Beispiele im clothify.py und auf http://www.gimp.org/docs/python/index.html sehen ja auch dementsprechend aus. Die nutzen keine dieser pdb-Funktionen.

Ravetracer
09.01.2008, 14:26
Also genau ist es so:
>>> num_images, image_ids = pdb.gimp_image_list()
>>> print image_ids
(3, 2, 1)
>>> num_layers, layer_ids = pdb.gimp_image_get_layers(image)Und egal, was ich jetzt anstatt image einsetze, bekomme ich den TypeError:wrong parameter type

Gruß

Micha

Probiere mal bitte folgendes und vergiss einen Augenblick die PDB-Funktionen, da es ja direkte Python-Objekte gibt:

>>> num_images = len(gimp.image_list())
>>> images = gimp.image_list()

Jetzt sollte man mit einer Schleife durchgehen, ich mach das mal für's erste Bild.

>>> num_layers = len(images[0].layers())
>>> layers = images[0].layers()


Die layers kannst du wieder als Array/Liste/wasauchimmer aufrufen. Die PDB-Funktionen sollte man eigentlich auch nur nutzen für Filter oder so, da die Objekte ja schon schön in Python vorhanden und brauchbar sind.

TheGrudge
09.01.2008, 14:32
Wobei layers keine Methode, sondern ein Attribut ist, also

>>> num_layers = len(images[0].layers)
>>> layers = images[0].layers

MichaJo
09.01.2008, 15:23
Jou, so funktionierts :)

>>> num_images = len(gimp.image_list())
>>> print num_images
3
>>> images = gimp.image_list()
>>> print images
[<gimp.Image 'toglayvisSample.xcf'>, <gimp.Image 'Winterbild.xcf'>, <gimp.Image 'VerkehrteWelt.xcf'>]
>>> num_layers = len(images[0].layers)
>>> print num_layers
11
>>> layers = images[0].layers
>>> print layers
[<gimp.Layer 'layer nine'>, <gimp.Layer 'layer eight'>, <gimp.Layer 'layer seven'>, <gimp.Layer 'layer six'>, <gimp.Layer 'layer five'>, <gimp.Layer 'layer four'>, <gimp.Layer 'layer three'>, <gimp.Layer 'layer two'>, <gimp.Layer 'layer one'>, <gimp.Layer 'bottomline'>, <gimp.Layer 'background'>]
>>>

Wie ist die Notation z.B. bei <gimp.Layer 'layer three'> zu interpretieren?
Genauer: Ich kenne nicht die Bedeutung der kleiner- und größer-Zeichen.
Und zusätzlich, welche Information liefert mir gimp.Layer in dem Beispiel?
Für meinen Geschmack ist das eine redundante Information, also überflüssig...?


Gruß

Micha

TheGrudge
09.01.2008, 15:35
Das in den spitzen Klammern ist nur eine Objektbeschreibung, die du in einer Klasse festlegen kannst.
Meist wird so etwas wie der Basisname gefolgt von einer eindeutigen ID genannt.

Die Info dient in erster Linie nur dir, für Debuggingzwecke oder beim experimentieren in der Konsole.
Oder bei Konsolenanwendungen lässt sich mit
print obj
eine Ausgabe erzielen.

Ich habe zum Beispiel eine Netzwerküberwachung geschrieben, die auf Konsole, in Mails und Logfiles Routerinformationen schreibt. Als Zeilenanfang steht immer so etwas wie
<Router "hostname"|IP|uptime> ... bla
Dies ist einfach nur eine Repräsentation deines Objektes.

In deinem Beispiel siehst du also, das eine Liste existiert, die gimp.Layer Objekte enthält. Zur besseren Unterscheidung listen diese sich mit ihrem Namen auf.