/*******************************************************************************
* Copyright (c) 2014 Open Door Logistics (www.opendoorlogistics.com)
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License 3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl.html
*
******************************************************************************/
package com.opendoorlogistics.core.gis.map.background;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import javax.imageio.ImageIO;
import com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.AbstractTileFactory;
import com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.TileFactoryInfo;
import com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.util.GeoUtil;
import com.opendoorlogistics.core.AppConstants;
import com.opendoorlogistics.core.cache.ApplicationCache;
import com.opendoorlogistics.core.cache.RecentlyUsedCache;
import com.opendoorlogistics.core.utils.images.CompressedImage;
import com.opendoorlogistics.core.utils.images.CompressedImage.CompressedType;
class ODLWebTileFactory extends AbstractTileFactory {
private final FadeConfig fade;
public ODLWebTileFactory(TileFactoryInfo info, FadeConfig fadeColor) {
super(info);
setThreadPoolSize(2);
this.fade = fadeColor;
}
private BufferedImage multiAttemptDownload(String url) {
int tries = 0;
while (tries < 3) {
tries++;
try {
URI uri = new URI(url);
byte[] bimg = download(uri.toURL());
BufferedImage img = null;
if (bimg != null) {
img = ImageIO.read(new ByteArrayInputStream(bimg));
}
if (img != null) {
return img;
}
} catch (Throwable e) {
}
}
return null;
}
private byte[] download(URL url) throws IOException {
URLConnection connection = url.openConnection();
connection.setRequestProperty("User-Agent", AppConstants.ORG_NAME + "/" + AppConstants.getAppVersion().toString());
InputStream ins = connection.getInputStream();
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] buf = new byte[256];
while (true) {
int n = ins.read(buf);
if (n == -1)
break;
bout.write(buf, 0, n);
}
return bout.toByteArray();
}
@Override
public BufferedImage renderSynchronously(int tpx, int tpy, int zoom) {
// wrap the tiles horizontally --> mod the X with the max width and use that
int tileX = tpx;
int numTilesWide = (int) GeoUtil.getMapSize(zoom, getInfo()).getWidth();
if (tileX < 0) {
tileX = numTilesWide - (Math.abs(tileX) % numTilesWide);
}
tileX = tileX % numTilesWide;
int tileY = tpy;
RecentlyUsedCache cache = ApplicationCache.singleton().get(ApplicationCache.SYNCHRONOUS_RETRIEVED_TILE_CACHE);
// try getting from cache
String url = getInfo().getTileUrl(tileX, tileY, zoom);
CompressedImage img = (CompressedImage) cache.get(url);
if (img != null) {
return img.getBufferedImage();
}
// try downloading
BufferedImage bimg = multiAttemptDownload(url);
if(bimg==null){
return null;
}
// turn image into argb so we can fade, then do fade
BufferedImage workImg = greyscaleFade(bimg);
// save to cache
CompressedImage compressed = new CompressedImage(workImg, CompressedType.PNG);
cache.put(url, compressed, compressed.getSizeBytes());
return workImg;
}
/**
* @param bimg
* @return
*/
private BufferedImage greyscaleFade(BufferedImage bimg) {
BufferedImage workImg = new BufferedImage(bimg.getWidth(), bimg.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g=null;
try {
g = workImg.createGraphics();
g.setClip(0, 0, bimg.getWidth(), bimg.getHeight());
g.drawImage(bimg, 0, 0, null);
if(fade!=null){
BackgroundMapUtils.renderFade(g, fade.getColour());
}
} catch (Exception e) {
// TODO: handle exception
}
finally{
if(g!=null){
g.dispose();
g = null;
}
}
if(fade!=null){
workImg = BackgroundMapUtils.greyscale(workImg, fade.getGreyscale());
}
return workImg;
}
@Override
protected BufferedImage processLoadedImage(BufferedImage img){
return greyscaleFade(img);
}
@Override
public boolean isRenderedOffline() {
return false;
}
}