mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-10-04 11:26:44 -04:00
New code style. No functional changes.
This commit is contained in:
@@ -41,21 +41,24 @@ import java.util.ArrayList;
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/AbstractImageSource.java#1 $
|
||||
*/
|
||||
public abstract class AbstractImageSource implements ImageProducer {
|
||||
private List<ImageConsumer> mConsumers = new ArrayList<ImageConsumer>();
|
||||
protected int mWidth;
|
||||
protected int mHeight;
|
||||
protected int mXOff;
|
||||
protected int mYOff;
|
||||
private List<ImageConsumer> consumers = new ArrayList<ImageConsumer>();
|
||||
protected int width;
|
||||
protected int height;
|
||||
protected int xOff;
|
||||
protected int yOff;
|
||||
|
||||
// ImageProducer interface
|
||||
public void addConsumer(ImageConsumer pConsumer) {
|
||||
if (mConsumers.contains(pConsumer)) {
|
||||
public void addConsumer(final ImageConsumer pConsumer) {
|
||||
if (consumers.contains(pConsumer)) {
|
||||
return;
|
||||
}
|
||||
mConsumers.add(pConsumer);
|
||||
|
||||
consumers.add(pConsumer);
|
||||
|
||||
try {
|
||||
initConsumer(pConsumer);
|
||||
sendPixels(pConsumer);
|
||||
|
||||
if (isConsumer(pConsumer)) {
|
||||
pConsumer.imageComplete(ImageConsumer.STATICIMAGEDONE);
|
||||
|
||||
@@ -68,34 +71,35 @@ public abstract class AbstractImageSource implements ImageProducer {
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
if (isConsumer(pConsumer)) {
|
||||
pConsumer.imageComplete(ImageConsumer.IMAGEERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeConsumer(ImageConsumer pConsumer) {
|
||||
mConsumers.remove(pConsumer);
|
||||
public void removeConsumer(final ImageConsumer pConsumer) {
|
||||
consumers.remove(pConsumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation silently ignores this instruction. If pixeldata is
|
||||
* This implementation silently ignores this instruction. If pixel data is
|
||||
* not in TDLR order by default, subclasses must override this method.
|
||||
*
|
||||
* @param pConsumer the consumer that requested the resend
|
||||
*
|
||||
* @see ImageProducer#requestTopDownLeftRightResend(java.awt.image.ImageConsumer)
|
||||
*/
|
||||
public void requestTopDownLeftRightResend(ImageConsumer pConsumer) {
|
||||
public void requestTopDownLeftRightResend(final ImageConsumer pConsumer) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
public void startProduction(ImageConsumer pConsumer) {
|
||||
public void startProduction(final ImageConsumer pConsumer) {
|
||||
addConsumer(pConsumer);
|
||||
}
|
||||
|
||||
public boolean isConsumer(ImageConsumer pConsumer) {
|
||||
return mConsumers.contains(pConsumer);
|
||||
public boolean isConsumer(final ImageConsumer pConsumer) {
|
||||
return consumers.contains(pConsumer);
|
||||
}
|
||||
|
||||
protected abstract void initConsumer(ImageConsumer pConsumer);
|
||||
|
@@ -47,33 +47,34 @@ import java.io.IOException;
|
||||
*/
|
||||
public class AreaAverageOp implements BufferedImageOp, RasterOp {
|
||||
|
||||
final private int mWidth;
|
||||
final private int mHeight;
|
||||
final private int width;
|
||||
final private int height;
|
||||
|
||||
private Rectangle mSourceRegion;
|
||||
private Rectangle sourceRegion;
|
||||
|
||||
public AreaAverageOp(final int pWidth, final int pHeight) {
|
||||
mWidth = pWidth;
|
||||
mHeight = pHeight;
|
||||
width = pWidth;
|
||||
height = pHeight;
|
||||
}
|
||||
|
||||
public Rectangle getSourceRegion() {
|
||||
if (mSourceRegion == null) {
|
||||
if (sourceRegion == null) {
|
||||
return null;
|
||||
}
|
||||
return new Rectangle(mSourceRegion);
|
||||
|
||||
return new Rectangle(sourceRegion);
|
||||
}
|
||||
|
||||
public void setSourceRegion(final Rectangle pSourceRegion) {
|
||||
if (pSourceRegion == null) {
|
||||
mSourceRegion = null;
|
||||
sourceRegion = null;
|
||||
}
|
||||
else {
|
||||
if (mSourceRegion == null) {
|
||||
mSourceRegion = new Rectangle(pSourceRegion);
|
||||
if (sourceRegion == null) {
|
||||
sourceRegion = new Rectangle(pSourceRegion);
|
||||
}
|
||||
else {
|
||||
mSourceRegion.setBounds(pSourceRegion);
|
||||
sourceRegion.setBounds(pSourceRegion);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,7 +94,7 @@ public class AreaAverageOp implements BufferedImageOp, RasterOp {
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
// Straight-forward version
|
||||
//Image scaled = src.getScaledInstance(mWidth, mHeight, Image.SCALE_AREA_AVERAGING);
|
||||
//Image scaled = src.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING);
|
||||
//ImageUtil.drawOnto(result, scaled);
|
||||
//result = new BufferedImageFactory(scaled).getBufferedImage();
|
||||
|
||||
@@ -104,7 +105,7 @@ public class AreaAverageOp implements BufferedImageOp, RasterOp {
|
||||
AffineTransform xform = null;
|
||||
int w = src.getWidth();
|
||||
int h = src.getHeight();
|
||||
while (w / 2 > mWidth && h / 2 > mHeight) {
|
||||
while (w / 2 > width && h / 2 > height) {
|
||||
w /= 2;
|
||||
h /= 2;
|
||||
|
||||
@@ -129,7 +130,7 @@ public class AreaAverageOp implements BufferedImageOp, RasterOp {
|
||||
src = temp.getSubimage(0, 0, w, h);
|
||||
}
|
||||
|
||||
resample(src, result, AffineTransform.getScaleInstance(mWidth / (double) w, mHeight / (double) h));
|
||||
resample(src, result, AffineTransform.getScaleInstance(width / (double) w, height / (double) h));
|
||||
*/
|
||||
|
||||
// The real version
|
||||
@@ -160,11 +161,11 @@ public class AreaAverageOp implements BufferedImageOp, RasterOp {
|
||||
private WritableRaster filterImpl(Raster src, WritableRaster dest) {
|
||||
//System.out.println("src: " + src);
|
||||
//System.out.println("dest: " + dest);
|
||||
if (mSourceRegion != null) {
|
||||
int cx = mSourceRegion.x;
|
||||
int cy = mSourceRegion.y;
|
||||
int cw = mSourceRegion.width;
|
||||
int ch = mSourceRegion.height;
|
||||
if (sourceRegion != null) {
|
||||
int cx = sourceRegion.x;
|
||||
int cy = sourceRegion.y;
|
||||
int cw = sourceRegion.width;
|
||||
int ch = sourceRegion.height;
|
||||
|
||||
boolean same = src == dest;
|
||||
dest = dest.createWritableChild(cx, cy, cw, ch, 0, 0, null);
|
||||
@@ -179,11 +180,11 @@ public class AreaAverageOp implements BufferedImageOp, RasterOp {
|
||||
// TODO: This don't work too well..
|
||||
// The thing is that the step length and the scan length will vary, for
|
||||
// non-even (1/2, 1/4, 1/8 etc) resampling
|
||||
int widthSteps = (width + mWidth - 1) / mWidth;
|
||||
int heightSteps = (height + mHeight - 1) / mHeight;
|
||||
int widthSteps = (width + this.width - 1) / this.width;
|
||||
int heightSteps = (height + this.height - 1) / this.height;
|
||||
|
||||
final boolean oddX = width % mWidth != 0;
|
||||
final boolean oddY = height % mHeight != 0;
|
||||
final boolean oddX = width % this.width != 0;
|
||||
final boolean oddY = height % this.height != 0;
|
||||
|
||||
final int dataElements = src.getNumDataElements();
|
||||
final int bands = src.getNumBands();
|
||||
@@ -210,16 +211,16 @@ public class AreaAverageOp implements BufferedImageOp, RasterOp {
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < mHeight; y++) {
|
||||
if (!oddY || y < mHeight) {
|
||||
for (int y = 0; y < this.height; y++) {
|
||||
if (!oddY || y < this.height) {
|
||||
scanH = heightSteps;
|
||||
}
|
||||
else {
|
||||
scanH = height - (y * heightSteps);
|
||||
}
|
||||
|
||||
for (int x = 0; x < mWidth; x++) {
|
||||
if (!oddX || x < mWidth) {
|
||||
for (int x = 0; x < this.width; x++) {
|
||||
if (!oddX || x < this.width) {
|
||||
scanW = widthSteps;
|
||||
}
|
||||
else {
|
||||
@@ -243,8 +244,8 @@ public class AreaAverageOp implements BufferedImageOp, RasterOp {
|
||||
//
|
||||
//System.err.println("width: " + width);
|
||||
//System.err.println("height: " + height);
|
||||
//System.err.println("mWidth: " + mWidth);
|
||||
//System.err.println("mHeight: " + mHeight);
|
||||
//System.err.println("width: " + width);
|
||||
//System.err.println("height: " + height);
|
||||
//
|
||||
//e.printStackTrace();
|
||||
continue;
|
||||
@@ -382,20 +383,20 @@ public class AreaAverageOp implements BufferedImageOp, RasterOp {
|
||||
public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) {
|
||||
ColorModel cm = destCM != null ? destCM : src.getColorModel();
|
||||
return new BufferedImage(cm,
|
||||
ImageUtil.createCompatibleWritableRaster(src, cm, mWidth, mHeight),
|
||||
ImageUtil.createCompatibleWritableRaster(src, cm, width, height),
|
||||
cm.isAlphaPremultiplied(), null);
|
||||
}
|
||||
|
||||
public WritableRaster createCompatibleDestRaster(Raster src) {
|
||||
return src.createCompatibleWritableRaster(mWidth, mHeight);
|
||||
return src.createCompatibleWritableRaster(width, height);
|
||||
}
|
||||
|
||||
public Rectangle2D getBounds2D(Raster src) {
|
||||
return new Rectangle(mWidth, mHeight);
|
||||
return new Rectangle(width, height);
|
||||
}
|
||||
|
||||
public Rectangle2D getBounds2D(BufferedImage src) {
|
||||
return new Rectangle(mWidth, mHeight);
|
||||
return new Rectangle(width, height);
|
||||
}
|
||||
|
||||
public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
|
||||
|
@@ -67,7 +67,7 @@ public class BrightnessContrastFilter extends RGBImageFilter {
|
||||
}
|
||||
|
||||
// Use a precalculated lookup table for performace
|
||||
private int[] mLUT = null;
|
||||
private final int[] LUT;
|
||||
|
||||
/**
|
||||
* Creates a BrightnessContrastFilter with default values
|
||||
@@ -105,7 +105,7 @@ public class BrightnessContrastFilter extends RGBImageFilter {
|
||||
* {@code -1.0,..,0.0,..,1.0}.
|
||||
*/
|
||||
public BrightnessContrastFilter(float pBrightness, float pContrast) {
|
||||
mLUT = createLUT(pBrightness, pContrast);
|
||||
LUT = createLUT(pBrightness, pContrast);
|
||||
}
|
||||
|
||||
private static int[] createLUT(float pBrightness, float pContrast) {
|
||||
@@ -157,9 +157,9 @@ public class BrightnessContrastFilter extends RGBImageFilter {
|
||||
int b = pARGB & 0xFF;
|
||||
|
||||
// Scale to new contrast
|
||||
r = mLUT[r];
|
||||
g = mLUT[g];
|
||||
b = mLUT[b];
|
||||
r = LUT[r];
|
||||
g = LUT[g];
|
||||
b = LUT[b];
|
||||
|
||||
// Return ARGB pixel, leave transparency as is
|
||||
return (pARGB & 0xFF000000) | (r << 16) | (g << 8) | b;
|
||||
|
@@ -28,11 +28,14 @@
|
||||
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.EventListener;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
@@ -52,50 +55,53 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/BufferedImageFactory.java#1 $
|
||||
*/
|
||||
public final class BufferedImageFactory {
|
||||
private List<ProgressListener> mListeners;
|
||||
private int mPercentageDone;
|
||||
private List<ProgressListener> listeners;
|
||||
private int percentageDone;
|
||||
|
||||
private ImageProducer mProducer;
|
||||
private boolean mError;
|
||||
private boolean mFetching;
|
||||
private boolean mReadColorModelOnly;
|
||||
private ImageProducer producer;
|
||||
private boolean error;
|
||||
private volatile boolean fetching;
|
||||
private boolean readColorModelOnly;
|
||||
|
||||
private int mX = 0;
|
||||
private int mY = 0;
|
||||
private int mWidth = -1;
|
||||
private int mHeight = -1;
|
||||
private int x = 0;
|
||||
private int y = 0;
|
||||
private int width = -1;
|
||||
private int height = -1;
|
||||
|
||||
private int mXSub = 1;
|
||||
private int mYSub = 1;
|
||||
private int xSub = 1;
|
||||
private int ySub = 1;
|
||||
|
||||
private int mOffset;
|
||||
private int mScanSize;
|
||||
private int offset;
|
||||
private int scanSize;
|
||||
|
||||
private ColorModel mSourceColorModel;
|
||||
private Hashtable mSourceProperties; // ImageConsumer API dictates Hashtable
|
||||
private ColorModel sourceColorModel;
|
||||
private Hashtable sourceProperties; // ImageConsumer API dictates Hashtable
|
||||
|
||||
private Object mSourcePixels;
|
||||
private Object sourcePixels;
|
||||
|
||||
private BufferedImage mBuffered;
|
||||
private ColorModel mColorModel;
|
||||
private BufferedImage buffered;
|
||||
private ColorModel colorModel;
|
||||
|
||||
// NOTE: Just to not expose the inheritance
|
||||
private final Consumer mConsumer = new Consumer();
|
||||
private final Consumer consumer = new Consumer();
|
||||
|
||||
/**
|
||||
* Creates a {@code BufferedImageFactory}.
|
||||
* @param pSource the source image
|
||||
* @throws IllegalArgumentException if {@code pSource == null}
|
||||
*/
|
||||
public BufferedImageFactory(final Image pSource) {
|
||||
this(pSource.getSource());
|
||||
this(pSource != null ? pSource.getSource() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code BufferedImageFactory}.
|
||||
* @param pSource the source image producer
|
||||
* @throws IllegalArgumentException if {@code pSource == null}
|
||||
*/
|
||||
public BufferedImageFactory(final ImageProducer pSource) {
|
||||
mProducer = pSource;
|
||||
Validate.notNull(pSource, "source");
|
||||
producer = pSource;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,7 +115,7 @@ public final class BufferedImageFactory {
|
||||
*/
|
||||
public BufferedImage getBufferedImage() throws ImageConversionException {
|
||||
doFetch(false);
|
||||
return mBuffered;
|
||||
return buffered;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,7 +129,7 @@ public final class BufferedImageFactory {
|
||||
*/
|
||||
public ColorModel getColorModel() throws ImageConversionException {
|
||||
doFetch(true);
|
||||
return mBuffered != null ? mBuffered.getColorModel() : mColorModel;
|
||||
return buffered != null ? buffered.getColorModel() : colorModel;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,15 +137,15 @@ public final class BufferedImageFactory {
|
||||
*/
|
||||
public void dispose() {
|
||||
freeResources();
|
||||
mBuffered = null;
|
||||
mColorModel = null;
|
||||
buffered = null;
|
||||
colorModel = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aborts the image production.
|
||||
*/
|
||||
public void abort() {
|
||||
mConsumer.imageComplete(ImageConsumer.IMAGEABORTED);
|
||||
consumer.imageComplete(ImageConsumer.IMAGEABORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,14 +155,14 @@ public final class BufferedImageFactory {
|
||||
*/
|
||||
public void setSourceRegion(final Rectangle pRegion) {
|
||||
// Re-fetch everything, if region changed
|
||||
if (mX != pRegion.x || mY != pRegion.y || mWidth != pRegion.width || mHeight != pRegion.height) {
|
||||
if (x != pRegion.x || y != pRegion.y || width != pRegion.width || height != pRegion.height) {
|
||||
dispose();
|
||||
}
|
||||
|
||||
mX = pRegion.x;
|
||||
mY = pRegion.y;
|
||||
mWidth = pRegion.width;
|
||||
mHeight = pRegion.height;
|
||||
x = pRegion.x;
|
||||
y = pRegion.y;
|
||||
width = pRegion.width;
|
||||
height = pRegion.height;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,50 +173,51 @@ public final class BufferedImageFactory {
|
||||
*/
|
||||
public void setSourceSubsampling(int pXSub, int pYSub) {
|
||||
// Re-fetch everything, if subsampling changed
|
||||
if (mXSub != pXSub || mYSub != pYSub) {
|
||||
if (xSub != pXSub || ySub != pYSub) {
|
||||
dispose();
|
||||
}
|
||||
|
||||
if (pXSub > 1) {
|
||||
mXSub = pXSub;
|
||||
xSub = pXSub;
|
||||
}
|
||||
if (pYSub > 1) {
|
||||
mYSub = pYSub;
|
||||
ySub = pYSub;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void doFetch(boolean pColorModelOnly) throws ImageConversionException {
|
||||
if (!mFetching && (!pColorModelOnly && mBuffered == null || mBuffered == null && mSourceColorModel == null)) {
|
||||
if (!fetching && (!pColorModelOnly && buffered == null || buffered == null && sourceColorModel == null)) {
|
||||
// NOTE: Subsampling is only applied if extracting full image
|
||||
if (!pColorModelOnly && (mXSub > 1 || mYSub > 1)) {
|
||||
if (!pColorModelOnly && (xSub > 1 || ySub > 1)) {
|
||||
// If only sampling a region, the region must be scaled too
|
||||
if (mWidth > 0 && mHeight > 0) {
|
||||
mWidth = (mWidth + mXSub - 1) / mXSub;
|
||||
mHeight = (mHeight + mYSub - 1) / mYSub;
|
||||
if (width > 0 && height > 0) {
|
||||
width = (width + xSub - 1) / xSub;
|
||||
height = (height + ySub - 1) / ySub;
|
||||
|
||||
mX = (mX + mXSub - 1) / mXSub;
|
||||
mY = (mY + mYSub - 1) / mYSub;
|
||||
x = (x + xSub - 1) / xSub;
|
||||
y = (y + ySub - 1) / ySub;
|
||||
}
|
||||
|
||||
mProducer = new FilteredImageSource(mProducer, new SubsamplingFilter(mXSub, mYSub));
|
||||
producer = new FilteredImageSource(producer, new SubsamplingFilter(xSub, ySub));
|
||||
}
|
||||
|
||||
// Start fetching
|
||||
mFetching = true;
|
||||
mReadColorModelOnly = pColorModelOnly;
|
||||
mProducer.startProduction(mConsumer); // Note: If single-thread (synchronous), this call will block
|
||||
fetching = true;
|
||||
readColorModelOnly = pColorModelOnly;
|
||||
|
||||
producer.startProduction(consumer); // Note: If single-thread (synchronous), this call will block
|
||||
|
||||
// Wait until the producer wakes us up, by calling imageComplete
|
||||
while (mFetching) {
|
||||
while (fetching) {
|
||||
try {
|
||||
wait();
|
||||
wait(200l);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new ImageConversionException("Image conversion aborted: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
if (mError) {
|
||||
if (error) {
|
||||
throw new ImageConversionException("Image conversion failed: ImageConsumer.IMAGEERROR.");
|
||||
}
|
||||
|
||||
@@ -224,21 +231,21 @@ public final class BufferedImageFactory {
|
||||
}
|
||||
|
||||
private void createColorModel() {
|
||||
mColorModel = mSourceColorModel;
|
||||
colorModel = sourceColorModel;
|
||||
|
||||
// Clean up, in case any objects are copied/cloned, so we can free resources
|
||||
freeResources();
|
||||
}
|
||||
|
||||
private void createBuffered() {
|
||||
if (mWidth > 0 && mHeight > 0) {
|
||||
if (mSourceColorModel != null && mSourcePixels != null) {
|
||||
if (width > 0 && height > 0) {
|
||||
if (sourceColorModel != null && sourcePixels != null) {
|
||||
// TODO: Fix pixel size / color model problem
|
||||
WritableRaster raster = ImageUtil.createRaster(mWidth, mHeight, mSourcePixels, mSourceColorModel);
|
||||
mBuffered = new BufferedImage(mSourceColorModel, raster, mSourceColorModel.isAlphaPremultiplied(), mSourceProperties);
|
||||
WritableRaster raster = ImageUtil.createRaster(width, height, sourcePixels, sourceColorModel);
|
||||
buffered = new BufferedImage(sourceColorModel, raster, sourceColorModel.isAlphaPremultiplied(), sourceProperties);
|
||||
}
|
||||
else {
|
||||
mBuffered = ImageUtil.createClear(mWidth, mHeight, null);
|
||||
buffered = ImageUtil.createClear(width, height, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,21 +254,21 @@ public final class BufferedImageFactory {
|
||||
}
|
||||
|
||||
private void freeResources() {
|
||||
mSourceColorModel = null;
|
||||
mSourcePixels = null;
|
||||
mSourceProperties = null;
|
||||
sourceColorModel = null;
|
||||
sourcePixels = null;
|
||||
sourceProperties = null;
|
||||
}
|
||||
|
||||
private void processProgress(int mScanline) {
|
||||
if (mListeners != null) {
|
||||
int percent = 100 * mScanline / mHeight;
|
||||
if (listeners != null) {
|
||||
int percent = 100 * mScanline / height;
|
||||
|
||||
//System.out.println("Progress: " + percent + "%");
|
||||
|
||||
if (percent > mPercentageDone) {
|
||||
mPercentageDone = percent;
|
||||
if (percent > percentageDone) {
|
||||
percentageDone = percent;
|
||||
|
||||
for (ProgressListener listener : mListeners) {
|
||||
for (ProgressListener listener : listeners) {
|
||||
listener.progress(this, percent);
|
||||
}
|
||||
}
|
||||
@@ -278,11 +285,11 @@ public final class BufferedImageFactory {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mListeners == null) {
|
||||
mListeners = new CopyOnWriteArrayList<ProgressListener>();
|
||||
if (listeners == null) {
|
||||
listeners = new CopyOnWriteArrayList<ProgressListener>();
|
||||
}
|
||||
|
||||
mListeners.add(pListener);
|
||||
listeners.add(pListener);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -295,19 +302,19 @@ public final class BufferedImageFactory {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mListeners == null) {
|
||||
if (listeners == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mListeners.remove(pListener);
|
||||
listeners.remove(pListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all progress listeners from this factory.
|
||||
*/
|
||||
public void removeAllProgressListeners() {
|
||||
if (mListeners != null) {
|
||||
mListeners.clear();
|
||||
if (listeners != null) {
|
||||
listeners.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,21 +385,21 @@ public final class BufferedImageFactory {
|
||||
}
|
||||
|
||||
// Allocate array if necessary
|
||||
if (mSourcePixels == null) {
|
||||
if (sourcePixels == null) {
|
||||
// Allocate a suitable source pixel array
|
||||
// TODO: Should take pixel "width" into consideration, for byte packed rasters?!
|
||||
// OR... Is anything but single-pixel models really supported by the API?
|
||||
mSourcePixels = Array.newInstance(pPixels.getClass().getComponentType(), mWidth * mHeight);
|
||||
mScanSize = mWidth;
|
||||
mOffset = 0;
|
||||
sourcePixels = Array.newInstance(pPixels.getClass().getComponentType(), width * height);
|
||||
scanSize = width;
|
||||
offset = 0;
|
||||
}
|
||||
else if (mSourcePixels.getClass() != pPixels.getClass()) {
|
||||
else if (sourcePixels.getClass() != pPixels.getClass()) {
|
||||
throw new IllegalStateException("Only one pixel type allowed");
|
||||
}
|
||||
|
||||
// AOI stuff
|
||||
if (pY < mY) {
|
||||
int diff = mY - pY;
|
||||
if (pY < y) {
|
||||
int diff = y - pY;
|
||||
if (diff >= pHeight) {
|
||||
return;
|
||||
}
|
||||
@@ -400,15 +407,15 @@ public final class BufferedImageFactory {
|
||||
pY += diff;
|
||||
pHeight -= diff;
|
||||
}
|
||||
if (pY + pHeight > mY + mHeight) {
|
||||
pHeight = (mY + mHeight) - pY;
|
||||
if (pY + pHeight > y + height) {
|
||||
pHeight = (y + height) - pY;
|
||||
if (pHeight <= 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pX < mX) {
|
||||
int diff = mX - pX;
|
||||
if (pX < x) {
|
||||
int diff = x - pX;
|
||||
if (diff >= pWidth) {
|
||||
return;
|
||||
}
|
||||
@@ -416,20 +423,20 @@ public final class BufferedImageFactory {
|
||||
pX += diff;
|
||||
pWidth -= diff;
|
||||
}
|
||||
if (pX + pWidth > mX + mWidth) {
|
||||
pWidth = (mX + mWidth) - pX;
|
||||
if (pX + pWidth > x + width) {
|
||||
pWidth = (x + width) - pX;
|
||||
if (pWidth <= 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int dstOffset = mOffset + (pY - mY) * mScanSize + (pX - mX);
|
||||
int dstOffset = offset + (pY - y) * scanSize + (pX - x);
|
||||
|
||||
// Do the pixel copying
|
||||
for (int i = pHeight; i > 0; i--) {
|
||||
System.arraycopy(pPixels, pOffset, mSourcePixels, dstOffset, pWidth);
|
||||
System.arraycopy(pPixels, pOffset, sourcePixels, dstOffset, pWidth);
|
||||
pOffset += pScanSize;
|
||||
dstOffset += mScanSize;
|
||||
dstOffset += scanSize;
|
||||
}
|
||||
|
||||
processProgress(pY + pHeight);
|
||||
@@ -439,14 +446,14 @@ public final class BufferedImageFactory {
|
||||
setPixelsImpl(pX, pY, pWidth, pHeight, pModel, pPixels, pOffset, pScanSize);
|
||||
}
|
||||
|
||||
private void setColorModelOnce(ColorModel pModel) {
|
||||
private void setColorModelOnce(final ColorModel pModel) {
|
||||
// NOTE: There seems to be a "bug" in AreaAveragingScaleFilter, as it
|
||||
// first passes the original color model through in setColorModel, then
|
||||
// later replaces it with the default RGB in the first setPixels call
|
||||
// (this is probably allowed according to the spec, but it's a waste of time and space).
|
||||
if (mSourceColorModel != pModel) {
|
||||
if (/*mSourceColorModel == null ||*/ mSourcePixels == null) {
|
||||
mSourceColorModel = pModel;
|
||||
if (sourceColorModel != pModel) {
|
||||
if (/*sourceColorModel == null ||*/ sourcePixels == null) {
|
||||
sourceColorModel = pModel;
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Change of ColorModel after pixel delivery not supported");
|
||||
@@ -454,23 +461,22 @@ public final class BufferedImageFactory {
|
||||
}
|
||||
|
||||
// If color model is all we ask for, stop now
|
||||
if (mReadColorModelOnly) {
|
||||
mConsumer.imageComplete(ImageConsumer.IMAGEABORTED);
|
||||
if (readColorModelOnly) {
|
||||
consumer.imageComplete(ImageConsumer.IMAGEABORTED);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"ThrowableInstanceNeverThrown"})
|
||||
public void imageComplete(int pStatus) {
|
||||
mFetching = false;
|
||||
fetching = false;
|
||||
|
||||
if (mProducer != null) {
|
||||
mProducer.removeConsumer(this);
|
||||
if (producer != null) {
|
||||
producer.removeConsumer(this);
|
||||
}
|
||||
|
||||
switch (pStatus) {
|
||||
case ImageConsumer.IMAGEERROR:
|
||||
new Error().printStackTrace();
|
||||
mError = true;
|
||||
Thread.dumpStack();
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -484,15 +490,15 @@ public final class BufferedImageFactory {
|
||||
}
|
||||
|
||||
public void setDimensions(int pWidth, int pHeight) {
|
||||
if (mWidth < 0) {
|
||||
mWidth = pWidth - mX;
|
||||
if (width < 0) {
|
||||
width = pWidth - x;
|
||||
}
|
||||
if (mHeight < 0) {
|
||||
mHeight = pHeight - mY;
|
||||
if (height < 0) {
|
||||
height = pHeight - y;
|
||||
}
|
||||
|
||||
// Hmm.. Special case, but is it a good idea?
|
||||
if (mWidth <= 0 || mHeight <= 0) {
|
||||
if (width <= 0 || height <= 0) {
|
||||
imageComplete(ImageConsumer.STATICIMAGEDONE);
|
||||
}
|
||||
}
|
||||
@@ -530,7 +536,7 @@ public final class BufferedImageFactory {
|
||||
}
|
||||
|
||||
public void setProperties(Hashtable pProperties) {
|
||||
mSourceProperties = pProperties;
|
||||
sourceProperties = pProperties;
|
||||
}
|
||||
}
|
||||
}
|
@@ -28,6 +28,8 @@
|
||||
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.*;
|
||||
@@ -41,51 +43,44 @@ import java.awt.geom.AffineTransform;
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/BufferedImageIcon.java#2 $
|
||||
*/
|
||||
public class BufferedImageIcon implements Icon {
|
||||
private final BufferedImage mImage;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
private final boolean mFast;
|
||||
private final BufferedImage image;
|
||||
private int width;
|
||||
private int height;
|
||||
private final boolean fast;
|
||||
|
||||
public BufferedImageIcon(BufferedImage pImage) {
|
||||
this(pImage, pImage.getWidth(), pImage.getHeight());
|
||||
}
|
||||
|
||||
public BufferedImageIcon(BufferedImage pImage, int pWidth, int pHeight) {
|
||||
if (pImage == null) {
|
||||
throw new IllegalArgumentException("image == null");
|
||||
}
|
||||
if (pWidth <= 0 || pHeight <= 0) {
|
||||
throw new IllegalArgumentException("Icon size must be positive");
|
||||
}
|
||||
image = Validate.notNull(pImage, "image");
|
||||
width = Validate.isTrue(pWidth > 0, pWidth, "width must be positive: %d");
|
||||
height = Validate.isTrue(pHeight > 0, pHeight, "height must be positive: %d");
|
||||
|
||||
mImage = pImage;
|
||||
mWidth = pWidth;
|
||||
mHeight = pHeight;
|
||||
|
||||
mFast = pImage.getWidth() == mWidth && pImage.getHeight() == mHeight;
|
||||
fast = image.getWidth() == width && image.getHeight() == height;
|
||||
}
|
||||
|
||||
public int getIconHeight() {
|
||||
return mHeight;
|
||||
return height;
|
||||
}
|
||||
|
||||
public int getIconWidth() {
|
||||
return mWidth;
|
||||
return width;
|
||||
}
|
||||
|
||||
public void paintIcon(Component c, Graphics g, int x, int y) {
|
||||
if (mFast || !(g instanceof Graphics2D)) {
|
||||
if (fast || !(g instanceof Graphics2D)) {
|
||||
//System.out.println("Scaling fast");
|
||||
g.drawImage(mImage, x, y, mWidth, mHeight, null);
|
||||
g.drawImage(image, x, y, width, height, null);
|
||||
}
|
||||
else {
|
||||
//System.out.println("Scaling using interpolation");
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
AffineTransform xform = AffineTransform.getTranslateInstance(x, y);
|
||||
xform.scale(mWidth / (double) mImage.getWidth(), mHeight / (double) mImage.getHeight());
|
||||
xform.scale(width / (double) image.getWidth(), height / (double) image.getHeight());
|
||||
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
||||
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
g2.drawImage(mImage, xform, null);
|
||||
g2.drawImage(image, xform, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -73,14 +73,15 @@ public class ConvolveWithEdgeOp implements BufferedImageOp, RasterOp {
|
||||
*/
|
||||
public static final int EDGE_WRAP = 3; // as JAI BORDER_WRAP
|
||||
|
||||
private final Kernel mKernel;
|
||||
private final int mEdgeCondition;
|
||||
private final Kernel kernel;
|
||||
private final int edgeCondition;
|
||||
|
||||
private final ConvolveOp mConvolve;
|
||||
private final ConvolveOp convolve;
|
||||
|
||||
public ConvolveWithEdgeOp(final Kernel pKernel, final int pEdgeCondition, final RenderingHints pHints) {
|
||||
// Create convolution operation
|
||||
int edge;
|
||||
|
||||
switch (pEdgeCondition) {
|
||||
case EDGE_REFLECT:
|
||||
case EDGE_WRAP:
|
||||
@@ -90,9 +91,10 @@ public class ConvolveWithEdgeOp implements BufferedImageOp, RasterOp {
|
||||
edge = pEdgeCondition;
|
||||
break;
|
||||
}
|
||||
mKernel = pKernel;
|
||||
mEdgeCondition = pEdgeCondition;
|
||||
mConvolve = new ConvolveOp(pKernel, edge, pHints);
|
||||
|
||||
kernel = pKernel;
|
||||
edgeCondition = pEdgeCondition;
|
||||
convolve = new ConvolveOp(pKernel, edge, pHints);
|
||||
}
|
||||
|
||||
public ConvolveWithEdgeOp(final Kernel pKernel) {
|
||||
@@ -107,8 +109,8 @@ public class ConvolveWithEdgeOp implements BufferedImageOp, RasterOp {
|
||||
throw new IllegalArgumentException("source image cannot be the same as the destination image");
|
||||
}
|
||||
|
||||
int borderX = mKernel.getWidth() / 2;
|
||||
int borderY = mKernel.getHeight() / 2;
|
||||
int borderX = kernel.getWidth() / 2;
|
||||
int borderY = kernel.getHeight() / 2;
|
||||
|
||||
BufferedImage original = addBorder(pSource, borderX, borderY);
|
||||
|
||||
@@ -126,7 +128,7 @@ public class ConvolveWithEdgeOp implements BufferedImageOp, RasterOp {
|
||||
}
|
||||
|
||||
// Do the filtering (if destination is null, a new image will be created)
|
||||
destination = mConvolve.filter(original, destination);
|
||||
destination = convolve.filter(original, destination);
|
||||
|
||||
if (pSource != original) {
|
||||
// Remove the border
|
||||
@@ -137,7 +139,7 @@ public class ConvolveWithEdgeOp implements BufferedImageOp, RasterOp {
|
||||
}
|
||||
|
||||
private BufferedImage addBorder(final BufferedImage pOriginal, final int pBorderX, final int pBorderY) {
|
||||
if ((mEdgeCondition & 2) == 0) {
|
||||
if ((edgeCondition & 2) == 0) {
|
||||
return pOriginal;
|
||||
}
|
||||
|
||||
@@ -158,7 +160,7 @@ public class ConvolveWithEdgeOp implements BufferedImageOp, RasterOp {
|
||||
g.drawImage(pOriginal, pBorderX, pBorderY, null);
|
||||
|
||||
// TODO: I guess we need the top/left etc, if the corner pixels are covered by the kernel
|
||||
switch (mEdgeCondition) {
|
||||
switch (edgeCondition) {
|
||||
case EDGE_REFLECT:
|
||||
// Top/left (empty)
|
||||
g.drawImage(pOriginal, pBorderX, 0, pBorderX + w, pBorderY, 0, 0, w, 1, null); // Top/center
|
||||
@@ -186,7 +188,7 @@ public class ConvolveWithEdgeOp implements BufferedImageOp, RasterOp {
|
||||
g.drawImage(pOriginal, w + pBorderX, h + pBorderY, null); // Bottom/right
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Illegal edge operation " + mEdgeCondition);
|
||||
throw new IllegalArgumentException("Illegal edge operation " + edgeCondition);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -206,39 +208,39 @@ public class ConvolveWithEdgeOp implements BufferedImageOp, RasterOp {
|
||||
* @see #EDGE_WRAP
|
||||
*/
|
||||
public int getEdgeCondition() {
|
||||
return mEdgeCondition;
|
||||
return edgeCondition;
|
||||
}
|
||||
|
||||
public WritableRaster filter(final Raster pSource, final WritableRaster pDestination) {
|
||||
return mConvolve.filter(pSource, pDestination);
|
||||
return convolve.filter(pSource, pDestination);
|
||||
}
|
||||
|
||||
public BufferedImage createCompatibleDestImage(final BufferedImage pSource, final ColorModel pDesinationColorModel) {
|
||||
return mConvolve.createCompatibleDestImage(pSource, pDesinationColorModel);
|
||||
return convolve.createCompatibleDestImage(pSource, pDesinationColorModel);
|
||||
}
|
||||
|
||||
public WritableRaster createCompatibleDestRaster(final Raster pSource) {
|
||||
return mConvolve.createCompatibleDestRaster(pSource);
|
||||
return convolve.createCompatibleDestRaster(pSource);
|
||||
}
|
||||
|
||||
public Rectangle2D getBounds2D(final BufferedImage pSource) {
|
||||
return mConvolve.getBounds2D(pSource);
|
||||
return convolve.getBounds2D(pSource);
|
||||
}
|
||||
|
||||
public Rectangle2D getBounds2D(final Raster pSource) {
|
||||
return mConvolve.getBounds2D(pSource);
|
||||
return convolve.getBounds2D(pSource);
|
||||
}
|
||||
|
||||
public Point2D getPoint2D(final Point2D pSourcePoint, final Point2D pDestinationPoint) {
|
||||
return mConvolve.getPoint2D(pSourcePoint, pDestinationPoint);
|
||||
return convolve.getPoint2D(pSourcePoint, pDestinationPoint);
|
||||
}
|
||||
|
||||
public RenderingHints getRenderingHints() {
|
||||
return mConvolve.getRenderingHints();
|
||||
return convolve.getRenderingHints();
|
||||
}
|
||||
|
||||
public Kernel getKernel() {
|
||||
return mConvolve.getKernel();
|
||||
return convolve.getKernel();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -51,7 +51,7 @@ import java.awt.image.WritableRaster;
|
||||
*/
|
||||
public class CopyDither implements BufferedImageOp, RasterOp {
|
||||
|
||||
protected IndexColorModel mIndexColorModel = null;
|
||||
protected IndexColorModel indexColorModel = null;
|
||||
|
||||
/**
|
||||
* Creates a {@code CopyDither}, using the given
|
||||
@@ -61,7 +61,7 @@ public class CopyDither implements BufferedImageOp, RasterOp {
|
||||
*/
|
||||
public CopyDither(IndexColorModel pICM) {
|
||||
// Store colormodel
|
||||
mIndexColorModel = pICM;
|
||||
indexColorModel = pICM;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,17 +83,12 @@ public class CopyDither implements BufferedImageOp, RasterOp {
|
||||
* @throws ImageFilterException if {@code pDestCM} is not {@code null} or
|
||||
* an instance of {@code IndexColorModel}.
|
||||
*/
|
||||
public final BufferedImage createCompatibleDestImage(BufferedImage pSource,
|
||||
ColorModel pDestCM) {
|
||||
public final BufferedImage createCompatibleDestImage(BufferedImage pSource, ColorModel pDestCM) {
|
||||
if (pDestCM == null) {
|
||||
return new BufferedImage(pSource.getWidth(), pSource.getHeight(),
|
||||
BufferedImage.TYPE_BYTE_INDEXED,
|
||||
mIndexColorModel);
|
||||
return new BufferedImage(pSource.getWidth(), pSource.getHeight(), BufferedImage.TYPE_BYTE_INDEXED, indexColorModel);
|
||||
}
|
||||
else if (pDestCM instanceof IndexColorModel) {
|
||||
return new BufferedImage(pSource.getWidth(), pSource.getHeight(),
|
||||
BufferedImage.TYPE_BYTE_INDEXED,
|
||||
(IndexColorModel) pDestCM);
|
||||
return new BufferedImage(pSource.getWidth(), pSource.getHeight(), BufferedImage.TYPE_BYTE_INDEXED, (IndexColorModel) pDestCM);
|
||||
}
|
||||
else {
|
||||
throw new ImageFilterException("Only IndexColorModel allowed.");
|
||||
@@ -112,13 +107,7 @@ public class CopyDither implements BufferedImageOp, RasterOp {
|
||||
return createCompatibleDestRaster(pSrc, getICM(pSrc));
|
||||
}
|
||||
|
||||
public final WritableRaster createCompatibleDestRaster(Raster pSrc,
|
||||
IndexColorModel pIndexColorModel) {
|
||||
/*
|
||||
return new BufferedImage(pSrc.getWidth(), pSrc.getHeight(),
|
||||
BufferedImage.TYPE_BYTE_INDEXED,
|
||||
pIndexColorModel).getRaster();
|
||||
*/
|
||||
public final WritableRaster createCompatibleDestRaster(Raster pSrc, IndexColorModel pIndexColorModel) {
|
||||
return pIndexColorModel.createCompatibleWritableRaster(pSrc.getWidth(), pSrc.getHeight());
|
||||
}
|
||||
|
||||
@@ -207,8 +196,7 @@ public class CopyDither implements BufferedImageOp, RasterOp {
|
||||
* @return the destination image, or a new image, if {@code pDest} was
|
||||
* {@code null}.
|
||||
*/
|
||||
public final BufferedImage filter(BufferedImage pSource,
|
||||
BufferedImage pDest) {
|
||||
public final BufferedImage filter(BufferedImage pSource, BufferedImage pDest) {
|
||||
// Create destination image, if none provided
|
||||
if (pDest == null) {
|
||||
pDest = createCompatibleDestImage(pSource, getICM(pSource));
|
||||
@@ -238,16 +226,17 @@ public class CopyDither implements BufferedImageOp, RasterOp {
|
||||
}
|
||||
|
||||
private IndexColorModel getICM(BufferedImage pSource) {
|
||||
return (mIndexColorModel != null ? mIndexColorModel : IndexImage.getIndexColorModel(pSource, 256, IndexImage.TRANSPARENCY_BITMASK | IndexImage.COLOR_SELECTION_QUALITY));
|
||||
return (indexColorModel != null ? indexColorModel : IndexImage.getIndexColorModel(pSource, 256, IndexImage.TRANSPARENCY_BITMASK | IndexImage.COLOR_SELECTION_QUALITY));
|
||||
}
|
||||
|
||||
private IndexColorModel getICM(Raster pSource) {
|
||||
return (mIndexColorModel != null ? mIndexColorModel : createIndexColorModel(pSource));
|
||||
return (indexColorModel != null ? indexColorModel : createIndexColorModel(pSource));
|
||||
}
|
||||
|
||||
private IndexColorModel createIndexColorModel(Raster pSource) {
|
||||
BufferedImage image = new BufferedImage(pSource.getWidth(), pSource.getHeight(),
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
BufferedImage image = new BufferedImage(pSource.getWidth(), pSource.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
image.setData(pSource);
|
||||
|
||||
return IndexImage.getIndexColorModel(image, 256, IndexImage.TRANSPARENCY_BITMASK | IndexImage.COLOR_SELECTION_QUALITY);
|
||||
}
|
||||
|
||||
@@ -261,8 +250,7 @@ public class CopyDither implements BufferedImageOp, RasterOp {
|
||||
* @return the destination raster, or a new raster, if {@code pDest} was
|
||||
* {@code null}.
|
||||
*/
|
||||
public final WritableRaster filter(final Raster pSource, WritableRaster pDest,
|
||||
IndexColorModel pColorModel) {
|
||||
public final WritableRaster filter(final Raster pSource, WritableRaster pDest, IndexColorModel pColorModel) {
|
||||
int width = pSource.getWidth();
|
||||
int height = pSource.getHeight();
|
||||
|
||||
@@ -292,6 +280,7 @@ public class CopyDither implements BufferedImageOp, RasterOp {
|
||||
pDest.setDataElements(x, y, pixel);
|
||||
}
|
||||
}
|
||||
|
||||
return pDest;
|
||||
}
|
||||
}
|
||||
|
@@ -41,8 +41,8 @@ import java.util.Random;
|
||||
*/
|
||||
public class DiffusionDither implements BufferedImageOp, RasterOp {
|
||||
|
||||
protected IndexColorModel mIndexColorModel = null;
|
||||
private boolean mAlternateScans = true;
|
||||
protected IndexColorModel indexColorModel = null;
|
||||
private boolean alternateScans = true;
|
||||
private static final int FS_SCALE = 1 << 8;
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
@@ -54,7 +54,7 @@ public class DiffusionDither implements BufferedImageOp, RasterOp {
|
||||
*/
|
||||
public DiffusionDither(IndexColorModel pICM) {
|
||||
// Store colormodel
|
||||
mIndexColorModel = pICM;
|
||||
indexColorModel = pICM;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,7 +74,7 @@ public class DiffusionDither implements BufferedImageOp, RasterOp {
|
||||
* @param pUse {@code true} if scan mode should be alternating left/right
|
||||
*/
|
||||
public void setAlternateScans(boolean pUse) {
|
||||
mAlternateScans = pUse;
|
||||
alternateScans = pUse;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -252,10 +252,10 @@ public class DiffusionDither implements BufferedImageOp, RasterOp {
|
||||
}
|
||||
|
||||
private IndexColorModel getICM(BufferedImage pSource) {
|
||||
return (mIndexColorModel != null ? mIndexColorModel : IndexImage.getIndexColorModel(pSource, 256, IndexImage.TRANSPARENCY_BITMASK));
|
||||
return (indexColorModel != null ? indexColorModel : IndexImage.getIndexColorModel(pSource, 256, IndexImage.TRANSPARENCY_BITMASK));
|
||||
}
|
||||
private IndexColorModel getICM(Raster pSource) {
|
||||
return (mIndexColorModel != null ? mIndexColorModel : createIndexColorModel(pSource));
|
||||
return (indexColorModel != null ? indexColorModel : createIndexColorModel(pSource));
|
||||
}
|
||||
|
||||
private IndexColorModel createIndexColorModel(Raster pSource) {
|
||||
@@ -456,7 +456,7 @@ public class DiffusionDither implements BufferedImageOp, RasterOp {
|
||||
mNextErr = temperr;
|
||||
|
||||
// Toggle direction
|
||||
if (mAlternateScans) {
|
||||
if (alternateScans) {
|
||||
forward = !forward;
|
||||
}
|
||||
}
|
||||
|
@@ -48,8 +48,8 @@ public class GrayFilter extends RGBImageFilter {
|
||||
canFilterIndexColorModel = true;
|
||||
}
|
||||
|
||||
private int mLow = 0;
|
||||
private float mRange = 1.0f;
|
||||
private int low = 0;
|
||||
private float range = 1.0f;
|
||||
|
||||
/**
|
||||
* Constructs a GrayFilter using ITU color-conversion.
|
||||
@@ -82,8 +82,8 @@ public class GrayFilter extends RGBImageFilter {
|
||||
pHigh = 1f;
|
||||
}
|
||||
|
||||
mLow = (int) (pLow * 255f);
|
||||
mRange = pHigh - pLow;
|
||||
low = (int) (pLow * 255f);
|
||||
range = pHigh - pLow;
|
||||
|
||||
}
|
||||
|
||||
@@ -118,9 +118,9 @@ public class GrayFilter extends RGBImageFilter {
|
||||
|
||||
//int gray = (int) ((float) (r + g + b) / 3.0f);
|
||||
|
||||
if (mRange != 1.0f) {
|
||||
if (range != 1.0f) {
|
||||
// Apply range
|
||||
gray = mLow + (int) (gray * mRange);
|
||||
gray = low + (int) (gray * range);
|
||||
}
|
||||
|
||||
// Return ARGB pixel
|
||||
|
@@ -32,42 +32,20 @@ package com.twelvemonkeys.image;
|
||||
* This class wraps IllegalArgumentException as thrown by the
|
||||
* BufferedImageOp interface for more fine-grained control.
|
||||
*
|
||||
* @author Harald Kuhr
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
*
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/ImageFilterException.java#1 $
|
||||
*/
|
||||
public class ImageFilterException extends IllegalArgumentException {
|
||||
private Throwable mCause = null;
|
||||
|
||||
public ImageFilterException(String pStr) {
|
||||
super(pStr);
|
||||
public ImageFilterException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ImageFilterException(Throwable pT) {
|
||||
initCause(pT);
|
||||
public ImageFilterException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public ImageFilterException(String pStr, Throwable pT) {
|
||||
super(pStr);
|
||||
initCause(pT);
|
||||
}
|
||||
|
||||
public Throwable initCause(Throwable pThrowable) {
|
||||
if (mCause != null) {
|
||||
// May only be called once
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
else if (pThrowable == this) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
mCause = pThrowable;
|
||||
|
||||
// Hmmm...
|
||||
return this;
|
||||
}
|
||||
|
||||
public Throwable getCause() {
|
||||
return mCause;
|
||||
public ImageFilterException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
@@ -32,7 +32,6 @@ import java.awt.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.*;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
@@ -354,7 +353,7 @@ public final class ImageUtil {
|
||||
* The new image will have the same {@code ColorModel}, {@code Raster} and
|
||||
* properties as the original image, if possible.
|
||||
* <p/>
|
||||
* If the image is allready a {@code BufferedImage}, it is simply returned
|
||||
* If the image is already a {@code BufferedImage}, it is simply returned
|
||||
* and no conversion takes place.
|
||||
*
|
||||
* @param pOriginal the image to convert.
|
||||
@@ -365,7 +364,7 @@ public final class ImageUtil {
|
||||
* @throws ImageConversionException if the image cannot be converted
|
||||
*/
|
||||
public static BufferedImage toBuffered(Image pOriginal) {
|
||||
// Don't convert if it allready is BufferedImage
|
||||
// Don't convert if it already is BufferedImage
|
||||
if (pOriginal instanceof BufferedImage) {
|
||||
return (BufferedImage) pOriginal;
|
||||
}
|
||||
@@ -543,9 +542,10 @@ public final class ImageUtil {
|
||||
*/
|
||||
static WritableRaster createCompatibleWritableRaster(BufferedImage pOriginal, ColorModel pModel, int mWidth, int mHeight) {
|
||||
if (pModel == null || equals(pOriginal.getColorModel(), pModel)) {
|
||||
int[] bOffs;
|
||||
switch (pOriginal.getType()) {
|
||||
case BufferedImage.TYPE_3BYTE_BGR:
|
||||
int[] bOffs = {2, 1, 0}; // NOTE: These are reversed from what the cm.createCompatibleWritableRaster would return
|
||||
bOffs = new int[]{2, 1, 0}; // NOTE: These are reversed from what the cm.createCompatibleWritableRaster would return
|
||||
return Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
|
||||
mWidth, mHeight,
|
||||
mWidth * 3, 3,
|
||||
@@ -557,6 +557,17 @@ public final class ImageUtil {
|
||||
mWidth, mHeight,
|
||||
mWidth * 4, 4,
|
||||
bOffs, null);
|
||||
case BufferedImage.TYPE_CUSTOM:
|
||||
// Peek into the sample model to see if we have a sample model that will be incompatible with the default case
|
||||
SampleModel sm = pOriginal.getRaster().getSampleModel();
|
||||
if (sm instanceof ComponentSampleModel) {
|
||||
bOffs = ((ComponentSampleModel) sm).getBandOffsets();
|
||||
return Raster.createInterleavedRaster(sm.getDataType(),
|
||||
mWidth, mHeight,
|
||||
mWidth * bOffs.length, bOffs.length,
|
||||
bOffs, null);
|
||||
}
|
||||
// Else fall through
|
||||
default:
|
||||
return pOriginal.getColorModel().createCompatibleWritableRaster(mWidth, mHeight);
|
||||
}
|
||||
@@ -569,7 +580,7 @@ public final class ImageUtil {
|
||||
* The new image will have the same {@code ColorModel}, {@code Raster} and
|
||||
* properties as the original image, if possible.
|
||||
* <p/>
|
||||
* If the image is allready a {@code BufferedImage} of the given type, it
|
||||
* If the image is already a {@code BufferedImage} of the given type, it
|
||||
* is simply returned and no conversion takes place.
|
||||
*
|
||||
* @param pOriginal the image to convert.
|
||||
@@ -597,7 +608,7 @@ public final class ImageUtil {
|
||||
* the color model
|
||||
*/
|
||||
private static BufferedImage toBuffered(Image pOriginal, int pType, IndexColorModel pICM) {
|
||||
// Don't convert if it allready is BufferedImage and correct type
|
||||
// Don't convert if it already is BufferedImage and correct type
|
||||
if ((pOriginal instanceof BufferedImage)
|
||||
&& ((BufferedImage) pOriginal).getType() == pType
|
||||
&& (pICM == null || equals(((BufferedImage) pOriginal).getColorModel(), pICM))) {
|
||||
@@ -784,7 +795,7 @@ public final class ImageUtil {
|
||||
* Creates a scaled instance of the given {@code Image}, and converts it to
|
||||
* a {@code BufferedImage} if needed.
|
||||
* If the original image is a {@code BufferedImage} the result will have
|
||||
* same type and colormodel. Note that this implies overhead, and is
|
||||
* same type and color model. Note that this implies overhead, and is
|
||||
* probably not useful for anything but {@code IndexColorModel} images.
|
||||
*
|
||||
* @param pImage the {@code Image} to scale
|
||||
@@ -820,7 +831,7 @@ public final class ImageUtil {
|
||||
|
||||
BufferedImage scaled = createResampled(pImage, pWidth, pHeight, pHints);
|
||||
|
||||
// Convert if colormodels or type differ, to behave as documented
|
||||
// Convert if color models or type differ, to behave as documented
|
||||
if (type != scaled.getType() && type != BI_TYPE_ANY || !equals(scaled.getColorModel(), cm)) {
|
||||
//System.out.print("Converting TYPE " + scaled.getType() + " -> " + type + "... ");
|
||||
//long start = System.currentTimeMillis();
|
||||
@@ -965,9 +976,6 @@ public final class ImageUtil {
|
||||
}
|
||||
|
||||
private static int convertAWTHints(int pHints) {
|
||||
// TODO: These conversions are broken!
|
||||
// box == area average
|
||||
// point == replicate (or..?)
|
||||
switch (pHints) {
|
||||
case Image.SCALE_FAST:
|
||||
case Image.SCALE_REPLICATE:
|
||||
|
@@ -72,12 +72,12 @@ class InverseColorMap {
|
||||
*/
|
||||
final static int MAXQUANTVAL = 1 << 5;
|
||||
|
||||
byte[] mRGBMapByte;
|
||||
int[] mRGBMapInt;
|
||||
int mNumColors;
|
||||
int mMaxColor;
|
||||
byte[] mInverseRGB; // inverse rgb color map
|
||||
int mTransparentIndex = -1;
|
||||
byte[] rgbMapByte;
|
||||
int[] rgbMapInt;
|
||||
int numColors;
|
||||
int maxColor;
|
||||
byte[] inverseRGB; // inverse rgb color map
|
||||
int transparentIndex = -1;
|
||||
|
||||
/**
|
||||
* @param pRGBColorMap the rgb color map to create inverse color map for.
|
||||
@@ -99,11 +99,11 @@ class InverseColorMap {
|
||||
* @param pTransparent the index of the transparent pixel in the map
|
||||
*/
|
||||
InverseColorMap(byte[] pRGBColorMap, int pTransparent) {
|
||||
mRGBMapByte = pRGBColorMap;
|
||||
mNumColors = mRGBMapByte.length / 4;
|
||||
mTransparentIndex = pTransparent;
|
||||
rgbMapByte = pRGBColorMap;
|
||||
numColors = rgbMapByte.length / 4;
|
||||
transparentIndex = pTransparent;
|
||||
|
||||
mInverseRGB = new byte[MAXQUANTVAL * MAXQUANTVAL * MAXQUANTVAL];
|
||||
inverseRGB = new byte[MAXQUANTVAL * MAXQUANTVAL * MAXQUANTVAL];
|
||||
initIRGB(new int[MAXQUANTVAL * MAXQUANTVAL * MAXQUANTVAL]);
|
||||
}
|
||||
|
||||
@@ -112,11 +112,11 @@ class InverseColorMap {
|
||||
* @param pTransparent the index of the transparent pixel in the map
|
||||
*/
|
||||
InverseColorMap(int[] pRGBColorMap, int pTransparent) {
|
||||
mRGBMapInt = pRGBColorMap;
|
||||
mNumColors = mRGBMapInt.length;
|
||||
mTransparentIndex = pTransparent;
|
||||
rgbMapInt = pRGBColorMap;
|
||||
numColors = rgbMapInt.length;
|
||||
transparentIndex = pTransparent;
|
||||
|
||||
mInverseRGB = new byte[MAXQUANTVAL * MAXQUANTVAL * MAXQUANTVAL];
|
||||
inverseRGB = new byte[MAXQUANTVAL * MAXQUANTVAL * MAXQUANTVAL];
|
||||
initIRGB(new int[MAXQUANTVAL * MAXQUANTVAL * MAXQUANTVAL]);
|
||||
}
|
||||
|
||||
@@ -130,8 +130,8 @@ class InverseColorMap {
|
||||
final int xsqr = 1 << (TRUNCBITS * 2); // 64 - twice the smallest step size vale of quantized colors
|
||||
final int xsqr2 = xsqr + xsqr;
|
||||
|
||||
for (int i = 0; i < mNumColors; ++i) {
|
||||
if (i == mTransparentIndex) {
|
||||
for (int i = 0; i < numColors; ++i) {
|
||||
if (i == transparentIndex) {
|
||||
// Skip the transparent pixel
|
||||
continue;
|
||||
}
|
||||
@@ -141,15 +141,15 @@ class InverseColorMap {
|
||||
int blue, b, bdist, binc, bxx;
|
||||
|
||||
// HaraldK 20040801: Added support for int[]
|
||||
if (mRGBMapByte != null) {
|
||||
red = mRGBMapByte[i * 4] & 0xFF;
|
||||
green = mRGBMapByte[i * 4 + 1] & 0xFF;
|
||||
blue = mRGBMapByte[i * 4 + 2] & 0xFF;
|
||||
if (rgbMapByte != null) {
|
||||
red = rgbMapByte[i * 4] & 0xFF;
|
||||
green = rgbMapByte[i * 4 + 1] & 0xFF;
|
||||
blue = rgbMapByte[i * 4 + 2] & 0xFF;
|
||||
}
|
||||
else if (mRGBMapInt != null) {
|
||||
red = (mRGBMapInt[i] >> 16) & 0xFF;
|
||||
green = (mRGBMapInt[i] >> 8) & 0xFF;
|
||||
blue = mRGBMapInt[i] & 0xFF;
|
||||
else if (rgbMapInt != null) {
|
||||
red = (rgbMapInt[i] >> 16) & 0xFF;
|
||||
green = (rgbMapInt[i] >> 8) & 0xFF;
|
||||
blue = rgbMapInt[i] & 0xFF;
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("colormap == null");
|
||||
@@ -170,7 +170,7 @@ class InverseColorMap {
|
||||
for (b = 0, bdist = gdist, bxx = binc; b < MAXQUANTVAL; bdist += bxx, ++b, ++rgbI, bxx += xsqr2) {
|
||||
if (i == 0 || pTemp[rgbI] > bdist) {
|
||||
pTemp[rgbI] = bdist;
|
||||
mInverseRGB[rgbI] = (byte) i;
|
||||
inverseRGB[rgbI] = (byte) i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,7 +187,7 @@ class InverseColorMap {
|
||||
* created inverse color map.
|
||||
*/
|
||||
public final int getIndexNearest(int pColor) {
|
||||
return mInverseRGB[((pColor >> (3 * TRUNCBITS)) & QUANTMASK_RED) +
|
||||
return inverseRGB[((pColor >> (3 * TRUNCBITS)) & QUANTMASK_RED) +
|
||||
((pColor >> (2 * TRUNCBITS)) & QUANTMASK_GREEN) +
|
||||
((pColor >> (/* 1 * */ TRUNCBITS)) & QUANTMASK_BLUE)] & 0xFF;
|
||||
}
|
||||
@@ -203,7 +203,7 @@ class InverseColorMap {
|
||||
*/
|
||||
public final int getIndexNearest(int pRed, int pGreen, int pBlue) {
|
||||
// NOTE: the third line in expression for blue is shifting DOWN not UP.
|
||||
return mInverseRGB[((pRed << (2 * QUANTBITS - TRUNCBITS)) & QUANTMASK_RED) +
|
||||
return inverseRGB[((pRed << (2 * QUANTBITS - TRUNCBITS)) & QUANTMASK_RED) +
|
||||
((pGreen << (/* 1 * */ QUANTBITS - TRUNCBITS)) & QUANTMASK_GREEN) +
|
||||
((pBlue >> (TRUNCBITS)) & QUANTMASK_BLUE)] & 0xFF;
|
||||
}
|
||||
|
@@ -46,13 +46,13 @@ import java.awt.image.IndexColorModel;
|
||||
*/
|
||||
public class InverseColorMapIndexColorModel extends IndexColorModel {
|
||||
|
||||
protected int mRGBs[];
|
||||
protected int mMapSize;
|
||||
protected int rgbs[];
|
||||
protected int mapSize;
|
||||
|
||||
protected InverseColorMap mInverseMap = null;
|
||||
protected InverseColorMap inverseMap = null;
|
||||
private final static int ALPHA_THRESHOLD = 0x80;
|
||||
|
||||
private int mWhiteIndex = -1;
|
||||
private int whiteIndex = -1;
|
||||
private final static int WHITE = 0x00FFFFFF;
|
||||
private final static int RGB_MASK = 0x00FFFFFF;
|
||||
|
||||
@@ -74,11 +74,11 @@ public class InverseColorMapIndexColorModel extends IndexColorModel {
|
||||
ImageUtil.getTransferType(pColorModel),
|
||||
pColorModel.getValidPixels());
|
||||
|
||||
mRGBs = pRGBs;
|
||||
mMapSize = mRGBs.length;
|
||||
rgbs = pRGBs;
|
||||
mapSize = rgbs.length;
|
||||
|
||||
mInverseMap = new InverseColorMap(mRGBs);
|
||||
mWhiteIndex = getWhiteIndex();
|
||||
inverseMap = new InverseColorMap(rgbs);
|
||||
whiteIndex = getWhiteIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,6 +91,7 @@ public class InverseColorMapIndexColorModel extends IndexColorModel {
|
||||
private static int[] getRGBs(IndexColorModel pColorModel) {
|
||||
int[] rgb = new int[pColorModel.getMapSize()];
|
||||
pColorModel.getRGBs(rgb);
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
@@ -111,15 +112,13 @@ public class InverseColorMapIndexColorModel extends IndexColorModel {
|
||||
*
|
||||
* @see IndexColorModel#IndexColorModel(int, int, int[], int, boolean, int, int)
|
||||
*/
|
||||
public InverseColorMapIndexColorModel(int pNumBits, int pSize, int[] pRGBs,
|
||||
int pStart, boolean pAlpha, int pTransparentIndex,
|
||||
int pTransferType) {
|
||||
public InverseColorMapIndexColorModel(int pNumBits, int pSize, int[] pRGBs, int pStart, boolean pAlpha, int pTransparentIndex, int pTransferType) {
|
||||
super(pNumBits, pSize, pRGBs, pStart, pAlpha, pTransparentIndex, pTransferType);
|
||||
mRGBs = getRGBs(this);
|
||||
mMapSize = mRGBs.length;
|
||||
rgbs = getRGBs(this);
|
||||
mapSize = rgbs.length;
|
||||
|
||||
mInverseMap = new InverseColorMap(mRGBs, pTransparentIndex);
|
||||
mWhiteIndex = getWhiteIndex();
|
||||
inverseMap = new InverseColorMap(rgbs, pTransparentIndex);
|
||||
whiteIndex = getWhiteIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,15 +137,13 @@ public class InverseColorMapIndexColorModel extends IndexColorModel {
|
||||
*
|
||||
* @see IndexColorModel#IndexColorModel(int, int, byte[], byte[], byte[], int)
|
||||
*/
|
||||
public InverseColorMapIndexColorModel(int pNumBits, int pSize,
|
||||
byte[] pReds, byte[] pGreens, byte[] pBlues,
|
||||
int pTransparentIndex) {
|
||||
public InverseColorMapIndexColorModel(int pNumBits, int pSize, byte[] pReds, byte[] pGreens, byte[] pBlues, int pTransparentIndex) {
|
||||
super(pNumBits, pSize, pReds, pGreens, pBlues, pTransparentIndex);
|
||||
mRGBs = getRGBs(this);
|
||||
mMapSize = mRGBs.length;
|
||||
rgbs = getRGBs(this);
|
||||
mapSize = rgbs.length;
|
||||
|
||||
mInverseMap = new InverseColorMap(mRGBs, pTransparentIndex);
|
||||
mWhiteIndex = getWhiteIndex();
|
||||
inverseMap = new InverseColorMap(rgbs, pTransparentIndex);
|
||||
whiteIndex = getWhiteIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,19 +161,18 @@ public class InverseColorMapIndexColorModel extends IndexColorModel {
|
||||
*
|
||||
* @see IndexColorModel#IndexColorModel(int, int, byte[], byte[], byte[])
|
||||
*/
|
||||
public InverseColorMapIndexColorModel(int pNumBits, int pSize,
|
||||
byte[] pReds, byte[] pGreens, byte[] pBlues) {
|
||||
public InverseColorMapIndexColorModel(int pNumBits, int pSize, byte[] pReds, byte[] pGreens, byte[] pBlues) {
|
||||
super(pNumBits, pSize, pReds, pGreens, pBlues);
|
||||
mRGBs = getRGBs(this);
|
||||
mMapSize = mRGBs.length;
|
||||
rgbs = getRGBs(this);
|
||||
mapSize = rgbs.length;
|
||||
|
||||
mInverseMap = new InverseColorMap(mRGBs);
|
||||
mWhiteIndex = getWhiteIndex();
|
||||
inverseMap = new InverseColorMap(rgbs);
|
||||
whiteIndex = getWhiteIndex();
|
||||
}
|
||||
|
||||
private int getWhiteIndex() {
|
||||
for (int i = 0; i < mRGBs.length; i++) {
|
||||
int color = mRGBs[i];
|
||||
for (int i = 0; i < rgbs.length; i++) {
|
||||
int color = rgbs[i];
|
||||
if ((color & RGB_MASK) == WHITE) {
|
||||
return i;
|
||||
}
|
||||
@@ -244,7 +240,6 @@ public class InverseColorMapIndexColorModel extends IndexColorModel {
|
||||
*
|
||||
*/
|
||||
public Object getDataElements(int rgb, Object pixel) {
|
||||
|
||||
int alpha = (rgb>>>24);
|
||||
|
||||
int pix;
|
||||
@@ -253,11 +248,11 @@ public class InverseColorMapIndexColorModel extends IndexColorModel {
|
||||
}
|
||||
else {
|
||||
int color = rgb & RGB_MASK;
|
||||
if (color == WHITE && mWhiteIndex != -1) {
|
||||
pix = mWhiteIndex;
|
||||
if (color == WHITE && whiteIndex != -1) {
|
||||
pix = whiteIndex;
|
||||
}
|
||||
else {
|
||||
pix = mInverseMap.getIndexNearest(color);
|
||||
pix = inverseMap.getIndexNearest(color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,8 +292,7 @@ public class InverseColorMapIndexColorModel extends IndexColorModel {
|
||||
shortObj[0] = (short) pix;
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("This method has not been " +
|
||||
"implemented for transferType " + transferType);
|
||||
throw new UnsupportedOperationException("This method has not been implemented for transferType " + transferType);
|
||||
}
|
||||
return pixel;
|
||||
}
|
||||
|
@@ -54,11 +54,11 @@ final class MagickAccelerator {
|
||||
|
||||
private static final int RESAMPLE_OP = 0;
|
||||
|
||||
private static Class[] sNativeOp = new Class[1];
|
||||
private static Class[] nativeOp = new Class[1];
|
||||
|
||||
static {
|
||||
try {
|
||||
sNativeOp[RESAMPLE_OP] = Class.forName("com.twelvemonkeys.image.ResampleOp");
|
||||
nativeOp[RESAMPLE_OP] = Class.forName("com.twelvemonkeys.image.ResampleOp");
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
System.err.println("Could not find class: " + e);
|
||||
@@ -94,8 +94,8 @@ final class MagickAccelerator {
|
||||
}
|
||||
|
||||
private static int getNativeOpIndex(Class pOpClass) {
|
||||
for (int i = 0; i < sNativeOp.length; i++) {
|
||||
if (pOpClass == sNativeOp[i]) {
|
||||
for (int i = 0; i < nativeOp.length; i++) {
|
||||
if (pOpClass == nativeOp[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -112,7 +112,7 @@ final class MagickAccelerator {
|
||||
switch (getNativeOpIndex(pOperation.getClass())) {
|
||||
case RESAMPLE_OP:
|
||||
ResampleOp resample = (ResampleOp) pOperation;
|
||||
result = resampleMagick(pInput, resample.mWidth, resample.mHeight, resample.mFilterType);
|
||||
result = resampleMagick(pInput, resample.width, resample.height, resample.filterType);
|
||||
|
||||
// NOTE: If output parameter is non-null, we have to return that
|
||||
// image, instead of result
|
||||
|
@@ -33,7 +33,7 @@ import java.awt.image.*;
|
||||
/**
|
||||
* Monochrome B/W color model.
|
||||
*
|
||||
* @author Harald Kuhr
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
*/
|
||||
public class MonochromeColorModel extends IndexColorModel {
|
||||
|
||||
|
@@ -48,37 +48,37 @@ public class PixelizeOp implements BufferedImageOp, RasterOp {
|
||||
// TODO: support more raster types/color models
|
||||
// TODO: This is actually an implementation of Area Averaging, without the scale... Let's extract it...
|
||||
|
||||
final private int mPixelSizeX;
|
||||
final private int mPixelSizeY;
|
||||
final private int pixelSizeX;
|
||||
final private int pixelSizeY;
|
||||
|
||||
private Rectangle mSourceRegion;
|
||||
private Rectangle sourceRegion;
|
||||
|
||||
public PixelizeOp(final int pPixelSize) {
|
||||
this(pPixelSize, pPixelSize);
|
||||
}
|
||||
|
||||
public PixelizeOp(final int pPixelSizeX, final int pPixelSizeY) {
|
||||
mPixelSizeX = pPixelSizeX;
|
||||
mPixelSizeY = pPixelSizeY;
|
||||
pixelSizeX = pPixelSizeX;
|
||||
pixelSizeY = pPixelSizeY;
|
||||
}
|
||||
|
||||
public Rectangle getSourceRegion() {
|
||||
if (mSourceRegion == null) {
|
||||
if (sourceRegion == null) {
|
||||
return null;
|
||||
}
|
||||
return new Rectangle(mSourceRegion);
|
||||
return new Rectangle(sourceRegion);
|
||||
}
|
||||
|
||||
public void setSourceRegion(final Rectangle pSourceRegion) {
|
||||
if (pSourceRegion == null) {
|
||||
mSourceRegion = null;
|
||||
sourceRegion = null;
|
||||
}
|
||||
else {
|
||||
if (mSourceRegion == null) {
|
||||
mSourceRegion = new Rectangle(pSourceRegion);
|
||||
if (sourceRegion == null) {
|
||||
sourceRegion = new Rectangle(pSourceRegion);
|
||||
}
|
||||
else {
|
||||
mSourceRegion.setBounds(pSourceRegion);
|
||||
sourceRegion.setBounds(pSourceRegion);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,11 +107,11 @@ public class PixelizeOp implements BufferedImageOp, RasterOp {
|
||||
private WritableRaster filterImpl(Raster src, WritableRaster dest) {
|
||||
//System.out.println("src: " + src);
|
||||
//System.out.println("dest: " + dest);
|
||||
if (mSourceRegion != null) {
|
||||
int cx = mSourceRegion.x;
|
||||
int cy = mSourceRegion.y;
|
||||
int cw = mSourceRegion.width;
|
||||
int ch = mSourceRegion.height;
|
||||
if (sourceRegion != null) {
|
||||
int cx = sourceRegion.x;
|
||||
int cy = sourceRegion.y;
|
||||
int cw = sourceRegion.width;
|
||||
int ch = sourceRegion.height;
|
||||
|
||||
boolean same = src == dest;
|
||||
dest = dest.createWritableChild(cx, cy, cw, ch, 0, 0, null);
|
||||
@@ -122,8 +122,8 @@ public class PixelizeOp implements BufferedImageOp, RasterOp {
|
||||
|
||||
final int width = src.getWidth();
|
||||
final int height = src.getHeight();
|
||||
int w = (width + mPixelSizeX - 1) / mPixelSizeX;
|
||||
int h = (height + mPixelSizeY - 1) / mPixelSizeY;
|
||||
int w = (width + pixelSizeX - 1) / pixelSizeX;
|
||||
int h = (height + pixelSizeY - 1) / pixelSizeY;
|
||||
|
||||
final boolean oddX = width % w != 0;
|
||||
final boolean oddY = height % h != 0;
|
||||
@@ -156,23 +156,23 @@ public class PixelizeOp implements BufferedImageOp, RasterOp {
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
if (!oddY || y + 1 < h) {
|
||||
scanH = mPixelSizeY;
|
||||
scanH = pixelSizeY;
|
||||
}
|
||||
else {
|
||||
scanH = height - (y * mPixelSizeY);
|
||||
scanH = height - (y * pixelSizeY);
|
||||
}
|
||||
|
||||
for (int x = 0; x < w; x++) {
|
||||
if (!oddX || x + 1 < w) {
|
||||
scanW = mPixelSizeX;
|
||||
scanW = pixelSizeX;
|
||||
}
|
||||
else {
|
||||
scanW = width - (x * mPixelSizeX);
|
||||
scanW = width - (x * pixelSizeX);
|
||||
}
|
||||
final int pixelCount = scanW * scanH;
|
||||
final int pixelLength = pixelCount * dataElements;
|
||||
|
||||
data = src.getDataElements(x * mPixelSizeX, y * mPixelSizeY, scanW, scanH, data);
|
||||
data = src.getDataElements(x * pixelSizeX, y * pixelSizeY, scanW, scanH, data);
|
||||
|
||||
// NOTE: These are not neccessarily ARGB..
|
||||
double valueA = 0.0;
|
||||
@@ -277,7 +277,7 @@ public class PixelizeOp implements BufferedImageOp, RasterOp {
|
||||
|
||||
}
|
||||
|
||||
dest.setDataElements(x * mPixelSizeX, y * mPixelSizeY, scanW, scanH, data);
|
||||
dest.setDataElements(x * pixelSizeX, y * pixelSizeY, scanW, scanH, data);
|
||||
}
|
||||
}
|
||||
/*/
|
||||
|
@@ -60,7 +60,6 @@ import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.*;
|
||||
|
||||
|
||||
/**
|
||||
* Resamples (scales) a {@code BufferedImage} to a new width and height, using
|
||||
* high performance and high quality algorithms.
|
||||
@@ -138,7 +137,7 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
// MagickAccelerator to work consistently (see magick.FilterType).
|
||||
|
||||
/**
|
||||
* Undefined interpolation, filter method will use default filter
|
||||
* Undefined interpolation, filter method will use default filter.
|
||||
*/
|
||||
public final static int FILTER_UNDEFINED = 0;
|
||||
/**
|
||||
@@ -194,11 +193,11 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
/**
|
||||
* Mitchell interpolation. High quality.
|
||||
*/
|
||||
public final static int FILTER_MITCHELL = 12;// IM default scale with palette or alpha, or scale up
|
||||
public final static int FILTER_MITCHELL = 12; // IM default scale with palette or alpha, or scale up
|
||||
/**
|
||||
* Lanczos interpolation. High quality.
|
||||
*/
|
||||
public final static int FILTER_LANCZOS = 13;// IM default
|
||||
public final static int FILTER_LANCZOS = 13; // IM default
|
||||
/**
|
||||
* Blackman-Bessel interpolation. High quality.
|
||||
*/
|
||||
@@ -291,10 +290,10 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
|
||||
// Member variables
|
||||
// Package access, to allow access from MagickAccelerator
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
int mFilterType;
|
||||
int filterType;
|
||||
private static final boolean TRANSFORM_OP_BICUBIC_SUPPORT = SystemUtil.isFieldAvailable(AffineTransformOp.class.getName(), "TYPE_BICUBIC");
|
||||
|
||||
/**
|
||||
@@ -302,14 +301,13 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
*/
|
||||
// TODO: Move to abstract class AbstractBufferedImageOp?
|
||||
static class Key extends RenderingHints.Key {
|
||||
|
||||
static int sIndex = 10000;
|
||||
|
||||
private final String mName;
|
||||
private final String name;
|
||||
|
||||
public Key(final String pName) {
|
||||
super(sIndex++);
|
||||
mName = pName;
|
||||
name = pName;
|
||||
}
|
||||
|
||||
public boolean isCompatibleValue(Object pValue) {
|
||||
@@ -317,7 +315,7 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return mName;
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,27 +324,27 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
*/
|
||||
// TODO: Extract abstract Value class, and move to AbstractBufferedImageOp
|
||||
static final class Value {
|
||||
final private RenderingHints.Key mKey;
|
||||
final private String mName;
|
||||
final private int mType;
|
||||
final private RenderingHints.Key key;
|
||||
final private String name;
|
||||
final private int type;
|
||||
|
||||
public Value(final RenderingHints.Key pKey, final String pName, final int pType) {
|
||||
mKey = pKey;
|
||||
mName = pName;
|
||||
key = pKey;
|
||||
name = pName;
|
||||
validateFilterType(pType);
|
||||
mType = pType;// TODO: test for duplicates
|
||||
type = pType;// TODO: test for duplicates
|
||||
}
|
||||
|
||||
public boolean isCompatibleKey(Key pKey) {
|
||||
return pKey == mKey;
|
||||
return pKey == key;
|
||||
}
|
||||
|
||||
public int getFilterType() {
|
||||
return mType;
|
||||
return type;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return mName;
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,11 +352,11 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
* Creates a {@code ResampleOp} that will resample input images to the
|
||||
* given width and height, using the default interpolation filter.
|
||||
*
|
||||
* @param pWidth width of the resampled image
|
||||
* @param pHeight height of the resampled image
|
||||
* @param width width of the re-sampled image
|
||||
* @param height height of the re-sampled image
|
||||
*/
|
||||
public ResampleOp(int pWidth, int pHeight) {
|
||||
this(pWidth, pHeight, FILTER_UNDEFINED);
|
||||
public ResampleOp(int width, int height) {
|
||||
this(width, height, FILTER_UNDEFINED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -394,38 +392,38 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
* </ul>
|
||||
* Other hints have no effect on this filter.
|
||||
*
|
||||
* @param pWidth width of the resampled image
|
||||
* @param pHeight height of the resampled image
|
||||
* @param pHints rendering hints, affecting interpolation algorithm
|
||||
* @param width width of the re-sampled image
|
||||
* @param height height of the re-sampled image
|
||||
* @param hints rendering hints, affecting interpolation algorithm
|
||||
* @see #KEY_RESAMPLE_INTERPOLATION
|
||||
* @see RenderingHints#KEY_INTERPOLATION
|
||||
* @see RenderingHints#KEY_RENDERING
|
||||
* @see RenderingHints#KEY_COLOR_RENDERING
|
||||
*/
|
||||
public ResampleOp(int pWidth, int pHeight, RenderingHints pHints) {
|
||||
this(pWidth, pHeight, getFilterType(pHints));
|
||||
public ResampleOp(int width, int height, RenderingHints hints) {
|
||||
this(width, height, getFilterType(hints));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code ResampleOp} that will resample input images to the
|
||||
* given width and height, using the given interpolation filter.
|
||||
*
|
||||
* @param pWidth width of the resampled image
|
||||
* @param pHeight height of the resampled image
|
||||
* @param pFilterType interpolation filter algorithm
|
||||
* @param width width of the re-sampled image
|
||||
* @param height height of the re-sampled image
|
||||
* @param filterType interpolation filter algorithm
|
||||
* @see <a href="#field_summary">filter type constants</a>
|
||||
*/
|
||||
public ResampleOp(int pWidth, int pHeight, int pFilterType) {
|
||||
if (pWidth <= 0 || pHeight <= 0) {
|
||||
public ResampleOp(int width, int height, int filterType) {
|
||||
if (width <= 0 || height <= 0) {
|
||||
// NOTE: w/h == 0 makes the Magick DLL crash and the JVM dies.. :-P
|
||||
throw new IllegalArgumentException("width and height must be positive");
|
||||
}
|
||||
|
||||
mWidth = pWidth;
|
||||
mHeight = pHeight;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
validateFilterType(pFilterType);
|
||||
mFilterType = pFilterType;
|
||||
validateFilterType(filterType);
|
||||
this.filterType = filterType;
|
||||
}
|
||||
|
||||
private static void validateFilterType(int pFilterType) {
|
||||
@@ -471,25 +469,21 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
}
|
||||
return value != null ? ((Value) value).getFilterType() : FILTER_UNDEFINED;
|
||||
}
|
||||
else
|
||||
if (RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR.equals(pHints.get(RenderingHints.KEY_INTERPOLATION))
|
||||
else if (RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR.equals(pHints.get(RenderingHints.KEY_INTERPOLATION))
|
||||
|| (!pHints.containsKey(RenderingHints.KEY_INTERPOLATION)
|
||||
&& (RenderingHints.VALUE_RENDER_SPEED.equals(pHints.get(RenderingHints.KEY_RENDERING))
|
||||
|| RenderingHints.VALUE_COLOR_RENDER_SPEED.equals(pHints.get(RenderingHints.KEY_COLOR_RENDERING))))) {
|
||||
// Nearest neighbour, or prioritze speed
|
||||
// Nearest neighbour, or prioritize speed
|
||||
return FILTER_POINT;
|
||||
}
|
||||
else
|
||||
if (RenderingHints.VALUE_INTERPOLATION_BILINEAR.equals(pHints.get(RenderingHints.KEY_INTERPOLATION))) {
|
||||
else if (RenderingHints.VALUE_INTERPOLATION_BILINEAR.equals(pHints.get(RenderingHints.KEY_INTERPOLATION))) {
|
||||
// Triangle equals bi-linear interpolation
|
||||
return FILTER_TRIANGLE;
|
||||
}
|
||||
else
|
||||
if (RenderingHints.VALUE_INTERPOLATION_BICUBIC.equals(pHints.get(RenderingHints.KEY_INTERPOLATION))) {
|
||||
else if (RenderingHints.VALUE_INTERPOLATION_BICUBIC.equals(pHints.get(RenderingHints.KEY_INTERPOLATION))) {
|
||||
return FILTER_QUADRATIC;// No idea if this is correct..?
|
||||
}
|
||||
else
|
||||
if (RenderingHints.VALUE_RENDER_QUALITY.equals(pHints.get(RenderingHints.KEY_RENDERING))
|
||||
else if (RenderingHints.VALUE_RENDER_QUALITY.equals(pHints.get(RenderingHints.KEY_RENDERING))
|
||||
|| RenderingHints.VALUE_COLOR_RENDER_QUALITY.equals(pHints.get(RenderingHints.KEY_COLOR_RENDERING))) {
|
||||
// Prioritize quality
|
||||
return FILTER_MITCHELL;
|
||||
@@ -500,83 +494,88 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
}
|
||||
|
||||
/**
|
||||
* Resamples (scales) the image to the size, and using the algorithm
|
||||
* Re-samples (scales) the image to the size, and using the algorithm
|
||||
* specified in the constructor.
|
||||
*
|
||||
* @param pInput The {@code BufferedImage} to be filtered
|
||||
* @param pOutput The {@code BufferedImage} in which to store the resampled
|
||||
* @param input The {@code BufferedImage} to be filtered
|
||||
* @param output The {@code BufferedImage} in which to store the resampled
|
||||
* image
|
||||
* @return The resampled {@code BufferedImage}.
|
||||
* @throws NullPointerException if {@code pInput} is {@code null}
|
||||
* @throws IllegalArgumentException if {@code pInput == pOutput}.
|
||||
* @return The re-sampled {@code BufferedImage}.
|
||||
* @throws NullPointerException if {@code input} is {@code null}
|
||||
* @throws IllegalArgumentException if {@code input == output}.
|
||||
* @see #ResampleOp(int,int,int)
|
||||
*/
|
||||
public final BufferedImage filter(final BufferedImage pInput, final BufferedImage pOutput) {
|
||||
if (pInput == null) {
|
||||
public final BufferedImage filter(final BufferedImage input, final BufferedImage output) {
|
||||
if (input == null) {
|
||||
throw new NullPointerException("Input == null");
|
||||
}
|
||||
if (pInput == pOutput) {
|
||||
if (input == output) {
|
||||
throw new IllegalArgumentException("Output image cannot be the same as the input image");
|
||||
}
|
||||
|
||||
InterpolationFilter filter;
|
||||
|
||||
|
||||
// Special case for POINT, TRIANGLE and QUADRATIC filter, as standard
|
||||
// Java implementation is very fast (possibly H/W accellerated)
|
||||
switch (mFilterType) {
|
||||
// Java implementation is very fast (possibly H/W accelerated)
|
||||
switch (filterType) {
|
||||
case FILTER_POINT:
|
||||
return fastResample(pInput, pOutput, mWidth, mHeight, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
|
||||
case FILTER_TRIANGLE:
|
||||
return fastResample(pInput, pOutput, mWidth, mHeight, AffineTransformOp.TYPE_BILINEAR);
|
||||
case FILTER_QUADRATIC:
|
||||
if (TRANSFORM_OP_BICUBIC_SUPPORT) {
|
||||
return fastResample(pInput, pOutput, mWidth, mHeight, 3); // AffineTransformOp.TYPE_BICUBIC
|
||||
if (input.getType() != BufferedImage.TYPE_CUSTOM) {
|
||||
return fastResample(input, output, width, height, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
|
||||
}
|
||||
// Fall through
|
||||
// Else fall through
|
||||
case FILTER_TRIANGLE:
|
||||
if (input.getType() != BufferedImage.TYPE_CUSTOM) {
|
||||
return fastResample(input, output, width, height, AffineTransformOp.TYPE_BILINEAR);
|
||||
}
|
||||
// Else fall through
|
||||
case FILTER_QUADRATIC:
|
||||
if (input.getType() != BufferedImage.TYPE_CUSTOM && TRANSFORM_OP_BICUBIC_SUPPORT) {
|
||||
return fastResample(input, output, width, height, 3); // AffineTransformOp.TYPE_BICUBIC
|
||||
}
|
||||
// Else fall through
|
||||
default:
|
||||
filter = createFilter(mFilterType);
|
||||
filter = createFilter(filterType);
|
||||
// NOTE: Workaround for filter throwing exceptions when input or output is less than support...
|
||||
if (Math.min(pInput.getWidth(), pInput.getHeight()) <= filter.support() || Math.min(mWidth, mHeight) <= filter.support()) {
|
||||
return fastResample(pInput, pOutput, mWidth, mHeight, AffineTransformOp.TYPE_BILINEAR);
|
||||
if (Math.min(input.getWidth(), input.getHeight()) <= filter.support() || Math.min(width, height) <= filter.support()) {
|
||||
return fastResample(input, output, width, height, AffineTransformOp.TYPE_BILINEAR);
|
||||
}
|
||||
// Fall through
|
||||
}
|
||||
|
||||
|
||||
// Try to use native ImageMagick code
|
||||
BufferedImage result = MagickAccelerator.filter(this, pInput, pOutput);
|
||||
BufferedImage result = MagickAccelerator.filter(this, input, output);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Otherwise, continue in pure Java mode
|
||||
|
||||
// TODO: What if pOutput != null and wrong size? Create new? Render on only a part? Document?
|
||||
// TODO: What if output != null and wrong size? Create new? Render on only a part? Document?
|
||||
|
||||
// If filter type != POINT or BOX an input has IndexColorModel, convert
|
||||
// to true color, with alpha reflecting that of the original colormodel.
|
||||
BufferedImage input;
|
||||
// to true color, with alpha reflecting that of the original color model.
|
||||
BufferedImage temp;
|
||||
ColorModel cm;
|
||||
if (mFilterType != FILTER_BOX && (cm = pInput.getColorModel()) instanceof IndexColorModel) {
|
||||
// TODO: OPTIMIZE: If colormodel has only b/w or gray, we could skip color info
|
||||
input = ImageUtil.toBuffered(pInput, cm.hasAlpha() ? BufferedImage.TYPE_4BYTE_ABGR : BufferedImage.TYPE_3BYTE_BGR);
|
||||
if (filterType != FILTER_POINT && filterType != FILTER_BOX && (cm = input.getColorModel()) instanceof IndexColorModel) {
|
||||
// TODO: OPTIMIZE: If color model has only b/w or gray, we could skip color info
|
||||
temp = ImageUtil.toBuffered(input, cm.hasAlpha() ? BufferedImage.TYPE_4BYTE_ABGR : BufferedImage.TYPE_3BYTE_BGR);
|
||||
}
|
||||
else {
|
||||
input = pInput;
|
||||
temp = input;
|
||||
}
|
||||
|
||||
// Create or convert output to a suitable image
|
||||
// TODO: OPTIMIZE: Don't really need to convert all types to same as input
|
||||
result = pOutput != null ? /*pOutput*/ ImageUtil.toBuffered(pOutput, input.getType()) : createCompatibleDestImage(input, null);
|
||||
result = output != null && temp.getType() != BufferedImage.TYPE_CUSTOM ? /*output*/ ImageUtil.toBuffered(output, temp.getType()) : createCompatibleDestImage(temp, null);
|
||||
// result = output != null ? output : createCompatibleDestImage(temp, null);
|
||||
|
||||
resample(input, result, filter);
|
||||
resample(temp, result, filter);
|
||||
|
||||
// If pOutput != null and needed to be converted, draw it back
|
||||
if (pOutput != null && pOutput != result) {
|
||||
//pOutput.setData(output.getRaster());
|
||||
ImageUtil.drawOnto(pOutput, result);
|
||||
result = pOutput;
|
||||
// If output != null and needed to be converted, draw it back
|
||||
if (output != null && output != result) {
|
||||
//output.setData(output.getRaster());
|
||||
ImageUtil.drawOnto(output, result);
|
||||
result = output;
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -672,8 +671,8 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
}
|
||||
*/
|
||||
|
||||
private static BufferedImage fastResample(final BufferedImage pInput, final BufferedImage pOutput, final int pWidth, final int pHeight, final int pType) {
|
||||
BufferedImage temp = pInput;
|
||||
private static BufferedImage fastResample(final BufferedImage input, final BufferedImage output, final int width, final int height, final int type) {
|
||||
BufferedImage temp = input;
|
||||
|
||||
double xScale;
|
||||
double yScale;
|
||||
@@ -681,20 +680,20 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
AffineTransform transform;
|
||||
AffineTransformOp scale;
|
||||
|
||||
if (pType > AffineTransformOp.TYPE_NEAREST_NEIGHBOR) {
|
||||
if (type > AffineTransformOp.TYPE_NEAREST_NEIGHBOR) {
|
||||
// Initially scale so all remaining operations will halve the image
|
||||
if (pWidth < pInput.getWidth() || pHeight < pInput.getHeight()) {
|
||||
int w = pWidth;
|
||||
int h = pHeight;
|
||||
while (w < pInput.getWidth() / 2) {
|
||||
if (width < input.getWidth() || height < input.getHeight()) {
|
||||
int w = width;
|
||||
int h = height;
|
||||
while (w < input.getWidth() / 2) {
|
||||
w *= 2;
|
||||
}
|
||||
while (h < pInput.getHeight() / 2) {
|
||||
while (h < input.getHeight() / 2) {
|
||||
h *= 2;
|
||||
}
|
||||
|
||||
xScale = w / (double) pInput.getWidth();
|
||||
yScale = h / (double) pInput.getHeight();
|
||||
xScale = w / (double) input.getWidth();
|
||||
yScale = h / (double) input.getHeight();
|
||||
|
||||
//System.out.println("First scale by x=" + xScale + ", y=" + yScale);
|
||||
|
||||
@@ -704,12 +703,12 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
}
|
||||
}
|
||||
|
||||
scale = null;// NOTE: This resets!
|
||||
scale = null; // NOTE: This resets!
|
||||
|
||||
xScale = pWidth / (double) temp.getWidth();
|
||||
yScale = pHeight / (double) temp.getHeight();
|
||||
xScale = width / (double) temp.getWidth();
|
||||
yScale = height / (double) temp.getHeight();
|
||||
|
||||
if (pType > AffineTransformOp.TYPE_NEAREST_NEIGHBOR) {
|
||||
if (type > AffineTransformOp.TYPE_NEAREST_NEIGHBOR) {
|
||||
// TODO: Test skipping first scale (above), and instead scale once
|
||||
// more here, and a little less than .5 each time...
|
||||
// That would probably make the scaling smoother...
|
||||
@@ -740,17 +739,15 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
}
|
||||
|
||||
temp = scale.filter(temp, null);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//System.out.println("Rest to scale by x=" + xScale + ", y=" + yScale);
|
||||
|
||||
transform = AffineTransform.getScaleInstance(xScale, yScale);
|
||||
scale = new AffineTransformOp(transform, pType);
|
||||
|
||||
return scale.filter(temp, pOutput);
|
||||
scale = new AffineTransformOp(transform, type);
|
||||
|
||||
return scale.filter(temp, output);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -760,7 +757,7 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
* @see <a href="#field_summary">filter type constants</a>
|
||||
*/
|
||||
public int getFilterType() {
|
||||
return mFilterType;
|
||||
return filterType;
|
||||
}
|
||||
|
||||
private static InterpolationFilter createFilter(int pFilterType) {
|
||||
@@ -770,7 +767,8 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
}
|
||||
|
||||
switch (pFilterType) {
|
||||
//case FILTER_POINT: // Should never happen
|
||||
case FILTER_POINT:
|
||||
return new PointFilter();
|
||||
case FILTER_BOX:
|
||||
return new BoxFilter();
|
||||
case FILTER_TRIANGLE:
|
||||
@@ -815,14 +813,14 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
// If indexcolormodel, we probably don't want to use that...
|
||||
// NOTE: Either BOTH or NONE of the images must have ALPHA
|
||||
|
||||
return new BufferedImage(cm, ImageUtil.createCompatibleWritableRaster(pInput, cm, mWidth, mHeight),
|
||||
return new BufferedImage(cm, ImageUtil.createCompatibleWritableRaster(pInput, cm, width, height),
|
||||
cm.isAlphaPremultiplied(), null);
|
||||
|
||||
}
|
||||
|
||||
public RenderingHints getRenderingHints() {
|
||||
Object value;
|
||||
switch (mFilterType) {
|
||||
switch (filterType) {
|
||||
case FILTER_UNDEFINED:
|
||||
return null;
|
||||
case FILTER_POINT:
|
||||
@@ -871,14 +869,14 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
value = VALUE_INTERPOLATION_BLACKMAN_SINC;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown filter type: " + mFilterType);
|
||||
throw new IllegalStateException("Unknown filter type: " + filterType);
|
||||
}
|
||||
|
||||
return new RenderingHints(KEY_RESAMPLE_INTERPOLATION, value);
|
||||
}
|
||||
|
||||
public Rectangle2D getBounds2D(BufferedImage src) {
|
||||
return new Rectangle(mWidth, mHeight);
|
||||
return new Rectangle(width, height);
|
||||
}
|
||||
|
||||
public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
|
||||
@@ -1439,10 +1437,8 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
resample()
|
||||
|
||||
Resizes bitmaps while resampling them.
|
||||
Returns -1 if error, 0 if success.
|
||||
*/
|
||||
private BufferedImage resample(BufferedImage pSource, BufferedImage pDest, InterpolationFilter pFilter) {
|
||||
// TODO: Don't work... Could fix by creating a temporary image in filter method
|
||||
final int dstWidth = pDest.getWidth();
|
||||
final int dstHeight = pDest.getHeight();
|
||||
|
||||
@@ -1451,7 +1447,8 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
|
||||
/* create intermediate column to hold horizontal dst column zoom */
|
||||
final ColorModel cm = pSource.getColorModel();
|
||||
final WritableRaster work = cm.createCompatibleWritableRaster(1, srcHeight);
|
||||
// final WritableRaster work = cm.createCompatibleWritableRaster(1, srcHeight);
|
||||
final WritableRaster work = ImageUtil.createCompatibleWritableRaster(pSource, cm, 1, srcHeight);
|
||||
|
||||
double xscale = (double) dstWidth / (double) srcWidth;
|
||||
double yscale = (double) dstHeight / (double) srcHeight;
|
||||
@@ -1566,7 +1563,7 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
final WritableRaster out = pDest.getRaster();
|
||||
|
||||
// TODO: This is not optimal for non-byte-packed rasters...
|
||||
// (What? Maybe I implemented the fix, but forgot to remove the qTODO?)
|
||||
// (What? Maybe I implemented the fix, but forgot to remove the TODO?)
|
||||
final int numChannels = raster.getNumBands();
|
||||
final int[] channelMax = new int[numChannels];
|
||||
for (int k = 0; k < numChannels; k++) {
|
||||
@@ -1575,7 +1572,7 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
|
||||
for (int xx = 0; xx < dstWidth; xx++) {
|
||||
ContributorList contribX = calcXContrib(xscale, fwidth, srcWidth, pFilter, xx);
|
||||
/* Apply horz filter to make dst column in tmp. */
|
||||
/* Apply horiz filter to make dst column in tmp. */
|
||||
for (int k = 0; k < srcHeight; k++) {
|
||||
for (int channel = 0; channel < numChannels; channel++) {
|
||||
|
||||
|
@@ -42,8 +42,8 @@ import java.awt.image.ReplicateScaleFilter;
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/SubsamplingFilter.java#1 $
|
||||
*/
|
||||
public class SubsamplingFilter extends ReplicateScaleFilter {
|
||||
private int mXSub;
|
||||
private int mYSub;
|
||||
private int xSub;
|
||||
private int ySub;
|
||||
|
||||
/**
|
||||
* Creates a {@code SubsamplingFilter}.
|
||||
@@ -62,16 +62,16 @@ public class SubsamplingFilter extends ReplicateScaleFilter {
|
||||
throw new IllegalArgumentException("Subsampling factors must be positive.");
|
||||
}
|
||||
|
||||
mXSub = pXSub;
|
||||
mYSub = pYSub;
|
||||
xSub = pXSub;
|
||||
ySub = pYSub;
|
||||
}
|
||||
|
||||
/** {@code ImageFilter} implementation, do not invoke. */
|
||||
public void setDimensions(int pWidth, int pHeight) {
|
||||
destWidth = (pWidth + mXSub - 1) / mXSub;
|
||||
destHeight = (pHeight + mYSub - 1) / mYSub;
|
||||
destWidth = (pWidth + xSub - 1) / xSub;
|
||||
destHeight = (pHeight + ySub - 1) / ySub;
|
||||
|
||||
//System.out.println("Subsampling: " + mXSub + "," + mYSub + "-> " + destWidth + ", " + destHeight);
|
||||
//System.out.println("Subsampling: " + xSub + "," + ySub + "-> " + destWidth + ", " + destHeight);
|
||||
super.setDimensions(pWidth, pHeight);
|
||||
}
|
||||
}
|
||||
|
@@ -4,6 +4,6 @@
|
||||
* See the class {@link com.twelvemonkeys.image.ImageUtil}.
|
||||
*
|
||||
* @version 1.0
|
||||
* @author <a href="mailto:harald@escenic.com">Harald Kuhr</a>
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
*/
|
||||
package com.twelvemonkeys.image;
|
@@ -0,0 +1,206 @@
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.net.URL;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* BufferedImageFactoryTestCase
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: BufferedImageFactoryTestCase.java,v 1.0 May 7, 2010 12:40:08 PM haraldk Exp$
|
||||
*/
|
||||
public class BufferedImageFactoryTestCase {
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCreateNullImage() {
|
||||
new BufferedImageFactory((Image) null);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCreateNullProducer() {
|
||||
new BufferedImageFactory((ImageProducer) null);
|
||||
}
|
||||
|
||||
// Image source = Toolkit.getDefaultToolkit().createImage((byte[]) null); // - NPE in Toolkit, ok
|
||||
|
||||
@Test(timeout = 1000, expected = IllegalArgumentException.class)
|
||||
public void testGetBufferedImageErrorSourceIP() {
|
||||
Image source = Toolkit.getDefaultToolkit().createImage((ImageProducer) null);
|
||||
|
||||
new BufferedImageFactory(source);
|
||||
}
|
||||
|
||||
// TODO: This is a quite serious bug, but it can be argued that the bug is in the
|
||||
// Toolkit, allowing such images in the first place... In any case, there's
|
||||
// not much we can do, except until someone is bored and kills the app... :-P
|
||||
/*
|
||||
@Test(timeout = 1000, expected = ImageConversionException.class)
|
||||
public void testGetBufferedImageErrorSourceString() {
|
||||
Image source = Toolkit.getDefaultToolkit().createImage((String) null);
|
||||
|
||||
BufferedImageFactory factory = new BufferedImageFactory(source);
|
||||
factory.getBufferedImage();
|
||||
}
|
||||
*/
|
||||
|
||||
// This is a little random, and it would be nicer if we could throw an IllegalArgumentException on create.
|
||||
// Unfortunately, the API doesn't allow this...
|
||||
@Test(timeout = 1000, expected = ImageConversionException.class)
|
||||
public void testGetBufferedImageErrorSourceURL() {
|
||||
Image source = Toolkit.getDefaultToolkit().createImage(getClass().getResource("/META-INF/MANIFEST.MF"));
|
||||
|
||||
BufferedImageFactory factory = new BufferedImageFactory(source);
|
||||
factory.getBufferedImage();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBufferedImageJPEG() {
|
||||
URL resource = getClass().getResource("/sunflower.jpg");
|
||||
assertNotNull(resource);
|
||||
Image source = Toolkit.getDefaultToolkit().createImage(resource);
|
||||
assertNotNull(source);
|
||||
|
||||
BufferedImageFactory factory = new BufferedImageFactory(source);
|
||||
BufferedImage image = factory.getBufferedImage();
|
||||
|
||||
assertEquals(187, image.getWidth());
|
||||
assertEquals(283, image.getHeight());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetColorModelJPEG() {
|
||||
URL resource = getClass().getResource("/sunflower.jpg");
|
||||
assertNotNull(resource);
|
||||
Image source = Toolkit.getDefaultToolkit().createImage(resource);
|
||||
assertNotNull(source);
|
||||
|
||||
BufferedImageFactory factory = new BufferedImageFactory(source);
|
||||
ColorModel colorModel = factory.getColorModel();
|
||||
|
||||
assertNotNull(colorModel);
|
||||
assertEquals(3, colorModel.getNumColorComponents()); // getNumComponents may include alpha, we don't care
|
||||
assertEquals(ColorSpace.getInstance(ColorSpace.CS_sRGB), colorModel.getColorSpace());
|
||||
|
||||
for (int i = 0; i < colorModel.getNumComponents(); i++) {
|
||||
assertEquals(8, colorModel.getComponentSize(i));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Test a GIF or PNG with PLTE chunk, and make sure we get an IndexColorModel
|
||||
|
||||
@Test
|
||||
public void testGetBufferedImageSubsampled() {
|
||||
URL resource = getClass().getResource("/sunflower.jpg");
|
||||
assertNotNull(resource);
|
||||
Image source = Toolkit.getDefaultToolkit().createImage(resource);
|
||||
assertNotNull(source);
|
||||
|
||||
BufferedImageFactory factory = new BufferedImageFactory(source);
|
||||
BufferedImage original = factory.getBufferedImage();
|
||||
|
||||
factory.setSourceSubsampling(2, 2);
|
||||
BufferedImage image = factory.getBufferedImage(); // Accidentally also tests reuse...
|
||||
|
||||
// Values rounded up
|
||||
assertEquals(94, image.getWidth());
|
||||
assertEquals(142, image.getHeight());
|
||||
|
||||
for (int y = 0; y < image.getHeight(); y++) {
|
||||
for (int x = 0; x < image.getWidth(); x++) {
|
||||
assertEquals("RGB[" + x + ", " + y + "]", original.getRGB(x * 2, y * 2), image.getRGB(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBufferedImageSourceRegion() {
|
||||
URL resource = getClass().getResource("/sunflower.jpg");
|
||||
assertNotNull(resource);
|
||||
Image source = Toolkit.getDefaultToolkit().createImage(resource);
|
||||
assertNotNull(source);
|
||||
|
||||
BufferedImageFactory factory = new BufferedImageFactory(source);
|
||||
BufferedImage original = factory.getBufferedImage();
|
||||
|
||||
factory.setSourceRegion(new Rectangle(40, 40, 40, 40));
|
||||
BufferedImage image = factory.getBufferedImage(); // Accidentally also tests reuse...
|
||||
|
||||
assertEquals(40, image.getWidth());
|
||||
assertEquals(40, image.getHeight());
|
||||
|
||||
for (int y = 0; y < image.getHeight(); y++) {
|
||||
for (int x = 0; x < image.getWidth(); x++) {
|
||||
assertEquals("RGB[" + x + ", " + y + "]", original.getRGB(40 + x, 40 + y), image.getRGB(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBufferedImageSubsampledSourceRegion() throws Exception{
|
||||
URL resource = getClass().getResource("/sunflower.jpg");
|
||||
assertNotNull(resource);
|
||||
Image source = Toolkit.getDefaultToolkit().createImage(resource);
|
||||
assertNotNull(source);
|
||||
|
||||
BufferedImageFactory factory = new BufferedImageFactory(source);
|
||||
BufferedImage original = factory.getBufferedImage();
|
||||
|
||||
factory.setSourceRegion(new Rectangle(40, 40, 40, 40));
|
||||
factory.setSourceSubsampling(2, 2);
|
||||
BufferedImage image = factory.getBufferedImage(); // Accidentally also tests reuse...
|
||||
|
||||
assertEquals(20, image.getWidth());
|
||||
assertEquals(20, image.getHeight());
|
||||
|
||||
for (int y = 0; y < image.getHeight(); y++) {
|
||||
for (int x = 0; x < image.getWidth(); x++) {
|
||||
assertEquals("RGB[" + x + ", " + y + "]", original.getRGB(40 + x * 2, 40 + y * 2), image.getRGB(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListener() {
|
||||
URL resource = getClass().getResource("/sunflower.jpg");
|
||||
assertNotNull(resource);
|
||||
Image source = Toolkit.getDefaultToolkit().createImage(resource);
|
||||
assertNotNull(source);
|
||||
|
||||
BufferedImageFactory factory = new BufferedImageFactory(source);
|
||||
|
||||
VerifyingListener listener = new VerifyingListener(factory);
|
||||
factory.addProgressListener(listener);
|
||||
factory.getBufferedImage();
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
private static class VerifyingListener implements BufferedImageFactory.ProgressListener {
|
||||
private final BufferedImageFactory factory;
|
||||
private float progress;
|
||||
|
||||
public VerifyingListener(BufferedImageFactory factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
public void progress(BufferedImageFactory pFactory, float pPercentage) {
|
||||
assertEquals(factory, pFactory);
|
||||
assertTrue(pPercentage >= progress && pPercentage <= 100f);
|
||||
|
||||
progress = pPercentage;
|
||||
}
|
||||
|
||||
|
||||
public void verify() {
|
||||
assertEquals(100f, progress, .1f); // Sanity test that the listener was invoked
|
||||
}
|
||||
}
|
||||
}
|
@@ -24,35 +24,35 @@ import java.lang.reflect.InvocationTargetException;
|
||||
public class ImageUtilTestCase extends TestCase {
|
||||
|
||||
private final static String IMAGE_NAME = "/sunflower.jpg";
|
||||
private BufferedImage mOriginal;
|
||||
private BufferedImage mImage;
|
||||
private Image mScaled;
|
||||
private BufferedImage original;
|
||||
private BufferedImage image;
|
||||
private Image scaled;
|
||||
|
||||
public ImageUtilTestCase() throws Exception {
|
||||
mImage = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
|
||||
mScaled = mImage.getScaledInstance(5, 5, Image.SCALE_FAST);
|
||||
image = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
|
||||
scaled = image.getScaledInstance(5, 5, Image.SCALE_FAST);
|
||||
|
||||
// Read image from class path
|
||||
InputStream is = getClass().getResourceAsStream(IMAGE_NAME);
|
||||
mOriginal = ImageIO.read(is);
|
||||
original = ImageIO.read(is);
|
||||
|
||||
assertNotNull(mOriginal);
|
||||
assertNotNull(original);
|
||||
}
|
||||
|
||||
/*
|
||||
public void setUp() throws Exception {
|
||||
mImage = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
|
||||
mScaled = mImage.getScaledInstance(5, 5, Image.SCALE_FAST);
|
||||
image = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
|
||||
scaled = image.getScaledInstance(5, 5, Image.SCALE_FAST);
|
||||
|
||||
// Read image from class path
|
||||
InputStream is = ClassLoader.getSystemResourceAsStream(IMAGE_NAME);
|
||||
mOriginal = ImageIO.read(is);
|
||||
original = ImageIO.read(is);
|
||||
|
||||
assertNotNull(mOriginal);
|
||||
assertNotNull(original);
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
mOriginal = null;
|
||||
original = null;
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -94,20 +94,20 @@ public class ImageUtilTestCase extends TestCase {
|
||||
// Should not be a buffered image
|
||||
assertFalse(
|
||||
"FOR SOME IMPLEMENTATIONS THIS MIGHT FAIL!\nIn that case, testToBufferedImage() will fail too.",
|
||||
mScaled instanceof BufferedImage
|
||||
scaled instanceof BufferedImage
|
||||
);
|
||||
}
|
||||
|
||||
public void testToBufferedImage() {
|
||||
BufferedImage sameAsImage = ImageUtil.toBuffered((RenderedImage) mImage);
|
||||
BufferedImage bufferedScaled = ImageUtil.toBuffered(mScaled);
|
||||
BufferedImage sameAsImage = ImageUtil.toBuffered((RenderedImage) image);
|
||||
BufferedImage bufferedScaled = ImageUtil.toBuffered(scaled);
|
||||
|
||||
// Should be no need to convert
|
||||
assertSame(mImage, sameAsImage);
|
||||
assertSame(image, sameAsImage);
|
||||
|
||||
// Should have same dimensions
|
||||
assertEquals(mScaled.getWidth(null), bufferedScaled.getWidth());
|
||||
assertEquals(mScaled.getHeight(null), bufferedScaled.getHeight());
|
||||
assertEquals(scaled.getWidth(null), bufferedScaled.getWidth());
|
||||
assertEquals(scaled.getHeight(null), bufferedScaled.getHeight());
|
||||
|
||||
// Hmmm...
|
||||
assertTrue(new Integer(42).equals(bufferedScaled.getProperty("lucky-number"))
|
||||
@@ -116,28 +116,28 @@ public class ImageUtilTestCase extends TestCase {
|
||||
}
|
||||
|
||||
public void testToBufferedImageType() {
|
||||
// Assumes mImage is TYPE_INT_ARGB
|
||||
BufferedImage converted = ImageUtil.toBuffered(mImage, BufferedImage.TYPE_BYTE_INDEXED);
|
||||
BufferedImage convertedToo = ImageUtil.toBuffered(mImage, BufferedImage.TYPE_BYTE_BINARY);
|
||||
// Assumes image is TYPE_INT_ARGB
|
||||
BufferedImage converted = ImageUtil.toBuffered(image, BufferedImage.TYPE_BYTE_INDEXED);
|
||||
BufferedImage convertedToo = ImageUtil.toBuffered(image, BufferedImage.TYPE_BYTE_BINARY);
|
||||
|
||||
// Should not be the same
|
||||
assertNotSame(mImage, converted);
|
||||
assertNotSame(mImage, convertedToo);
|
||||
assertNotSame(image, converted);
|
||||
assertNotSame(image, convertedToo);
|
||||
|
||||
// Correct type
|
||||
assertTrue(converted.getType() == BufferedImage.TYPE_BYTE_INDEXED);
|
||||
assertTrue(convertedToo.getType() == BufferedImage.TYPE_BYTE_BINARY);
|
||||
|
||||
// Should have same dimensions
|
||||
assertEquals(mImage.getWidth(), converted.getWidth());
|
||||
assertEquals(mImage.getHeight(), converted.getHeight());
|
||||
assertEquals(image.getWidth(), converted.getWidth());
|
||||
assertEquals(image.getHeight(), converted.getHeight());
|
||||
|
||||
assertEquals(mImage.getWidth(), convertedToo.getWidth());
|
||||
assertEquals(mImage.getHeight(), convertedToo.getHeight());
|
||||
assertEquals(image.getWidth(), convertedToo.getWidth());
|
||||
assertEquals(image.getHeight(), convertedToo.getHeight());
|
||||
}
|
||||
|
||||
public void testBrightness() {
|
||||
final BufferedImage original = mOriginal;
|
||||
final BufferedImage original = this.original;
|
||||
assertNotNull(original);
|
||||
|
||||
final BufferedImage notBrightened = ImageUtil.toBuffered(ImageUtil.brightness(original, 0f));
|
||||
@@ -217,7 +217,7 @@ public class ImageUtilTestCase extends TestCase {
|
||||
|
||||
|
||||
public void testContrast() {
|
||||
final BufferedImage original = mOriginal;
|
||||
final BufferedImage original = this.original;
|
||||
|
||||
assertNotNull(original);
|
||||
|
||||
@@ -370,7 +370,7 @@ public class ImageUtilTestCase extends TestCase {
|
||||
}
|
||||
|
||||
public void testSharpen() {
|
||||
final BufferedImage original = mOriginal;
|
||||
final BufferedImage original = this.original;
|
||||
|
||||
assertNotNull(original);
|
||||
|
||||
@@ -495,7 +495,7 @@ public class ImageUtilTestCase extends TestCase {
|
||||
}
|
||||
|
||||
public void testBlur() {
|
||||
final BufferedImage original = mOriginal;
|
||||
final BufferedImage original = this.original;
|
||||
|
||||
assertNotNull(original);
|
||||
|
||||
@@ -563,7 +563,7 @@ public class ImageUtilTestCase extends TestCase {
|
||||
}
|
||||
|
||||
public void testIndexImage() {
|
||||
BufferedImage sunflower = mOriginal;
|
||||
BufferedImage sunflower = original;
|
||||
|
||||
assertNotNull(sunflower);
|
||||
|
||||
|
Reference in New Issue
Block a user