diff --git a/runelite-client/src/main/java/net/runelite/client/game/ClanManager.java b/runelite-client/src/main/java/net/runelite/client/game/ClanManager.java index 3d35edac8d..53908086a6 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/ClanManager.java +++ b/runelite-client/src/main/java/net/runelite/client/game/ClanManager.java @@ -28,16 +28,17 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.eventbus.Subscribe; +import java.awt.Color; +import java.awt.Dimension; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.DataBufferByte; import java.awt.image.IndexColorModel; import java.awt.image.WritableRaster; -import java.io.IOException; import java.util.Arrays; import java.util.Objects; import java.util.concurrent.TimeUnit; -import javax.imageio.ImageIO; +import javax.annotation.Nonnull; import javax.inject.Inject; import javax.inject.Singleton; import lombok.extern.slf4j.Slf4j; @@ -46,26 +47,33 @@ import net.runelite.api.ClanMemberRank; import net.runelite.api.Client; import net.runelite.api.GameState; import net.runelite.api.IndexedSprite; +import net.runelite.api.SpriteID; import net.runelite.api.events.ClanChanged; import net.runelite.api.events.GameStateChanged; +import net.runelite.client.util.ImageUtil; import net.runelite.client.util.Text; @Singleton @Slf4j public class ClanManager { - private static final String[] CLANCHAT_IMAGES = + private static final int[] CLANCHAT_IMAGES = { - "Friend_clan_rank.png", "Recruit_clan_rank.png", - "Corporal_clan_rank.png", "Sergeant_clan_rank.png", - "Lieutenant_clan_rank.png", "Captain_clan_rank.png", - "General_clan_rank.png", "Owner_clan_rank.png", - "JMod_clan_rank.png" + SpriteID.CLAN_CHAT_RANK_SMILEY_FRIEND, + SpriteID.CLAN_CHAT_RANK_SINGLE_CHEVRON_RECRUIT, + SpriteID.CLAN_CHAT_RANK_DOUBLE_CHEVRON_CORPORAL, + SpriteID.CLAN_CHAT_RANK_TRIPLE_CHEVRON_SERGEANT, + SpriteID.CLAN_CHAT_RANK_BRONZE_STAR_LIEUTENANT, + SpriteID.CLAN_CHAT_RANK_SILVER_STAR_CAPTAIN, + SpriteID.CLAN_CHAT_RANK_GOLD_STAR_GENERAL, + SpriteID.CLAN_CHAT_RANK_KEY_CHANNEL_OWNER, + SpriteID.CLAN_CHAT_RANK_CROWN_JAGEX_MODERATOR, }; - - private int modIconsLength; + private static final Dimension CLANCHAT_IMAGE_DIMENSION = new Dimension(11, 11); + private static final Color CLANCHAT_IMAGE_OUTLINE_COLOR = new Color(33, 33, 33); private final Client client; + private final SpriteManager spriteManager; private final BufferedImage[] clanChatImages = new BufferedImage[CLANCHAT_IMAGES.length]; private final LoadingCache clanRanksCache = CacheBuilder.newBuilder() @@ -74,7 +82,7 @@ public class ClanManager .build(new CacheLoader() { @Override - public ClanMemberRank load(String key) throws Exception + public ClanMemberRank load(@Nonnull String key) { final ClanMember[] clanMembersArr = client.getClanMembers(); @@ -92,27 +100,13 @@ public class ClanManager } }); + private int modIconsLength; + @Inject - private ClanManager(Client client) + private ClanManager(Client client, SpriteManager spriteManager) { this.client = client; - - int i = 0; - for (String resource : CLANCHAT_IMAGES) - { - try - { - final BufferedImage bufferedImage = rgbaToIndexedBufferedImage(ImageIO - .read(ClanManager.class.getResource(resource))); - clanChatImages[i] = bufferedImage; - } - catch (IOException e) - { - log.warn("unable to load clan image", e); - } - - ++i; - } + this.spriteManager = spriteManager; } public ClanMemberRank getRank(String playerName) @@ -138,10 +132,9 @@ public class ClanManager @Subscribe public void onGameStateChanged(GameStateChanged gameStateChanged) { - if (gameStateChanged.getGameState() == GameState.LOGIN_SCREEN + if (gameStateChanged.getGameState() == GameState.LOGGED_IN && modIconsLength == 0) { - // this is after "Loading sprites" so we can modify modicons now loadClanChatIcons(); } } @@ -154,25 +147,19 @@ public class ClanManager private void loadClanChatIcons() { - try - { - final IndexedSprite[] modIcons = client.getModIcons(); - final IndexedSprite[] newModIcons = Arrays.copyOf(modIcons, modIcons.length + CLANCHAT_IMAGES.length); - int curPosition = newModIcons.length - CLANCHAT_IMAGES.length; + final IndexedSprite[] modIcons = client.getModIcons(); + final IndexedSprite[] newModIcons = Arrays.copyOf(modIcons, modIcons.length + CLANCHAT_IMAGES.length); + int curPosition = newModIcons.length - CLANCHAT_IMAGES.length; - for (BufferedImage image : clanChatImages) - { - IndexedSprite sprite = createIndexedSprite(client, image); - newModIcons[curPosition++] = sprite; - } - - client.setModIcons(newModIcons); - modIconsLength = newModIcons.length; - } - catch (IOException e) + for (int i = 0; i < CLANCHAT_IMAGES.length; i++, curPosition++) { - log.warn("Failed loading of clan chat icons", e); + final int resource = CLANCHAT_IMAGES[i]; + clanChatImages[i] = rgbaToIndexedBufferedImage(clanChatImageFromSprite(spriteManager.getSprite(resource, 0))); + newModIcons[curPosition] = createIndexedSprite(client, clanChatImages[i]); } + + client.setModIcons(newModIcons); + modIconsLength = newModIcons.length; } private static String sanitize(String lookup) @@ -181,7 +168,7 @@ public class ClanManager return cleaned.replace('\u00A0', ' '); } - private static IndexedSprite createIndexedSprite(final Client client, final BufferedImage bufferedImage) throws IOException + private static IndexedSprite createIndexedSprite(final Client client, final BufferedImage bufferedImage) { final IndexColorModel indexedCM = (IndexColorModel) bufferedImage.getColorModel(); @@ -228,4 +215,10 @@ public class ClanManager resultIndexedImage.getGraphics().drawImage(sourceBufferedImage, 0, 0, null); return resultIndexedImage; } + + private static BufferedImage clanChatImageFromSprite(final BufferedImage clanSprite) + { + final BufferedImage clanChatCanvas = ImageUtil.resizeCanvas(clanSprite, CLANCHAT_IMAGE_DIMENSION.width, CLANCHAT_IMAGE_DIMENSION.height); + return ImageUtil.outlineImage(clanChatCanvas, CLANCHAT_IMAGE_OUTLINE_COLOR); + } } diff --git a/runelite-client/src/main/java/net/runelite/client/game/SkillIconManager.java b/runelite-client/src/main/java/net/runelite/client/game/SkillIconManager.java index d3883be67b..03c78617b1 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/SkillIconManager.java +++ b/runelite-client/src/main/java/net/runelite/client/game/SkillIconManager.java @@ -25,11 +25,10 @@ package net.runelite.client.game; import java.awt.image.BufferedImage; -import java.io.IOException; -import javax.imageio.ImageIO; import javax.inject.Singleton; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Skill; +import net.runelite.client.util.ImageUtil; @Singleton @Slf4j @@ -48,21 +47,11 @@ public class SkillIconManager return imgCache[skillIdx]; } - try - { - String skillIconPath = (small ? "/skill_icons_small/" : "/skill_icons/") - + skill.getName().toLowerCase() + ".png"; - log.debug("Loading skill icon from {}", skillIconPath); - synchronized (ImageIO.class) - { - skillImage = ImageIO.read(SkillIconManager.class.getResourceAsStream(skillIconPath)); - } - imgCache[skillIdx] = skillImage; - } - catch (IOException e) - { - log.debug("Error Loading skill icons {}", e); - } + String skillIconPath = (small ? "/skill_icons_small/" : "/skill_icons/") + + skill.getName().toLowerCase() + ".png"; + log.debug("Loading skill icon from {}", skillIconPath); + skillImage = ImageUtil.getResourceStreamFromClass(getClass(), skillIconPath); + imgCache[skillIdx] = skillImage; return skillImage; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/account/AccountPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/account/AccountPlugin.java index fdf173829e..1be02b4eed 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/account/AccountPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/account/AccountPlugin.java @@ -26,9 +26,7 @@ package net.runelite.client.plugins.account; import com.google.common.eventbus.Subscribe; import java.awt.image.BufferedImage; -import java.io.IOException; import java.util.concurrent.ScheduledExecutorService; -import javax.imageio.ImageIO; import javax.inject.Inject; import javax.swing.JOptionPane; import lombok.extern.slf4j.Slf4j; @@ -40,6 +38,7 @@ import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.ClientToolbar; import net.runelite.client.ui.NavigationButton; +import net.runelite.client.util.ImageUtil; import net.runelite.client.util.RunnableExceptionLogger; @PluginDescriptor( @@ -67,18 +66,8 @@ public class AccountPlugin extends Plugin static { - try - { - synchronized (ImageIO.class) - { - LOGIN_IMAGE = ImageIO.read(AccountPlugin.class.getResourceAsStream("login_icon.png")); - LOGOUT_IMAGE = ImageIO.read(AccountPlugin.class.getResourceAsStream("logout_icon.png")); - } - } - catch (IOException e) - { - throw new RuntimeException(e); - } + LOGIN_IMAGE = ImageUtil.getResourceStreamFromClass(AccountPlugin.class, "login_icon.png"); + LOGOUT_IMAGE = ImageUtil.getResourceStreamFromClass(AccountPlugin.class, "logout_icon.png"); } @Override diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityArenaTimer.java b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityArenaTimer.java index 740852ef92..05b217e125 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityArenaTimer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityArenaTimer.java @@ -25,9 +25,7 @@ package net.runelite.client.plugins.agility; import java.awt.image.BufferedImage; -import java.io.IOException; import java.time.temporal.ChronoUnit; -import javax.imageio.ImageIO; import lombok.extern.slf4j.Slf4j; import net.runelite.client.plugins.Plugin; import net.runelite.client.ui.overlay.infobox.Timer; @@ -35,32 +33,9 @@ import net.runelite.client.ui.overlay.infobox.Timer; @Slf4j class AgilityArenaTimer extends Timer { - AgilityArenaTimer(Plugin plugin) + AgilityArenaTimer(Plugin plugin, BufferedImage image) { - super(1, ChronoUnit.MINUTES, getTicketImage(), plugin); + super(1, ChronoUnit.MINUTES, image, plugin); setTooltip("Time left until location changes"); } - - private static BufferedImage image; - private static BufferedImage getTicketImage() - { - if (image != null) - { - return image; - } - - try - { - synchronized (ImageIO.class) - { - image = ImageIO.read(AgilityArenaTimer.class.getResourceAsStream( "agilityarenaticket.png")); - } - } - catch (IOException ex) - { - log.warn("unable to load image", ex); - } - - return image; - } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java index 06a33a285c..735a070cf2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java @@ -35,6 +35,7 @@ import lombok.Getter; import net.runelite.api.Client; import net.runelite.api.Item; import net.runelite.api.ItemID; +import static net.runelite.api.ItemID.AGILITY_ARENA_TICKET; import net.runelite.api.Player; import static net.runelite.api.Skill.AGILITY; import net.runelite.api.Tile; @@ -60,6 +61,7 @@ import net.runelite.api.events.WallObjectDespawned; import net.runelite.api.events.WallObjectSpawned; import net.runelite.client.Notifier; import net.runelite.client.config.ConfigManager; +import net.runelite.client.game.ItemManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.overlay.OverlayManager; @@ -101,6 +103,9 @@ public class AgilityPlugin extends Plugin @Inject private AgilityConfig config; + @Inject + private ItemManager itemManager; + @Getter private AgilitySession session; @@ -275,7 +280,7 @@ public class AgilityPlugin extends Plugin private void showNewAgilityArenaTimer() { removeAgilityArenaTimer(); - infoBoxManager.addInfoBox(new AgilityArenaTimer(this)); + infoBoxManager.addInfoBox(new AgilityArenaTimer(this, itemManager.getImage(AGILITY_ARENA_TICKET))); } @Subscribe diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultPlugin.java index 01edaebce0..8b6c81e84d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultPlugin.java @@ -30,7 +30,6 @@ import java.awt.Font; import java.awt.Image; import java.util.ArrayList; import java.util.List; -import javax.imageio.ImageIO; import javax.inject.Inject; import net.runelite.api.ChatMessageType; import net.runelite.api.Client; @@ -46,6 +45,7 @@ import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.FontManager; import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.util.ImageUtil; @PluginDescriptor( name = "Barbarian Assault", @@ -87,10 +87,7 @@ public class BarbarianAssaultPlugin extends Plugin font = FontManager.getRunescapeFont() .deriveFont(Font.BOLD, 24); - synchronized (ImageIO.class) - { - clockImage = ImageIO.read(getClass().getResourceAsStream("clock.png")); - } + clockImage = ImageUtil.getResourceStreamFromClass(getClass(), "clock.png"); } @Override diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsPlugin.java index f734f0d9fa..acd8a2ef3b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsPlugin.java @@ -30,7 +30,6 @@ import com.google.inject.Provides; import java.util.Arrays; import java.util.HashSet; import java.util.Set; -import javax.imageio.ImageIO; import javax.inject.Inject; import javax.inject.Singleton; import lombok.Getter; @@ -49,6 +48,7 @@ import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; +import net.runelite.client.util.ImageUtil; @PluginDescriptor( name = "Boosts Information", @@ -118,11 +118,8 @@ public class BoostsPlugin extends Plugin Arrays.fill(lastSkillLevels, -1); // Add infoboxes for everything at startup and then determine inside if it will be rendered - synchronized (ImageIO.class) - { - infoBoxManager.addInfoBox(new StatChangeIndicator(true, ImageIO.read(getClass().getResourceAsStream("debuffed.png")), this, config)); - infoBoxManager.addInfoBox(new StatChangeIndicator(false, ImageIO.read(getClass().getResourceAsStream("buffed.png")), this, config)); - } + infoBoxManager.addInfoBox(new StatChangeIndicator(true, ImageUtil.getResourceStreamFromClass(getClass(), "debuffed.png"), this, config)); + infoBoxManager.addInfoBox(new StatChangeIndicator(false, ImageUtil.getResourceStreamFromClass(getClass(), "buffed.png"), this, config)); for (final Skill skill : Skill.values()) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java index 4ac8fab050..c81ae85777 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java @@ -29,13 +29,11 @@ package net.runelite.client.plugins.cluescrolls; import com.google.common.eventbus.Subscribe; import com.google.inject.Provides; import java.awt.image.BufferedImage; -import java.io.IOException; import java.time.Duration; import java.time.Instant; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; -import javax.imageio.ImageIO; import javax.inject.Inject; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -47,6 +45,7 @@ import net.runelite.api.InventoryID; import net.runelite.api.Item; import net.runelite.api.ItemComposition; import net.runelite.api.ItemContainer; +import net.runelite.api.ItemID; import net.runelite.api.NPC; import net.runelite.api.Query; import net.runelite.api.Scene; @@ -83,6 +82,7 @@ import net.runelite.client.plugins.cluescrolls.clues.ObjectClueScroll; import net.runelite.client.plugins.cluescrolls.clues.TextClueScroll; import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.worldmap.WorldMapPointManager; +import net.runelite.client.util.ImageUtil; import net.runelite.client.util.QueryRunner; import net.runelite.client.util.Text; @@ -96,11 +96,6 @@ public class ClueScrollPlugin extends Plugin { private static final Duration WAIT_DURATION = Duration.ofMinutes(4); - public static final BufferedImage CLUE_SCROLL_IMAGE; - public static final BufferedImage MAP_ARROW; - public static final BufferedImage EMOTE_IMAGE; - public static final BufferedImage SPADE_IMAGE; - @Getter private ClueScroll clue; @@ -147,28 +142,12 @@ public class ClueScrollPlugin extends Plugin @Inject private WorldMapPointManager worldMapPointManager; + private BufferedImage emoteImage; + private BufferedImage mapArrow; private Integer clueItemId; private boolean clueItemChanged = false; private boolean worldMapPointsSet = false; - static - { - try - { - synchronized (ImageIO.class) - { - CLUE_SCROLL_IMAGE = ImageIO.read(ClueScrollPlugin.class.getResourceAsStream("clue_scroll.png")); - MAP_ARROW = ImageIO.read(ClueScrollPlugin.class.getResourceAsStream("clue_arrow.png")); - EMOTE_IMAGE = ImageIO.read(ClueScrollPlugin.class.getResourceAsStream("emote.png")); - SPADE_IMAGE = ImageIO.read(ClueScrollPlugin.class.getResourceAsStream("spade.png")); - } - } - catch (IOException e) - { - throw new RuntimeException(e); - } - } - @Provides ClueScrollConfig getConfig(ConfigManager configManager) { @@ -411,6 +390,40 @@ public class ClueScrollPlugin extends Plugin } } + public BufferedImage getClueScrollImage() + { + return itemManager.getImage(ItemID.CLUE_SCROLL_MASTER); + } + + public BufferedImage getEmoteImage() + { + if (emoteImage != null) + { + return emoteImage; + } + + emoteImage = ImageUtil.getResourceStreamFromClass(getClass(), "emote.png"); + + return emoteImage; + } + + public BufferedImage getSpadeImage() + { + return itemManager.getImage(ItemID.SPADE); + } + + BufferedImage getMapArrow() + { + if (mapArrow != null) + { + return mapArrow; + } + + mapArrow = ImageUtil.getResourceStreamFromClass(getClass(), "/util/clue_arrow.png"); + + return mapArrow; + } + private void resetClue() { if (!clueItemChanged) @@ -594,7 +607,7 @@ public class ClueScrollPlugin extends Plugin for (final WorldPoint point : points) { - worldMapPointManager.add(new ClueScrollWorldMapPoint(point)); + worldMapPointManager.add(new ClueScrollWorldMapPoint(point, this)); } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollWorldMapPoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollWorldMapPoint.java index 62b7891c9c..45fa1f874c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollWorldMapPoint.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollWorldMapPoint.java @@ -32,41 +32,40 @@ import net.runelite.client.ui.overlay.worldmap.WorldMapPoint; class ClueScrollWorldMapPoint extends WorldMapPoint { - private static final BufferedImage CLUE_SCROLL_WORLD_IMAGE; - private static final Point CLUE_SCROLL_WORLD_IMAGE_POINT; + private final ClueScrollPlugin plugin; + private final BufferedImage clueScrollWorldImage; + private final Point clueScrollWorldImagePoint; - static - { - CLUE_SCROLL_WORLD_IMAGE = new BufferedImage(ClueScrollPlugin.MAP_ARROW.getWidth(), ClueScrollPlugin.MAP_ARROW.getHeight(), BufferedImage.TYPE_INT_ARGB); - Graphics graphics = CLUE_SCROLL_WORLD_IMAGE.getGraphics(); - graphics.drawImage(ClueScrollPlugin.MAP_ARROW, 0, 0, null); - graphics.drawImage(ClueScrollPlugin.CLUE_SCROLL_IMAGE, 0, 2, null); - CLUE_SCROLL_WORLD_IMAGE_POINT = new Point( - CLUE_SCROLL_WORLD_IMAGE.getWidth() / 2, - CLUE_SCROLL_WORLD_IMAGE.getHeight()); - } - - ClueScrollWorldMapPoint(final WorldPoint worldPoint) + ClueScrollWorldMapPoint(final WorldPoint worldPoint, ClueScrollPlugin plugin) { super(worldPoint, null); + clueScrollWorldImage = new BufferedImage(plugin.getMapArrow().getWidth(), plugin.getMapArrow().getHeight(), BufferedImage.TYPE_INT_ARGB); + Graphics graphics = clueScrollWorldImage.getGraphics(); + graphics.drawImage(plugin.getMapArrow(), 0, 0, null); + graphics.drawImage(plugin.getClueScrollImage(), 0, 0, null); + clueScrollWorldImagePoint = new Point( + clueScrollWorldImage.getWidth() / 2, + clueScrollWorldImage.getHeight()); + + this.plugin = plugin; this.setSnapToEdge(true); this.setJumpOnClick(true); - this.setImage(CLUE_SCROLL_WORLD_IMAGE); - this.setImagePoint(CLUE_SCROLL_WORLD_IMAGE_POINT); + this.setImage(clueScrollWorldImage); + this.setImagePoint(clueScrollWorldImagePoint); } @Override public void onEdgeSnap() { - this.setImage(ClueScrollPlugin.CLUE_SCROLL_IMAGE); + this.setImage(plugin.getClueScrollImage()); this.setImagePoint(null); } @Override public void onEdgeUnsnap() { - this.setImage(CLUE_SCROLL_WORLD_IMAGE); - this.setImagePoint(CLUE_SCROLL_WORLD_IMAGE_POINT); + this.setImage(clueScrollWorldImage); + this.setImagePoint(clueScrollWorldImagePoint); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java index b4f51254f1..294907dcfe 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java @@ -33,7 +33,6 @@ import net.runelite.api.NPC; import net.runelite.api.coords.WorldPoint; import static net.runelite.client.plugins.cluescrolls.ClueScrollOverlay.TITLED_CONTENT_COLOR; import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; -import static net.runelite.client.plugins.cluescrolls.ClueScrollPlugin.CLUE_SCROLL_IMAGE; import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.IMAGE_Z_OFFSET; import net.runelite.client.ui.overlay.OverlayUtil; import net.runelite.client.ui.overlay.components.LineComponent; @@ -203,7 +202,7 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc { for (NPC npc : plugin.getNpcsToMark()) { - OverlayUtil.renderActorOverlayImage(graphics, npc, CLUE_SCROLL_IMAGE, Color.ORANGE, IMAGE_Z_OFFSET); + OverlayUtil.renderActorOverlayImage(graphics, npc, plugin.getClueScrollImage(), Color.ORANGE, IMAGE_Z_OFFSET); } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java index f715c84576..a55751fbd1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java @@ -33,7 +33,6 @@ import net.runelite.api.NPC; import net.runelite.api.coords.WorldPoint; import static net.runelite.client.plugins.cluescrolls.ClueScrollOverlay.TITLED_CONTENT_COLOR; import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; -import static net.runelite.client.plugins.cluescrolls.ClueScrollPlugin.CLUE_SCROLL_IMAGE; import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.IMAGE_Z_OFFSET; import net.runelite.client.ui.overlay.OverlayUtil; import net.runelite.client.ui.overlay.components.LineComponent; @@ -112,7 +111,7 @@ public class CipherClue extends ClueScroll implements TextClueScroll, NpcClueScr { for (NPC npc : plugin.getNpcsToMark()) { - OverlayUtil.renderActorOverlayImage(graphics, npc, CLUE_SCROLL_IMAGE, Color.ORANGE, IMAGE_Z_OFFSET); + OverlayUtil.renderActorOverlayImage(graphics, npc, plugin.getClueScrollImage(), Color.ORANGE, IMAGE_Z_OFFSET); } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java index 5a84d40508..654f31e977 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java @@ -32,7 +32,6 @@ import net.runelite.api.ItemID; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; -import static net.runelite.client.plugins.cluescrolls.ClueScrollPlugin.SPADE_IMAGE; import net.runelite.client.plugins.cluescrolls.clues.emote.ItemRequirement; import net.runelite.client.plugins.cluescrolls.clues.emote.SingleItemRequirement; import net.runelite.client.ui.overlay.OverlayUtil; @@ -77,6 +76,6 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati return; } - OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, SPADE_IMAGE, Color.ORANGE); + OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, plugin.getSpadeImage(), Color.ORANGE); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java index 65ce2ebb59..d1aabbe261 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java @@ -38,8 +38,6 @@ import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import static net.runelite.client.plugins.cluescrolls.ClueScrollOverlay.TITLED_CONTENT_COLOR; import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; -import static net.runelite.client.plugins.cluescrolls.ClueScrollPlugin.CLUE_SCROLL_IMAGE; -import static net.runelite.client.plugins.cluescrolls.ClueScrollPlugin.SPADE_IMAGE; import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_BORDER_COLOR; import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_FILL_COLOR; import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_HOVER_BORDER_COLOR; @@ -391,7 +389,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc if (localLocation != null) { - OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, SPADE_IMAGE, Color.ORANGE); + OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, plugin.getSpadeImage(), Color.ORANGE); } } @@ -400,7 +398,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc { for (NPC npc : plugin.getNpcsToMark()) { - OverlayUtil.renderActorOverlayImage(graphics, npc, CLUE_SCROLL_IMAGE, Color.ORANGE, IMAGE_Z_OFFSET); + OverlayUtil.renderActorOverlayImage(graphics, npc, plugin.getClueScrollImage(), Color.ORANGE, IMAGE_Z_OFFSET); } } @@ -416,7 +414,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc OverlayUtil.renderHoverableArea(graphics, gameObject.getClickbox(), mousePosition, CLICKBOX_FILL_COLOR, CLICKBOX_BORDER_COLOR, CLICKBOX_HOVER_BORDER_COLOR); - OverlayUtil.renderImageLocation(plugin.getClient(), graphics, gameObject.getLocalLocation(), CLUE_SCROLL_IMAGE, IMAGE_Z_OFFSET); + OverlayUtil.renderImageLocation(plugin.getClient(), graphics, gameObject.getLocalLocation(), plugin.getClueScrollImage(), IMAGE_Z_OFFSET); } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java index 2e9f25bf27..2e718d2b3f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java @@ -38,7 +38,6 @@ import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import static net.runelite.client.plugins.cluescrolls.ClueScrollOverlay.TITLED_CONTENT_COLOR; import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; -import static net.runelite.client.plugins.cluescrolls.ClueScrollPlugin.EMOTE_IMAGE; import net.runelite.client.plugins.cluescrolls.clues.emote.AllRequirementsCollection; import net.runelite.client.plugins.cluescrolls.clues.emote.AnyRequirementCollection; import net.runelite.client.plugins.cluescrolls.clues.emote.Emote; @@ -285,7 +284,7 @@ public class EmoteClue extends ClueScroll implements TextClueScroll, LocationClu return; } - OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, EMOTE_IMAGE, Color.ORANGE); + OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, plugin.getEmoteImage(), Color.ORANGE); } public static EmoteClue forText(String text) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/FairyRingClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/FairyRingClue.java index 590f31ee68..7841c85447 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/FairyRingClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/FairyRingClue.java @@ -34,7 +34,6 @@ import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import static net.runelite.client.plugins.cluescrolls.ClueScrollOverlay.TITLED_CONTENT_COLOR; import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; -import static net.runelite.client.plugins.cluescrolls.ClueScrollPlugin.SPADE_IMAGE; import net.runelite.client.plugins.cluescrolls.clues.emote.ItemRequirement; import net.runelite.client.plugins.cluescrolls.clues.emote.SingleItemRequirement; import net.runelite.client.ui.overlay.OverlayUtil; @@ -102,7 +101,7 @@ public class FairyRingClue extends ClueScroll implements TextClueScroll, Locatio return; } - OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, SPADE_IMAGE, Color.ORANGE); + OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, plugin.getSpadeImage(), Color.ORANGE); } public static FairyRingClue forText(String text) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java index b340e9947d..f7c71b3f3d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java @@ -45,8 +45,6 @@ import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import static net.runelite.client.plugins.cluescrolls.ClueScrollOverlay.TITLED_CONTENT_COLOR; import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; -import static net.runelite.client.plugins.cluescrolls.ClueScrollPlugin.CLUE_SCROLL_IMAGE; -import static net.runelite.client.plugins.cluescrolls.ClueScrollPlugin.SPADE_IMAGE; import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.IMAGE_Z_OFFSET; import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdArea; import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdLocation; @@ -196,7 +194,7 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat if (localLocation != null) { - OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, SPADE_IMAGE, Color.ORANGE); + OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, plugin.getSpadeImage(), Color.ORANGE); } return; @@ -210,7 +208,7 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat { for (NPC npc : plugin.getNpcsToMark()) { - OverlayUtil.renderActorOverlayImage(graphics, npc, CLUE_SCROLL_IMAGE, Color.ORANGE, IMAGE_Z_OFFSET); + OverlayUtil.renderActorOverlayImage(graphics, npc, plugin.getClueScrollImage(), Color.ORANGE, IMAGE_Z_OFFSET); } } } @@ -229,7 +227,7 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat return; } - OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, SPADE_IMAGE, Color.ORANGE); + OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, plugin.getSpadeImage(), Color.ORANGE); } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/MapClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/MapClue.java index a032e3c894..fd2b65f874 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/MapClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/MapClue.java @@ -40,8 +40,6 @@ import static net.runelite.api.ObjectID.CRATE_6616; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; -import static net.runelite.client.plugins.cluescrolls.ClueScrollPlugin.CLUE_SCROLL_IMAGE; -import static net.runelite.client.plugins.cluescrolls.ClueScrollPlugin.SPADE_IMAGE; import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_BORDER_COLOR; import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_FILL_COLOR; import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_HOVER_BORDER_COLOR; @@ -179,14 +177,14 @@ public class MapClue extends ClueScroll implements ObjectClueScroll OverlayUtil.renderHoverableArea(graphics, gameObject.getClickbox(), mousePosition, CLICKBOX_FILL_COLOR, CLICKBOX_BORDER_COLOR, CLICKBOX_HOVER_BORDER_COLOR); - OverlayUtil.renderImageLocation(plugin.getClient(), graphics, gameObject.getLocalLocation(), CLUE_SCROLL_IMAGE, IMAGE_Z_OFFSET); + OverlayUtil.renderImageLocation(plugin.getClient(), graphics, gameObject.getLocalLocation(), plugin.getClueScrollImage(), IMAGE_Z_OFFSET); } } } // Mark tile else { - OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, SPADE_IMAGE, Color.ORANGE); + OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, plugin.getSpadeImage(), Color.ORANGE); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java index 632b365611..2e37feca4a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java @@ -38,14 +38,12 @@ import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; -import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.concurrent.ScheduledExecutorService; import java.util.stream.Collectors; -import javax.imageio.ImageIO; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JButton; @@ -89,7 +87,7 @@ import net.runelite.client.ui.PluginPanel; import net.runelite.client.ui.components.ComboBoxListRenderer; import net.runelite.client.ui.components.IconButton; import net.runelite.client.ui.components.IconTextField; -import net.runelite.client.util.SwingUtil; +import net.runelite.client.util.ImageUtil; @Slf4j public class ConfigPanel extends PluginPanel @@ -124,20 +122,10 @@ public class ConfigPanel extends PluginPanel static { - try - { - synchronized (ImageIO.class) - { - BufferedImage backIcon = ImageIO.read(ConfigPanel.class.getResourceAsStream("config_back_icon.png")); - BACK_ICON = new ImageIcon(backIcon); - BACK_ICON_HOVER = new ImageIcon(SwingUtil.grayscaleOffset(backIcon, -100)); - SEARCH = new ImageIcon(ImageIO.read(IconTextField.class.getResourceAsStream("search.png"))); - } - } - catch (IOException e) - { - throw new RuntimeException(e); - } + final BufferedImage backIcon = ImageUtil.getResourceStreamFromClass(ConfigPanel.class, "config_back_icon.png"); + BACK_ICON = new ImageIcon(backIcon); + BACK_ICON_HOVER = new ImageIcon(ImageUtil.alphaOffset(backIcon, -100)); + SEARCH = new ImageIcon(ImageUtil.getResourceStreamFromClass(IconTextField.class, "search.png")); } ConfigPanel(PluginManager pluginManager, ConfigManager configManager, ScheduledExecutorService executorService, diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPlugin.java index f72c74c854..3b9af9868c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPlugin.java @@ -27,7 +27,6 @@ package net.runelite.client.plugins.config; import com.google.common.eventbus.Subscribe; import java.awt.image.BufferedImage; import java.util.concurrent.ScheduledExecutorService; -import javax.imageio.ImageIO; import javax.inject.Inject; import javax.swing.SwingUtilities; import net.runelite.client.config.ChatColorConfig; @@ -39,6 +38,7 @@ import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginManager; import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.ClientToolbar; +import net.runelite.client.util.ImageUtil; @PluginDescriptor( name = "Configuration", @@ -73,11 +73,7 @@ public class ConfigPlugin extends Plugin { configPanel = new ConfigPanel(pluginManager, configManager, executorService, runeLiteConfig, chatColorConfig); - BufferedImage icon; - synchronized (ImageIO.class) - { - icon = ImageIO.read(getClass().getResourceAsStream("config_icon.png")); - } + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "config_icon.png"); navButton = NavigationButton.builder() .tooltip("Configuration") diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java index 0514795de1..e70643f6fa 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java @@ -29,12 +29,10 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.image.BufferedImage; -import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.annotation.Nullable; -import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; @@ -45,7 +43,7 @@ import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.PluginPanel; import net.runelite.client.ui.components.IconButton; -import net.runelite.client.util.SwingUtil; +import net.runelite.client.util.ImageUtil; import org.apache.commons.text.similarity.JaroWinklerDistance; class PluginListItem extends JPanel @@ -84,26 +82,27 @@ class PluginListItem extends JPanel static { - try - { - BufferedImage configIcon; - - synchronized (ImageIO.class) - { - 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"))); - } - - CONFIG_ICON_HOVER = new ImageIcon(SwingUtil.grayscaleOffset(configIcon, -100)); - } - catch (IOException e) - { - throw new RuntimeException(e); - } + BufferedImage configIcon = ImageUtil.getResourceStreamFromClass(ConfigPanel.class, "config_edit_icon.png"); + BufferedImage onSwitcher = ImageUtil.getResourceStreamFromClass(ConfigPanel.class, "switcher_on.png"); + BufferedImage onStar = ImageUtil.getResourceStreamFromClass(ConfigPanel.class, "star_on.png"); + CONFIG_ICON = new ImageIcon(configIcon); + ON_SWITCHER = new ImageIcon(onSwitcher); + ON_STAR = new ImageIcon(onStar); + CONFIG_ICON_HOVER = new ImageIcon(ImageUtil.grayscaleOffset(configIcon, -100)); + BufferedImage offSwitcherImage = ImageUtil.flipImage( + ImageUtil.grayscaleOffset( + ImageUtil.grayscaleImage(onSwitcher), + 0.61f + ), + true, + false + ); + OFF_SWITCHER = new ImageIcon(offSwitcherImage); + BufferedImage offStar = ImageUtil.grayscaleOffset( + ImageUtil.grayscaleImage(onStar), + 0.77f + ); + OFF_STAR = new ImageIcon(offStar); } /** diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/deathindicator/DeathIndicatorPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/deathindicator/DeathIndicatorPlugin.java index a739568db1..133a34cbb1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/deathindicator/DeathIndicatorPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/deathindicator/DeathIndicatorPlugin.java @@ -28,17 +28,16 @@ import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.Subscribe; import com.google.inject.Provides; import java.awt.image.BufferedImage; -import java.io.IOException; import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Set; -import javax.imageio.ImageIO; import javax.inject.Inject; import lombok.extern.slf4j.Slf4j; import static net.runelite.api.AnimationID.DEATH; import net.runelite.api.Client; import net.runelite.api.GameState; +import net.runelite.api.ItemID; import net.runelite.api.Player; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.AnimationChanged; @@ -46,11 +45,13 @@ import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; import net.runelite.client.config.ConfigManager; +import net.runelite.client.game.ItemManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import net.runelite.client.ui.overlay.infobox.Timer; import net.runelite.client.ui.overlay.worldmap.WorldMapPointManager; +import net.runelite.client.util.ImageUtil; @PluginDescriptor( name = "Death Indicator", @@ -66,7 +67,6 @@ public class DeathIndicatorPlugin extends Plugin 12342, // Edgeville 11062 // Camelot ); - static BufferedImage BONES; @Inject private Client client; @@ -80,27 +80,17 @@ public class DeathIndicatorPlugin extends Plugin @Inject private InfoBoxManager infoBoxManager; + @Inject + private ItemManager itemManager; + + private BufferedImage mapArrow; + private Timer deathTimer; private WorldPoint lastDeath; private Instant lastDeathTime; private int lastDeathWorld; - static - { - try - { - synchronized (ImageIO.class) - { - BONES = ImageIO.read(DeathIndicatorPlugin.class.getResourceAsStream("bones.png")); - } - } - catch (IOException e) - { - throw new RuntimeException(e); - } - } - @Provides DeathIndicatorConfig deathIndicatorConfig(ConfigManager configManager) { @@ -133,7 +123,7 @@ public class DeathIndicatorPlugin extends Plugin if (config.showDeathOnWorldMap()) { worldMapPointManager.removeIf(DeathWorldMapPoint.class::isInstance); - worldMapPointManager.add(new DeathWorldMapPoint(new WorldPoint(config.deathLocationX(), config.deathLocationY(), config.deathLocationPlane()))); + worldMapPointManager.add(new DeathWorldMapPoint(new WorldPoint(config.deathLocationX(), config.deathLocationY(), config.deathLocationPlane()), this)); } } @@ -204,7 +194,7 @@ public class DeathIndicatorPlugin extends Plugin if (config.showDeathOnWorldMap()) { worldMapPointManager.removeIf(DeathWorldMapPoint.class::isInstance); - worldMapPointManager.add(new DeathWorldMapPoint(lastDeath)); + worldMapPointManager.add(new DeathWorldMapPoint(lastDeath, this)); } resetInfobox(); @@ -290,7 +280,7 @@ public class DeathIndicatorPlugin extends Plugin if (config.showDeathOnWorldMap()) { worldMapPointManager.removeIf(DeathWorldMapPoint.class::isInstance); - worldMapPointManager.add(new DeathWorldMapPoint(deathPoint)); + worldMapPointManager.add(new DeathWorldMapPoint(deathPoint, this)); } } else @@ -328,10 +318,27 @@ public class DeathIndicatorPlugin extends Plugin Duration timeLeft = Duration.ofHours(1).minus(Duration.between(config.timeOfDeath(), now)); if (!timeLeft.isNegative() && !timeLeft.isZero()) { - deathTimer = new Timer(timeLeft.getSeconds(), ChronoUnit.SECONDS, BONES, this); + deathTimer = new Timer(timeLeft.getSeconds(), ChronoUnit.SECONDS, getBonesImage(), this); deathTimer.setTooltip("Died on world: " + config.deathWorld()); infoBoxManager.addInfoBox(deathTimer); } } } + + BufferedImage getMapArrow() + { + if (mapArrow != null) + { + return mapArrow; + } + + mapArrow = ImageUtil.getResourceStreamFromClass(getClass(), "/util/clue_arrow.png"); + + return mapArrow; + } + + BufferedImage getBonesImage() + { + return itemManager.getImage(ItemID.BONES); + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/deathindicator/DeathWorldMapPoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/deathindicator/DeathWorldMapPoint.java index 629d05b27e..e6368d87ce 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/deathindicator/DeathWorldMapPoint.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/deathindicator/DeathWorldMapPoint.java @@ -26,56 +26,40 @@ package net.runelite.client.plugins.deathindicator; import java.awt.Graphics; import java.awt.image.BufferedImage; -import java.io.IOException; -import javax.imageio.ImageIO; import net.runelite.api.Point; import net.runelite.api.coords.WorldPoint; -import static net.runelite.client.plugins.deathindicator.DeathIndicatorPlugin.BONES; import net.runelite.client.ui.overlay.worldmap.WorldMapPoint; class DeathWorldMapPoint extends WorldMapPoint { - private static final BufferedImage WORLDMAP_HINT_ARROW; - private static final Point WORLDMAP_HINT_ARROW_POINT; + private final DeathIndicatorPlugin plugin; + private final BufferedImage worldmapHintArrow; + private final Point worldmapHintArrowPoint; - static - { - BufferedImage MAP_ARROW; - try - { - synchronized (ImageIO.class) - { - MAP_ARROW = ImageIO.read(DeathWorldMapPoint.class.getResourceAsStream("clue_arrow.png")); - } - } - catch (IOException e) - { - throw new RuntimeException(e); - } - - WORLDMAP_HINT_ARROW = new BufferedImage(MAP_ARROW.getWidth(), - MAP_ARROW.getHeight(), BufferedImage.TYPE_INT_ARGB); - - Graphics graphics = WORLDMAP_HINT_ARROW.getGraphics(); - graphics.drawImage(MAP_ARROW, 0, 0, null); - graphics.drawImage(BONES, 0, 1, null); - WORLDMAP_HINT_ARROW_POINT = new Point(WORLDMAP_HINT_ARROW.getWidth() / 2, WORLDMAP_HINT_ARROW.getHeight()); - } - - DeathWorldMapPoint(final WorldPoint worldPoint) + DeathWorldMapPoint(final WorldPoint worldPoint, final DeathIndicatorPlugin plugin) { super(worldPoint, null); + + worldmapHintArrow = new BufferedImage(plugin.getMapArrow().getWidth(), plugin.getMapArrow().getHeight(), BufferedImage.TYPE_INT_ARGB); + Graphics graphics = worldmapHintArrow.getGraphics(); + graphics.drawImage(plugin.getMapArrow(), 0, 0, null); + graphics.drawImage(plugin.getBonesImage(), 0, 0, null); + worldmapHintArrowPoint = new Point( + worldmapHintArrow.getWidth() / 2, + worldmapHintArrow.getHeight()); + + this.plugin = plugin; this.setSnapToEdge(true); this.setJumpOnClick(true); - this.setImage(WORLDMAP_HINT_ARROW); - this.setImagePoint(WORLDMAP_HINT_ARROW_POINT); + this.setImage(worldmapHintArrow); + this.setImagePoint(worldmapHintArrowPoint); this.setTooltip("Death Location"); } @Override public void onEdgeSnap() { - this.setImage(BONES); + this.setImage(plugin.getBonesImage()); this.setImagePoint(null); this.setTooltip(null); } @@ -83,8 +67,8 @@ class DeathWorldMapPoint extends WorldMapPoint @Override public void onEdgeUnsnap() { - this.setImage(WORLDMAP_HINT_ARROW); - this.setImagePoint(WORLDMAP_HINT_ARROW_POINT); + this.setImage(worldmapHintArrow); + this.setImagePoint(worldmapHintArrowPoint); this.setTooltip("Death Location"); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java index 981b023f8a..535b98cecb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java @@ -32,7 +32,6 @@ import com.google.inject.Provides; import java.awt.Font; import java.awt.image.BufferedImage; import static java.lang.Math.min; -import javax.imageio.ImageIO; import javax.inject.Inject; import lombok.extern.slf4j.Slf4j; import net.runelite.api.ChatMessageType; @@ -51,6 +50,7 @@ import net.runelite.client.ui.FontManager; import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.ClientToolbar; import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.util.ImageUtil; import org.slf4j.LoggerFactory; @PluginDescriptor( @@ -130,11 +130,7 @@ public class DevToolsPlugin extends Plugin final DevToolsPanel panel = injector.getInstance(DevToolsPanel.class); - BufferedImage icon; - synchronized (ImageIO.class) - { - icon = ImageIO.read(getClass().getResourceAsStream("devtools_icon.png")); - } + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "devtools_icon.png"); navButton = NavigationButton.builder() .tooltip("Developer Tools") diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java index 0ee6689640..c2605d5186 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java @@ -33,7 +33,6 @@ import java.time.temporal.ChronoUnit; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; -import javax.imageio.ImageIO; import net.runelite.api.Client; import static net.runelite.api.Constants.CHUNK_SIZE; import net.runelite.api.GameState; @@ -51,6 +50,7 @@ import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.task.Schedule; import net.runelite.client.ui.ClientToolbar; import net.runelite.client.ui.NavigationButton; +import net.runelite.client.util.ImageUtil; import net.runelite.client.util.LinkBrowser; @PluginDescriptor( @@ -88,11 +88,7 @@ public class DiscordPlugin extends Plugin @Override protected void startUp() throws Exception { - BufferedImage icon; - synchronized (ImageIO.class) - { - icon = ImageIO.read(getClass().getResourceAsStream("discord.png")); - } + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "discord.png"); discordButton = NavigationButton.builder() .tab(false) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/farmingtracker/FarmingTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/farmingtracker/FarmingTrackerPlugin.java index f1127f62de..81c4b9c495 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/farmingtracker/FarmingTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/farmingtracker/FarmingTrackerPlugin.java @@ -29,7 +29,6 @@ import com.google.inject.Provides; import java.awt.image.BufferedImage; import java.time.Instant; import java.time.temporal.ChronoUnit; -import javax.imageio.ImageIO; import javax.inject.Inject; import javax.swing.SwingUtilities; import lombok.extern.slf4j.Slf4j; @@ -46,6 +45,7 @@ import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.task.Schedule; import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.ClientToolbar; +import net.runelite.client.util.ImageUtil; @PluginDescriptor( name = "Farming Tracker", @@ -88,11 +88,7 @@ public class FarmingTrackerPlugin extends Plugin @Override protected void startUp() throws Exception { - BufferedImage icon; - synchronized (ImageIO.class) - { - icon = ImageIO.read(getClass().getResourceAsStream("farming.png")); - } + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "farming.png"); panel = new FarmingTrackerPanel(client, itemManager, configManager, config, farmingWorld); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/feed/FeedPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/feed/FeedPanel.java index 6c355a8c46..a9abb4636b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/feed/FeedPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/feed/FeedPanel.java @@ -53,6 +53,7 @@ import lombok.extern.slf4j.Slf4j; import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.FontManager; import net.runelite.client.ui.PluginPanel; +import net.runelite.client.util.ImageUtil; import net.runelite.client.util.LinkBrowser; import net.runelite.http.api.RuneLiteAPI; import net.runelite.http.api.feed.FeedItem; @@ -102,18 +103,8 @@ class FeedPanel extends PluginPanel static { - try - { - synchronized (ImageIO.class) - { - RUNELITE_ICON = new ImageIcon(ImageIO.read(FeedPanel.class.getResourceAsStream("runelite.png"))); - OSRS_ICON = new ImageIcon(ImageIO.read(FeedPanel.class.getResourceAsStream("osrs.png"))); - } - } - catch (IOException e) - { - throw new RuntimeException(e); - } + RUNELITE_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(FeedPanel.class, "runelite.png")); + OSRS_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(FeedPanel.class, "osrs.png")); } private final FeedConfig config; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/feed/FeedPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/feed/FeedPlugin.java index a54c272930..79ada10499 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/feed/FeedPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/feed/FeedPlugin.java @@ -33,7 +33,6 @@ import java.time.temporal.ChronoUnit; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; -import javax.imageio.ImageIO; import javax.inject.Inject; import lombok.extern.slf4j.Slf4j; import net.runelite.api.events.ConfigChanged; @@ -43,6 +42,7 @@ import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.task.Schedule; import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.ClientToolbar; +import net.runelite.client.util.ImageUtil; import net.runelite.http.api.feed.FeedClient; import net.runelite.http.api.feed.FeedResult; @@ -86,11 +86,7 @@ public class FeedPlugin extends Plugin { feedPanel = new FeedPanel(config, feedSupplier); - BufferedImage icon; - synchronized (ImageIO.class) - { - icon = ImageIO.read(getClass().getResourceAsStream("icon.png")); - } + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "icon.png"); navButton = NavigationButton.builder() .tooltip("News Feed") diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveOverlay.java index cb718637da..b1b33e724e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveOverlay.java @@ -28,11 +28,11 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.image.BufferedImage; -import java.io.IOException; -import javax.imageio.ImageIO; import javax.inject.Inject; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; +import net.runelite.api.SpriteID; +import net.runelite.client.game.SpriteManager; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayPriority; @@ -47,17 +47,17 @@ public class FightCaveOverlay extends Overlay private final Client client; private final FightCavePlugin plugin; + private final SpriteManager spriteManager; private final PanelComponent imagePanelComponent = new PanelComponent(); - private BufferedImage protectFromMagicImg; - private BufferedImage protectFromMissilesImg; @Inject - private FightCaveOverlay(Client client, FightCavePlugin plugin) + private FightCaveOverlay(Client client, FightCavePlugin plugin, SpriteManager spriteManager) { setPosition(OverlayPosition.BOTTOM_RIGHT); setPriority(OverlayPriority.HIGH); this.client = client; this.plugin = plugin; + this.spriteManager = spriteManager; } @Override @@ -83,43 +83,7 @@ public class FightCaveOverlay extends Overlay private BufferedImage getPrayerImage(JadAttack attack) { - return attack == JadAttack.MAGIC ? getProtectFromMagicImage() : getProtectFromMissilesImage(); - } - - private BufferedImage getProtectFromMagicImage() - { - if (protectFromMagicImg == null) - { - String path = "/prayers/protect_from_magic.png"; - protectFromMagicImg = getImage(path); - } - return protectFromMagicImg; - } - - private BufferedImage getProtectFromMissilesImage() - { - if (protectFromMissilesImg == null) - { - String path = "/prayers/protect_from_missiles.png"; - protectFromMissilesImg = getImage(path); - } - return protectFromMissilesImg; - } - - private BufferedImage getImage(String path) - { - BufferedImage image = null; - try - { - synchronized (ImageIO.class) - { - image = ImageIO.read(FightCaveOverlay.class.getResourceAsStream(path)); - } - } - catch (IOException e) - { - log.warn("Error loading image", e); - } - return image; + final int prayerSpriteID = attack == JadAttack.MAGIC ? SpriteID.PRAYER_PROTECT_FROM_MAGIC : SpriteID.PRAYER_PROTECT_FROM_MISSILES; + return spriteManager.getSprite(prayerSpriteID, 0); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeOfferSlot.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeOfferSlot.java index 356d6f843c..8843193064 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeOfferSlot.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeOfferSlot.java @@ -36,9 +36,7 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.image.BufferedImage; -import java.io.IOException; import javax.annotation.Nullable; -import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; @@ -54,6 +52,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 @@ -83,18 +82,9 @@ public class GrandExchangeOfferSlot extends JPanel static { - try - { - 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"))); - } - } - catch (IOException e) - { - throw new RuntimeException(e); - } + final BufferedImage rightArrow = ImageUtil.alphaOffset(ImageUtil.getResourceStreamFromClass(GrandExchangeOfferSlot.class, "/util/arrow_right.png"), 0.25f); + RIGHT_ARROW_ICON = new ImageIcon(rightArrow); + LEFT_ARROW_ICON = new ImageIcon(ImageUtil.flipImage(rightArrow, true, false)); } /** diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java index ea278f3a19..3f59fa440d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java @@ -32,7 +32,6 @@ import com.google.inject.Provides; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.concurrent.ScheduledExecutorService; -import javax.imageio.ImageIO; import javax.inject.Inject; import javax.swing.SwingUtilities; import lombok.AccessLevel; @@ -66,6 +65,7 @@ import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.ClientToolbar; +import net.runelite.client.util.ImageUtil; import net.runelite.client.util.StackFormatter; import net.runelite.client.util.Text; import net.runelite.http.api.osbuddy.GrandExchangeClient; @@ -134,15 +134,11 @@ public class GrandExchangePlugin extends Plugin } @Override - protected void startUp() throws IOException + protected void startUp() { panel = injector.getInstance(GrandExchangePanel.class); - BufferedImage icon; - synchronized (ImageIO.class) - { - icon = ImageIO.read(getClass().getResourceAsStream("ge_icon.png")); - } + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "ge_icon.png"); button = NavigationButton.builder() .tooltip("Grand Exchange") diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeSearchPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeSearchPanel.java index 05e92315c4..20d28c7a16 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeSearchPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeSearchPanel.java @@ -31,11 +31,9 @@ import java.awt.CardLayout; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ScheduledExecutorService; -import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JPanel; import javax.swing.JScrollPane; @@ -49,6 +47,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; @@ -95,19 +94,9 @@ class GrandExchangeSearchPanel extends JPanel static { - try - { - synchronized (ImageIO.class) - { - SEARCH_ICON = new ImageIcon(ImageIO.read(IconTextField.class.getResourceAsStream("search_darker.png"))); - LOADING_ICON = new ImageIcon(IconTextField.class.getResource("loading_spinner.gif")); - ERROR_ICON = new ImageIcon(ImageIO.read(IconTextField.class.getResourceAsStream("error.png"))); - } - } - catch (IOException e) - { - throw new RuntimeException(e); - } + SEARCH_ICON = new ImageIcon(ImageUtil.alphaOffset(ImageUtil.grayscaleOffset(ImageUtil.getResourceStreamFromClass(IconTextField.class, "search.png"), 0f), 1.75f)); + LOADING_ICON = new ImageIcon(IconTextField.class.getResource("loading_spinner.gif")); + ERROR_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(IconTextField.class, "error.png")); } GrandExchangeSearchPanel(Client client, ItemManager itemManager, ScheduledExecutorService executor) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePanel.java index c669337aa4..2e0b558202 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePanel.java @@ -41,7 +41,6 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.ScheduledExecutorService; import javax.annotation.Nullable; -import javax.imageio.ImageIO; import javax.inject.Inject; import javax.swing.ImageIcon; import javax.swing.JLabel; @@ -57,6 +56,7 @@ import net.runelite.client.ui.PluginPanel; import net.runelite.client.ui.components.IconTextField; import net.runelite.client.ui.components.materialtabs.MaterialTab; import net.runelite.client.ui.components.materialtabs.MaterialTabGroup; +import net.runelite.client.util.ImageUtil; import net.runelite.client.util.RunnableExceptionLogger; import net.runelite.client.util.StackFormatter; import net.runelite.http.api.hiscore.HiscoreClient; @@ -146,19 +146,9 @@ public class HiscorePanel extends PluginPanel static { - try - { - synchronized (ImageIO.class) - { - SEARCH_ICON = new ImageIcon(ImageIO.read(IconTextField.class.getResourceAsStream("search.png"))); - LOADING_ICON = new ImageIcon(IconTextField.class.getResource("loading_spinner_darker.gif")); - ERROR_ICON = new ImageIcon(ImageIO.read(IconTextField.class.getResourceAsStream("error.png"))); - } - } - catch (IOException e) - { - throw new RuntimeException(e); - } + SEARCH_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(IconTextField.class, "search.png")); + LOADING_ICON = new ImageIcon(IconTextField.class.getResource("loading_spinner_darker.gif")); + ERROR_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(IconTextField.class, "error.png")); } @Inject @@ -220,51 +210,39 @@ public class HiscorePanel extends PluginPanel for (HiscoreEndpoint endpoint : HiscoreEndpoint.values()) { - try + final BufferedImage iconImage = ImageUtil.getResourceStreamFromClass(getClass(), endpoint.name().toLowerCase() + ".png"); + + MaterialTab tab = new MaterialTab(new ImageIcon(iconImage), tabGroup, null); + tab.setToolTipText(endpoint.getName() + " Hiscores"); + tab.setOnSelectEvent(() -> { - BufferedImage iconImage; - synchronized (ImageIO.class) + if (loading) { - iconImage = ImageIO.read(HiscorePanel.class.getResourceAsStream( - endpoint.name().toLowerCase() + ".png")); + return false; } - MaterialTab tab = new MaterialTab(new ImageIcon(iconImage), tabGroup, null); - tab.setToolTipText(endpoint.getName() + " Hiscores"); - tab.setOnSelectEvent(() -> + selectedEndPoint = endpoint; + return true; + }); + + // Adding the lookup method to a mouseListener instead of the above onSelectedEvent + // Because sometimes you might want to switch the tab, without calling for lookup + // Ex: selecting the normal hiscores as default + tab.addMouseListener(new MouseAdapter() + { + @Override + public void mousePressed(MouseEvent mouseEvent) { if (loading) { - return false; + return; } - selectedEndPoint = endpoint; - return true; - }); + executor.execute(HiscorePanel.this::lookup); + } + }); - // Adding the lookup method to a mouseListener instead of the above onSelectedEvent - // Because sometimes you might want to switch the tab, without calling for lookup - // Ex: selecting the normal hiscores as default - tab.addMouseListener(new MouseAdapter() - { - @Override - public void mousePressed(MouseEvent mouseEvent) - { - if (loading) - { - return; - } - - executor.execute(HiscorePanel.this::lookup); - } - }); - - tabGroup.addTab(tab); - } - catch (IOException ex) - { - throw new RuntimeException(ex); - } + tabGroup.addTab(tab); } // Default selected tab is normal hiscores @@ -328,22 +306,22 @@ public class HiscorePanel extends PluginPanel label.setFont(FontManager.getRunescapeSmallFont()); label.setText("--"); - String skillIcon = "skill_icons_small/" + (skill == null ? "combat" : skill.getName().toLowerCase()) + ".png"; + String skillName = (skill == null ? "combat" : skill.getName().toLowerCase()); + String directory = "/skill_icons"; + if (skillName.equals("combat") || skillName.equals("overall")) + { + // Cannot use SpriteManager as HiscorePlugin loads before a Client is available + directory += "/"; + } + else + { + directory += "_small/"; + } + + String skillIcon = directory + skillName + ".png"; log.debug("Loading skill icon from {}", skillIcon); - try - { - BufferedImage icon; - synchronized (ImageIO.class) - { - icon = ImageIO.read(HiscorePanel.class.getResourceAsStream(skillIcon)); - } - label.setIcon(new ImageIcon(icon)); - } - catch (IOException ex) - { - log.warn(null, ex); - } + label.setIcon(new ImageIcon(ImageUtil.getResourceStreamFromClass(getClass(), skillIcon))); boolean totalLabel = skill == HiscoreSkill.OVERALL || skill == null; //overall or combat label.setIconTextGap(totalLabel ? 10 : 4); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePlugin.java index 56c350a1cc..f6f32b631a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePlugin.java @@ -32,7 +32,6 @@ import java.awt.image.BufferedImage; import java.lang.reflect.InvocationTargetException; import java.util.concurrent.ScheduledExecutorService; import javax.annotation.Nullable; -import javax.imageio.ImageIO; import javax.inject.Inject; import javax.inject.Provider; import javax.swing.SwingUtilities; @@ -49,6 +48,7 @@ import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.ClientToolbar; +import net.runelite.client.util.ImageUtil; import net.runelite.client.util.Text; import org.apache.commons.lang3.ArrayUtils; @@ -98,11 +98,7 @@ public class HiscorePlugin extends Plugin { hiscorePanel = injector.getInstance(HiscorePanel.class); - BufferedImage icon; - synchronized (ImageIO.class) - { - icon = ImageIO.read(getClass().getResourceAsStream("normal.png")); - } + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "normal.png"); navButton = NavigationButton.builder() .tooltip("Hiscore") diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPanel.java index 7415591e34..8aabb7e6b6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPanel.java @@ -36,10 +36,8 @@ import java.awt.Font; import java.awt.GridLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.io.IOException; import java.util.concurrent.ScheduledExecutorService; import javax.annotation.Nullable; -import javax.imageio.ImageIO; import javax.inject.Singleton; import javax.swing.Box; import javax.swing.ImageIcon; @@ -56,6 +54,7 @@ import net.runelite.client.account.SessionManager; import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.FontManager; import net.runelite.client.ui.PluginPanel; +import net.runelite.client.util.ImageUtil; import net.runelite.client.util.LinkBrowser; import net.runelite.client.util.RunnableExceptionLogger; @@ -92,21 +91,11 @@ public class InfoPanel extends PluginPanel static { - try - { - synchronized (ImageIO.class) - { - ARROW_RIGHT_ICON = new ImageIcon(ImageIO.read(InfoPanel.class.getResourceAsStream("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"))); - WIKI_ICON = new ImageIcon(ImageIO.read(InfoPanel.class.getResourceAsStream("wiki_icon.png"))); - } - } - catch (IOException e) - { - throw new RuntimeException(e); - } + ARROW_RIGHT_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "/util/arrow_right.png")); + GITHUB_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "github_icon.png")); + DISCORD_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "discord_icon.png")); + PATREON_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "patreon_icon.png")); + WIKI_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "wiki_icon.png")); } void init() diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPlugin.java index a394b6b0b7..f986a28ffa 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPlugin.java @@ -25,12 +25,12 @@ package net.runelite.client.plugins.info; import java.awt.image.BufferedImage; -import javax.imageio.ImageIO; import javax.inject.Inject; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.ClientToolbar; +import net.runelite.client.util.ImageUtil; @PluginDescriptor( name = "Info Panel", @@ -50,11 +50,7 @@ public class InfoPlugin extends Plugin final InfoPanel panel = injector.getInstance(InfoPanel.class); panel.init(); - BufferedImage icon; - synchronized (ImageIO.class) - { - icon = ImageIO.read(getClass().getResourceAsStream("info_icon.png")); - } + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "info_icon.png"); navButton = NavigationButton.builder() .tooltip("Info") diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/kingdomofmiscellania/KingdomPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/kingdomofmiscellania/KingdomPlugin.java index 9da8c27813..09302135f9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/kingdomofmiscellania/KingdomPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/kingdomofmiscellania/KingdomPlugin.java @@ -26,16 +26,16 @@ package net.runelite.client.plugins.kingdomofmiscellania; import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.Subscribe; -import java.awt.image.BufferedImage; -import javax.imageio.ImageIO; import javax.inject.Inject; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.api.GameState; +import static net.runelite.api.ItemID.TEAK_CHEST; import net.runelite.api.Varbits; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.VarbitChanged; +import net.runelite.client.game.ItemManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; @@ -57,20 +57,13 @@ public class KingdomPlugin extends Plugin @Inject private InfoBoxManager infoBoxManager; + @Inject + private ItemManager itemManager; + @Getter private int favor = 0, coffer = 0; private KingdomCounter counter; - private BufferedImage counterImage; - - @Override - protected void startUp() throws Exception - { - synchronized (ImageIO.class) - { - counterImage = ImageIO.read(getClass().getResourceAsStream("teak_chest.png")); - } - } @Override protected void shutDown() throws Exception @@ -112,7 +105,7 @@ public class KingdomPlugin extends Plugin { if (counter == null) { - counter = new KingdomCounter(counterImage, this); + counter = new KingdomCounter(itemManager.getImage(TEAK_CHEST), this); infoBoxManager.addInfoBox(counter); log.debug("Added Kingdom Infobox"); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryPanel.java index 33b7edba41..29f5525919 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryPanel.java @@ -33,14 +33,12 @@ import java.awt.GridBagLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; -import java.io.IOException; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; -import javax.imageio.ImageIO; import javax.inject.Singleton; import javax.swing.BorderFactory; import javax.swing.GroupLayout; @@ -52,7 +50,7 @@ import javax.swing.border.CompoundBorder; import javax.swing.border.EmptyBorder; import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.PluginPanel; -import net.runelite.client.util.SwingUtil; +import net.runelite.client.util.ImageUtil; @Singleton class KourendLibraryPanel extends PluginPanel @@ -67,19 +65,9 @@ class KourendLibraryPanel extends PluginPanel static { - try - { - synchronized (ImageIO.class) - { - BufferedImage resetIcon = ImageIO.read(KourendLibraryPanel.class.getResourceAsStream("reset.png")); - RESET_ICON = new ImageIcon(resetIcon); - RESET_CLICK_ICON = new ImageIcon(SwingUtil.grayscaleOffset(resetIcon, -100)); - } - } - catch (IOException e) - { - throw new RuntimeException(e); - } + final BufferedImage resetIcon = ImageUtil.getResourceStreamFromClass(KourendLibraryPanel.class, "/util/reset.png"); + RESET_ICON = new ImageIcon(resetIcon); + RESET_CLICK_ICON = new ImageIcon(ImageUtil.alphaOffset(resetIcon, -100)); } void init() diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryPlugin.java index 5c05200c82..d1e31b3ce9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryPlugin.java @@ -29,7 +29,6 @@ import com.google.inject.Provides; import java.awt.image.BufferedImage; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.imageio.ImageIO; import javax.inject.Inject; import javax.swing.SwingUtilities; import lombok.extern.slf4j.Slf4j; @@ -53,6 +52,7 @@ import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.ClientToolbar; import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.util.ImageUtil; @PluginDescriptor( name = "Kourend Library", @@ -109,11 +109,7 @@ public class KourendLibraryPlugin extends Plugin panel = injector.getInstance(KourendLibraryPanel.class); panel.init(); - BufferedImage icon; - synchronized (ImageIO.class) - { - icon = ImageIO.read(Book.class.getResourceAsStream("panel_icon.png")); - } + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "panel_icon.png"); navButton = NavigationButton.builder() .tooltip("Kourend Library") diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java index 3817e1a67b..35fe556174 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java @@ -34,7 +34,6 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import javax.imageio.ImageIO; import javax.inject.Inject; import javax.swing.SwingUtilities; import lombok.extern.slf4j.Slf4j; @@ -59,6 +58,7 @@ import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.ClientToolbar; import net.runelite.client.ui.NavigationButton; +import net.runelite.client.util.ImageUtil; import net.runelite.client.util.Text; import net.runelite.http.api.item.ItemPrice; @@ -125,11 +125,7 @@ public class LootTrackerPlugin extends Plugin panel = new LootTrackerPanel(itemManager); spriteManager.getSpriteAsync(SpriteID.UNUSED_TAB_INVENTORY, 0, panel::loadHeaderIcon); - final BufferedImage icon; - synchronized (ImageIO.class) - { - icon = ImageIO.read(LootTrackerPanel.class.getResourceAsStream("panel_icon.png")); - } + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "panel_icon.png"); navButton = NavigationButton.builder() .tooltip("Loot Tracker") diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/mta/alchemy/AlchemyRoomTimer.java b/runelite-client/src/main/java/net/runelite/client/plugins/mta/alchemy/AlchemyRoomTimer.java index 1cde50d6f3..3c85391da8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/mta/alchemy/AlchemyRoomTimer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/mta/alchemy/AlchemyRoomTimer.java @@ -25,12 +25,11 @@ package net.runelite.client.plugins.mta.alchemy; import java.awt.image.BufferedImage; -import java.io.IOException; import java.time.temporal.ChronoUnit; -import javax.imageio.ImageIO; import lombok.extern.slf4j.Slf4j; import net.runelite.client.plugins.Plugin; import net.runelite.client.ui.overlay.infobox.Timer; +import net.runelite.client.util.ImageUtil; @Slf4j public class AlchemyRoomTimer extends Timer @@ -51,17 +50,7 @@ public class AlchemyRoomTimer extends Timer return image; } - try - { - synchronized (ImageIO.class) - { - image = ImageIO.read(AlchemyRoomTimer.class.getResourceAsStream("reset.png")); - } - } - catch (IOException ex) - { - log.warn(null, ex); - } + image = ImageUtil.getResourceStreamFromClass(AlchemyRoomTimer.class, "/util/reset.png"); return image; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/notes/NotesPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/notes/NotesPlugin.java index e705561b27..fc178db38f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/notes/NotesPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/notes/NotesPlugin.java @@ -27,7 +27,6 @@ package net.runelite.client.plugins.notes; import com.google.common.eventbus.Subscribe; import com.google.inject.Provides; import java.awt.image.BufferedImage; -import javax.imageio.ImageIO; import javax.inject.Inject; import lombok.extern.slf4j.Slf4j; import net.runelite.api.events.SessionOpen; @@ -36,6 +35,7 @@ import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.ClientToolbar; +import net.runelite.client.util.ImageUtil; @PluginDescriptor( name = "Notes", @@ -67,11 +67,7 @@ public class NotesPlugin extends Plugin panel = injector.getInstance(NotesPanel.class); panel.init(config); - BufferedImage icon; - synchronized (ImageIO.class) - { - icon = ImageIO.read(getClass().getResourceAsStream("notes_icon.png")); - } + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "notes_icon.png"); navButton = NavigationButton.builder() .tooltip("Notes") diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohIcons.java b/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohIcons.java index e484621786..fe88c23027 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohIcons.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohIcons.java @@ -25,14 +25,13 @@ package net.runelite.client.plugins.poh; import java.awt.image.BufferedImage; -import java.io.IOException; import java.util.HashMap; import java.util.Map; -import javax.imageio.ImageIO; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import static net.runelite.api.ObjectID.*; import static net.runelite.api.NullObjectID.*; +import net.runelite.client.util.ImageUtil; @Slf4j public enum PohIcons @@ -105,17 +104,7 @@ public enum PohIcons return image; } - try - { - synchronized (ImageIO.class) - { - image = ImageIO.read(PohIcons.class.getResourceAsStream(getImageResource() + ".png")); - } - } - catch (IOException ex) - { - log.warn("unable to load image", ex); - } + image = ImageUtil.getResourceStreamFromClass(getClass(), getImageResource() + ".png"); return image; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/PuzzleSolverOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/PuzzleSolverOverlay.java index 33b8aff485..9fbdb61629 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/PuzzleSolverOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/PuzzleSolverOverlay.java @@ -32,14 +32,10 @@ import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; -import java.awt.geom.AffineTransform; -import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; -import java.io.IOException; import java.util.Arrays; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; -import javax.imageio.ImageIO; import javax.inject.Inject; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; @@ -47,8 +43,10 @@ import net.runelite.api.GameState; import net.runelite.api.InventoryID; import net.runelite.api.Item; import net.runelite.api.ItemContainer; +import static net.runelite.api.SpriteID.MINIMAP_DESTINATION_FLAG; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.game.SpriteManager; import net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver; import net.runelite.client.plugins.puzzlesolver.solver.PuzzleState; import net.runelite.client.plugins.puzzlesolver.solver.heuristics.ManhattanDistance; @@ -60,6 +58,7 @@ import net.runelite.client.ui.overlay.OverlayPriority; import net.runelite.client.ui.overlay.OverlayUtil; import net.runelite.client.ui.overlay.components.BackgroundComponent; import net.runelite.client.ui.overlay.components.TextComponent; +import net.runelite.client.util.ImageUtil; @Slf4j public class PuzzleSolverOverlay extends Overlay @@ -78,18 +77,18 @@ public class PuzzleSolverOverlay extends Overlay private final Client client; private final PuzzleSolverConfig config; private final ScheduledExecutorService executorService; + private final SpriteManager spriteManager; private PuzzleSolver solver; private Future solverFuture; private int[] cachedItems; - private BufferedImage downArrow; private BufferedImage upArrow; private BufferedImage leftArrow; private BufferedImage rightArrow; @Inject - public PuzzleSolverOverlay(Client client, PuzzleSolverConfig config, ScheduledExecutorService executorService) + public PuzzleSolverOverlay(Client client, PuzzleSolverConfig config, ScheduledExecutorService executorService, SpriteManager spriteManager) { setPosition(OverlayPosition.DYNAMIC); setPriority(OverlayPriority.HIGH); @@ -97,6 +96,7 @@ public class PuzzleSolverOverlay extends Overlay this.client = client; this.config = config; this.executorService = executorService; + this.spriteManager = spriteManager; } @Override @@ -427,28 +427,14 @@ public class PuzzleSolverOverlay extends Overlay private BufferedImage getDownArrow() { - if (downArrow == null) - { - try - { - synchronized (ImageIO.class) - { - downArrow = ImageIO.read(PuzzleSolverOverlay.class.getResourceAsStream("arrow.png")); - } - } - catch (IOException e) - { - log.warn("Error loading image", e); - } - } - return downArrow; + return spriteManager.getSprite(MINIMAP_DESTINATION_FLAG, 1); } private BufferedImage getUpArrow() { if (upArrow == null) { - upArrow = getRotatedImage(getDownArrow(), Math.PI); + upArrow = ImageUtil.rotateImage(getDownArrow(), Math.PI); } return upArrow; } @@ -457,7 +443,7 @@ public class PuzzleSolverOverlay extends Overlay { if (leftArrow == null) { - leftArrow = getRotatedImage(getDownArrow(), Math.PI / 2); + leftArrow = ImageUtil.rotateImage(getDownArrow(), Math.PI / 2); } return leftArrow; } @@ -466,16 +452,8 @@ public class PuzzleSolverOverlay extends Overlay { if (rightArrow == null) { - rightArrow = getRotatedImage(getDownArrow(), 3 * Math.PI / 2); + rightArrow = ImageUtil.rotateImage(getDownArrow(), 3 * Math.PI / 2); } return rightArrow; } - - private BufferedImage getRotatedImage(BufferedImage image, double theta) - { - AffineTransform transform = new AffineTransform(); - transform.rotate(theta, image.getWidth() / 2, image.getHeight() / 2); - AffineTransformOp transformOp = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR); - return transformOp.filter(image, null); - } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java index 1a2cf07cce..42a4b49d55 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java @@ -27,15 +27,12 @@ package net.runelite.client.plugins.raids; import com.google.common.eventbus.Subscribe; import com.google.inject.Binder; import com.google.inject.Provides; -import java.awt.image.BufferedImage; -import java.io.IOException; import java.text.DecimalFormat; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.imageio.ImageIO; import javax.inject.Inject; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -46,6 +43,7 @@ import net.runelite.api.InstanceTemplates; import net.runelite.api.NullObjectID; import static net.runelite.api.Perspective.SCENE_SIZE; import net.runelite.api.Point; +import static net.runelite.api.SpriteID.TAB_QUESTS_BROWN_RAIDING_PARTY; import net.runelite.api.Tile; import net.runelite.api.VarPlayer; import net.runelite.api.Varbits; @@ -60,6 +58,7 @@ import net.runelite.client.chat.ChatMessageBuilder; import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.chat.QueuedMessage; import net.runelite.client.config.ConfigManager; +import net.runelite.client.game.SpriteManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.raids.solver.Layout; @@ -86,7 +85,6 @@ public class RaidsPlugin extends Plugin private static final String SPLIT_REGEX = "\\s*,\\s*"; private static final Pattern ROTATION_REGEX = Pattern.compile("\\[(.*?)]"); - private BufferedImage raidsIcon; private RaidsTimer timer; @Getter @@ -116,6 +114,9 @@ public class RaidsPlugin extends Plugin @Inject private LayoutSolver layoutSolver; + @Inject + private SpriteManager spriteManager; + @Getter private Raid raid; @@ -270,7 +271,7 @@ public class RaidsPlugin extends Plugin if (config.raidsTimer() && message.startsWith(RAID_START_MESSAGE)) { - timer = new RaidsTimer(getRaidsIcon(), this, Instant.now()); + timer = new RaidsTimer(spriteManager.getSprite(TAB_QUESTS_BROWN_RAIDING_PARTY, 0), this, Instant.now()); infoBoxManager.addInfoBox(timer); } @@ -602,25 +603,4 @@ public class RaidsPlugin extends Plugin return room; } - - private BufferedImage getRaidsIcon() - { - if (raidsIcon != null) - { - return raidsIcon; - } - try - { - synchronized (ImageIO.class) - { - raidsIcon = ImageIO.read(RaidsPlugin.class.getResourceAsStream("raids_icon.png")); - } - } - catch (IOException ex) - { - log.warn("Unable to load image", ex); - } - - return raidsIcon; - } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerPlugin.java index 43b44c3658..4684e258b5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerPlugin.java @@ -39,7 +39,6 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; -import javax.imageio.ImageIO; import javax.inject.Inject; import lombok.AccessLevel; import lombok.Getter; @@ -53,6 +52,7 @@ import net.runelite.client.plugins.screenmarkers.ui.ScreenMarkerPluginPanel; import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.ClientToolbar; import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.util.ImageUtil; @PluginDescriptor( name = "Screen Markers", @@ -108,11 +108,7 @@ public class ScreenMarkerPlugin extends Plugin pluginPanel = injector.getInstance(ScreenMarkerPluginPanel.class); pluginPanel.rebuild(); - BufferedImage icon; - synchronized (ImageIO.class) - { - icon = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream(ICON_FILE)); - } + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), ICON_FILE); navigationButton = NavigationButton.builder() .tooltip(PLUGIN_NAME) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerCreationPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerCreationPanel.java index 6385fa3163..51567dd2dc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerCreationPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerCreationPanel.java @@ -29,8 +29,7 @@ import java.awt.Color; import java.awt.GridLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.io.IOException; -import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; @@ -39,6 +38,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 { @@ -54,21 +54,13 @@ public class ScreenMarkerCreationPanel extends JPanel static { - try - { - 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); - } + CONFIRM_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(ScreenMarkerPlugin.class, "confirm_icon.png")); + CANCEL_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(ScreenMarkerPlugin.class, "cancel_icon.png")); + + 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) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPanel.java index e7b4d71044..053fb57613 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPanel.java @@ -34,8 +34,6 @@ import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; -import java.io.IOException; -import javax.imageio.ImageIO; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JColorChooser; @@ -55,7 +53,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.FlatTextField; -import net.runelite.client.util.SwingUtil; +import net.runelite.client.util.ImageUtil; class ScreenMarkerPanel extends JPanel { @@ -108,48 +106,38 @@ class ScreenMarkerPanel extends JPanel static { - try - { - synchronized (ImageIO.class) - { - BufferedImage borderImg = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("border_color_icon.png")); - BORDER_COLOR_ICON = new ImageIcon(borderImg); - BORDER_COLOR_HOVER_ICON = new ImageIcon(SwingUtil.grayscaleOffset(borderImg, -100)); + final BufferedImage borderImg = ImageUtil.getResourceStreamFromClass(ScreenMarkerPlugin.class, "border_color_icon.png"); + BORDER_COLOR_ICON = new ImageIcon(borderImg); + 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(SwingUtil.grayscaleOffset(noBorderImg, -100)); + final BufferedImage noBorderImg = ImageUtil.getResourceStreamFromClass(ScreenMarkerPlugin.class, "no_border_color_icon.png"); + NO_BORDER_COLOR_ICON = new ImageIcon(noBorderImg); + 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(SwingUtil.grayscaleOffset(fillImg, -100)); + final BufferedImage fillImg = ImageUtil.getResourceStreamFromClass(ScreenMarkerPlugin.class, "fill_color_icon.png"); + FILL_COLOR_ICON = new ImageIcon(fillImg); + 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(SwingUtil.grayscaleOffset(noFillImg, -100)); + final BufferedImage noFillImg = ImageUtil.getResourceStreamFromClass(ScreenMarkerPlugin.class, "no_fill_color_icon.png"); + NO_FILL_COLOR_ICON = new ImageIcon(noFillImg); + 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(SwingUtil.grayscaleOffset(opacityImg, -100)); - NO_OPACITY_ICON = new ImageIcon(SwingUtil.grayscaleOffset(opacityImg, -150)); + final BufferedImage opacityImg = ImageUtil.getResourceStreamFromClass(ScreenMarkerPlugin.class, "opacity_icon.png"); + FULL_OPACITY_ICON = new ImageIcon(opacityImg); + 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(SwingUtil.grayscaleOffset(visibleImg, -100)); + final BufferedImage visibleImg = ImageUtil.getResourceStreamFromClass(ScreenMarkerPlugin.class, "visible_icon.png"); + VISIBLE_ICON = new ImageIcon(visibleImg); + 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(SwingUtil.grayscaleOffset(invisibleImg, -100)); + final BufferedImage invisibleImg = ImageUtil.getResourceStreamFromClass(ScreenMarkerPlugin.class, "invisible_icon.png"); + INVISIBLE_ICON = new ImageIcon(invisibleImg); + 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(SwingUtil.grayscaleOffset(deleteImg, -100)); - } - } - catch (IOException e) - { - throw new RuntimeException(e); - } + final BufferedImage deleteImg = ImageUtil.getResourceStreamFromClass(ScreenMarkerPlugin.class, "delete_icon.png"); + DELETE_ICON = new ImageIcon(deleteImg); + DELETE_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(deleteImg, -100)); } ScreenMarkerPanel(ScreenMarkerPlugin plugin, ScreenMarkerOverlay marker) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPluginPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPluginPanel.java index 9dca4e8d11..3e43abaa4d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPluginPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPluginPanel.java @@ -34,8 +34,7 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.io.IOException; -import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; import javax.swing.Box; import javax.swing.ImageIcon; import javax.swing.JLabel; @@ -47,6 +46,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 @@ -80,18 +80,9 @@ public class ScreenMarkerPluginPanel extends PluginPanel static { - try - { - 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); - } + final BufferedImage addIcon = ImageUtil.getResourceStreamFromClass(ScreenMarkerPlugin.class, "add_icon.png"); + ADD_ICON = new ImageIcon(addIcon); + ADD_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(addIcon, 0.53f)); } public void init() diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotOverlay.java index 69357d5bdb..07248ed58a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotOverlay.java @@ -31,16 +31,13 @@ import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.image.BufferedImage; -import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.function.Consumer; -import javax.imageio.ImageIO; import javax.inject.Inject; -import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.api.MainBufferProvider; import net.runelite.client.ui.DrawManager; @@ -50,41 +47,26 @@ import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayPriority; -@Slf4j public class ScreenshotOverlay extends Overlay { private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MMM. dd, yyyy"); private static final int REPORT_BUTTON_X_OFFSET = 404; - private static BufferedImage REPORT_BUTTON; - - static - { - try - { - synchronized (ImageIO.class) - { - REPORT_BUTTON = ImageIO.read(ScreenshotPlugin.class.getResourceAsStream("report_button.png")); - } - } - catch (IOException e) - { - log.warn("Report button image failed to load", e); - } - } private final Client client; private final DrawManager drawManager; + private final ScreenshotPlugin plugin; private final Queue> consumers = new ConcurrentLinkedQueue<>(); @Inject - public ScreenshotOverlay(Client client, DrawManager drawManager) + public ScreenshotOverlay(Client client, DrawManager drawManager, ScreenshotPlugin plugin) { setPosition(OverlayPosition.DYNAMIC); setPriority(OverlayPriority.HIGH); setLayer(OverlayLayer.ABOVE_WIDGETS); this.client = client; this.drawManager = drawManager; + this.plugin = plugin; } @Override @@ -97,9 +79,9 @@ public class ScreenshotOverlay extends Overlay final MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider(); final int imageHeight = ((BufferedImage) bufferProvider.getImage()).getHeight(); - final int y = imageHeight - REPORT_BUTTON.getHeight() - 1; + final int y = imageHeight - plugin.getReportButton().getHeight() - 1; - graphics.drawImage(REPORT_BUTTON, REPORT_BUTTON_X_OFFSET, y, null); + graphics.drawImage(plugin.getReportButton(), REPORT_BUTTON_X_OFFSET, y, null); graphics.setFont(FontManager.getRunescapeSmallFont()); FontMetrics fontMetrics = graphics.getFontMetrics(); @@ -108,8 +90,8 @@ public class ScreenshotOverlay extends Overlay final int dateWidth = fontMetrics.stringWidth(date); final int dateHeight = fontMetrics.getHeight(); - final int textX = REPORT_BUTTON_X_OFFSET + REPORT_BUTTON.getWidth() / 2 - dateWidth / 2; - final int textY = y + REPORT_BUTTON.getHeight() / 2 + dateHeight / 2; + final int textX = REPORT_BUTTON_X_OFFSET + plugin.getReportButton().getWidth() / 2 - dateWidth / 2; + final int textY = y + plugin.getReportButton().getHeight() / 2 + dateHeight / 2; graphics.setColor(Color.BLACK); graphics.drawString(date, textX + 1, textY + 1); @@ -130,7 +112,7 @@ public class ScreenshotOverlay extends Overlay public void queueForTimestamp(Consumer screenshotConsumer) { - if (REPORT_BUTTON == null) + if (plugin.getReportButton() == null) { return; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java index 01e4ab47c4..557f19c3c1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java @@ -52,13 +52,17 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.imageio.ImageIO; import javax.inject.Inject; +import lombok.AccessLevel; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.runelite.api.ChatMessageType; import net.runelite.api.Client; import net.runelite.api.GameState; import net.runelite.api.Point; +import net.runelite.api.SpriteID; import net.runelite.api.WorldType; import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; import net.runelite.api.events.WidgetLoaded; import net.runelite.api.widgets.Widget; @@ -74,6 +78,7 @@ import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.Notifier; import static net.runelite.client.RuneLite.SCREENSHOT_DIR; import net.runelite.client.config.ConfigManager; +import net.runelite.client.game.SpriteManager; import net.runelite.client.input.KeyManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; @@ -85,6 +90,7 @@ import net.runelite.client.ui.DrawManager; import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.util.HotkeyListener; +import net.runelite.client.util.ImageUtil; import net.runelite.client.util.Text; import net.runelite.http.api.RuneLiteAPI; import okhttp3.Call; @@ -170,6 +176,12 @@ public class ScreenshotPlugin extends Plugin @Inject private KeyManager keyManager; + @Inject + private SpriteManager spriteManager; + + @Getter(AccessLevel.PACKAGE) + private BufferedImage reportButton; + private NavigationButton titleBarButton; private final HotkeyListener hotkeyListener = new HotkeyListener(() -> config.hotkey()) @@ -194,42 +206,30 @@ public class ScreenshotPlugin extends Plugin SCREENSHOT_DIR.mkdirs(); keyManager.registerKeyListener(hotkeyListener); - try - { - BufferedImage iconImage; - synchronized (ImageIO.class) - { - iconImage = ImageIO.read(ScreenshotPlugin.class.getResourceAsStream("screenshot.png")); - } + final BufferedImage iconImage = ImageUtil.getResourceStreamFromClass(getClass(), "screenshot.png"); - titleBarButton = NavigationButton.builder() - .tab(false) - .tooltip("Take screenshot") - .icon(iconImage) - .onClick(() -> takeScreenshot(format(new Date()))) - .popup(ImmutableMap - .builder() - .put("Open screenshot folder...", () -> + titleBarButton = NavigationButton.builder() + .tab(false) + .tooltip("Take screenshot") + .icon(iconImage) + .onClick(() -> takeScreenshot(format(new Date()))) + .popup(ImmutableMap + .builder() + .put("Open screenshot folder...", () -> + { + try { - try - { - Desktop.getDesktop().open(SCREENSHOT_DIR); - } - catch (IOException ex) - { - log.warn("Error opening screenshot dir", ex); + Desktop.getDesktop().open(SCREENSHOT_DIR); + } + catch (IOException ex) + { + log.warn("Error opening screenshot dir", ex); + } + }) + .build()) + .build(); - } - }) - .build()) - .build(); - - clientToolbar.addNavigation(titleBarButton); - } - catch (IOException ex) - { - log.warn("Error adding screenshot button to titlebar", ex); - } + clientToolbar.addNavigation(titleBarButton); } @Override @@ -240,6 +240,16 @@ public class ScreenshotPlugin extends Plugin keyManager.unregisterKeyListener(hotkeyListener); } + @Subscribe + public void onGameStateChanged(GameStateChanged event) + { + if (event.getGameState() == GameState.LOGGED_IN + && reportButton == null) + { + reportButton = spriteManager.getSprite(SpriteID.CHATBOX_REPORT_BUTTON, 0); + } + } + @Subscribe public void onGameTick(GameTick event) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculatorPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculatorPlugin.java index fe073b7822..7f90d123fb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculatorPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculatorPlugin.java @@ -26,7 +26,6 @@ package net.runelite.client.plugins.skillcalculator; import java.awt.image.BufferedImage; -import javax.imageio.ImageIO; import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.client.game.ItemManager; @@ -37,6 +36,7 @@ import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.ClientUI; import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.ClientToolbar; +import net.runelite.client.util.ImageUtil; @PluginDescriptor( name = "Skill Calculator", @@ -69,11 +69,7 @@ public class SkillCalculatorPlugin extends Plugin @Override protected void startUp() throws Exception { - BufferedImage icon; - synchronized (ImageIO.class) - { - icon = ImageIO.read(getClass().getResourceAsStream("calc.png")); - } + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "calc.png"); SkillCalculator.spriteManager = spriteManager; SkillCalculator.itemManager = itemManager; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportPoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportPoint.java index e283bec935..831cda90d1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportPoint.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportPoint.java @@ -25,10 +25,9 @@ */ package net.runelite.client.plugins.worldmap; -import java.io.IOException; -import javax.imageio.ImageIO; import lombok.Getter; import net.runelite.client.ui.overlay.worldmap.WorldMapPoint; +import net.runelite.client.util.ImageUtil; class TeleportPoint extends WorldMapPoint { @@ -42,13 +41,6 @@ class TeleportPoint extends WorldMapPoint this.data = data; setTooltip(data.getTooltip()); - try - { - setImage(ImageIO.read(WorldMapPlugin.class.getResourceAsStream(data.getIconPath()))); - } - catch (IOException e) - { - throw new RuntimeException(e); - } + setImage(ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, data.getIconPath())); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/WorldMapPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/WorldMapPlugin.java index 8f2e701299..bb60566745 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/WorldMapPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/WorldMapPlugin.java @@ -29,9 +29,7 @@ import com.google.common.eventbus.Subscribe; import com.google.inject.Inject; import com.google.inject.Provides; import java.awt.image.BufferedImage; -import java.io.IOException; import java.util.Arrays; -import javax.imageio.ImageIO; import net.runelite.api.Client; import net.runelite.api.Experience; import net.runelite.api.Skill; @@ -41,6 +39,7 @@ import net.runelite.client.config.ConfigManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.overlay.worldmap.WorldMapPointManager; +import net.runelite.client.util.ImageUtil; @PluginDescriptor( name = "World Map", @@ -73,23 +72,13 @@ public class WorldMapPlugin extends Plugin BLANK_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB); - try - { - synchronized (ImageIO.class) - { - FAIRY_TRAVEL_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB); - final BufferedImage icon = ImageIO.read(WorldMapPlugin.class.getResourceAsStream("fairy_ring_travel.png")); - FAIRY_TRAVEL_ICON.getGraphics().drawImage(icon, 1, 1, null); + FAIRY_TRAVEL_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB); + final BufferedImage fairyTravelIcon = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, "fairy_ring_travel.png"); + FAIRY_TRAVEL_ICON.getGraphics().drawImage(fairyTravelIcon, 1, 1, null); - NOPE_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB); - final BufferedImage nopeImage = ImageIO.read(WorldMapPlugin.class.getResourceAsStream("nope_icon.png")); - NOPE_ICON.getGraphics().drawImage(nopeImage, 1, 1, null); - } - } - catch (IOException e) - { - throw new RuntimeException(e); - } + NOPE_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB); + final BufferedImage nopeImage = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, "nope_icon.png"); + NOPE_ICON.getGraphics().drawImage(nopeImage, 1, 1, null); } @Inject diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java index 4eb005b5ac..9f13ea9d33 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java @@ -33,7 +33,6 @@ import java.awt.image.BufferedImage; import java.time.temporal.ChronoUnit; import java.util.EnumSet; import java.util.Objects; -import javax.imageio.ImageIO; import javax.inject.Inject; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; @@ -53,6 +52,7 @@ import static net.runelite.client.plugins.xptracker.XpWorldType.NORMAL; import net.runelite.client.task.Schedule; import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.ClientToolbar; +import net.runelite.client.util.ImageUtil; import net.runelite.http.api.xp.XpClient; @PluginDescriptor( @@ -102,11 +102,7 @@ public class XpTrackerPlugin extends Plugin { xpPanel = new XpPanel(this, client, skillIconManager); - BufferedImage icon; - synchronized (ImageIO.class) - { - icon = ImageIO.read(getClass().getResourceAsStream("xp.png")); - } + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "/skill_icons/overall.png"); navButton = NavigationButton.builder() .tooltip("XP Tracker") diff --git a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java index 0539517a65..22424d4f74 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java @@ -38,9 +38,7 @@ import java.awt.LayoutManager; import java.awt.Rectangle; import java.awt.TrayIcon; import java.awt.image.BufferedImage; -import java.io.IOException; import javax.annotation.Nullable; -import javax.imageio.ImageIO; import javax.inject.Inject; import javax.inject.Singleton; import javax.swing.BoxLayout; @@ -70,6 +68,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; @@ -95,27 +94,9 @@ public class ClientUI static { - BufferedImage icon; - BufferedImage sidebarOpen; - BufferedImage sidebarClose; - - try - { - synchronized (ImageIO.class) - { - 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) - { - throw new RuntimeException(e); - } - - ICON = icon; - SIDEBAR_OPEN = sidebarOpen; - SIDEBAR_CLOSE = sidebarClose; + ICON = ImageUtil.getResourceStreamFromClass(ClientUI.class, "/runelite.png"); + SIDEBAR_OPEN = ImageUtil.getResourceStreamFromClass(ClientUI.class, "open.png"); + SIDEBAR_CLOSE = ImageUtil.flipImage(SIDEBAR_OPEN, true, false); } @Getter diff --git a/runelite-client/src/main/java/net/runelite/client/util/ColorUtil.java b/runelite-client/src/main/java/net/runelite/client/util/ColorUtil.java index f09cac21c9..7cd6ae0e1a 100644 --- a/runelite-client/src/main/java/net/runelite/client/util/ColorUtil.java +++ b/runelite-client/src/main/java/net/runelite/client/util/ColorUtil.java @@ -112,4 +112,14 @@ public class ColorUtil { return String.format("%06x", color.getRGB() & 0xFFFFFF); } + + static boolean isFullyTransparent(final Color color) + { + return color.getAlpha() == 0; + } + + static boolean isNotFullyTransparent(final Color color) + { + return !isFullyTransparent(color); + } } diff --git a/runelite-client/src/main/java/net/runelite/client/util/ImageUtil.java b/runelite-client/src/main/java/net/runelite/client/util/ImageUtil.java new file mode 100644 index 0000000000..3d66bef7da --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/util/ImageUtil.java @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2018, Jordan Atwood + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.util; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.geom.AffineTransform; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; +import java.awt.image.RescaleOp; +import java.io.IOException; +import java.util.Arrays; +import javax.imageio.ImageIO; +import javax.swing.GrayFilter; +import java.util.function.Predicate; + +/** + * 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. + * + * @param image The image to be darkened or brightened. + * @param offset A signed 8-bit integer value to brighten or darken the image with. + * Values above 0 will brighten, and values below 0 will darken. + * @return The given image with its brightness adjusted by the given offset. + */ + public static BufferedImage grayscaleOffset(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); + for (int i = 0; i < numComponents; i++) + { + offsets[i] = offsetFloat; + } + // Set alpha to not offset + offsets[numComponents - 1] = 0f; + + 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. + * + * @param image the BufferedImage. + * @param newWidth The width to set the BufferedImage to. + * @param newHeight The height to set the BufferedImage to. + * @return The BufferedImage with the specified dimensions + */ + public static BufferedImage resizeImage(final BufferedImage image, final int newWidth, final int newHeight) + { + final Image resized = image.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH); + return ImageUtil.bufferedImageFromImage(resized); + } + + /** + * Re-size a BufferedImage's canvas to the given dimensions. + * + * @param image The image whose canvas should be re-sized. + * @param newWidth The width to set the BufferedImage to. + * @param newHeight The height to set the BufferedImage to. + * @return The BufferedImage centered within canvas of given dimensions. + */ + public static BufferedImage resizeCanvas(final BufferedImage image, final int newWidth, final int newHeight) + { + final BufferedImage dimg = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB); + final int centeredX = newWidth / 2 - image.getWidth() / 2; + final int centeredY = newHeight / 2 - image.getHeight() / 2; + + final Graphics2D g2d = dimg.createGraphics(); + g2d.drawImage(image, centeredX, centeredY, null); + g2d.dispose(); + return dimg; + } + + /** + * Rotates an image around its center by a given number of radians. + * + * @param image The image to be rotated. + * @param theta The number of radians to rotate the image. + * @return The given image, rotated by the given theta. + */ + public static BufferedImage rotateImage(final BufferedImage image, final double theta) + { + AffineTransform transform = new AffineTransform(); + transform.rotate(theta, image.getWidth() / 2.0, image.getHeight() / 2.0); + AffineTransformOp transformOp = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR); + 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; + } + + /** + * Outlines non-transparent pixels of a BufferedImage with the given color. + * + * @param image The image to be outlined. + * @param color The color to use for the outline. + * @return The BufferedImage with its edges outlined with the given color. + */ + public static BufferedImage outlineImage(final BufferedImage image, final Color color) + { + return outlineImage(image, color, ColorUtil::isNotFullyTransparent, false); + } + + /** + * Outlines pixels of a BufferedImage with the given color, using a given predicate to colorize + * the given image for outlining. + * + * @param image The image to be outlined. + * @param color The color to use for the outline. + * @param fillCondition The predicate to be consumed by {@link #fillImage(BufferedImage, Color, Predicate) fillImage(BufferedImage, Color, Predicate)} + * @return The BufferedImage with its edges outlined with the given color. + */ + public static BufferedImage outlineImage(final BufferedImage image, final Color color, final Predicate fillCondition) + { + return outlineImage(image, color, fillCondition, false); + } + + /** + * Outlines non-transparent pixels of a BufferedImage with the given color. Optionally outlines + * corners in addition to edges. + * + * @param image The image to be outlined. + * @param color The color to use for the outline. + * @param outlineCorners Whether to draw an outline around corners, or only around edges. + * @return The BufferedImage with its edges--and optionally, corners--outlined + * with the given color. + */ + public static BufferedImage outlineImage(final BufferedImage image, final Color color, final Boolean outlineCorners) + { + return outlineImage(image, color, ColorUtil::isNotFullyTransparent, outlineCorners); + } + + /** + * Outlines pixels of a BufferedImage with the given color, using a given predicate to colorize + * the given image for outlining. Optionally outlines corners in addition to edges. + * + * @param image The image to be outlined. + * @param color The color to use for the outline. + * @param fillCondition The predicate to be consumed by {@link #fillImage(BufferedImage, Color, Predicate) fillImage(BufferedImage, Color, Predicate)} + * @param outlineCorners Whether to draw an outline around corners, or only around edges. + * @return The BufferedImage with its edges--and optionally, corners--outlined + * with the given color. + */ + public static BufferedImage outlineImage(final BufferedImage image, final Color color, final Predicate fillCondition, final Boolean outlineCorners) + { + final BufferedImage filledImage = fillImage(image, color, fillCondition); + final BufferedImage outlinedImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB); + + final Graphics2D g2d = outlinedImage.createGraphics(); + for (int x = -1; x <= 1; x++) + { + for (int y = -1; y <= 1; y++) + { + if ((x == 0 && y == 0) + || (!outlineCorners && Math.abs(x) + Math.abs(y) != 1)) + { + continue; + } + + g2d.drawImage(filledImage, x, y, null); + } + } + g2d.drawImage(image, 0, 0, null); + g2d.dispose(); + + return outlinedImage; + } + + /** + * Reads an image resource from a given path relative to a given class. + * This method is primarily shorthand for the synchronization and error handling required for + * loading image resources from classes. + * + * @param c The class to be referenced for resource path. + * @param path The path, relative to the given class. + * @return A {@link BufferedImage} of the loaded image resource from the given path. + */ + public static BufferedImage getResourceStreamFromClass(final Class c, final String path) + { + try + { + synchronized (ImageIO.class) + { + return ImageIO.read(c.getResourceAsStream(path)); + } + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + /** + * Fills all non-transparent pixels of the given image with the given color. + * + * @param image The image which should have its non-transparent pixels filled. + * @param color The color with which to fill pixels. + * @return The given image with all non-transparent pixels set to the given color. + */ + static BufferedImage fillImage(final BufferedImage image, final Color color) + { + return fillImage(image, color, ColorUtil::isNotFullyTransparent); + } + + /** + * Fills pixels of the given image with the given color based on a given fill condition + * predicate. + * + * @param image The image which should have its non-transparent pixels filled. + * @param color The color with which to fill pixels. + * @param fillCondition The condition on which to fill pixels with the given color. + * @return The given image with all pixels fulfilling the fill condition predicate + * set to the given color. + */ + static BufferedImage fillImage(final BufferedImage image, final Color color, final Predicate fillCondition) + { + final BufferedImage filledImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB); + for (int x = 0; x < filledImage.getWidth(); x++) + { + for (int y = 0; y < filledImage.getHeight(); y++) + { + final Color pixelColor = new Color(image.getRGB(x, y), true); + if (!fillCondition.test(pixelColor)) + { + continue; + } + + filledImage.setRGB(x, y, color.getRGB()); + } + } + return filledImage; + } + + /** + * Performs a rescale operation on the image's color components. + * + * @param image The image to be adjusted. + * @param scales An array of scale operations to be performed on the image's color components. + * @param offsets An array of offset operations to be performed on the image's color components. + * @return The modified image after applying the given adjustments. + */ + private static BufferedImage offset(final BufferedImage image, final float[] scales, final float[] offsets) + { + return new RescaleOp(scales, offsets, null).filter(image, null); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/util/SwingUtil.java b/runelite-client/src/main/java/net/runelite/client/util/SwingUtil.java index 514b7c4550..e951393709 100644 --- a/runelite-client/src/main/java/net/runelite/client/util/SwingUtil.java +++ b/runelite-client/src/main/java/net/runelite/client/util/SwingUtil.java @@ -29,10 +29,8 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Frame; -import java.awt.Graphics2D; import java.awt.Image; import java.awt.Rectangle; -import java.awt.RenderingHints; import java.awt.SystemTray; import java.awt.Toolkit; import java.awt.TrayIcon; @@ -42,8 +40,6 @@ import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; -import java.awt.image.LookupOp; -import java.awt.image.LookupTable; import java.util.Enumeration; import java.util.concurrent.Callable; import java.util.function.BiConsumer; @@ -106,40 +102,6 @@ public class SwingUtil System.setProperty("sun.awt.noerasebackground", "true"); } - /** - * Offsets an image in the grayscale (darkens/brightens) by an offset - */ - public static BufferedImage grayscaleOffset(BufferedImage image, int offset) - { - int numComponents = image.getColorModel().getNumComponents(); - int index = numComponents - 1; - - LookupTable lookup = new LookupTable(0, numComponents) - { - @Override - public int[] lookupPixel(int[] src, int[] dest) - { - if (dest[index] != 0) - { - dest[index] = dest[index] + offset; - if (dest[index] < 0) - { - dest[index] = 0; - } - else if (dest[index] > 255) - { - dest[index] = 255; - } - } - - return dest; - } - }; - - LookupOp op = new LookupOp(lookup, new RenderingHints(null)); - return op.filter(image, null); - } - /** * Safely sets Swing theme * @@ -280,25 +242,6 @@ public class SwingUtil }); } - /** - * Re-size a BufferedImage to the given dimensions. - * - * @param image the BufferedImage. - * @param newWidth The width to set the BufferedImage to. - * @param newHeight The height to set the BufferedImage to. - * @return The BufferedImage with the specified dimensions - */ - private static BufferedImage resizeImage(BufferedImage image, int newWidth, 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; - } - /** * Create swing button from navigation button. * @@ -314,7 +257,7 @@ public class SwingUtil { final BufferedImage scaledImage = iconSize > 0 - ? resizeImage(navigationButton.getIcon(), iconSize, iconSize) + ? ImageUtil.resizeImage(navigationButton.getIcon(), iconSize, iconSize) : navigationButton.getIcon(); final JButton button = new JButton(); @@ -364,5 +307,4 @@ public class SwingUtil { return SubstanceCoreUtilities.getTitlePaneComponent(frame) != null; } - } diff --git a/runelite-client/src/main/resources/net/runelite/client/game/Captain_clan_rank.png b/runelite-client/src/main/resources/net/runelite/client/game/Captain_clan_rank.png deleted file mode 100644 index 396ec708c9..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/game/Captain_clan_rank.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/game/Corporal_clan_rank.png b/runelite-client/src/main/resources/net/runelite/client/game/Corporal_clan_rank.png deleted file mode 100644 index 197b1ad469..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/game/Corporal_clan_rank.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/game/Friend_clan_rank.png b/runelite-client/src/main/resources/net/runelite/client/game/Friend_clan_rank.png deleted file mode 100644 index ab2d17e156..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/game/Friend_clan_rank.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/game/General_clan_rank.png b/runelite-client/src/main/resources/net/runelite/client/game/General_clan_rank.png deleted file mode 100644 index 42a4fd8be3..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/game/General_clan_rank.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/game/JMod_clan_rank.png b/runelite-client/src/main/resources/net/runelite/client/game/JMod_clan_rank.png deleted file mode 100644 index a2d4ca9037..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/game/JMod_clan_rank.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/game/Lieutenant_clan_rank.png b/runelite-client/src/main/resources/net/runelite/client/game/Lieutenant_clan_rank.png deleted file mode 100644 index 8663e80186..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/game/Lieutenant_clan_rank.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/game/Owner_clan_rank.png b/runelite-client/src/main/resources/net/runelite/client/game/Owner_clan_rank.png deleted file mode 100644 index 96f259592a..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/game/Owner_clan_rank.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/game/Recruit_clan_rank.png b/runelite-client/src/main/resources/net/runelite/client/game/Recruit_clan_rank.png deleted file mode 100644 index 0debd30512..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/game/Recruit_clan_rank.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/game/Sergeant_clan_rank.png b/runelite-client/src/main/resources/net/runelite/client/game/Sergeant_clan_rank.png deleted file mode 100644 index d85228c073..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/game/Sergeant_clan_rank.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/agility/agilityarenaticket.png b/runelite-client/src/main/resources/net/runelite/client/plugins/agility/agilityarenaticket.png deleted file mode 100644 index 55b841db97..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/agility/agilityarenaticket.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/cluescrolls/clue_scroll.png b/runelite-client/src/main/resources/net/runelite/client/plugins/cluescrolls/clue_scroll.png deleted file mode 100644 index c4f28ce63b..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/cluescrolls/clue_scroll.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/cluescrolls/spade.png b/runelite-client/src/main/resources/net/runelite/client/plugins/cluescrolls/spade.png deleted file mode 100644 index 092326b31f..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/cluescrolls/spade.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/config/stars/on.png b/runelite-client/src/main/resources/net/runelite/client/plugins/config/star_on.png similarity index 100% rename from runelite-client/src/main/resources/net/runelite/client/plugins/config/stars/on.png rename to runelite-client/src/main/resources/net/runelite/client/plugins/config/star_on.png diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/config/stars/off.png b/runelite-client/src/main/resources/net/runelite/client/plugins/config/stars/off.png deleted file mode 100644 index b030162e0c..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/config/stars/off.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/config/switchers/on.png b/runelite-client/src/main/resources/net/runelite/client/plugins/config/switcher_on.png similarity index 100% rename from runelite-client/src/main/resources/net/runelite/client/plugins/config/switchers/on.png rename to runelite-client/src/main/resources/net/runelite/client/plugins/config/switcher_on.png diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/config/switchers/off.png b/runelite-client/src/main/resources/net/runelite/client/plugins/config/switchers/off.png deleted file mode 100644 index ff25cc611a..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/config/switchers/off.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/deathindicator/bones.png b/runelite-client/src/main/resources/net/runelite/client/plugins/deathindicator/bones.png deleted file mode 100644 index 90ff52f208..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/deathindicator/bones.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/deathindicator/clue_arrow.png b/runelite-client/src/main/resources/net/runelite/client/plugins/deathindicator/clue_arrow.png deleted file mode 100644 index 1d0e780564..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/deathindicator/clue_arrow.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/grandexchange/arrow_left.png b/runelite-client/src/main/resources/net/runelite/client/plugins/grandexchange/arrow_left.png deleted file mode 100644 index 480358e6a1..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/grandexchange/arrow_left.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/grandexchange/arrow_right.png b/runelite-client/src/main/resources/net/runelite/client/plugins/grandexchange/arrow_right.png deleted file mode 100644 index 63ab23f273..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/grandexchange/arrow_right.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/agility.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/agility.png deleted file mode 100644 index 19c26d9022..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/agility.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/attack.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/attack.png deleted file mode 100644 index 4d9aaa87f6..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/attack.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/combat.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/combat.png deleted file mode 100644 index b1e17fb28d..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/combat.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/construction.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/construction.png deleted file mode 100644 index 3c8e176a3e..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/construction.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/cooking.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/cooking.png deleted file mode 100644 index 2030f1d25b..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/cooking.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/crafting.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/crafting.png deleted file mode 100644 index 7b5fd52464..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/crafting.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/defence.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/defence.png deleted file mode 100644 index 370a1cc729..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/defence.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/farming.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/farming.png deleted file mode 100644 index 0b9becd5f5..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/farming.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/firemaking.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/firemaking.png deleted file mode 100644 index a9297c8edc..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/firemaking.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/fishing.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/fishing.png deleted file mode 100644 index caa5ca9738..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/fishing.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/fletching.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/fletching.png deleted file mode 100644 index 56b50c4067..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/fletching.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/herblore.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/herblore.png deleted file mode 100644 index fde27351c4..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/herblore.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/hitpoints.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/hitpoints.png deleted file mode 100644 index bf431f7518..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/hitpoints.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/hunter.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/hunter.png deleted file mode 100644 index 88be793bbb..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/hunter.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/magic.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/magic.png deleted file mode 100644 index 5e9974c7bd..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/magic.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/mining.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/mining.png deleted file mode 100644 index 57430882d0..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/mining.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/overall.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/overall.png deleted file mode 100644 index 4b2dd265a4..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/overall.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/prayer.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/prayer.png deleted file mode 100644 index 7c348987eb..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/prayer.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/ranged.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/ranged.png deleted file mode 100644 index 9b73588023..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/ranged.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/runecraft.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/runecraft.png deleted file mode 100644 index 2c52ffe913..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/runecraft.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/slayer.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/slayer.png deleted file mode 100644 index f02563044c..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/slayer.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/smithing.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/smithing.png deleted file mode 100644 index b07ec45b86..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/smithing.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/strength.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/strength.png deleted file mode 100644 index 976c550712..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/strength.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/thieving.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/thieving.png deleted file mode 100644 index 4aca64fdb0..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/thieving.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/woodcutting.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/woodcutting.png deleted file mode 100644 index 379d09b76f..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/woodcutting.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/kingdomofmiscellania/teak_chest.png b/runelite-client/src/main/resources/net/runelite/client/plugins/kingdomofmiscellania/teak_chest.png deleted file mode 100644 index 9fc9961b4f..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/kingdomofmiscellania/teak_chest.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/mta/alchemy/reset.png b/runelite-client/src/main/resources/net/runelite/client/plugins/mta/alchemy/reset.png deleted file mode 100644 index e94f6102a5..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/mta/alchemy/reset.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/puzzlesolver/arrow.png b/runelite-client/src/main/resources/net/runelite/client/plugins/puzzlesolver/arrow.png deleted file mode 100644 index 904f3c296e..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/puzzlesolver/arrow.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/raids/raids_icon.png b/runelite-client/src/main/resources/net/runelite/client/plugins/raids/raids_icon.png deleted file mode 100644 index 3a239a5f33..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/raids/raids_icon.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/screenmarkers/add_hover_icon.png b/runelite-client/src/main/resources/net/runelite/client/plugins/screenmarkers/add_hover_icon.png deleted file mode 100644 index 9eb7fe3baa..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/screenmarkers/add_hover_icon.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/screenmarkers/cancel_hover_icon.png b/runelite-client/src/main/resources/net/runelite/client/plugins/screenmarkers/cancel_hover_icon.png deleted file mode 100644 index d1ddc4ef67..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/screenmarkers/cancel_hover_icon.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/screenmarkers/confirm_hover_icon.png b/runelite-client/src/main/resources/net/runelite/client/plugins/screenmarkers/confirm_hover_icon.png deleted file mode 100644 index e5b7199658..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/screenmarkers/confirm_hover_icon.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/screenmarkers/confirm_locked_icon.png b/runelite-client/src/main/resources/net/runelite/client/plugins/screenmarkers/confirm_locked_icon.png deleted file mode 100644 index d6300bc3e9..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/screenmarkers/confirm_locked_icon.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/screenshot/report_button.png b/runelite-client/src/main/resources/net/runelite/client/plugins/screenshot/report_button.png deleted file mode 100644 index 34603643c6..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/screenshot/report_button.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/screenshot/screenshot_inverted.png b/runelite-client/src/main/resources/net/runelite/client/plugins/screenshot/screenshot_inverted.png deleted file mode 100644 index 37a546d555..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/screenshot/screenshot_inverted.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/specorb/special_orb_icon.png b/runelite-client/src/main/resources/net/runelite/client/plugins/specorb/special_orb_icon.png deleted file mode 100644 index fbdd8a0546..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/specorb/special_orb_icon.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/xptracker/xp.png b/runelite-client/src/main/resources/net/runelite/client/plugins/xptracker/xp.png deleted file mode 100644 index 90914d8f57..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/xptracker/xp.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/ui/close.png b/runelite-client/src/main/resources/net/runelite/client/ui/close.png deleted file mode 100644 index 4e016c4872..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/ui/close.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/ui/components/search_darker.png b/runelite-client/src/main/resources/net/runelite/client/ui/components/search_darker.png deleted file mode 100644 index 0d5d4608a6..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/ui/components/search_darker.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/ui/overlay/components/minimap_orb_background.png b/runelite-client/src/main/resources/net/runelite/client/ui/overlay/components/minimap_orb_background.png deleted file mode 100644 index efa939b4f0..0000000000 Binary files a/runelite-client/src/main/resources/net/runelite/client/ui/overlay/components/minimap_orb_background.png and /dev/null differ diff --git a/runelite-client/src/main/resources/prayers/protect_from_magic.png b/runelite-client/src/main/resources/prayers/protect_from_magic.png deleted file mode 100644 index b71e1d395f..0000000000 Binary files a/runelite-client/src/main/resources/prayers/protect_from_magic.png and /dev/null differ diff --git a/runelite-client/src/main/resources/prayers/protect_from_missiles.png b/runelite-client/src/main/resources/prayers/protect_from_missiles.png deleted file mode 100644 index 210e0ff6d6..0000000000 Binary files a/runelite-client/src/main/resources/prayers/protect_from_missiles.png and /dev/null differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/bounty hunter - hunter.png b/runelite-client/src/main/resources/skill_icons_small/bounty hunter - hunter.png similarity index 100% rename from runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/bounty hunter - hunter.png rename to runelite-client/src/main/resources/skill_icons_small/bounty hunter - hunter.png diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/bounty hunter - rogue.png b/runelite-client/src/main/resources/skill_icons_small/bounty hunter - rogue.png similarity index 100% rename from runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/bounty hunter - rogue.png rename to runelite-client/src/main/resources/skill_icons_small/bounty hunter - rogue.png diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/clue scrolls (all).png b/runelite-client/src/main/resources/skill_icons_small/clue scrolls (all).png similarity index 100% rename from runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/clue scrolls (all).png rename to runelite-client/src/main/resources/skill_icons_small/clue scrolls (all).png diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/last man standing.png b/runelite-client/src/main/resources/skill_icons_small/last man standing.png similarity index 100% rename from runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/skill_icons_small/last man standing.png rename to runelite-client/src/main/resources/skill_icons_small/last man standing.png diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/info/arrow_right.png b/runelite-client/src/main/resources/util/arrow_right.png similarity index 100% rename from runelite-client/src/main/resources/net/runelite/client/plugins/info/arrow_right.png rename to runelite-client/src/main/resources/util/arrow_right.png diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/cluescrolls/clue_arrow.png b/runelite-client/src/main/resources/util/clue_arrow.png similarity index 100% rename from runelite-client/src/main/resources/net/runelite/client/plugins/cluescrolls/clue_arrow.png rename to runelite-client/src/main/resources/util/clue_arrow.png diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/kourendlibrary/reset.png b/runelite-client/src/main/resources/util/reset.png similarity index 100% rename from runelite-client/src/main/resources/net/runelite/client/plugins/kourendlibrary/reset.png rename to runelite-client/src/main/resources/util/reset.png diff --git a/runelite-client/src/test/java/net/runelite/client/util/ColorUtilTest.java b/runelite-client/src/test/java/net/runelite/client/util/ColorUtilTest.java index d5c7530c51..3697dac28c 100644 --- a/runelite-client/src/test/java/net/runelite/client/util/ColorUtilTest.java +++ b/runelite-client/src/test/java/net/runelite/client/util/ColorUtilTest.java @@ -96,4 +96,26 @@ public class ColorUtilTest assertEquals(hex, ColorUtil.colorToHexCode(color)); }); } + + @Test + public void isFullyTransparent() + { + for (Color color : COLOR_HEXSTRING_MAP.keySet()) + { + assert(!ColorUtil.isFullyTransparent(color)); + } + assert(ColorUtil.isFullyTransparent(new Color(0, 0, 0, 0))); + assert(!ColorUtil.isFullyTransparent(new Color(0, 0, 0, 1))); + } + + @Test + public void isNotFullyTransparent() + { + for (Color color : COLOR_HEXSTRING_MAP.keySet()) + { + assert(ColorUtil.isNotFullyTransparent(color)); + } + assert(!ColorUtil.isNotFullyTransparent(new Color(0, 0, 0, 0))); + assert(ColorUtil.isNotFullyTransparent(new Color(0, 0, 0, 1))); + } } diff --git a/runelite-client/src/test/java/net/runelite/client/util/ImageUtilTest.java b/runelite-client/src/test/java/net/runelite/client/util/ImageUtilTest.java new file mode 100644 index 0000000000..a5d64b6a43 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/util/ImageUtilTest.java @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2018, Jordan Atwood + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.util; + +import java.awt.Color; +import static java.awt.Color.BLACK; +import static java.awt.Color.BLUE; +import static java.awt.Color.GRAY; +import static java.awt.Color.GREEN; +import static java.awt.Color.RED; +import static java.awt.Color.WHITE; +import java.awt.image.BufferedImage; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferInt; +import java.util.Arrays; +import java.util.function.Predicate; +import javax.annotation.Nonnull; +import org.apache.commons.lang3.ArrayUtils; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class ImageUtilTest +{ + private static final Color BLACK_HALF_TRANSPARENT = new Color(0, 0, 0, 128); + private static final Color BLACK_TRANSPARENT = new Color(0, true); + private static final int CORNER_SIZE = 2; + private static final int CENTERED_SIZE = 3; + + private static final BufferedImage BLACK_PIXEL_TOP_LEFT; + private static final BufferedImage BLACK_PIXEL_TOP_RIGHT; + private static final BufferedImage BLACK_PIXEL_BOTTOM_LEFT; + private static final BufferedImage BLACK_PIXEL_BOTTOM_RIGHT; + + static + { + BLACK_PIXEL_TOP_LEFT = new BufferedImage(CORNER_SIZE, CORNER_SIZE, BufferedImage.TYPE_INT_ARGB); + BLACK_PIXEL_TOP_LEFT.setRGB(0, 0, BLACK.getRGB()); + + BLACK_PIXEL_TOP_RIGHT = new BufferedImage(CORNER_SIZE, CORNER_SIZE, BufferedImage.TYPE_INT_ARGB); + BLACK_PIXEL_TOP_RIGHT.setRGB(1, 0, BLACK.getRGB()); + + BLACK_PIXEL_BOTTOM_LEFT = new BufferedImage(CORNER_SIZE, CORNER_SIZE, BufferedImage.TYPE_INT_ARGB); + BLACK_PIXEL_BOTTOM_LEFT.setRGB(0, 1, BLACK.getRGB()); + + BLACK_PIXEL_BOTTOM_RIGHT = new BufferedImage(CORNER_SIZE, CORNER_SIZE, BufferedImage.TYPE_INT_ARGB); + 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))); + assert(bufferedImagesEqual(oneByOne(BLACK), ImageUtil.grayscaleOffset(oneByOne(GRAY), -255))); + 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 + public void resizeImage() + { + // TODO: test image contents after changing size + + final BufferedImage larger = ImageUtil.resizeImage(oneByOne(BLACK), 46, 46); + final BufferedImage smaller = ImageUtil.resizeImage(centeredPixel(WHITE), 1, 1); + final BufferedImage stretched = ImageUtil.resizeImage(solidColor(30, 30, RED), 12, 34); + + assertEquals(46, larger.getWidth()); + assertEquals(46, larger.getHeight()); + assertEquals(1, smaller.getWidth()); + assertEquals(1, smaller.getHeight()); + assertEquals(12, stretched.getWidth()); + assertEquals(34, stretched.getHeight()); + + final BufferedImage[] assertSameAfterResize = new BufferedImage[] { + oneByOne(WHITE), + oneByOne(GRAY), + oneByOne(BLACK), + oneByOne(RED), + oneByOne(GREEN), + oneByOne(BLUE), + oneByOne(BLACK_HALF_TRANSPARENT), + oneByOne(BLACK_TRANSPARENT), + centeredPixel(WHITE), + centeredPixel(GRAY), + centeredPixel(BLACK), + BLACK_PIXEL_TOP_LEFT, + BLACK_PIXEL_TOP_RIGHT, + BLACK_PIXEL_BOTTOM_LEFT, + BLACK_PIXEL_BOTTOM_RIGHT, + }; + for (BufferedImage image : assertSameAfterResize) + { + assert(bufferedImagesEqual(image, ImageUtil.resizeImage(image, image.getWidth(), image.getHeight()))); + } + } + + @Test + public void resizeCanvas() + { + assert(bufferedImagesEqual(centeredPixel(BLACK), ImageUtil.resizeCanvas(oneByOne(BLACK), 3, 3))); + assert(bufferedImagesEqual(oneByOne(BLACK), ImageUtil.resizeCanvas(oneByOne(BLACK), 1, 1))); + assert(bufferedImagesEqual(oneByOne(BLACK), ImageUtil.resizeCanvas(centeredPixel(BLACK), 1, 1))); + + BufferedImage expected = new BufferedImage(2, 1, BufferedImage.TYPE_INT_ARGB); + expected.setRGB(1, 0, BLACK.getRGB()); + assert(bufferedImagesEqual(expected, ImageUtil.resizeCanvas(oneByOne(BLACK), 2, 1))); + + expected = new BufferedImage(1, 2, BufferedImage.TYPE_INT_ARGB); + expected.setRGB(0, 1, BLACK.getRGB()); + assert(bufferedImagesEqual(expected, ImageUtil.resizeCanvas(oneByOne(BLACK), 1, 2))); + } + + @Test + public void rotateImage() + { + // TODO: Test more than 90° rotations + + // Evenly-sized images (2x2) + assert(bufferedImagesEqual(BLACK_PIXEL_TOP_RIGHT, ImageUtil.rotateImage(BLACK_PIXEL_TOP_LEFT, Math.PI / 2))); + assert(bufferedImagesEqual(BLACK_PIXEL_BOTTOM_RIGHT, ImageUtil.rotateImage(BLACK_PIXEL_TOP_LEFT, Math.PI))); + assert(bufferedImagesEqual(BLACK_PIXEL_BOTTOM_LEFT, ImageUtil.rotateImage(BLACK_PIXEL_TOP_LEFT, Math.PI * 3 / 2))); + assert(bufferedImagesEqual(BLACK_PIXEL_TOP_LEFT, ImageUtil.rotateImage(BLACK_PIXEL_TOP_LEFT, Math.PI * 2))); + + // Unevenly-sized images (2x1); when rotated 90° become (2x2) images + final BufferedImage twoByOneLeft = new BufferedImage(2, 1, BufferedImage.TYPE_INT_ARGB); + twoByOneLeft.setRGB(0, 0, BLACK.getRGB()); + final BufferedImage twoByTwoRight = new BufferedImage(2, 1, BufferedImage.TYPE_INT_ARGB); + twoByTwoRight.setRGB(1, 0, BLACK.getRGB()); + final BufferedImage oneByTwoTop = new BufferedImage(2, 2, BufferedImage.TYPE_INT_ARGB); + oneByTwoTop.setRGB(1, 0, new Color(0, 0, 0, 127).getRGB()); + final BufferedImage oneByTwoBottom = new BufferedImage(2, 2, BufferedImage.TYPE_INT_ARGB); + oneByTwoBottom.setRGB(0, 0, new Color(0, 0, 0, 127).getRGB()); + oneByTwoBottom.setRGB(0, 1, BLACK.getRGB()); + + assert(bufferedImagesEqual(oneByTwoTop, ImageUtil.rotateImage(twoByOneLeft, Math.PI / 2))); + assert(bufferedImagesEqual(twoByTwoRight, ImageUtil.rotateImage(twoByOneLeft, Math.PI))); + assert(bufferedImagesEqual(oneByTwoBottom, ImageUtil.rotateImage(twoByOneLeft, Math.PI * 3 / 2))); + 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))); + } + + @Test + public void fillImage() + { + // fillImage(BufferedImage image, Color color) + assert(bufferedImagesEqual(centeredPixel(GRAY), ImageUtil.fillImage(centeredPixel(BLACK), GRAY))); + assert(bufferedImagesEqual(solidColor(3, 3, GREEN), ImageUtil.fillImage(solidColor(3, 3, BLACK), GREEN))); + assert(bufferedImagesEqual(oneByOne(BLACK_TRANSPARENT), ImageUtil.fillImage(oneByOne(BLACK_TRANSPARENT), WHITE))); + + // fillImage(BufferedImage image, Color color, Predicate fillCondition) + BufferedImage expected = solidColor(CORNER_SIZE, CORNER_SIZE, WHITE); + expected.setRGB(0, 0, new Color(0, true).getRGB()); + assert(bufferedImagesEqual(expected, ImageUtil.fillImage(BLACK_PIXEL_TOP_LEFT, WHITE, ColorUtil::isFullyTransparent))); + } + + @Test + public void outlineImage() + { + // outlineImage(BufferedImage image, Color color) + BufferedImage expected = new BufferedImage(CENTERED_SIZE, CENTERED_SIZE, BufferedImage.TYPE_INT_ARGB); + for (int x = 0; x < expected.getWidth(); x++) + { + for (int y = 0; y < expected.getHeight(); y++) + { + if (x != 1 && y != 1) + { + continue; + } + expected.setRGB(x, y, BLACK.getRGB()); + } + } + assert(bufferedImagesEqual(expected, ImageUtil.outlineImage(centeredPixel(BLACK), BLACK))); + expected.setRGB(1, 1, WHITE.getRGB()); + assert(bufferedImagesEqual(expected, ImageUtil.outlineImage(centeredPixel(WHITE), BLACK))); + expected = solidColor(CORNER_SIZE, CORNER_SIZE, WHITE); + expected.setRGB(0, 0, BLACK.getRGB()); + expected.setRGB(1, 1, new Color(0, true).getRGB()); + assert(bufferedImagesEqual(expected, ImageUtil.outlineImage(BLACK_PIXEL_TOP_LEFT, WHITE))); + + // outlineImage(BufferedImage image, Color color, Predicate fillCondition) + BufferedImage test = new BufferedImage(CORNER_SIZE, CORNER_SIZE, BufferedImage.TYPE_INT_ARGB); + test.setRGB(0, 0, BLACK.getRGB()); + test.setRGB(1, 0, GRAY.getRGB()); + expected = test; + expected.setRGB(0, 1, BLUE.getRGB()); + assert(bufferedImagesEqual(expected, ImageUtil.outlineImage(test, BLUE, (color -> color.equals(BLACK))))); + + // outlineImage(BufferedImage image, Color color, Boolean outlineCorners) + expected = solidColor(CORNER_SIZE, CORNER_SIZE, WHITE); + expected.setRGB(0, 0, BLACK.getRGB()); + assert(bufferedImagesEqual(expected, ImageUtil.outlineImage(BLACK_PIXEL_TOP_LEFT, WHITE, true))); + assert(bufferedImagesEqual(solidColor(3, 3, BLACK), ImageUtil.outlineImage(centeredPixel(BLACK), BLACK, true))); + + // outlineImage(BufferedImage image, Color color, Predicate fillCondition, Boolean outlineCorners) + test = new BufferedImage(5, 5, BufferedImage.TYPE_INT_ARGB); + test.setRGB(2, 2, BLACK.getRGB()); + test.setRGB(1,2, new Color(50, 50, 50).getRGB()); + test.setRGB(3, 2, new Color(100, 100, 100).getRGB()); + test.setRGB(2, 3, new Color(150, 150, 150).getRGB()); + expected = test; + expected.setRGB(2, 1, RED.getRGB()); + expected.setRGB(3, 1, RED.getRGB()); + expected.setRGB(4, 1, RED.getRGB()); + expected.setRGB(4, 2, RED.getRGB()); + expected.setRGB(1, 3, RED.getRGB()); + expected.setRGB(3, 3, RED.getRGB()); + expected.setRGB(4, 3, RED.getRGB()); + expected.setRGB(1, 4, RED.getRGB()); + expected.setRGB(2, 4, RED.getRGB()); + expected.setRGB(3, 4, RED.getRGB()); + Predicate testPredicate = (color -> ColorUtil.isNotFullyTransparent(color) && color.getRed() > 75 && color.getGreen() > 75 && color.getBlue() > 75); + assert(bufferedImagesEqual(expected, ImageUtil.outlineImage(test, RED, testPredicate, true))); + } + + /** + * Compares whether two {@link BufferedImage}s are equal in data. + * + * @param expected The first {@link BufferedImage} to be compared. + * @param actual The second {@link BufferedImage} to be compared. + * @return A boolean indicating whether the given {@link BufferedImage}s are of the same image data. + */ + private boolean bufferedImagesEqual(final @Nonnull BufferedImage expected, final @Nonnull BufferedImage actual) + { + if (expected.getWidth() != actual.getWidth()) + { + return false; + } + + if (!expected.getColorModel().equals(actual.getColorModel())) + { + return false; + } + + final DataBuffer aBuffer = expected.getRaster().getDataBuffer(); + final DataBuffer bBuffer = actual.getRaster().getDataBuffer(); + final DataBufferInt aBufferInt = (DataBufferInt) aBuffer; + final DataBufferInt bBufferInt = (DataBufferInt) bBuffer; + + if (aBufferInt.getNumBanks() != bBufferInt.getNumBanks()) + { + return false; + } + + for (int i = 0; i < aBufferInt.getNumBanks(); i++) + { + final int[] aDataBank = aBufferInt.getData(i); + final int[] bDataBank = bBufferInt.getData(i); + if (!Arrays.equals(aDataBank, bDataBank)) + { + return false; + } + } + + 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. + * + * @param color The color to use for the image's single pixel. + * @return A {@link BufferedImage} containing a single pixel of the given color. + */ + private BufferedImage oneByOne(final @Nonnull Color color) + { + return solidColor(1, 1, color); + } + + /** + * Creates a {@link BufferedImage} of a single pixel of the given color centered in a 3-by-3px + * image. + * + * @param color The color to use for the centered pixel. + * @return A {@link BufferedImage} with completely transparent pixels and one pixel of the + * given color in the center. + */ + private BufferedImage centeredPixel(final @Nonnull Color color) + { + final BufferedImage out = new BufferedImage(CENTERED_SIZE, CENTERED_SIZE, BufferedImage.TYPE_INT_ARGB); + out.setRGB(1, 1, color.getRGB()); + return out; + } + + /** + * Creates a {@link BufferedImage} of a solid color of given width and height. + * + * @param width The desired width of the color image. + * @param height The desired height of the color image. + * @param color The desired color of the image. + * @return A {@link BufferedImage} of given dimensions filled with the given color. + */ + private BufferedImage solidColor(final int width, final int height, final @Nonnull Color color) + { + final BufferedImage out = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + for (int x = 0; x < width; x++) + { + for (int y = 0; y < height; y++) + { + out.setRGB(x, y, color.getRGB()); + } + } + return out; + } +}