Source code for kalasiris.specialpixels

# -*- coding: utf-8 -*-

"""Constants for Isis Special Pixels.

The constants are provided as SpecialPixel :func:collection.namedtuple:
objects, and have the following keys: Min, Null, Lrs, Lis, His,
Hrs, and Max.

Null
    A null pixel indicates no data was collected at the particular
    location.

Lis
    A low instrument saturation pixel occurred meaning the
    instrument readout was at its lowest possible value.

His
    A high instrument saturation pixel occurred meaning the
    instrument readout was at its highest possible value.

Lrs
    A low representation saturation pixel occurred meaning a
    program computed a new pixel value at this location that
    was lower than native bit-type for the file (e.g., less
    than zero for an 8-bit file).

Hrs:
    A high representation saturation pixel occurred meaning a
    program computed a new pixel value at this location that
    was greater than native bit-type for the file (e.g., greater
    than 255 for an 8-bit file).

The above definitions come from the `Logical Cube Format Guide
<https://isis.astrogeology.usgs.gov/documents/LogicalCubeFormatGuide/LogicalCubeFormatGuide.html>`_
and the numerical values come from the ISIS `SpecialPixel.h
<https://github.com/USGS-Astrogeology/ISIS3/blob/dev/isis/src/base/objs/SpecialPixel/SpecialPixel.h>`_ file.

In order to be able to know whether value should result in a
*Lrs* or *Hrs* value, we must also know:

Min
    The minimum valid value for a pixel.

Max
    The maximum valid value for a pixel.
"""  # noqa

# Copyright 2015, William Trevor Olson
# Copyright 2020, Ross A. Beyer (rbeyer@seti.org)
#
# Reuse is permitted under the terms of the license.
# The AUTHORS file and the LICENSE file are at the
# top level of this library.

import collections
import struct
import sys


SpecialPixels = collections.namedtuple(
    "SpecialPixels", ["Min", "Null", "Lrs", "Lis", "His", "Hrs", "Max"]
)

# 1-byte special pixel values from SpecialPixel.h
UnsignedByte = SpecialPixels(
    Min=1, Null=0, Lrs=0, Lis=0, His=255, Hrs=255, Max=254
)

# 2-byte unsigned special pixel values from SpecialPixel.h
UnsignedWord = SpecialPixels(
    Min=3, Null=0, Lrs=1, Lis=2, His=65534, Hrs=65535, Max=65522
)

# 2-byte signed special pixel values from SpecialPixel.h
SignedWord = SpecialPixels(
    Min=-32752,
    Null=-32768,
    Lrs=-32767,
    Lis=-32766,
    His=-32765,
    Hrs=-32764,
    Max=32767,
)

# 4-byte unsigned special pixel values from SpecialPixel.h
# This deals with unsigned long int values.  Not sure why there
# is so much space between 'Max' and the 'His' and 'Hrs' values, but
# that's what's in SpecialPixel.h.
UnsignedInteger = SpecialPixels(
    Min=3, Null=0, Lrs=1, Lis=2, His=4294967294, Hrs=4294967295, Max=4294967282
)

# This was in the original pysis, but I don't see it in SpecialPixel.h?
# The 'Max' value indicates that it is like a long int, but the 'Min'
# and other negative values are far from the possible representation
# minimum of a long int, so not sure what's going on here.
SignedInteger = SpecialPixels(
    Min=-8388614,
    Null=-8388613,
    Lrs=-8388612,
    Lis=-8388611,
    His=-8388610,
    Hrs=-8388609,
    Max=2147483647,
)

# 4-byte special pixel values for IEEE floating point from SpecialPixel.h
Real = SpecialPixels(
    Min=struct.unpack(">f", bytes.fromhex("FF7FFFFA"))[0],
    Null=struct.unpack(">f", bytes.fromhex("FF7FFFFB"))[0],
    Lrs=struct.unpack(">f", bytes.fromhex("FF7FFFFC"))[0],
    Lis=struct.unpack(">f", bytes.fromhex("FF7FFFFD"))[0],
    His=struct.unpack(">f", bytes.fromhex("FF7FFFFE"))[0],
    Hrs=struct.unpack(">f", bytes.fromhex("FF7FFFFF"))[0],
    Max=sys.float_info.max,
)

# 8-byte special pixel values for IEEE floating point from SpecialPixel.h
Double = SpecialPixels(
    Min=struct.unpack(">d", bytes.fromhex("FFEFFFFF FFFFFFFA"))[0],
    Null=struct.unpack(">d", bytes.fromhex("FFEFFFFF FFFFFFFB"))[0],
    Lrs=struct.unpack(">d", bytes.fromhex("FFEFFFFF FFFFFFFC"))[0],
    Lis=struct.unpack(">d", bytes.fromhex("FFEFFFFF FFFFFFFD"))[0],
    His=struct.unpack(">d", bytes.fromhex("FFEFFFFF FFFFFFFE"))[0],
    Hrs=struct.unpack(">d", bytes.fromhex("FFEFFFFF FFFFFFFF"))[0],
    Max=sys.float_info.max,
)