resources: Remove derivative images

This commit adds `ImageUtil::bufferedImageFromImage`,
`ImageUtil::alphaOffset`, `ImageUtil::grayscaleImage`, and
`ImageUtil::flipImage` functions and applies them to client and plugin
code to remove unneeded derivative images from the resources directory.
This commit is contained in:
Jordan Atwood
2018-07-29 19:14:14 -07:00
parent 06cd5cd7d0
commit 8fb36d3ea4
25 changed files with 292 additions and 34 deletions

View File

@@ -130,7 +130,7 @@ public class ConfigPanel extends PluginPanel
{
BufferedImage backIcon = ImageIO.read(ConfigPanel.class.getResourceAsStream("config_back_icon.png"));
BACK_ICON = new ImageIcon(backIcon);
BACK_ICON_HOVER = new ImageIcon(ImageUtil.grayscaleOffset(backIcon, -100));
BACK_ICON_HOVER = new ImageIcon(ImageUtil.alphaOffset(backIcon, -100));
SEARCH = new ImageIcon(ImageIO.read(IconTextField.class.getResourceAsStream("search.png")));
}
}

View File

@@ -92,13 +92,21 @@ class PluginListItem extends JPanel
{
configIcon = ImageIO.read(ConfigPanel.class.getResourceAsStream("config_edit_icon.png"));
CONFIG_ICON = new ImageIcon(configIcon);
ON_SWITCHER = new ImageIcon(ImageIO.read(ConfigPanel.class.getResourceAsStream("switchers/on.png")));
OFF_SWITCHER = new ImageIcon(ImageIO.read(ConfigPanel.class.getResourceAsStream("switchers/off.png")));
ON_STAR = new ImageIcon(ImageIO.read(ConfigPanel.class.getResourceAsStream("stars/on.png")));
OFF_STAR = new ImageIcon(ImageIO.read(ConfigPanel.class.getResourceAsStream("stars/off.png")));
ON_SWITCHER = new ImageIcon(ImageIO.read(ConfigPanel.class.getResourceAsStream("switcher_on.png")));
ON_STAR = new ImageIcon(ImageIO.read(ConfigPanel.class.getResourceAsStream("star_on.png")));
}
CONFIG_ICON_HOVER = new ImageIcon(ImageUtil.grayscaleOffset(configIcon, -100));
BufferedImage offSwitcherImage = ImageUtil.bufferedImageFromImage(ON_SWITCHER.getImage());
offSwitcherImage = ImageUtil.grayscaleImage(offSwitcherImage);
offSwitcherImage = ImageUtil.grayscaleOffset(offSwitcherImage, 0.61f);
offSwitcherImage = ImageUtil.flipImage(offSwitcherImage, true, false);
OFF_SWITCHER = new ImageIcon(offSwitcherImage);
BufferedImage offStarImage = ImageUtil.bufferedImageFromImage(ON_STAR.getImage());
offStarImage = ImageUtil.grayscaleImage(offStarImage);
offStarImage = ImageUtil.grayscaleOffset(offStarImage, 0.77f);
OFF_STAR = new ImageIcon(offStarImage);
CONFIG_ICON_HOVER = new ImageIcon(ImageUtil.alphaOffset(configIcon, -100));
}
catch (IOException e)
{

View File

@@ -54,6 +54,7 @@ import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.components.ThinProgressBar;
import net.runelite.client.util.ColorUtil;
import net.runelite.client.util.ImageUtil;
import net.runelite.client.util.StackFormatter;
@Slf4j
@@ -87,8 +88,8 @@ public class GrandExchangeOfferSlot extends JPanel
{
synchronized (ImageIO.class)
{
RIGHT_ARROW_ICON = new ImageIcon(ImageIO.read(GrandExchangeOfferSlot.class.getResourceAsStream("arrow_right.png")));
LEFT_ARROW_ICON = new ImageIcon(ImageIO.read(GrandExchangeOfferSlot.class.getResourceAsStream("arrow_left.png")));
RIGHT_ARROW_ICON = new ImageIcon(ImageUtil.alphaOffset(ImageIO.read(GrandExchangeOfferSlot.class.getResourceAsStream("/util/arrow_right.png")), 0.25f));
LEFT_ARROW_ICON = new ImageIcon(ImageUtil.flipImage(ImageUtil.bufferedImageFromImage(RIGHT_ARROW_ICON.getImage()), true, false));
}
}
catch (IOException e)

View File

@@ -49,6 +49,7 @@ import net.runelite.client.game.ItemManager;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.components.IconTextField;
import net.runelite.client.ui.components.PluginErrorPanel;
import net.runelite.client.util.ImageUtil;
import net.runelite.http.api.item.Item;
import net.runelite.http.api.item.ItemPrice;
import net.runelite.http.api.item.SearchResult;
@@ -99,7 +100,7 @@ class GrandExchangeSearchPanel extends JPanel
{
synchronized (ImageIO.class)
{
SEARCH_ICON = new ImageIcon(ImageIO.read(IconTextField.class.getResourceAsStream("search_darker.png")));
SEARCH_ICON = new ImageIcon(ImageUtil.alphaOffset(ImageUtil.grayscaleOffset(ImageIO.read(IconTextField.class.getResourceAsStream("search.png")), 0f), 1.75f));
LOADING_ICON = new ImageIcon(IconTextField.class.getResource("loading_spinner.gif"));
ERROR_ICON = new ImageIcon(ImageIO.read(IconTextField.class.getResourceAsStream("error.png")));
}

View File

@@ -96,7 +96,7 @@ public class InfoPanel extends PluginPanel
{
synchronized (ImageIO.class)
{
ARROW_RIGHT_ICON = new ImageIcon(ImageIO.read(InfoPanel.class.getResourceAsStream("arrow_right.png")));
ARROW_RIGHT_ICON = new ImageIcon(ImageIO.read(InfoPanel.class.getResourceAsStream("/util/arrow_right.png")));
GITHUB_ICON = new ImageIcon(ImageIO.read(InfoPanel.class.getResourceAsStream("github_icon.png")));
DISCORD_ICON = new ImageIcon(ImageIO.read(InfoPanel.class.getResourceAsStream("discord_icon.png")));
PATREON_ICON = new ImageIcon(ImageIO.read(InfoPanel.class.getResourceAsStream("patreon_icon.png")));

View File

@@ -73,7 +73,7 @@ class KourendLibraryPanel extends PluginPanel
{
BufferedImage resetIcon = ImageIO.read(KourendLibraryPanel.class.getResourceAsStream("reset.png"));
RESET_ICON = new ImageIcon(resetIcon);
RESET_CLICK_ICON = new ImageIcon(ImageUtil.grayscaleOffset(resetIcon, -100));
RESET_CLICK_ICON = new ImageIcon(ImageUtil.alphaOffset(resetIcon, -100));
}
}
catch (IOException e)

View File

@@ -29,6 +29,7 @@ import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
@@ -39,6 +40,7 @@ import net.runelite.client.plugins.screenmarkers.ScreenMarkerPlugin;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
import net.runelite.client.util.ImageUtil;
public class ScreenMarkerCreationPanel extends JPanel
{
@@ -59,16 +61,18 @@ public class ScreenMarkerCreationPanel extends JPanel
synchronized (ImageIO.class)
{
CONFIRM_ICON = new ImageIcon(ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("confirm_icon.png")));
CONFIRM_HOVER_ICON = new ImageIcon(ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("confirm_hover_icon.png")));
CONFIRM_LOCKED_ICON = new ImageIcon(ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("confirm_locked_icon.png")));
CANCEL_ICON = new ImageIcon(ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("cancel_icon.png")));
CANCEL_HOVER_ICON = new ImageIcon(ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("cancel_hover_icon.png")));
}
}
catch (IOException e)
{
throw new RuntimeException(e);
}
final BufferedImage confirmIcon = ImageUtil.bufferedImageFromImage(CONFIRM_ICON.getImage());
CONFIRM_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(confirmIcon, 0.54f));
CONFIRM_LOCKED_ICON = new ImageIcon(ImageUtil.grayscaleImage(confirmIcon));
CANCEL_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(ImageUtil.bufferedImageFromImage(CANCEL_ICON.getImage()), 0.6f));
}
ScreenMarkerCreationPanel(ScreenMarkerPlugin plugin)

View File

@@ -114,36 +114,36 @@ class ScreenMarkerPanel extends JPanel
{
BufferedImage borderImg = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("border_color_icon.png"));
BORDER_COLOR_ICON = new ImageIcon(borderImg);
BORDER_COLOR_HOVER_ICON = new ImageIcon(ImageUtil.grayscaleOffset(borderImg, -100));
BORDER_COLOR_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(borderImg, -100));
BufferedImage noBorderImg = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("no_border_color_icon.png"));
NO_BORDER_COLOR_ICON = new ImageIcon(noBorderImg);
NO_BORDER_COLOR_HOVER_ICON = new ImageIcon(ImageUtil.grayscaleOffset(noBorderImg, -100));
NO_BORDER_COLOR_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(noBorderImg, -100));
BufferedImage fillImg = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("fill_color_icon.png"));
FILL_COLOR_ICON = new ImageIcon(fillImg);
FILL_COLOR_HOVER_ICON = new ImageIcon(ImageUtil.grayscaleOffset(fillImg, -100));
FILL_COLOR_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(fillImg, -100));
BufferedImage noFillImg = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("no_fill_color_icon.png"));
NO_FILL_COLOR_ICON = new ImageIcon(noFillImg);
NO_FILL_COLOR_HOVER_ICON = new ImageIcon(ImageUtil.grayscaleOffset(noFillImg, -100));
NO_FILL_COLOR_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(noFillImg, -100));
BufferedImage opacityImg = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("opacity_icon.png"));
FULL_OPACITY_ICON = new ImageIcon(opacityImg);
OPACITY_HOVER_ICON = new ImageIcon(ImageUtil.grayscaleOffset(opacityImg, -100));
NO_OPACITY_ICON = new ImageIcon(ImageUtil.grayscaleOffset(opacityImg, -150));
OPACITY_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(opacityImg, -100));
NO_OPACITY_ICON = new ImageIcon(ImageUtil.alphaOffset(opacityImg, -150));
BufferedImage visibleImg = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("visible_icon.png"));
VISIBLE_ICON = new ImageIcon(visibleImg);
VISIBLE_HOVER_ICON = new ImageIcon(ImageUtil.grayscaleOffset(visibleImg, -100));
VISIBLE_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(visibleImg, -100));
BufferedImage invisibleImg = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("invisible_icon.png"));
INVISIBLE_ICON = new ImageIcon(invisibleImg);
INVISIBLE_HOVER_ICON = new ImageIcon(ImageUtil.grayscaleOffset(invisibleImg, -100));
INVISIBLE_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(invisibleImg, -100));
BufferedImage deleteImg = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("delete_icon.png"));
DELETE_ICON = new ImageIcon(deleteImg);
DELETE_HOVER_ICON = new ImageIcon(ImageUtil.grayscaleOffset(deleteImg, -100));
DELETE_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(deleteImg, -100));
}
}
catch (IOException e)

View File

@@ -47,6 +47,7 @@ import net.runelite.client.plugins.screenmarkers.ScreenMarkerPlugin;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.PluginPanel;
import net.runelite.client.ui.components.PluginErrorPanel;
import net.runelite.client.util.ImageUtil;
@Singleton
public class ScreenMarkerPluginPanel extends PluginPanel
@@ -85,13 +86,14 @@ public class ScreenMarkerPluginPanel extends PluginPanel
synchronized (ImageIO.class)
{
ADD_ICON = new ImageIcon(ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("add_icon.png")));
ADD_HOVER_ICON = new ImageIcon(ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("add_hover_icon.png")));
}
}
catch (IOException e)
{
throw new RuntimeException(e);
}
ADD_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(ImageUtil.bufferedImageFromImage(ADD_ICON.getImage()), 0.53f));
}
public void init()

View File

@@ -70,6 +70,7 @@ import net.runelite.client.events.NavigationButtonAdded;
import net.runelite.client.events.NavigationButtonRemoved;
import net.runelite.client.input.KeyManager;
import net.runelite.client.ui.skin.SubstanceRuneLiteLookAndFeel;
import net.runelite.client.util.ImageUtil;
import net.runelite.client.util.OSType;
import net.runelite.client.util.OSXUtil;
import net.runelite.client.util.SwingUtil;
@@ -97,7 +98,6 @@ public class ClientUI
{
BufferedImage icon;
BufferedImage sidebarOpen;
BufferedImage sidebarClose;
try
{
@@ -105,7 +105,6 @@ public class ClientUI
{
icon = ImageIO.read(ClientUI.class.getResourceAsStream("/runelite.png"));
sidebarOpen = ImageIO.read(ClientUI.class.getResourceAsStream("open.png"));
sidebarClose = ImageIO.read(ClientUI.class.getResourceAsStream("close.png"));
}
}
catch (IOException e)
@@ -115,7 +114,7 @@ public class ClientUI
ICON = icon;
SIDEBAR_OPEN = sidebarOpen;
SIDEBAR_CLOSE = sidebarClose;
SIDEBAR_CLOSE = ImageUtil.flipImage(SIDEBAR_OPEN, true, false);
}
@Getter

View File

@@ -31,12 +31,33 @@ import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.util.Arrays;
import javax.swing.GrayFilter;
/**
* Various Image/BufferedImage utilities.
*/
public class ImageUtil
{
/**
* Creates a {@link BufferedImage} from an {@link Image}.
*
* @param image An Image to be converted to a BufferedImage.
* @return A BufferedImage instance of the same given image.
*/
public static BufferedImage bufferedImageFromImage(final Image image)
{
if (image instanceof BufferedImage)
{
return (BufferedImage) image;
}
final BufferedImage out = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2d = out.createGraphics();
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
return out;
}
/**
* Offsets an image in the grayscale (darkens/brightens) by a given offset.
*
@@ -63,6 +84,86 @@ public class ImageUtil
return offset(image, scales, offsets);
}
/**
* Offsets an image in the grayscale (darkens/brightens) by a given percentage.
*
* @param image The image to be darkened or brightened.
* @param percentage The ratio to darken or brighten the given image.
* Values above 1 will brighten, and values below 1 will darken.
* @return The given image with its brightness scaled by the given percentage.
*/
public static BufferedImage grayscaleOffset(final BufferedImage image, final float percentage)
{
final int numComponents = image.getColorModel().getNumComponents();
final float[] scales = new float[numComponents];
final float[] offsets = new float[numComponents];
Arrays.fill(offsets, 0f);
for (int i = 0; i < numComponents; i++)
{
scales[i] = percentage;
}
// Set alpha to not scale
scales[numComponents - 1] = 1f;
return offset(image, scales, offsets);
}
/**
* Offsets an image's alpha component by a given offset.
*
* @param image The image to be made more or less transparent.
* @param offset A signed 8-bit integer value to modify the image's alpha component with.
* Values above 0 will increase transparency, and values below 0 will decrease
* transparency.
* @return The given image with its alpha component adjusted by the given offset.
*/
public static BufferedImage alphaOffset(final BufferedImage image, final int offset)
{
final float offsetFloat = (float) offset;
final int numComponents = image.getColorModel().getNumComponents();
final float[] scales = new float[numComponents];
final float[] offsets = new float[numComponents];
Arrays.fill(scales, 1f);
Arrays.fill(offsets, 0f);
offsets[numComponents - 1] = offsetFloat;
return offset(image, scales, offsets);
}
/**
* Offsets an image's alpha component by a given percentage.
*
* @param image The image to be made more or less transparent.
* @param percentage The ratio to modify the image's alpha component with.
* Values above 1 will increase transparency, and values below 1 will decrease
* transparency.
* @return The given image with its alpha component scaled by the given percentage.
*/
public static BufferedImage alphaOffset(final BufferedImage image, final float percentage)
{
final int numComponents = image.getColorModel().getNumComponents();
final float[] scales = new float[numComponents];
final float[] offsets = new float[numComponents];
Arrays.fill(scales, 1f);
Arrays.fill(offsets, 0f);
scales[numComponents - 1] = percentage;
return offset(image, scales, offsets);
}
/**
* Creates a grayscale image from the given image.
*
* @param image The source image to be converted.
* @return A copy of the given imnage, with colors converted to grayscale.
*/
public static BufferedImage grayscaleImage(final BufferedImage image)
{
final Image grayImage = GrayFilter.createDisabledImage(image);
return ImageUtil.bufferedImageFromImage(grayImage);
}
/**
* Re-size a BufferedImage to the given dimensions.
*
@@ -73,13 +174,8 @@ public class ImageUtil
*/
public static BufferedImage resizeImage(final BufferedImage image, final int newWidth, final int newHeight)
{
final Image tmp = image.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH);
final BufferedImage dimg = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2d = dimg.createGraphics();
g2d.drawImage(tmp, 0, 0, null);
g2d.dispose();
return dimg;
final Image resized = image.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH);
return ImageUtil.bufferedImageFromImage(resized);
}
/**
@@ -97,6 +193,42 @@ public class ImageUtil
return transformOp.filter(image, null);
}
/**
* Flips an image horizontally and/or vertically.
*
* @param image The image to be flipped.
* @param horizontal Whether the image should be flipped horizontally.
* @param vertical Whether the image should be flipped vertically.
* @return The given image, flipped horizontally and/or vertically.
*/
public static BufferedImage flipImage(final BufferedImage image, final boolean horizontal, final boolean vertical)
{
int x = 0;
int y = 0;
int w = image.getWidth();
int h = image.getHeight();
final BufferedImage out = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2d = out.createGraphics();
if (horizontal)
{
x = w;
w *= -1;
}
if (vertical)
{
y = h;
h *= -1;
}
g2d.drawImage(image, x, y, w, h, null);
g2d.dispose();
return out;
}
/**
* Performs a rescale operation on the image's color components.
*

Binary file not shown.

Before

Width:  |  Height:  |  Size: 654 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -36,6 +36,7 @@ import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.util.Arrays;
import javax.annotation.Nonnull;
import org.apache.commons.lang3.ArrayUtils;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
@@ -66,9 +67,17 @@ public class ImageUtilTest
BLACK_PIXEL_BOTTOM_RIGHT.setRGB(1, 1, BLACK.getRGB());
}
@Test
public void bufferedImageFromImage()
{
final BufferedImage buffered = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
assertEquals(buffered, ImageUtil.bufferedImageFromImage(buffered));
}
@Test
public void grayscaleOffset()
{
// grayscaleOffset(BufferedImage image, int offset)
assert(bufferedImagesEqual(oneByOne(BLACK), ImageUtil.grayscaleOffset(oneByOne(BLACK), -255)));
assert(bufferedImagesEqual(oneByOne(new Color(50, 50, 50)), ImageUtil.grayscaleOffset(oneByOne(BLACK), 50)));
assert(bufferedImagesEqual(oneByOne(GRAY), ImageUtil.grayscaleOffset(oneByOne(BLACK), 128)));
@@ -76,6 +85,73 @@ public class ImageUtilTest
assert(bufferedImagesEqual(oneByOne(WHITE), ImageUtil.grayscaleOffset(oneByOne(BLACK), 255)));
assert(bufferedImagesEqual(oneByOne(new Color(200, 200, 200)), ImageUtil.grayscaleOffset(oneByOne(WHITE), -55)));
assert(bufferedImagesEqual(oneByOne(WHITE), ImageUtil.grayscaleOffset(oneByOne(WHITE), 55)));
// grayscaleOffset(BufferedImage image, float percentage)
assert(bufferedImagesEqual(oneByOne(BLACK), ImageUtil.grayscaleOffset(oneByOne(BLACK), 0f)));
assert(bufferedImagesEqual(oneByOne(BLACK), ImageUtil.grayscaleOffset(oneByOne(BLACK), 1f)));
assert(bufferedImagesEqual(oneByOne(BLACK), ImageUtil.grayscaleOffset(oneByOne(BLACK), 2f)));
assert(bufferedImagesEqual(oneByOne(BLACK), ImageUtil.grayscaleOffset(oneByOne(GRAY), 0f)));
assert(bufferedImagesEqual(oneByOne(GRAY), ImageUtil.grayscaleOffset(oneByOne(GRAY), 1f)));
assert(bufferedImagesEqual(oneByOne(WHITE), ImageUtil.grayscaleOffset(oneByOne(GRAY), 2f)));
assert(bufferedImagesEqual(oneByOne(BLACK), ImageUtil.grayscaleOffset(oneByOne(WHITE), 0f)));
assert(bufferedImagesEqual(oneByOne(GRAY), ImageUtil.grayscaleOffset(oneByOne(WHITE), 0.503f))); // grayscaleOffset does Math.floor
assert(bufferedImagesEqual(oneByOne(WHITE), ImageUtil.grayscaleOffset(oneByOne(WHITE), 1f)));
assert(bufferedImagesEqual(oneByOne(WHITE), ImageUtil.grayscaleOffset(oneByOne(WHITE), 2f)));
}
@Test
public void alphaOffset()
{
// alphaOffset(BufferedImage image, int offset)
assert(bufferedImagesEqual(oneByOne(BLACK_TRANSPARENT), ImageUtil.alphaOffset(oneByOne(BLACK_TRANSPARENT), -255)));
assert(bufferedImagesEqual(oneByOne(new Color(0, 0, 0, 50)), ImageUtil.alphaOffset(oneByOne(BLACK_TRANSPARENT), 50)));
assert(bufferedImagesEqual(oneByOne(BLACK_HALF_TRANSPARENT), ImageUtil.alphaOffset(oneByOne(BLACK_TRANSPARENT), 128)));
assert(bufferedImagesEqual(oneByOne(BLACK_TRANSPARENT), ImageUtil.alphaOffset(oneByOne(BLACK_HALF_TRANSPARENT), -255)));
assert(bufferedImagesEqual(oneByOne(BLACK), ImageUtil.alphaOffset(oneByOne(BLACK_TRANSPARENT), 255)));
assert(bufferedImagesEqual(oneByOne(new Color(0, 0, 0, 200)), ImageUtil.alphaOffset(oneByOne(BLACK), -55)));
assert(bufferedImagesEqual(oneByOne(BLACK), ImageUtil.alphaOffset(oneByOne(BLACK), 255)));
// alphaOffset(BufferedImage image, float offset)
assert(bufferedImagesEqual(oneByOne(BLACK_TRANSPARENT), ImageUtil.alphaOffset(oneByOne(BLACK_TRANSPARENT), 0f)));
assert(bufferedImagesEqual(oneByOne(BLACK_TRANSPARENT), ImageUtil.alphaOffset(oneByOne(BLACK_TRANSPARENT), 1f)));
assert(bufferedImagesEqual(oneByOne(BLACK_TRANSPARENT), ImageUtil.alphaOffset(oneByOne(BLACK_TRANSPARENT), 2f)));
assert(bufferedImagesEqual(oneByOne(BLACK_TRANSPARENT), ImageUtil.alphaOffset(oneByOne(BLACK_HALF_TRANSPARENT), 0f)));
assert(bufferedImagesEqual(oneByOne(BLACK_HALF_TRANSPARENT), ImageUtil.alphaOffset(oneByOne(BLACK_HALF_TRANSPARENT), 1f)));
assert(bufferedImagesEqual(oneByOne(BLACK), ImageUtil.alphaOffset(oneByOne(BLACK_HALF_TRANSPARENT), 2f)));
assert(bufferedImagesEqual(oneByOne(BLACK_TRANSPARENT), ImageUtil.alphaOffset(oneByOne(BLACK), 0f)));
assert(bufferedImagesEqual(oneByOne(BLACK_HALF_TRANSPARENT), ImageUtil.alphaOffset(oneByOne(BLACK), 0.503f))); // opacityOffset does Math.floor
assert(bufferedImagesEqual(oneByOne(BLACK), ImageUtil.alphaOffset(oneByOne(BLACK), 1f)));
assert(bufferedImagesEqual(oneByOne(BLACK), ImageUtil.alphaOffset(oneByOne(BLACK), 2f)));
}
@Test
public void grayscaleImage()
{
final BufferedImage[] grayscaleColors = new BufferedImage[] {
oneByOne(WHITE),
oneByOne(GRAY),
oneByOne(BLACK),
oneByOne(BLACK_HALF_TRANSPARENT),
oneByOne(BLACK_TRANSPARENT),
};
final BufferedImage[] nonGrayscaleColors = new BufferedImage[] {
oneByOne(RED),
oneByOne(GREEN),
oneByOne(BLUE),
};
for (BufferedImage image : grayscaleColors)
{
assert(isGrayscale(image));
}
for (BufferedImage image : nonGrayscaleColors)
{
assert(!isGrayscale(image));
}
for (BufferedImage image : ArrayUtils.addAll(grayscaleColors, nonGrayscaleColors))
{
assert(isGrayscale(ImageUtil.grayscaleImage(image)));
}
}
@Test
@@ -145,6 +221,15 @@ public class ImageUtilTest
assert(bufferedImagesEqual(twoByOneLeft, ImageUtil.rotateImage(twoByOneLeft, Math.PI * 2)));
}
@Test
public void flipImage()
{
assert(bufferedImagesEqual(BLACK_PIXEL_TOP_LEFT, ImageUtil.flipImage(BLACK_PIXEL_TOP_LEFT, false, false)));
assert(bufferedImagesEqual(BLACK_PIXEL_TOP_RIGHT, ImageUtil.flipImage(BLACK_PIXEL_TOP_LEFT, true, false)));
assert(bufferedImagesEqual(BLACK_PIXEL_BOTTOM_LEFT, ImageUtil.flipImage(BLACK_PIXEL_TOP_LEFT, false, true)));
assert(bufferedImagesEqual(BLACK_PIXEL_BOTTOM_RIGHT, ImageUtil.flipImage(BLACK_PIXEL_TOP_LEFT, true, true)));
}
/**
* Compares whether two {@link BufferedImage}s are equal in data.
*
@@ -187,6 +272,32 @@ public class ImageUtilTest
return true;
}
/**
* Returns whether a {@link BufferedImage} contains only grayscale pixel data.
*
* @param image The image to be checked.
* @return A boolean indicating whether all of the given image's pixels are grayscale.
*/
private boolean isGrayscale(final @Nonnull BufferedImage image)
{
for (int x = 0; x < image.getWidth(); x++)
{
for (int y = 0; y < image.getHeight(); y++)
{
final int color = image.getRGB(x, y);
final int red = (color & 0xff0000) >> 16;
final int green = (color & 0xff00) >> 8;
final int blue = color & 0xff;
if (red != green
|| green != blue)
{
return false;
}
}
}
return true;
}
/**
* Creates a {@link BufferedImage} of a 1-by-1px image of the given color.
*