/* * 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 { private static final String GDAL_JP2ECW_SPI = "it.geosolutions.imageio.plugins.jp2ecw.JP2GDALEcwImageReaderSpi"; private static final String GDAL_JP2KAKADU_SPI = "it.geosolutions.imageio.plugins.jp2kakadu.JP2GDALKakaduImageReaderSpi"; private static final String GDAL_JP2MrSID_SPI = "it.geosolutions.imageio.plugins.jp2mrsid.JP2GDALMrSidImageReaderSpi"; private static final String GDAL_SPI = "it.geosolutions.imageio.gdalframework.GDALImageReaderSpi"; private static final String KAKADU_SPI = "it.geosolutions.imageio.plugins.jp2k.JP2KKakaduImageReaderSpi"; /** Logger. */ private final static Logger LOGGER = org.geotools.util.logging.Logging .getLogger(ImageMosaicFormatFactory.class); static { replaceTIFF(); if (hasJP2Kakadu()) { replaceJP2Kakadu(); } else { if (hasJP2GDALECW()) { replaceECW(); } if (hasJP2GDALMRSID()) { replaceMRSID(); } if (hasJP2GDALKakadu()) { replaceGDALKakadu(); } } } private static boolean hasJP2GDALECW() { try { 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) { return (Boolean) method.invoke(jp2ecwSPI, (Object[]) null); } } 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; } private static boolean hasJP2GDALKakadu() { try { 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) { return (Boolean) method.invoke(jp2Kak, (Object[]) null); } } 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 boolean hasJP2GDALMRSID() { try { 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) { return (Boolean) method.invoke(jp2MrSid, (Object[]) null); } } 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 boolean hasJP2Kakadu() { try { 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) { return (Boolean) method.invoke(null, (Object[]) null); } } 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 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 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 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 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 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); } } /** * @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(); } /** * 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; } }