]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.maps/src/org/simantics/maps/wms/WMSTileProvider.java
Ensure ITileProviders return BufferedImages with compatible ColorModel
[simantics/district.git] / org.simantics.district.maps / src / org / simantics / maps / wms / WMSTileProvider.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.wms;
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
33 /**
34  * @author Tuukka Lehtonen
35  */
36 public class WMSTileProvider implements ITileProvider {
37
38     private WebService  service;
39
40     private int      tileSize;
41
42     private String[] layers;
43
44     public WMSTileProvider(WebService service, int tileSize, String... layers) {
45         this.service = service;
46         this.tileSize = tileSize;
47         this.layers = layers;
48     }
49
50     @Override
51     public URI getSource() {
52         return service.getURI();
53     }
54
55     @Override
56     public Rectangle2D getExtent() {
57         return new Rectangle2D.Double(-180, -90, 360, 180);
58     }
59
60     @Override
61     public Image get(TileKey key) throws ProvisionException {
62         int level = key.getLevel();
63         int x = key.getX();
64         int y = key.getY();
65
66         double xTiles = Math.pow(2, level + 1);
67         double yTiles = Math.pow(2, level);
68
69         if (level < 0)
70             throw new IllegalArgumentException("invalid tile level " + level + " (tile=" + key +")");
71         if (x < 0 || x >= (int) xTiles)
72             throw new IllegalArgumentException("tile x out of bounds " + x + " (tile=" + key +")");
73         if (y < 0 || y >= (int) yTiles)
74             throw new IllegalArgumentException("tile y out of bounds " + y + " (tile=" + key +")");
75
76         try {
77             Rectangle2D r = new Rectangle2D.Double();
78
79             double minx = -180;
80             double miny = -90;
81             double w = 360;
82             double h = 180;
83
84             double xdelta = w / xTiles;
85             double ydelta = h / yTiles;
86             double xx = x;
87             double yy = yTiles - y - 1;
88
89             r.setFrame(
90                     minx + xdelta*xx,
91                     miny + ydelta*yy,
92                     xdelta,
93                     ydelta
94             );
95
96 //            System.out.println("TileProvider: requesting " + key + ", bbox=" + r + ", size=" + tileSize);
97             BufferedImage img = getMap(service, tileSize, tileSize, r, "image/jpeg", layers);
98 //            System.out.println("TileProvider: response: " + img);
99             return img;
100         } catch (MalformedURLException e) {
101             throw new ProvisionException(e);
102         } catch (IOException e) {
103             throw new ProvisionException(e);
104         }
105     }
106     
107     /**
108      * Get a bufferedimage of the map data for the geographical coordinates.
109      * 
110      * @param x
111      * @param y
112      * @param z
113      * @return
114      * @throws MalformedURLException 
115      */
116     public static BufferedImage getMap(WebService service, Dimension rasterSize, Rectangle2D bbox, String format, String... layers) throws MalformedURLException, IOException {
117         return getMap(service, rasterSize.width, rasterSize.height, bbox, format, layers);
118     }
119
120     /**
121      * Get a bufferedimage of the map data for the geographical coordinates.
122      * 
123      * @param x
124      * @param y
125      * @param z
126      * @return
127      * @throws MalformedURLException 
128      */
129     public static BufferedImage getMap(WebService service, int rasterWidth, int rasterHeight, Rectangle2D bbox, String format, String... layers) throws MalformedURLException, IOException {
130         if (rasterWidth == 0 || rasterHeight == 0)
131             return new BufferedImage(0, 0, BufferedImage.TYPE_INT_ARGB);
132
133         // Create a method instance.
134         WMSGetMapQuery req = new WMSGetMapQuery(rasterWidth, rasterHeight, bbox, format, layers);
135 //        req.setStyles("visual");
136
137 //        String requestUrl = service.getRequestURL("", req.toString());
138 //        System.out.println("REQUEST: " + requestUrl);
139
140         HttpURLConnection connection = null;
141         try {
142                 connection = service.openConnection("", req.toString());
143             // Execute the method.
144             int statusCode = connection.getResponseCode();
145
146             if (statusCode != HttpURLConnection.HTTP_OK) {
147                 System.err.println("Method failed: " + connection.getResponseMessage());
148             }
149
150 //            for (Header h : method.getResponseHeaders()) {
151 //                System.out.println("HDR: " + h.getName() + ": " + h.getValue());
152 //            }
153
154             String contentType = connection.getHeaderField("Content-Type");
155             if (contentType != null) {
156 //                System.out.println("Content-Type: " + contentType);
157                 if (contentType.equals(format)) {
158                     InputStream response = connection.getInputStream();
159                     BufferedImage img = ImageIO.read(response);
160                     if (img == null) {
161                         throw new IIOException("ImageIO returned null, unable to decode stream as image data.");
162                     }
163                     return ImageUtil.toScreenCompatibleImage(img);
164                 }
165             }
166
167             // Request failed,  produce as much debug information as possible.
168             StringBuilder sb = new StringBuilder();
169             for (String h : connection.getHeaderFields().keySet()) {
170                 sb.append(h);
171                 sb.append(": ");
172                 sb.append(connection.getHeaderField(h));
173                 sb.append("\n");
174             }
175             String response = connection.getContent().toString();
176             sb.append("Response body:\n");
177             sb.append(response);
178             throw new ServiceException("WMS GetMap request failed: " + connection.getURL().toString() + "\n" + sb.toString());
179         } finally {
180             // Release the connection.
181             connection.disconnect();
182         }
183     }
184
185 }