ImageMagic convert popen

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.
Shining-Blue
User
Beiträge: 37
Registriert: Samstag 15. August 2009, 04:36

Hallo allerseits,
ich habe hier ein kleines Problem mit dem Aufruf von convert über subprozess-Popen

folgender Aufruf funktioniert:

Code: Alles auswählen

 os.system(pathtobin + 'convert ' + infile + ' -resize 320x ' + folder + '/thumb_' + infile + ' 1>NUL 2>NUL')
dieser hingegen gibt den Fehler 'Unzulässiger Parameter - 320x' aus

Code: Alles auswählen

 sub.Popen([pathtobin + 'convert', '-resize', '320x', infile, folder + '/thumb_' + infile], shell = False)
ich habe nun schon etliche Varianten der Parameter probiert, doch hier komme ich nicht weiter :(

Ich hoffe jemand von Euch weiß Rat.

LG SB[/code]
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Kann ich nur nachvollziehen, wenn ich '-resize 320x' statt '-resize', '320x' verwende.
Letzteres funktioniert.

``shell`` ist btw per default `False`.
Shining-Blue
User
Beiträge: 37
Registriert: Samstag 15. August 2009, 04:36

Das ist ja merkwürdig.
Ich habe gerade noch einmal meinen Code überprüft - bei mir funktioniert das nicht.
Versuche ich die gleiche Zeile unter OS X, so findet er nicht einmal die Dateien.
Die os.system - Variante klappt soweit unter allen Plattformen ohne Probleme, doch wenn ich das Prog dann mit py2exe in eine ausführbare Datei zusammenstellen lasse, bombardiert mich das Programm mit etlichen aufflackernden Shell-/cmd-Fenstern und die nerven gewaltig.
Deshalb der Versuch mit popen und shell=false.
Wenn mir jemand sagen könnte, wie ich die aufblitzenden Fenster los werde, kann ich locker mit der os.system Variante leben.

LG Lena
problembär

Ich würde mir immer erstmal den String ausgeben lassen, den man an os.system() übergeben will, und den überprüfen. Oft hat man irgendwo ein Leerzeichen oder so vergessen.

Gruß
Shining-Blue
User
Beiträge: 37
Registriert: Samstag 15. August 2009, 04:36

Mit os.system klappt es ja alles wunderbar.
Unter Linux und Mac werden auch keine Shellfenster aufgemacht und unter Windows nur wenn ich es durch py2exe jage.
Da das Skript aber für Software-DAUs einen Forums sein soll, ist das so leider nicht tragbar.
Deshalb versuche ich ja eine Lösung mit popen hinzubekommen.

LG SB
BlackJack

@Shining-Blue: Gibt's einen Grund warum Du beim `Popen` plötzlich eine andere Reihenfolge für die Argumente wählst? Kann es vielleicht sein, dass `convert` als erstes die Eingabedatei verlangt, und nun versucht die "Option" `320x` auf die Datei "-resize" anzuwenden!? Und diese Option aber unbekannt ist!?
Shining-Blue
User
Beiträge: 37
Registriert: Samstag 15. August 2009, 04:36

Ja, das habe ich mir von einem anderen Beispiel abgeschaut.
Vorher hatte ich die Reihenfolge der Parameter genau so wie es auch bei einem Aufruf von der Shell oder über os.system sein müsste.
In der Reihenfolge convert infile -resize 320x outfile meckert er aber schon über -rezise als ungültigen Parameter.
Ich tüftel da wirklich schon eine ganze Weile rum, aber finde auch sonst im Netz kaum etwas brauchbares.
Wird denn sooo selten ImageMagick direkt aus Python verwendet?
Immerhin gab es doch lange sogar entsprechende Wrapper, die leider nicht mehr weiter entwickelt wurden.
Ich bin schon drauf und drann das alles auf PIL umzuschreiben.
Die Distutils bzw. py2app und py2exe würden ja PIL mit einbinden, so das es für die Endanwender sogar den Vorteil hätte, das sie nicht einmal IM auf seinem System haben müsten.

LG SB
BlackJack

Also folgendes funktioniert bei mir:

Code: Alles auswählen

import os
from subprocess import Popen

def main():
    bin_foldername = '/usr/bin/'
    filename = 'test.jpg'
    out_foldername = '/tmp'
    convert_process = Popen([os.path.join(bin_foldername, 'convert'),
                             filename,
                             '-resize', '320x',
                             os.path.join(out_foldername, 'thumb_' + filename)])
    return_code = convert_process.wait()
    if return_code:
        print 'There was a problem.', return_code
@Shining-Blu: Bist Du sicher, dass Du das richtige `convert` ausführst? Vielleicht gibt es auf Deinem System noch ein anderes Programm, dass so heisst. Ist ja kein besonders origineller Name.
Shining-Blue
User
Beiträge: 37
Registriert: Samstag 15. August 2009, 04:36

Ich bin mir sicher, daß das richtige convert aufgerufen wird, da eine Funktion zuvor die Existenz überprüft. Wenn ich convert verschiebe wird brav gemeckert. Auch funktioniert es ja mit os.system einwandfrei.
Dein Segment werde ich mir mal genauer ansehen - es ähnelt ja stark meinen ersten Versuchen auf Popen umzustellen.
Der gravierende Unterschied scheint ja das zusammenführen des Pfadnamens mit dem Befehl bzw dem dem Namenszusatz der Ausgabe zu sein.
Wenn das der Trick ist, dann wäre ich da alleine wohl in drei Wochen noch nicht drauf gekommen - werde berichten.

LG SB
Shining-Blue
User
Beiträge: 37
Registriert: Samstag 15. August 2009, 04:36

@BlackJack

Dein Codefragment brachte den Durchbruch :)

so funktioniert es nun auch bei mir:

Code: Alles auswählen

convert_process = sub.Popen(
    [os.path.join(pathtobin , 'convert'),
    os.path.join(workpath , infile), '-resize', '640x', 
    os.path.join(workpath , folder , ('small_' + infile))])
return_code = convert_process.wait() 
Ich hatte im ersten Versuch Deine Variante zu übertragen die .wait Zeile unterschlagen, was zu sehr sonderbaren Ergebnissen führte.
Nun bleibt noch abzuwarten, ob sich so die lästigen Shellfenster unter Windoof unterdrücken lassen.

Herzlichen Dank & LG

SB
lunar

Ungetestet:

Code: Alles auswählen

import subprocess

cmd = [os.path.join(pathtobin , 'convert'),
           os.path.join(workpath , infile), '-resize', '640x',
           os.path.join(workpath , folder , ('small_' + infile))]
options = {}
if subprocess.mswindows:
    options['startupinfo'] = info = subprocess.STARTUPINFO
    info.wShowWindow = subprocess.SW_HIDE
    options['creationflags'] = subprocess.STARTF_USESHOWWINDOW
subprocess.call(cmd, **options)
Da ich kein Windows zur Verfügung habe, kann ich das auch nicht testen, nach meinem Verständnis der Dokumentation und nach einem Blick in den Quellcode von subprocess müsste es aber funktionieren. Die Dokumentation zu diesen Werten findest Du, wenn Du in der MSDN nach "CreateProcess" suchst. Von dort aus findest Du dann über weitere Links Beschreibungen der Struktur und der erlaubten creationflags-Werte (von denen meines Wissens aber nicht alle durch subprocess zur Verfügung gestellt werden).
Shining-Blue
User
Beiträge: 37
Registriert: Samstag 15. August 2009, 04:36

@lunar

Puh Du mutest mir als Newbee aber eine Menge zu :wink:
Ist doch mein Erstlingswerk in Python und meine anderen Programmiererfahrungen beschränken sich auf Pascal, Assembler u.s.w. und stammen noch aus den guten alten 8-Bitter Tagen, wo man noch mit jedem Byte auf Du & Du stand.
Aber ich werde mal versuchen mich durch die angegebene Doku zu wühlen.
Grrr - alles nur wegen dieser dusseligen DOSen :evil:

LG SB

P.S.: Sinnlos läuft bei uns auch nur als Gast-OS unter OS X - das langt dicke
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Shining-Blue hat geschrieben:guten alten 8-Bitter Tagen, wo man noch mit jedem Byte auf Du & Du stand
Ich kann nicht anders: http://www.youtube.com/watch?v=4qsWFFuYZYI
lunar

Shining-Blue hat geschrieben:Puh Du mutest mir als Newbee aber eine Menge zu :wink:
Verzeihung, aber konnte ich das ahnen? ;)
Shining-Blue
User
Beiträge: 37
Registriert: Samstag 15. August 2009, 04:36

@cofi

Absolut cool !
Schon irre was Leute so mit Legosteinen so zaubern können.
Schön das Du nicht anders konntest.

LG SB
Shining-Blue
User
Beiträge: 37
Registriert: Samstag 15. August 2009, 04:36

Zitat aus MS-Doku:
....
Eine möglicherweise davon aus, die an die erstellte Anwendung übergebenen Befehlszeile ein zusammengesetztes der Anwendungsname und CommandLine-Parameter ist, aber dies nicht der Fall ist.
... u.s.w.

Aua, das ist ja jenseits jeglicher Verständlichkeitsgrenze :x

LG SB
Shining-Blue
User
Beiträge: 37
Registriert: Samstag 15. August 2009, 04:36

Es wäre ja auch zu schön um wahr zu sein, aber ein Viraus aus Redmond muß einem mal wieder die Suppe versalzen :(
Natürlich läuft das, was wir uns bisher ausgetüftelt haben unter Mac und Linux einwandfrei, aber unter Windows geht so überhaupt nichts mehr.
Wenn man nicht in das "Pfad mit Leerstellen" Problem läuft (liegt nicht einer der häufigsten unter "Dokumente und Einstellungen"???), dann wird das letzte Pfadelement als ungültiger Parameter angemahnt.
Ich glaube ich schweinke wirklich mal auf den PIL-Ansatz um.
Mit Popen Plattformubergreifend zu arbeiten scheint doch arg kniffelig - schade eigentlich.

LG SB
BlackJack

@Shining-Blue: Das verstehe ich jetzt nicht. Mit `Popen()` hat man wesentlich weniger Probleme mit Leerzeichen in Argumenten als Beispielsweise mit `os.system()`. Man braucht nichts mehr zu "escapen" und kann den Pfad genau so hinschreiben, wie er auch heisst.
lunar

@BlackJack: Das kann schon sein. "subprocess" benutzt unter Windows "CreateProcess". Diese Funktion nimmt allerdings eine Zeichenkette mit der Befehlszeile entgegen. "subprocess" behilft sich damit, übergebene Listen mittels "subprocess.list2cmdline()" in eine Zeichenkette umzuwandeln. Das geht natürlich schief, wenn das Programm andere, unerwartete Regeln zum Parsen der Argumente nutzt. Dieses Verhalten ist auch dokumentiert.

Allerdings kann man das nicht subprocess anlasten, sondern dem abenteuerlichen Design der Windows-API. Andere Bibliotheken und Rahmenwerke wie Qt oder das JRE dürften das selbe Problem haben.

@Shining-Blue: Rufe doch unter Windows mal manuell "subprocess.list2cmdline()" mit deiner Liste aus und lass dir dessen Rückgabewert anzeigen. Vielleicht erkennst Du ja wo der Fehler liegt.
Shining-Blue
User
Beiträge: 37
Registriert: Samstag 15. August 2009, 04:36

Das war eine gute Idee.

Code: Alles auswählen

print sub.list2cmdline([os.path.join(pathtobin , 'convert'), os.path.join(workpath , infile), '-resize', '320x', os.path.join(workpath , folder , ('thumb_' + infile))])
ergibt die Consolenausgabe

Code: Alles auswählen

convert "C:/Dokumente und Einstellungen/Lena/Desktop/aaaaa/test_2.JPG" -resize 3
20x "C:/Dokumente und Einstellungen/Lena/Desktop/aaaaa/test_2\thumb_test_2.JPG"
Unzulässiger Parameter - /Dokumente
So wie es scheint werden die Pfaddelimeter nicht wingerecht auf C:\Dokumente und Einstellungen\Lena\Desktop\aaaaa umgesetzt.

Die os.xxx und shutils machen dies jedoch richtig.

Wäre is im Sinne einer einfacheren, plattformübergreifenden Weitergabe nicht sinnvoller ganz auf externe Programme ala ImageMagick zu verzichten und dafür die PIL zu nutzen?
Der Ansatz mit ImageMagick stammt noch aus dem Ursprung des Scripts als Shellscript. Von der Pil habe ich erst im Laufe der "Entwicklung" dieses kleinen Progs erfahren.
Ich glaube ich könnte mir so gleichzeitig mehere Probleme vom Hals schaffen.
Auf der anderen Seite ist es natürlich äußerst unbefriedigend an einer so simplen Aufgabe wie der plattformübergreifenden Ausführung eines externen Befehls zu scheitern :cry:

LG SB
Zuletzt geändert von Shining-Blue am Dienstag 25. August 2009, 10:34, insgesamt 1-mal geändert.
Antworten