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 29 other followers

  • Archives

  • Categories

  • Stats

    • 379,210
  • Live Traffic

Image Manipulation: Using ImageMagick from Java

Posted by Jai on October 16, 2012

ImageMagick is well know image manipulation suite. The functionality of ImageMagick is typically utilized from the command line and the challenge comes to use the command line utility from with programming language like Java. In this post we will cover to use imagemagick command line utility from Java and will explore the available solution and approaches to achieve the same.

ImageMagick

ImageMagick is a software suite to create, edit, compose, or convert bitmap images. The functionality of ImageMagick is typically utilized from the command line or you can use the features from programs written in your favorite language. In this post we will cover different ways to use imagemagick from java,

For detailed usage of the suite, have a look at documentation.

Programming Interface in Java

We will have a look at different options available to use imagemagick from java,

  • Accessing imagemagick api from java
  • Accessing imagemagick commandline utility from java
  • Developing custom solution to access imagemagick from java

Accessing imagemagick api from java

jmagick

JMagick is an open source Java interface of ImageMagick.It is merely a thin interface layer into the ImageMagick API.

Accessing imagemagick commandline utility from java

im4java

im4java is a pure-java interface to the ImageMagick commandline.

It generates the commandline for the ImageMagick commands and passes the generated line to the selected IM-command (using the java.lang.ProcessBuilder.start()-method).

For full feature list, have a look at Features

Developing custom solution to access imagemagick from java

Custom solutions

We will try to design a solution which will help us to call different command line utilities for image manipulation. The java model should take into account,

  • Multiple command line utilities (eg. ImageMagick, Gimp, GraphicsMagick etc.)
  • Flexibility to pass runtime environment parameters (preview servert, production server, image quality parameters)
  • Option to define exact commandLine options to be called in the utility
  • Option to call custom script on the system (either .bat file or .sh bash script)
  • Option to replace commandlineoptions parameters like input/output file names, width height etc.
  • Option to define image quality and size etc. for final output image.
  • Option to define multiple image manipulation in single command (eg. piping multiple commands using imagemagick convert command).
  • Option to group and define image manipulation in series based on command type etc (combine all convert in single command and execute gimp in series).

ImageManipulationInfo

Object to hold all the image manipulation information.


public class ImageManipulationInfo
{
//List defining all the image manipulation to be done on the input file.
private List imageManipulations;
//Default last manipulation quality, for print
private int lastManipulationQuality = 100;
//Environment property to control if the thumbnails needs to be created
//This can be used to develop image for preview servers for user display
private boolean forPreview;
//Parameters to store final image properties, what size of image you want.
//Can be used in resize or can also be used as input image properties as runtime param.
private final int width;
private final int height;
private final int rotation;

....

}

ImageManipulation

Single image manipulation to be applied on an image.


public class ImageManipulation
{
//Key-value params which can be replaced in the exact commandLineOptions and/or additional runtime params
public static enum ImageManipulationParams {INPUT_FILE, OUTPUT_FILE, FILTER_PATH, DEFAULT_PREFIX_PARAMS};
//base image directory path, which will be appended as path in commandLineOptions
private String filterPath;
//Different command line options to be passed to actual command
// Key param will be replaced by key values from below map.
private String commandLineOptions;
//Command type, can be ImageMagick.Convert, ImageMagick.Mogrify, Gimp.Plugin etc.
private ImageManipulationCommand commandType;
//Key-value pair to be relaced in commandLineOptions above.
//The map is generated based on your runtime params values.
private Map<String, String> params;
....

}

ImageManipulationGroup

Grouping of the different ImageManipulation objects in single group is required to performance improvements. Image you have three-four ImageMagick convert commands as ImageManipulations and you want to execute those in series on command line.

One Option is to Execute_Convert_Command1->Stroe_Temp_File1->Execute_Convert_Command2->Stroe_Temp_File2->Execute_Convert_Command3->and so on…

Another option is to execute all the command in single command from java and let convert command to pipe the output of one command as input of another convert command. The grouping of ImageManipulations is very handy in such scenarios.

Each group will have input/output file references. In case of multiple command utilities this is necessary to execute command in series. ImageManipulationHandler will generate command string and will actually execute the command for you.


class ImageManipulationGroup
{
//Input file for the group, in case of multiple serial manipulations this can be temp file generated.
private File inputFile;
//output file from the image manipulation group.
private File outputFile;
//the selected image manipulations to be be applied in this group.
private List selectedImageManipualtions;

//In practical, it can be any command utility available
//In our example case it is only imagemagick (say convert or mogrify etc. based on command type).
private ImageManipulationHandler handler;

....
}

ImageManipulationHandler

The handler will generate Command string to be executed and will actually call the command to be applied based on your ImageManipulationGroup.


public void applyManipulations(File inputFile, File outputFile, ImageManipulationInfo imageManipulationInfo)
{
//Based on different requirements
//Multiple command utilities, different manipulation group will be created
//Based on different commands (mogrify, convert etc.) same or different groups can be created if you want to run operations in single or multiple commands.
List groups = constructImageManipulationGroups(inputFile, outputFile, imageManipulationInfo);

for (ImageManipulationGroup group : groups)
{
     group .getHandler().applyManipulations(group .getInputFile(), group .getOutputFile(), group .getSelectedManipulationInfo());
}
}

public String generateCommand(File inputFile, File outputFile, List imageManipulations)
{
private String pipedShellCommandStringQuote = "\"";
private String SPACE = " ";
private String SEPARATOR_FOR_PIPING = " | ";
private String PLACEHOLDER_FOR_PIPING = "-";

//Your logic to generate actual command to be executed on the system
//eg it will be combination of
// ACTUAL_COMMAND + COMMAND_LINE_OPTIONS + REPLACE_MAP_PARAMS + ADD_RUNTIME_PARAMS + ADD_ESCAPE_CHARS etc.
...

return commandString;
}

CommandExecutor

This class actually builds the process and calls the command on the operating system. It allows you to watch the process, and allow you to control success or failure cases from command line to java.


public class CommandExecutor
{
private final ExecutorService cachedExecutorService = Executors.newCachedThreadPool();
private final ObjectPool byteArrayOutputStreamObjectPool = new StackObjectPool( new ByteArrayOutputStreamPoolFactory() );

.....

//Break earlier command line string to array which will be used to construct process later.
//Control wait time, how long you want to set the timeout for the process.
public String runCommandLine(String[] cmdarray, long maxWaitTimeInMillis)
{

.....
//Escape spaces and special characters here at common place. eg. escaped.add( cmd.replaceAll(" ", "\\ ") );
//The list containing the program and its arguments
List commands = escapeSpacesAndNullArguments(cmdarray);

ProcessBuilder processBuilder = new ProcessBuilder(commands);

// Start the command
Process process = processBuilder.start();

// Start watchdog
ProcessWatchDog processWatchDog = new ProcessWatchDog(completeCommandLine, process, maxWaitTimeInMillis, checkIntervalInMillis);
processWatchDogFuture = executorService.submit( processWatchDog, new Object());

// Start error output drainer
ByteArrayOutputStream errorOutputByteArray = (ByteArrayOutputStream) byteArrayOutputStreamObjectPool.borrowObject();
ProcessOutputDrainer processErrorOutputDrainer = new ProcessOutputDrainer( completeCommandLine, process.getErrorStream(), errorOutputByteArray, true);
Future processErrorOutputDrainerFuture = cachedExecutorService.submit(processErrorOutputDrainer, errorOutputByteArray);

// Start normal output drainer
ByteArrayOutputStream normalOutputByteArray = (ByteArrayOutputStream) byteArrayOutputStreamObjectPool.borrowObject();
ProcessOutputDrainer processNormalOutputDrainer = new ProcessOutputDrainer( completeCommandLine, process.getInputStream(), normalOutputByteArray, false);
Future processNormalOutputDrainerFuture = cachedExecutorService.submit(processNormalOutputDrainer, normalOutputByteArray);

// Wait on process to finish
processExitValue = process.waitFor();
logger.debug("Process exit value: {}", processExitValue);

// Wait on drainers to finish
processNormalOutput = processNormalOutputDrainerFuture.get().toString();
final String processErrorOutput = processErrorOutputDrainerFuture.get().toString();

byteArrayOutputStreamObjectPool.returnObject(normalOutputByteArray);
byteArrayOutputStreamObjectPool.returnObject(errorOutputByteArray);

logger.info("Executing commandline '{}' took {}ms", completeCommandLine, stopWatch.getTime());

}

If the process is executed well, you would be able to apply as many image manipulation on the file as required. The design would allow you to control to use different scripts and different utilities on different environments.

Hope the design will help you too to play around java code while taking full benefit of calling command utilities from java. Feel free to share your experiences regarding designing your custom solutions around image manipulations!

8 Responses to “Image Manipulation: Using ImageMagick from Java”

  1. Great overview. We played around using imagemagick from Java but ended up using a pure java solution for image manipulation. https://github.com/thebuzzmedia/imgscalr is a good one to check out as an alternative.

  2. […] Image Manipulation: Using ImageMagick from Java […]

  3. […] Image Manipulation: Using ImageMagick from Java […]

  4. About Java said

    hi
    i’m fresher to java..
    good and informative article of image manipulation..
    thanks for sharing..🙂

  5. Sagar said

    Hi
    I am new to java and want to use imagemagick in an web application. Which jar should i use. I am not able to find any jars for imagemagick. Only what i can find is source download and binary downloads

  6. Sreevani said

    Hi Jai,
    Good one!! You made it clear. I will give it a try. Thanks.

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

 
%d bloggers like this: