ImageMaker Image Processing (Java Sample)

ImageMaker uses the Java Advanced Imaging API, which was still in alpha/early beta when I started using it. The documentation had not been updated from the previous version at that time, so I found myself hacking my way through the API trying to make things works. Since it was still not finalized, I wrote a wrapper class around the functions I needed so that I could easily swap code in and out. It's also just a good design policy.


package com.robzazueta.imagemaker;

import java.awt.image.BufferedImage;
import java.awt.image.AffineTransformOp;
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.Font;
import java.awt.FontMetrics;
import javax.media.jai.PlanarImage;
import javax.media.jai.JAI;
import javax.media.jai.InterpolationNearest;
import javax.media.jai.ParameterBlockJAI;
import javax.media.jai.TiledImage;
import com.sun.media.jai.codec.*;

/**
 *ImageHandler
 *
 *Abstracts the actions needed to open, process and save images. Since the Java Advanced Imaging and
 *Java 2D APIs are frustratingly in flux, this is a pretty basic go-between that performs ulta-simple imaging 
 *processes on given images, like a PhotoShop Super LE API
 */

public class ImageHandler {
    public static final int OVERLAY_TOP_LEFT = 1 << 1;
    public static final int OVERLAY_TOP_RIGHT = 1 << 2;
    public static final int OVERLAY_CENTER = 1 << 3;
    public static final int OVERLAY_BOTTOM_LEFT = 1 << 4;
    public static final int OVERLAY_BOTTOM_RIGHT = 1 << 5;
    
    PlanarImage img;
    
    public ImageHandler() {
        
    }
    
    /**
     *@param amount The amount to scale by (i.e. 2.0F means "twice as big")
     *
     *Scales the image by the given amount
     */
    public void scale(float amount) {
        ParameterBlockJAI pb = new ParameterBlockJAI("scale");
        pb.addSource(this.img);
        pb.setParameter("xScale", amount); //x Scale Factor
        pb.setParameter("yScale", amount); //y Scale Factor
        pb.setParameter("xTrans", 0.0F);      //x Translate amount
        pb.setParameter("yTrans", 0.0F);      //y Translate amount
        pb.setParameter("interpolation", new InterpolationNearest());
        this.img = JAI.create("scale", pb, null);
    }
        
    
    /**
     *@param width The width this image should be scaled to as a max
     *
     *Scales the image uniformly by calculating the scale value generated by using the width as a maximum width
     */
    public void scaleX(float width) {
        float scaleFactor;
        scaleFactor = width / (float)img.getWidth();
        scale(scaleFactor);
    }
    
    /**
     *@param height The height this image should be scaled to as a max
     *
     *Scales the image uniformly by calculating the scale value generated by using the height as a maximum height.
     */
    public void scaleY(float height) {
        float scaleFactor;
        scaleFactor = height / (float)img.getHeight();
        scale(scaleFactor);
    }
    
    /**
     *Resizes the image to fit inside the width and height given. Not guaranteed to be the exact dimensions
     *given, just fit within them.
     *@param width The maximum width to fit
     *@param height The maximum height to fit
     */
    public void scaleToFit(int width, int height) {
        if(img.getWidth() > img.getHeight()) {
            scaleX((float)width);
        } else {
            scaleY((float)height);
        }
    }
    
    /**
     *Loads the image from a path and filename
     *
     *@param filepath The oath and filename where the file can be found
     */
    public void loadImage(String filepath) {
        //Loads the image from the given path and filename
        this.img = (PlanarImage)JAI.create("fileload", filepath);
    }
    
    /**
     *Saves the image to the given path and filename
     *
     *@param filepath the path and filename to save the image to.
     */
    public void saveImage(String filepath) {
        //Saves the image to the given path and filename as a JPEG image
        saveImage(filepath, "JPEG");
    }
    
    /**
     *Saves the image to the given path and filename using the given codec
     *
     *@param filepath the path and filename to save the image to.
     *@param type The JAI-defined codec type to save as.
     */
    public void saveImage(String filepath, String type) {
        //Saves the image to the given path and filename
        JAI.create("filestore", img, filepath, type, null);
    }
    
    /**
     *@param radians the amount to rotate by in radians
     *
     *Rotates the image by the given amount. Use degreesToRadians to convert degrees.
     */
    public void rotate(float radians) {
        
    }
    
    /**
     *@param degrees the angle to convert
     *
     *Converts degrees into radians.
     */
    public static float degreesToRadians(float degrees) {
        return (float)((degrees*Math.PI)/180.0F);
    }
    
    /**
     *Overlays the image specified by filepath on the current image.
     *
     *@param filepath The path and file to the image to use as the overlay
     *@param alpha the amount of transparency to apply to the overlay
     */
    public void overlay(String filepath, float alpha, int align) {
        BufferedImage bi = ((PlanarImage)JAI.create("fileload", filepath)).getAsBufferedImage();
        overlay(bi, alpha, align);
    }
    
    /**
     *Overlays the image specified by filepath on the current image.
     *
     *@param bi The image to overlay on the current image.
     *@param alpha The amount of transparency to apply to the overlay.
     */ 
    public void overlay(BufferedImage bi, float alpha, int align) {
        AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
        int overX, overY;
        /*
        //The following will resize the overlay image before applying it.
        //CURRENTLY NOT WORKING
        if(bi.getWidth() > this.img.getWidth()) {
            bi = (BufferedImage)bi.getScaledInstance(this.img.getWidth(), (int)((float)bi.getHeight()*((float)this.img.getWidth()/(float)bi.getWidth())), java.awt.Image.SCALE_DEFAULT);
        }
        if(bi.getHeight() > this.img.getHeight()) {
            bi = (BufferedImage)bi.getScaledInstance((int)((float)bi.getWidth()*((float)this.img.getHeight()/(float)bi.getHeight())), this.img.getHeight(), java.awt.Image.SCALE_DEFAULT);
        }*/
        if(align == OVERLAY_BOTTOM_RIGHT){
            overX = this.img.getMaxX() - bi.getWidth();
            overY = this.img.getMaxY() - bi.getHeight();
        } else if(align == OVERLAY_BOTTOM_LEFT) {
            overX = 0;
            overY = this.img.getMaxY() - bi.getHeight();
        } else if(align == OVERLAY_TOP_RIGHT) {
            overX = this.img.getMaxX() - bi.getWidth();
            overY = 0;
        } else if(align == OVERLAY_CENTER) {
            overX = this.img.getWidth()/2 - bi.getWidth()/2;
            overY = this.img.getHeight()/2 - bi.getHeight()/2; 
        } else {
            overX = 0;
            overY = 0;
        }
            
        TiledImage ti = new TiledImage(this.img, false);
        Graphics2D g2 = ti.createGraphics();
        g2.setComposite(ac);
        g2.drawImage(bi, overX, overY, null);
        this.img = ti;
    }
    
    public void overlayText(String text, float alpha, int align, Font f, java.awt.Color col) {
        TiledImage ti = new TiledImage(this.img, false);
        Graphics2D g2 = ti.createGraphics();
        AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
        
        int overX, overY;
        java.awt.font.FontRenderContext frc = g2.getFontRenderContext();
        java.awt.font.TextLayout layout = new java.awt.font.TextLayout(text, f, frc);
        java.awt.geom.Rectangle2D rect = layout.getBounds();
        
        if(align == OVERLAY_BOTTOM_RIGHT){
            overX = this.img.getMaxX() - (int)rect.getWidth();
            overY = this.img.getMaxY() - (int)rect.getHeight();
        } else if(align == OVERLAY_BOTTOM_LEFT) {
            overX = 0;
            overY = this.img.getMaxY() - (int)rect.getHeight();
        } else if(align == OVERLAY_TOP_RIGHT) {
            overX = this.img.getMaxX() - (int)rect.getWidth();
            overY = 0;
        } else if(align == OVERLAY_CENTER) {
            overX = this.img.getWidth()/2 - (int)rect.getWidth()/2;
            overY = this.img.getHeight()/2 - (int)rect.getHeight()/2; 
        } else {
            overX = 0;
            overY = 0;
        }
        g2.setComposite(ac);
        g2.setFont(f);
        g2.setColor(col);
        g2.drawString(text, overX, overY);
        this.img = ti;
    }
    
    public BufferedImage getCurrentImage() {
        return img.getAsBufferedImage();
    }
    
    public static void main(String[] args) {
        if(args.length < 2) {
            System.out.println("Usage: java com.robzazueta.imagemaker.ImageHandler [inputfilename] [outputfilename]");
            System.exit(0);
        }
        
        ImageHandler ih = new ImageHandler();
        ih.loadImage(args[0]);
        ih.scale(2.0F);
        ih.saveImage(args[1]);
        System.out.println("Done!\n");
    }
    
}



Home · Photography · Brew Blog · Resume · Contact me
 
Creative Commons License
Unless otherwise noted, all content on this site is Copyright © 2004 by Rob Zazueta and licensed under a Creative Commons License.