package net.aufdemrand.denizen.utilities.maps; import net.aufdemrand.denizen.objects.dPlayer; import net.aufdemrand.denizen.utilities.debugging.dB; import org.bukkit.map.MapCanvas; import org.bukkit.map.MapPalette; import org.bukkit.map.MapView; import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; import java.lang.reflect.Field; import java.util.Map; import java.util.UUID; public class MapImage extends MapObject { protected boolean useCache; protected byte[] cachedImage; protected Image image; protected ImageIcon imageIcon; protected int width = 0; protected int height = 0; protected String fileTag; protected String actualFile = null; public MapImage(String xTag, String yTag, String visibilityTag, boolean debug, String fileTag, int width, int height) { this(xTag, yTag, visibilityTag, debug, fileTag, width, height, true); } public MapImage(String xTag, String yTag, String visibilityTag, boolean debug, String fileTag, int width, int height, boolean useCache) { super(xTag, yTag, visibilityTag, debug); this.useCache = useCache; if (useCache) { this.cachedImage = null; } this.fileTag = fileTag; if (width > 0 || height > 0) { this.width = width > 0 ? width : 0; this.height = height > 0 ? height : 0; } } protected void setImage(Image image) { this.image = image; } @Override public Map<String, Object> getSaveData() { Map<String, Object> data = super.getSaveData(); data.put("type", "IMAGE"); data.put("width", width); data.put("height", height); data.put("image", fileTag); return data; } @Override public void render(MapView mapView, MapCanvas mapCanvas, dPlayer player, UUID uuid) { if (actualFile == null) { String file = fileTag; actualFile = DenizenMapManager.getActualFile(file); imageIcon = new ImageIcon(actualFile); image = imageIcon.getImage(); if (width == 0) { width = image.getWidth(null); } if (height == 0) { height = image.getHeight(null); } } // Use custom functions to draw image to allow transparency and reduce lag intensely byte[] bytes; if (!useCache || cachedImage == null) { bytes = imageToBytes(image, width, height); if (useCache) { cachedImage = bytes; } } else { bytes = cachedImage; } int x = getX(player, uuid); int y = getY(player, uuid); for (int x2 = 0; x2 < width; ++x2) { for (int y2 = 0; y2 < height; ++y2) { byte p = bytes[y2 * width + x2]; if (p != MapPalette.TRANSPARENT) { mapCanvas.setPixel(x + x2, y + y2, p); } } } } private static final Color[] bukkitColors; static { Color[] colors = null; try { Field field = MapPalette.class.getDeclaredField("colors"); field.setAccessible(true); colors = (Color[]) field.get(null); } catch (Exception e) { dB.echoError(e); } bukkitColors = colors; } private static byte[] imageToBytes(Image image, int width, int height) { BufferedImage temp = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB); Graphics2D graphics = temp.createGraphics(); graphics.drawImage(image, 0, 0, width, height, null); graphics.dispose(); int[] pixels = new int[width * height]; temp.getRGB(0, 0, width, height, pixels, 0, width); byte[] result = new byte[width * height]; for (int i = 0; i < pixels.length; i++) { result[i] = matchColor(new Color(pixels[i])); } return result; } private static byte matchColor(Color color) { if (color.getAlpha() < 128) { return 0; } int index = 0; double best = -1; for (int i = 4; i < bukkitColors.length; i++) { double distance = getDistance(color, bukkitColors[i]); if (distance < best || best == -1) { best = distance; index = i; } } return (byte) (index < 128 ? index : -129 + (index - 127)); } private static double getDistance(Color c1, Color c2) { double rmean = (c1.getRed() + c2.getRed()) / 2.0; double r = c1.getRed() - c2.getRed(); double g = c1.getGreen() - c2.getGreen(); int b = c1.getBlue() - c2.getBlue(); double weightR = 2 + rmean / 256.0; double weightG = 4.0; double weightB = 2 + (255 - rmean) / 256.0; return weightR * r * r + weightG * g * g + weightB * b * b; } }