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

Last change on this file since 3715 was 3715, checked in by Upliner, 14 years ago

Added imagery plugin to josm core. Imagery plugin is union of wmsplugin and slippymap plugins. It includes code by Tim Waters, Petr Dlouhý, Frederik Ramm and others. Also enables the remotecontol which was integrated in [3707].

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