/*
* ImageI/O-Ext - OpenSource Java Image translation Library
* http://www.geo-solutions.it/
* http://java.net/projects/imageio-ext/
* (C) 2007 - 2009, GeoSolutions
*
* 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;
* either version 3 of the License, or (at your option) any later version.
*
* 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 it.geosolutions.imageio.plugins.jp2k;
import it.geosolutions.imageio.stream.input.FileImageInputStreamExt;
import it.geosolutions.imageio.utilities.Utilities;
import it.geosolutions.util.KakaduUtilities;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import javax.imageio.ImageReader;
import javax.imageio.spi.IIORegistry;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.spi.ImageReaderWriterSpi;
import javax.imageio.spi.ServiceRegistry;
import kdu_jni.Jp2_family_src;
import kdu_jni.Jpx_source;
import kdu_jni.KduException;
import kdu_jni.Kdu_simple_file_source;
/**
* Service provider interface for the JPEG2000SimpleBox
*
* @author Simone Giannecchini, GeoSolutions.
* @author Daniele Romagnoli, GeoSolutions.
*
*/
public class JP2KKakaduImageReaderSpi extends ImageReaderSpi {
static {
KakaduUtilities.loadKakadu();
}
protected boolean registered = false;
static final String[] suffixes = { "jp2", "jp2k", "j2k", "j2c" };
static final String[] formatNames = { "JP2KSimpleBox", "jpeg2000", "jpeg 2000", "JPEG 2000", "JPEG2000" };
static final String[] MIMETypes = { "image/jp2", "image/jp2k", "image/j2k", "image/j2c" };
static final String version = "1.0";
static final String readerCN = "it.geosolutions.imageio.plugins.jp2k.JP2KKakaduImageReader";
static final String vendorName = "GeoSolutions";
// writerSpiNames
static final String[] wSN = { null };
// StreamMetadataFormatNames and StreamMetadataFormatClassNames
static final boolean supportsStandardStreamMetadataFormat = false;
static final String nativeStreamMetadataFormatName = null;
static final String nativeStreamMetadataFormatClassName = null;
static final String[] extraStreamMetadataFormatNames = { null };
static final String[] extraStreamMetadataFormatClassNames = { null };
// ImageMetadataFormatNames and ImageMetadataFormatClassNames
static final boolean supportsStandardImageMetadataFormat = false;
static final String nativeImageMetadataFormatName = null;
static final String nativeImageMetadataFormatClassName = null;
static final String[] extraImageMetadataFormatNames = { null };
static final String[] extraImageMetadataFormatClassNames = { null };
public JP2KKakaduImageReaderSpi() {
super(
vendorName,
version,
formatNames,
suffixes,
MIMETypes,
readerCN, // readerClassName
new Class[] { File.class, FileImageInputStreamExt.class,
URL.class },
wSN, // writer Spi Names
supportsStandardStreamMetadataFormat,
nativeStreamMetadataFormatName,
nativeStreamMetadataFormatClassName,
extraStreamMetadataFormatNames,
extraStreamMetadataFormatClassNames,
supportsStandardImageMetadataFormat,
nativeImageMetadataFormatName,
nativeImageMetadataFormatClassName,
extraImageMetadataFormatNames,
extraImageMetadataFormatClassNames);
}
/**
* This method checks if the provided input can be decoded from this SPI
*/
public boolean canDecodeInput(Object input) throws IOException {
boolean isDecodable = true;
File source = null;
// Retrieving the File source
if (input instanceof File) {
source = (File) input;
} else if (input instanceof FileImageInputStreamExt) {
source = ((FileImageInputStreamExt) input).getFile();
} else if (input instanceof URL) {
final URL tempURL = (URL) input;
if (tempURL.getProtocol().equalsIgnoreCase("file")) {
source = Utilities.urlToFile(tempURL);
}
} else
return false;
Jp2_family_src familySource = new Jp2_family_src();
Jpx_source wrappedSource = new Jpx_source();
Kdu_simple_file_source rawSource = null;
try {
String fileName = source.getAbsolutePath();
familySource.Open(fileName);
int success = wrappedSource.Open(familySource, true);
// success is 0 if there isn't sufficient information from the
// source object to complete the opening operation.
// success is -1 if the source is not compatible with the JPX or JP2
// specifications
if (success < 0) { // Must open as a raw file
familySource.Close();
wrappedSource.Close();
rawSource = new Kdu_simple_file_source(fileName);
if (rawSource != null){
if (fileName != null){
FileInputStream fis = new FileInputStream (new File(fileName));
byte[] jp2SocMarker = new byte[2];
fis.read(jp2SocMarker);
if (jp2SocMarker[0] == (byte)0xFF && jp2SocMarker[1] == (byte)0x4F)
isDecodable = true;
else
isDecodable = false;
fis.close();
}
}
else
isDecodable = false;
}
} catch (KduException e) {
throw new RuntimeException(
"Error caused by a Kakadu exception during creation of key objects! ",
e);
}
// Dispose
wrappedSource.Native_destroy();
familySource.Native_destroy();
if (rawSource != null)
rawSource.Native_destroy();
return isDecodable;
}
/**
* Returns an instance of the {@link JP2KKakaduImageReader}
*
* @see javax.imageio.spi.ImageReaderSpi#createReaderInstance(java.lang.Object)
*/
public ImageReader createReaderInstance(Object source) throws IOException {
return new JP2KKakaduImageReader(this);
}
/**
* @see javax.imageio.spi.IIOServiceProvider#getDescription(java.util.Locale)
*/
public String getDescription(Locale locale) {
return new StringBuffer("JP2K Image Reader, version ").append(version)
.toString();
}
/**
* Upon registration, this method ensures that this SPI is listed at the top
* of the ImageReaderSpi items, so that it will be invoked before the
* default ImageReaderSpi
*
* @param registry
* ServiceRegistry where this object has been registered.
* @param category
* a Class object indicating the registry category under
* which this object has been registered.
*/
@SuppressWarnings("unchecked")
public synchronized void onRegistration(ServiceRegistry registry, Class category) {
super.onRegistration(registry, category);
if (registered) {
return;
}
registered = true;
if (!KakaduUtilities.isKakaduAvailable()) {
final IIORegistry iioRegistry = (IIORegistry) registry;
final Class<ImageReaderSpi> spiClass = ImageReaderSpi.class;
final Iterator<ImageReaderSpi> iter = iioRegistry.getServiceProviders(spiClass,true);
while (iter.hasNext()) {
final ImageReaderSpi provider = (ImageReaderSpi) iter.next();
if (provider instanceof JP2KKakaduImageReaderSpi) {
registry.deregisterServiceProvider(provider);
}
}
return;
}
final List<ImageReaderWriterSpi> readers = KakaduUtilities.getJDKImageReaderWriterSPI(registry,"jpeg2000", true);
for (ImageReaderWriterSpi elem:readers) {
if (elem instanceof ImageReaderSpi){
final ImageReaderSpi spi = (ImageReaderSpi) elem;;
if (spi == this)
continue;
registry.deregisterServiceProvider(spi);
registry.setOrdering(category, this, spi);
}
}
}
}