Changeset 7132 in josm
- Timestamp:
- 2014-05-15T03:15:28+02:00 (10 years ago)
- Location:
- trunk
- Files:
-
- 3 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/imagery/GeorefImage.java
r7025 r7132 22 22 import org.openstreetmap.josm.gui.layer.ImageryLayer; 23 23 import org.openstreetmap.josm.gui.layer.WMSLayer; 24 import org.openstreetmap.josm.tools.ImageProvider; 24 25 25 26 public class GeorefImage implements Serializable { … … 46 47 return layer.getEastNorth(xIndex+1, yIndex+1); 47 48 } 48 49 49 50 50 public GeorefImage(WMSLayer layer) { … … 57 57 this.yIndex = yIndex; 58 58 this.image = null; 59 flush edResizedCachedInstance();59 flushResizedCachedInstance(); 60 60 } 61 61 } … … 65 65 } 66 66 67 /** 68 * Resets this image to initial state and release all resources being used. 69 * @since 7132 70 */ 71 public void resetImage() { 72 if (image != null) { 73 image.flush(); 74 } 75 changeImage(null, null); 76 } 77 67 78 public void changeImage(State state, BufferedImage image) { 68 flush edResizedCachedInstance();79 flushResizedCachedInstance(); 69 80 this.image = image; 70 81 this.state = state; 71 82 if (state == null) 83 return; 72 84 switch (state) { 73 85 case FAILED: … … 103 115 104 116 public boolean paint(Graphics g, NavigatableComponent nc, int xIndex, int yIndex, int leftEdge, int bottomEdge) { 105 if ( image== null)117 if (getImage() == null) 106 118 return false; 107 119 … … 174 186 175 187 private void fallbackDraw(Graphics g, Image img, int x, int y, int width, int height, boolean alphaChannel) { 176 flush edResizedCachedInstance();188 flushResizedCachedInstance(); 177 189 g.drawImage( 178 190 img, x, y, x + width, y + height, … … 195 207 boolean hasImage = in.readBoolean(); 196 208 if (hasImage) { 197 image = (ImageIO.read(ImageIO.createImageInputStream(in)));209 image = ImageProvider.read(ImageIO.createImageInputStream(in), true, WMSLayer.PROP_ALPHA_CHANNEL.get()); 198 210 } else { 199 211 in.readObject(); // read null from input stream … … 213 225 } 214 226 215 public void flush edResizedCachedInstance() {227 public void flushResizedCachedInstance() { 216 228 if (reImg != null) { 217 229 BufferedImage img = reImg.get(); … … 223 235 } 224 236 225 226 237 public BufferedImage getImage() { 227 238 return image; -
trunk/src/org/openstreetmap/josm/data/imagery/WmsCache.java
r7033 r7132 42 42 import org.openstreetmap.josm.data.preferences.StringProperty; 43 43 import org.openstreetmap.josm.data.projection.Projection; 44 import org.openstreetmap.josm.gui.layer.WMSLayer; 45 import org.openstreetmap.josm.tools.ImageProvider; 44 46 import org.openstreetmap.josm.tools.Utils; 45 47 … … 48 50 //TODO Property for maximum age of tile, automatically remove old tiles 49 51 //TODO Measure time for partially loading from cache, compare with time to download tile. If slower, disable partial cache 50 //TODO Do loading from partial cache and downloading at the same time, don't wait for parti cal cache to load52 //TODO Do loading from partial cache and downloading at the same time, don't wait for partial cache to load 51 53 52 54 private static final StringProperty PROP_CACHE_PATH = new StringProperty("imagery.wms-cache.path", "wms"); … … 70 72 this.bounds = new ProjectionBounds(east, north, east + tileSize / pixelPerDegree, north + tileSize / pixelPerDegree); 71 73 this.filename = filename; 74 } 75 76 @Override 77 public String toString() { 78 return "CacheEntry [pixelPerDegree=" + pixelPerDegree + ", east=" + east + ", north=" + north + ", bounds=" 79 + bounds + ", filename=" + filename + ", lastUsed=" + lastUsed + ", lastModified=" + lastModified 80 + "]"; 72 81 } 73 82 } … … 299 308 } 300 309 301 private BufferedImage loadImage(ProjectionEntries projectionEntries, CacheEntry entry) throws IOException { 302 310 private BufferedImage loadImage(ProjectionEntries projectionEntries, CacheEntry entry, boolean enforceTransparency) throws IOException { 303 311 synchronized (this) { 304 312 entry.lastUsed = System.currentTimeMillis(); … … 307 315 if (memCache != null) { 308 316 BufferedImage result = memCache.get(); 309 if (result != null) 310 return result; 317 if (result != null) { 318 if (enforceTransparency == ImageProvider.isTransparencyForced(result)) { 319 return result; 320 } else if (Main.isDebugEnabled()) { 321 Main.debug("Skipping "+entry+" from memory cache (transparency enforcement)"); 322 } 323 } 311 324 } 312 325 } … … 314 327 try { 315 328 // Reading can't be in synchronized section, it's too slow 316 BufferedImage result = Image IO.read(getImageFile(projectionEntries, entry));329 BufferedImage result = ImageProvider.read(getImageFile(projectionEntries, entry), true, enforceTransparency); 317 330 synchronized (this) { 318 331 if (result == null) { … … 354 367 if (entry != null) { 355 368 try { 356 return loadImage(projectionEntries, entry );369 return loadImage(projectionEntries, entry, WMSLayer.PROP_ALPHA_CHANNEL.get()); 357 370 } catch (IOException e) { 358 371 Main.error("Unable to load file from wms cache"); … … 364 377 } 365 378 366 public 379 public BufferedImage getPartialMatch(Projection projection, double pixelPerDegree, double east, double north) { 367 380 ProjectionEntries projectionEntries; 368 381 List<CacheEntry> matches; … … 390 403 return null; 391 404 392 393 405 Collections.sort(matches, new Comparator<CacheEntry>() { 394 406 @Override … … 399 411 } 400 412 401 //TODO Use alpha layer only when enabled on wms layer 402 BufferedImage result = new BufferedImage(tileSize, tileSize, BufferedImage.TYPE_4BYTE_ABGR); 413 // Use alpha layer only when enabled on wms layer 414 boolean alpha = WMSLayer.PROP_ALPHA_CHANNEL.get(); 415 BufferedImage result = new BufferedImage(tileSize, tileSize, 416 alpha ? BufferedImage.TYPE_4BYTE_ABGR : BufferedImage.TYPE_3BYTE_BGR); 403 417 Graphics2D g = result.createGraphics(); 404 405 418 406 419 boolean drawAtLeastOnce = false; … … 409 422 BufferedImage img; 410 423 try { 411 img = loadImage(projectionEntries, ce); 424 // Enforce transparency only when alpha enabled on wms layer too 425 img = loadImage(projectionEntries, ce, alpha); 412 426 localCache.put(ce, new SoftReference<>(img)); 413 427 } catch (IOException e) { -
trunk/src/org/openstreetmap/josm/gui/layer/WMSLayer.java
r7119 r7132 66 66 import org.openstreetmap.josm.io.imagery.WMSGrabber; 67 67 import org.openstreetmap.josm.io.imagery.WMSRequest; 68 import org.openstreetmap.josm.tools.ImageProvider; 68 69 69 70 /** … … 813 814 boolean alphaChannel = checkbox.isSelected(); 814 815 PROP_ALPHA_CHANNEL.put(alphaChannel); 816 Main.info("WMS Alpha channel changed to "+alphaChannel); 815 817 816 818 // clear all resized cached instances and repaint the layer … … 818 820 for (int y = 0; y < day; ++y) { 819 821 GeorefImage img = images[modulo(x, dax)][modulo(y, day)]; 820 img.flushedResizedCachedInstance(); 822 img.flushResizedCachedInstance(); 823 BufferedImage bi = img.getImage(); 824 // Completely erases images for which transparency has been forced, 825 // or images that should be forced now, as they need to be recreated 826 if (ImageProvider.isTransparencyForced(bi) || ImageProvider.hasTransparentColor(bi)) { 827 img.resetImage(); 828 } 821 829 } 822 830 } -
trunk/src/org/openstreetmap/josm/io/CacheFiles.java
r7082 r7132 15 15 16 16 import org.openstreetmap.josm.Main; 17 import org.openstreetmap.josm.tools.ImageProvider; 17 18 18 19 /** … … 168 169 img.setLastModified(System.currentTimeMillis()); 169 170 } 170 return Image IO.read(img);171 return ImageProvider.read(img, false, false); 171 172 } catch (Exception e) { 172 173 Main.warn(e); -
trunk/src/org/openstreetmap/josm/io/imagery/Grabber.java
r6883 r7132 44 44 if (!layer.cache.hasExactMatch(Main.getProjection(), request.getPixelPerDegree(), b.minEast, b.minNorth)) { 45 45 attempt(request); 46 } else if (Main.isDebugEnabled()) { 47 Main.debug("Ignoring "+request+" (precache only + exact match)"); 46 48 } 47 } else {48 if(!loadFromCache(request)){49 attempt(request);50 }49 } else if (!loadFromCache(request)){ 50 attempt(request); 51 } else if (Main.isDebugEnabled()) { 52 Main.debug("Ignoring "+request+" (loaded from cache)"); 51 53 } 52 54 layer.finishRequest(request); … … 70 72 Main.debug("InterruptedException in "+getClass().getSimpleName()+" during WMS request"); 71 73 } 72 if (i == maxTries) {74 if (i == maxTries) { 73 75 Main.error(e); 74 76 request.finish(State.FAILED, null); -
trunk/src/org/openstreetmap/josm/io/imagery/HTMLGrabber.java
r7005 r7132 12 12 import java.util.StringTokenizer; 13 13 14 import javax.imageio.ImageIO;15 16 14 import org.openstreetmap.josm.Main; 17 15 import org.openstreetmap.josm.data.preferences.StringProperty; 18 16 import org.openstreetmap.josm.gui.MapView; 19 17 import org.openstreetmap.josm.gui.layer.WMSLayer; 18 import org.openstreetmap.josm.tools.ImageProvider; 20 19 import org.openstreetmap.josm.tools.Utils; 21 20 … … 51 50 Utils.copyStream(browser.getInputStream(), baos); 52 51 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 53 BufferedImage img = layer.normalizeImage(Image IO.read(bais));52 BufferedImage img = layer.normalizeImage(ImageProvider.read(bais, true, WMSLayer.PROP_ALPHA_CHANNEL.get())); 54 53 bais.reset(); 55 54 layer.cache.saveToCache(layer.isOverlapEnabled()?img:null, bais, Main.getProjection(), request.getPixelPerDegree(), b.minEast, b.minNorth); -
trunk/src/org/openstreetmap/josm/io/imagery/WMSGrabber.java
r7082 r7132 24 24 import java.util.regex.Pattern; 25 25 26 import javax.imageio.ImageIO;27 28 26 import org.openstreetmap.josm.Main; 29 27 import org.openstreetmap.josm.data.coor.EastNorth; … … 35 33 import org.openstreetmap.josm.io.OsmTransferException; 36 34 import org.openstreetmap.josm.io.ProgressInputStream; 35 import org.openstreetmap.josm.tools.ImageProvider; 37 36 import org.openstreetmap.josm.tools.Utils; 38 39 37 40 38 public class WMSGrabber extends Grabber { … … 137 135 @Override 138 136 public boolean loadFromCache(WMSRequest request) { 139 BufferedImage cached = layer.cache.getExactMatch(Main.getProjection(), request.getPixelPerDegree(), b.minEast, b.minNorth); 137 BufferedImage cached = layer.cache.getExactMatch( 138 Main.getProjection(), request.getPixelPerDegree(), b.minEast, b.minNorth); 140 139 141 140 if (cached != null) { … … 143 142 return true; 144 143 } else if (request.isAllowPartialCacheMatch()) { 145 BufferedImage partialMatch = layer.cache.getPartialMatch(Main.getProjection(), request.getPixelPerDegree(), b.minEast, b.minNorth); 144 BufferedImage partialMatch = layer.cache.getPartialMatch( 145 Main.getProjection(), request.getPixelPerDegree(), b.minEast, b.minNorth); 146 146 if (partialMatch != null) { 147 147 request.finish(State.PARTLY_IN_CACHE, partialMatch); … … 179 179 180 180 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 181 BufferedImage img = layer.normalizeImage(Image IO.read(bais));181 BufferedImage img = layer.normalizeImage(ImageProvider.read(bais, true, WMSLayer.PROP_ALPHA_CHANNEL.get())); 182 182 bais.reset(); 183 183 layer.cache.saveToCache(layer.isOverlapEnabled()?img:null, bais, Main.getProjection(), request.getPixelPerDegree(), b.minEast, b.minNorth); -
trunk/src/org/openstreetmap/josm/tools/ImageProvider.java
r7090 r7132 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.awt.Color; 6 7 import java.awt.Cursor; 7 8 import java.awt.Dimension; … … 13 14 import java.awt.RenderingHints; 14 15 import java.awt.Toolkit; 16 import java.awt.Transparency; 15 17 import java.awt.image.BufferedImage; 18 import java.awt.image.ColorModel; 19 import java.awt.image.FilteredImageSource; 20 import java.awt.image.ImageFilter; 21 import java.awt.image.ImageProducer; 22 import java.awt.image.RGBImageFilter; 23 import java.awt.image.WritableRaster; 16 24 import java.io.ByteArrayInputStream; 17 25 import java.io.File; … … 29 37 import java.util.Collection; 30 38 import java.util.HashMap; 39 import java.util.Hashtable; 40 import java.util.Iterator; 31 41 import java.util.Map; 32 42 import java.util.concurrent.ExecutorService; … … 37 47 import java.util.zip.ZipFile; 38 48 49 import javax.imageio.IIOException; 39 50 import javax.imageio.ImageIO; 51 import javax.imageio.ImageReadParam; 52 import javax.imageio.ImageReader; 53 import javax.imageio.metadata.IIOMetadata; 54 import javax.imageio.stream.ImageInputStream; 40 55 import javax.swing.Icon; 41 56 import javax.swing.ImageIcon; … … 46 61 import org.openstreetmap.josm.io.MirroredInputStream; 47 62 import org.openstreetmap.josm.plugins.PluginHandler; 63 import org.w3c.dom.Element; 64 import org.w3c.dom.Node; 48 65 import org.xml.sax.Attributes; 49 66 import org.xml.sax.EntityResolver; … … 90 107 OTHER 91 108 } 109 110 /** 111 * Property set on {@code BufferedImage} returned by {@link #makeImageTransparent}. 112 * @since 7132 113 */ 114 public static String PROP_TRANSPARENCY_FORCED = "josm.transparency.forced"; 115 116 /** 117 * Property set on {@code BufferedImage} returned by {@link #read} if metadata is required. 118 * @since 7132 119 */ 120 public static String PROP_TRANSPARENCY_COLOR = "josm.transparency.color"; 92 121 93 122 protected Collection<String> dirs; … … 513 542 BufferedImage img = null; 514 543 try { 515 img = ImageIO.read(Utils.fileToURL(is.getFile()));544 img = read(Utils.fileToURL(is.getFile()), false, false); 516 545 } catch (IOException e) { 517 546 Main.warn("IOException while reading HTTP image: "+e.getMessage()); … … 555 584 } else { 556 585 try { 557 return new ImageResource( ImageIO.read(new ByteArrayInputStream(bytes)));586 return new ImageResource(read(new ByteArrayInputStream(bytes), false, false)); 558 587 } catch (IOException e) { 559 588 Main.warn("IOException while reading image: "+e.getMessage()); … … 625 654 BufferedImage img = null; 626 655 try { 627 img = ImageIO.read(new ByteArrayInputStream(buf));656 img = read(new ByteArrayInputStream(buf), false, false); 628 657 } catch (IOException e) { 629 658 Main.warn(e); … … 650 679 BufferedImage img = null; 651 680 try { 652 img = ImageIO.read(path);681 img = read(path, false, false); 653 682 } catch (IOException e) { 654 683 Main.warn(e); … … 1004 1033 return svgUniverse; 1005 1034 } 1035 1036 /** 1037 * Returns a <code>BufferedImage</code> as the result of decoding 1038 * a supplied <code>File</code> with an <code>ImageReader</code> 1039 * chosen automatically from among those currently registered. 1040 * The <code>File</code> is wrapped in an 1041 * <code>ImageInputStream</code>. If no registered 1042 * <code>ImageReader</code> claims to be able to read the 1043 * resulting stream, <code>null</code> is returned. 1044 * 1045 * <p> The current cache settings from <code>getUseCache</code>and 1046 * <code>getCacheDirectory</code> will be used to control caching in the 1047 * <code>ImageInputStream</code> that is created. 1048 * 1049 * <p> Note that there is no <code>read</code> method that takes a 1050 * filename as a <code>String</code>; use this method instead after 1051 * creating a <code>File</code> from the filename. 1052 * 1053 * <p> This method does not attempt to locate 1054 * <code>ImageReader</code>s that can read directly from a 1055 * <code>File</code>; that may be accomplished using 1056 * <code>IIORegistry</code> and <code>ImageReaderSpi</code>. 1057 * 1058 * @param input a <code>File</code> to read from. 1059 * @param readMetadata if {@code true}, makes sure to read image metadata to detect transparency color, if any. 1060 * In that case the color can be retrieved later through {@link #PROP_TRANSPARENCY_COLOR}. 1061 * Always considered {@code true} if {@code enforceTransparency} is also {@code true} 1062 * @param enforceTransparency if {@code true}, makes sure to read image metadata and, if the image does not 1063 * provide an alpha channel but defines a {@code TransparentColor} metadata node, that the resulting image 1064 * has a transparency set to {@code TRANSLUCENT} and uses the correct transparent color. 1065 * 1066 * @return a <code>BufferedImage</code> containing the decoded 1067 * contents of the input, or <code>null</code>. 1068 * 1069 * @throws IllegalArgumentException if <code>input</code> is <code>null</code>. 1070 * @throws IOException if an error occurs during reading. 1071 * @since 7132 1072 * @see BufferedImage#getProperty 1073 */ 1074 public static BufferedImage read(File input, boolean readMetadata, boolean enforceTransparency) throws IOException { 1075 CheckParameterUtil.ensureParameterNotNull(input, "input"); 1076 if (!input.canRead()) { 1077 throw new IIOException("Can't read input file!"); 1078 } 1079 1080 ImageInputStream stream = ImageIO.createImageInputStream(input); 1081 if (stream == null) { 1082 throw new IIOException("Can't create an ImageInputStream!"); 1083 } 1084 BufferedImage bi = read(stream, readMetadata, enforceTransparency); 1085 if (bi == null) { 1086 stream.close(); 1087 } 1088 return bi; 1089 } 1090 1091 /** 1092 * Returns a <code>BufferedImage</code> as the result of decoding 1093 * a supplied <code>InputStream</code> with an <code>ImageReader</code> 1094 * chosen automatically from among those currently registered. 1095 * The <code>InputStream</code> is wrapped in an 1096 * <code>ImageInputStream</code>. If no registered 1097 * <code>ImageReader</code> claims to be able to read the 1098 * resulting stream, <code>null</code> is returned. 1099 * 1100 * <p> The current cache settings from <code>getUseCache</code>and 1101 * <code>getCacheDirectory</code> will be used to control caching in the 1102 * <code>ImageInputStream</code> that is created. 1103 * 1104 * <p> This method does not attempt to locate 1105 * <code>ImageReader</code>s that can read directly from an 1106 * <code>InputStream</code>; that may be accomplished using 1107 * <code>IIORegistry</code> and <code>ImageReaderSpi</code>. 1108 * 1109 * <p> This method <em>does not</em> close the provided 1110 * <code>InputStream</code> after the read operation has completed; 1111 * it is the responsibility of the caller to close the stream, if desired. 1112 * 1113 * @param input an <code>InputStream</code> to read from. 1114 * @param readMetadata if {@code true}, makes sure to read image metadata to detect transparency color for non translucent images, if any. 1115 * In that case the color can be retrieved later through {@link #PROP_TRANSPARENCY_COLOR}. 1116 * Always considered {@code true} if {@code enforceTransparency} is also {@code true} 1117 * @param enforceTransparency if {@code true}, makes sure to read image metadata and, if the image does not 1118 * provide an alpha channel but defines a {@code TransparentColor} metadata node, that the resulting image 1119 * has a transparency set to {@code TRANSLUCENT} and uses the correct transparent color. 1120 * 1121 * @return a <code>BufferedImage</code> containing the decoded 1122 * contents of the input, or <code>null</code>. 1123 * 1124 * @throws IllegalArgumentException if <code>input</code> is <code>null</code>. 1125 * @throws IOException if an error occurs during reading. 1126 * @since 7132 1127 */ 1128 public static BufferedImage read(InputStream input, boolean readMetadata, boolean enforceTransparency) throws IOException { 1129 CheckParameterUtil.ensureParameterNotNull(input, "input"); 1130 1131 ImageInputStream stream = ImageIO.createImageInputStream(input); 1132 BufferedImage bi = read(stream, readMetadata, enforceTransparency); 1133 if (bi == null) { 1134 stream.close(); 1135 } 1136 return bi; 1137 } 1138 1139 /** 1140 * Returns a <code>BufferedImage</code> as the result of decoding 1141 * a supplied <code>URL</code> with an <code>ImageReader</code> 1142 * chosen automatically from among those currently registered. An 1143 * <code>InputStream</code> is obtained from the <code>URL</code>, 1144 * which is wrapped in an <code>ImageInputStream</code>. If no 1145 * registered <code>ImageReader</code> claims to be able to read 1146 * the resulting stream, <code>null</code> is returned. 1147 * 1148 * <p> The current cache settings from <code>getUseCache</code>and 1149 * <code>getCacheDirectory</code> will be used to control caching in the 1150 * <code>ImageInputStream</code> that is created. 1151 * 1152 * <p> This method does not attempt to locate 1153 * <code>ImageReader</code>s that can read directly from a 1154 * <code>URL</code>; that may be accomplished using 1155 * <code>IIORegistry</code> and <code>ImageReaderSpi</code>. 1156 * 1157 * @param input a <code>URL</code> to read from. 1158 * @param readMetadata if {@code true}, makes sure to read image metadata to detect transparency color for non translucent images, if any. 1159 * In that case the color can be retrieved later through {@link #PROP_TRANSPARENCY_COLOR}. 1160 * Always considered {@code true} if {@code enforceTransparency} is also {@code true} 1161 * @param enforceTransparency if {@code true}, makes sure to read image metadata and, if the image does not 1162 * provide an alpha channel but defines a {@code TransparentColor} metadata node, that the resulting image 1163 * has a transparency set to {@code TRANSLUCENT} and uses the correct transparent color. 1164 * 1165 * @return a <code>BufferedImage</code> containing the decoded 1166 * contents of the input, or <code>null</code>. 1167 * 1168 * @throws IllegalArgumentException if <code>input</code> is <code>null</code>. 1169 * @throws IOException if an error occurs during reading. 1170 * @since 7132 1171 */ 1172 public static BufferedImage read(URL input, boolean readMetadata, boolean enforceTransparency) throws IOException { 1173 CheckParameterUtil.ensureParameterNotNull(input, "input"); 1174 1175 InputStream istream = null; 1176 try { 1177 istream = input.openStream(); 1178 } catch (IOException e) { 1179 throw new IIOException("Can't get input stream from URL!", e); 1180 } 1181 ImageInputStream stream = ImageIO.createImageInputStream(istream); 1182 BufferedImage bi; 1183 try { 1184 bi = read(stream, readMetadata, enforceTransparency); 1185 if (bi == null) { 1186 stream.close(); 1187 } 1188 } finally { 1189 istream.close(); 1190 } 1191 return bi; 1192 } 1193 1194 /** 1195 * Returns a <code>BufferedImage</code> as the result of decoding 1196 * a supplied <code>ImageInputStream</code> with an 1197 * <code>ImageReader</code> chosen automatically from among those 1198 * currently registered. If no registered 1199 * <code>ImageReader</code> claims to be able to read the stream, 1200 * <code>null</code> is returned. 1201 * 1202 * <p> Unlike most other methods in this class, this method <em>does</em> 1203 * close the provided <code>ImageInputStream</code> after the read 1204 * operation has completed, unless <code>null</code> is returned, 1205 * in which case this method <em>does not</em> close the stream. 1206 * 1207 * @param stream an <code>ImageInputStream</code> to read from. 1208 * @param readMetadata if {@code true}, makes sure to read image metadata to detect transparency color for non translucent images, if any. 1209 * In that case the color can be retrieved later through {@link #PROP_TRANSPARENCY_COLOR}. 1210 * Always considered {@code true} if {@code enforceTransparency} is also {@code true} 1211 * @param enforceTransparency if {@code true}, makes sure to read image metadata and, if the image does not 1212 * provide an alpha channel but defines a {@code TransparentColor} metadata node, that the resulting image 1213 * has a transparency set to {@code TRANSLUCENT} and uses the correct transparent color. 1214 * 1215 * @return a <code>BufferedImage</code> containing the decoded 1216 * contents of the input, or <code>null</code>. 1217 * 1218 * @throws IllegalArgumentException if <code>stream</code> is <code>null</code>. 1219 * @throws IOException if an error occurs during reading. 1220 * @since 7132 1221 */ 1222 public static BufferedImage read(ImageInputStream stream, boolean readMetadata, boolean enforceTransparency) throws IOException { 1223 CheckParameterUtil.ensureParameterNotNull(stream, "stream"); 1224 1225 Iterator<ImageReader> iter = ImageIO.getImageReaders(stream); 1226 if (!iter.hasNext()) { 1227 return null; 1228 } 1229 1230 ImageReader reader = iter.next(); 1231 ImageReadParam param = reader.getDefaultReadParam(); 1232 reader.setInput(stream, true, !readMetadata && !enforceTransparency); 1233 BufferedImage bi; 1234 try { 1235 bi = reader.read(0, param); 1236 if (bi.getTransparency() != Transparency.TRANSLUCENT && (readMetadata || enforceTransparency)) { 1237 Color color = getTransparentColor(reader); 1238 if (color != null) { 1239 Hashtable<String, Object> properties = new Hashtable<>(1); 1240 properties.put(PROP_TRANSPARENCY_COLOR, color); 1241 bi = new BufferedImage(bi.getColorModel(), bi.getRaster(), bi.isAlphaPremultiplied(), properties); 1242 if (enforceTransparency) { 1243 if (Main.isDebugEnabled()) { 1244 Main.debug("Enforcing image transparency of "+stream+" for "+color); 1245 } 1246 bi = makeImageTransparent(bi, color); 1247 } 1248 } 1249 } 1250 } finally { 1251 reader.dispose(); 1252 stream.close(); 1253 } 1254 return bi; 1255 } 1256 1257 /** 1258 * Returns the {@code TransparentColor} defined in image reader metadata. 1259 * @param reader The image reader 1260 * @return the {@code TransparentColor} defined in image reader metadata, or {@code null} 1261 * @throws IOException if an error occurs during reading 1262 * @since 7132 1263 * @see <a href="http://docs.oracle.com/javase/7/docs/api/javax/imageio/metadata/doc-files/standard_metadata.html">javax_imageio_1.0 metadata</a> 1264 */ 1265 public static Color getTransparentColor(ImageReader reader) throws IOException { 1266 IIOMetadata metadata = reader.getImageMetadata(0); 1267 if (metadata != null) { 1268 String[] formats = metadata.getMetadataFormatNames(); 1269 if (formats != null) { 1270 for (String f : formats) { 1271 if ("javax_imageio_1.0".equals(f)) { 1272 Node root = metadata.getAsTree(f); 1273 if (root instanceof Element) { 1274 Node item = ((Element)root).getElementsByTagName("TransparentColor").item(0); 1275 if (item instanceof Element) { 1276 String value = ((Element)item).getAttribute("value"); 1277 String[] s = value.split(" "); 1278 if (s.length == 3) { 1279 int[] rgb = new int[3]; 1280 try { 1281 for (int i = 0; i<3; i++) { 1282 rgb[i] = Integer.parseInt(s[i]); 1283 } 1284 return new Color(rgb[0], rgb[1], rgb[2]); 1285 } catch (IllegalArgumentException e) { 1286 Main.error(e); 1287 } 1288 } 1289 } 1290 } 1291 break; 1292 } 1293 } 1294 } 1295 } 1296 return null; 1297 } 1298 1299 /** 1300 * Returns a transparent version of the given image, based on the given transparent color. 1301 * @param bi The image to convert 1302 * @param color The transparent color 1303 * @return The same image as {@code bi} where all pixels of the given color are transparent. 1304 * This resulting image has also the special property {@link #PROP_TRANSPARENCY_FORCED} set to {@code color} 1305 * @since 7132 1306 * @see BufferedImage#getProperty 1307 * @see #isTransparencyForced 1308 */ 1309 public static BufferedImage makeImageTransparent(BufferedImage bi, Color color) { 1310 // the color we are looking for. Alpha bits are set to opaque 1311 final int markerRGB = color.getRGB() | 0xFFFFFFFF; 1312 ImageFilter filter = new RGBImageFilter() { 1313 @Override 1314 public int filterRGB(int x, int y, int rgb) { 1315 if ((rgb | 0xFF000000) == markerRGB) { 1316 // Mark the alpha bits as zero - transparent 1317 return 0x00FFFFFF & rgb; 1318 } else { 1319 return rgb; 1320 } 1321 } 1322 }; 1323 ImageProducer ip = new FilteredImageSource(bi.getSource(), filter); 1324 Image img = Toolkit.getDefaultToolkit().createImage(ip); 1325 ColorModel colorModel = ColorModel.getRGBdefault(); 1326 WritableRaster raster = colorModel.createCompatibleWritableRaster(img.getWidth(null), img.getHeight(null)); 1327 String[] names = bi.getPropertyNames(); 1328 Hashtable<String, Object> properties = new Hashtable<>(1 + (names != null ? names.length : 0)); 1329 if (names != null) { 1330 for (String name : names) { 1331 properties.put(name, bi.getProperty(name)); 1332 } 1333 } 1334 properties.put(PROP_TRANSPARENCY_FORCED, Boolean.TRUE); 1335 BufferedImage result = new BufferedImage(colorModel, raster, false, properties); 1336 Graphics2D g2 = result.createGraphics(); 1337 g2.drawImage(img, 0, 0, null); 1338 g2.dispose(); 1339 return result; 1340 } 1341 1342 /** 1343 * Determines if the transparency of the given {@code BufferedImage} has been enforced by a previous call to {@link #makeImageTransparent}. 1344 * @param bi The {@code BufferedImage} to test 1345 * @return {@code true} if the transparency of {@code bi} has been enforced by a previous call to {@code makeImageTransparent}. 1346 * @since 7132 1347 * @see #makeImageTransparent 1348 */ 1349 public static boolean isTransparencyForced(BufferedImage bi) { 1350 return bi != null && !bi.getProperty(PROP_TRANSPARENCY_FORCED).equals(Image.UndefinedProperty); 1351 } 1352 1353 /** 1354 * Determines if the given {@code BufferedImage} has a transparent color determiend by a previous call to {@link #read}. 1355 * @param bi The {@code BufferedImage} to test 1356 * @return {@code true} if {@code bi} has a transparent color determined by a previous call to {@code read}. 1357 * @since 7132 1358 * @see #read 1359 */ 1360 public static boolean hasTransparentColor(BufferedImage bi) { 1361 return bi != null && !bi.getProperty(PROP_TRANSPARENCY_COLOR).equals(Image.UndefinedProperty); 1362 } 1006 1363 }
Note:
See TracChangeset
for help on using the changeset viewer.