/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2006-2008, Open Source Geospatial Foundation (OSGeo) * * 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.geotools.gce.imagemosaic; import it.geosolutions.imageio.utilities.ImageIOUtilities; import java.awt.RenderingHints; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collections; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.imageio.spi.ImageReaderSpi; import org.geotools.coverage.grid.io.AbstractGridFormat; import org.geotools.coverage.grid.io.GridFormatFactorySpi; import com.sun.media.imageioimpl.common.PackageUtil; import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReaderCodecLibSpi; import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReaderSpi; import com.sun.media.imageioimpl.plugins.tiff.TIFFImageReaderSpi; /** * Implementation of the GridCoverageFormat service provider interface for * mosaic of georeferenced images. * * @author Simone Giannecchini, GeoSolutions S.A.S. * @since 2.3 * * @source $URL$ */ public final class ImageMosaicFormatFactory implements GridFormatFactorySpi { /** Logger. */ private final static Logger LOGGER = org.geotools.util.logging.Logging.getLogger(ImageMosaicFormatFactory.class); private static final String KAKADU_SPI = "it.geosolutions.imageio.plugins.jp2k.JP2KKakaduImageReaderSpi"; private static final String GDAL_SPI = "it.geosolutions.imageio.gdalframework.GDALImageReaderSpi"; private static final String GDAL_JP2ECW_SPI = "it.geosolutions.imageio.plugins.jp2ecw.JP2GDALEcwImageReaderSpi"; private static final String GDAL_JP2MrSID_SPI = "it.geosolutions.imageio.plugins.jp2mrsid.JP2GDALMrSidImageReaderSpi"; private static final String GDAL_JP2KAKADU_SPI = "it.geosolutions.imageio.plugins.jp2kakadu.JP2GDALKakaduImageReaderSpi"; static { replaceTIFF(); if(hasJP2Kakadu()){ replaceJP2Kakadu(); } else{ if(hasJP2GDALECW()){ replaceECW(); } if(hasJP2GDALMRSID()){ replaceMRSID(); } if(hasJP2GDALKakadu()){ replaceGDALKakadu(); } } } /** * Tells me if this plugin will work on not given the actual installation. * * <p> * Dependecies are mostly from JAI and ImageIO so if they are installed you * should not have many problems. * * @return False if something's missing, true otherwise. */ public boolean isAvailable() { boolean available = true; // if these classes are here, then the runtine environment has // access to JAI and the JAI ImageI/O toolbox. try { Class.forName("javax.media.jai.JAI"); Class.forName("com.sun.media.jai.operator.ImageReadDescriptor"); } catch (ClassNotFoundException cnf) { available = false; } return available; } private static boolean hasJP2Kakadu() { try{ @SuppressWarnings("unused") Class<?> cl = Class.forName(KAKADU_SPI); Class<?> utilityClass = Class.forName("it.geosolutions.util.KakaduUtilities"); final Method method = utilityClass.getDeclaredMethod("isKakaduAvailable", (Class[])null); if (method != null){ Boolean isAvailable = (Boolean) method.invoke(null, null); return isAvailable.booleanValue(); } } catch (ClassNotFoundException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load kakadu JPEG2000 reader spi",e); } catch (SecurityException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load kakadu JPEG2000 reader spi",e); } catch (NoSuchMethodException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load kakadu JPEG2000 reader spi",e); } catch (IllegalArgumentException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load kakadu JPEG2000 reader spi",e); } catch (IllegalAccessException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load kakadu JPEG2000 reader spi",e); } catch (InvocationTargetException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load kakadu JPEG2000 reader spi",e); } return false; } private static void replaceJP2Kakadu() { try{ Class.forName(KAKADU_SPI); // imageio kakJP2 reader final String imageioJ2KImageReaderCodecName=J2KImageReaderCodecLibSpi.class.getName(); if(PackageUtil.isCodecLibAvailable()){ boolean succeeded=ImageIOUtilities.replaceProvider(ImageReaderSpi.class, KAKADU_SPI, imageioJ2KImageReaderCodecName, "JPEG 2000"); if(!succeeded) if (LOGGER.isLoggable(Level.WARNING)) LOGGER.warning("Unable to set ordering between jp2 readers spi-"+KAKADU_SPI+":"+imageioJ2KImageReaderCodecName); } // imageio kakJP2 reader final String imageioJ2KImageReaderName=J2KImageReaderSpi.class.getName(); final boolean succeeded=ImageIOUtilities.replaceProvider(ImageReaderSpi.class, KAKADU_SPI, imageioJ2KImageReaderName, "JPEG 2000"); if(!succeeded) if (LOGGER.isLoggable(Level.WARNING)) LOGGER.warning("Unable to set ordering between jp2 readers spi-"+KAKADU_SPI+":"+imageioJ2KImageReaderName); } catch (ClassNotFoundException e) { if (LOGGER.isLoggable(Level.WARNING)) LOGGER.log(Level.WARNING, "Unable to load specific JPEG2000 reader spi",e); } } private static void replaceTIFF() { try{ //check if our tiff plugin is in the path final String customTiffName=it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReaderSpi.class.getName(); Class.forName(customTiffName); // imageio tiff reader final String imageioTiffName=TIFFImageReaderSpi.class.getName(); final boolean succeeded=ImageIOUtilities.replaceProvider(ImageReaderSpi.class, customTiffName, imageioTiffName, "tiff"); if(!succeeded) if (LOGGER.isLoggable(Level.WARNING)) LOGGER.warning("Unable to set ordering between tiff readers spi"); } catch (ClassNotFoundException e) { if (LOGGER.isLoggable(Level.WARNING)) LOGGER.log(Level.WARNING,"Unable to load specific TIFF reader spi",e); } } private static boolean hasJP2GDALKakadu() { try{ @SuppressWarnings("unused") Class<?> cl = Class.forName(GDAL_JP2KAKADU_SPI); Class<?> cGdal = Class.forName(GDAL_SPI); Object jp2Kak = cl.newInstance(); final Method method = cGdal.getDeclaredMethod("isAvailable", (Class[])null); if (method != null){ Boolean isAvailable = (Boolean) method.invoke(jp2Kak, null); return isAvailable.booleanValue(); } } catch (ClassNotFoundException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 Kakadu Reader SPI", e); } catch (SecurityException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 Kakadu Reader SPI", e); } catch (NoSuchMethodException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 Kakadu Reader SPI", e); } catch (IllegalArgumentException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 Kakadu Reader SPI", e); } catch (IllegalAccessException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 Kakadu Reader SPI", e); } catch (InvocationTargetException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 Kakadu Reader SPI", e); } catch (InstantiationException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 Kakadu Reader SPI", e); } return false; } private static void replaceGDALKakadu() { try{ //check if our kakJP2 plugin is in the path Class.forName(GDAL_JP2KAKADU_SPI); // imageio kakJP2 reader final String imageioJ2KImageReaderCodecName=J2KImageReaderCodecLibSpi.class.getName(); if(PackageUtil.isCodecLibAvailable()){ boolean succeeded=ImageIOUtilities.replaceProvider(ImageReaderSpi.class, GDAL_JP2KAKADU_SPI, imageioJ2KImageReaderCodecName, "JPEG 2000"); if(!succeeded) if (LOGGER.isLoggable(Level.WARNING)) LOGGER.warning("Unable to set ordering between jp2 readers spi-"+GDAL_JP2KAKADU_SPI+":"+imageioJ2KImageReaderCodecName); } // imageio kakJP2 reader final String imageioJ2KImageReaderName=J2KImageReaderSpi.class.getName(); final boolean succeeded=ImageIOUtilities.replaceProvider(ImageReaderSpi.class, GDAL_JP2KAKADU_SPI, imageioJ2KImageReaderName, "JPEG 2000"); if(!succeeded) if (LOGGER.isLoggable(Level.WARNING)) LOGGER.warning("Unable to set ordering between jp2 readers spi-"+GDAL_JP2KAKADU_SPI+":"+imageioJ2KImageReaderName); } catch (ClassNotFoundException e) { if (LOGGER.isLoggable(Level.WARNING)) LOGGER.log(Level.WARNING, "Unable to load specific JPEG2000 reader spi",e); } } private static void replaceMRSID() { try{ //check if our mrsidJP2 plugin is in the path Class.forName(GDAL_JP2MrSID_SPI ); // imageio tiff reader final String imageioJ2KImageReaderCodecName=J2KImageReaderCodecLibSpi.class.getName(); if(PackageUtil.isCodecLibAvailable()){ boolean succeeded=ImageIOUtilities.replaceProvider(ImageReaderSpi.class, GDAL_JP2MrSID_SPI , imageioJ2KImageReaderCodecName, "JPEG 2000"); if(!succeeded) if (LOGGER.isLoggable(Level.WARNING)) LOGGER.warning("Unable to set ordering between jp2 readers spi-"+GDAL_JP2MrSID_SPI +":"+imageioJ2KImageReaderCodecName); } // imageio mrsidJP2 reader final String imageioJ2KImageReaderName=J2KImageReaderSpi.class.getName(); final boolean succeeded=ImageIOUtilities.replaceProvider(ImageReaderSpi.class, GDAL_JP2MrSID_SPI , imageioJ2KImageReaderName, "JPEG 2000"); if(!succeeded) if (LOGGER.isLoggable(Level.WARNING)) LOGGER.warning("Unable to set ordering between jp2 readers spi-"+GDAL_JP2MrSID_SPI +":"+imageioJ2KImageReaderName); } catch (ClassNotFoundException e) { if (LOGGER.isLoggable(Level.WARNING)) LOGGER.log(Level.WARNING, "Unable to load specific JPEG2000 reader spi",e); } } private static boolean hasJP2GDALMRSID() { try{ @SuppressWarnings("unused") Class<?> cl = Class.forName(GDAL_JP2MrSID_SPI); Class<?> cGdal = Class.forName(GDAL_SPI); Object jp2MrSid = cl.newInstance(); final Method method = cGdal.getDeclaredMethod("isAvailable", (Class[])null); if (method != null){ Boolean isAvailable = (Boolean) method.invoke(jp2MrSid, null); return isAvailable.booleanValue(); } } catch (ClassNotFoundException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 MrSID Reader SPI", e); } catch (SecurityException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 MrSID Reader SPI", e); } catch (NoSuchMethodException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 MrSID Reader SPI", e); } catch (IllegalArgumentException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 MrSID Reader SPI", e); } catch (IllegalAccessException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 MrSID Reader SPI", e); } catch (InvocationTargetException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 MrSID Reader SPI", e); } catch (InstantiationException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 MrSID Reader SPI", e); } return false; } private static void replaceECW() { try{ //check if our ecwJP2 plugin is in the path Class.forName(GDAL_JP2ECW_SPI); // imageio ecwJP2 reader final String imageioJ2KImageReaderCodecName=J2KImageReaderCodecLibSpi.class.getName(); if(PackageUtil.isCodecLibAvailable()){ boolean succeeded=ImageIOUtilities.replaceProvider(ImageReaderSpi.class, GDAL_JP2ECW_SPI, imageioJ2KImageReaderCodecName, "JPEG 2000"); if(!succeeded) if (LOGGER.isLoggable(Level.WARNING)) LOGGER.warning("Unable to set ordering between jp2 readers spi-"+GDAL_JP2ECW_SPI+":"+imageioJ2KImageReaderCodecName); } // imageio ecwJP2 reader final String imageioJ2KImageReaderName=J2KImageReaderSpi.class.getName(); final boolean succeeded=ImageIOUtilities.replaceProvider(ImageReaderSpi.class, GDAL_JP2ECW_SPI, imageioJ2KImageReaderName, "JPEG 2000"); if(!succeeded) if (LOGGER.isLoggable(Level.WARNING)) LOGGER.warning("Unable to set ordering between jp2 readers spi-"+GDAL_JP2ECW_SPI+":"+imageioJ2KImageReaderName); } catch (ClassNotFoundException e) { if (LOGGER.isLoggable(Level.WARNING)) LOGGER.log(Level.WARNING, "Unable to load specific JPEG2000 reader spi",e); } } private static boolean hasJP2GDALECW() { try{ @SuppressWarnings("unused") Class<?> cl = Class.forName(GDAL_JP2ECW_SPI); Class<?> cGdal = Class.forName(GDAL_SPI); Object jp2ecwSPI = cl.newInstance(); final Method method = cGdal.getDeclaredMethod("isAvailable", (Class[])null); if (method != null){ Boolean isAvailable = (Boolean) method.invoke(jp2ecwSPI, null); return isAvailable.booleanValue(); } } catch (ClassNotFoundException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 ECW Reader SPI", e); } catch (SecurityException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 ECW Reader SPI", e); } catch (NoSuchMethodException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 ECW Reader SPI", e); } catch (IllegalArgumentException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 ECW Reader SPI", e); } catch (IllegalAccessException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 ECW Reader SPI", e); } catch (InvocationTargetException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 ECW Reader SPI", e); } catch (InstantiationException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, "Unable to load GDAL JP2 ECW Reader SPI", e); } return false; } /** * @see GridFormatFactorySpi#createFormat(). */ public AbstractGridFormat createFormat() { return new ImageMosaicFormat(); } /** * Returns the implementation hints. The default implementation returns an * empty map. * * @return An empty map. */ public Map<RenderingHints.Key, ?> getImplementationHints() { return Collections.emptyMap(); } }