package com.twelvemonkeys.image;
import org.junit.Test;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.IndexColorModel;
import java.awt.image.RenderedImage;
import java.io.InputStream;
import static org.junit.Assert.*;
public class ImageUtilTestCase {
private final static String IMAGE_NAME = "/sunflower.jpg";
private BufferedImage original;
private BufferedImage image;
private Image scaled;
public ImageUtilTestCase() throws Exception {
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);
original = ImageIO.read(is);
assertNotNull(original);
}
/*
public void setUp() throws Exception {
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);
original = ImageIO.read(is);
assertNotNull(original);
}
protected void tearDown() throws Exception {
original = null;
}
*/
@Test
public void testToBufferedImageNull() {
BufferedImage img = null;
boolean threwRuntimeException = false;
try {
img = ImageUtil.toBuffered((Image) null);
}
catch (RuntimeException ne) {
threwRuntimeException = true;
}
// No input should return null
assertNull(img);
// Should have thrown an exception
assertTrue(threwRuntimeException);
}
@Test
public void testToBufferedImageTypeNull() {
BufferedImage img = null;
boolean threwRuntimeException = false;
try {
img = ImageUtil.toBuffered(null, BufferedImage.TYPE_INT_ARGB);
}
catch (RuntimeException ne) {
threwRuntimeException = true;
}
// No input should return null
assertNull(img);
// Should have thrown an exception
assertTrue(threwRuntimeException);
}
@Test
public void testImageIsNotBufferedImage() {
// Should not be a buffered image
assertFalse(
"FOR SOME IMPLEMENTATIONS THIS MIGHT FAIL!\nIn that case, testToBufferedImage() will fail too.",
scaled instanceof BufferedImage
);
}
@Test
public void testToBufferedImage() {
BufferedImage sameAsImage = ImageUtil.toBuffered((RenderedImage) image);
BufferedImage bufferedScaled = ImageUtil.toBuffered(scaled);
// Should be no need to convert
assertSame(image, sameAsImage);
// Should have same dimensions
assertEquals(scaled.getWidth(null), bufferedScaled.getWidth());
assertEquals(scaled.getHeight(null), bufferedScaled.getHeight());
}
@Test
public void testToBufferedImageType() {
// 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(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(image.getWidth(), converted.getWidth());
assertEquals(image.getHeight(), converted.getHeight());
assertEquals(image.getWidth(), convertedToo.getWidth());
assertEquals(image.getHeight(), convertedToo.getHeight());
}
@Test
public void testBrightness() {
final BufferedImage original = this.original;
assertNotNull(original);
final BufferedImage notBrightened = ImageUtil.toBuffered(ImageUtil.brightness(original, 0f));
// Assumed: Images should be equal
if (original != notBrightened) { // Don't care to test if images are same
for (int y = 0; y < original.getHeight(); y++) {
for (int x = 0; x < original.getWidth(); x++) {
assertEquals(original.getRGB(x, y), notBrightened.getRGB(x, y));
}
}
}
// Assumed: All pixels should be brighter or equal to original
final BufferedImage brightened = ImageUtil.toBuffered(ImageUtil.brightness(original, 0.4f));
final BufferedImage brightenedMore = ImageUtil.toBuffered(ImageUtil.brightness(original, 0.9f));
for (int y = 0; y < original.getHeight(); y++) {
for (int x = 0; x < original.getWidth(); x++) {
assertTrue(original.getRGB(x, y) <= brightened.getRGB(x, y));
assertTrue(brightened.getRGB(x, y) <= brightenedMore.getRGB(x, y));
}
}
// Assumed: Image should be all white
final BufferedImage brightenedMax = ImageUtil.toBuffered(ImageUtil.brightness(original, 2f));
for (int y = 0; y < brightenedMax.getHeight(); y++) {
for (int x = 0; x < brightenedMax.getWidth(); x++) {
assertEquals(0x00FFFFFF, brightenedMax.getRGB(x, y) & 0x00FFFFFF);
}
}
// Assumed: All pixels should be darker or equal to originial
final BufferedImage brightenedNegative = ImageUtil.toBuffered(ImageUtil.brightness(original, -0.4f));
final BufferedImage brightenedNegativeMore = ImageUtil.toBuffered(ImageUtil.brightness(original, -0.9f));
for (int y = 0; y < original.getHeight(); y++) {
for (int x = 0; x < original.getWidth(); x++) {
assertTrue(original.getRGB(x, y) >= brightenedNegative.getRGB(x, y));
assertTrue(brightenedNegative.getRGB(x, y) >= brightenedNegativeMore.getRGB(x, y));
}
}
// Assumed: Image should be all black
final BufferedImage brightenedMaxNegative = ImageUtil.toBuffered(ImageUtil.brightness(original, -2f));
for (int y = 0; y < brightenedMaxNegative.getHeight(); y++) {
for (int x = 0; x < brightenedMaxNegative.getWidth(); x++) {
assertEquals(0x0, brightenedMaxNegative.getRGB(x, y) & 0x00FFFFFF);
}
}
/*
JFrame frame = new JFrame("Sunflower - brightness");
frame.setSize(sunflower.getWidth() * 4, sunflower.getHeight() * 2);
Canvas canvas = new Canvas() {
public void paint(Graphics g) {
// Draw original for comparison
g.drawImage(original, 0, 0, null);
// This should look like original
g.drawImage(notBrightened, 0, original.getHeight(), null);
// Different versions
g.drawImage(brightened, original.getWidth(), 0, null);
g.drawImage(brightenedMore, original.getWidth() * 2, 0, null);
g.drawImage(brightenedMax, original.getWidth() * 3, 0, null);
g.drawImage(brightenedNegative, original.getWidth(), original.getHeight(), null);
g.drawImage(brightenedNegativeMore, original.getWidth() * 2, original.getHeight(), null);
g.drawImage(brightenedMaxNegative, original.getWidth() * 3, original.getHeight(), null);
}
};
frame.getContentPane().add(canvas);
frame.setVisible(true);
assertTrue(true);
*/
}
@Test
public void testContrast() {
final BufferedImage original = this.original;
assertNotNull(original);
final BufferedImage notContrasted = ImageUtil.toBuffered(ImageUtil.contrast(original, 0f));
// Assumed: Images should be equal
if (original != notContrasted) { // Don't care to test if images are same
for (int y = 0; y < original.getHeight(); y++) {
for (int x = 0; x < original.getWidth(); x++) {
assertEquals("0 constrast should not change image", original.getRGB(x, y), notContrasted.getRGB(x, y));
}
}
}
// Assumed: Contrast should be greater or equal to original
final BufferedImage contrasted = ImageUtil.toBuffered(ImageUtil.contrast(original));
final BufferedImage contrastedDefault = ImageUtil.toBuffered(ImageUtil.contrast(original, 0.5f));
for (int y = 0; y < original.getHeight(); y++) {
for (int x = 0; x < original.getWidth(); x++) {
int oRGB = original.getRGB(x, y);
int cRGB = contrasted.getRGB(x, y);
int dRGB = contrastedDefault.getRGB(x, y);
int oR = oRGB >> 16 & 0xFF;
int oG = oRGB >> 8 & 0xFF;
int oB = oRGB & 0xFF;
int cR = cRGB >> 16 & 0xFF;
int cG = cRGB >> 8 & 0xFF;
int cB = cRGB & 0xFF;
int dR = dRGB >> 16 & 0xFF;
int dG = dRGB >> 8 & 0xFF;
int dB = dRGB & 0xFF;
// RED
if (oR < 127) {
assertTrue("Contrast should be decreased or same", oR >= cR && cR >= dR);
}
else {
assertTrue("Contrast should be increased or same", oR <= cR && cR <= dR);
}
// GREEN
if (oG < 127) {
assertTrue("Contrast should be decreased or same", oG >= cG && cG >= dG);
}
else {
assertTrue("Contrast should be increased or same", oG <= cG && cG <= dG);
}
// BLUE
if (oB < 127) {
assertTrue("Contrast should be decreased or same", oB >= cB && cB >= dB);
}
else {
assertTrue("Contrast should be increased or same", oB <= cB && cB <= dB);
}
}
}
// Assumed: Only primary colors (w/b/r/g/b/c/y/m)
final BufferedImage contrastedMax = ImageUtil.toBuffered(ImageUtil.contrast(original, 1f));
for (int y = 0; y < contrastedMax.getHeight(); y++) {
for (int x = 0; x < contrastedMax.getWidth(); x++) {
int rgb = contrastedMax.getRGB(x, y);
int r = rgb >> 16 & 0xFF;
int g = rgb >> 8 & 0xFF;
int b = rgb & 0xFF;
assertTrue("Max contrast should only produce primary colors", r == 0 || r == 255);
assertTrue("Max contrast should only produce primary colors", g == 0 || g == 255);
assertTrue("Max contrast should only produce primary colors", b == 0 || b == 255);
}
}
// Assumed: Contrasts should be less than or equal to original
final BufferedImage contrastedNegative = ImageUtil.toBuffered(ImageUtil.contrast(original, -0.5f));
for (int y = 0; y < original.getHeight(); y++) {
for (int x = 0; x < original.getWidth(); x++) {
int oRGB = original.getRGB(x, y);
int cRGB = contrastedNegative.getRGB(x, y);
int oR = oRGB >> 16 & 0xFF;
int oG = oRGB >> 8 & 0xFF;
int oB = oRGB & 0xFF;
int cR = cRGB >> 16 & 0xFF;
int cG = cRGB >> 8 & 0xFF;
int cB = cRGB & 0xFF;
// RED
if (oR >= 127) {
assertTrue("Contrast should be decreased or same", oR >= cR);
}
else {
assertTrue("Contrast should be increased or same", oR <= cR);
}
// GREEN
if (oG >= 127) {
assertTrue("Contrast should be decreased or same", oG >= cG);
}
else {
assertTrue("Contrast should be increased or same", oG <= cG);
}
// BLUE
if (oB >= 127) {
assertTrue("Contrast should be decreased or same", oB >= cB);
}
else {
assertTrue("Contrast should be increased or same", oB <= cB);
}
}
}
// Assumed: All gray (127)!
final BufferedImage contrastedMoreNegative = ImageUtil.toBuffered(ImageUtil.contrast(original, -1.0f));
for (int y = 0; y < contrastedMoreNegative.getHeight(); y++) {
for (int x = 0; x < contrastedMoreNegative.getWidth(); x++) {
int rgb = contrastedMoreNegative.getRGB(x, y);
int r = rgb >> 16 & 0xFF;
int g = rgb >> 8 & 0xFF;
int b = rgb & 0xFF;
assertTrue("Minimum contrast should be all gray", r == 127 && g == 127 && b == 127);
}
}
/*
JFrame frame = new JFrame("Sunflower - contrast");
frame.setSize(sunflower.getWidth() * 4, sunflower.getHeight() * 2);
Canvas canvas = new Canvas() {
public void paint(Graphics g) {
// Draw original for comparison
g.drawImage(original, 0, 0, null);
// This should look like original
g.drawImage(notContrasted, 0, original.getHeight(), null);
// Different versions
g.drawImage(contrasted, original.getWidth(), 0, null);
g.drawImage(contrastedDefault, original.getWidth() * 2, 0, null);
g.drawImage(contrastedMax, original.getWidth() * 3, 0, null);
g.drawImage(contrastedNegative, original.getWidth() * 2, original.getHeight(), null);
g.drawImage(contrastedMoreNegative, original.getWidth() * 3, original.getHeight(), null);
}
};
frame.getContentPane().add(canvas);
frame.setVisible(true);
assertTrue(true);
*/
}
@Test
public void testSharpen() {
final BufferedImage original = this.original;
assertNotNull(original);
final BufferedImage notSharpened = ImageUtil.sharpen(original, 0f);
// Assumed: Images should be equal
if (original != notSharpened) { // Don't care to test if images are same
for (int y = 0; y < original.getHeight(); y++) {
for (int x = 0; x < original.getWidth(); x++) {
assertEquals("0 sharpen should not change image", original.getRGB(x, y), notSharpened.getRGB(x, y));
}
}
}
// Assumed: Difference between neighbouring pixels should increase for higher sharpen values
// Assumed: Dynamics of entire image should not change
final BufferedImage sharpened = ImageUtil.sharpen(original);
final BufferedImage sharpenedDefault = ImageUtil.sharpen(original, 0.3f);
final BufferedImage sharpenedMore = ImageUtil.sharpen(original, 1.3f);
// long diffOriginal = 0;
// long diffSharpened = 0;
// long diffDefault = 0;
// long diffMore = 0;
long absDiffOriginal = 0;
long absDiffSharpened = 0;
long absDiffDefault = 0;
long absDiffMore = 0;
for (int y = 0; y < original.getHeight(); y++) {
for (int x = 1; x < original.getWidth(); x++) {
int oRGB = 0x00FFFFFF & original.getRGB(x, y);
int sRGB = 0x00FFFFFF & sharpened.getRGB(x, y);
int dRGB = 0x00FFFFFF & sharpenedDefault.getRGB(x, y);
int mRGB = 0x00FFFFFF & sharpenedMore.getRGB(x, y);
int poRGB = 0x00FFFFFF & original.getRGB(x - 1, y);
int psRGB = 0x00FFFFFF & sharpened.getRGB(x - 1, y);
int pdRGB = 0x00FFFFFF & sharpenedDefault.getRGB(x - 1, y);
int pmRGB = 0x00FFFFFF & sharpenedMore.getRGB(x - 1, y);
// diffOriginal += poRGB - oRGB;
// diffSharpened += psRGB - sRGB;
// diffDefault += pdRGB - dRGB;
// diffMore += pmRGB - mRGB;
absDiffOriginal += Math.abs(poRGB - oRGB);
absDiffSharpened += Math.abs(psRGB - sRGB);
absDiffDefault += Math.abs(pdRGB - dRGB);
absDiffMore += Math.abs(pmRGB - mRGB);
}
}
// assertEquals("Difference should not change", diffOriginal, diffSharpened);
assertTrue("Abs difference should increase", absDiffOriginal < absDiffSharpened);
// assertEquals("Difference should not change", diffOriginal, diffDefault);
assertTrue("Abs difference should increase", absDiffOriginal < absDiffDefault);
// assertEquals("Difference should not change", diffOriginal, diffMore);
assertTrue("Abs difference should increase", absDiffOriginal < absDiffMore);
// assertEquals("Difference should not change", diffSharpened, diffMore);
assertTrue("Abs difference should increase", absDiffSharpened < absDiffMore);
}
@Test
public void testBlur() {
final BufferedImage original = this.original;
assertNotNull(original);
final BufferedImage notBlurred = ImageUtil.blur(original, 0f);
// Assumed: Images should be equal
if (original != notBlurred) { // Don't care to test if images are same
for (int y = 0; y < original.getHeight(); y++) {
for (int x = 0; x < original.getWidth(); x++) {
assertEquals("0 blur should not change image", original.getRGB(x, y), notBlurred.getRGB(x, y));
}
}
}
// Assumed: Difference between neighbouring pixels should decrease for higher blur values
// Assumed: Dynamics of entire image should not change
final BufferedImage blurred = ImageUtil.blur(original);
final BufferedImage blurredDefault = ImageUtil.blur(original, 1.5f);
final BufferedImage blurredMore = ImageUtil.blur(original, 3f);
// long diffOriginal = 0;
// long diffBlurred = 0;
// long diffDefault = 0;
// long diffMore = 0;
long absDiffOriginal = 0;
long absDiffBlurred = 0;
long absDiffDefault = 0;
long absDiffMore = 0;
for (int y = 0; y < original.getHeight(); y++) {
for (int x = 1; x < original.getWidth(); x++) {
int oRGB = 0x00FFFFFF & original.getRGB(x, y);
int bRGB = 0x00FFFFFF & blurred.getRGB(x, y);
int dRGB = 0x00FFFFFF & blurredDefault.getRGB(x, y);
int mRGB = 0x00FFFFFF & blurredMore.getRGB(x, y);
int poRGB = 0x00FFFFFF & original.getRGB(x - 1, y);
int pbRGB = 0x00FFFFFF & blurred.getRGB(x - 1, y);
int pdRGB = 0x00FFFFFF & blurredDefault.getRGB(x - 1, y);
int pmRGB = 0x00FFFFFF & blurredMore.getRGB(x - 1, y);
// diffOriginal += poRGB - oRGB;
// diffBlurred += pbRGB - bRGB;
// diffDefault += pdRGB - dRGB;
// diffMore += pmRGB - mRGB;
absDiffOriginal += Math.abs(poRGB - oRGB);
absDiffBlurred += Math.abs(pbRGB - bRGB);
absDiffDefault += Math.abs(pdRGB - dRGB);
absDiffMore += Math.abs(pmRGB - mRGB);
}
}
// assertEquals("Difference should not change", diffOriginal, diffBlurred);
assertTrue(String.format("Abs difference should decrease: %s <= %s", absDiffOriginal, absDiffBlurred), absDiffOriginal > absDiffBlurred);
// assertEquals("Difference should not change", diffOriginal, diffDefault);
assertTrue("Abs difference should decrease", absDiffOriginal > absDiffDefault);
// assertEquals("Difference should not change", diffOriginal, diffMore);
assertTrue("Abs difference should decrease", absDiffOriginal > absDiffMore);
// assertEquals("Difference should not change", diffBlurred, diffMore);
assertTrue("Abs difference should decrease", absDiffBlurred > absDiffMore);
}
@Test
public void testIndexImage() {
BufferedImage sunflower = original;
assertNotNull(sunflower);
BufferedImage image = ImageUtil.createIndexed(sunflower);
assertNotNull("Image was null", image);
assertTrue(image.getColorModel() instanceof IndexColorModel);
}
}