001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.cache; 003 004import java.awt.image.BufferedImage; 005import java.io.ByteArrayInputStream; 006import java.io.IOException; 007 008import javax.imageio.ImageIO; 009 010/** 011 * Cache Entry that has methods to get the BufferedImage, that will be cached along in memory 012 * but will be not serialized when saved to the disk (to avoid duplication of data) 013 * 014 * @author Wiktor Niesiobędzki 015 */ 016public class BufferedImageCacheEntry extends CacheEntry { 017 private static final long serialVersionUID = 1L; //version 018 // transient to avoid serialization, volatile to avoid synchronization of whole getImage() method 019 private transient volatile BufferedImage img; 020 // we need to have separate control variable, to know, if we already tried to load the image, as img might be null 021 // after we loaded image, as for example, when image file is malformed (eg. HTML file) 022 private transient volatile boolean imageLoaded; 023 024 /** 025 * 026 * @param content byte array containing image 027 */ 028 public BufferedImageCacheEntry(byte[] content) { 029 super(content); 030 } 031 032 /** 033 * Returns BufferedImage from for the content. Subsequent calls will return the same instance, 034 * to reduce overhead of ImageIO 035 * 036 * @return BufferedImage of cache entry content 037 * @throws IOException if an error occurs during reading. 038 */ 039 public BufferedImage getImage() throws IOException { 040 if (imageLoaded) 041 return img; 042 synchronized (this) { 043 if (imageLoaded) 044 return img; 045 byte[] content = getContent(); 046 if (content.length > 0) { 047 img = ImageIO.read(new ByteArrayInputStream(content)); 048 imageLoaded = true; 049 } 050 } 051 return img; 052 } 053 054 private void writeObject(java.io.ObjectOutputStream out) throws IOException { 055 /* 056 * This method below will be needed, if Apache Commons JCS (or any other caching system), will update 057 * disk representation of object from memory, once it is put into the cache (for example - at closing the cache) 058 * 059 * For now it is not the case, as we use DiskUsagePattern.UPDATE, which on JCS shutdown doesn't write again memory 060 * contents to file, so the fact, that we've cleared never gets saved to the disk 061 * 062 * This method is commented out, as it will convert all cache entries to PNG files regardless of what was returned. 063 * It might cause recompression/change of format which may result in decreased quality of imagery 064 */ 065 /* synchronized (this) { 066 if (content == null && img != null) { 067 ByteArrayOutputStream restoredData = new ByteArrayOutputStream(); 068 ImageIO.write(img, "png", restoredData); 069 content = restoredData.toByteArray(); 070 } 071 out.writeObject(this); 072 } 073 */ 074 synchronized (this) { 075 if (content == null && img != null) { 076 throw new AssertionError("Trying to serialize (save to disk?) an BufferedImageCacheEntry " + 077 "that was converted to BufferedImage and no raw data is present anymore"); 078 } 079 out.writeObject(this); 080 081 if (img != null) { 082 content = null; 083 } 084 } 085 } 086}