/**
* This program 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 program 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 General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @author Nicola Lagomarsini, GeoSolutions S.A.S., Copyright 2014
*
*/
package org.geowebcache.io;
import it.geosolutions.imageio.stream.input.FileImageInputStreamExtImpl;
import it.geosolutions.imageio.stream.input.ImageInputStreamAdapter;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageReader;
import javax.imageio.spi.IIORegistry;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;
import org.apache.log4j.Logger;
/**
* Class implementing the ImageDecoder interface, the user should only create a new bean for instantiating a new decoder object.
*/
public class ImageDecoderImpl implements ImageDecoder{
/**
* Logger used
*/
private static final Logger LOGGER = Logger.getLogger(ImageEncoderImpl.class);
/**
* Default string used for exceptions
*/
public static final String OPERATION_NOT_SUPPORTED = "Operation not supported";
/**Boolean indicating is aggressive inputstream is supported*/
private final boolean isAggressiveInputStreamSupported;
/**Supported Mimetypes*/
private final List<String> supportedMimeTypes;
/**ImageReaderSpi object used*/
private ImageReaderSpi spi;
/**
* Creates a new Instance of ImageEncoder supporting or not OutputStream optimization, with the defined MimeTypes and Spi classes.
*
* @param aggressiveOutputStreamOptimization
* @param supportedMimeTypes
* @param writerSpi
*/
public ImageDecoderImpl(boolean aggressiveInputStreamOptimization,
List<String> supportedMimeTypes, List<String> readerSpi, ImageIOInitializer initializer) {
this.isAggressiveInputStreamSupported = aggressiveInputStreamOptimization;
this.supportedMimeTypes = new ArrayList<String>(supportedMimeTypes);
// Get the IIORegistry if needed
IIORegistry theRegistry = initializer.getRegistry();
// Checks for each Spi class if it is present and then it is added to the list.
for (String spi : readerSpi) {
try {
Class<?> clazz = Class.forName(spi);
ImageReaderSpi reader = (ImageReaderSpi) theRegistry
.getServiceProviderByClass(clazz);
if (reader != null) {
this.spi=reader;
break;
}
} catch (ClassNotFoundException e) {
LOGGER.error(e.getMessage(), e);
}
}
}
/**
* Encodes the selected image with the defined output object. The user can set the aggressive outputStream if supported.
*
* @param image Image to write.
* @param source Destination object where the image is written.
* @param aggressiveOutputStreamOptimization Parameter used if aggressive outputStream optimization must be used.
* @throws IOException
*/
public BufferedImage decode(Object source,
boolean aggressiveInputStreamOptimization, Map<String,Object> map) throws Exception{
if (!isAggressiveInputStreamSupported() && aggressiveInputStreamOptimization) {
throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED);
}
// Selection of the first priority writerSpi
ImageReaderSpi newSpi = getReaderSpi();
if(newSpi!=null){
// Creation of the associated Writer
ImageReader reader = null;
ImageInputStream stream = null;
try {
reader = newSpi.createReaderInstance();
if (source instanceof FileResource) {
// file
stream= new FileImageInputStreamExtImpl(((FileResource)source).getFile());
// Image reading
reader.setInput(stream);
return reader.read(0);
} else {
// create a stream and move on
source=((Resource)source).getInputStream();
}
// Check if the input object is an InputStream
if (source instanceof InputStream) {
// Use of the ImageInputStreamAdapter
if (isAggressiveInputStreamSupported()) {
stream = new ImageInputStreamAdapter((InputStream) source);
} else {
stream = new MemoryCacheImageInputStream((InputStream) source);
}
// Image reading
reader.setInput(stream);
return reader.read(0);
}else{
throw new IllegalArgumentException("Wrong input object");
}
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
throw e;
} finally {
// reader disposal
if (reader != null) {
reader.dispose();
}
// Stream closure
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
}
stream = null;
}
}
}
return null;
}
/**
* Returns the ImageSpiReader associated to
* @return
*/
ImageReaderSpi getReaderSpi() {
return spi;
}
/**
* Returns all the supported MimeTypes
*
* @return supportedMimeTypes List of all the supported Mime Types
*/
public List<String> getSupportedMimeTypes() {
return supportedMimeTypes;
}
/**
* Indicates if optimization on InputStream can be used
*
* @return isAggressiveInputStreamSupported Boolean indicating if the selected decoder supports an aggressive input stream optimization
*/
public boolean isAggressiveInputStreamSupported() {
return isAggressiveInputStreamSupported;
}
}