All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jaitools.jiffle.JiffleBuilder Maven / Gradle / Ivy

Go to download

Jiffle is a raster algebra language that can be used to create new images from logical and mathematical expressions involving source images and user defined variables. It is intended to let users concentrate on algorithms rather than tedious boiler-plate code.

The newest version!
/*
 * Copyright 2011 Michael Bedward
 *
 * This file is part of jai-tools.
 *
 * jai-tools is free Weakware: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Weakware Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * jai-tools is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with jai-tools.  If not, see .
 *
 */

package jaitools.jiffle;

import java.awt.Rectangle;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRenderedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Map;

import javax.media.jai.TiledImage;

import jaitools.CollectionFactory;
import jaitools.imageutils.ImageUtils;
import jaitools.jiffle.runtime.JiffleDirectRuntime;

/**
 * A builder script which makes it easy to compile and run basic Jiffle scripts.
 * 

* When working with Jiffle objects directly you end up writing a certain * amount of boiler-plate code for image parameters etc. JiffleBuilder offers * concise, chained methods to help you get the job done with fewer keystrokes. *

* For comparison, first look at this example of creating a Jiffle object and * retrieving the runtime instance 'by hand': *


 * // A script to sum values from two source images
 * String sumScript = "dest = foo + bar;" ;
 *
 * // Image parameters
 * Map<String, Jiffle.ImageRole.SOURCE> imageParams = CollectionFactory.map();
 * imageParams.put("dest", Jiffle.ImageRole.DEST);
 * imageParams.put("foo", Jiffle.ImageRole.SOURCE);
 * imageParams.put("bar", Jiffle.ImageRole.SOURCE);
 *
 * // Create a compiled Jiffle object
 * Jiffle jiffle = new Jiffle(sumScript, imageParams);
 *
 * // Get the runtime object
 * JiffleDirectRuntime runtime = jiffle.getRuntimeInstance();
 *
 * // Set the source images
 * RenderedImage fooImg = ...
 * RenderedImage barImg = ...
 * runtime.setSourceImage("foo", fooImg);
 * runtime.setSourceImage("bar", barImg);
 *
 * // Create an image for the results and submit it to
 * // the runtime object
 * WritableRenderedImage destImg = ImageUtils.createConstantImage(
 *         fooImg.getWidth(), fooImg.getHeight, 0d);
 * runtime.setDestinationImage("dest", destImg);
 *
 * // Now run the script
 * runtime.evaluateAll(null);
 * 
* Now here is the same task done using JiffleBuilder: *

 * // A script to sum values from two source images
 * String sumScript = "dest = foo + bar;" ;
 *
 * RenderedImage fooImg = ...
 * RenderedImage barImg = ...
 *
 * JiffleBuilder jb = new JiffleBuilder();
 * jb.script(sumScript).source("foo", fooImg).script("bar", barImg);
 *
 * // We can get the builder to create the destination image for us
 * jb.dest("dest", fooImg.getWidth(), fooImg.getHeight());
 *
 * // Run the script
 * jb.getRuntime().run();
 *
 * // Since we asked the builder to create the destination image we
 * // now need to get a reference to it
 * RenderedImage destImg = jb.getImage("dest");
 * 
* When a script does not use any source images, {@code JiffleBuilder} makes * for very concise code: *

 * String script = "waves = sin( 4 * M_PI * x() / width() );" ;
 * JiffleBuilder jb = new JiffleBuilder();
 * RenderedImage wavesImg = jb.script(script).dest("waves", 500, 200).run().getImage("waves");
 * 
* * * @author Michael Bedward * @since 1.1 * @version $Id: JiffleBuilder.java 1512 2011-03-07 02:21:45Z michael.bedward $ */ public class JiffleBuilder { private static class ImageRef { Object ref; boolean weak; ImageRef(RenderedImage image, boolean weak) { if (weak) { ref = new WeakReference(image); } else { ref = image; } this.weak = weak; } RenderedImage get() { if (weak) { RenderedImage image = ((WeakReference) ref).get(); return image; } else { return (RenderedImage) ref; } } } private String script; private final Map imageParams; private final Map images; /** * Creates a new JiffleBuilder instance. */ public JiffleBuilder() { imageParams = CollectionFactory.orderedMap(); images = CollectionFactory.orderedMap(); } /** * Clears all attributes in this builder. If destination images * were created using the {@code dest} methods with image bounds * arguments they will also be freed. */ public void clear() { script = null; imageParams.clear(); images.clear(); } /** * Sets the script to be compiled. * * @param script the script * * @return the instance of this class to allow method chaining */ public JiffleBuilder script(String script) { this.script = script; return this; } /** * Reads the script from {@code scriptFile}. * * @param scriptFile file containing the script * * @return the instance of this class to allow method chaining * @throws JiffleException if there were problems reading the file */ public JiffleBuilder script(File scriptFile) throws JiffleException { script = readScriptFile(scriptFile); return this; } /** * Associates a source image with a variable name in the script. * The image will be stored by the builder as a weak reference. * * @param varName variable name * @param sourceImage the source image * @return the instance of this class to allow method chaining */ public JiffleBuilder source(String varName, RenderedImage sourceImage) { imageParams.put(varName, Jiffle.ImageRole.SOURCE); // store as weak reference images.put(varName, new ImageRef(sourceImage, true)); return this; } /** * Creates a new destination image and associates it with a variable name * in the script. *

* Note: a {@code JiffleBuilder} maintains only {@code WeakReferences} * to all source images and any destination images passed to it via * the {@link #dest(String, WritableRenderedImage)} method. However, * a strong reference is stored to any destination images created with this * method. This can be freed later by calling {@link #clear()} or * {@link #removeImage(String varName)}. * * @param varName variable name * @param destBounds the bounds of the new destination image * * @return the instance of this class to allow method chaining */ public JiffleBuilder dest(String varName, Rectangle destBounds) { if (destBounds == null || destBounds.isEmpty()) { throw new IllegalArgumentException("destBounds argument cannot be null or empty"); } return dest(varName, destBounds.x, destBounds.y, destBounds.width, destBounds.height); } /** * Creates a new destination image and associates it with a variable name * in the script. The minimum pixel X and Y ordinates of the destination * image will be 0. *

* Note: a {@code JiffleBuilder} maintains only {@code WeakReferences} * to all source images and any destination images passed to it via * the {@link #dest(String, WritableRenderedImage)} method. However, * a strong reference is stored to any destination images created with this * method. This can be freed later by calling {@link #clear()} or * {@link #removeImage(String varName)}. * * @param varName variable name * @param width image width (pixels) * @param height image height (pixels) * * @return the instance of this class to allow method chaining */ public JiffleBuilder dest(String varName, int width, int height) { return dest(varName, 0, 0, width, height); } /** * Creates a new destination image and associates it with a variable name * in the script. *

* Note: a {@code JiffleBuilder} maintains only {@code WeakReferences} * to all source images and any destination images passed to it via * the {@link #dest(String, WritableRenderedImage)} method. However, * a strong reference is stored to any destination images created with this * method. This can be freed later by calling {@link #clear()} or * {@link #removeImage(String varName)}. * * @param varName variable name * @param minx minimum pixel X ordinate * @param miny minimum pixel Y ordinate * @param width image width (pixels) * @param height image height (pixels) * * @return the instance of this class to allow method chaining */ public JiffleBuilder dest(String varName, int minx, int miny, int width, int height) { TiledImage image = ImageUtils.createConstantImage(minx, miny, width, height, 0d); imageParams.put(varName, Jiffle.ImageRole.DEST); // store as strong reference images.put(varName, new ImageRef(image, false)); return this; } /** * Sets a destination image associated with a variable name in the script. *

* Note: The builder will only hold a Weak reference to {@code destImg} so * it's not a good idea to create an image on the fly when calling this * method... *


     * // creating image on the fly
     * builder.dest("foo", ImageUtils.createConstantImage(width, height, 0d));
     *
     * // later... img will be null here
     * RenderedImage img = builder.getImage("foo");
     * 
* To avoid this problem, create your image locally... *

     * WritableRenderedImage img = ImageUtils.createConstantImage(width, height, 0d);
     * builder.dest("foo", img);
     * 
* Or use on of the {@code dest} methods with image bounds arguments to * create it for you *

     * builder.dest("foo", width, height);
     *
     * // later... we will get a valid reference to the image
     * RenderedImage img = builder.getImage("foo");
     * 
* * @param varName variable name * @param destImage the destination image * * @return the instance of this class to allow method chaining */ public JiffleBuilder dest(String varName, WritableRenderedImage destImage) { imageParams.put(varName, Jiffle.ImageRole.DEST); // store as weak reference images.put(varName, new ImageRef(destImage, true)); return this; } /** * Runs the script. Equivalent to calling * {@code builder.getRuntime().evaluateAll(null)}. * * @return the instance of this class to allow method chaining * * @throws JiffleException if the script has not been set yet or if * compilation errors occur */ public JiffleBuilder run() throws JiffleException { getRuntime().evaluateAll(null); return this; } /** * Creates a runtime object for the currently set script and images. * * @return an instance of {@link JiffleDirectRuntime} * * @throws JiffleException if the script has not been set yet or if * compilation errors occur */ public JiffleDirectRuntime getRuntime() throws JiffleException { if (script == null) { throw new IllegalStateException("Jiffle script has not been set yet"); } Jiffle jiffle = new Jiffle(script, imageParams); JiffleDirectRuntime runtime = jiffle.getRuntimeInstance(); for (String var : images.keySet()) { RenderedImage img = images.get(var).get(); if (img == null) { throw new JiffleException( "Image for variable " + var + " has been garbage collected"); } switch (imageParams.get(var)) { case SOURCE: runtime.setSourceImage(var, img); break; case DEST: runtime.setDestinationImage(var, (WritableRenderedImage)img); break; } } return runtime; } /** * Get an image associated with a script variable name. The image must * have been previously suppolied to the builder using the (@code source} * method or one of the {@code dest} methods. *

* In the case of a destination image the object returned can be cast * to {@link WritableRenderedImage}. * * @param varName variable name * * @return the associated image or {@code null} if the variable name is * not recognized or the image has since been garbage collected */ public RenderedImage getImage(String varName) { ImageRef ref = images.get(varName); if (ref != null) { return ref.get(); } return null; } /** * Removes an image associated with a script variable name. The image should * have been previously suppolied to the builder using the (@code source} * method or one of the {@code dest} methods. *

* In the case of a destination image the object returned can be cast * to {@link WritableRenderedImage}. * * @param varName variable name * * @return the associated image or {@code null} if the variable name is * not recognized or the image has since been garbage collected */ public RenderedImage removeImage(String varName) { ImageRef ref = images.remove(varName); if (ref != null) { return ref.get(); } return null; } private String readScriptFile(File scriptFile) throws JiffleException { BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(scriptFile)); StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { line = line.trim(); if (line.length() > 0) { sb.append(line); sb.append('\n'); // put the newline back on for the parser } } return sb.toString(); } catch (IOException ex) { throw new JiffleException("Could not read the script file", ex); } finally { if (reader != null) { try { reader.close(); } catch (IOException ignored) { } } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy