001 package org.bukkit.map;
002
003 import java.awt.Color;
004 import java.awt.Graphics2D;
005 import java.awt.Image;
006 import java.awt.image.BufferedImage;
007
008 /**
009 * Represents the palette that map items use.
010 * <p>
011 * These fields are hee base color ranges. Each entry corresponds to four
012 * colors of varying shades with values entry to entry + 3.
013 */
014 public final class MapPalette {
015 // Internal mechanisms
016 private MapPalette() {}
017
018 private static Color c(int r, int g, int b) {
019 return new Color(r, g, b);
020 }
021
022 private static double getDistance(Color c1, Color c2) {
023 double rmean = (c1.getRed() + c2.getRed()) / 2.0;
024 double r = c1.getRed() - c2.getRed();
025 double g = c1.getGreen() - c2.getGreen();
026 int b = c1.getBlue() - c2.getBlue();
027 double weightR = 2 + rmean / 256.0;
028 double weightG = 4.0;
029 double weightB = 2 + (255 - rmean) / 256.0;
030 return weightR * r * r + weightG * g * g + weightB * b * b;
031 }
032
033 private static final Color[] colors = {
034 new Color(0, 0, 0, 0), new Color(0, 0, 0, 0),
035 new Color(0, 0, 0, 0), new Color(0, 0, 0, 0),
036 c(89, 125, 39), c(109, 153, 48), c(127, 178, 56), c(67, 94, 29),
037 c(174, 164, 115), c(213, 201, 140), c(247, 233, 163), c(130, 123, 86),
038 c(117, 117, 117), c(144, 144, 144), c(167, 167, 167), c(88, 88, 88),
039 c(180, 0, 0), c(220, 0, 0), c(255, 0, 0), c(135, 0, 0),
040 c(112, 112, 180), c(138, 138, 220), c(160, 160, 255), c(84, 84, 135),
041 c(117, 117, 117), c(144, 144, 144), c(167, 167, 167), c(88, 88, 88),
042 c(0, 87, 0), c(0, 106, 0), c(0, 124, 0), c(0, 65, 0),
043 c(180, 180, 180), c(220, 220, 220), c(255, 255, 255), c(135, 135, 135),
044 c(115, 118, 129), c(141, 144, 158), c(164, 168, 184), c(86, 88, 97),
045 c(129, 74, 33), c(157, 91, 40), c(183, 106, 47), c(96, 56, 24),
046 c(79, 79, 79), c(96, 96, 96), c(112, 112, 112), c(59, 59, 59),
047 c(45, 45, 180), c(55, 55, 220), c(64, 64, 255), c(33, 33, 135),
048 c(73, 58, 35), c(89, 71, 43), c(104, 83, 50), c(55, 43, 26),
049 c(180, 177, 172), c(220, 217, 211), c(255, 252, 245), c(135, 133, 129),
050 c(152, 89, 36), c(186, 109, 44), c(216, 127, 51), c(114, 67, 27),
051 c(125, 53, 152), c(153, 65, 186), c(178, 76, 216), c(94, 40, 114),
052 c(72, 108, 152), c(88, 132, 186), c(102, 153, 216), c(54, 81, 114),
053 c(161, 161, 36), c(197, 197, 44), c(229, 229, 51), c(121, 121, 27),
054 c(89, 144, 17), c(109, 176, 21), c(127, 204, 25), c(67, 108, 13),
055 c(170, 89, 116), c(208, 109, 142), c(242, 127, 165), c(128, 67, 87),
056 c(53, 53, 53), c(65, 65, 65), c(76, 76, 76), c(40, 40, 40),
057 c(108, 108, 108), c(132, 132, 132), c(153, 153, 153), c(81, 81, 81),
058 c(53, 89, 108), c(65, 109, 132), c(76, 127, 153), c(40, 67, 81),
059 c(89, 44, 125), c(109, 54, 153), c(127, 63, 178), c(67, 33, 94),
060 c(36, 53, 125), c(44, 65, 153), c(51, 76, 178), c(27, 40, 94),
061 c(72, 53, 36), c(88, 65, 44), c(102, 76, 51), c(54, 40, 27),
062 c(72, 89, 36), c(88, 109, 44), c(102, 127, 51), c(54, 67, 27),
063 c(108, 36, 36), c(132, 44, 44), c(153, 51, 51), c(81, 27, 27),
064 c(17, 17, 17), c(21, 21, 21), c(25, 25, 25), c(13, 13, 13),
065 c(176, 168, 54), c(215, 205, 66), c(250, 238, 77), c(132, 126, 40),
066 c(64, 154, 150), c(79, 188, 183), c(92, 219, 213), c(48, 115, 112),
067 c(52, 90, 180), c(63, 110, 220), c(74, 128, 255), c(39, 67, 135),
068 c(0, 153, 40), c(0, 187, 50), c(0, 217, 58), c(0, 114, 30),
069 c(14, 14, 21), c(18, 17, 26), c(21, 20, 31), c(11, 10, 16),
070 c(79, 1, 0), c(96, 1, 0), c(112, 2, 0), c(59, 1, 0)
071 };
072
073 // Interface
074 /**
075 * @deprecated Magic value
076 */
077 @Deprecated
078 public static final byte TRANSPARENT = 0;
079 /**
080 * @deprecated Magic value
081 */
082 @Deprecated
083 public static final byte LIGHT_GREEN = 4;
084 /**
085 * @deprecated Magic value
086 */
087 @Deprecated
088 public static final byte LIGHT_BROWN = 8;
089 /**
090 * @deprecated Magic value
091 */
092 @Deprecated
093 public static final byte GRAY_1 = 12;
094 /**
095 * @deprecated Magic value
096 */
097 @Deprecated
098 public static final byte RED = 16;
099 /**
100 * @deprecated Magic value
101 */
102 @Deprecated
103 public static final byte PALE_BLUE = 20;
104 /**
105 * @deprecated Magic value
106 */
107 @Deprecated
108 public static final byte GRAY_2 = 24;
109 /**
110 * @deprecated Magic value
111 */
112 @Deprecated
113 public static final byte DARK_GREEN = 28;
114 /**
115 * @deprecated Magic value
116 */
117 @Deprecated
118 public static final byte WHITE = 32;
119 /**
120 * @deprecated Magic value
121 */
122 @Deprecated
123 public static final byte LIGHT_GRAY = 36;
124 /**
125 * @deprecated Magic value
126 */
127 @Deprecated
128 public static final byte BROWN = 40;
129 /**
130 * @deprecated Magic value
131 */
132 @Deprecated
133 public static final byte DARK_GRAY = 44;
134 /**
135 * @deprecated Magic value
136 */
137 @Deprecated
138 public static final byte BLUE = 48;
139 /**
140 * @deprecated Magic value
141 */
142 @Deprecated
143 public static final byte DARK_BROWN = 52;
144
145 /**
146 * Resize an image to 128x128.
147 *
148 * @param image The image to resize.
149 * @return The resized image.
150 */
151 public static BufferedImage resizeImage(Image image) {
152 BufferedImage result = new BufferedImage(128, 128, BufferedImage.TYPE_INT_ARGB);
153 Graphics2D graphics = result.createGraphics();
154 graphics.drawImage(image, 0, 0, 128, 128, null);
155 graphics.dispose();
156 return result;
157 }
158
159 /**
160 * Convert an Image to a byte[] using the palette.
161 *
162 * @param image The image to convert.
163 * @return A byte[] containing the pixels of the image.
164 * @deprecated Magic value
165 */
166 @Deprecated
167 public static byte[] imageToBytes(Image image) {
168 BufferedImage temp = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
169 Graphics2D graphics = temp.createGraphics();
170 graphics.drawImage(image, 0, 0, null);
171 graphics.dispose();
172
173 int[] pixels = new int[temp.getWidth() * temp.getHeight()];
174 temp.getRGB(0, 0, temp.getWidth(), temp.getHeight(), pixels, 0, temp.getWidth());
175
176 byte[] result = new byte[temp.getWidth() * temp.getHeight()];
177 for (int i = 0; i < pixels.length; i++) {
178 result[i] = matchColor(new Color(pixels[i], true));
179 }
180 return result;
181 }
182
183 /**
184 * Get the index of the closest matching color in the palette to the given
185 * color.
186 *
187 * @param r The red component of the color.
188 * @param b The blue component of the color.
189 * @param g The green component of the color.
190 * @return The index in the palette.
191 * @deprecated Magic value
192 */
193 @Deprecated
194 public static byte matchColor(int r, int g, int b) {
195 return matchColor(new Color(r, g, b));
196 }
197
198 /**
199 * Get the index of the closest matching color in the palette to the given
200 * color.
201 *
202 * @param color The Color to match.
203 * @return The index in the palette.
204 * @deprecated Magic value
205 */
206 @Deprecated
207 public static byte matchColor(Color color) {
208 if (color.getAlpha() < 128) return 0;
209
210 int index = 0;
211 double best = -1;
212
213 for (int i = 4; i < colors.length; i++) {
214 double distance = getDistance(color, colors[i]);
215 if (distance < best || best == -1) {
216 best = distance;
217 index = i;
218 }
219 }
220
221 // Minecraft has 143 colors, some of which have negative byte representations
222 return (byte) (index < 128 ? index : -129 + (index - 127));
223 }
224
225 /**
226 * Get the value of the given color in the palette.
227 *
228 * @param index The index in the palette.
229 * @return The Color of the palette entry.
230 * @deprecated Magic value
231 */
232 @Deprecated
233 public static Color getColor(byte index) {
234 if ((index > -113 && index < 0) || index > 127) {
235 throw new IndexOutOfBoundsException();
236 } else {
237 // Minecraft has 143 colors, some of which have negative byte representations
238 return colors[index >= 0 ? index : index + 256];
239 }
240 }
241 }