/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wms.decoration;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.GeoServerResourceLoader;
import org.geoserver.wms.WMSMapContent;
import org.geotools.data.DataUtilities;
import org.geotools.util.SoftValueHashMap;
public class WatermarkDecoration implements MapDecoration {
/** A logger for this class. */
private static final Logger LOGGER = Logger.getLogger("org.geoserver.wms.responses");
public static final Color TRANSPARENT = new Color(255, 255, 255, 0);
private static final int TRANSPARENT_CODE = (255 << 16) | (255 << 8) | 255;
private String imageURL;
private float opacity = 1.0f;
/**
* Transient cache to avoid reloading the same file over and over
*/
private static final Map<URL, LogoCacheEntry> logoCache =
new SoftValueHashMap<URL, LogoCacheEntry>();
public void loadOptions(Map<String, String> options){
this.imageURL = options.get("url");
if (options.containsKey("opacity")) {
try {
opacity = Float.valueOf(options.get("opacity")) / 100f;
opacity = Math.max(Math.min(opacity, 1f), 0f);
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Invalid opacity value: " + options.get("opacity"), e);
}
}
}
public Dimension findOptimalSize(Graphics2D g2d, WMSMapContent mapContent){
try{
BufferedImage logo = getLogo();
return new Dimension(logo.getWidth(), logo.getHeight());
} catch (Exception e) {
return new Dimension(20, 20);
}
}
/**
* Print the WaterMarks into the graphic2D.
*
* @param g2D
* @param paintArea
* @throws IOException
* @throws ClassCastException
* @throws MalformedURLException
*/
public void paint(Graphics2D g2D, Rectangle paintArea, WMSMapContent mapContent)
throws MalformedURLException, ClassCastException, IOException {
BufferedImage logo = getLogo();
if (logo != null) {
Composite oldComposite = g2D.getComposite();
g2D.setComposite(
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity)
);
AffineTransform tx =
AffineTransform.getTranslateInstance(paintArea.getX(), paintArea.getY());
tx.scale(
paintArea.getWidth() / logo.getWidth(),
paintArea.getHeight() / logo.getHeight()
);
g2D.drawImage(logo, tx, null);
g2D.setComposite(oldComposite);
}
}
protected BufferedImage getLogo() throws IOException {
BufferedImage logo = null;
// fully resolve the url (consider data dir)
URL url = null;
try {
url = new URL(imageURL);
if (url.getProtocol() == null || url.getProtocol().equals("file")) {
GeoServerResourceLoader loader = GeoServerExtensions.bean(GeoServerResourceLoader.class);
File file = loader.url(imageURL);
if (file.exists()){
url = DataUtilities.fileToURL(file);
}
}
} catch (MalformedURLException e) {
url = null;
}
if (url == null)
return null;
LogoCacheEntry entry = logoCache.get(url);
if (entry == null || entry.isExpired()) {
logo = ImageIO.read(url);
if (url.getProtocol().equals("file")) {
entry = new LogoCacheEntry(logo, new File(url.getFile()));
logoCache.put(url, entry);
}
} else {
logo = entry.getLogo();
}
return logo;
}
/**
* Contains an already loaded logo and the tools to check it's up to date
* compared to the file system
*
* @author Andrea Aime - TOPP
*
*/
private static class LogoCacheEntry {
private BufferedImage logo;
private long lastModified;
private File file;
public LogoCacheEntry(BufferedImage logo, File file) {
this.logo = logo;
this.file = file;
lastModified = file.lastModified();
}
public boolean isExpired() {
return file.lastModified() > lastModified;
}
public BufferedImage getLogo() {
return logo;
}
}
}