Jai’s Weblog – Tech, Security & Fun…

Tech, Security & Fun…

  • Jaibeer Malik

    Jaibeer Malik
  • View Jaibeer Malik's profile on LinkedIn
  • Subscribe

  • Feedburner

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 28 other followers

  • Archives

  • Categories

  • Stats

    • 275,664
  • Live Traffic

ImageMagick: Using piped convert commands from java

Posted by Jai on October 18, 2012

ImageMagick fits best for most of the image manipulation operations. The convert command line utility meets most of the requirement. On top of that the additional features of convert command to pipe output of commands is really very handy. In this post we will see how we can use piped convert command line utility from java to achieve the same behavior.

Convert Command

ImageMagick Convert command allows to convert between image formats as well as many other image manipulations.

The different command line processing options are also allowed with the convert command.

Piped Convert Commands

ImageMagick permits image data to be read and written from the standard streams STDIN (standard in) and STDOUT (standard out), respectively, using a pseudo-filename of “-“.

convert rose: gif:- | convert - -resize "200%" bigrose.jpg

Piped Convert Commands from Java

From earlier post “Using ImageMagick from Java”, you can see the java data model to call the convert command line utility from java.

Here we will see how we can call the piped convert command from java. We can combine multiple image manipulations together (here eg. one image manipulation is one convert command). We can combine multiple convert commands using pipe and generate a single command to be called on the command line.

The general Issues in calling so are,

  • Calling command line utility from java (which we have covered in last post how to solve the same. There are problems in using java ProcessBuilder for piped command, eg. post)
  • Piped command execution from java is not allowed (it treats whole string a single command and causes parsing issues. One nice example is as stated on post, but the real issue starts if along with pipe you have string quotes and special characters to be passed.)
  • String quote escape issues (while executing command string on command line it behaves differently on both unix and windows. The escape quotes single and dobule behaves differently)
  • Special characters like “(” and “\” used in convert command in imagemagick are not properly passed to command line string (double parsing does not work well while executing the command string, need to have local script to parse the string quotes separately).
  • Try out apache common utility, exec commandline. but the issue still remains of quotes and escaping special characters.

Some example errors are like below,

"bash -c" unexpected EOF while looking for matching `"'
java -c: line 0: unexpected EOF while looking for matching `"'
convert.exe: clone unable to open image "\(" No such file or directory @ error/blob.c/OpenBlob/2614.
"\(" Permission denied @ error/blob.c/OpenBlob/2614.

Looking at the error messages, sometimes it is even so hard to debug the exact issue. But as usual the parsing issues throw strange error messages.

Below example shows, how you can try to solve above problem to make the java code independent of unix/windows environments. Below code snippets generates a piped convert command based on different image manipulations provided as list.

public String generateCommand(File inputFile, File outputFile, List imageManipulations)
{
   //Used for java to OS string wrapping on unix the double quotes will for you
   // and on windows try with single quote. set it as system property
    String pipedShellCommandStringQuote = "\"";
    String SPACE = " ";
    //pipe between different convert commands
    String SEPARATOR_FOR_PIPING = " | ";
    //convert command piped files naming convention.
    String PLACEHOLDER_FOR_PIPING = "-";
    //Executable path either can be path to convert command line utility or
    //your custom script parsing the params for piped command.
    String pipedCommandShellExecutablePath;
    StringBuilder commandSB = new StringBuilder();
    commandSB.append(pipedCommandShellExecutablePath + SPACE + pipedShellCommandStringQuote);
    boolean isFirstCommand = true;
        for (int counter=0; counter < imageManipulations.size(); counter++)
        {
            boolean isLastCommand = counter == imageManipulations.size() - 1;
            ImageManipulation imageManipulation = (ImageManipulation) imageManipulations.get(counter );
            String commandName = getCommandName(imageManipulation.getCommandType());
            String inputFileName = PLACEHOLDER_FOR_PIPING; // default always piping
            String outputFileName = PLACEHOLDER_FOR_PIPING; // default always piping
            if (isFirstCommand)
            {
                // first command should use real inputFile name instead of piping placeholder
                inputFileName = inputFile.getAbsolutePath();
                isFirstCommand = false;
            }
            if (isLastCommand && outputFile != null)
            {
                // last command, should use real outputFile name instead of piping placeholder
                outputFileName = outputFile.getAbsolutePath();
            }
            //Add default additional parameters for each manipulation
            //Add default quality etc. runtime params for image manipulation here.
            String commandLineOptions = addDefaultCommandLineOptionsForImageManipulation(imageManipulation.getCommandLineOptions(), isLastCommand);

            ........

            //prepare parameter values for command line
            Map<String, Object> optionsValuesMap = new HashMap<String, Object>();
           for (Entry<String, String> parameterEntry : imageManipulation.getParams().entrySet())
           {
            String paramaterValue = parameterEntry.getValue();
            // find parameter
            optionsValuesMap.put(parameterEntry.getKey(), paramaterValue);
            }

            //replace param value for the command line options
            //use template to replace key-value pair inside the command line options.
            StringWriter writer = new StringWriter();
            Template template = new Template("", new StringReader(commandLineOptions), new Configuration());
            template.process(optionsValuesMap, writer);
            String commandForImageManipulation = writer.toString();

            commandSB.append(commandName + SPACE + commandForImageManipulation);

            if (!isLastCommand)
            {
                // not last command add piping separator
                commandSB.append(SEPARATOR_FOR_PIPING);
            }
        }

      commandSB.append(pipedShellCommandStringQuote);

  return commandSB.toString();
}

Piped Convert Commands Script

To solve the above mentioned issues related to environment string quote issues and to escape out the special characters in the command line options of imagemagick convert command, here is a small perl script to does exactly the same for us.

#!/usr/bin/perl

open LOG, ">>/var/log/imagemagickpipedconvert.log";

printf LOG "Got " . $#ARGV . " args\n";
my $i = 0;

for( $i = 0; $i <= $#ARGV; $i++ )
{
printf LOG "Args[$i] = " . $ARGV[$i] . "\n";
}

my $commandline = join(" ", @ARGV );

print LOG "Commandline = '$commandline'\n";

`$commandline`

Depending on the requirement, you can choose either to construct single convert command and piped convert command to be executed on command line from java. Hope above example will help you to start with actual implementation of the big logic. It is indeed to be very helpful sometimes for performance gains and processing time in case you doing big image manipulations real time. Feel free to share your experiences on using command line utility in piped manner from java.

About these ads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 28 other followers

%d bloggers like this: