- #0000743: OutOfMemoryError caused by image ResampleOp in FImagePanel. (http://www.cardforge.org/bugz/view.php?id=743)

This commit is contained in:
spr
2013-09-25 10:15:05 +00:00
parent 12fd77953f
commit d38898b1dd

View File

@@ -41,7 +41,7 @@ import com.mortennobel.imagescaling.ResampleOp;
* <p> * <p>
* Options to scale and rotate the image are available if required. * Options to scale and rotate the image are available if required.
* *
* @version $Id:$ * @version $Id$
* *
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
@@ -55,6 +55,11 @@ public class FImagePanel extends JPanel {
// Remains the same regardless of any transformations that might be applied to it. // Remains the same regardless of any transformations that might be applied to it.
private BufferedImage sourceImage = null; private BufferedImage sourceImage = null;
// Resampling is an expensive operation so keep a copy of last resampled image and
// use this for repaints if image has not been resized or changed.
private BufferedImage scaledImage = null;
private boolean isResampleEnabled = true;
private double imageScale = 1; private double imageScale = 1;
private int degreesOfRotation = 0; private int degreesOfRotation = 0;
@@ -69,12 +74,6 @@ public class FImagePanel extends JPanel {
setResizeListener(); setResizeListener();
}; };
public void clearImage() {
this.sourceImage = null;
this.imageScale = 1;
repaint();
}
/** /**
* This timer is used to identify when resizing has finished. * This timer is used to identify when resizing has finished.
* <p> * <p>
@@ -95,6 +94,7 @@ public class FImagePanel extends JPanel {
private void doResizedFinished() { private void doResizedFinished() {
this.resizingTimer.stop(); this.resizingTimer.stop();
this.isResizing = false; this.isResizing = false;
this.isResampleEnabled = true;
this.repaint(); this.repaint();
} }
@@ -118,11 +118,11 @@ public class FImagePanel extends JPanel {
* This means the image can only have either a vertical or horizontal orientation. * This means the image can only have either a vertical or horizontal orientation.
*/ */
public void setImage(BufferedImage image, int initialRotation, AutoSizeImageMode autoSizeMode) { public void setImage(BufferedImage image, int initialRotation, AutoSizeImageMode autoSizeMode) {
if (this.sourceImage != image) { if (this.sourceImage != image || this.degreesOfRotation != initialRotation || this.autoSizeMode != autoSizeMode) {
isResampleEnabled = true;
this.autoSizeMode = autoSizeMode; this.autoSizeMode = autoSizeMode;
if (initialRotation > 0) { setRotation(initialRotation); } if (initialRotation > 0) { setRotation(initialRotation); }
this.sourceImage = image; this.sourceImage = image;
setImageScale();
repaint(); repaint();
} }
} }
@@ -165,10 +165,12 @@ public class FImagePanel extends JPanel {
* This means the image can only have either a vertical or horizontal orientation. * This means the image can only have either a vertical or horizontal orientation.
*/ */
public void setRotation(int degrees) { public void setRotation(int degrees) {
if (this.degreesOfRotation != degrees) {
this.degreesOfRotation = ImageUtil.getRotationToNearest(degrees, 90); this.degreesOfRotation = ImageUtil.getRotationToNearest(degrees, 90);
setImageScale(); isResampleEnabled = true;
repaint(); repaint();
} }
}
/** /**
* Gets the rotation of the displayed image relative to the original image. * Gets the rotation of the displayed image relative to the original image.
@@ -217,19 +219,26 @@ public class FImagePanel extends JPanel {
/** /**
* Uses Morten Nobel's java-image-scaling library to resize image. * Uses Morten Nobel's java-image-scaling library to resize image.
* <p> * <p>
* This produces superior quality to affine scaling as image sizes * This produces superior quality to affine scaling especially as
* are reduced but at the cost of performance. * image sizes are reduced but at the cost of performance.
* <p>
* You cannot legislate for when this will be called since it depends
* on how often paintComponent() is invoked and any number of external
* events can cause this to happen. But resampling is an expensive operation
* so use an existing copy if the image has not changed or been resized.
*/ */
private BufferedImage getResampledImage() { private BufferedImage getResampledImage() {
BufferedImage scaledImage = null;
if (this.imageScale != 1) { if (this.imageScale != 1) {
if (isResampleEnabled) {
isResampleEnabled = false;
DimensionConstrain constrain = DimensionConstrain.createRelativeDimension((float)this.imageScale); DimensionConstrain constrain = DimensionConstrain.createRelativeDimension((float)this.imageScale);
ResampleOp resampler = new ResampleOp(constrain); ResampleOp resampler = new ResampleOp(constrain);
scaledImage = resampler.filter(sourceImage, null); this.scaledImage = resampler.filter(sourceImage, null);
} else {
scaledImage = sourceImage;
} }
return scaledImage; } else {
this.scaledImage = sourceImage;
}
return this.scaledImage;
} }
/** /**
@@ -319,13 +328,17 @@ public class FImagePanel extends JPanel {
private void setImageScale() { private void setImageScale() {
if (this.sourceImage != null) { if (this.sourceImage != null) {
if (this.autoSizeMode != AutoSizeImageMode.OFF) { if (this.autoSizeMode != AutoSizeImageMode.OFF) {
this.imageScale = ImageUtil.getBestFitScale(getSourceImageSize(), this.getSize()); Double newScale = ImageUtil.getBestFitScale(getSourceImageSize(), this.getSize());
if (this.imageScale == 0) { this.imageScale = 1; }; if (newScale != this.imageScale) {
if (this.autoSizeMode == AutoSizeImageMode.SOURCE && this.imageScale > 1) { isResampleEnabled = true;
this.imageScale = newScale;
if (newScale == 0) { this.imageScale = 1; };
if (this.autoSizeMode == AutoSizeImageMode.SOURCE && newScale > 1) {
this.imageScale = 1; this.imageScale = 1;
} }
} }
} }
} }
}
} }