|
|
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");
}
}