]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.maps/src/org/simantics/maps/osm/OSMTileProvider.java
Ensure ITileProviders return BufferedImages with compatible ColorModel
[simantics/district.git] / org.simantics.district.maps / src / org / simantics / maps / osm / OSMTileProvider.java
1 /*******************************************************************************
2  * Copyright (c) 2012 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.maps.osm;
13
14 import java.awt.Dimension;
15 import java.awt.Image;
16 import java.awt.geom.Rectangle2D;
17 import java.awt.image.BufferedImage;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.net.HttpURLConnection;
21 import java.net.MalformedURLException;
22 import java.net.URI;
23
24 import javax.imageio.IIOException;
25 import javax.imageio.ImageIO;
26
27 import org.simantics.maps.ProvisionException;
28 import org.simantics.maps.WebService;
29 import org.simantics.maps.internal.ImageUtil;
30 import org.simantics.maps.tile.ITileProvider;
31 import org.simantics.maps.tile.TileKey;
32 import org.simantics.maps.wms.ServiceException;
33
34 /**
35  * @author Tuukka Lehtonen
36  * @see OSMGetMapQuery
37  */
38 public class OSMTileProvider implements ITileProvider {
39
40     private WebService  service;
41
42     private int      tileSize;
43
44     public OSMTileProvider(WebService service, int tileSize) {
45         this.service = service;
46         this.tileSize = tileSize;
47     }
48
49     @Override
50     public URI getSource() {
51         return service.getURI();
52     }
53
54     @Override
55     public Rectangle2D getExtent() {
56         return new Rectangle2D.Double(-180, -90, 360, 180);
57     }
58
59     @Override
60     public Image get(TileKey key) throws ProvisionException {
61         int level = key.getLevel();
62         int x = key.getX();
63         int y = key.getY();
64
65         double xTiles = Math.pow(2, level + 1);
66         double yTiles = Math.pow(2, level);
67
68         if (level < 0)
69             throw new IllegalArgumentException("invalid tile level " + level + " (tile=" + key +")");
70         if (x < 0 || x >= (int) xTiles)
71             throw new IllegalArgumentException("tile x out of bounds " + x + " (tile=" + key +")");
72         if (y < 0 || y >= (int) yTiles)
73             throw new IllegalArgumentException("tile y out of bounds " + y + " (tile=" + key +")");
74
75         try {
76             Rectangle2D r = new Rectangle2D.Double(x, y, 10, 10);
77
78 //            System.out.println("TileProvider: requesting " + key + ", bbox=" + r + ", size=" + tileSize);
79             BufferedImage img = getMap(service, tileSize, tileSize, r, "image/png", level);//layers);
80 //            System.out.println("TileProvider: response: " + img);
81             return img;
82         } catch (MalformedURLException e) {
83             throw new ProvisionException(e);
84         } catch (IOException e) {
85             throw new ProvisionException(e);
86         }
87     }
88
89     
90     /**
91      * Get a bufferedimage of the map data for the geographical coordinates.
92      * 
93      * @param x
94      * @param y
95      * @param z
96      * @return
97      * @throws MalformedURLException 
98      */
99     public static BufferedImage getMap(WebService service, Dimension rasterSize, Rectangle2D bbox, String format, int level) throws MalformedURLException, IOException {
100         return getMap(service, rasterSize.width, rasterSize.height, bbox, format, level);
101     }
102
103     /**
104      * Get a bufferedimage of the map data for the geographical coordinates.
105      * 
106      * @param x
107      * @param y
108      * @param z
109      * @return
110      * @throws MalformedURLException 
111      */
112     public static BufferedImage getMap(WebService service, int rasterWidth, int rasterHeight, Rectangle2D bbox, String format, int level) throws MalformedURLException, IOException {
113         if (rasterWidth == 0 || rasterHeight == 0)
114             return new BufferedImage(0, 0, BufferedImage.TYPE_INT_ARGB);
115
116         HttpURLConnection connection = null;
117         try {
118             connection = service.openConnection(("" + level + "/" + Math.round(bbox.getMinX()) + "/" + Math.round(bbox.getMinY())+".png"), null);
119
120             // Execute the method.
121             int statusCode = connection.getResponseCode();
122
123             if (statusCode != HttpURLConnection.HTTP_OK) {
124                 System.err.println("Method failed: " + connection.getResponseMessage());
125             }
126
127 //            for (Header h : method.getResponseHeaders()) {
128 //                System.out.println("HDR: " + h.getName() + ": " + h.getValue());
129 //            }
130
131             String contentType = connection.getHeaderField("Content-Type");
132             if (contentType != null) {
133 //                System.out.println("Content-Type: " + contentType);
134                 if (contentType.equals(format)) {
135                     InputStream response = connection.getInputStream();
136                     BufferedImage img = ImageIO.read(response);
137                     if (img == null) {
138                         throw new IIOException("ImageIO returned null, unable to decode stream as image data.");
139                     }
140                     return ImageUtil.toScreenCompatibleImage(img);
141                 }
142             }
143
144             // Request failed,  produce as much debug information as possible.
145             StringBuilder sb = new StringBuilder();
146             sb.append("Response headers:\n");
147             for (String h : connection.getHeaderFields().keySet()) {
148                 sb.append(h);
149                 sb.append(": ");
150                 sb.append(connection.getHeaderField(h));
151                 sb.append("\n");
152             }
153             String response = connection.getContent().toString();
154             sb.append("Response body:\n");
155             sb.append(response);
156             throw new ServiceException("WMS GetMap request failed: " + connection.getURL().toString() + "\n" + sb.toString());
157         } finally {
158             // Release the connection.
159             if (connection != null)
160                 connection.disconnect();
161         }
162     }
163
164 }