/*
 * Copyright (c) 2022 - 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 *
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * 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 OR COPYRIGHT HOLDERS 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.
 */

/**
 * @brief nvTIFF library - GPU-accelerated TIFF encoding and decoding
 *
 * @file nvtiff.h
 */

#ifndef NVTIFF_HEADER
#define NVTIFF_HEADER

#include "library_types.h"
#include "nvtiff_version.h"

#include <cuda_runtime.h>

#include <stdint.h>
#include <stdlib.h>

#define NVTIFFAPI

#if defined(__cplusplus)
extern "C" {
#endif

/**
 * @brief Maximum number of samples per pixel supported.
 */
#define MAX_NUM_SAMPLES (16)

/**********************************************************************/
/*                       Status Codes                                 */
/**********************************************************************/

/**
 * @brief Return status codes for nvTIFF APIs.
 */
typedef enum nvtiffStatus
{
    NVTIFF_STATUS_SUCCESS = 0, /**< The API call finished successfully. Note that many calls are asynchronous and some
                                  errors may only be seen after synchronization. */
    NVTIFF_STATUS_NOT_INITIALIZED   = 1, /**< The library handle was not initialized. */
    NVTIFF_STATUS_INVALID_PARAMETER = 2, /**< Wrong parameter was passed. For example, a null pointer as input data, or
                                            an invalid enum value. */
    NVTIFF_STATUS_BAD_TIFF = 3, /**< Cannot parse the TIFF stream. Likely due to a corruption that cannot be handled. */
    NVTIFF_STATUS_TIFF_NOT_SUPPORTED = 4,  /**< Attempting to decode a TIFF stream that is not supported by the nvTIFF
                                              library. */
    NVTIFF_STATUS_ALLOCATOR_FAILURE  = 5,  /**< The user-provided allocator functions returned a non-zero code. */
    NVTIFF_STATUS_EXECUTION_FAILED   = 6,  /**< Error during the execution of the device tasks. */
    NVTIFF_STATUS_ARCH_MISMATCH      = 7,  /**< The device capabilities are not enough for the set of input parameters
                                              provided. */
    NVTIFF_STATUS_INTERNAL_ERROR     = 8,  /**< Unknown error occurred in the library. */
    NVTIFF_STATUS_NVCOMP_NOT_FOUND   = 9,  /**< nvTIFF is unable to load the nvcomp library. */
    NVTIFF_STATUS_NVJPEG_NOT_FOUND   = 10, /**< nvTIFF is unable to load the nvjpeg library. */
    NVTIFF_STATUS_TAG_NOT_FOUND      = 11, /**< nvTIFF is unable to find information about the provided tag. */
    NVTIFF_STATUS_PARAMETER_OUT_OF_BOUNDS = 12, /**< Provided parameter is outside the range of possible values. */
    NVTIFF_STATUS_NVJPEG2K_NOT_FOUND      = 13, /**< nvTIFF is unable to load the nvJPEG2000 library. */
} nvtiffStatus_t;

/**********************************************************************/
/*                       Encoder Types                                */
/**********************************************************************/

/**
 * @brief Opaque nvTIFF encoder instance type.
 */
struct nvtiffEncoder;

/**
 * @brief Handle to opaque nvTIFF encoder instance.
 */
typedef struct nvtiffEncoder* nvtiffEncoder_t;

/**
 * @brief Opaque nvTIFF encode parameters type.
 */
struct nvtiffEncodeParams;

/**
 * @brief Handle to opaque nvTIFF encode parameters.
 */
typedef struct nvtiffEncodeParams* nvtiffEncodeParams_t;

/**
 * @brief TIFF file format variant.
 */
typedef enum nvtiffVariant
{
    NVTIFF_REGULAR_TIFF = 42, /**< Standard TIFF format (up to 4GB file size). */
    NVTIFF_BIG_TIFF     = 43  /**< BigTIFF format (supports files larger than 4GB). */
} nvtiffVariant_t;

/**********************************************************************/
/*                       GeoTIFF Types                                */
/**********************************************************************/

/**
 * @brief GeoTIFF key identifiers.
 *
 * Corresponds to various geo keys listed in the GeoTIFF specification.
 * User can refer to the GeoTIFF specification for additional details.
 */
typedef enum nvtiffGeoKeys
{
    // GeoTIFF Configuration Keys
    NVTIFF_GEOKEY_GT_MODEL_TYPE  = 1024, /**< Model type. */
    NVTIFF_GEOKEY_GT_RASTER_TYPE = 1025, /**< Raster type. */
    NVTIFF_GEOKEY_GT_CITATION    = 1026, /**< Citation. */

    // Geodetic CRS Parameter Keys
    NVTIFF_GEOKEY_GEODETIC_CRS              = 2048, /**< Geodetic CRS. */
    NVTIFF_GEOKEY_GEODETIC_CITATION         = 2049, /**< Geodetic citation. */
    NVTIFF_GEOKEY_GEODETIC_DATUM            = 2050, /**< Geodetic datum. */
    NVTIFF_GEOKEY_PRIME_MERIDIAN            = 2051, /**< Prime meridian. */
    NVTIFF_GEOKEY_GEOG_LINEAR_UNITS         = 2052, /**< Geographic linear units. */
    NVTIFF_GEOKEY_GEOG_LINEAR_UNIT_SIZE     = 2053, /**< Geographic linear unit size. */
    NVTIFF_GEOKEY_GEOG_ANGULAR_UNITS        = 2054, /**< Geographic angular units. */
    NVTIFF_GEOKEY_GEOG_ANGULAR_UNIT_SIZE    = 2055, /**< Geographic angular unit size. */
    NVTIFF_GEOKEY_ELLIPSOID                 = 2056, /**< Ellipsoid. */
    NVTIFF_GEOKEY_ELLIPSOID_SEMI_MAJOR_AXIS = 2057, /**< Ellipsoid semi-major axis. */
    NVTIFF_GEOKEY_ELLIPSOID_SEMI_MINOR_AXIS = 2058, /**< Ellipsoid semi-minor axis. */
    NVTIFF_GEOKEY_ELLIPSOID_INV_FLATTENING  = 2059, /**< Ellipsoid inverse flattening. */
    NVTIFF_GEOKEY_GEOG_AZIMUTH_UNITS        = 2060, /**< Geographic azimuth units. */
    NVTIFF_GEOKEY_PRIME_MERIDIAN_LONG       = 2061, /**< Prime meridian longitude. */

    // Projected CRS Parameter Keys
    NVTIFF_GEOKEY_PROJECTED_CRS                = 3072, /**< Projected CRS. */
    NVTIFF_GEOKEY_PROJECTED_CITATION           = 3073, /**< Projected citation. */
    NVTIFF_GEOKEY_PROJECTION                   = 3074, /**< Projection. */
    NVTIFF_GEOKEY_PROJ_METHOD                  = 3075, /**< Projection method. */
    NVTIFF_GEOKEY_PROJ_LINEAR_UNITS            = 3076, /**< Projection linear units. */
    NVTIFF_GEOKEY_PROJ_LINEAR_UNIT_SIZE        = 3077, /**< Projection linear unit size. */
    NVTIFF_GEOKEY_PROJ_STD_PARALLEL1           = 3078, /**< Standard parallel 1. */
    NVTIFF_GEOKEY_PROJ_STD_PARALLEL            = 3078, /**< Standard parallel (alias for PROJ_STD_PARALLEL1). */
    NVTIFF_GEOKEY_PROJ_STD_PARALLEL2           = 3079, /**< Standard parallel 2. */
    NVTIFF_GEOKEY_PROJ_NAT_ORIGIN_LONG         = 3080, /**< Natural origin longitude. */
    NVTIFF_GEOKEY_PROJ_ORIGIN_LONG             = 3080, /**< Origin longitude (alias for PROJ_NAT_ORIGIN_LONG). */
    NVTIFF_GEOKEY_PROJ_NAT_ORIGIN_LAT          = 3081, /**< Natural origin latitude. */
    NVTIFF_GEOKEY_PROJ_ORIGIN_LAT              = 3081, /**< Origin latitude (alias for PROJ_NAT_ORIGIN_LAT). */
    NVTIFF_GEOKEY_PROJ_FALSE_EASTING           = 3082, /**< False easting. */
    NVTIFF_GEOKEY_PROJ_FALSE_NORTHING          = 3083, /**< False northing. */
    NVTIFF_GEOKEY_PROJ_FALSE_ORIGIN_LONG       = 3084, /**< False origin longitude. */
    NVTIFF_GEOKEY_PROJ_FALSE_ORIGIN_LAT        = 3085, /**< False origin latitude. */
    NVTIFF_GEOKEY_PROJ_FALSE_ORIGIN_EASTING    = 3086, /**< False origin easting. */
    NVTIFF_GEOKEY_PROJ_FALSE_ORIGIN_NORTHING   = 3087, /**< False origin northing. */
    NVTIFF_GEOKEY_PROJ_CENTER_LONG             = 3088, /**< Center longitude. */
    NVTIFF_GEOKEY_PROJ_CENTER_LAT              = 3089, /**< Center latitude. */
    NVTIFF_GEOKEY_PROJ_CENTER_EASTING          = 3090, /**< Center easting. */
    NVTIFF_GEOKEY_PROJ_CENTER_NORTHING         = 3091, /**< Center northing. */
    NVTIFF_GEOKEY_PROJ_SCALE_AT_NAT_ORIGIN     = 3092, /**< Scale at natural origin. */
    NVTIFF_GEOKEY_PROJ_SCALE_AT_ORIGIN         = 3092, /**< Scale at origin (alias for PROJ_SCALE_AT_NAT_ORIGIN). */
    NVTIFF_GEOKEY_PROJ_SCALE_AT_CENTER         = 3093, /**< Scale at center. */
    NVTIFF_GEOKEY_PROJ_AZIMUTH_ANGLE           = 3094, /**< Azimuth angle. */
    NVTIFF_GEOKEY_PROJ_STRAIGHT_VERT_POLE_LONG = 3095, /**< Straight vertical pole longitude. */

    // Vertical CRS Parameter Keys (4096-5119)
    NVTIFF_GEOKEY_VERTICAL          = 4096, /**< Vertical CRS. */
    NVTIFF_GEOKEY_VERTICAL_CITATION = 4097, /**< Vertical citation. */
    NVTIFF_GEOKEY_VERTICAL_DATUM    = 4098, /**< Vertical datum. */
    NVTIFF_GEOKEY_VERTICAL_UNITS    = 4099, /**< Vertical units. */

    NVTIFF_GEOKEY_BASE = 32768, /**< Reserved for private use. */
    NVTIFF_GEOKEY_END  = 65535  /**< Maximum value. */
} nvtiffGeoKey_t;

/**
 * @brief Data type for GeoTIFF key values.
 */
typedef enum nvtiffGeoKeyDataType
{
    NVTIFF_GEOKEY_TYPE_SHORT   = 1, /**< 16-bit unsigned integer. */
    NVTIFF_GEOKEY_TYPE_ASCII   = 2, /**< ASCII string. */
    NVTIFF_GEOKEY_TYPE_DOUBLE  = 3, /**< 64-bit floating point. */
    NVTIFF_GEOKEY_TYPE_UNKNOWN = 4  /**< Unknown type. */
} nvtiffGeoKeyDataType_t;

/**********************************************************************/
/*                       TIFF Tag Types                               */
/**********************************************************************/

/**
 * @brief TIFF tag data types as defined in the TIFF specification.
 */
typedef enum nvtiffTagDataType
{
    NVTIFF_TAG_TYPE_BYTE      = 1,  /**< 8-bit unsigned integer. */
    NVTIFF_TAG_TYPE_ASCII     = 2,  /**< 8-bit byte containing ASCII code (null-terminated). */
    NVTIFF_TAG_TYPE_SHORT     = 3,  /**< 16-bit unsigned integer. */
    NVTIFF_TAG_TYPE_LONG      = 4,  /**< 32-bit unsigned integer. */
    NVTIFF_TAG_TYPE_RATIONAL  = 5,  /**< Two LONGs: numerator and denominator. */
    NVTIFF_TAG_TYPE_SBYTE     = 6,  /**< 8-bit signed integer. */
    NVTIFF_TAG_TYPE_UNDEFINED = 7,  /**< 8-bit byte that may contain anything. */
    NVTIFF_TAG_TYPE_SSHORT    = 8,  /**< 16-bit signed integer. */
    NVTIFF_TAG_TYPE_SLONG     = 9,  /**< 32-bit signed integer. */
    NVTIFF_TAG_TYPE_SRATIONAL = 10, /**< Two SLONGs: numerator and denominator. */
    NVTIFF_TAG_TYPE_FLOAT     = 11, /**< 32-bit IEEE floating point. */
    NVTIFF_TAG_TYPE_DOUBLE    = 12, /**< 64-bit IEEE floating point. */
    NVTIFF_TAG_TYPE_LONG8     = 16, /**< BigTIFF 64-bit unsigned integer. */
    NVTIFF_TAG_TYPE_SLONG8    = 17, /**< BigTIFF 64-bit signed integer. */
    NVTIFF_TAG_TYPE_IFD8      = 18, /**< BigTIFF 64-bit unsigned IFD offset. */
} nvtiffTagDataType_t;

/**
 * @brief TIFF tag identifiers.
 *
 * Corresponds to various TIFF tags listed in the TIFF specification.
 * Currently only GeoTIFF relevant tags are supported.
 */
typedef enum nvtiffTag
{
    NVTIFF_TAG_UNKNOWN              = -1,    /**< Unknown tag. */
    NVTIFF_TAG_MODEL_PIXEL_SCALE    = 33550, /**< GeoTIFF ModelPixelScaleTag. */
    NVTIFF_TAG_MODEL_TIE_POINT      = 33922, /**< GeoTIFF ModelTiepointTag. */
    NVTIFF_TAG_MODEL_TRANSFORMATION = 34264  /**< GeoTIFF ModelTransformationTag. */
} nvtiffTag_t;

/**********************************************************************/
/*                       Decoder Types                                */
/**********************************************************************/

/**
 * @brief Prototype for stream-ordered device memory allocation.
 *
 * @param ctx [in] User-defined context pointer.
 * @param ptr [out] Pointer to allocated memory.
 * @param size [in] Size in bytes to allocate.
 * @param stream [in] CUDA stream for ordered allocation.
 * @return 0 on success, non-zero on failure.
 */
typedef int (*nvtiffDeviceMallocAsync)(void* ctx, void** ptr, size_t size, cudaStream_t stream);

/**
 * @brief Prototype for stream-ordered device memory deallocation.
 *
 * @param ctx [in] User-defined context pointer.
 * @param ptr [in] Pointer to memory to free.
 * @param size [in] Size in bytes that was allocated.
 * @param stream [in] CUDA stream for ordered deallocation.
 * @return 0 on success, non-zero on failure.
 */
typedef int (*nvtiffDeviceFreeAsync)(void* ctx, void* ptr, size_t size, cudaStream_t stream);

/**
 * @brief Prototype for stream-ordered pinned memory allocation.
 *
 * @param ctx [in] User-defined context pointer.
 * @param ptr [out] Pointer to allocated memory.
 * @param size [in] Size in bytes to allocate.
 * @param stream [in] CUDA stream for ordered allocation.
 * @return 0 on success, non-zero on failure.
 */
typedef int (*nvtiffPinnedMallocAsync)(void* ctx, void** ptr, size_t size, cudaStream_t stream);

/**
 * @brief Prototype for stream-ordered pinned memory deallocation.
 *
 * @param ctx [in] User-defined context pointer.
 * @param ptr [in] Pointer to memory to free.
 * @param size [in] Size in bytes that was allocated.
 * @param stream [in] CUDA stream for ordered deallocation.
 * @return 0 on success, non-zero on failure.
 */
typedef int (*nvtiffPinnedFreeAsync)(void* ctx, void* ptr, size_t size, cudaStream_t stream);

/**
 * @brief Custom device memory allocator interface.
 *
 * Supports stream-ordered allocation and user-defined context information.
 * When invoking the device allocators, nvTIFF will pass device_ctx as input.
 */
typedef struct nvtiffDeviceAllocator
{
    nvtiffDeviceMallocAsync device_malloc; /**< Device allocator callback. */
    nvtiffDeviceFreeAsync device_free;     /**< Device free callback. */
    void* device_ctx;                      /**< User-defined context pointer. */
} nvtiffDeviceAllocator_t;

/**
 * @brief Custom pinned memory allocator interface.
 *
 * Supports stream-ordered allocation and user-defined context information.
 * When invoking the pinned allocators, nvTIFF will pass pinned_ctx as input.
 */
typedef struct nvtiffPinnedAllocator
{
    nvtiffPinnedMallocAsync pinned_malloc; /**< Pinned allocator callback. */
    nvtiffPinnedFreeAsync pinned_free;     /**< Pinned free callback. */
    void* pinned_ctx;                      /**< User-defined context pointer. */
} nvtiffPinnedAllocator_t;

/**
 * @brief Opaque nvTIFF decoder instance type.
 */
struct nvtiffDecoder;

/**
 * @brief Handle to opaque nvTIFF decoder instance.
 *
 * Stores intermediate decode buffers used in decoding.
 */
typedef struct nvtiffDecoder* nvtiffDecoder_t;

/**
 * @brief Opaque nvTIFF stream instance type.
 */
struct nvtiffStream;

/**
 * @brief Handle to opaque nvTIFF stream instance.
 *
 * Used for parsing a TIFF file. TIFF metadata can be extracted using parser APIs.
 */
typedef struct nvtiffStream* nvtiffStream_t;

/**
 * @brief Sample format types.
 *
 * Corresponds to the SampleFormat (339) tag defined in the TIFF specification.
 */
typedef enum nvtiffSampleFormat
{
    NVTIFF_SAMPLEFORMAT_UNKNOWN       = 0, /**< Unknown sample format. */
    NVTIFF_SAMPLEFORMAT_UINT          = 1, /**< Unsigned integer data. */
    NVTIFF_SAMPLEFORMAT_INT           = 2, /**< Signed integer data. */
    NVTIFF_SAMPLEFORMAT_IEEEFP        = 3, /**< IEEE floating point data. */
    NVTIFF_SAMPLEFORMAT_VOID          = 4, /**< Undefined data format. */
    NVTIFF_SAMPLEFORMAT_COMPLEXINT    = 5, /**< Complex integer data. */
    NVTIFF_SAMPLEFORMAT_COMPLEXIEEEFP = 6  /**< Complex IEEE floating point data. */
} nvtiffSampleFormat_t;

/**
 * @brief Photometric interpretation types.
 *
 * Corresponds to the PhotometricInterpretation (262) tag defined in the TIFF specification.
 */
typedef enum nvtiffPhotometricInt
{
    NVTIFF_PHOTOMETRIC_UNKNOWN    = -1, /**< Unknown photometric interpretation. */
    NVTIFF_PHOTOMETRIC_MINISWHITE = 0,  /**< 0 is white, max value is black. */
    NVTIFF_PHOTOMETRIC_MINISBLACK = 1,  /**< 0 is black, max value is white. */
    NVTIFF_PHOTOMETRIC_RGB        = 2,  /**< RGB color model. */
    NVTIFF_PHOTOMETRIC_PALETTE    = 3,  /**< Color map indexed (palette color). */
    NVTIFF_PHOTOMETRIC_MASK       = 4,  /**< Holdout mask. */
    NVTIFF_PHOTOMETRIC_SEPARATED  = 5,  /**< Color separations (e.g., CMYK). */
    NVTIFF_PHOTOMETRIC_YCBCR      = 6,  /**< YCbCr color space. */
} nvtiffPhotometricInt_t;

/**
 * @brief Planar configuration types.
 *
 * Corresponds to the PlanarConfiguration (284) tag defined in the TIFF specification.
 */
typedef enum nvtiffPlanarConfig
{
    NVTIFF_PLANARCONFIG_UNKNOWN  = 0, /**< Unknown planar configuration. */
    NVTIFF_PLANARCONFIG_CONTIG   = 1, /**< Chunky format (interleaved). */
    NVTIFF_PLANARCONFIG_SEPARATE = 2  /**< Planar format (separate planes). */
} nvtiffPlanarConfig_t;

/**
 * @brief Compression types.
 *
 * Corresponds to the Compression (259) tag defined in the TIFF specification.
 */
typedef enum nvtiffCompression
{
    NVTIFF_COMPRESSION_UNKNOWN           = 0,     /**< Unknown compression. */
    NVTIFF_COMPRESSION_NONE              = 1,     /**< No compression. */
    NVTIFF_COMPRESSION_LZW               = 5,     /**< LZW compression. */
    NVTIFF_COMPRESSION_JPEG              = 7,     /**< JPEG compression. */
    NVTIFF_COMPRESSION_ADOBE_DEFLATE     = 8,     /**< Adobe Deflate compression. */
    NVTIFF_COMPRESSION_DEFLATE           = 32946, /**< Deflate compression. */
    NVTIFF_COMPRESSION_APERIO_JP2000_YCC = 33003, /**< Aperio JPEG2000 YCC compression. */
    NVTIFF_COMPRESSION_APERIO_JP2000_RGB = 33005, /**< Aperio JPEG2000 RGB compression. */
    NVTIFF_COMPRESSION_JP2000            = 34712  /**< JPEG2000 compression. */
} nvtiffCompression_t;

/**
 * @brief Image type flags.
 *
 * Corresponds to the NewSubfileType (254) tag defined in the TIFF specification.
 */
typedef enum
{
    NVTIFF_IMAGETYPE_REDUCED_IMAGE     = 0b0001,     /**< Reduced resolution version of another image. */
    NVTIFF_IMAGETYPE_PAGE              = 0b0010,     /**< Single page of a multi-page image. */
    NVTIFF_IMAGETYPE_MASK              = 0b0100,     /**< Transparency mask for another image. */
    NVTIFF_IMAGETYPE_ENUM_FORCE_UINT32 = 0xFFFFFFFF, /**< Force enum to 32-bit. */
} nvtiffImageType;

/**
 * @brief Image type storage type.
 */
typedef uint32_t nvtiffImageType_t;

/**
 * @brief TIFF image metadata structure.
 *
 * Contains metadata of an image stored in a TIFF file.
 */
typedef struct nvtiffImageInfo
{
    nvtiffImageType_t image_type;                        /**< Image type flags from NewSubfileType tag. */
    uint32_t image_width;                                /**< Image width in pixels. */
    uint32_t image_height;                               /**< Image height in pixels. */
    nvtiffCompression_t compression;                     /**< Compression method used. */
    nvtiffPhotometricInt_t photometric_int;              /**< Photometric interpretation. */
    nvtiffPlanarConfig_t planar_config;                  /**< Planar configuration. */
    uint16_t samples_per_pixel;                          /**< Number of samples (channels) per pixel. */
    uint16_t bits_per_pixel;                             /**< Total bits per pixel (sum of @c bits_per_sample). */
    uint16_t bits_per_sample[MAX_NUM_SAMPLES];           /**< Bits per sample for each channel. */
    nvtiffSampleFormat_t sample_format[MAX_NUM_SAMPLES]; /**< Sample format for each channel. */
} nvtiffImageInfo_t;

/**
 * @brief Image geometry type.
 *
 * Specifies whether a TIFF file uses strips or tiles.
 */
typedef enum nvtiffImageGeometryType
{
    NVTIFF_IMAGE_STRIPED = 0, /**< Image is organized in strips. */
    NVTIFF_IMAGE_TILED   = 1, /**< Image is organized in tiles. */
} nvtiffImageGeometryType_t;

/**
 * @brief Image geometry information.
 *
 * Stores image geometry along with strip/tile dimensions.
 * When the geometry type is @c ::NVTIFF_IMAGE_STRIPED, @c strile_width equals @c image_width.
 */
typedef struct nvtiffImageGeometry
{
    nvtiffImageGeometryType_t type; /**< Geometry type (striped or tiled). */
    uint32_t image_depth;           /**< Image depth (for 3D images). */
    uint32_t strile_width;          /**< Strip/tile width (equals @c image_width for strips). */
    uint32_t strile_height;         /**< Strip/tile height. */
    uint32_t strile_depth;          /**< Strip/tile depth (equals @c image_depth for strips). */
    uint32_t num_striles_per_plane; /**< Number of strips/tiles per plane. */
    uint32_t num_striles;           /**< Total number of strips/tiles. */
} nvtiffImageGeometry_t;

/**
 * @brief Decode output format types.
 *
 * Used to specify the decode output format.
 */
typedef enum nvtiffOutputFormat
{
    NVTIFF_OUTPUT_UNCHANGED_I  = 0, /**< Keep original format, interleaved channels. */
    NVTIFF_OUTPUT_RGB_I_UINT8  = 1, /**< Interleaved RGB with 8 bits per channel. */
    NVTIFF_OUTPUT_RGB_I_UINT16 = 2, /**< Interleaved RGB with 16 bits per channel. */
} nvtiffOutputFormat_t;

/**
 * @brief Opaque decode parameters type.
 */
struct nvtiffDecodeParams;

/**
 * @brief Handle to opaque decode parameters.
 *
 * Used to specify decode output parameters such as region of interest and output format.
 */
typedef struct nvtiffDecodeParams* nvtiffDecodeParams_t;

/**
 * @brief Output image data structure.
 *
 * Contains output image data buffers used by @c nvtiffDecodeImageEx().
 */
typedef struct nvtiffImage
{
    void** plane_data;         /**< Array of pointers to plane data buffers on device. */
    size_t* plane_pitch_bytes; /**< Array of pitch values (bytes per row) for each plane. */
    uint32_t num_planes;       /**< Number of planes in the output image. */
} nvtiffImage_t;

/**********************************************************************/
/*                       Helper APIs                                  */
/**********************************************************************/

/**
 * @brief Gets the library's property values.
 *
 * This function retrieves version information about the nvTIFF library.
 * The @c libraryPropertyType enum is defined in CUDA's @c library_types.h header.
 *
 * @param type [in] The property to retrieve. Valid values are:
 *        - @c MAJOR_VERSION - Returns the major version number.
 *        - @c MINOR_VERSION - Returns the minor version number.
 *        - @c PATCH_LEVEL - Returns the patch level.
 * @param value [out] Pointer to receive the numeric value of the requested property.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffGetProperty(libraryPropertyType type, int* value);

/**
 * @brief Creates an instance of the decode parameters handle.
 *
 * @param decode_params [out] Pointer to decode parameters handle.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffDecodeParamsCreate(nvtiffDecodeParams_t* decode_params);

/**
 * @brief Releases the decode parameters handle.
 *
 * @param decode_params [in] Decode parameters handle to destroy.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffDecodeParamsDestroy(nvtiffDecodeParams_t decode_params);

/**
 * @brief Creates an instance of the bitstream handle.
 *
 * @param tiff_stream [out] Pointer to nvTIFF bitstream handle.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamCreate(nvtiffStream_t* tiff_stream);

/**
 * @brief Releases the bitstream handle.
 *
 * @param tiff_stream [in] nvTIFF bitstream handle to destroy.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamDestroy(nvtiffStream_t tiff_stream);

/**
 * @brief Creates an instance of the decoder handle with custom memory allocators.
 *
 * @param decoder [out] Pointer to nvTIFF decoder handle.
 * @param device_allocator [in] User-provided device memory allocator. If @c NULL, the library
 *        uses @c cudaMalloc / @c cudaFree.
 * @param pinned_allocator [in] User-provided pinned memory allocator. If @c NULL, the library
 *        uses @c cudaHostAlloc / @c cudaFreeHost.
 * @param stream [in] CUDA stream for asynchronous API calls.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffDecoderCreate(nvtiffDecoder_t* decoder, nvtiffDeviceAllocator_t* device_allocator,
    nvtiffPinnedAllocator_t* pinned_allocator, cudaStream_t stream);

/**
 * @brief Creates an instance of the decoder handle with default memory allocators.
 *
 * @param decoder [out] Pointer to nvTIFF decoder handle.
 * @param stream [in] CUDA stream for asynchronous API calls.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffDecoderCreateSimple(nvtiffDecoder_t* decoder, cudaStream_t stream);

/**
 * @brief Releases the decoder handle.
 *
 * @param decoder [in] nvTIFF decoder handle to destroy.
 * @param stream [in] CUDA stream for asynchronous API calls.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffDecoderDestroy(nvtiffDecoder_t decoder, cudaStream_t stream);

/**********************************************************************/
/*    nvTIFF Stream APIs for file Parsing and extracting Metadata     */
/**********************************************************************/

/**
 * @brief Parses a TIFF file and stores the metadata in the stream handle.
 *
 * @param fname [in] TIFF file name on disk.
 * @param tiff_stream [in/out] TIFF stream handle to be initialized.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamParseFromFile(const char* fname, nvtiffStream_t tiff_stream);

/**
 * @brief Parses a TIFF file from host memory and stores the metadata.
 *
 * For best decode performance, the host buffer should be page-locked (pinned) memory.
 * This can be allocated with @c cudaHostAlloc.
 *
 * @param buffer [in] Buffer containing TIFF file data.
 * @param buffer_size [in] Size of the buffer in bytes.
 * @param tiff_stream [in/out] TIFF stream handle to be initialized.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamParse(const uint8_t* buffer, size_t buffer_size, nvtiffStream_t tiff_stream);

/**
 * @brief Extended version of @c nvtiffStreamParseFromFile() with pagination support.
 *
 * Supports parsing from a specific bitstream offset and limiting the number of images parsed.
 * This is useful for parsing large multi-image TIFFs incrementally.
 *
 * If @c bitstream_offset is zero, parsing starts at the first IFD specified in the TIFF header.
 * If @c limit_images is zero, all images in the IFD chain are parsed.
 *
 * @param fname [in] TIFF file name on disk.
 * @param tiff_stream [in/out] TIFF stream handle to be initialized.
 * @param bitstream_offset [in] Bitstream offset of the IFD to start parsing from (0 = beginning).
 * @param limit_images [in] Maximum number of images to parse (0 = no limit).
 * @param next_bitstream_offset [out] If non-null, receives the offset of the next IFD (0 if end of chain).
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamParseFromFileEx(const char* fname, nvtiffStream_t tiff_stream,
    size_t bitstream_offset, uint32_t limit_images, size_t* next_bitstream_offset);

/**
 * @brief Extended version of @c nvtiffStreamParse() with pagination support.
 *
 * Supports parsing from a specific bitstream offset and limiting the number of images parsed.
 * This is useful for parsing large multi-image TIFFs from memory incrementally.
 *
 * @param buffer [in] Buffer containing TIFF file data.
 * @param buffer_size [in] Size of the buffer in bytes.
 * @param tiff_stream [in/out] TIFF stream handle to be initialized.
 * @param bitstream_offset [in] Bitstream offset of the IFD to start parsing from (0 = beginning).
 * @param limit_images [in] Maximum number of images to parse (0 = no limit).
 * @param next_bitstream_offset [out] If non-null, receives the offset of the next IFD (0 if end of chain).
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamParseEx(const uint8_t* buffer, size_t buffer_size, nvtiffStream_t tiff_stream,
    size_t bitstream_offset, uint32_t limit_images, size_t* next_bitstream_offset);

/**
 * @brief Parses a new stream from a specified bitstream offset within an existing TIFF stream.
 *
 * This can be used to parse SubIFDs and other custom IFD chains. The new stream shares the same
 * base resource (file or memory buffer) as the parent stream. The resource is only released when
 * all streams referencing it have been destroyed.
 *
 * The @c offset_stream parameter can be the same as @c parent_stream, in which case the source stream
 * will be replaced with the target stream.
 *
 * @param parent_stream [in] Parent TIFF stream handle.
 * @param offset_stream [in/out] Stream handle to be initialized from the specified offset.
 * @param bitstream_offset [in] Bitstream offset of the IFD to parse relative to the file beginning.
 * @param limit_images [in] Maximum number of images to parse along the IFD chain (0 = no limit).
 * @param next_bitstream_offset [out] If non-null, receives the offset of the next IFD (0 if end of chain).
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamParseFromParentStream(nvtiffStream_t parent_stream, nvtiffStream_t offset_stream,
    size_t bitstream_offset, uint32_t limit_images, size_t* next_bitstream_offset);

/**
 * @brief Retrieves the bitstream offset of a given IFD within the TIFF file.
 *
 * Each image's bitstream offset serves as a unique identifier, which is helpful for dealing
 * with complex TIFF structures involving SubIFDs.
 *
 * @param tiff_stream [in] TIFF stream handle.
 * @param image_id [in] Image index.
 * @param offset [out] Pointer to receive the file offset where the image's IFD begins.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamGetBitstreamOffset(nvtiffStream_t tiff_stream, uint32_t image_id, size_t* offset);

/**
 * @brief Prints the TIFF file metadata to standard output.
 *
 * @param tiff_stream [in] TIFF stream handle.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamPrint(nvtiffStream_t tiff_stream);

/**
 * @brief Retrieves the number of images stored in a TIFF file.
 *
 * @param tiff_stream [in] TIFF stream handle.
 * @param num_images [out] Pointer to receive the number of images.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamGetNumImages(nvtiffStream_t tiff_stream, uint32_t* num_images);

/**
 * @brief Retrieves the image information for a given image in a TIFF file.
 *
 * @param tiff_stream [in] TIFF stream handle.
 * @param image_id [in] Image index.
 * @param image_info [out] Pointer to nvtiffImageInfo_t structure to receive the image information.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamGetImageInfo(
    nvtiffStream_t tiff_stream, uint32_t image_id, nvtiffImageInfo_t* image_info);

/**
 * @brief Retrieves image geometry information.
 *
 * Geometry includes information whether the images use strips or tiles and their
 * corresponding dimensions.
 *
 * @param tiff_stream [in] TIFF stream handle.
 * @param image_id [in] Image index.
 * @param geometry [out] Pointer to nvtiffImageGeometry_t structure.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamGetImageGeometry(
    nvtiffStream_t tiff_stream, uint32_t image_id, nvtiffImageGeometry_t* geometry);

/**
 * @brief Retrieves information about a GeoTIFF key.
 *
 * This information is useful for retrieving the values associated with the geo key.
 *
 * @param tiff_stream [in] TIFF stream handle.
 * @param key [in] GeoTIFF key to query.
 * @param size [out] Pointer to receive the size of each value (in bytes).
 * @param count [out] Pointer to receive the number of values stored in key.
 * @param type [out] Pointer to receive the datatype of values stored in key.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamGetGeoKeyInfo(
    nvtiffStream_t tiff_stream, nvtiffGeoKey_t key, uint32_t* size, uint32_t* count, nvtiffGeoKeyDataType_t* type);

/**
 * @brief Retrieves TIFF tag information.
 *
 * Retrieves tag type, size per element, and count for a specific tag in an image.
 *
 * @param tiff_stream [in] TIFF stream handle.
 * @param image_id [in] Image index.
 * @param tiff_tag [in] TIFF tag to query.
 * @param tag_type [out] Pointer to receive the datatype of the tag.
 * @param size [out] Pointer to receive the size of individual values in the tag.
 * @param count [out] Pointer to receive the number of values in the tag.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamGetTagInfo(nvtiffStream_t tiff_stream, uint32_t image_id, nvtiffTag_t tiff_tag,
    nvtiffTagDataType_t* tag_type, uint32_t* size, uint32_t* count);

/**
 * @brief Retrieves the values stored in a TIFF tag.
 *
 * @param tiff_stream [in] TIFF stream handle.
 * @param image_id [in] Image index.
 * @param tiff_tag [in] TIFF tag to query.
 * @param tag_value [out] Pointer to buffer to receive the tag values.
 * @param count [in] Number of values to retrieve.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamGetTagValue(
    nvtiffStream_t tiff_stream, uint32_t image_id, nvtiffTag_t tiff_tag, void* tag_value, uint32_t count);

/**
 * @brief Retrieves TIFF tag information using a generic tag ID.
 *
 * Retrieves tag type, size per element, and count for any TIFF tag (not just nvtiffTag_t values).
 * If the tag is not found, returns @c ::NVTIFF_STATUS_TAG_NOT_FOUND.
 *
 * @param tiff_stream [in] TIFF stream handle.
 * @param image_id [in] Image index.
 * @param tiff_tag [in] TIFF tag ID (any valid TIFF tag number).
 * @param tag_type [out] Pointer to receive the datatype of the tag.
 * @param size [out] Pointer to receive the size per element. When tag type is @c ::NVTIFF_TAG_TYPE_ASCII, the string is
 * NULL terminated.
 * @param count [out] Pointer to receive the number of elements.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamGetTagInfoGeneric(nvtiffStream_t tiff_stream, uint32_t image_id, uint16_t tiff_tag,
    nvtiffTagDataType_t* tag_type, uint32_t* size, uint32_t* count);

/**
 * @brief Retrieves the values stored in a TIFF tag using a generic tag ID.
 *
 * If the tag is not found, returns @c ::NVTIFF_STATUS_TAG_NOT_FOUND.
 *
 * @param tiff_stream [in] TIFF stream handle.
 * @param image_id [in] Image index.
 * @param tiff_tag [in] TIFF tag ID (any valid TIFF tag number).
 * @param tag_value [out] Output buffer to receive the tag value.
 * @param count [in] Number of elements to retrieve.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamGetTagValueGeneric(
    nvtiffStream_t tiff_stream, uint32_t image_id, uint16_t tiff_tag, void* tag_value, uint32_t count);

/**
 * @brief Enumerates all TIFF tags present in a specific image.
 *
 * Use the two-call pattern: first call with tags=@c NULL to get the count, then allocate a buffer
 * and call again to retrieve the tag IDs.
 *
 * @param tiff_stream [in] TIFF stream handle.
 * @param image_id [in] Image index.
 * @param tags [out] Pointer to buffer for storing tag IDs (can be @c NULL to get count only).
 * @param num_tags [out] Pointer to receive the number of tags.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamGetNumberOfTags(
    nvtiffStream_t tiff_stream, uint32_t image_id, uint16_t* tags, uint32_t* num_tags);

/**
 * @brief Checks whether a specific tag exists in an image.
 *
 * This is useful for quickly determining tag presence without enumerating all tags.
 *
 * @param tiff_stream [in] TIFF stream handle.
 * @param image_id [in] Image index.
 * @param tag [in] Tag ID to check for.
 * @param has_tag [out] Set to 1 if tag exists, 0 if not.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamHasTag(nvtiffStream_t tiff_stream, uint32_t image_id, uint16_t tag, int* has_tag);

/**
 * @brief Retrieves the list of GeoTIFF keys present in a TIFF file and their count.
 *
 * Use the two-call pattern: first call with key=@c NULL to get the count, then allocate a buffer
 * and call again to retrieve the key IDs.
 *
 * @param tiff_stream [in] TIFF stream handle.
 * @param key [out] Pointer to buffer for storing geokey IDs (can be @c NULL to get count only).
 * @param num_keys [out] Pointer to receive the number of geokeys.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamGetNumberOfGeoKeys(
    nvtiffStream_t tiff_stream, nvtiffGeoKey_t* key, uint32_t* num_keys);

/**
 * @brief Retrieves the values associated with a given GeoTIFF key.
 *
 * @param tiff_stream [in] TIFF stream handle.
 * @param key [in] GeoTIFF key to retrieve.
 * @param val [out] Pointer to buffer to receive the key values.
 * @param count [in] Number of values to copy. For @c ::NVTIFF_GEOKEY_TYPE_ASCII this is ignored.
 *        For @c ::NVTIFF_GEOKEY_TYPE_SHORT, @c count=1 is implied.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamGetGeoKey(
    nvtiffStream_t tiff_stream, nvtiffGeoKey_t key, void* val, uint32_t count);

/**
 * @brief Retrieves ASCII values associated with a GeoTIFF key.
 *
 * @param tiff_stream [in] TIFF stream handle.
 * @param key [in] GeoTIFF key to retrieve.
 * @param str [out] Pointer to buffer to receive the ASCII string.
 * @param max_len [in] Size of the user-allocated buffer @c str.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamGetGeoKeyASCII(
    nvtiffStream_t tiff_stream, nvtiffGeoKey_t key, char* str, uint32_t max_len);

/**
 * @brief Retrieves SHORT values associated with a GeoTIFF key.
 *
 * @param tiff_stream [in] TIFF stream handle.
 * @param key [in] GeoTIFF key to retrieve.
 * @param val [out] Pointer to buffer to receive the SHORT values.
 * @param index [in] Index of the starting value to copy.
 * @param count [in] Number of values to copy.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamGetGeoKeySHORT(
    nvtiffStream_t tiff_stream, nvtiffGeoKey_t key, unsigned short* val, uint32_t index, uint32_t count);

/**
 * @brief Retrieves DOUBLE values associated with a GeoTIFF key.
 *
 * @param tiff_stream [in] TIFF stream handle.
 * @param key [in] GeoTIFF key to retrieve.
 * @param val [out] Pointer to buffer to receive the DOUBLE values.
 * @param index [in] Index of the starting value to copy.
 * @param count [in] Number of values to copy.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffStreamGetGeoKeyDOUBLE(
    nvtiffStream_t tiff_stream, nvtiffGeoKey_t key, double* val, uint32_t index, uint32_t count);

/**********************************************************************/
/*                       Decode APIs                                  */
/**********************************************************************/

/**
 * @brief Decodes a range of images from a TIFF file.
 *
 * Decodes images in the range <tt>[sub_file_start, sub_file_start + sub_file_num)</tt>.
 * When the photometric interpretation is @c ::NVTIFF_PHOTOMETRIC_PALETTE or @c ::NVTIFF_PHOTOMETRIC_YCBCR,
 * the decode output will be converted to RGB.
 * For images with multiple samples, the decode output will always be in planar contiguous format.
 *
 * @param tiff_stream [in] TIFF stream handle containing the parsed file.
 * @param decoder [in] Decoder handle.
 * @param sub_file_start [in] Index of the first image to decode, in the range <tt>[0, num_images)</tt>.
 * @param sub_file_num [in] Number of images to decode starting from @c sub_file_start.
 * @param image_out [out] Host array of pointers to device buffers. Each buffer size should be
 *        <tt>image_height * DivUp(image_width * bits_per_pixel, 8)</tt>.
 *        For palette mode images, buffer size should be
 *        <tt>image_width * image_height * 6</tt>.
 * @param stream [in] CUDA stream for GPU work submission.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffDecodeRange(nvtiffStream_t tiff_stream, nvtiffDecoder_t decoder,
    unsigned int sub_file_start, unsigned int sub_file_num, unsigned char** image_out, cudaStream_t stream);

/**
 * @brief Decodes all images from a TIFF file.
 *
 * Decodes all image data on the GPU. Each image is copied into the respective buffer pointed to
 * by @c image_out. This function is fully asynchronous.
 * When the photometric interpretation is @c ::NVTIFF_PHOTOMETRIC_PALETTE or @c ::NVTIFF_PHOTOMETRIC_YCBCR,
 * the decode output will be converted to RGB.
 * For images with multiple samples, the decode output will always be in planar contiguous format.
 *
 * @param tiff_stream [in] TIFF stream handle containing the parsed file.
 * @param decoder [in] Decoder handle.
 * @param image_out [out] Host array (of size @c num_images) of pointers to device buffers.
 *        Each buffer size should be <tt>image_height * DivUp(image_width * bits_per_pixel, 8)</tt>.
 *        For palette mode images, buffer size should be <tt>image_width * image_height * 6</tt>.
 * @param stream [in] CUDA stream for GPU work submission.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffDecode(
    nvtiffStream_t tiff_stream, nvtiffDecoder_t decoder, unsigned char** image_out, cudaStream_t stream);

/**
 * @brief Decodes a single image with additional output control.
 *
 * Decodes a single image on the GPU. The function is asynchronous with respect to the host.
 * Additional control of the decode output is possible using @c ::nvtiffDecodeParams_t.
 *
 * @param tiff_stream [in] TIFF stream handle containing the parsed file.
 * @param decoder [in] Decoder handle.
 * @param params [in] Decode parameters for controlling output (ROI, output format).
 * @param image_id [in] Image index within the TIFF file.
 * @param image_out_d [out] Device buffer for decoded output. See @c nvtiffDecodeParamsSetOutputFormat() for size
 * requirements.
 * @param stream [in] CUDA stream for GPU work submission.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffDecodeImage(nvtiffStream_t tiff_stream, nvtiffDecoder_t decoder,
    nvtiffDecodeParams_t params, uint32_t image_id, void* image_out_d, cudaStream_t stream);

/**
 * @brief Decodes a single image with extended output support.
 *
 * Decodes a single image on the GPU with extended output buffer control via @c nvtiffImage_t.
 * The function is asynchronous with respect to the host.
 *
 * @param tiff_stream [in] TIFF stream handle containing the parsed file.
 * @param decoder [in] Decoder handle.
 * @param params [in] Decode parameters for controlling output (ROI, output format).
 * @param image_id [in] Image index within the TIFF file.
 * @param image_out [out] Output image structure. Only one output plane is currently supported.
 *        The pitch must be aligned to the size of the sample type.
 * @param stream [in] CUDA stream for GPU work submission.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffDecodeImageEx(nvtiffStream_t tiff_stream, nvtiffDecoder_t decoder,
    nvtiffDecodeParams_t params, uint32_t image_id, nvtiffImage_t* image_out, cudaStream_t stream);

/**
 * @brief Checks whether an image can be decoded by nvTIFF.
 *
 * Returns @c ::NVTIFF_STATUS_SUCCESS if the image is supported.
 *
 * @param tiff_stream [in] TIFF stream handle containing the parsed file.
 * @param decoder [in] Decoder handle.
 * @param params [in] Decode parameters.
 * @param image_id [in] Image index within the TIFF file.
 * @return @c ::NVTIFF_STATUS_SUCCESS if supported, otherwise an error code as specified in @ref nvtiffStatus_t "API
 * Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffDecodeCheckSupported(
    nvtiffStream_t tiff_stream, nvtiffDecoder_t decoder, nvtiffDecodeParams_t params, uint32_t image_id);

/**********************************************************************/
/*                       Decode Parameters APIs                       */
/**********************************************************************/

/**
 * @brief Sets the decode output format.
 *
 * The default value is @c ::NVTIFF_OUTPUT_UNCHANGED_I.
 *
 * **Buffer size and pitch requirements:**
 *
 * When @c ::NVTIFF_OUTPUT_UNCHANGED_I is used:
 * - Buffer size: <tt>image_height * DivUp(image_width * bits_per_pixel, 8)</tt>
 * - Pitch must be aligned to <tt>DivUp(bits_per_sample[0], 8)</tt> bytes.
 * - Default pitch (if not specified): <tt>DivUp(image_width * bits_per_pixel, 8)</tt>
 *
 * When @c ::NVTIFF_OUTPUT_RGB_I_UINT8 is used:
 * - Buffer size: <tt>image_width * image_height * 3</tt>
 * - Pitch must be aligned to 1 byte.
 *
 * When @c ::NVTIFF_OUTPUT_RGB_I_UINT16 is used:
 * - Buffer size: <tt>image_width * image_height * 6</tt>
 * - Pitch must be aligned to 2 bytes.
 *
 * @param decode_params [in/out] Decode parameters handle.
 * @param format [in] Output format value.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffDecodeParamsSetOutputFormat(
    nvtiffDecodeParams_t decode_params, nvtiffOutputFormat_t format);

/**
 * @brief Sets the region of interest for decoding.
 *
 * The entire image is decoded by default.
 *
 * Constraints:
 * - @c offset_x and @c offset_y must be non-negative and cannot exceed image dimensions.
 * - <tt>offset_x + roi_width</tt> and <tt>offset_y + roi_height</tt> cannot exceed image dimensions.
 * - When image bitdepth is 1, @c offset_x and @c roi_width must be multiples of 8.
 *
 * @param decode_params [in/out] Decode parameters handle.
 * @param offset_x [in] Horizontal offset from top-left corner.
 * @param offset_y [in] Vertical offset from top-left corner.
 * @param roi_width [in] Width of the region of interest.
 * @param roi_height [in] Height of the region of interest.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffDecodeParamsSetROI(
    nvtiffDecodeParams_t decode_params, int32_t offset_x, int32_t offset_y, int32_t roi_width, int32_t roi_height);

/**********************************************************************/
/*                       Encode APIs                                  */
/**********************************************************************/

/**
 * @brief Creates and initializes a TIFF encoder instance.
 *
 * @param encoder [out] Pointer to encoder handle.
 * @param device_allocator [in] Custom device memory allocator (can be @c NULL to use @c cudaMalloc() / @c cudaFree()).
 * @param pinned_allocator [in] Custom pinned memory allocator (can be @c NULL to use @c cudaHostAlloc() / @c
 * cudaFreeHost()).
 * @param stream [in] CUDA stream.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffEncoderCreate(nvtiffEncoder_t* encoder, nvtiffDeviceAllocator_t* device_allocator,
    nvtiffPinnedAllocator_t* pinned_allocator, cudaStream_t stream);

/**
 * @brief Destroys a TIFF encoder instance and frees associated resources.
 *
 * @param encoder [in] Encoder handle to destroy.
 * @param stream [in] CUDA stream.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffEncoderDestroy(nvtiffEncoder_t encoder, cudaStream_t stream);

/**
 * @brief Calculates the size of TIFF metadata and/or compressed bitstream.
 *
 * Either @c metadata_size or @c bitstream_size can be @c NULL to skip that calculation.
 * @c metadata_size can be calculated before calling @c nvtiffEncode(), but @c bitstream_size
 * can only be calculated after @c nvtiffEncodeFinalize() is called.
 *
 * @param encoder [in] Encoder handle.
 * @param params [in] Array of encode parameters.
 * @param num_params [in] Number of encode parameters (must be 1 for now).
 * @param metadata_size [out] Size of TIFF metadata in bytes (can be NULL).
 * @param bitstream_size [out] Size of compressed data in bytes (can be NULL).
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffGetBitstreamSize(nvtiffEncoder_t encoder, nvtiffEncodeParams_t* params,
    uint32_t num_params, size_t* metadata_size, size_t* bitstream_size);

/**
 * @brief Writes complete TIFF data including metadata to a host memory buffer.
 *
 * This function performs stream synchronization internally to ensure the bitstream is ready.
 *
 * @param encoder [in] Encoder handle.
 * @param params [in] Array of encode parameters.
 * @param num_params [in] Number of encode parameters (must be 1 for now).
 * @param buffer [out] Buffer to write TIFF data to.
 * @param size [in] Size of output buffer in bytes.
 * @param stream [in] CUDA stream.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffWriteTiffBuffer(nvtiffEncoder_t encoder, nvtiffEncodeParams_t* params,
    uint32_t num_params, uint8_t* buffer, size_t size, cudaStream_t stream);

/**
 * @brief Writes complete TIFF data including metadata to a file.
 *
 * This function performs stream synchronization internally to ensure the bitstream is ready.
 *
 * @param encoder [in] Encoder handle.
 * @param params [in] Array of encode parameters.
 * @param num_params [in] Number of encode parameters (must be 1 for now).
 * @param fname [in] Output file path.
 * @param stream [in] CUDA stream.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffWriteTiffFile(
    nvtiffEncoder_t encoder, nvtiffEncodeParams_t* params, uint32_t num_params, const char* fname, cudaStream_t stream);

/**
 * @brief Performs asynchronous TIFF encoding of one or more images.
 *
 * Parameters must be set using @c nvtiffEncodeParamsSetImageInfo() and @c nvtiffEncodeParamsSetInputs()
 * before calling this function. If the provided compression method (LZW by default) results
 * in a bitstream larger than the raw input image data, compression is automatically disabled.
 *
 * @param encoder [in] Encoder handle.
 * @param params [in] Array of encode parameters.
 * @param num_params [in] Number of encode parameters (must be 1 for now).
 * @param stream [in] CUDA stream.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffEncode(
    nvtiffEncoder_t encoder, nvtiffEncodeParams_t* params, uint32_t num_params, cudaStream_t stream);

/**
 * @brief Finalizes asynchronous TIFF encoding operation started by @c nvtiffEncode().
 *
 * This function must be called before the encoded bitstream can be written with
 * @c nvtiffWriteTiffBuffer() or @c nvtiffWriteTiffFile().
 *
 * @param encoder [in] Encoder handle.
 * @param params [in] Array of encode parameters.
 * @param num_params [in] Number of encode parameters (must be 1 for now).
 * @param stream [in] CUDA stream.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffEncodeFinalize(
    nvtiffEncoder_t encoder, nvtiffEncodeParams_t* params, uint32_t num_params, cudaStream_t stream);

/**********************************************************************/
/*                       Encode Parameters APIs                       */
/**********************************************************************/

/**
 * @brief Creates and initializes encode parameters object.
 *
 * @param params [out] Pointer to encode parameters handle.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffEncodeParamsCreate(nvtiffEncodeParams_t* params);

/**
 * @brief Destroys encode parameters object and frees associated resources.
 *
 * @param params [in] Encode parameters handle.
 * @param stream [in] CUDA stream.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffEncodeParamsDestroy(nvtiffEncodeParams_t params, cudaStream_t stream);

/**
 * @brief Sets the TIFF variant (regular or BigTIFF) for encoding.
 *
 * This API is optional; by default, regular TIFF is used.
 *
 * @param params [in] Encode parameters handle.
 * @param variant [in] TIFF variant (@c ::NVTIFF_REGULAR_TIFF or @c ::NVTIFF_BIG_TIFF).
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffEncodeParamsSetTiffVariant(nvtiffEncodeParams_t params, nvtiffVariant_t variant);

/**
 * @brief Sets image information for encoding.
 *
 * Required fields: @c image_width, @c image_height, @c samples_per_pixel, @c bits_per_sample,
 * and @c sample_format (for each sample in a pixel).
 *
 * Constraints:
 * - @c samples_per_pixel must be either 1 or 3.
 * - @c photometric_int must be @c ::NVTIFF_PHOTOMETRIC_RGB (if @c samples_per_pixel is 3) or
 *   @c ::NVTIFF_PHOTOMETRIC_MINISBLACK (if @c samples_per_pixel is 1). @c ::NVTIFF_PHOTOMETRIC_UNKNOWN is auto-set.
 * - @c sample_format must be @c ::NVTIFF_SAMPLEFORMAT_UNKNOWN, @c ::NVTIFF_SAMPLEFORMAT_UINT,
 *   or @c ::NVTIFF_SAMPLEFORMAT_IEEEFP.
 * - @c planar_config must be @c ::NVTIFF_PLANARCONFIG_CONTIG.
 * - @c compression must be @c ::NVTIFF_COMPRESSION_LZW or @c ::NVTIFF_COMPRESSION_NONE.
 *
 * @param params [in] Encode parameters handle.
 * @param image_info [in] Pointer to image information structure.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffEncodeParamsSetImageInfo(
    nvtiffEncodeParams_t params, const nvtiffImageInfo_t* image_info);

/**
 * @brief Sets strip size for encoding.
 *
 * This is optional; by default, strip size will be set to 8 KB.
 * Only the @c strile_height field (number of rows per strip) needs to be set,
 * as only stripes (not tiles) are currently supported.
 *
 * @param params [in] Encode parameters handle.
 * @param geometry [in] Pointer to image geometry structure.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffEncodeParamsSetImageGeometry(
    nvtiffEncodeParams_t params, const nvtiffImageGeometry_t* geometry);

/**
 * @brief Sets input image pointers for encoding.
 *
 * @param params [in] Encode parameters handle.
 * @param images_d [in] Host array of size @c num_images of pointers to device buffers.
 * @param num_images [in] Number of input images.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffEncodeParamsSetInputs(
    nvtiffEncodeParams_t params, uint8_t** images_d, uint32_t num_images);

/**********************************************************************/
/*                       GeoTIFF Encode APIs                          */
/**********************************************************************/

/**
 * @brief Sets a GeoTIFF key with arbitrary type and value.
 *
 * @param params [in] Encode parameters handle.
 * @param key [in] GeoTIFF key to set.
 * @param type [in] Data type of the key value.
 * @param value [in] Pointer to key value.
 * @param value_size [in] Size of individual value in bytes.
 * @param count [in] Number of values.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffEncodeParamsSetGeoKey(nvtiffEncodeParams_t params, nvtiffGeoKey_t key,
    nvtiffGeoKeyDataType_t type, void* value, uint32_t value_size, uint32_t count);

/**
 * @brief Sets a TIFF tag with specified type and value.
 *
 * @param params [in] Encode parameters handle.
 * @param tag [in] TIFF tag to set.
 * @param type [in] Data type of tag value.
 * @param value [in] Pointer to tag value.
 * @param count [in] Number of values.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffEncodeParamsSetTag(
    nvtiffEncodeParams_t params, uint16_t tag, nvtiffTagDataType type, void* value, uint32_t count);

/**
 * @brief Sets a GeoTIFF key with SHORT value type.
 *
 * @param params [in] Encode parameters handle.
 * @param key [in] GeoTIFF key to set.
 * @param value [in] SHORT value to set.
 * @param count [in] Number of values.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffEncodeParamsSetGeoKeySHORT(
    nvtiffEncodeParams_t params, nvtiffGeoKey_t key, uint16_t value, uint32_t count);

/**
 * @brief Sets a GeoTIFF key with DOUBLE value type.
 *
 * @param params [in] Encode parameters handle.
 * @param key [in] GeoTIFF key to set.
 * @param value [in] DOUBLE value to set.
 * @param count [in] Number of values.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffEncodeParamsSetGeoKeyDOUBLE(
    nvtiffEncodeParams_t params, nvtiffGeoKey_t key, double value, uint32_t count);

/**
 * @brief Sets a GeoTIFF key with ASCII value type.
 *
 * @param params [in] Encode parameters handle.
 * @param key [in] GeoTIFF key to set.
 * @param value [in] ASCII string value.
 * @param value_size [in] Size of ASCII string including null terminator.
 * @return An error code as specified in @ref nvtiffStatus_t "API Return Status Codes".
 */
nvtiffStatus_t NVTIFFAPI nvtiffEncodeParamsSetGeoKeyASCII(
    nvtiffEncodeParams_t params, nvtiffGeoKey_t key, const char* value, uint32_t value_size);

#if defined(__cplusplus)
}
#endif

#endif
