Problem mit subprocess, pipes und Umleitung

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Ich möchte folgenden Konsolenaufruf aus einem Python-Skript starten:

Code: Alles auswählen

xwd -name "My Window" -silent | xwdtopnm | pnmtopng > screenshot.png
Ich habe es mit subprocess.Popen() versucht und mich dabei am Beipiel aus der Library Reference orientiert. Ich habe es trotzdem nicht hinbekommen.

Wäre nett, wenn mir jemand auf die Sprünge helfen könnte.
BlackJack

Also wenn Du jetzt ein Neuling wärst, hätte ich erst einmal gefragt, was Du für die Hausaufgabe denn bisher versucht hast. ;-)

Meinst Du so etwas hier!?

Code: Alles auswählen

from subprocess import Popen, PIPE

def main():
    out_file = open('test.png', 'wb')
    pnmtopng = Popen(['pnmtopng'], stdin=PIPE, stdout=out_file)
    xwdtopnm = Popen(['xwdtopnm'], stdin=PIPE, stdout=pnmtopng.stdin)
    xwd = Popen(['xwd', '-root', '-silent'], stdout=xwdtopnm.stdin)
    pnmtopng.wait()
    out_file.close()
lunar

Alternativ kannst du auch eine Kombination aus ImageMagick und xwininfo nutzen, dann spart man sich zwei Prozesse.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

BlackJack hat geschrieben:Also wenn Du jetzt ein Neuling wärst, hätte ich erst einmal gefragt, was Du für die Hausaufgabe denn bisher versucht hast. ;-)
Im Grunde bin ich, was Python angeht, ein Neuling, und das Arbeiten mit subprocess ist für mich völliges Neuland; gelegentlich mal ein subprocess.call(), das war's. Aber das ändert sich ja gerade.

Also: Mein Code war deinem schon recht ähnlich. Ich hatte für die einzelnen Pipes mittels Popen() entsprechende Objekte erstellt und stdin und stdout eingestellt. Was mir überhaupt nicht bewusst war, war, dass ich für das Anlegen der abschließenden Datei ein eigenes Dateiobjekt öffnen muss. Ich wollte den letzten Strom halt irgendwie "umleiten", wusste aber auch nicht wie.

Weiteres Problem, das sich aber erst gezeigt hat, als ich dank deines Codebeispiels dieses Problem lösen konnte, war, dass "-name 'My Window'" nicht als EIN Parameter, sondern als zwei Parameter aufgefasst werden.

Im Unterschied zu deinem Code hatte ich communicate() statt wait() verwendet, was sich jetzt - wo der Rest funktioniert - auch als der anscheinend bessere Weg gezeigt hat. Mit wait() hat sich das Programm an der Stelle aufgehängt. Wenn ich es in eine Tkinter-Anwendung einbaue (da soll es mal hin), dann hängt die Anwendung an der Stelle und die angelegte Bilddatei, bleibt zunächst leer. Erst wenn ich das Programm beende, wird der Prozess abgeschlossen und der Screenshot erstellt.

Fazit: Dein Code hat die entscheidende Hilfe geliefert, Screenshot funktioniert jetzt wie er soll.

@lunar: Danke für den Hinweis. Hat mich veranlasst, mir nochmal die möglichen Optionen von ImageMagicks "import" anzusehen und dann auch dort ein "-silent" zu entdecken. Das war mir bisher durchgegangen und weil mich das "klingeln" gestört hat, habe ich diesen Weg nicht weiter verfolgt.

Du meinst das?

Code: Alles auswählen

xwininfo -name "My Window"
Daraus die Window-ID extrahieren und dann z.B.

Code: Alles auswählen

import -window 0x2e0000a -silent test.png
Werde ich mal ausprobieren.

Etwas lästig und ggf. auch problematisch finde ich bei beiden Lösungen, dass es über den Namen (in der Titelleiste) läuft. Was ich will - s.o. - ist ein Screenshot aus einer Tkinter-Anwendung heraus, die sich selbst knipst. Gibt es eine Möglichkeit, die benötigte Window-ID anders zu ermitteln als über den Namen des Fensters?
lunar

numerix hat geschrieben:@lunar: Danke für den Hinweis. Hat mich veranlasst, mir nochmal die möglichen Optionen von ImageMagicks "import" anzusehen und dann auch dort ein "-silent" zu entdecken. Das war mir bisher durchgegangen und weil mich das "klingeln" gestört hat, habe ich diesen Weg nicht weiter verfolgt.
Oha, ich wusste gar nicht, dass das "klingelt". Ich nehme mal an, damit ist ein Sound aus dem PC-Lautsprecher des Mainboards gemeint, und den habe ich durch blacklisten bzw. deaktivieren von pcspkr immer stummgeschaltet.
Du meinst das?

Code: Alles auswählen

xwininfo -name "My Window"
Daraus die Window-ID extrahieren und dann z.B.

Code: Alles auswählen

import -window 0x2e0000a -silent test.png
Jo, siehe Code.
Was ich will - s.o. - ist ein Screenshot aus einer Tkinter-Anwendung heraus, die sich selbst knipst. Gibt es eine Möglichkeit, die benötigte Window-ID anders zu ermitteln als über den Namen des Fensters?
Im Allgemeinen ist das möglich, ob das im Speziellen bei Tkinter so ist, weiß ich nicht. Frag am besten mal im Tkinter-Subforum nach, denn dein Problem ist ja jetzt eher "Wie finde ich mit Tk die X11-ID eines Fensters heraus?".

Qt4-QWidgets haben eine winId()-Methode, vielleicht gibts das ja auch bei Tkinter (wobei man bei Qt4 natürlich QPixmap.grabWidget() nutzen würde, anstatt eine externes Programm zu bemühen ;) )
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

lunar hat geschrieben:Oha, ich wusste gar nicht, dass das "klingelt". Ich nehme mal an, damit ist ein Sound aus dem PC-Lautsprecher des Mainboards gemeint
Genau, und zwar einmal beim Aufruf von "import" und ein zweites Mal wenn der Screenshot fertiggestellt ist.
lunar hat geschrieben:Jo, siehe Code.
Hatte ich glatt übersehen :oops: - ich hatte nur die Stichwörter gelesen und selbst nachgedacht. Aber beruhigt mich zumindest, dass ich die richtige Idee hatte. Danke also für den Code!
Antworten