MultiResolutionCachedImage.java revision 12677:a4299d47bd00
1/* 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25package sun.awt.image; 26 27import java.awt.Dimension; 28import java.awt.Image; 29import java.awt.geom.Dimension2D; 30import java.awt.image.ImageObserver; 31import java.util.Arrays; 32import java.util.List; 33import java.util.function.Function; 34import java.util.function.BiFunction; 35import java.util.stream.Collectors; 36 37public class MultiResolutionCachedImage extends AbstractMultiResolutionImage { 38 39 private final int baseImageWidth; 40 private final int baseImageHeight; 41 private final Dimension2D[] sizes; 42 private final BiFunction<Integer, Integer, Image> mapper; 43 private int availableInfo; 44 45 public MultiResolutionCachedImage(int baseImageWidth, int baseImageHeight, 46 BiFunction<Integer, Integer, Image> mapper) { 47 this(baseImageWidth, baseImageHeight, new Dimension[]{new Dimension( 48 baseImageWidth, baseImageHeight) 49 }, mapper); 50 } 51 52 public MultiResolutionCachedImage(int baseImageWidth, int baseImageHeight, 53 Dimension2D[] sizes, BiFunction<Integer, Integer, Image> mapper) { 54 this.baseImageWidth = baseImageWidth; 55 this.baseImageHeight = baseImageHeight; 56 this.sizes = (sizes == null) ? null : Arrays.copyOf(sizes, sizes.length); 57 this.mapper = mapper; 58 } 59 60 @Override 61 public Image getResolutionVariant(int width, int height) { 62 ImageCache cache = ImageCache.getInstance(); 63 ImageCacheKey key = new ImageCacheKey(this, width, height); 64 Image resolutionVariant = cache.getImage(key); 65 if (resolutionVariant == null) { 66 resolutionVariant = mapper.apply(width, height); 67 cache.setImage(key, resolutionVariant); 68 } 69 preload(resolutionVariant, availableInfo); 70 return resolutionVariant; 71 } 72 73 @Override 74 public List<Image> getResolutionVariants() { 75 return Arrays.stream(sizes).map((Function<Dimension2D, Image>) size 76 -> getResolutionVariant((int) size.getWidth(), 77 (int) size.getHeight())).collect(Collectors.toList()); 78 } 79 80 public MultiResolutionCachedImage map(Function<Image, Image> mapper) { 81 return new MultiResolutionCachedImage(baseImageWidth, baseImageHeight, 82 sizes, (width, height) -> 83 mapper.apply(getResolutionVariant(width, height))); 84 } 85 86 @Override 87 public int getWidth(ImageObserver observer) { 88 updateInfo(observer, ImageObserver.WIDTH); 89 return baseImageWidth; 90 } 91 92 @Override 93 public int getHeight(ImageObserver observer) { 94 updateInfo(observer, ImageObserver.HEIGHT); 95 return baseImageHeight; 96 } 97 98 @Override 99 public Object getProperty(String name, ImageObserver observer) { 100 updateInfo(observer, ImageObserver.PROPERTIES); 101 return Image.UndefinedProperty; 102 } 103 104 @Override 105 public Image getScaledInstance(int width, int height, int hints) { 106 return getResolutionVariant(width, height); 107 } 108 109 @Override 110 protected Image getBaseImage() { 111 return getResolutionVariant(baseImageWidth, baseImageHeight); 112 } 113 114 private void updateInfo(ImageObserver observer, int info) { 115 availableInfo |= (observer == null) ? ImageObserver.ALLBITS : info; 116 } 117 118 private static int getInfo(Image image) { 119 if (image instanceof ToolkitImage) { 120 return ((ToolkitImage) image).getImageRep().check( 121 (img, infoflags, x, y, w, h) -> false); 122 } 123 return 0; 124 } 125 126 private static void preload(Image image, int availableInfo) { 127 if (availableInfo != 0 && image instanceof ToolkitImage) { 128 ((ToolkitImage) image).preload(new ImageObserver() { 129 int flags = availableInfo; 130 131 @Override 132 public boolean imageUpdate(Image img, int infoflags, 133 int x, int y, int width, int height) { 134 flags &= ~infoflags; 135 return (flags != 0) && ((infoflags 136 & (ImageObserver.ERROR | ImageObserver.ABORT)) == 0); 137 } 138 }); 139 } 140 } 141 142 private static class ImageCacheKey implements ImageCache.PixelsKey { 143 144 private final int pixelCount; 145 private final int hash; 146 147 private final int w; 148 private final int h; 149 private final Image baseImage; 150 151 ImageCacheKey(final Image baseImage, 152 final int w, final int h) { 153 this.baseImage = baseImage; 154 this.w = w; 155 this.h = h; 156 this.pixelCount = w * h; 157 hash = hash(); 158 } 159 160 @Override 161 public int getPixelCount() { 162 return pixelCount; 163 } 164 165 private int hash() { 166 int hash = baseImage.hashCode(); 167 hash = 31 * hash + w; 168 hash = 31 * hash + h; 169 return hash; 170 } 171 172 @Override 173 public int hashCode() { 174 return hash; 175 } 176 177 @Override 178 public boolean equals(Object obj) { 179 if (obj instanceof ImageCacheKey) { 180 ImageCacheKey key = (ImageCacheKey) obj; 181 return baseImage == key.baseImage && w == key.w && h == key.h; 182 } 183 return false; 184 } 185 } 186} 187