|
#ifndef PACKJPG_H
|
|
#define PACKJPG_H
|
|
|
|
#include <filesystem>
|
|
#include <memory>
|
|
|
|
#define MEM_ERRMSG "out of memory error"
|
|
#define FRD_ERRMSG "could not read file / file not found: %s"
|
|
#define FWR_ERRMSG "could not write file / file write-protected: %s"
|
|
#define MSG_SIZE 128
|
|
#define BARLEN 36
|
|
|
|
namespace sfs = std::filesystem;
|
|
|
|
// Forward declarations -- real includes are in the source file so we can use
|
|
// this header externally
|
|
class ArithmeticDecoder;
|
|
class ArithmeticEncoder;
|
|
class BitReader;
|
|
class BitWriter;
|
|
class Reader;
|
|
class Writer;
|
|
|
|
/* -----------------------------------------------
|
|
struct declarations
|
|
----------------------------------------------- */
|
|
|
|
struct componentInfo
|
|
{
|
|
unsigned short* qtable; // quantization table
|
|
int huffdc; // no of huffman table (DC)
|
|
int huffac; // no of huffman table (AC)
|
|
int sfv; // sample factor vertical
|
|
int sfh; // sample factor horizontal
|
|
int mbs; // blocks in mcu
|
|
int bcv; // block count vertical (interleaved)
|
|
int bch; // block count horizontal (interleaved)
|
|
int bc; // block count (all) (interleaved)
|
|
int ncv; // block count vertical (non interleaved)
|
|
int nch; // block count horizontal (non interleaved)
|
|
int nc; // block count (all) (non interleaved)
|
|
int sid; // statistical identity
|
|
int jid; // jpeg internal id
|
|
};
|
|
|
|
struct huffCodes
|
|
{
|
|
unsigned short cval[256];
|
|
unsigned short clen[256];
|
|
unsigned short max_eobrun;
|
|
};
|
|
|
|
struct huffTree
|
|
{
|
|
unsigned short l[256];
|
|
unsigned short r[256];
|
|
};
|
|
|
|
class packJPG
|
|
{
|
|
public:
|
|
|
|
packJPG();
|
|
|
|
~packJPG();
|
|
|
|
static const char* pjglib_version_info(void);
|
|
static const char* pjglib_short_name(void);
|
|
|
|
/* -----------------------------------------------
|
|
checks if a file exists
|
|
----------------------------------------------- */
|
|
inline bool file_exists(const char* filename)
|
|
{
|
|
return sfs::exists(filename);
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Library functions
|
|
*************************************************************************/
|
|
|
|
bool pjglib_convert_stream2stream(char* msg);
|
|
|
|
bool pjglib_convert_file2file(char* in, char* out, char* msg);
|
|
|
|
bool pjglib_convert_stream2mem(
|
|
unsigned char** out_file,
|
|
unsigned int* out_size,
|
|
char* msg);
|
|
|
|
void pjglib_init_streams(
|
|
void* in_src,
|
|
int in_type,
|
|
int in_size,
|
|
void* out_dest,
|
|
int out_type);
|
|
|
|
/**************************************************************************
|
|
* Main interface functions
|
|
*************************************************************************/
|
|
|
|
void process_file(void);
|
|
|
|
void execute(bool (*function)());
|
|
|
|
/**************************************************************************
|
|
* Main functions
|
|
*************************************************************************/
|
|
|
|
bool reset_buffers(void);
|
|
|
|
bool read_jpeg(void);
|
|
|
|
bool merge_jpeg(void);
|
|
|
|
bool decode_jpeg(void);
|
|
|
|
bool recode_jpeg(void);
|
|
|
|
bool adapt_icos(void);
|
|
|
|
bool predict_dc(void);
|
|
|
|
bool unpredict_dc(void);
|
|
|
|
bool check_value_range(void);
|
|
|
|
bool calc_zdst_lists(void);
|
|
|
|
bool pack_pjg(void);
|
|
|
|
bool unpack_pjg(void);
|
|
|
|
/* -----------------------------------------------
|
|
global variables: info about program
|
|
----------------------------------------------- */
|
|
static const unsigned char appversion;
|
|
static const char* subversion;
|
|
static const char* apptitle;
|
|
static const char* appname;
|
|
static const char* versiondate;
|
|
static const char* author;
|
|
static const char pjg_magic[2];
|
|
|
|
private:
|
|
|
|
/**************************************************************************
|
|
* JPEG specific functions
|
|
*************************************************************************/
|
|
|
|
bool jpg_setup_imginfo(void);
|
|
|
|
bool jpg_parse_jfif(
|
|
unsigned char type,
|
|
unsigned int len,
|
|
unsigned char* segment);
|
|
|
|
bool jpg_rebuild_header(void);
|
|
|
|
int jpg_decode_block_seq(
|
|
BitReader* huffr,
|
|
huffTree* dctree,
|
|
huffTree* actree,
|
|
short* block);
|
|
|
|
int jpg_encode_block_seq(
|
|
BitWriter* huffw,
|
|
huffCodes* dctbl,
|
|
huffCodes* actbl,
|
|
short* block);
|
|
|
|
int jpg_decode_dc_prg_fs(
|
|
BitReader* huffr,
|
|
huffTree* dctree,
|
|
short* block);
|
|
|
|
int jpg_encode_dc_prg_fs(
|
|
BitWriter* huffw,
|
|
huffCodes* dctbl,
|
|
short* block);
|
|
|
|
int jpg_decode_ac_prg_fs(
|
|
BitReader* huffr,
|
|
huffTree* actree,
|
|
short* block,
|
|
int* eobrun,
|
|
int from,
|
|
int to);
|
|
|
|
int jpg_encode_ac_prg_fs(
|
|
BitWriter* huffw,
|
|
huffCodes* actbl,
|
|
short* block,
|
|
int* eobrun,
|
|
int from,
|
|
int to);
|
|
|
|
int jpg_decode_dc_prg_sa(BitReader* huffr, short* block);
|
|
|
|
int jpg_encode_dc_prg_sa(BitWriter* huffw, short* block);
|
|
|
|
int jpg_decode_ac_prg_sa(
|
|
BitReader* huffr,
|
|
huffTree* actree,
|
|
short* block,
|
|
int* eobrun,
|
|
int from,
|
|
int to);
|
|
|
|
int jpg_encode_ac_prg_sa(
|
|
BitWriter* huffw,
|
|
std::vector<std::uint8_t>& storw,
|
|
huffCodes* actbl,
|
|
short* block,
|
|
int* eobrun,
|
|
int from,
|
|
int to);
|
|
|
|
int jpg_decode_eobrun_sa(
|
|
BitReader* huffr,
|
|
short* block,
|
|
int* eobrun,
|
|
int from,
|
|
int to);
|
|
|
|
int jpg_encode_eobrun(
|
|
BitWriter* huffw,
|
|
huffCodes* actbl,
|
|
int* eobrun);
|
|
|
|
int jpg_encode_crbits(
|
|
BitWriter* huffw,
|
|
std::vector<std::uint8_t>& storw);
|
|
|
|
int jpg_next_huffcode(BitReader* huffw, huffTree* ctree);
|
|
|
|
int jpg_next_mcupos(
|
|
int* mcu,
|
|
int* cmp,
|
|
int* csc,
|
|
int* sub,
|
|
int* dpos,
|
|
int* rstw);
|
|
|
|
int jpg_next_mcuposn(int* cmp, int* dpos, int* rstw);
|
|
|
|
int jpg_skip_eobrun(int* cmp, int* dpos, int* rstw, int* eobrun);
|
|
|
|
void jpg_build_huffcodes(
|
|
unsigned char* clen,
|
|
unsigned char* cval,
|
|
huffCodes* hc,
|
|
huffTree* ht);
|
|
|
|
/**************************************************************************
|
|
* PJG specific functions
|
|
*************************************************************************/
|
|
|
|
bool pjg_encode_zstscan(ArithmeticEncoder* enc, int cmp);
|
|
|
|
bool pjg_encode_zdst_high(ArithmeticEncoder* enc, int cmp);
|
|
|
|
bool pjg_encode_zdst_low(ArithmeticEncoder* enc, int cmp);
|
|
|
|
bool pjg_encode_dc(ArithmeticEncoder* enc, int cmp);
|
|
|
|
bool pjg_encode_ac_high(ArithmeticEncoder* enc, int cmp);
|
|
|
|
bool pjg_encode_ac_low(ArithmeticEncoder* enc, int cmp);
|
|
|
|
bool pjg_encode_generic(
|
|
ArithmeticEncoder* enc,
|
|
unsigned char* data,
|
|
int len);
|
|
|
|
bool pjg_encode_bit(ArithmeticEncoder* enc, unsigned char bit);
|
|
|
|
bool pjg_decode_zstscan(ArithmeticDecoder* dec, int cmp);
|
|
|
|
bool pjg_decode_zdst_high(ArithmeticDecoder* dec, int cmp);
|
|
|
|
bool pjg_decode_zdst_low(ArithmeticDecoder* dec, int cmp);
|
|
|
|
bool pjg_decode_dc(ArithmeticDecoder* dec, int cmp);
|
|
|
|
bool pjg_decode_ac_high(ArithmeticDecoder* dec, int cmp);
|
|
|
|
bool pjg_decode_ac_low(ArithmeticDecoder* dec, int cmp);
|
|
|
|
bool pjg_decode_generic(
|
|
ArithmeticDecoder* dec,
|
|
unsigned char** data,
|
|
int* len);
|
|
|
|
bool pjg_decode_bit(ArithmeticDecoder* dec, unsigned char* bit);
|
|
|
|
void pjg_get_zerosort_scan(unsigned char* sv, int cmp);
|
|
|
|
bool pjg_optimize_header(void);
|
|
|
|
bool pjg_unoptimize_header(void);
|
|
|
|
void pjg_aavrg_prepare(
|
|
unsigned short** abs_coeffs,
|
|
int* weights,
|
|
unsigned short* abs_store,
|
|
int cmp);
|
|
|
|
int pjg_aavrg_context(
|
|
unsigned short** abs_coeffs,
|
|
int* weights,
|
|
int pos,
|
|
int p_y,
|
|
int p_x,
|
|
int r_x);
|
|
|
|
int pjg_lakh_context(
|
|
signed short** coeffs_x,
|
|
signed short** coeffs_a,
|
|
int* pred_cf,
|
|
int pos);
|
|
|
|
void get_context_nnb(int pos, int w, int* a, int* b);
|
|
|
|
/**************************************************************************
|
|
* DCT functions
|
|
*************************************************************************/
|
|
|
|
int idct_2d_fst_8x1(int cmp, int dpos, int ix, int iy);
|
|
|
|
int idct_2d_fst_1x8(int cmp, int dpos, int ix, int iy);
|
|
|
|
/**************************************************************************
|
|
* Prediction functions
|
|
*************************************************************************/
|
|
|
|
int dc_coll_predictor(int cmp, int dpos);
|
|
|
|
int dc_1ddct_predictor(int cmp, int dpos);
|
|
|
|
/* -----------------------------------------------
|
|
loco-i predictor
|
|
----------------------------------------------- */
|
|
inline int plocoi(int a, int b, int c)
|
|
{
|
|
// a -> left; b -> above; c -> above-left
|
|
|
|
int min = (a < b) ? a : b;
|
|
int max = (a > b) ? a : b;
|
|
|
|
if (c >= max)
|
|
{
|
|
return min;
|
|
}
|
|
if (c <= min)
|
|
{
|
|
return max;
|
|
}
|
|
|
|
return a + b - c;
|
|
}
|
|
|
|
/* -----------------------------------------------
|
|
calculates median out of an integer array
|
|
----------------------------------------------- */
|
|
inline int median_int(int* values, int size)
|
|
{
|
|
int middle = (size >> 1);
|
|
bool done;
|
|
int swap;
|
|
int i;
|
|
|
|
// sort data first
|
|
done = false;
|
|
while (!done)
|
|
{
|
|
done = true;
|
|
for (i = 1; i < size; i++)
|
|
{
|
|
if (values[i] < values[i - 1])
|
|
{
|
|
swap = values[i];
|
|
values[i] = values[i - 1];
|
|
values[i - 1] = swap;
|
|
done = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// return median
|
|
return ((size % 2) == 0) ?
|
|
(values[middle] + values[middle - 1]) / 2 : values[middle];
|
|
}
|
|
|
|
/* -----------------------------------------------
|
|
calculates median out of an float array
|
|
----------------------------------------------- */
|
|
inline float median_float(float* values, int size)
|
|
{
|
|
int middle = (size >> 1);
|
|
bool done;
|
|
float swap;
|
|
int i;
|
|
|
|
|
|
// sort data first
|
|
done = false;
|
|
while (!done)
|
|
{
|
|
done = true;
|
|
for (i = 1; i < size; i++)
|
|
{
|
|
if (values[i] < values[i - 1])
|
|
{
|
|
swap = values[i];
|
|
values[i] = values[i - 1];
|
|
values[i - 1] = swap;
|
|
done = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// return median
|
|
if ((size % 2) == 0)
|
|
{
|
|
return (values[middle] + values[middle - 1]) / 2.0;
|
|
}
|
|
else
|
|
{
|
|
return (values[middle]);
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Member variables
|
|
*************************************************************************/
|
|
/* -----------------------------------------------
|
|
global variables: library only variables
|
|
----------------------------------------------- */
|
|
int lib_in_type;
|
|
int lib_out_type;
|
|
|
|
/* -----------------------------------------------
|
|
global variables: data storage
|
|
----------------------------------------------- */
|
|
unsigned short qtables[4][64]; // quantization tables
|
|
huffCodes hcodes[2][4]; // huffman codes
|
|
huffTree htrees[2][4]; // huffman decoding trees
|
|
unsigned char htset[2][4]; // 1 if huffman table is set
|
|
|
|
unsigned char* grbgdata; // garbage data
|
|
unsigned char* hdrdata ; // header data
|
|
unsigned char* huffdata; // huffman coded data
|
|
int hufs; // size of huffman data
|
|
int hdrs; // size of header
|
|
int grbs; // size of garbage
|
|
|
|
unsigned int* rstp; // restart markers positions in huffdata
|
|
unsigned int* scnp; // scan start positions in huffdata
|
|
int rstc; // count of restart markers
|
|
int scnc; // count of scans
|
|
int rsti; // restart interval
|
|
char padbit; // padbit (for huffman coding)
|
|
unsigned char* rst_err; // number of wrong-set RST markers per scan
|
|
|
|
unsigned char* zdstdata[4]; // zero distribution (# of non-zeroes) lists (for higher 7x7 block)
|
|
unsigned char* eobxhigh[4]; // eob in x direction (for higher 7x7 block)
|
|
unsigned char* eobyhigh[4]; // eob in y direction (for higher 7x7 block)
|
|
unsigned char* zdstxlow[4]; // # of non zeroes for first row
|
|
unsigned char* zdstylow[4]; // # of non zeroes for first collumn
|
|
signed short* colldata[4][64]; // collection sorted DCT coefficients
|
|
|
|
unsigned char* freqscan[4]; // optimized order for frequency scans (only pointers to scans)
|
|
unsigned char zsrtscan[4][64]; // zero optimized frequency scan
|
|
|
|
int adpt_idct_8x8[4][8 * 8 * 8 * 8]; // precalculated/adapted values for idct (8x8)
|
|
int adpt_idct_1x8[4][1 * 1 * 8 * 8]; // precalculated/adapted values for idct (1x8)
|
|
int adpt_idct_8x1[4][8 * 8 * 1 * 1]; // precalculated/adapted values for idct (8x1)
|
|
|
|
/* -----------------------------------------------
|
|
global variables: info about image
|
|
----------------------------------------------- */
|
|
componentInfo cmpnfo[4]; // seperate info for each color component
|
|
|
|
int cmpc; // component count
|
|
int imgwidth; // width of image
|
|
int imgheight; // height of image
|
|
|
|
int sfhm; // max horizontal sample factor
|
|
int sfvm; // max verical sample factor
|
|
int mcuv; // mcus per line
|
|
int mcuh; // mcus per collumn
|
|
int mcuc; // count of mcus
|
|
|
|
/* -----------------------------------------------
|
|
global variables: info about current scan
|
|
----------------------------------------------- */
|
|
int cs_cmpc; // component count in current scan
|
|
int cs_cmp[4]; // component numbers in current scan
|
|
int cs_from; // begin - band of current scan ( inclusive )
|
|
int cs_to; // end - band of current scan ( inclusive )
|
|
int cs_sah; // successive approximation bit pos high
|
|
int cs_sal; // successive approximation bit pos low
|
|
|
|
/* -----------------------------------------------
|
|
global variables: info about files
|
|
----------------------------------------------- */
|
|
char* jpgfilename; // name of JPEG file
|
|
char* pjgfilename; // name of PJG file
|
|
int jpgfilesize; // size of JPEG file
|
|
int pjgfilesize; // size of PJG file
|
|
int jpegtype; // type of JPEG coding: 0->unknown, 1->sequential, 2->progressive
|
|
int filetype; // type of current file
|
|
std::unique_ptr<Reader> str_in; // input stream
|
|
std::unique_ptr<Writer> str_out; // output stream
|
|
|
|
/* -----------------------------------------------
|
|
global variables: messages
|
|
----------------------------------------------- */
|
|
char errormessage[MSG_SIZE];
|
|
bool (*errorfunction)();
|
|
|
|
// meaning of errorlevel:
|
|
// -1 -> wrong input
|
|
// 0 -> no error
|
|
// 1 -> warning
|
|
// 2 -> fatal error
|
|
int errorlevel;
|
|
|
|
/* -----------------------------------------------
|
|
global variables: settings
|
|
----------------------------------------------- */
|
|
int err_tol; // error threshold ( proceed on warnings yes (2) / no (1) )
|
|
bool disc_meta; // discard meta-info yes / no
|
|
bool auto_set; // automatic find best settings yes/no
|
|
int action; // what to do with JPEG/PJG files
|
|
|
|
unsigned char nois_trs[4]; // bit pattern noise threshold
|
|
unsigned char segm_cnt[4]; // number of segments
|
|
};
|
|
|
|
|
|
#endif
|