source: josm/trunk/src/org/openstreetmap/josm/data/imagery/GeorefImage.java@ 3872

Last change on this file since 3872 was 3808, checked in by jttt, 13 years ago

wmslayer - when overlapping is enabled, keep (and cache) only visible part of image; center text in case of "not in cache" or "error"

  • Property svn:eol-style set to native
File size: 8.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.imagery;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Color;
7import java.awt.Font;
8import java.awt.Graphics;
9import java.awt.Image;
10import java.awt.Transparency;
11import java.awt.image.BufferedImage;
12import java.io.IOException;
13import java.io.ObjectInputStream;
14import java.io.ObjectOutputStream;
15import java.io.Serializable;
16import java.lang.ref.SoftReference;
17
18import javax.imageio.ImageIO;
19
20import org.openstreetmap.josm.data.coor.EastNorth;
21import org.openstreetmap.josm.gui.NavigatableComponent;
22import org.openstreetmap.josm.gui.layer.ImageryLayer;
23import org.openstreetmap.josm.gui.layer.WMSLayer;
24
25public class GeorefImage implements Serializable {
26 private static final long serialVersionUID = 1L;
27
28 public enum State { IMAGE, NOT_IN_CACHE, FAILED}
29
30 private WMSLayer layer;
31 private State state;
32
33 private BufferedImage image;
34 private SoftReference<BufferedImage> reImg;
35 private int xIndex;
36 private int yIndex;
37
38 private static final Color transparentColor = new Color(0,0,0,0);
39 private Color fadeColor = transparentColor;
40
41 public EastNorth getMin() {
42 return layer.getEastNorth(xIndex, yIndex);
43 }
44
45 public EastNorth getMax() {
46 return layer.getEastNorth(xIndex+1, yIndex+1);
47 }
48
49
50 public GeorefImage(WMSLayer layer) {
51 this.layer = layer;
52 }
53
54 public void changePosition(int xIndex, int yIndex) {
55 if (!equalPosition(xIndex, yIndex)) {
56 this.xIndex = xIndex;
57 this.yIndex = yIndex;
58 this.image = null;
59 flushedResizedCachedInstance();
60 }
61 }
62
63 public boolean equalPosition(int xIndex, int yIndex) {
64 return this.xIndex == xIndex && this.yIndex == yIndex;
65 }
66
67 public void changeImage(State state, BufferedImage image) {
68 flushedResizedCachedInstance();
69 this.image = image;
70 this.state = state;
71
72 switch (state) {
73 case FAILED:
74 {
75 BufferedImage img = createImage();
76 layer.drawErrorTile(img);
77 this.image = img;
78 break;
79 }
80 case NOT_IN_CACHE:
81 {
82 BufferedImage img = createImage();
83 Graphics g = img.getGraphics();
84 g.setColor(Color.GRAY);
85 g.fillRect(0, 0, img.getWidth(), img.getHeight());
86 Font font = g.getFont();
87 Font tempFont = font.deriveFont(Font.PLAIN).deriveFont(36.0f);
88 g.setFont(tempFont);
89 g.setColor(Color.BLACK);
90 String text = tr("Not in cache");
91 g.drawString(text, (img.getWidth() - g.getFontMetrics().stringWidth(text)) / 2, img.getHeight()/2);
92 g.setFont(font);
93 this.image = img;
94 break;
95 }
96 default:
97 this.image = layer.sharpenImage(this.image);
98 break;
99 }
100 }
101
102 private BufferedImage createImage() {
103 return new BufferedImage(layer.getImageSize(), layer.getImageSize(), BufferedImage.TYPE_INT_RGB);
104 }
105
106 public boolean paint(Graphics g, NavigatableComponent nc, int xIndex, int yIndex, int leftEdge, int bottomEdge) {
107 if (image == null)
108 return false;
109
110 if(!(this.xIndex == xIndex && this.yIndex == yIndex))
111 return false;
112
113 int left = layer.getImageX(xIndex);
114 int bottom = layer.getImageY(yIndex);
115 int width = layer.getImageWidth(xIndex);
116 int height = layer.getImageHeight(yIndex);
117
118 int x = left - leftEdge;
119 int y = nc.getHeight() - (bottom - bottomEdge) - height;
120
121 // This happens if you zoom outside the world
122 if(width == 0 || height == 0)
123 return false;
124
125 // TODO: implement per-layer fade color
126 Color newFadeColor;
127 if (ImageryLayer.PROP_FADE_AMOUNT.get() == 0) {
128 newFadeColor = transparentColor;
129 } else {
130 newFadeColor = ImageryLayer.getFadeColorWithAlpha();
131 }
132
133 BufferedImage img = reImg == null?null:reImg.get();
134 if(img != null && img.getWidth() == width && img.getHeight() == height && fadeColor.equals(newFadeColor)) {
135 g.drawImage(img, x, y, null);
136 return true;
137 }
138
139 fadeColor = newFadeColor;
140
141 boolean alphaChannel = WMSLayer.PROP_ALPHA_CHANNEL.get() && getImage().getTransparency() != Transparency.OPAQUE;
142
143 try {
144 if(img != null) {
145 img.flush();
146 }
147 long freeMem = Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory();
148 //System.out.println("Free Memory: "+ (freeMem/1024/1024) +" MB");
149 // Notice that this value can get negative due to integer overflows
150 //System.out.println("Img Size: "+ (width*height*3/1024/1024) +" MB");
151
152 int multipl = alphaChannel ? 4 : 3;
153 // This happens when requesting images while zoomed out and then zooming in
154 // Storing images this large in memory will certainly hang up JOSM. Luckily
155 // traditional rendering is as fast at these zoom levels, so it's no loss.
156 // Also prevent caching if we're out of memory soon
157 if(width > 2000 || height > 2000 || width*height*multipl > freeMem) {
158 fallbackDraw(g, getImage(), x, y, width, height, alphaChannel);
159 } else {
160 // We haven't got a saved resized copy, so resize and cache it
161 img = new BufferedImage(width, height, alphaChannel?BufferedImage.TYPE_INT_ARGB:BufferedImage.TYPE_3BYTE_BGR);
162 img.getGraphics().drawImage(getImage(),
163 0, 0, width, height, // dest
164 0, 0, getImage().getWidth(null), getImage().getHeight(null), // src
165 null);
166 if (!alphaChannel) {
167 drawFadeRect(img.getGraphics(), 0, 0, width, height);
168 }
169 img.getGraphics().dispose();
170 g.drawImage(img, x, y, null);
171 reImg = new SoftReference<BufferedImage>(img);
172 }
173 } catch(Exception e) {
174 fallbackDraw(g, getImage(), x, y, width, height, alphaChannel);
175 }
176 return true;
177 }
178
179 private void fallbackDraw(Graphics g, Image img, int x, int y, int width, int height, boolean alphaChannel) {
180 flushedResizedCachedInstance();
181 g.drawImage(
182 img, x, y, x + width, y + height,
183 0, 0, img.getWidth(null), img.getHeight(null),
184 null);
185 if (!alphaChannel) { //FIXME: fading for layers with alpha channel currently is not supported
186 drawFadeRect(g, x, y, width, height);
187 }
188 }
189
190 private void drawFadeRect(Graphics g, int x, int y, int width, int height) {
191 if (fadeColor != transparentColor) {
192 g.setColor(fadeColor);
193 g.fillRect(x, y, width, height);
194 }
195 }
196
197 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
198 state = (State) in.readObject();
199 boolean hasImage = in.readBoolean();
200 if (hasImage) {
201 image = (ImageIO.read(ImageIO.createImageInputStream(in)));
202 } else {
203 in.readObject(); // read null from input stream
204 image = null;
205 }
206 }
207
208 private void writeObject(ObjectOutputStream out) throws IOException {
209 out.writeObject(state);
210 if(getImage() == null) {
211 out.writeBoolean(false);
212 out.writeObject(null);
213 } else {
214 out.writeBoolean(true);
215 ImageIO.write(getImage(), "png", ImageIO.createImageOutputStream(out));
216 }
217 }
218
219 public void flushedResizedCachedInstance() {
220 if (reImg != null) {
221 BufferedImage img = reImg.get();
222 if (img != null) {
223 img.flush();
224 }
225 }
226 reImg = null;
227 }
228
229
230 public BufferedImage getImage() {
231 return image;
232 }
233
234 public State getState() {
235 return state;
236 }
237
238 public int getXIndex() {
239 return xIndex;
240 }
241
242 public int getYIndex() {
243 return yIndex;
244 }
245
246 public void setLayer(WMSLayer layer) {
247 this.layer = layer;
248 }
249}
Note: See TracBrowser for help on using the repository browser.