Part of the new Imaging libary: Relies on ImageGenerator for saving images, implements a bunch of new functions.
This commit is contained in:
parent
6fd57e8598
commit
b19370cdbc
1 changed files with 301 additions and 246 deletions
|
@ -14,27 +14,41 @@
|
||||||
* $Date$
|
* $Date$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A few explanations:
|
||||||
|
*
|
||||||
|
* - ImageWrapper.image is either an AWT Image or a BufferedImage.
|
||||||
|
* It depends on the ImageGenerator in what form the Image initially is.
|
||||||
|
* (the ImageIO implementation only uses BufferedImages for example.
|
||||||
|
*
|
||||||
|
* As soon as some action that needs the graphics object is performed and the
|
||||||
|
* image is still in AWT format, it is converted to a BufferedImage
|
||||||
|
*
|
||||||
|
* Any internal function that performs graphical actions needs to call
|
||||||
|
* createGraphics (but only if this.graphics == null)
|
||||||
|
*
|
||||||
|
* - ImageWrapper objects are created and safed by the ImageGenerator class
|
||||||
|
* all different implementations of Imaging functionallity are implemented
|
||||||
|
* as a ImageGenerator extending class.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
package helma.image;
|
package helma.image;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.awt.geom.AffineTransform;
|
||||||
import java.awt.image.*;
|
import java.awt.image.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.rmi.*;
|
|
||||||
import java.rmi.server.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for Image Wrappers.
|
* Abstract base class for Image Wrappers.
|
||||||
*/
|
*/
|
||||||
public abstract class ImageWrapper {
|
public class ImageWrapper {
|
||||||
Image img;
|
protected Image image;
|
||||||
Graphics g;
|
protected int width;
|
||||||
int width;
|
protected int height;
|
||||||
int height;
|
protected Graphics2D graphics;
|
||||||
int fontstyle;
|
protected ImageGenerator generator;
|
||||||
int fontsize;
|
|
||||||
String fontname;
|
|
||||||
ImageGenerator imggen;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new ImageWrapper object.
|
* Creates a new ImageWrapper object.
|
||||||
|
@ -45,30 +59,112 @@ public abstract class ImageWrapper {
|
||||||
* @param height ...
|
* @param height ...
|
||||||
* @param imggen ...
|
* @param imggen ...
|
||||||
*/
|
*/
|
||||||
public ImageWrapper(Image img, Graphics g, int width, int height,
|
public ImageWrapper(Image image, int width, int height,
|
||||||
ImageGenerator imggen) {
|
ImageGenerator generator) {
|
||||||
this.img = img;
|
this.image = image;
|
||||||
this.g = g;
|
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.imggen = imggen;
|
this.generator = generator;
|
||||||
|
// graphics are turned off by default. every graphical function
|
||||||
if (g != null) {
|
// has to assure that graphcis != null, and if not, call createGraphics
|
||||||
Font f = g.getFont();
|
// the function that turns this image into a paintable one!
|
||||||
|
this.graphics = null;
|
||||||
fontname = f.getName();
|
|
||||||
fontstyle = f.getStyle();
|
|
||||||
fontsize = f.getSize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ImageWrapper(Image image, ImageGenerator generator) {
|
||||||
|
this(image, image.getWidth(null), image.getHeight(null), generator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the Graphics object to directly paint to this Image.
|
* Converts the internal image object to a BufferedImage (if it's not
|
||||||
|
* already) and returns it. this is necessary as not all images are of type
|
||||||
|
* BufferedImage. e.g. images loaded from a resource with the Toolkit are
|
||||||
|
* not. By using getBufferedImage, images are only converted to a
|
||||||
|
* getBufferedImage when this is actually needed, which is better than
|
||||||
|
* storing images as BufferedImage in general.
|
||||||
|
*
|
||||||
|
* @return the Image object as a BufferedImage
|
||||||
|
*/
|
||||||
|
public BufferedImage getBufferedImage() {
|
||||||
|
if (!(image instanceof BufferedImage)) {
|
||||||
|
BufferedImage buffered = new BufferedImage(width, height,
|
||||||
|
BufferedImage.TYPE_INT_ARGB);
|
||||||
|
buffered.createGraphics().drawImage(image, 0, 0, null);
|
||||||
|
image = buffered;
|
||||||
|
}
|
||||||
|
return (BufferedImage)image;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert's the internal image to a BufferedImage and creates a graphics object:
|
||||||
|
*/
|
||||||
|
protected void createGraphics() {
|
||||||
|
BufferedImage img = getBufferedImage();
|
||||||
|
graphics = img.createGraphics();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the palette index of the transparent color for Images with an
|
||||||
|
* IndexColorModel. This can be used together with
|
||||||
|
* {@link helma.image.ImageWrapper#getPixel}.
|
||||||
|
*/
|
||||||
|
public void setTransparentPixel(int trans) throws IOException {
|
||||||
|
BufferedImage bi = this.getBufferedImage();
|
||||||
|
ColorModel cm = bi.getColorModel();
|
||||||
|
if (!(cm instanceof IndexColorModel))
|
||||||
|
throw new IOException("Image is not indexed!");
|
||||||
|
IndexColorModel icm = (IndexColorModel) cm;
|
||||||
|
int mapSize = icm.getMapSize();
|
||||||
|
byte reds[] = new byte[mapSize];
|
||||||
|
byte greens[] = new byte[mapSize];
|
||||||
|
byte blues[] = new byte[mapSize];
|
||||||
|
icm.getReds(reds);
|
||||||
|
icm.getGreens(greens);
|
||||||
|
icm.getBlues(blues);
|
||||||
|
// create the new IndexColorModel with the changed transparentPixel:
|
||||||
|
icm = new IndexColorModel(icm.getPixelSize(), mapSize, reds, greens,
|
||||||
|
blues, trans);
|
||||||
|
// create a new BufferedImage with the new IndexColorModel and the old
|
||||||
|
// raster:
|
||||||
|
image = new BufferedImage(icm, bi.getRaster(), false, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the pixel at x, y. If the image is indexed, it returns the
|
||||||
|
* palette index, otherwise the rgb code of the color is returned.
|
||||||
|
*
|
||||||
|
* @param x the x coordinate of the pixel
|
||||||
|
* @param y the y coordinate of the pixel
|
||||||
|
* @return the pixel at x, y
|
||||||
|
*/
|
||||||
|
public int getPixel(int x, int y) {
|
||||||
|
BufferedImage bi = this.getBufferedImage();
|
||||||
|
if (bi.getColorModel() instanceof IndexColorModel)
|
||||||
|
return bi.getRaster().getSample(x, y, 0);
|
||||||
|
else
|
||||||
|
return bi.getRGB(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and returns a copy of this image.
|
||||||
|
*
|
||||||
|
* @return a clone of this image.
|
||||||
|
*/
|
||||||
|
public Object clone() {
|
||||||
|
ImageWrapper wrapper = generator.createImage(this.width,
|
||||||
|
this.height);
|
||||||
|
wrapper.getGraphics().drawImage(image, 0, 0, null);
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Graphics object to directly paint to this Image.
|
||||||
*
|
*
|
||||||
* @return the Graphics object used by this image
|
* @return the Graphics object used by this image
|
||||||
*/
|
*/
|
||||||
public Graphics getGraphics() {
|
public Graphics getGraphics() {
|
||||||
return g;
|
if (graphics == null) createGraphics();
|
||||||
|
return graphics;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -77,17 +173,26 @@ public abstract class ImageWrapper {
|
||||||
* @return the image object
|
* @return the image object
|
||||||
*/
|
*/
|
||||||
public Image getImage() {
|
public Image getImage() {
|
||||||
return img;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ImageProducer of the wrapped image
|
||||||
|
*
|
||||||
|
* @return the images's ImageProducer
|
||||||
|
*/
|
||||||
|
public ImageProducer getSource() {
|
||||||
|
return image.getSource();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispose the Graphics context and null out the image.
|
* Dispose the Graphics context and null out the image.
|
||||||
*/
|
*/
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
if (img != null) {
|
image = null;
|
||||||
g.dispose();
|
if (graphics != null) {
|
||||||
img = null;
|
graphics.dispose();
|
||||||
|
graphics = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,45 +200,56 @@ public abstract class ImageWrapper {
|
||||||
* Set the font used to write on this image.
|
* Set the font used to write on this image.
|
||||||
*/
|
*/
|
||||||
public void setFont(String name, int style, int size) {
|
public void setFont(String name, int style, int size) {
|
||||||
this.fontname = name;
|
if (graphics == null) createGraphics();
|
||||||
this.fontstyle = style;
|
graphics.setFont(new Font(name, style, size));
|
||||||
this.fontsize = size;
|
|
||||||
g.setFont(new Font(name, style, size));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the color used to write/paint to this image.
|
* Sets the color used to write/paint to this image.
|
||||||
*
|
*
|
||||||
* @param red ...
|
* @param red ...
|
||||||
* @param green ...
|
* @param green ...
|
||||||
* @param blue ...
|
* @param blue ...
|
||||||
*/
|
*/
|
||||||
public void setColor(int red, int green, int blue) {
|
public void setColor(int red, int green, int blue) {
|
||||||
g.setColor(new Color(red, green, blue));
|
if (graphics == null) createGraphics();
|
||||||
|
graphics.setColor(new Color(red, green, blue));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the color used to write/paint to this image.
|
* Sets the color used to write/paint to this image.
|
||||||
*
|
*
|
||||||
* @param color ...
|
* @param color ...
|
||||||
*/
|
*/
|
||||||
public void setColor(int color) {
|
public void setColor(int color) {
|
||||||
g.setColor(new Color(color));
|
if (graphics == null) createGraphics();
|
||||||
|
graphics.setColor(new Color(color));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw a string to this image at the given coordinates.
|
* Sets the color used to write/paint to this image.
|
||||||
|
*
|
||||||
|
* @param color ...
|
||||||
|
*/
|
||||||
|
public void setColor(Color color) {
|
||||||
|
if (graphics == null) createGraphics();
|
||||||
|
graphics.setColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws a string to this image at the given coordinates.
|
||||||
*
|
*
|
||||||
* @param str ...
|
* @param str ...
|
||||||
* @param x ...
|
* @param x ...
|
||||||
* @param y ...
|
* @param y ...
|
||||||
*/
|
*/
|
||||||
public void drawString(String str, int x, int y) {
|
public void drawString(String str, int x, int y) {
|
||||||
g.drawString(str, x, y);
|
if (graphics == null) createGraphics();
|
||||||
|
graphics.drawString(str, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw a line to this image from x1/y1 to x2/y2.
|
* Draws a line to this image from x1/y1 to x2/y2.
|
||||||
*
|
*
|
||||||
* @param x1 ...
|
* @param x1 ...
|
||||||
* @param y1 ...
|
* @param y1 ...
|
||||||
|
@ -141,11 +257,12 @@ public abstract class ImageWrapper {
|
||||||
* @param y2 ...
|
* @param y2 ...
|
||||||
*/
|
*/
|
||||||
public void drawLine(int x1, int y1, int x2, int y2) {
|
public void drawLine(int x1, int y1, int x2, int y2) {
|
||||||
g.drawLine(x1, y1, x2, y2);
|
if (graphics == null) createGraphics();
|
||||||
|
graphics.drawLine(x1, y1, x2, y2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw a rectangle to this image.
|
* Draws a rectangle to this image.
|
||||||
*
|
*
|
||||||
* @param x ...
|
* @param x ...
|
||||||
* @param y ...
|
* @param y ...
|
||||||
|
@ -153,27 +270,28 @@ public abstract class ImageWrapper {
|
||||||
* @param h ...
|
* @param h ...
|
||||||
*/
|
*/
|
||||||
public void drawRect(int x, int y, int w, int h) {
|
public void drawRect(int x, int y, int w, int h) {
|
||||||
g.drawRect(x, y, w, h);
|
if (graphics == null) createGraphics();
|
||||||
|
graphics.drawRect(x, y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw another image to this image.
|
* Draws another image to this image.
|
||||||
*
|
*
|
||||||
* @param filename ...
|
* @param filename ...
|
||||||
* @param x ...
|
* @param x ...
|
||||||
* @param y ...
|
* @param y ...
|
||||||
*/
|
*/
|
||||||
public void drawImage(String filename, int x, int y) {
|
public void drawImage(String filename, int x, int y) {
|
||||||
|
if (graphics == null) createGraphics();
|
||||||
try {
|
try {
|
||||||
Image i = imggen.createImage(filename);
|
Image img = generator.read(filename);
|
||||||
|
graphics.drawImage(img, x, y, null);
|
||||||
g.drawImage(i, x, y, null);
|
|
||||||
} catch (Exception ignore) {
|
} catch (Exception ignore) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw a filled rectangle to this image.
|
* Draws a filled rectangle to this image.
|
||||||
*
|
*
|
||||||
* @param x ...
|
* @param x ...
|
||||||
* @param y ...
|
* @param y ...
|
||||||
|
@ -181,29 +299,30 @@ public abstract class ImageWrapper {
|
||||||
* @param h ...
|
* @param h ...
|
||||||
*/
|
*/
|
||||||
public void fillRect(int x, int y, int w, int h) {
|
public void fillRect(int x, int y, int w, int h) {
|
||||||
g.fillRect(x, y, w, h);
|
if (graphics == null) createGraphics();
|
||||||
|
graphics.fillRect(x, y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the width of this image.
|
* Returns the width of this image.
|
||||||
*
|
*
|
||||||
* @return ...
|
* @return the width of this image
|
||||||
*/
|
*/
|
||||||
public int getWidth() {
|
public int getWidth() {
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the height of this image.
|
* Returns the height of this image.
|
||||||
*
|
*
|
||||||
* @return ...
|
* @return the height of this image
|
||||||
*/
|
*/
|
||||||
public int getHeight() {
|
public int getHeight() {
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* crop this image.
|
* Crops the image.
|
||||||
*
|
*
|
||||||
* @param x ...
|
* @param x ...
|
||||||
* @param y ...
|
* @param y ...
|
||||||
|
@ -211,214 +330,150 @@ public abstract class ImageWrapper {
|
||||||
* @param h ...
|
* @param h ...
|
||||||
*/
|
*/
|
||||||
public void crop(int x, int y, int w, int h) {
|
public void crop(int x, int y, int w, int h) {
|
||||||
ImageFilter filter = new CropImageFilter(x, y, w, h);
|
if (image instanceof BufferedImage) {
|
||||||
|
image = ((BufferedImage)image).getSubimage(x, y, w, h);
|
||||||
img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(img.getSource(),
|
} else {
|
||||||
filter));
|
BufferedImage buffered = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
Graphics2D g2d = buffered.createGraphics();
|
||||||
|
g2d.drawImage(image, -x, -y, null);
|
||||||
|
g2d.dispose();
|
||||||
|
image = buffered;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* resize this image
|
* resizes the image using the Graphics2D approach
|
||||||
|
*/
|
||||||
|
protected BufferedImage resize(int w, int h, boolean smooth) {
|
||||||
|
BufferedImage buffered = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
Graphics2D g2d = buffered.createGraphics();
|
||||||
|
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
||||||
|
smooth ? RenderingHints.VALUE_INTERPOLATION_BICUBIC :
|
||||||
|
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR
|
||||||
|
);
|
||||||
|
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
|
||||||
|
smooth ? RenderingHints.VALUE_RENDER_QUALITY :
|
||||||
|
RenderingHints.VALUE_RENDER_SPEED
|
||||||
|
);
|
||||||
|
|
||||||
|
AffineTransform at = AffineTransform.getScaleInstance(
|
||||||
|
(double) w / width,
|
||||||
|
(double) h / height
|
||||||
|
);
|
||||||
|
g2d.drawImage(image, at, null);
|
||||||
|
g2d.dispose();
|
||||||
|
return buffered;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize the image
|
||||||
*
|
*
|
||||||
* @param w ...
|
* @param w ...
|
||||||
* @param h ...
|
* @param h ...
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void resize(int w, int h) {
|
public void resize(int w, int h) {
|
||||||
img = img.getScaledInstance(w, h, Image.SCALE_SMOOTH);
|
double factor = Math.max(
|
||||||
|
(double) w / width,
|
||||||
|
(double) h / height
|
||||||
|
);
|
||||||
|
// if the image is scaled, used the Graphcis2D method, otherwise use AWT:
|
||||||
|
if (factor > 1f)
|
||||||
|
image = resize(w, h, true);
|
||||||
|
else {
|
||||||
|
// Area averaging has the best results for shrinking of images:
|
||||||
|
/*
|
||||||
|
// as getScaledInstance is asynchronous, the ImageWaiter is needed here too:
|
||||||
|
Image scaled = ImageWaiter.waitForImage(image.getScaledInstance(w, h, Image.SCALE_AREA_AVERAGING));
|
||||||
|
if (scaled == null)
|
||||||
|
throw new RuntimeException("Image cannot be resized.");
|
||||||
|
*/
|
||||||
|
image = new ImageFilterOp(new AreaAveragingScaleFilter(w, h)).filter(getBufferedImage(), null);
|
||||||
|
}
|
||||||
width = w;
|
width = w;
|
||||||
height = h;
|
height = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* resize this image, using a fast and cheap algorithm
|
* Resize the image, using a fast and cheap algorithm
|
||||||
*
|
*
|
||||||
* @param w ...
|
* @param w ...
|
||||||
* @param h ...
|
* @param h ...
|
||||||
*/
|
*/
|
||||||
public void resizeFast(int w, int h) {
|
public void resizeFast(int w, int h) {
|
||||||
img = img.getScaledInstance(w, h, Image.SCALE_FAST);
|
image = resize(w, h, false);
|
||||||
width = w;
|
width = w;
|
||||||
height = h;
|
height = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* reduce the colors used in this image. Necessary before saving as GIF.
|
* Reduces the colors used in the image. Necessary before saving as GIF.
|
||||||
*
|
*
|
||||||
* @param colors ...
|
* @param colors colors the number of colors to use, usually <= 256.
|
||||||
*/
|
*/
|
||||||
public abstract void reduceColors(int colors);
|
public void reduceColors(int colors) {
|
||||||
|
reduceColors(colors, false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save this image. Image format is deduced from filename.
|
* Reduces the colors used in the image. Necessary before saving as GIF.
|
||||||
|
*
|
||||||
|
* @param colors colors the number of colors to use, usually <= 256.
|
||||||
|
* @param dither ...
|
||||||
|
*/
|
||||||
|
public void reduceColors(int colors, boolean dither) {
|
||||||
|
reduceColors(colors, dither, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduce the colors used in this image. Useful and necessary before saving
|
||||||
|
* the image as GIF file.
|
||||||
|
*
|
||||||
|
* @param colors the number of colors to use, usually <= 256.
|
||||||
|
* @param dither ...
|
||||||
|
* @param alphaToBitmask ...
|
||||||
|
*/
|
||||||
|
|
||||||
|
public void reduceColors(int colors, boolean dither, boolean alphaToBitmask) {
|
||||||
|
image = Quantize.process(getBufferedImage(), colors, dither,
|
||||||
|
alphaToBitmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the image. Image format is deduced from filename.
|
||||||
*
|
*
|
||||||
* @param filename ...
|
* @param filename ...
|
||||||
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public abstract void saveAs(String filename);
|
public void saveAs(String filename)
|
||||||
|
throws IOException {
|
||||||
/**
|
saveAs(filename, -1f, false); // -1 means default quality
|
||||||
* Get ImageProducer of the wrapped image
|
|
||||||
*/
|
|
||||||
public ImageProducer getSource() {
|
|
||||||
return img.getSource();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw a string to this image, breaking lines when necessary.
|
* Saves the image. Image format is deduced from filename.
|
||||||
*
|
*
|
||||||
* @param str ...
|
* @param filename ...
|
||||||
|
* @param quality ...
|
||||||
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public void fillString(String str) {
|
public void saveAs(String filename, float quality)
|
||||||
Filler filler = new Filler(0, 0, width, height);
|
throws IOException {
|
||||||
|
saveAs(filename, quality, false);
|
||||||
filler.layout(str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw a line to a rectangular section of this image, breaking lines when necessary.
|
* Saves the image. Image format is deduced from filename.
|
||||||
*
|
*
|
||||||
* @param str ...
|
* @param filename ...
|
||||||
* @param x ...
|
* @param quality ...
|
||||||
* @param y ...
|
* @param alpha ...
|
||||||
* @param w ...
|
* @throws IOException
|
||||||
* @param h ...
|
|
||||||
*/
|
*/
|
||||||
public void fillString(String str, int x, int y, int w, int h) {
|
public void saveAs(String filename, float quality, boolean alpha)
|
||||||
Filler filler = new Filler(x, y, w, h);
|
throws IOException {
|
||||||
|
generator.write(this, filename, quality, alpha);
|
||||||
filler.layout(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
class Filler {
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
int w;
|
|
||||||
int h;
|
|
||||||
int addedSpace = 0;
|
|
||||||
int xLeft;
|
|
||||||
int yLeft;
|
|
||||||
int realHeight;
|
|
||||||
transient Vector lines;
|
|
||||||
|
|
||||||
public Filler(int x, int y, int w, int h) {
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.w = w;
|
|
||||||
this.h = h;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void layout(String str) {
|
|
||||||
int size = fontsize;
|
|
||||||
|
|
||||||
lines = new Vector();
|
|
||||||
|
|
||||||
while (!splitMessage(str, size) && (size > 10)) {
|
|
||||||
lines.setSize(0);
|
|
||||||
size = Math.max(2, size - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Font oldfont = g.getFont();
|
|
||||||
|
|
||||||
g.setFont(new Font(fontname, fontstyle, size));
|
|
||||||
|
|
||||||
int l = lines.size();
|
|
||||||
|
|
||||||
for (int i = 0; i < l; i++) {
|
|
||||||
((Line) lines.elementAt(i)).paint(g, xLeft / 2, (yLeft / 2) + y);
|
|
||||||
}
|
|
||||||
|
|
||||||
g.setFont(oldfont);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean splitMessage(String string, int size) {
|
|
||||||
Font font = new Font(fontname, fontstyle, size);
|
|
||||||
FontMetrics metrics = Toolkit.getDefaultToolkit().getFontMetrics(font);
|
|
||||||
int longestLine = 0;
|
|
||||||
int heightSoFar = 0;
|
|
||||||
int heightIncrement = (int) (0.84f * metrics.getHeight());
|
|
||||||
StringTokenizer tk = new StringTokenizer(string);
|
|
||||||
StringBuffer buffer = new StringBuffer();
|
|
||||||
int spaceWidth = metrics.stringWidth(" ");
|
|
||||||
int currentWidth = 0;
|
|
||||||
int maxWidth = w - 2;
|
|
||||||
int maxHeight = (h + addedSpace) - 2;
|
|
||||||
|
|
||||||
while (tk.hasMoreTokens()) {
|
|
||||||
String nextToken = tk.nextToken();
|
|
||||||
int nextWidth = metrics.stringWidth(nextToken);
|
|
||||||
|
|
||||||
if ((((currentWidth + nextWidth) >= maxWidth) && (currentWidth != 0))) {
|
|
||||||
Line line = new Line(buffer.toString(), x, heightSoFar, metrics);
|
|
||||||
|
|
||||||
lines.addElement(line);
|
|
||||||
|
|
||||||
if (line.textwidth > longestLine) {
|
|
||||||
longestLine = line.textwidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer = new StringBuffer();
|
|
||||||
|
|
||||||
currentWidth = 0;
|
|
||||||
heightSoFar += heightIncrement;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.append(nextToken);
|
|
||||||
buffer.append(" ");
|
|
||||||
currentWidth += (nextWidth + spaceWidth);
|
|
||||||
|
|
||||||
if (((1.18 * heightSoFar) > maxHeight) && (fontsize > 10)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!"".equals(buffer.toString().trim())) {
|
|
||||||
Line line = new Line(buffer.toString(), x, heightSoFar, metrics);
|
|
||||||
|
|
||||||
lines.addElement(line);
|
|
||||||
|
|
||||||
if (line.textwidth > longestLine) {
|
|
||||||
longestLine = line.textwidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((longestLine > maxWidth) && (fontsize > 10)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
heightSoFar += heightIncrement;
|
|
||||||
}
|
|
||||||
|
|
||||||
xLeft = w - longestLine;
|
|
||||||
yLeft = (addedSpace + h) - heightSoFar;
|
|
||||||
realHeight = heightSoFar;
|
|
||||||
|
|
||||||
return ((1.18 * heightSoFar) <= maxHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Line implements Serializable {
|
|
||||||
String text;
|
|
||||||
int xoff;
|
|
||||||
int yoff;
|
|
||||||
FontMetrics fm;
|
|
||||||
public int textwidth;
|
|
||||||
public int len;
|
|
||||||
int ascent;
|
|
||||||
|
|
||||||
public Line(String text, int xoff, int yoff, FontMetrics fm) {
|
|
||||||
this.text = text.trim();
|
|
||||||
len = text.length();
|
|
||||||
this.xoff = xoff;
|
|
||||||
this.yoff = yoff;
|
|
||||||
this.fm = fm;
|
|
||||||
textwidth = (len == 0) ? 0 : fm.stringWidth(this.text);
|
|
||||||
ascent = (int) (0.9f * fm.getAscent());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void paint(Graphics g, int xadd, int yadd) {
|
|
||||||
g.drawString(text, xoff + xadd, yoff + ascent + yadd);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean contains(int y) {
|
|
||||||
return (y < (yoff + fm.getHeight())) ? true : false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue