/*
 *    Copyright (C) 2016-2021 Grok Image Compression Inc.
 *
 *    This source code is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This source code is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 *    This source code incorporates work covered by the BSD 2-clause license.
 *    Please see the LICENSE file in the root directory for details.
 *
 */

#pragma once

#ifdef __cplusplus
extern "C" {
#endif

#include "grk_config.h"
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <limits.h>

#ifdef __GNUC__
#define GRK_DEPRECATED(func) func __attribute__((deprecated))
#elif defined(_MSC_VER)
#define GRK_DEPRECATED(func) __declspec(deprecated) func
#else
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
#define GRK_DEPRECATED(func) func
#endif

#if defined(GRK_STATIC) || !defined(_WIN32)
#if defined(GRK_STATIC) /* static library uses "hidden" */
#define GRK_API __attribute__((visibility("hidden")))
#else
#define GRK_API __attribute__((visibility("default")))
#endif
#define GRK_CALLCONV
#else
#define GRK_CALLCONV __stdcall
#if defined(GRK_EXPORTS) || defined(DLL_EXPORT)
#define GRK_API __declspec(dllexport)
#else
#define GRK_API __declspec(dllimport)
#endif
#endif

typedef enum GRK_RATE_CONTROL_ALGORITHM
{
	GRK_RATE_CONTROL_BISECT,
	GRK_RATE_CONTROL_PCRD_OPT
} GRK_RATE_CONTROL_ALGORITHM;

typedef enum GRK_SUPPORTED_FILE_FMT
{
	GRK_UNK_FMT,
	GRK_J2K_FMT,
	GRK_JP2_FMT,
	GRK_PXM_FMT,
	GRK_PGX_FMT,
	GRK_PAM_FMT,
	GRK_BMP_FMT,
	GRK_TIF_FMT,
	GRK_RAW_FMT, /* MSB / Big Endian */
	GRK_PNG_FMT,
	GRK_RAWL_FMT, /* LSB / Little Endian */
	GRK_JPG_FMT
} GRK_SUPPORTED_FILE_FMT;

#define GRK_PATH_LEN 4096 /**< Maximum allowed size for filenames */
#define GRK_MAX_LAYERS 100
#define GRK_MAX_SUPPORTED_IMAGE_PRECISION 16 // maximum supported precision for Grok library

/*
 * note: range for number of decomposition levels is 0-32
 * So, accordingly, range for number of resolutions is 1-33
 * */

#define GRK_J2K_MAX_DECOMP_LVLS 32 /**< Maximum number of decomposition levels authorized */
#define GRK_J2K_MAXRLVLS \
	(GRK_J2K_MAX_DECOMP_LVLS + 1) /**< Maximum number of resolution levels authorized */
#define GRK_J2K_MAXBANDS (3 * GRK_J2K_MAXRLVLS - 2) /**< Maximum number of sub-bands */

// used by dump
#define GRK_IMG_INFO 1 /**< Basic image information provided to the user */
#define GRK_J2K_MH_INFO 2 /**< Codestream information based only on the main header */
#define GRK_J2K_TH_INFO 4 /**< Tile information based on the current tile header */
#define GRK_J2K_TCH_INFO 8 /**< Tile/Component information of all tiles */
#define GRK_J2K_MH_IND 16 /**< Codestream index based only on the main header */
#define GRK_J2K_TH_IND 32 /**< Tile index based on the current tile */
#define GRK_JP2_INFO 128 /**< JP2 file information */
#define GRK_JP2_IND 256 /**< JP2 file index */

#define GRK_CBLKSTY_LAZY 		0x001 /**< Selective arithmetic coding bypass */
#define GRK_CBLKSTY_RESET		0x002 /**< Reset context probabilities on coding pass boundaries */
#define GRK_CBLKSTY_TERMALL 	0x004 /**< Termination on each coding pass */
#define GRK_CBLKSTY_VSC 		0x008 /**< Vertical stripe causal context */
#define GRK_CBLKSTY_PTERM 		0x010 /**< Predictable termination */
#define GRK_CBLKSTY_SEGSYM 		0x020 /**< Segmentation symbols are used */
#define GRK_CBLKSTY_HT 			0x040 /**< high throughput block coding */
#define GRK_CBLKSTY_HT_MIXED 	0x080 /**< high throughput block coding - mixed*/
#define GRK_CBLKSTY_HT_PHLD		0x100 /**< high throughput block coding - placeholder */
#define GRK_JPH_RSIZ_FLAG 		0x4000 /**<for JPH, bit 14 of RSIZ must be set to 1 */

/**
 * JPEG 2000 Profiles, see Table A.10 from 15444-1 (updated in various AMDs)
 *
 * These values help choose the RSIZ value for the JPEG 2000 code stream.
 * The RSIZ value forces various compressing options, as detailed in Table A.10.
 * If GRK_PROFILE_PART2 is chosen, it must be combined with one or more extensions
 * described below.
 *
 *   Example: rsiz = GRK_PROFILE_PART2 | GRK_EXTENSION_MCT;
 *
 * For broadcast profiles, the GRK_PROFILE_X value has to be combined with the target
 * level (3-0 LSB, value between 0 and 11):
 *   Example: rsiz = GRK_PROFILE_BC_MULTI | 0x0005; //level equals 5
 *
 * For IMF profiles, the GRK_PROFILE_X value has to be combined with the target main-level
 * (3-0 LSB, value between 0 and 11) and sub-level (7-4 LSB, value between 0 and 9):
 *   Example: rsiz = GRK_PROFILE_IMF_2K | 0x0040 | 0x0005; // main-level equals 5 and sub-level
 * equals 4
 *
 * */
#define GRK_PROFILE_NONE 0x0000 /** no profile, conform to 15444-1 */
#define GRK_PROFILE_0 0x0001 /** Profile 0 as described in 15444-1,Table A.45 */
#define GRK_PROFILE_1 0x0002 /** Profile 1 as described in 15444-1,Table A.45 */
#define GRK_PROFILE_CINEMA_2K 0x0003 /** 2K cinema profile defined in 15444-1 AMD1 */
#define GRK_PROFILE_CINEMA_4K 0x0004 /** 4K cinema profile defined in 15444-1 AMD1 */
#define GRK_PROFILE_CINEMA_S2K 0x0005 /** Scalable 2K cinema profile defined in 15444-1 AMD2 */
#define GRK_PROFILE_CINEMA_S4K 0x0006 /** Scalable 4K cinema profile defined in 15444-1 AMD2 */
#define GRK_PROFILE_CINEMA_LTS \
	0x0007 /** Long term storage cinema profile defined in 15444-1 AMD2 */
#define GRK_PROFILE_BC_SINGLE 0x0100 /** Single Tile Broadcast profile defined in 15444-1 AMD3 */
#define GRK_PROFILE_BC_MULTI 0x0200 /** Multi Tile Broadcast profile defined in 15444-1 AMD3 */
#define GRK_PROFILE_BC_MULTI_R \
	0x0300 /** Multi Tile Reversible Broadcast profile defined in 15444-1 AMD3 */
#define GRK_PROFILE_BC_MASK 0x030F /** Mask for broadcast profile including main level */
#define GRK_PROFILE_IMF_2K 0x0400 /** 2K Single Tile Lossy IMF profile defined in 15444-1 AMD8 */
#define GRK_PROFILE_IMF_4K 0x0500 /** 4K Single Tile Lossy IMF profile defined in 15444-1 AMD8 */
#define GRK_PROFILE_IMF_8K 0x0600 /** 8K Single Tile Lossy IMF profile defined in 15444-1 AMD8 */
#define GRK_PROFILE_IMF_2K_R \
	0x0700 /** 2K Single/Multi Tile Reversible IMF profile defined in 15444-1 AMD8 */
#define GRK_PROFILE_IMF_4K_R \
	0x0800 /** 4K Single/Multi Tile Reversible IMF profile defined in 15444-1 AMD8 */
#define GRK_PROFILE_IMF_8K_R \
	0x0900 /** 8K Single/Multi Tile Reversible IMF profile defined in 15444-1 AMD8 */
#define GRK_PROFILE_MASK 0x0FFF /** Mask for profile bits */
#define GRK_PROFILE_PART2 0x8000 /** At least 1 extension defined in 15444-2 (Part-2) */
#define GRK_PROFILE_PART2_EXTENSIONS_MASK 0x3FFF // Mask for Part-2 extension bits

/**
 * JPEG 2000 Part-2 extensions
 * */
#define GRK_EXTENSION_NONE 0x0000 /** No Part-2 extension */
#define GRK_EXTENSION_MCT 0x0100 /** Custom MCT support */
#define GRK_IS_PART2(v) ((v)&GRK_PROFILE_PART2)

#define GRK_IS_CINEMA(v) (((v) >= GRK_PROFILE_CINEMA_2K) && ((v) <= GRK_PROFILE_CINEMA_S4K))
#define GRK_IS_STORAGE(v) ((v) == GRK_PROFILE_CINEMA_LTS)

/*
 *
 * *********************************************
 * Broadcast level (3-0 LSB) (15444-1 AMD4,AMD8)
 * *********************************************
 *
 * indicates maximum bit rate and sample rate for a code stream
 *
 * Note: Mbit/s == 10^6 bits/s;  Msamples/s == 10^6 samples/s
 *
 * 0:		no maximum rate
 * 1:		200 Mbits/s, 65  Msamples/s
 * 2:		200 Mbits/s, 130 Msamples/s
 * 3:		200 Mbits/s, 195 Msamples/s
 * 4:		400 Mbits/s, 260 Msamples/s
 * 5:		800Mbits/s,  520 Msamples/s
 * >= 6:	2^(level-6) * 1600 Mbits/s, 2^(level-6) * 1200 Msamples/s
 *
 * Note: level cannot be greater than 11
 *
 * ****************
 * Broadcast tiling
 * ****************
 *
 * Either single-tile or multi-tile. Multi-tile only permits
 * 1 or 4 tiles per frame, where multiple tiles have identical
 * sizes, and are configured in either 2x2 or 1x4 layout.
 *
 *************************************************************
 *
 * ***************************************
 * IMF main-level (3-0) LSB (15444-1 AMD8)
 * ***************************************
 *
 * main-level indicates maximum number of samples per second,
 * as listed above.
 *
 *
 * **************************************
 * IMF sub-level (7-4) LSB (15444-1 AMD8)
 * **************************************
 *
 * sub-level indicates maximum bit rate for a code stream:
 *
 * 0:	no maximum rate
 * >0:	2^sub-level * 100 Mbits/second
 *
 * Note: sub-level cannot be greater than 9, and cannot be larger
 * then maximum of (main-level -2) and 1.
 *
 */
/** Extract profile without mainlevel/sublevel */
#define GRK_GET_IMF_OR_BROADCAST_PROFILE(v) ((v)&0x0f00)

#define GRK_LEVEL_MAX 11U /** Maximum (main) level */
#define GRK_GET_LEVEL(v) ((v)&0xf) /** Extract (main) level */

/******* BROADCAST **********/

#define GRK_IS_BROADCAST(v)                                                          \
	(((v) >= GRK_PROFILE_BC_SINGLE) && ((v) <= (GRK_PROFILE_BC_MULTI_R | 0x000b)) && \
	 (((v)&0xf) <= 0xb))

/* Maximum component sampling Rate (Mbits/sec) per level */
#define GRK_BROADCAST_LEVEL_1_MBITSSEC 200U /** Mbits/sec for level 1 */
#define GRK_BROADCAST_LEVEL_2_MBITSSEC 200U /** Mbits/sec for level 2 */
#define GRK_BROADCAST_LEVEL_3_MBITSSEC 200U /** Mbits/sec for level 3 */
#define GRK_BROADCAST_LEVEL_4_MBITSSEC 400U /** Mbits/sec for level 4 */
#define GRK_BROADCAST_LEVEL_5_MBITSSEC 800U /** Mbits/sec for level 5 */
#define GRK_BROADCAST_LEVEL_6_MBITSSEC 1600U /** Mbits/sec for level 6 */
#define GRK_BROADCAST_LEVEL_7_MBITSSEC 3200U /** Mbits/sec for level 7 */
#define GRK_BROADCAST_LEVEL_8_MBITSSEC 6400U /** Mbits/sec for level 8 */
#define GRK_BROADCAST_LEVEL_9_MBITSSEC 12800U /** Mbits/sec for level 9 */
#define GRK_BROADCAST_LEVEL_10_MBITSSEC 25600U /** Mbits/sec for level 10 */
#define GRK_BROADCAST_LEVEL_11_MBITSSEC 51200U /** Mbits/sec for level 11 */

#define GRK_BROADCAST_LEVEL_1_MSAMPLESSEC 64U /** MSamples/sec for level 1 */
#define GRK_BROADCAST_LEVEL_2_MSAMPLESSEC 130U /** MSamples/sec for level 2 */
#define GRK_BROADCAST_LEVEL_3_MSAMPLESSEC 195U /** MSamples/sec for level 3 */
#define GRK_BROADCAST_LEVEL_4_MSAMPLESSEC 260U /** MSamples/sec for level 4 */
#define GRK_BROADCAST_LEVEL_5_MSAMPLESSEC 520U /** MSamples/sec for level 5 */
#define GRK_BROADCAST_LEVEL_6_MSAMPLESSEC 1200U /** MSamples/sec for level 6 */
#define GRK_BROADCAST_LEVEL_7_MSAMPLESSEC 2400U /** MSamples/sec for level 7 */
#define GRK_BROADCAST_LEVEL_8_MSAMPLESSEC 4800U /** MSamples/sec for level 8 */
#define GRK_BROADCAST_LEVEL_9_MSAMPLESSEC 9600U /** MSamples/sec for level 9 */
#define GRK_BROADCAST_LEVEL_10_MSAMPLESSEC 19200U /** MSamples/sec for level 10 */
#define GRK_BROADCAST_LEVEL_11_MSAMPLESSEC 38400U /** MSamples/sec for level 11 */

/********IMF ***********************************************************************/

#define GRK_IS_IMF(v)                                                           \
	(((v) >= GRK_PROFILE_IMF_2K) && ((v) <= (GRK_PROFILE_IMF_8K_R | 0x009b)) && \
	 (((v)&0xf) <= 0xb) && (((v)&0xf0) <= 0x90))

/* Maximum component sampling rate (MSamples/sec) per main level */
#define GRK_IMF_MAINLEVEL_1_MSAMPLESSEC 65U /** MSamples/sec for main level 1 */
#define GRK_IMF_MAINLEVEL_2_MSAMPLESSEC 130U /** MSamples/sec for main level 2 */
#define GRK_IMF_MAINLEVEL_3_MSAMPLESSEC 195U /** MSamples/sec for main level 3 */
#define GRK_IMF_MAINLEVEL_4_MSAMPLESSEC 260U /** MSamples/sec for main level 4 */
#define GRK_IMF_MAINLEVEL_5_MSAMPLESSEC 520U /** MSamples/sec for main level 5 */
#define GRK_IMF_MAINLEVEL_6_MSAMPLESSEC 1200U /** MSamples/sec for main level 6 */
#define GRK_IMF_MAINLEVEL_7_MSAMPLESSEC 2400U /** MSamples/sec for main level 7 */
#define GRK_IMF_MAINLEVEL_8_MSAMPLESSEC 4800U /** MSamples/sec for main level 8 */
#define GRK_IMF_MAINLEVEL_9_MSAMPLESSEC 9600U /** MSamples/sec for main level 9 */
#define GRK_IMF_MAINLEVEL_10_MSAMPLESSEC 19200U /** MSamples/sec for main level 10 */
#define GRK_IMF_MAINLEVEL_11_MSAMPLESSEC 38400U /** MSamples/sec for main level 11 */

#define GRK_IMF_SUBLEVEL_MAX 9U /** Maximum IMF sublevel */
#define GRK_GET_IMF_SUBLEVEL(v) (((v) >> 4) & 0xf) /** Extract IMF sub level */

/** Maximum compressed bit rate (Mbits/s) per IMF sub level */
#define GRK_IMF_SUBLEVEL_1_MBITSSEC 200U /** Mbits/s for IMF sub level 1 */
#define GRK_IMF_SUBLEVEL_2_MBITSSEC 400U /** Mbits/s for IMF sub level 2 */
#define GRK_IMF_SUBLEVEL_3_MBITSSEC 800U /** Mbits/s for IMF sub level 3 */
#define GRK_IMF_SUBLEVEL_4_MBITSSEC 1600U /** Mbits/s for IMF sub level 4 */
#define GRK_IMF_SUBLEVEL_5_MBITSSEC 3200U /** Mbits/s for IMF sub level 5 */
#define GRK_IMF_SUBLEVEL_6_MBITSSEC 6400U /** Mbits/s for IMF sub level 6 */
#define GRK_IMF_SUBLEVEL_7_MBITSSEC 12800U /** Mbits/s for IMF sub level 7 */
#define GRK_IMF_SUBLEVEL_8_MBITSSEC 25600U /** Mbits/s for IMF sub level 8 */
#define GRK_IMF_SUBLEVEL_9_MBITSSEC 51200U /** Mbits/s for IMF sub level 9 */
/**********************************************************************************/

/**
 * JPEG 2000 cinema profile code stream and component size limits
 * */
#define GRK_CINEMA_24_CS 1302083U /** Maximum code stream length @ 24fps */
#define GRK_CINEMA_48_CS 651041U /** Maximum code stream length @ 48fps */
#define GRK_CINEMA_24_COMP 1041666U /** Maximum size per color component @ 24fps */
#define GRK_CINEMA_48_COMP 520833U /** Maximum size per color component @ 48fps */

/**
 * Progression order
 * */
typedef enum _GRK_PROG_ORDER
{
	GRK_PROG_UNKNOWN = -1, /**< place-holder */
	GRK_LRCP = 0, /**< layer-resolution-component-precinct order */
	GRK_RLCP = 1, /**< resolution-layer-component-precinct order */
	GRK_RPCL = 2, /**< resolution-precinct-component-layer order */
	GRK_PCRL = 3, /**< precinct-component-resolution-layer order */
	GRK_CPRL = 4, /**< component-precinct-resolution-layer order */
	GRK_NUM_PROGRESSION_ORDERS = 5 /** number of possible progression orders */
} GRK_PROG_ORDER;

/*
 *
 * CIE Lab #defines
 */
#define GRK_CUSTOM_CIELAB_SPACE 0x0
#define GRK_DEFAULT_CIELAB_SPACE 0x44454600 //'DEF'
#define GRK_CIE_DAY ((((uint32_t)'C') << 24) + (((uint32_t)'T') << 16))
#define GRK_CIE_D50 ((uint32_t)0x00443530)
#define GRK_CIE_D65 ((uint32_t)0x00443635)
#define GRK_CIE_D75 ((uint32_t)0x00443735)
#define GRK_CIE_SA ((uint32_t)0x00005341)
#define GRK_CIE_SC ((uint32_t)0x00005343)
#define GRK_CIE_F2 ((uint32_t)0x00004632)
#define GRK_CIE_F7 ((uint32_t)0x00004637)
#define GRK_CIE_F11 ((uint32_t)0x00463131)

/**
 * Supported color spaces
 * */
typedef enum _GRK_COLOR_SPACE
{
	GRK_CLRSPC_UNKNOWN = 0, /**< unknown */
	GRK_CLRSPC_SRGB = 2, /**< sRGB */
	GRK_CLRSPC_GRAY = 3, /**< grayscale */
	GRK_CLRSPC_SYCC = 4, /**< standard YCC (YUV) */
	GRK_CLRSPC_EYCC = 5, /**< extended YCC */
	GRK_CLRSPC_CMYK = 6, /**< CMYK */
	GRK_CLRSPC_DEFAULT_CIE = 7, /**< default CIE LAB */
	GRK_CLRSPC_CUSTOM_CIE = 8, /**< custom CIE LAB */
	GRK_CLRSPC_ICC = 9 /**< ICC profile */
} GRK_COLOR_SPACE;

/* JPEG 2000 standard colour space enumeration */
typedef enum GRK_ENUM_COLOUR_SPACE
{
	GRK_ENUM_CLRSPC_UNKNOWN = 0xFFFFFFFF,
	GRK_ENUM_CLRSPC_BILEVEL1 = 0,
	GRK_ENUM_CLRSPC_YCBCR1 = 1,
	GRK_ENUM_CLRSPC_YCBCR2 = 3,
	GRK_ENUM_CLRSPC_YCBCR3 = 4,
	GRK_ENUM_CLRSPC_PHOTO_YCC = 9, // Kodak PhotoYCC
	GRK_ENUM_CLRSPC_CMY = 11, // cyan, magenta, yellow
	GRK_ENUM_CLRSPC_CMYK = 12, // cyan, magenta, yellow, black
	GRK_ENUM_CLRSPC_YCCK = 13,
	GRK_ENUM_CLRSPC_CIE = 14,
	GRK_ENUM_CLRSPC_BILEVEL2 = 15,
	GRK_ENUM_CLRSPC_SRGB = 16,
	GRK_ENUM_CLRSPC_GRAY = 17,
	GRK_ENUM_CLRSPC_SYCC = 18, // standard YCC
	GRK_ENUM_CLRSPC_CIEJAB = 19,
	GRK_ENUM_CLRSPC_ESRGB = 20,
	GRK_ENUM_CLRSPC_ROMMRGB = 21, // Reference Output Medium Metric RGB
	GRK_ENUM_CLRSPC_YPBPR60 = 22,
	GRK_ENUM_CLRSPC_YPBPR50 = 23,
	GRK_ENUM_CLRSPC_EYCC = 24, // extended YCC
} GRK_ENUM_COLOUR_SPACE;

/**
 * Supported codecs
 */
typedef enum _GRK_CODEC_FORMAT
{
	GRK_CODEC_UNKNOWN = -1, /**< place-holder */
	GRK_CODEC_J2K = 0, /**< JPEG 2000 code stream : read/write */
	GRK_CODEC_JP2 = 2 /**< JP2 file format : read/write */
} GRK_CODEC_FORMAT;

#define GRK_NUM_COMMENTS_SUPPORTED 256
#define GRK_NUM_ASOC_BOXES_SUPPORTED 256
#define GRK_MAX_COMMENT_LENGTH (UINT16_MAX - 2)

typedef enum GRK_TILE_CACHE_STRATEGY
{
	GRK_TILE_CACHE_NONE,
	GRK_TILE_CACHE_ALL,
} GRK_TILE_CACHE_STRATEGY;

/**
 * Callback function prototype for logging
 *
 * @param msg               Event message
 * @param client_data       Client object where will be return the event message
 * */
typedef void (*grk_msg_callback)(const char* msg, void* client_data);

/**
 *
 * Base Grok ref-counted object
 *
 */
typedef struct _grk_object
{
	void* wrapper;
} grk_object;

/**
 * Progression order change
 *
 */
typedef struct _grk_progression
{
	/** progression order bounds specified by POC */
	uint16_t layS;
	uint16_t layE;
	uint8_t resS;
	uint8_t resE;
	uint16_t compS;
	uint16_t compE;
	uint64_t precS;
	uint64_t precE;

	/** Progression order enum*/
	GRK_PROG_ORDER specifiedCompressionPocProg;
	GRK_PROG_ORDER progression;
	/** Progression order string*/
	char progressionString[5];
	/** Tile number */
	uint32_t tileno;
	/** Start and end values for tile width and height*/
	uint32_t tx0;
	uint32_t tx1;
	uint32_t ty0;
	uint32_t ty1;
	/** progression order bounds initialized in pi_create_compress*/
	uint16_t tpLayE;
	uint8_t tpResS;
	uint8_t tpResE;
	uint16_t tpCompS;
	uint16_t tpCompE;
	uint64_t tpPrecE;
	/** tile bounds initialized by pi_create_compress*/
	uint32_t tp_txS;
	uint32_t tp_txE;
	uint32_t tp_tyS;
	uint32_t tp_tyE;
	uint32_t dx;
	uint32_t dy;
	/** tile part temporary values initialized by pi_create_encode */
	uint16_t lay_temp;
	uint8_t res_temp;
	uint16_t comp_temp;
	uint64_t prec_temp;
	uint32_t tx0_temp;
	uint32_t ty0_temp;
} grk_progression;

/**@name RAW component compress parameters */
/*@{*/
typedef struct _grk_raw_comp_cparameters
{
	uint32_t dx; /** subsampling in X direction */
	uint32_t dy; /** subsampling in Y direction */
	/*@}*/
} grk_raw_comp_cparameters;

/**@name RAW image compress parameters */
/*@{*/
typedef struct _grk_raw_cparameters
{
	uint32_t width; /** width of the raw image */
	uint32_t height; /** height of the raw image */
	uint16_t numcomps; /** number of components of the raw image */
	uint8_t prec; /** bit depth of the raw image */
	bool sgnd; /** signed/unsigned raw image */
	grk_raw_comp_cparameters* comps; /** raw components parameters */
	/*@}*/
} grk_raw_cparameters;

/**
 * Compress parameters
 * */
typedef struct _grk_cparameters
{
	/** size of tile: tile_size_on = false (not in argument) or = true (in argument) */
	bool tile_size_on;
	/** XTOsiz */
	uint32_t tx0;
	/** YTOsiz */
	uint32_t ty0;
	/** XTsiz */
	uint32_t t_width;
	/** YTsiz */
	uint32_t t_height;
	/** number of layers */
	uint16_t numlayers;
	/** rate control allocation by rate/distortion curve */
	bool allocationByRateDistoration;
	/** layers rates expressed as compression ratios.
	 *  They might be subsequently limited by the max_cs_size field */
	double layer_rate[GRK_MAX_LAYERS];
	/** rate control allocation by fixed_PSNR quality */
	bool allocationByQuality;
	/** layer PSNR values */
	double layer_distortion[GRK_MAX_LAYERS];
	char* comment[GRK_NUM_COMMENTS_SUPPORTED];
	uint16_t comment_len[GRK_NUM_COMMENTS_SUPPORTED];
	bool is_binary_comment[GRK_NUM_COMMENTS_SUPPORTED];
	size_t num_comments;
	/** csty : coding style */
	uint8_t csty;
	/* number of guard bits */
	uint8_t numgbits;
	/** progression order (default is LRCP) */
	GRK_PROG_ORDER prog_order;
	/** progressions */
	grk_progression progression[GRK_J2K_MAXRLVLS];
	/** number of progression order changes (POCs), default to 0 */
	uint32_t numpocs;
	/** number of resolutions */
	uint8_t numresolution;
	/** initial code block width  (default to 64) */
	uint32_t cblockw_init;
	/** initial code block height (default to 64) */
	uint32_t cblockh_init;
	/** code block style */
	uint8_t cblk_sty;
	/* flag for high throughput */
	bool isHT;
	/** 1 : use the irreversible DWT 9-7, 0 :
	 *  use lossless compression (default) */
	bool irreversible;
	/** region of interest: affected component in [0..3];
	 *  -1 indicates no ROI */
	int32_t roi_compno;
	/** region of interest: upshift value */
	uint32_t roi_shift;
	/* number of precinct size specifications */
	uint32_t res_spec;
	/** initial precinct width */
	uint32_t prcw_init[GRK_J2K_MAXRLVLS];
	/** initial precinct height */
	uint32_t prch_init[GRK_J2K_MAXRLVLS];
	/** input file name */
	char infile[GRK_PATH_LEN];
	/** output file name */
	char outfile[GRK_PATH_LEN];
	/** subimage compressing: origin image offset in x direction */
	uint32_t image_offset_x0;
	/** subimage compressing: origin image offset in y direction */
	uint32_t image_offset_y0;
	/** subsampling value for dx */
	uint32_t subsampling_dx;
	/** subsampling value for dy */
	uint32_t subsampling_dy;
	/** input file format*/
	GRK_SUPPORTED_FILE_FMT decod_format;
	/** output file format*/
	GRK_SUPPORTED_FILE_FMT cod_format;
	grk_raw_cparameters raw_cp;
	/**
	 * Maximum size (in bytes) for each component.
	 * If == 0, component size limitation is not considered
	 * */
	uint32_t max_comp_size;
	/** Tile part generation*/
	bool enableTilePartGeneration;
	/** new tile part progression divider */
	uint8_t newTilePartProgressionDivider;
	/** MCT (multiple component transform) */
	uint8_t mct;
	/** Naive implementation of MCT restricted to a single reversible array based
	 compressing without offset concerning all the components. */
	void* mct_data;
	/**
	 * Maximum size (in bytes) for the whole code stream.
	 * If equal to zero, code stream size limitation is not considered
	 * If it does not comply with layer_rate, max_cs_size prevails
	 * and a warning is issued.
	 * */
	uint64_t max_cs_size;
	/** RSIZ value
	 To be used to combine GRK_PROFILE_*, GRK_EXTENSION_* and (sub)levels values. */
	uint16_t rsiz;
	uint16_t framerate;

	// set to true if input file stores capture resolution
	bool write_capture_resolution_from_file;
	double capture_resolution_from_file[2];

	bool write_capture_resolution;
	double capture_resolution[2];

	bool write_display_resolution;
	double display_resolution[2];

	// 0: bisect with all truncation points
	// 1: bisect with only feasible truncation points
	GRK_RATE_CONTROL_ALGORITHM rateControlAlgorithm;
	uint32_t numThreads;
	int32_t deviceId;
	uint32_t duration; // seconds
	uint32_t kernelBuildOptions;
	uint32_t repeats;
	bool writePLT;
	bool writeTLM;
	bool verbose;
} grk_cparameters;

/**
 Channel definition: channel index, type, association
 */
typedef struct _grk_channel_description
{
	uint16_t cn;
	uint16_t typ;
	uint16_t asoc;
} grk_channel_description;

/**
 Channel definitions and number of definitions
 */
typedef struct _grk_channel_definition
{
	grk_channel_description* descriptions;
	uint16_t num_channel_descriptions;
} grk_channel_definition;

/**
 Component mappings: component index, mapping type, palette column
 */
typedef struct _grk_component_mapping_comp
{
	uint16_t component_index;
	uint8_t mapping_type;
	uint8_t palette_column;
} grk_component_mapping_comp;

/**
 Palette data
 */
typedef struct _grk_palette_data
{
	int32_t* lut;
	uint16_t num_entries;
	grk_component_mapping_comp* component_mapping;
	uint8_t num_channels;
	bool* channel_sign;
	uint8_t* channel_prec;
} grk_palette_data;

/**
 ICC profile, palette, channel definition
 */
typedef struct grk_color
{
	uint8_t* icc_profile_buf;
	uint32_t icc_profile_len;
	grk_channel_definition* channel_definition;
	grk_palette_data* palette;
	bool has_colour_specification_box;
} grk_color;

typedef struct grk_asoc
{
	uint32_t level; // 0 for root level
	const char* label;
	uint8_t* xml;
	uint32_t xml_len;
} grk_asoc;

/**
 * Header info
 */
typedef struct _grk_header_info
{
	/** initial code block width, default to 64 */
	uint32_t cblockw_init;
	/** initial code block height, default to 64 */
	uint32_t cblockh_init;
	/** 1 : use the irreversible DWT 9-7, 0 : use lossless compression (default) */
	bool irreversible;
	/** multi-component transform identifier */
	uint32_t mct;
	/** RSIZ value
	 To be used to combine GRK_PROFILE_*, GRK_EXTENSION_* and (sub)levels values. */
	uint16_t rsiz;
	/** number of resolutions */
	uint32_t numresolutions;
	// coding style can be specified in main header COD segment,
	// tile header COD segment, and tile component COC segment.
	// !!! Assume that coding style does not vary across tile components !!!
	uint8_t csty;
	// code block style is specified in main header COD segment, and can
	// be overridden in a tile header. !!! Assume that style does
	// not vary across tiles !!!
	uint8_t cblk_sty;
	/** initial precinct width */
	uint32_t prcw_init[GRK_J2K_MAXRLVLS];
	/** initial precinct height */
	uint32_t prch_init[GRK_J2K_MAXRLVLS];
	/** XTOsiz */
	uint32_t tx0;
	/** YTOsiz */
	uint32_t ty0;
	/** XTsiz */
	uint32_t t_width;
	/** YTsiz */
	uint32_t t_height;
	/** tile grid width */
	uint32_t t_grid_width;
	/** tile grid height  */
	uint32_t t_grid_height;
	/** number of layers */
	uint16_t numlayers;

	// note: xml_data will remain valid
	// until codec is destroyed
	uint8_t* xml_data;
	size_t xml_data_len;
	size_t num_comments;
	char* comment[GRK_NUM_COMMENTS_SUPPORTED];
	uint16_t comment_len[GRK_NUM_COMMENTS_SUPPORTED];
	bool isBinaryComment[GRK_NUM_COMMENTS_SUPPORTED];

	grk_asoc asocs[GRK_NUM_ASOC_BOXES_SUPPORTED];
	uint32_t num_asocs;

} grk_header_info;

/**
 * Core decompress parameters
 * */
typedef struct _grk_dparameters
{
	/**
	 Set the number of highest resolution levels to be discarded.
	 The image resolution is effectively divided by 2 to the power of the number of discarded
	 levels. The reduce factor is limited by the smallest total number of decomposition levels among
	 tiles. if greater than zero, then image is decoded to original dimension divided by
	 2^(cp_reduce); if equal to zero or not used, image is decompressed to full resolution
	 */
	uint8_t cp_reduce;
	/**
	 Set the maximum number of quality layers to decompress.
	 If there are fewer quality layers than the specified number, all quality layers will be
	 decompressed. if != 0, then only the first "layer" layers are decompressed; if == 0 or not
	 used, all the quality layers are decompressed
	 */
	uint16_t cp_layer;
	/** input file name */
	char infile[GRK_PATH_LEN];
	/** output file name */
	char outfile[GRK_PATH_LEN];
	/** input file format*/
	GRK_SUPPORTED_FILE_FMT decod_format;
	/** output file format*/
	GRK_SUPPORTED_FILE_FMT cod_format;
	/** Decompress window left boundary */
	uint32_t DA_x0;
	/** Decompress window right boundary */
	uint32_t DA_x1;
	/** Decompress window up boundary */
	uint32_t DA_y0;
	/** Decompress window bottom boundary */
	uint32_t DA_y1;
	/** Verbose mode */
	bool m_verbose;
	/** tile number of the decompressed tile*/
	uint16_t tileIndex;
	/** Number of tiles to decompress */
	uint32_t nb_tile_to_decompress;
	uint32_t flags;
	GRK_TILE_CACHE_STRATEGY tileCacheStrategy;
} grk_dparameters;

/**
 * Precision mode
 */
typedef enum grk_prec_mode
{
	GRK_PREC_MODE_CLIP,
	GRK_PREC_MODE_SCALE
} grk_precision_mode;

/**
 * Precision
 */
typedef struct _grk_prec
{
	uint8_t prec;
	grk_precision_mode mode;
} grk_precision;

#define GRK_DECOMPRESS_COMPRESSION_LEVEL_DEFAULT (UINT_MAX)

/**
 * Decompress parameters
 */
typedef struct _grk_decompress_params
{
	/** core library parameters */
	grk_dparameters core;
	/** input file name */
	char infile[GRK_PATH_LEN];
	/** output file name */
	char outfile[GRK_PATH_LEN];
	/** input file format 0: J2K, 1: JP2*/
	GRK_SUPPORTED_FILE_FMT decod_format;
	/** output file format 0: PGX, 1: PxM, 2: BMP */
	GRK_SUPPORTED_FILE_FMT cod_format;
	/** index file name */
	char indexfilename[GRK_PATH_LEN];
	/** Decompress window left boundary */
	uint32_t DA_x0;
	/** Decompress window right boundary */
	uint32_t DA_x1;
	/** Decompress window up boundary */
	uint32_t DA_y0;
	/** Decompress window bottom boundary */
	uint32_t DA_y1;
	/** Verbose mode */
	bool m_verbose;
	/** tile number of the decompressed tile*/
	uint16_t tileIndex;
	/** Number of tiles to decompress */
	uint32_t nb_tile_to_decompress;
	grk_precision* precision;
	uint32_t nb_precision;
	/* force output colorspace to RGB */
	bool force_rgb;
	/* upsample components according to their dx/dy values */
	bool upsample;
	/* split output components to different files */
	bool split_pnm;
	/* serialize XML metadata to disk */
	bool serialize_xml;
	uint32_t compression;
	// compression "quality". Meaning of "quality" depends
	// on file format we are writing to
	uint32_t compressionLevel;
	int32_t deviceId;
	uint32_t duration; // seconds
	uint32_t kernelBuildOptions;
	uint32_t repeats;
	bool verbose;
	uint32_t numThreads;
} grk_decompress_parameters;

typedef grk_object grk_codec;

/*
 ==========================================================
 I/O stream typedef definitions
 ==========================================================
 */

/*
 * Callback function prototype for read function
 *
 */
typedef size_t (*grk_stream_read_fn)(void* buffer, size_t numBytes, void* user_data);

/*
 * Callback function prototype for write function
 */
typedef size_t (*grk_stream_write_fn)(void* buffer, size_t numBytes, void* user_data);
/*
 * Callback function prototype for (absolute) seek function.
 */
typedef bool (*grk_stream_seek_fn)(uint64_t numBytes, void* user_data);
/*
 * Callback function prototype for free user data function
 */
typedef void (*grk_stream_free_user_data_fn)(void* user_data);
/*
 * JPEG 2000 stream.
 */
typedef grk_object grk_stream;

/*
 ==============================
 image typedef definitions
 ==============================
 */

// component type
typedef enum GRK_COMPONENT_TYPE
{

	GRK_COMPONENT_TYPE_COLOUR = 0,
	GRK_COMPONENT_TYPE_OPACITY = 1,
	GRK_COMPONENT_TYPE_PREMULTIPLIED_OPACITY = 2,
	GRK_COMPONENT_TYPE_UNSPECIFIED = 65535U

} GRK_COMPONENT_TYPE;

// component association
typedef enum GRK_COMPONENT_ASSOC
{

	GRK_COMPONENT_ASSOC_WHOLE_IMAGE = 0,
	GRK_COMPONENT_ASSOC_COLOUR_1 = 1,
	GRK_COMPONENT_ASSOC_COLOUR_2 = 2,
	GRK_COMPONENT_ASSOC_COLOUR_3 = 3,
	GRK_COMPONENT_ASSOC_UNASSOCIATED = 65535U

} GRK_COMPONENT_ASSOC;

/**
 * Image component
 * */
typedef struct _grk_image_comp
{
	grk_object obj;
	/** XRsiz: horizontal separation of a sample of with component with respect to the reference
	 * grid */
	uint32_t dx;
	/** YRsiz: vertical separation of a sample of with component with respect to the reference grid
	 */
	uint32_t dy;
	/** data width */
	uint32_t w;
	/** data stride */
	uint32_t stride;
	/** data height */
	uint32_t h;
	/** x component offset compared to the whole image */
	uint32_t x0;
	/** y component offset compared to the whole image */
	uint32_t y0;
	// component registration coordinates
	uint16_t Xcrg, Ycrg;
	/** precision */
	uint8_t prec;
	bool sgnd;
	/** image component data */
	int32_t* data;
	GRK_COMPONENT_TYPE type;
	GRK_COMPONENT_ASSOC association;
} grk_image_comp;

// Image meta data: colour, IPTC and XMP
typedef struct _grk_image_meta
{
	grk_object obj;
	grk_color color;
	uint8_t* iptc_buf;
	size_t iptc_len;
	uint8_t* xmp_buf;
	size_t xmp_len;
} grk_image_meta;

typedef struct _grk_image
{
	grk_object obj;
	/** XOsiz: horizontal offset from the origin of the reference grid
	 *  to the left side of the image area */
	uint32_t x0;
	/** YOsiz: vertical offset from the origin of the reference grid
	 *  to the top side of the image area */
	uint32_t y0;
	/** Xsiz: width of the reference grid */
	uint32_t x1;
	/** Ysiz: height of the reference grid */
	uint32_t y1;
	/** number of components in the image */
	uint16_t numcomps;
	GRK_COLOR_SPACE color_space;
	bool color_applied;
	bool has_capture_resolution;
	double capture_resolution[2];
	bool has_display_resolution;
	double display_resolution[2];
	grk_image_meta* meta;
	grk_image_comp* comps;
} grk_image;

/**
 * Image component parameters
 * */
typedef struct _grk_image_comptparm
{
	/** XRsiz: horizontal separation of a sample of component
	 *  with respect to the reference grid */
	uint32_t dx;
	/** YRsiz: vertical separation of a sample of component
	 *  with respect to the reference grid */
	uint32_t dy;
	/** data width */
	uint32_t w;
	/* data stride */
	uint32_t stride;
	/** data height */
	uint32_t h;
	/** x component offset compared to the whole image */
	uint32_t x0;
	/** y component offset compared to the whole image */
	uint32_t y0;
	/** precision */
	uint8_t prec;
	/** true if data is signed */
	bool sgnd;
} grk_image_cmptparm;

////////////////////////////////////////////////
// Structs to pass data between grok and plugin
/////////////////////////////////////////////////

/**
 * Plugin pass
 */
typedef struct _grk_plugin_pass
{
	double distortionDecrease; // distortion decrease up to and including this pass
	size_t rate; // rate up to and including this pass
	size_t length; // stream length for this pass
} grk_plugin_pass;

/**
 * Plugin code block
 */
typedef struct _grk_plugin_code_block
{
	/////////////////////////
	// debug info
	uint32_t x0, y0, x1, y1;
	unsigned int* contextStream;
	///////////////////////////
	uint32_t numPix;
	uint8_t* compressedData;
	uint32_t compressedDataLength;
	uint8_t numBitPlanes;
	size_t numPasses;
	grk_plugin_pass passes[67];
	unsigned int sortedIndex;
} grk_plugin_code_block;

/**
 * Plugin precinct
 */
typedef struct _grk_plugin_precinct
{
	uint64_t numBlocks;
	grk_plugin_code_block** blocks;
} grk_plugin_precinct;

/**
 * Plugin band
 */
typedef struct _grk_plugin_band
{
	uint8_t orientation;
	uint64_t numPrecincts;
	grk_plugin_precinct** precincts;
	float stepsize;
} grk_plugin_band;

/**
 * Plugin resolution
 */
typedef struct _grk_plugin_resolution
{
	size_t level;
	size_t numBands;
	grk_plugin_band** band;
} grk_plugin_resolution;

/**
 * Plugin tile component
 */
typedef struct grk_plugin_tile_component
{
	size_t numResolutions;
	grk_plugin_resolution** resolutions;
} grk_plugin_tile_component;

#define GRK_DECODE_HEADER (1 << 0)
#define GRK_DECODE_T2 (1 << 1)
#define GRK_DECODE_T1 (1 << 2)
#define GRK_DECODE_POST_T1 (1 << 3)
#define GRK_PLUGIN_DECODE_CLEAN (1 << 4)
#define GRK_DECODE_ALL                                                             \
	(GRK_PLUGIN_DECODE_CLEAN | GRK_DECODE_HEADER | GRK_DECODE_T2 | GRK_DECODE_T1 | \
	 GRK_DECODE_POST_T1)

/**
 * Plugin tile
 */
typedef struct _grk_plugin_tile
{
	uint32_t decompress_flags;
	size_t numComponents;
	grk_plugin_tile_component** tileComponents;
} grk_plugin_tile;

/**
 * library version
 */
GRK_API const char* GRK_CALLCONV grk_version(void);

/**
 * Initialize library
 *
 * @param pluginPath 	path to plugin
 * @param numthreads 	number of threads to use for compress/decompress
 */
GRK_API bool GRK_CALLCONV grk_initialize(const char* pluginPath, uint32_t numthreads);

/**
 * De-initialize library
 */
GRK_API void GRK_CALLCONV grk_deinitialize();

/**
 * Increment ref count
 */
GRK_API void GRK_CALLCONV grk_object_ref(grk_object* obj);

/*
 * Decrement ref count
 *
 */
GRK_API void GRK_CALLCONV grk_object_unref(grk_object* obj);

/**
 * Set info handler
 *
 * @param p_callback    the callback function which will be used
 * @param user_data   client object where will be returned the message
 */
GRK_API bool GRK_CALLCONV grk_set_info_handler(grk_msg_callback p_callback, void* user_data);
/**
 * Set warning handler
 *
 * @param p_callback    the callback function which will be used
 * @param user_data   client object where will be returned the message
 */
GRK_API bool GRK_CALLCONV grk_set_warning_handler(grk_msg_callback p_callback, void* user_data);
/**
 * Set error handler
 *
 * @param p_callback    the callback function which will be used
 * @param user_data   client object where will be returned the message
 */
GRK_API bool GRK_CALLCONV grk_set_error_handler(grk_msg_callback p_callback, void* user_data);

/**
 * Create image
 *
 * @param numcmpts      number of components
 * @param cmptparms     component parameters
 * @param clrspc        image color space
 * @param allocData		true if data is to be allocated, otherwise false
 *
 * @return returns      a new image if successful, otherwise nullptr
 * */
GRK_API grk_image* GRK_CALLCONV grk_image_new(uint16_t numcmpts, grk_image_cmptparm* cmptparms,
											  GRK_COLOR_SPACE clrspc, bool allocData);

GRK_API grk_image_meta* GRK_CALLCONV grk_image_meta_new(void);

/**
 * Deallocate all component data for an image
 *
 * @param image         image
 */
GRK_API void GRK_CALLCONV grk_image_all_components_data_free(grk_image* image);

/**
 * Deallocate data for single image component
 *
 * @param image         image
 */
GRK_API void GRK_CALLCONV grk_image_single_component_data_free(grk_image_comp* image);

/**
 * Create an abstract stream. This function does nothing except
 * allocate memory and initialize abstract stream.
 *
 * @param	buffer_size   size of stream's double-buffer
 * @param	is_input	  if set to true then the stream will be
 *  an input stream, an output stream else.
 *
 * @return	stream object.
 */
GRK_API grk_stream* GRK_CALLCONV grk_stream_new(size_t buffer_size, bool is_input);

/**
 * Set the given function to be used as a read function.
 *
 * @param		stream	the stream to modify
 * @param		p_function	the function to use a read function.
 */
GRK_API void GRK_CALLCONV grk_stream_set_read_function(grk_stream* stream,
													   grk_stream_read_fn p_function);

/**
 * Set the given function to be used as a write function.
 *
 * @param		stream	the stream to modify
 * @param		p_function	the function to use a write function.
 */
GRK_API void GRK_CALLCONV grk_stream_set_write_function(grk_stream* stream,
														grk_stream_write_fn p_function);

/**
 * Set the given function to be used as a seek function, the stream is then seekable.
 *
 * @param		stream	the stream to modify
 * @param		p_function	the function to use a skip function.
 */
GRK_API void GRK_CALLCONV grk_stream_set_seek_function(grk_stream* stream,
													   grk_stream_seek_fn p_function);

/**
 * Set the given data to be used as a user data for the stream.
 *
 * @param		stream	the stream to modify
 * @param		data		the data to set.
 * @param		p_function	the function to free data when grk_object_unref() is called.
 */
GRK_API void GRK_CALLCONV grk_stream_set_user_data(grk_stream* stream, void* data,
												   grk_stream_free_user_data_fn p_function);

/**
 * Set the length of the user data for the stream.
 *
 * @param stream    the stream to modify
 * @param data_length length of the user_data.
 */
GRK_API void GRK_CALLCONV grk_stream_set_user_data_length(grk_stream* stream, uint64_t data_length);

/** Create stream from a file identified with its filename with a specific buffer size
 *
 * @param fname             the filename of the file to stream
 * @param buffer_size     size of the chunk used to stream
 * @param is_read_stream  whether the stream is a read stream (true) or not (false)
 */
GRK_API grk_stream* GRK_CALLCONV grk_stream_create_file_stream(const char* fname,
															   size_t buffer_size,
															   bool is_read_stream);

/** Create stream from buffer
 *
 * @param buf			buffer
 * @param buffer_len    length of buffer
 * @param ownsBuffer	if true, library will delete[] buffer. Otherwise, it is the caller's
 *						responsibility to delete the buffer
 * @param is_read_stream  whether the stream is a read stream (true) or not (false)
 */
GRK_API grk_stream* GRK_CALLCONV grk_stream_create_mem_stream(uint8_t* buf, size_t buffer_len,
															  bool ownsBuffer, bool is_read_stream);

/**
 * Get length of memory stream
 *
 * @param stream memory stream
 */
GRK_API size_t GRK_CALLCONV grk_stream_get_write_mem_stream_length(grk_stream* stream);

/**
 * Create mapped file stream
 *
 * @param fname			file name
 * @param read_stream 	true if this is a read stream, otherwise false
 */
GRK_API grk_stream* GRK_CALLCONV grk_stream_create_mapped_file_stream(const char* fname,
																	  bool read_stream);

/**
 * Create J2K/JP2 decompression structure
 *
 * @param format 		JPEG 2000 format
 * @param	stream	JPEG 2000 stream.
 *
 * @return a handle to a decompressor if successful, otherwise nullptr
 * */
GRK_API grk_codec* GRK_CALLCONV grk_decompress_create(GRK_CODEC_FORMAT format, grk_stream* stream);

/**
 * Initialize decompress parameters with default values
 *
 * @param parameters decompression parameters
 */
GRK_API void GRK_CALLCONV grk_decompress_set_default_params(grk_dparameters* parameters);

/**
 * Set up the decompressor with decompress parameters
 *
 * @param codec 		decompressor handler
 * @param parameters 	decompression parameters
 *
 * @return true			if the decompressor is correctly set
 */
GRK_API bool GRK_CALLCONV grk_decompress_init(grk_codec* codec, grk_dparameters* parameters);

/**
 * Decompress JPEG 2000 header
 *
 * @param	codec				JPEG 2000 code stream to read.
 * @param	header_info			information read from JPEG 2000 header.
 * @param	image				the image structure initialized with the characteristics
 *								of encoded image.
 * @return true					if the main header of the code stream and the JP2 header
 * 							 	is correctly read.
 */
GRK_API bool GRK_CALLCONV grk_decompress_read_header(grk_codec* codec,
													 grk_header_info* header_info);

/**
 * Get decompressed tile image
 *
 * @param	codec				JPEG 2000 code stream to read.
 * @param	tileIndex			tile index
 *
 * @return pointer to decompressed image
 */
GRK_API grk_image* GRK_CALLCONV grk_decompress_get_tile_image(grk_codec* codec, uint16_t tileIndex);

/**
 * Get decompressed composite image
 *
 * @param	codec				JPEG 2000 code stream to read.
 *
 * @return pointer to decompressed image
 */
GRK_API grk_image* GRK_CALLCONV grk_decompress_get_composited_image(grk_codec* codec);

/**
 * Set the given area to be decompressed. This function should be called
 *  right after grk_decompress_read_header is called, and before any tile header is read.
 *
 * @param	codec			JPEG 2000 code stream.
 * @param	start_x		    left position of the rectangle to decompress (in image coordinates).
 * @param	end_x			the right position of the rectangle to decompress (in image
 * coordinates).
 * @param	start_y		    up position of the rectangle to decompress (in image coordinates).
 * @param	end_y			bottom position of the rectangle to decompress (in image coordinates).
 *
 * @return	true			if the area could be set.
 */
GRK_API bool GRK_CALLCONV grk_decompress_set_window(grk_codec* codec, uint32_t start_x,
													uint32_t start_y, uint32_t end_x,
													uint32_t end_y);

/**
 * Decompress image from a JPEG 2000 code stream
 *
 * @param p_decompressor 	decompressor handle
 * @param tile			 	tile struct from plugin
 * @return 					true if successful, otherwise false
 * */
GRK_API bool GRK_CALLCONV grk_decompress(grk_codec* p_decompressor, grk_plugin_tile* tile);

/**
 * Decompress a specific tile
 *
 * @param	codec			JPEG 2000 code stream
 * @param	tileIndex		index of the tile to be decompressed
 *
 * @return					true if successful, otherwise false
 */
GRK_API bool GRK_CALLCONV grk_decompress_tile(grk_codec* codec, uint16_t tileIndex);

/**
 * End decompression
 *
 * @param	codec			JPEG 2000 code stream
 */
GRK_API bool GRK_CALLCONV grk_decompress_end(grk_codec* codec);

/* COMPRESSION FUNCTIONS*/

/**
 * Creates a J2K/JP2 compression structure
 * @param 	format 		Coder to select
 * @param	stream	the JPEG 2000 stream.
 * @return 				Returns a handle to a compressor if successful,
 * 						returns nullptr otherwise
 */
GRK_API grk_codec* GRK_CALLCONV grk_compress_create(GRK_CODEC_FORMAT format, grk_stream* stream);

/**
 Set compressing parameters to default values, that means :

 Lossless
 Single tile
 Size of precinct : 2^15 x 2^15 (i.e. single precinct)
 Size of code block : 64 x 64
 Number of resolutions: 6
 No SOP marker in the code stream
 No EPH marker in the code stream
 No sub-sampling in x or y direction
 No mode switch activated
 Progression order: LRCP
 No index file
 No ROI upshifted
 Image origin lies at (0,0)
 Tile origin lies at (0,0)
 Reversible DWT 5-3 transform

 @param parameters Compression parameters
 */
GRK_API void GRK_CALLCONV grk_compress_set_default_params(grk_cparameters* parameters);

/**
 * Set up the compressor parameters using the current image and user parameters.
 *
 * @param codec 		JPEG 2000 code stream
 * @param parameters 	compression parameters
 * @param image 		input image
 */
GRK_API bool GRK_CALLCONV grk_compress_init(grk_codec* codec, grk_cparameters* parameters,
											grk_image* image);

/**
 * Start compressing current image.
 *
 * @param codec 		Compressor handle
 *
 */
GRK_API bool GRK_CALLCONV grk_compress_start(grk_codec* codec);

/**
 * Encode an image into a JPEG 2000 code stream
 * @param codec 		compressor handle
 *
 * @return 				Returns true if successful, returns false otherwise
 */
GRK_API bool GRK_CALLCONV grk_compress(grk_codec* codec);

/**
 * Compress uncompressed data stored in a buffer.
 * This method should be called right after grk_compress_start,
 * and before grk_end_compress.
 *
 * @param	codec		    JPEG 2000 code stream
 * @param	tileIndex		the index of the tile to write. At the moment,
 * 							the tiles must be written from 0 to n-1 in sequence.
 * @param	data			pointer to the data to write. Data is arranged in planar
 *  						sequence, data_comp0, data_comp1 etc,
 *  						The data should NOT BE INTERLEAVED.
 * @param	data_size		this value is used to ensure the data
 * 							being written is correct. The size must be
 * 							equal to the sum for each component of
 *                          tile_width * tile_height * component_size.
 *                          component_size can be 1 or 2 bytes, depending on
 *                          the precision of the given component.
 *
 * @return	true if the data could be written.
 */
GRK_API bool GRK_CALLCONV grk_compress_tile(grk_codec* codec, uint16_t tileIndex, uint8_t* data,
											uint64_t data_size);

/**
 * Encode an image into a JPEG 2000 code stream using plugin
 * @param codec 		compressor handle
 * @param tile			plugin tile
 *
 * @return 				Returns true if successful, returns false otherwise
 */
GRK_API bool GRK_CALLCONV grk_compress_with_plugin(grk_codec* codec, grk_plugin_tile* tile);

/**
 * End to compress the current image.
 * @param codec 		Compressor handle
 */
GRK_API bool GRK_CALLCONV grk_compress_end(grk_codec* codec);

/**
 * Dump codec information to file
 *
 * @param	codec			JPEG 2000 code stream.
 * @param	info_flag		type of information dump.
 * @param	output_stream	output stream where dump the information get from the codec.
 *
 */
GRK_API void GRK_CALLCONV grk_dump_codec(grk_codec* codec, uint32_t info_flag, FILE* output_stream);

/**
 * Set the MCT matrix to use.
 *
 * @param	parameters		the parameters to change.
 * @param	pEncodingMatrix	the compressing matrix.
 * @param	p_dc_shift		the dc shift coefficients to use.
 * @param	pNbComp			the number of components of the image.
 *
 * @return	true if the parameters could be set.
 */
GRK_API bool GRK_CALLCONV grk_set_MCT(grk_cparameters* parameters, float* pEncodingMatrix,
									  int32_t* p_dc_shift, uint32_t pNbComp);

/******************
 Plugin Interface
 ******************/

/*
 Plugin management
 */

typedef struct _grk_plugin_load_info
{
	const char* pluginPath;
} grk_plugin_load_info;

/**
 * Load plugin
 *
 * @param info		plugin loading info
 */
GRK_API bool GRK_CALLCONV grk_plugin_load(grk_plugin_load_info info);

/**
 * Release plugin resources
 */
GRK_API void GRK_CALLCONV grk_plugin_cleanup(void);

// No debug is done on plugin. Production setting.
#define GRK_PLUGIN_STATE_NO_DEBUG 0x0

/*
 For compress debugging, the plugin first performs a T1 compress.
 Then:
 1. perform host DWT on plugin MCT data, and write to host image
 This way, both plugin and host start from same point
 (assume MCT is equivalent for both host and plugin)
 2. map plugin DWT data, compare with host DWT, and then write to plugin image
 At this point in the code, the plugin image holds plugin DWT data. And if no warnings are
 triggered, then we can safely say that host and plugin DWT data are identical.
 3. Perform host compress, skipping MCT and DWT (they have already been performed)
 4. during host compress, each context that is formed is compared against context stream from plugin
 5. rate control - synch with plugin code stream, and compare
 6. T2 and store to disk
 */

#define GRK_PLUGIN_STATE_DEBUG 0x1
#define GRK_PLUGIN_STATE_PRE_TR1 0x2
#define GRK_PLUGIN_STATE_DWT_QUANTIZATION 0x4
#define GRK_PLUGIN_STATE_MCT_ONLY 0x8

/**
 * Get debug state of plugin
 */
GRK_API uint32_t GRK_CALLCONV grk_plugin_get_debug_state();

/*
 Plugin compressing
 */
typedef struct _grk_plugin_init_info
{
	int32_t deviceId;
	bool verbose;
} grk_plugin_init_info;

/**
 * Initialize plugin
 */
GRK_API bool GRK_CALLCONV grk_plugin_init(grk_plugin_init_info initInfo);

typedef struct grk_plugin_compress_user_callback_info
{
	const char* input_file_name;
	bool outputFileNameIsRelative;
	const char* output_file_name;
	grk_cparameters* compressor_parameters;
	grk_image* image;
	grk_plugin_tile* tile;
	uint8_t* compressBuffer;
	size_t compressBufferLen;
	unsigned int error_code;
	bool transferExifTags;
} grk_plugin_compress_user_callback_info;

typedef bool (*GRK_PLUGIN_COMPRESS_USER_CALLBACK)(grk_plugin_compress_user_callback_info* info);

/**
 * Compress with plugin
 *
 * @param compress_parameters 	compress parameters
 * @param callback				callback
 */
GRK_API int32_t GRK_CALLCONV grk_plugin_compress(grk_cparameters* compress_parameters,
												 GRK_PLUGIN_COMPRESS_USER_CALLBACK callback);

/**
 * Batch compress with plugin
 *
 * @param input_dir				directory holding input images
 * @param output_dir			directory holding compressed output images
 * @param compress_parameters 	compress parameters
 * @param callback				callback
 *
 * @return 0 if successful
 *
 */
GRK_API int32_t GRK_CALLCONV grk_plugin_batch_compress(const char* input_dir,
													   const char* output_dir,
													   grk_cparameters* compress_parameters,
													   GRK_PLUGIN_COMPRESS_USER_CALLBACK callback);

/**
 * Check if batch job is complete
 */
GRK_API bool GRK_CALLCONV grk_plugin_is_batch_complete(void);

/**
 * Stop batch compress
 */
GRK_API void GRK_CALLCONV grk_plugin_stop_batch_compress(void);

/*
 Plugin decompression
 */

typedef int (*GROK_INIT_DECOMPRESSORS)(grk_header_info* header_info, grk_image* image);

typedef struct _grk_plugin_decompress_callback_info
{
	size_t deviceId;
	GROK_INIT_DECOMPRESSORS init_decompressors_func;
	const char* input_file_name;
	const char* output_file_name;
	// input file format 0: J2K, 1: JP2
	GRK_SUPPORTED_FILE_FMT decod_format;
	// output file format 0: PGX, 1: PxM, 2: BMP etc
	GRK_SUPPORTED_FILE_FMT cod_format;
	grk_stream* stream;
	grk_codec* codec;
	grk_header_info header_info;
	grk_decompress_parameters* decompressor_parameters;
	grk_image* image;
	bool plugin_owns_image;
	grk_plugin_tile* tile;
	unsigned int error_code;
	uint32_t decompress_flags;
	uint32_t full_image_x0;
	uint32_t full_image_y0;
	void* user_data;
} grk_plugin_decompress_callback_info;

typedef int32_t (*grk_plugin_decompress_callback)(grk_plugin_decompress_callback_info* info);

/**
 * Decompress with plugin
 *
 * @param decompress_parameters  decompress parameters
 * @param callback  			 callback
 */
GRK_API int32_t GRK_CALLCONV grk_plugin_decompress(grk_decompress_parameters* decompress_parameters,
												   grk_plugin_decompress_callback callback);

/**
 * Initialize batch decompress
 *
 * @param input_dir input directory holding compressed images
 * @param output_dir output directory holding decompressed images
 * @param decompress_parameters  decompress parameters
 * @param callback  			 callback
 *
 * @return 0 if successful
 */
GRK_API int32_t GRK_CALLCONV grk_plugin_init_batch_decompress(
	const char* input_dir, const char* output_dir, grk_decompress_parameters* decompress_parameters,
	grk_plugin_decompress_callback callback);

/**
 * Batch decompress
 */
GRK_API int32_t GRK_CALLCONV grk_plugin_batch_decompress(void);

/**
 * Stop batch decompress
 */
GRK_API void GRK_CALLCONV grk_plugin_stop_batch_decompress(void);

#ifdef __cplusplus
}
#endif
