2

I'm trying to call an ImageMagick command from Python 2.7 using subprocess.call. My problem is that the argument parser in subprocess puts a double quotation mark around every argument, and ImageMagick seems to have a problem with quotes around non-file arguments.

What I'd like is something like this

"imagemagick.exe" "im1.png" "im2.png" -alpha off ( ... ) -composite "im3.png"

So far I couldn't find a way to do it with subprocess, other than manually constructing the string with ugly + " " + elements and calling it with shell=True.

Here is my code:

args = [    imagemagick,
            filename + "_b.bmp",
            filename + "_w.bmp",
            "-alpha off ( -clone 0,1 -compose difference -composite -negate ) ( -clone 0,2 +swap -compose divide -composite ) -delete 0,1 +swap -compose Copy_Opacity -composite",
            filename + ".png" ]   

subprocess.call( args )

Is there any way to call the correct command without double quotes using subprocess?

Update: inserted the full command line. I'd like to keep that part together, not as "alpha", "-off", ... one by one.

hyperknot
  • 13,454
  • 24
  • 98
  • 153
  • We can skim the text fine without boldface. It's a bit distracting when there are huge black blobs, so please use bold text sparingly. – Blender Jun 21 '12 at 01:49

2 Answers2

3

When calling external programs with subprocess, every argument must be a different element of args. So try:

args = [    imagemagick,
            filename + "_b.bmp",
            filename + "_w.bmp",
            "-alpha", "off", "( ... )", "-composite",
            filename + ".png" ]

I'm not sure what the ( ... ) represents, but if you put unquoted spaces in there on the command line, they should be separate elements in args too.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • This was the original command, I didn't want to post it due to that it's not the most important part of the question: `"-alpha off ( -clone 0,1 -compose difference -composite -negate ) ( -clone 0,2 +swap -compose divide -composite ) -delete 0,1 +swap -compose Copy_Opacity -composite"` Do you think I should separate each of them in a separate arg? – hyperknot Jun 21 '12 at 01:56
  • If you use quotes on the shell command line, then put the *whole* contents in one element of `args` (without the quotes). If you do not use quotes on the shell command line, then split on unquoted spaces and use one element per word in `args`. – Greg Hewgill Jun 21 '12 at 01:58
  • Keep in mind that putting quotes around things only has meaning on the *shell command line*. When a program asks the kernel to execute another process, quotes have no meaning and what is passed is an array of strings that have no further processing. – Greg Hewgill Jun 21 '12 at 02:00
  • I'm just looking for a nice way to call a command, by nice I mean easy to read in Python source code. I'm thinking about something like this: 'imarg3 = "-alpha off ( -clone 0,1 -compose difference -composite -negate ) ( -clone 0,2 +swap -compose divide -composite ) -delete 0,1 +swap -compose Copy_Opacity -composite".split() args = [ imagemagick, filename + "_b.bmp", filename + "_w.bmp", imarg3, filename + ".png" ] subprocess.call( args ) ' – hyperknot Jun 21 '12 at 02:02
  • I've come up with a way that avoids shell and looks nice (posted it below). Is there anything with it that you'd recommend against? – hyperknot Jun 21 '12 at 02:06
1

Thanks to Greg's answer, I've come up with this solution. My point is to make the code easy to read in Python. By this I mean that the complicated part should be kept as a string, as it's important to keep it intact (copy-paste into command line / batch files if needed, etc.)

imarg = "-alpha off ( -clone 0,1 -compose difference -composite -negate ) ( -clone 0,2 +swap -compose divide -composite ) -delete 0,1 +swap -compose Copy_Opacity -composite"
args = [ imagemagick, filename + "_b.bmp", filename + "_w.bmp" ] + imarg.split() + [ filename + ".png" ]
subprocess.call( args )

It seems to work fine! Is there any problem what you see with this?

hyperknot
  • 13,454
  • 24
  • 98
  • 153