Bugfix to avoid an invalid Graphics2D object after changes to the internal image (crop, scale, reduceColors, ...).
This commit is contained in:
parent
c444ada032
commit
1138a509ec
1 changed files with 72 additions and 13 deletions
|
@ -86,7 +86,7 @@ public class ImageWrapper {
|
||||||
BufferedImage buffered = new BufferedImage(width, height,
|
BufferedImage buffered = new BufferedImage(width, height,
|
||||||
BufferedImage.TYPE_INT_ARGB);
|
BufferedImage.TYPE_INT_ARGB);
|
||||||
buffered.createGraphics().drawImage(image, 0, 0, null);
|
buffered.createGraphics().drawImage(image, 0, 0, null);
|
||||||
image = buffered;
|
setImage(buffered);
|
||||||
}
|
}
|
||||||
return (BufferedImage)image;
|
return (BufferedImage)image;
|
||||||
}
|
}
|
||||||
|
@ -105,6 +105,16 @@ public class ImageWrapper {
|
||||||
}
|
}
|
||||||
return graphics;
|
return graphics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the internal image and clears the stored graphics object.
|
||||||
|
* Any code that is changing the internal image should do it through this function
|
||||||
|
* to make sure getGraphcis() returns a valid graphics object the next time it is called.
|
||||||
|
*/
|
||||||
|
protected void setImage(Image image) {
|
||||||
|
this.image = image;
|
||||||
|
graphics = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and returns a copy of this image.
|
* Creates and returns a copy of this image.
|
||||||
|
@ -183,6 +193,14 @@ public class ImageWrapper {
|
||||||
getGraphics().setColor(color);
|
getGraphics().setColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the color used to write/paint to this image.
|
||||||
|
*
|
||||||
|
* @param color ...
|
||||||
|
*/
|
||||||
|
public void setColor(String color) {
|
||||||
|
getGraphics().setColor(Color.decode(color));
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Draws a string to this image at the given coordinates.
|
* Draws a string to this image at the given coordinates.
|
||||||
*
|
*
|
||||||
|
@ -286,7 +304,7 @@ public class ImageWrapper {
|
||||||
// do not use the CropFilter any longer:
|
// do not use the CropFilter any longer:
|
||||||
if (image instanceof BufferedImage) {
|
if (image instanceof BufferedImage) {
|
||||||
// BufferedImages define their own function for cropping:
|
// BufferedImages define their own function for cropping:
|
||||||
image = ((BufferedImage)image).getSubimage(x, y, w, h);
|
setImage(((BufferedImage)image).getSubimage(x, y, w, h));
|
||||||
} else {
|
} else {
|
||||||
// The internal image will be a BufferedImage after this.
|
// The internal image will be a BufferedImage after this.
|
||||||
// Simply create it with the cropped dimensions and draw the image into it:
|
// Simply create it with the cropped dimensions and draw the image into it:
|
||||||
|
@ -294,7 +312,7 @@ public class ImageWrapper {
|
||||||
Graphics2D g2d = buffered.createGraphics();
|
Graphics2D g2d = buffered.createGraphics();
|
||||||
g2d.drawImage(image, -x, -y, null);
|
g2d.drawImage(image, -x, -y, null);
|
||||||
g2d.dispose();
|
g2d.dispose();
|
||||||
image = buffered;
|
setImage(buffered);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,16 +357,18 @@ public class ImageWrapper {
|
||||||
// if the image is scaled, used the Graphcis2D method, otherwise use AWT:
|
// if the image is scaled, used the Graphcis2D method, otherwise use AWT:
|
||||||
if (factor > 1f) {
|
if (factor > 1f) {
|
||||||
// scalie it with the Graphics2D approach for supperiour quality.
|
// scalie it with the Graphics2D approach for supperiour quality.
|
||||||
image = resize(w, h, true);
|
setImage(resize(w, h, true));
|
||||||
} else {
|
} else {
|
||||||
// Area averaging has the best results for shrinking of images:
|
// Area averaging has the best results for shrinking of images:
|
||||||
/*
|
|
||||||
// as getScaledInstance is asynchronous, the ImageWaiter is needed here too:
|
// as getScaledInstance is asynchronous, the ImageWaiter is needed here too:
|
||||||
Image scaled = ImageWaiter.waitForImage(image.getScaledInstance(w, h, Image.SCALE_AREA_AVERAGING));
|
// Image scaled = ImageWaiter.waitForImage(image.getScaledInstance(w, h, Image.SCALE_AREA_AVERAGING));
|
||||||
if (scaled == null)
|
// if (scaled == null)
|
||||||
throw new RuntimeException("Image cannot be resized.");
|
// throw new RuntimeException("Image cannot be resized.");
|
||||||
*/
|
|
||||||
image = new ImageFilterOp(new AreaAveragingScaleFilter(w, h)).filter(getBufferedImage(), null);
|
// this version is up to 4 times faster than getScaledInstance:
|
||||||
|
ImageFilterOp filter = new ImageFilterOp(new AreaAveragingScaleFilter(w, h));
|
||||||
|
setImage(filter.filter(getBufferedImage(), null));
|
||||||
}
|
}
|
||||||
width = w;
|
width = w;
|
||||||
height = h;
|
height = h;
|
||||||
|
@ -395,8 +415,8 @@ public class ImageWrapper {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void reduceColors(int colors, boolean dither, boolean alphaToBitmask) {
|
public void reduceColors(int colors, boolean dither, boolean alphaToBitmask) {
|
||||||
image = Quantize.process(getBufferedImage(), colors, dither,
|
setImage(Quantize.process(getBufferedImage(), colors, dither,
|
||||||
alphaToBitmask);
|
alphaToBitmask));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -435,6 +455,45 @@ public class ImageWrapper {
|
||||||
generator.write(this, filename, quality, alpha);
|
generator.write(this, filename, quality, alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the image. Image format is deduced from mimeType.
|
||||||
|
*
|
||||||
|
* @param out ...
|
||||||
|
* @param mimeType ...
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void saveAs(OutputStream out, String mimeType)
|
||||||
|
throws IOException {
|
||||||
|
generator.write(this, out, mimeType, -1f, false); // -1 means default quality
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the image. Image format is deduced from mimeType.
|
||||||
|
*
|
||||||
|
* @param out ...
|
||||||
|
* @param mimeType ...
|
||||||
|
* @param quality ...
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void saveAs(OutputStream out, String mimeType, float quality)
|
||||||
|
throws IOException {
|
||||||
|
generator.write(this, out, mimeType, quality, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the image. Image format is deduced from mimeType.
|
||||||
|
*
|
||||||
|
* @param out ...
|
||||||
|
* @param mimeType ...
|
||||||
|
* @param quality ...
|
||||||
|
* @param alpha ...
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void saveAs(OutputStream out, String mimeType, float quality, boolean alpha)
|
||||||
|
throws IOException {
|
||||||
|
generator.write(this, out, mimeType, quality, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the palette index of the transparent color for Images with an
|
* Sets the palette index of the transparent color for Images with an
|
||||||
* IndexColorModel. This can be used together with
|
* IndexColorModel. This can be used together with
|
||||||
|
@ -458,7 +517,7 @@ public class ImageWrapper {
|
||||||
blues, trans);
|
blues, trans);
|
||||||
// create a new BufferedImage with the new IndexColorModel and the old
|
// create a new BufferedImage with the new IndexColorModel and the old
|
||||||
// raster:
|
// raster:
|
||||||
image = new BufferedImage(icm, bi.getRaster(), false, null);
|
setImage(new BufferedImage(icm, bi.getRaster(), false, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Reference in a new issue