/src/mpv5/utils/images/MPIcon.java
Java | 338 lines | 170 code | 33 blank | 135 comment | 23 complexity | 3e4dd2481d382621b04f07a6e98a0227 MD5 | raw file
Possible License(s): LGPL-3.0, Apache-2.0, GPL-3.0, GPL-2.0, AGPL-3.0, JSON, BSD-3-Clause
1/* 2 * This file is part of YaBS. 3 * 4 * YaBS is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * YaBS is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with YaBS. If not, see <http://www.gnu.org/licenses/>. 16 */ 17package mpv5.utils.images; 18 19import java.awt.Component; 20import java.awt.Graphics; 21import java.awt.Graphics2D; 22import java.awt.GraphicsConfiguration; 23import java.awt.GraphicsDevice; 24import java.awt.GraphicsEnvironment; 25import java.awt.HeadlessException; 26import java.awt.Image; 27import java.awt.RenderingHints; 28import java.awt.Transparency; 29import java.awt.image.BufferedImage; 30import java.awt.image.ColorModel; 31import java.awt.image.PixelGrabber; 32import java.net.URL; 33import java.util.HashMap; 34import javax.swing.Icon; 35import javax.swing.ImageIcon; 36import mpv5.logging.Log; 37 38/** 39 * 40 */ 41public class MPIcon extends ImageIcon { 42 43 private static final long serialVersionUID = 1L; 44 public static String DIRECTORY_DEFAULT_ICONS = "/mpv5/resources/images/22/mimetypes/"; 45 public static Icon ICON_ENABLED = new javax.swing.ImageIcon(MPIcon.class.getResource("/mpv5/resources/images/16/yes.png")); 46 47 48 /** 49 * 50 * @param icon 51 */ 52 public MPIcon(Icon icon) { 53 super(iconToImage(icon)); 54 } 55 56 /** 57 * 58 * @param icon 59 */ 60 public MPIcon(ImageIcon icon) { 61 super(icon.getImage()); 62 } 63 64 /** 65 * 66 * @param icon 67 */ 68 public MPIcon(Image icon) { 69 super(icon); 70 } 71 72 /** 73 * Internal resources only! 74 * @param resource 75 */ 76 public MPIcon(String resource) { 77 super(MPIcon.class.getResource(resource)); 78 } 79 80 /** 81 * @param pathToImage 82 */ 83 public MPIcon(URL pathToImage) { 84 super(pathToImage); 85 } 86 87 private MPIcon() { 88 super(); 89 } 90 91 /** 92 * 93 * @param icon 94 * @return 95 */ 96 public static Image iconToImage(Icon icon) { 97 if (icon instanceof ImageIcon) { 98 return ((ImageIcon) icon).getImage(); 99 } else { 100 int w = icon.getIconWidth(); 101 int h = icon.getIconHeight(); 102 GraphicsEnvironment ge = 103 GraphicsEnvironment.getLocalGraphicsEnvironment(); 104 GraphicsDevice gd = ge.getDefaultScreenDevice(); 105 GraphicsConfiguration gc = gd.getDefaultConfiguration(); 106 BufferedImage image = gc.createCompatibleImage(w, h); 107 Graphics2D g = image.createGraphics(); 108 icon.paintIcon(null, g, 0, 0); 109 g.dispose(); 110 return image; 111 } 112 } 113 114// /** 115// * Paints the icon. 116// * The top-left corner of the icon is drawn at 117// * the point (<code>x</code>, <code>y</code>) 118// * in the coordinate space of the graphics context <code>g</code>. 119// * If this icon has no image observer, 120// * this method uses the <code>c</code> component 121// * as the observer. 122// * 123// * @param c the component to be used as the observer 124// * if this icon has no image observer 125// * @param g the graphics context 126// * @param x the X coordinate of the icon's top-left corner 127// * @param y the Y coordinate of the icon's top-left corner 128// */ 129// @Override 130// public synchronized void paintIcon(Component c, Graphics g, int x, int y) { 131// Image image = getImage(); 132// if (super.getImageObserver() == null) { 133// g.drawImage(image, x, y, c); 134// } else { 135// g.drawImage(image, x, y, super.getImageObserver()); 136// } 137// } 138 139 /** 140 * Creates an Icon with the specified size, fast and ugly 141 * @param maxWidthHeigth 142 * @return 143 */ 144 public Icon getIcon(int maxWidthHeigth) { 145 return getIcon(maxWidthHeigth, -1); 146 } 147 148 /** 149 * Creates an Icon with the specified size, nice but slowly 150 * @param maxWidth 151 * @param maxHeight 152 * @return 153 */ 154 public Icon getIcon(int maxWidth, int maxHeight) { 155 if (!cache.containsKey(maxWidth + "@" + maxHeight)) { 156 BufferedImage bi = toBufferedImage(this.getImage()); 157 bi = getScaledInstance(bi, maxWidth, maxHeight, RenderingHints.VALUE_INTERPOLATION_BILINEAR, maxHeight > 0); 158 MPIcon imic = new MPIcon(bi); 159 cache.put(maxWidth + "@" + maxHeight, imic); 160 return imic; 161 } else { 162 return cache.get(maxWidth + "@" + maxHeight); 163 } 164 } 165 private HashMap<String, MPIcon> cache = new HashMap<String, MPIcon>(); 166 167 /** 168 * Convenience method that returns a scaled instance of the 169 * provided {@code BufferedImage}. 170 * 171 * @param img the original image to be scaled 172 * @param targetWidth the desired width of the scaled instance, 173 * in pixels 174 * @param targetHeight the desired height of the scaled instance, 175 * in pixels 176 * @param hint one of the rendering hints that corresponds to 177 * {@code RenderingHints.KEY_INTERPOLATION} (e.g. 178 * {@code RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR}, 179 * {@code RenderingHints.VALUE_INTERPOLATION_BILINEAR}, 180 * {@code RenderingHints.VALUE_INTERPOLATION_BICUBIC}) 181 * @param higherQuality if true, this method will use a multi-step 182 * scaling technique that provides higher quality than the usual 183 * one-step technique (only useful in downscaling cases, where 184 * {@code targetWidth} or {@code targetHeight} is 185 * smaller than the original dimensions, and generally only when 186 * the {@code BILINEAR} hint is specified) 187 * @return a scaled version of the original {@code BufferedImage} 188 */ 189 public static BufferedImage getScaledInstance(BufferedImage img, 190 int targetWidth, 191 int targetHeight, 192 Object hint, 193 boolean higherQuality) { 194 int type = (img.getTransparency() == Transparency.OPAQUE) ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB; 195 BufferedImage ret = img; 196 int w, h; 197 if (higherQuality) { 198 // Use multi-step technique: start with original size, then 199 // scale down in multiple passes with drawImage() 200 // until the target size is reached 201 w = img.getWidth(); 202 h = img.getHeight(); 203 } else { 204 return toBufferedImage(img.getScaledInstance(targetWidth, -1, BufferedImage.SCALE_SMOOTH)); 205 } 206 207 do { 208 if (higherQuality && w > targetWidth) { 209 w /= 2; 210 if (w < targetWidth) { 211 w = targetWidth; 212 } 213 } 214 215 if (higherQuality && h > targetHeight) { 216 h /= 2; 217 if (h < targetHeight) { 218 h = targetHeight; 219 } 220 } 221 222 BufferedImage tmp = new BufferedImage(w, h, type); 223 Graphics2D g2 = tmp.createGraphics(); 224 g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint); 225 g2.drawImage(ret, 0, 0, w, h, null); 226 g2.dispose(); 227 228 ret = tmp; 229 } while (w > targetWidth || h > targetHeight); 230 231 return ret; 232 } 233 234 // 235 /** 236 * This method returns a buffered image with the contents of an image 237 * @param image 238 * @return 239 */ 240 public static BufferedImage toBufferedImage(Image image) { 241 if (image instanceof BufferedImage) { 242 return (BufferedImage) image; 243 } 244 245 // This code ensures that all the pixels in the image are loaded 246 image = new ImageIcon(image).getImage(); 247 248 // Determine if the image has transparent pixels; for this method's 249 // implementation, see e661 Determining If an Image Has Transparent Pixels 250 boolean hasAlpha = false; 251 try { 252 hasAlpha = hasAlpha(image); 253 } catch (Exception e) { 254 Log.Debug(MPIcon.class, "Could not determine alpha of image: " + image); 255 } 256 257 // Create a buffered image with a format that's compatible with the screen 258 BufferedImage bimage = null; 259 GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 260 try { 261 // Determine the type of transparency of the new buffered image 262 int transparency = Transparency.OPAQUE; 263 if (hasAlpha) { 264 transparency = Transparency.BITMASK; 265 } 266 267 // Create the buffered image 268 GraphicsDevice gs = ge.getDefaultScreenDevice(); 269 GraphicsConfiguration gc = gs.getDefaultConfiguration(); 270 bimage = gc.createCompatibleImage( 271 image.getWidth(null), image.getHeight(null), transparency); 272 } catch (HeadlessException e) { 273 // The system does not have a screen 274 } 275 276 if (bimage == null) { 277 // Create a buffered image using the default color model 278 int type = BufferedImage.TYPE_INT_RGB; 279 if (hasAlpha) { 280 type = BufferedImage.TYPE_INT_ARGB; 281 } 282 bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type); 283 } 284 285 // Copy image to buffered image 286 Graphics g = bimage.createGraphics(); 287 288 // Paint the image onto the buffered image 289 g.drawImage(image, 0, 0, null); 290 g.dispose(); 291 292 return bimage; 293 } 294 295 // 296 /** 297 * This method returns true if the specified image has transparent pixels 298 * @param image 299 * @return 300 */ 301 public static boolean hasAlpha(Image image) { 302 // If buffered image, the color model is readily available 303 if (image instanceof BufferedImage) { 304 BufferedImage bimage = (BufferedImage) image; 305 return bimage.getColorModel().hasAlpha(); 306 } 307 308 // Use a pixel grabber to retrieve the image's color model; 309 // grabbing a single pixel is usually sufficient 310 PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false); 311 try { 312 pg.grabPixels(); 313 } catch (InterruptedException e) { 314 } 315 316 // Get the image's color model 317 ColorModel cm = pg.getColorModel(); 318 return cm.hasAlpha(); 319 } 320 321 /** 322 * Scale the image of this icon 323 * @param width 324 * @param height 325 * @return 326 */ 327 public MPIcon getScaledIcon(int maxWidth, int maxHeight) { 328 if (!cache.containsKey(maxWidth + "@" + maxHeight)) { 329 BufferedImage bi = toBufferedImage(this.getImage()); 330 bi = getScaledInstance(bi, maxWidth, maxHeight, RenderingHints.VALUE_INTERPOLATION_BILINEAR, maxHeight > 0); 331 MPIcon imic = new MPIcon(bi); 332 cache.put(maxWidth + "@" + maxHeight, imic); 333 return imic; 334 } else { 335 return cache.get(maxWidth + "@" + maxHeight); 336 } 337 } 338}