
nom.tam.fits.compression.provider.CompressorProvider Maven / Gradle / Ivy
package nom.tam.fits.compression.provider;
/*
* #%L
* nom.tam FITS library
* %%
* Copyright (C) 1996 - 2024 nom-tam-fits
* %%
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
* #L%
*/
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.ServiceLoader;
import java.util.logging.Level;
import java.util.logging.Logger;
import nom.tam.fits.compression.algorithm.api.ICompressOption;
import nom.tam.fits.compression.algorithm.api.ICompressor;
import nom.tam.fits.compression.algorithm.api.ICompressorControl;
import nom.tam.fits.compression.algorithm.gzip.GZipCompressor.ByteGZipCompressor;
import nom.tam.fits.compression.algorithm.gzip.GZipCompressor.DoubleGZipCompressor;
import nom.tam.fits.compression.algorithm.gzip.GZipCompressor.FloatGZipCompressor;
import nom.tam.fits.compression.algorithm.gzip.GZipCompressor.IntGZipCompressor;
import nom.tam.fits.compression.algorithm.gzip.GZipCompressor.LongGZipCompressor;
import nom.tam.fits.compression.algorithm.gzip.GZipCompressor.ShortGZipCompressor;
import nom.tam.fits.compression.algorithm.gzip2.GZip2Compressor.ByteGZip2Compressor;
import nom.tam.fits.compression.algorithm.gzip2.GZip2Compressor.DoubleGZip2Compressor;
import nom.tam.fits.compression.algorithm.gzip2.GZip2Compressor.FloatGZip2Compressor;
import nom.tam.fits.compression.algorithm.gzip2.GZip2Compressor.IntGZip2Compressor;
import nom.tam.fits.compression.algorithm.gzip2.GZip2Compressor.LongGZip2Compressor;
import nom.tam.fits.compression.algorithm.gzip2.GZip2Compressor.ShortGZip2Compressor;
import nom.tam.fits.compression.algorithm.hcompress.HCompressor.ByteHCompressor;
import nom.tam.fits.compression.algorithm.hcompress.HCompressor.DoubleHCompressor;
import nom.tam.fits.compression.algorithm.hcompress.HCompressor.FloatHCompressor;
import nom.tam.fits.compression.algorithm.hcompress.HCompressor.IntHCompressor;
import nom.tam.fits.compression.algorithm.hcompress.HCompressor.ShortHCompressor;
import nom.tam.fits.compression.algorithm.hcompress.HCompressorQuantizeOption;
import nom.tam.fits.compression.algorithm.plio.PLIOCompress.BytePLIOCompressor;
import nom.tam.fits.compression.algorithm.plio.PLIOCompress.IntPLIOCompressor;
import nom.tam.fits.compression.algorithm.plio.PLIOCompress.ShortPLIOCompressor;
import nom.tam.fits.compression.algorithm.quant.QuantizeOption;
import nom.tam.fits.compression.algorithm.quant.QuantizeProcessor.DoubleQuantCompressor;
import nom.tam.fits.compression.algorithm.quant.QuantizeProcessor.FloatQuantCompressor;
import nom.tam.fits.compression.algorithm.rice.RiceCompressor.ByteRiceCompressor;
import nom.tam.fits.compression.algorithm.rice.RiceCompressor.DoubleRiceCompressor;
import nom.tam.fits.compression.algorithm.rice.RiceCompressor.FloatRiceCompressor;
import nom.tam.fits.compression.algorithm.rice.RiceCompressor.IntRiceCompressor;
import nom.tam.fits.compression.algorithm.rice.RiceCompressor.ShortRiceCompressor;
import nom.tam.fits.compression.algorithm.rice.RiceQuantizeCompressOption;
import nom.tam.fits.compression.algorithm.uncompressed.NoCompressCompressor.ByteNoCompressCompressor;
import nom.tam.fits.compression.algorithm.uncompressed.NoCompressCompressor.DoubleNoCompressCompressor;
import nom.tam.fits.compression.algorithm.uncompressed.NoCompressCompressor.FloatNoCompressCompressor;
import nom.tam.fits.compression.algorithm.uncompressed.NoCompressCompressor.IntNoCompressCompressor;
import nom.tam.fits.compression.algorithm.uncompressed.NoCompressCompressor.LongNoCompressCompressor;
import nom.tam.fits.compression.algorithm.uncompressed.NoCompressCompressor.ShortNoCompressCompressor;
import nom.tam.fits.compression.provider.api.ICompressorProvider;
import nom.tam.fits.compression.provider.param.api.ICompressHeaderParameter;
import nom.tam.fits.compression.provider.param.api.ICompressParameters;
import nom.tam.fits.compression.provider.param.base.CompressParameters;
import nom.tam.fits.compression.provider.param.hcompress.HCompressParameters;
import nom.tam.fits.compression.provider.param.rice.RiceCompressParameters;
/**
* (for internal use) Standard implementation of the {@code ICompressorProvider} interface.
*/
@SuppressWarnings({"javadoc", "deprecation"})
public class CompressorProvider implements ICompressorProvider {
/**
* private implementation of the tile compression provider, all is based on the option based constructor of the
* compressors.
*/
protected static class TileCompressorControl implements ICompressorControl {
private final Constructor>[] constructors;
private Class extends ICompressOption> optionClass;
private Class> quantType;
@SuppressWarnings("unchecked")
protected TileCompressorControl(Class> compressorClass) {
constructors = (Constructor>[]) compressorClass.getConstructors();
for (Constructor> c : constructors) {
if (c.getParameterTypes().length == 1) {
optionClass = (Class extends ICompressOption>) c.getParameterTypes()[0];
break;
}
}
}
/**
* Sets the floating-point type to quantize to use for this tile compressor.
*
* @param floatingPointType Floating-point primitive type to quantize. Must be either double.class
* or else float.class
.
*
* @return itself
*
* @since 1.18
*/
protected TileCompressorControl setQuantType(Class> floatingPointType) {
quantType = floatingPointType;
return this;
}
@Override
public boolean compress(Buffer in, ByteBuffer out, ICompressOption option) {
try {
return newCompressor(option).compress(in, out);
} catch (Exception e) {
LOG.log(Level.FINE, "could not compress using " + constructors[0].getName()
+ " must fallback to other compression method", e);
return false;
}
}
@Override
public void decompress(ByteBuffer in, Buffer out, ICompressOption option) {
try {
newCompressor(option).decompress(in, out);
} catch (Exception e) {
throw new IllegalStateException("could not decompress " + constructors[0].getName(), e);
}
}
@Override
public ICompressOption option() {
ICompressOption option = null;
if (optionClass != null) {
try {
option = optionClass.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new IllegalStateException("could not instantiate option class for " + constructors[0].getName(),
e);
}
}
if (option == null) {
option = NULL_OPTION;
}
if (quantType != null) {
return new QuantizeOption(option);
}
return option;
}
@SuppressWarnings({"unchecked", "rawtypes"})
private ICompressor newCompressor(ICompressOption option)
throws InstantiationException, IllegalAccessException, InvocationTargetException {
ICompressor compressor = null;
QuantizeOption quantOption = null;
if (option == NULL_OPTION) {
option = null;
} else if (option instanceof QuantizeOption) {
quantOption = (QuantizeOption) option;
option = quantOption.getCompressOption();
}
try {
for (Constructor> c : constructors) {
Class>[] parms = c.getParameterTypes();
if (option == null && parms.length == 0) {
compressor = c.newInstance();
break;
}
if (option != null && parms.length == 1) {
Class extends ICompressOption> p = (Class extends ICompressOption>) parms[0];
if (quantOption != null && p.isAssignableFrom(quantOption.getClass())) {
compressor = c.newInstance(quantOption);
quantOption = null; // Don't wrap in a quantizer below...
break;
}
if (p.isAssignableFrom(option.getClass())) {
compressor = c.newInstance(option);
break;
}
}
}
if (quantOption != null && quantType != null) {
if (quantType.equals(double.class)) {
return (ICompressor) new DoubleQuantCompressor(quantOption, (ICompressor) compressor);
}
if (quantType.equals(float.class)) {
return (ICompressor) new FloatQuantCompressor(quantOption, (ICompressor) compressor);
}
}
return compressor;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
private static final ICompressOption NULL_OPTION = new ICompressOption() {
@Override
public ICompressOption copy() {
return this;
}
@Override
public ICompressParameters getCompressionParameters() {
return NULL_PARAMETERS;
}
@Override
public boolean isLossyCompression() {
return false;
}
@Override
public void setParameters(ICompressParameters parameters) {
}
@Override
public ICompressOption setTileHeight(int value) {
return this;
}
@Override
public ICompressOption setTileWidth(int value) {
return this;
}
@Override
public T unwrap(Class clazz) {
return clazz.isAssignableFrom(this.getClass()) ? clazz.cast(this) : null;
}
};
private static final ICompressParameters NULL_PARAMETERS = new CompressParameters() {
@Override
protected ICompressHeaderParameter[] headerParameters() {
return new ICompressHeaderParameter[0];
}
@Override
public ICompressParameters copy(ICompressOption option) {
return this;
}
};
// @formatter:off
private static final Class>[][] AVAILABLE_COMPRESSORS = {//
{ByteRiceCompressor.class, RiceCompressParameters.class}, //
{ShortRiceCompressor.class, RiceCompressParameters.class}, //
{IntRiceCompressor.class, RiceCompressParameters.class}, //
{FloatRiceCompressor.class, RiceQuantizeCompressOption.class}, //
{DoubleRiceCompressor.class, RiceQuantizeCompressOption.class}, //
{BytePLIOCompressor.class}, //
{ShortPLIOCompressor.class}, //
{IntPLIOCompressor.class}, //
{ByteHCompressor.class, HCompressParameters.class}, //
{ShortHCompressor.class, HCompressParameters.class}, //
{IntHCompressor.class, HCompressParameters.class}, //
{FloatHCompressor.class, HCompressorQuantizeOption.class}, //
{DoubleHCompressor.class, HCompressorQuantizeOption.class}, //
{ByteGZip2Compressor.class}, //
{ShortGZip2Compressor.class}, //
{IntGZip2Compressor.class}, //
{FloatGZip2Compressor.class}, //
{DoubleGZip2Compressor.class}, //
{LongGZip2Compressor.class}, //
{ByteGZipCompressor.class}, //
{ShortGZipCompressor.class}, //
{IntGZipCompressor.class}, //
{LongGZipCompressor.class}, //
{FloatGZipCompressor.class}, //
{DoubleGZipCompressor.class}, //
{ByteNoCompressCompressor.class}, //
{ShortNoCompressCompressor.class}, //
{IntNoCompressCompressor.class}, //
{LongNoCompressCompressor.class}, //
{FloatNoCompressCompressor.class}, //
{DoubleNoCompressCompressor.class}};
// @formatter:on
private static final CompressorControlNameComputer NAME_COMPUTER = new CompressorControlNameComputer();
/**
* logger to log to.
*/
private static final Logger LOG = Logger.getLogger(CompressorProvider.class.getName());
public static ICompressorControl findCompressorControl(String quantAlgorithm, String compressionAlgorithm,
Class> baseType) {
for (ICompressorProvider iTileCompressorProvider : ServiceLoader.load(ICompressorProvider.class,
Thread.currentThread().getContextClassLoader())) {
ICompressorControl result = iTileCompressorProvider.createCompressorControl(quantAlgorithm,
compressionAlgorithm, baseType);
if (result != null) {
return result;
}
}
return new CompressorProvider().createCompressorControl(quantAlgorithm, compressionAlgorithm, baseType);
}
@Override
public ICompressorControl createCompressorControl(String quantAlgorithm, String compressionAlgorithm,
Class> baseType) {
Class> quantType = null;
if (quantAlgorithm != null) {
// Standard compression via 32-bit integers...
if (baseType.equals(double.class) || baseType.equals(float.class)) {
quantType = baseType;
baseType = int.class;
quantAlgorithm = null;
}
}
String className = NAME_COMPUTER.createCompressorClassName(quantAlgorithm, compressionAlgorithm, baseType);
for (Class>[] types : AVAILABLE_COMPRESSORS) {
Class> compressorClass = types[0];
if (compressorClass.getSimpleName().equals(className)) {
TileCompressorControl tc = new TileCompressorControl(compressorClass);
tc.setQuantType(quantType);
return tc;
}
}
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy