ImageMagick is the great set of image processing utilities. But there are some problems to interact with it from your programs (java program in my case). About one of them I would like to talk. In one of our latest projects we used ImageMagick to resize images and put a watermark on them. Everything was fine on developers machines with OS Windows, but when we put project on Unix server… Agrrr. WTF?! We got this error: “convert: Non-conforming drawing primitive definition `image”. Magic… ImageMagick! Here is the best article that I have founded about this problem. It doesn’t help me ’cause it describes a little different problem, but it may be helpful for you) Ok, let us see the code that throws the error (in this example I removed resize parameter ’cause it works fine and the problem only in draw):
public void convertImage() { // List of commands that we want to execute List commands = new ArrayList(); // Executable file commands.add("convert"); // Executable file parameters commands.add("-gravity"); commands.add("South-East"); commands.add("-draw"); commands.add(""image Over 0,0 0,0 'im-watermark.png'""); commands.add("im-image.png"); commands.add("im-new.png"); try { // I also tried to use Runtime.getRuntime().exec(...), but got the same result and it doesn't wonder // 'cause it use ProcessBuilder ProcessBuilder processBuilder = new ProcessBuilder(); processBuilder.command(commands); Process process = processBuilder.start(); BufferedReader error = new BufferedReader(new InputStreamReader(process.getErrorStream())); // Check if we have an error... if (error.ready()) { // ...then print them String line; while ((line = error.readLine()) != null) { System.out.println("error: " + line); } } } catch (IOException e) { e.printStackTrace(); } }
The process builder that we use in our code example must generate such command:
convert -gravity South-East -draw "image Over 0,0 0,0 'im-watermark.png'" im-image.png im-new.jpeg
Looks correct, but doesn’t work. Ok, let’s try to run this command from Unix shell. I can’t belive it! It works! In shell, but not from our program( I think that something happens with convert command parameters when JVM run it or may be it is some kind of Unix feature. I don’t know. So, I did this trick:
-
create shell script “im-convert-proxy.sh” (don’t forget to execute “chmod +x im-convert-proxy.sh” command. It allows you to execute this script) with code:
eval 'convert '$@
How you can see it just runs convert command with all parmeters that we passed to script from our java program.
-
replace executable file from “convert” to “im-convert-proxy.sh”:
commands.add("im-convert-proxy.sh"); // was commands.add("convert");
That’s all! Everything works, everyone is happy)
P.S.: if you have found a better solution, please write me.
Hi Alexander,
Nice trick invoking a script 🙂
I think the problem is in this line of your ProcessBuilder params:
> commands.add(“”image Over 0,0 0,0 ‘im-watermark.png'””);
If you re-write that as:
> commands.add(“image”);
> commands.add(“Over”);
> commands.add(“0,0”);
> commands.add(“0,0”);
> commands.add(“im-watermark.png”);
… it should work.
My bad, I posted that without actually trying it…
This works:
> commands.add(”image Over 0,0 0,0 ‘im-watermark.png’”);
which is basically what you had, less the double quotes.
Hi, Steve!
Thanks a lot for your commentaries, research and the article “Invoking Processes from Java”! I tried different combinations, but none of them worked. So, I used this dirty hack to solve the problem. Probably, something wrong was with the environment. I don’t know. I’ve never met with such problem after that)