All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nom.tam.fits.header.Bitpix Maven / Gradle / Ivy

Go to download

Java library for reading and writing FITS files. FITS, the Flexible Image Transport System, is the format commonly used in the archiving and transport of astronomical data.

There is a newer version: 1.21.0
Show newest version
package nom.tam.fits.header;

import java.util.logging.Logger;

/*
 * #%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 nom.tam.fits.FitsException;
import nom.tam.fits.FitsFactory;
import nom.tam.fits.Header;
import nom.tam.fits.HeaderCard;
import nom.tam.util.type.ElementType;

/**
 * Standard BITPIX values and associated functions. Since the FITS BITPIX keyword has only a handful of legal values, an
 * enum provides ideal type-safe representation. It also allows to interface the value for the type of data
 * it represents in a natural way.
 *
 * @author Attila Kovacs
 *
 * @since  1.16
 */
public enum Bitpix {
    /** For FITS data stored as bytes */
    BYTE(Byte.TYPE, ElementType.BYTE, "bytes"),

    /** For FITS data stored as 16-bit integers */
    SHORT(Short.TYPE, ElementType.SHORT, "16-bit integers"),

    /** For FITS data stored as 32-bit integers */
    INTEGER(Integer.TYPE, ElementType.INT, "32-bit integers"),

    /** For FITS data stored as 64-bit integers */
    LONG(Long.TYPE, ElementType.LONG, "64-bit integers"),

    /** For FITS data stored as 32-bit single-precision floating point values */
    FLOAT(Float.TYPE, ElementType.FLOAT, "32-bit floating point"),

    /** For FITS data stored as 64-bit double-precision floating point values */
    DOUBLE(Double.TYPE, ElementType.DOUBLE, "64-bit floating point");

    private static final Logger LOG = Logger.getLogger("nom.tam.fits.HeaderCardParser");

    private static final int BITS_TO_BYTES_SHIFT = 3;

    /** BITPIX value for byte type data */
    public static final int VALUE_FOR_BYTE = 8;

    /** BITPIX value for short type data */
    public static final int VALUE_FOR_SHORT = 16;

    /** BITPIX value for int type data */
    public static final int VALUE_FOR_INT = 32;

    /** BITPIX value for long type data */
    public static final int VALUE_FOR_LONG = 64;

    /** BITPIX value for float type data */
    public static final int VALUE_FOR_FLOAT = -32;

    /** BITPIX value for double type data */
    public static final int VALUE_FOR_DOUBLE = -64;

    /** the number subclass represented this BITPIX instance */
    private Class numberType;

    /** the library's element type */
    private ElementType elementType;

    /** a concise description of the data type represented */
    private String description;

    /**
     * Constructor for a standard BITPIX instance.
     *
     * @param numberType  the Number subclass
     * @param elementType the class of data element
     * @param desc        a concise description of the data type
     */
    Bitpix(Class numberType, ElementType elementType, String desc) {
        this.numberType = numberType;
        this.elementType = elementType;
        description = desc;
    }

    /**
     * Returns the FITS element type corresponding to this bitpix value
     * 
     * @return the FITS element type that corresponds to this bitpix value.
     */
    public final ElementType getElementType() {
        return elementType;
    }

    /**
     * Returns the sublass of {@link Number} corresponding for this BITPIX value.
     *
     * @return the number class for this BITPIX instance.
     *
     * @see    #getPrimitiveType()
     * @see    Bitpix#forNumberType(Class)
     */
    public final Class getNumberType() {
        return numberType;
    }

    /**
     * Returns the primitive built-in Java number type corresponding for this BITPIX value.
     *
     * @return the primitive class for this BITPIX instance, such as int.class, or
     *             double.class.
     *
     * @see    #getNumberType()
     * @see    Bitpix#forPrimitiveType(Class)
     */
    public final Class getPrimitiveType() {
        return elementType.primitiveClass();
    }

    /**
     * Returns the FITS standard BITPIX header value for this instance.
     *
     * @return the standard FITS BITPIX value, such as 8, 16, 32, 64, -32, or -64.
     *
     * @see    Bitpix#forValue(int)
     * @see    #getHeaderCard()
     */
    public final int getHeaderValue() {
        return elementType.bitPix();
    }

    /**
     * Returns the Java letter ID for this BITPIX instance, such as the letter ID used in the Java array representation
     * of that class. For example, an int[] array has class I[, so the letter ID is
     * I.
     *
     * @return The Java letter ID for arrays corresponding to this BITPIX instance.
     *
     * @see    Bitpix#forArrayID(char)
     */
    public final char getArrayID() {
        return elementType.type();
    }

    /**
     * Returns a concise description of the data type represented by this BITPIX instance.
     *
     * @return a brief description of the corresponding data type.
     */
    public final String getDescription() {
        return description;
    }

    /**
     * Returns the size of a data element, in bytes, for this BITPIX instance
     *
     * @return the size of a data element in bytes.
     */
    public final int byteSize() {
        return Math.abs(getHeaderValue()) >>> BITS_TO_BYTES_SHIFT;
    }

    /**
     * Returns the standard FITS header card for this BITPIX instance.
     *
     * @return the standard FITS header card with the BITPIX keyword and the corresponding value for this instance.
     *
     * @see    #getHeaderValue()
     */
    public final HeaderCard getHeaderCard() {
        return HeaderCard.create(Standard.BITPIX, getHeaderValue());
    }

    /**
     * Returns the standard BITPIX object for a primitive type.
     *
     * @param  dataType      the primitive class, such as int.class.
     *
     * @return               the standard BITPIX associated to the number type
     *
     * @throws FitsException if the class is not a primitive class, or if its not one that has a corresponding BITPIX
     *                           value (e.g. 
     *                          boolean.class).
     *
     * @see                  Bitpix#forNumberType(Class)
     * @see                  #getPrimitiveType()
     */
    public static Bitpix forPrimitiveType(Class dataType) throws FitsException {
        if (dataType == byte.class) {
            return BYTE;
        }
        if (dataType == short.class) {
            return SHORT;
        }
        if (dataType == int.class) {
            return INTEGER;
        }
        if (dataType == long.class) {
            return LONG;
        }
        if (dataType == float.class) {
            return FLOAT;
        }
        if (dataType == double.class) {
            return DOUBLE;
        }
        if (Object.class.isAssignableFrom(dataType)) {
            throw new FitsException("No BITPIX for type: " + dataType + " (expected primitive type)");
        }

        throw new FitsException("No BITPIX for primitive type: " + dataType);
    }

    /**
     * Returns the standard BITPIX object for a number type.
     *
     * @param  dataType      the class of number, such as {@link Integer#TYPE}.
     *
     * @return               the standard BITPIX associated to the number type
     *
     * @throws FitsException if there is no standard BITPIX value corresponding to the number type (e.g.
     *                           {@link java.math.BigDecimal}).
     *
     * @see                  Bitpix#forPrimitiveType(Class)
     * @see                  #getNumberType()
     */
    public static Bitpix forNumberType(Class dataType) throws FitsException {
        if (Byte.class.isAssignableFrom(dataType)) {
            return BYTE;
        }
        if (Short.class.isAssignableFrom(dataType)) {
            return SHORT;
        }
        if (Integer.class.isAssignableFrom(dataType)) {
            return INTEGER;
        }
        if (Long.class.isAssignableFrom(dataType)) {
            return LONG;
        }
        if (Float.class.isAssignableFrom(dataType)) {
            return FLOAT;
        }
        if (Double.class.isAssignableFrom(dataType)) {
            return DOUBLE;
        }
        throw new FitsException("No BITPIX for Number type " + dataType);
    }

    /**
     * Returns the standard BITPIX object based on the value assigned to the BITPIX keyword in the header
     *
     * @param  h             the FITS header
     *
     * @return               the standard BITPIX enum that matches the header description, or is inferred from an
     *                           invalid header description (provided {@link FitsFactory#setAllowHeaderRepairs(boolean)}
     *                           is enabled).
     *
     * @throws FitsException if the header does not contain a BITPIX value or it is invalid and cannot or will not be
     *                           repaired.
     *
     * @see                  Bitpix#fromHeader(Header, boolean)
     * @see                  Bitpix#forValue(int)
     * @see                  FitsFactory#setAllowHeaderRepairs(boolean)
     */
    public static Bitpix fromHeader(Header h) throws FitsException {
        return forValue(h.getIntValue(Standard.BITPIX, 0));
    }

    /**
     * Returns the standard BITPIX object based on the value assigned to the BITPIX keyword in the header
     *
     * @param  h             the FITS header
     * @param  allowRepair   if we can try repair non-standard (invalid) BITPIX values.
     *
     * @return               the standard BITPIX enum that matches the header description, or is inferred from an
     *                           invalid header description.
     *
     * @throws FitsException if the header does not contain a BITPIX value or it is invalid and cannot or will not be
     *                           repaired.
     *
     * @see                  Bitpix#fromHeader(Header)
     * @see                  Bitpix#forValue(int, boolean)
     */
    public static Bitpix fromHeader(Header h, boolean allowRepair) throws FitsException {
        return forValue(h.getIntValue(Standard.BITPIX, 0), allowRepair);
    }

    /**
     * Returns the standard BITPIX enum value for a given integer value, such as 8, 16, 32, 64, -32, or -64. If the
     * value is not one of the standard values, then depending on whether header repairs are enabled either an exception
     * is thrown, or else the value the value is 'repaired' and a loh entry is made to the logger of {@link Header}.
     *
     * @param  ival          The integer value of BITPIX in the FITS header.
     *
     * @return               The standard value as a Java object.
     *
     * @throws FitsException if the value was invalid or irreparable.
     *
     * @see                  Bitpix#forValue(int, boolean)
     * @see                  FitsFactory#setAllowHeaderRepairs(boolean)
     * @see                  #getHeaderValue()
     */
    public static Bitpix forValue(int ival) throws FitsException {
        try {
            return forValue(ival, FitsFactory.isAllowHeaderRepairs());
        } catch (FitsException e) {
            throw new FitsException(e.getMessage() + "\n\n" + " --> Try FitsFactory.setAllowHeaderRepairs(true).\n");
        }
    }

    /**
     * Returns the standard BITPIX enum value for a given integer value, such as 8, 16, 32, 64, -32, or -64. If the
     * value is not one of the standard values, then depending on whether repairs are enabled either an exception is
     * thrown, or else the value the value is 'repaired' and a loh entry is made to the logger of {@link Header}.
     *
     * @param  ival          The integer value of BITPIX in the FITS header.
     * @param  allowRepair   Whether we can fix up invalid values to make them valid.
     *
     * @return               The standard value as a Java object.
     *
     * @throws FitsException if the value was invalid or irreparable.
     *
     * @see                  Bitpix#forValue(int)
     * @see                  #getHeaderValue()
     */
    public static Bitpix forValue(int ival, boolean allowRepair) throws FitsException {

        if (ival == 0) {
            throw new FitsException("Invalid BITPIX value:" + ival);
        }

        // Normally BITPIX must be one one of the supported values. Unfortunately, some
        // commercial cameras fill illegal values, such as 20.
        // We can 'repair' them by rounding up to the next valid value, so 20 repairs to 32, and
        // maxing at +/- 64, so for example -80 repairs to -64.
        if (allowRepair) {
            int fixed = 0;

            if (ival < 0) {
                fixed = ival < VALUE_FOR_FLOAT ? VALUE_FOR_DOUBLE : VALUE_FOR_FLOAT;
            } else if (ival < VALUE_FOR_BYTE) {
                fixed = VALUE_FOR_BYTE;
            } else if (ival > VALUE_FOR_LONG) {
                fixed = VALUE_FOR_LONG;
            } else if (ival > Integer.highestOneBit(ival)) {
                fixed = (Integer.highestOneBit(ival) << 1);
            }

            if (fixed != 0) {
                LOG.warning("Repaired invalid BITPIX value:" + ival + " --> " + fixed);
                ival = fixed;
            }
        }

        switch (ival) {
        case VALUE_FOR_BYTE:
            return BYTE;
        case VALUE_FOR_SHORT:
            return SHORT;
        case VALUE_FOR_INT:
            return INTEGER;
        case VALUE_FOR_LONG:
            return LONG;
        case VALUE_FOR_FLOAT:
            return FLOAT;
        case VALUE_FOR_DOUBLE:
            return DOUBLE;
        default:
            throw new FitsException("Invalid BITPIX value:" + ival);
        }
    }

    /**
     * Returns the standard BITPIX object for the given Java array ID. The array ID is the same letter code as Java uses
     * for identifying ptrimitive array types. For example a Java array of long[][] has a class name of
     * J[[, so so the array ID for long arrays is J.
     *
     * @param  id            The Java letter ID for arrays of the underlying primitive type. E.g. J for
     *                           long.
     *
     * @return               The standard BITPIX enum corresponding to the data type.
     *
     * @throws FitsException if the data type is unknown or does not have a BITPIX ewquivalent.
     */
    public static Bitpix forArrayID(char id) throws FitsException {
        switch (id) {
        case 'B':
            return BYTE;
        case 'S':
            return SHORT;
        case 'I':
            return INTEGER;
        case 'J':
            return LONG;
        case 'F':
            return FLOAT;
        case 'D':
            return DOUBLE;
        default:
            throw new FitsException("Invalid BITPIX data ID: '" + id + "'");
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy