package net.sourceforge.dita4publishers.tools.imaging.im; import java.awt.image.BufferedImage; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import javax.imageio.ImageIO; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * This class implements the processing of image operations. It replaces * place-holders within the argument-stack and passes all arguments to the * generic run-method of ProcessStarter. */ public class ImageCommand extends ProcessStarter implements ErrorConsumer { private static Log log = LogFactory.getLog(ImageCommand.class); /** * The command (plus initial arguments) to execute. */ private LinkedList<String> iCommands; /** * List of stderr-output. */ private ArrayList<String> iErrorText; /** * List of temporary files (input). */ private LinkedList<String> iTmpFiles; /** * Temporary output file. */ private String iTmpOutputFile; /** * Constructor. */ public ImageCommand() { super(); iCommands = new LinkedList<String>(); iTmpFiles = new LinkedList<String>(); setOutputConsumer(StandardStream.STDOUT); setErrorConsumer(this); } /** * Constructor setting the commands. */ public ImageCommand(String... pCommands) { this(); setCommand(pCommands); } /** * Set the command. */ public void setCommand( String... pCommands) { for (String cmd : pCommands) { iCommands.add(cmd); } } /** * * @param imageMagicHomeDir * @param command * @return */ protected String getCommandForImageMagickBin( File imageMagicHomeDir, String command) { File binDir = new File(imageMagicHomeDir, "bin"); File commandFile = new File(binDir, command); return commandFile.getAbsolutePath(); } /** * Execute the command (replace given placeholders). * * @throws IM4JavaException */ public void run( Operation pOperation, Object... images) throws IOException, InterruptedException, IMException { // prepare list of arguments LinkedList<String> args = new LinkedList<String>(pOperation.getCmdArgs()); args.addAll(0, iCommands); resolveImages(args, images); resolveDynamicOperations(pOperation, args, images); int rc = run(args); removeTmpFiles(); if (rc > 0) { CommandException ce = new CommandException(); ce.setErrorText(iErrorText); throw ce; } } /** * Resolve images passed as arguments. */ private void resolveImages( LinkedList<String> pArgs, Object... pImages) throws IOException { ListIterator<String> argIterator = pArgs.listIterator(); int i = 0; for (Object obj : pImages) { // find the next placeholder while (argIterator.hasNext()) { if (argIterator.next().equals(Operation.IMG_PLACEHOLDER)) { break; } } if (obj instanceof String) { argIterator.set((String) obj); } else if (obj instanceof BufferedImage) { if (i < pImages.length) { // write BufferedImage to temporary file // and replace the placeholder with the temporary file String tmpFile = convert2TmpFile((BufferedImage) obj); argIterator.set(tmpFile); iTmpFiles.add(tmpFile); } else { // special case: BufferedImage is last image, so just create name iTmpOutputFile = getTmpFile(); argIterator.set(iTmpOutputFile); } } else { throw new IllegalArgumentException(obj.getClass().getName() + " is an unsupported image-type"); } i++; } } /** * Resolve DynamicOperations. * * @throws IM4JavaException */ private void resolveDynamicOperations( Operation pOp, LinkedList<String> pArgs, Object... pImages) throws IMException { ListIterator<String> argIterator = pArgs.listIterator(); ListIterator<DynamicOperation> dynOps = pOp.getDynamicOperations() .listIterator(); // iterate over all DynamicOperations while (dynOps.hasNext()) { DynamicOperation dynOp = dynOps.next(); Operation op = dynOp.resolveOperation(pImages); // find the next placeholder while (argIterator.hasNext()) { if (argIterator.next().equals(Operation.DOP_PLACEHOLDER)) { break; } } if (op == null) { // no operation argIterator.remove(); } else { List<String> args = dynOp.resolveOperation(pImages).getCmdArgs(); if (args == null) { // empty operation, remove placeholder argIterator.remove(); } else { // remove placeholder and add replacement argIterator.remove(); for (String arg : args) { argIterator.add(arg); } } } } // while (dynOps.hasNext()) } /** * This method just saves the stderr-output into an internal field. * * @see org.im4java.process.ErrorConsumer#consumeError(java.io.InputStream) */ public void consumeError( InputStream pInputStream) throws IOException { InputStreamReader esr = new InputStreamReader(pInputStream); BufferedReader reader = new BufferedReader(esr); String line; if (iErrorText == null) { iErrorText = new ArrayList<String>(); } while ((line = reader.readLine()) != null) { iErrorText.add(line); } reader.close(); esr.close(); } /** * Create a temporary file. */ private String getTmpFile() throws IOException { File tmpFile = File.createTempFile("im4java-", ".png"); tmpFile.deleteOnExit(); return tmpFile.getAbsolutePath(); } /** * Write a BufferedImage to a temporary file. */ private String convert2TmpFile( BufferedImage pBufferedImage) throws IOException { String tmpFile = getTmpFile(); ImageIO.write(pBufferedImage, "PNG", new File(tmpFile)); return tmpFile; } /** * Remove all temporary files. */ private void removeTmpFiles() { try { for (String file : iTmpFiles) { (new File(file)).delete(); } } catch (Exception e) { // ignore, since if we can't delete the file, we can't do anything about // it } } }