/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2008 - 2010, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotoolkit.display2d.style;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.logging.Level;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import org.geotoolkit.renderer.style.DynamicSymbolFactoryFinder;
import org.opengis.filter.expression.Function;
import org.opengis.metadata.citation.OnlineResource;
import org.opengis.style.ColorReplacement;
import org.opengis.style.ExternalGraphic;
import org.apache.sis.util.logging.Logging;
import org.geotoolkit.nio.IOUtilities;
/**
* Cached External graphic
*
* @author Johann Sorel (Geomatys)
* @module
*/
public class CachedExternal extends Cache<ExternalGraphic>{
//Cached values
private BufferedImage cachedImage = null;
private boolean isSVG = false;
private CachedExternal(final ExternalGraphic external){
super(external);
}
/**
* {@inheritDoc }
*/
@Override
protected void evaluate(){
if(!isNotEvaluated) return;
if(!evaluateExternal()){
//no valid image we can clear the cache, nothing to paint, nothing
// visible
cachedImage = null;
isStaticVisible = VisibilityState.UNVISIBLE;
}else{
isStaticVisible = VisibilityState.VISIBLE;
}
isStatic = !isSVG;
requieredAttributs = EMPTY_ATTRIBUTS;
isNotEvaluated = false;
}
/**
*
* @return true if is visible, false if something says there's nothing to paint
*/
private boolean evaluateExternal(){
//try to grab the inline image
final Icon inline = styleElement.getInlineContent();
if(inline != null){
cachedImage = new BufferedImage(inline.getIconWidth(), inline.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = (Graphics2D) cachedImage.getGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
inline.paintIcon(null, g2, 0,0);
g2.dispose();
}
//if no inline image then use the online image
if(cachedImage == null){
OnlineResource online = styleElement.getOnlineResource();
if(online != null && online.getLinkage() != null){
final URI uri = styleElement.getOnlineResource().getLinkage();
isSVG = uri != null && uri.toString().toLowerCase().endsWith(".svg");
if (!isSVG) {
try (InputStream in = IOUtilities.open(uri)){
cachedImage = ImageIO.read(in);
} catch (IOException ex) {
LOGGER.log(Level.INFO, "CacheExternal, can read image for path : "+ uri.toString()+" : "+ex.getMessage());
}
}
}
}
cachedImage = recode(cachedImage, styleElement.getColorReplacements());
return true;
}
/**
* {@inheritDoc }
*/
@Override
public boolean isVisible(final Object candidate) {
return isValid();
}
/**
*
* @return true if this external image is valid.
*/
public boolean isValid(){
evaluate();
return isSVG || cachedImage != null;
}
/**
* Create or generate the image at a giver size.
*
* @param size : image size
* @return BufferedImage
*/
public BufferedImage getImage(final Float size, final float coeff, final RenderingHints hints){
evaluate();
BufferedImage img = cachedImage;
if(cachedImage == null && isSVG){
final URI uri = styleElement.getOnlineResource().getLinkage();
if(uri != null){
try{
final BufferedImage buffer = DynamicSymbolFactoryFinder.getImage(uri, styleElement.getFormat(),size, hints);
return recode(buffer, styleElement.getColorReplacements());
}catch (Exception ex){
Logging.getLogger("org.geotoolkit.display2d.style").log(Level.WARNING, null, ex);
}
}
// final float aspect = (float)(cachedImage.getHeight()) / size.floatValue() ;
// final float maxwidth = cachedImage.getWidth() / aspect;
//
// BufferedImage buffer = new BufferedImage( (int)(maxwidth+0.5f), (int)(size.floatValue()), BufferedImage.TYPE_INT_ARGB);
// Graphics2D g2 = (Graphics2D) buffer.getGraphics();
// if(hints != null) g2.setRenderingHints(hints);
// g2.drawImage(cachedImage, 0, 0,buffer.getWidth(), buffer.getHeight(), 0, 0, cachedImage.getWidth(), cachedImage.getHeight(),null);
// g2.dispose();
// img = buffer;
}
//resize image if necessary
if(cachedImage != null && size != null && !size.isNaN()){
final float aspect = (float)(cachedImage.getHeight()) / size.floatValue() ;
final float maxwidth = cachedImage.getWidth() / aspect;
if((int)(maxwidth+0.5f)<=0 || (int)(size.floatValue()) <= 0){
return null;
}
final BufferedImage buffer = new BufferedImage( (int)(maxwidth+0.5f), (int)(size.floatValue()), BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2 = (Graphics2D) buffer.getGraphics();
if(hints != null) g2.setRenderingHints(hints);
g2.drawImage(cachedImage, 0, 0,buffer.getWidth(), buffer.getHeight(), 0, 0, cachedImage.getWidth(), cachedImage.getHeight(),null);
g2.dispose();
img = buffer;
}
if(coeff != 1){
final float aspect = (float)(cachedImage.getHeight()) / coeff ;
final float maxwidth = cachedImage.getWidth() / aspect;
final BufferedImage buffer = new BufferedImage( (int)(maxwidth+0.5f), (int)(coeff), BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2 = (Graphics2D) buffer.getGraphics();
if(hints != null) g2.setRenderingHints(hints);
g2.drawImage(cachedImage, 0, 0,buffer.getWidth(), buffer.getHeight(), 0, 0, cachedImage.getWidth(), cachedImage.getHeight(),null);
g2.dispose();
img = buffer;
}
return img;
}
public static CachedExternal cache(final ExternalGraphic external){
return new CachedExternal(external);
}
private static BufferedImage recode(BufferedImage buffer, final Collection<ColorReplacement> replacements){
if(buffer != null){
for(final ColorReplacement replace : replacements){
final Function fct = replace.getRecoding();
buffer = fct.evaluate(buffer, BufferedImage.class);
}
}
return buffer;
}
}