arithc.c

来自「傅立叶变换和小波变换是图像压缩的重要工具。该代大戏是利用小波变换进行图像压缩。」· C语言 代码 · 共 559 行

C
559
字号
#include <crblib/inc.h>
#include <crblib/arithc.h>
#include <crblib/arithc._h>

#pragma warning( disable : 4244 )	// loss of data in conversion

/*functions:*/

//#define PARANOID_ENCODEDONE	// @@ ?

//#define FAST_ENCODE
	/** actually makes very little difference in speed or compression
	*	presumably because the Pentium's branch prediction is doing
	*	a good job
	**/

arithInfo * arithInit(void)
{
arithInfo * ari;

	if ( (ari = new(arithInfo)) == NULL )
		return(NULL);

	ari->probMax = CumProbMax;
	ari->probMaxSafe = CumProbMax - 512;

return(ari);
}

void arithFree(arithInfo * ari)
{
	if (ari) free(ari);
}

void arithEncodeInitNoStuff(arithInfo * ari,ubyte *outBuf)
{
	ari->outBuf = outBuf;

	arithEncodeReInit(ari,outBuf - 1);
}

void arithEncodeInit(arithInfo * ari,ubyte *outBuf)
{
	ari->outBuf = outBuf;

	arithEncodeReInit(ari,outBuf);
}

void arithEncodeReInit(arithInfo * ari,ubyte *outBuf)
{

	ari->code  = 0;
	ari->range = One;
	ari->overflow_bytes = 0;
	ari->queue = 0;	// this is a waste of a byte

	// ari->outBuf unchanged
	ari->outPtr = outBuf;

}

void arithEncode(arithInfo * ari,ulong symlow,ulong symhigh,ulong symtot)
{
ulong code,range;

	code    = ari->code;
	range   = ari->range;

	assert( symlow < symhigh && symhigh <= symtot );
	assert( symtot <= CumProbMax );

	/** we want to do :
	*		 lowincr = (range * symlow) / symtot
	*	but range & symtot can both be large , so this would overflow the register	
	*	thus we instead do:
	*
	***/

#ifdef FAST_ENCODE
	/*#*/ { 
	ulong r;

	r = range / symtot;

	code += r * symlow;
	range = r * (symhigh - symlow);

	/*#*/ }
#else
	/*#*/ { 
	ulong lowincr,r;

	r = range / symtot;

	lowincr = r * symlow;
	code += lowincr;
	if ( symhigh == symtot )	range -= lowincr;
	else 						range = r * (symhigh - symlow);

	/*#*/ }
#endif

	arithEncRenorm(ari,code,range);
}

void arithEncBits(arithInfo * ari,uint val,uint bits)
{
ulong code,range;

	assert( val < (1UL<<bits) );
	assert( (1UL<<bits) <= CumProbMax );

	code    = ari->code;
	range   = ari->range;

	range >>= bits;

	code += range * val;

	arithEncRenorm(ari,code,range);
}

int arithEncodeDoneMinimal(arithInfo * ari)
{
uint rangeMask,rangeMSB;

	// set code to the maximum that won't change how it decodes.

	ari->code += ari->range - 1;

	/* first send the queue */

	if ( ari->code & One )
	{
		*(ari->outPtr)++ = (ubyte)(ari->queue + 1)&0xFF;
		while ( ari->overflow_bytes-- ) *(ari->outPtr)++ = 0;
	}
	else
	{
		*(ari->outPtr)++ = ari->queue;
		while ( ari->overflow_bytes-- ) *(ari->outPtr)++ = 0xFF;
	}

	/*****

	the minimal way to flush is to do :

		code += (range - 1);

		clear code below MSB of range

	eg. if range is 67 we do :
		
		code += 66;
		code &= ~63;

	then we just send code bytes until the remainder is zero.

	(this assumes that when the decoder reads past EOF, it reads zeros!)

	-----

	we almost always write just 1 byte
	(in fact, I think we might *always* write 1 byte)

	******/

	if ( ari->range >= (1UL<<31) )
	{
		rangeMSB = 1UL<<31;
	}
	else
	{
		for(rangeMSB=1;rangeMSB <= ari->range; rangeMSB <<= 1) ;
		rangeMSB >>= 1;
		
		assert( ari->range >= rangeMSB && ari->range < rangeMSB*2 );
	}

	// clear code under rangeMask :

	rangeMask = 0;
	rangeMSB >>= 1;
	while(rangeMSB)
	{
		rangeMask |= rangeMSB;
		rangeMSB >>= 1;
	}

	assert( rangeMask < ari->range );

	ari->code &= (~ rangeMask);
	ari->code &= CODE_MASK;

	while(ari->code)	
	{
		*(ari->outPtr)++ = (ari->code >> SHIFT_BITS) & 0xFF;
		ari->code <<= 8;
		ari->code &= CODE_MASK;
	}

	ari->outPtr[0] = 0;
	ari->outPtr[1] = 0;
	ari->outPtr[2] = 0;
	ari->outPtr[3] = 0;
	ari->outPtr[4] = 0;
	ari->outPtr[5] = 0;

return ari->outPtr - ari->outBuf;
}

int arithEncodeDoneSafe(arithInfo * ari)
{
	// set code to the maximum that won't change how it decodes.

	ari->code += ari->range - 1;

	/* first send the queue */

	if ( ari->code & One )
	{
		*(ari->outPtr)++ = (ubyte)(ari->queue + 1)&0xFF;
		while ( ari->overflow_bytes-- ) *(ari->outPtr)++ = 0;
	}
	else
	{
		*(ari->outPtr)++ = ari->queue;
		while ( ari->overflow_bytes-- ) *(ari->outPtr)++ = 0xFF;
	}

	*(ari->outPtr)++ = (ari->code >> SHIFT_BITS) & 0xFF;	ari->code <<= 8;
	*(ari->outPtr)++ = (ari->code >> SHIFT_BITS) & 0xFF;	ari->code <<= 8;
	
return ari->outPtr - ari->outBuf;
}

void arithDecodeInitNoStuff(arithInfo * ari,ubyte *outBuf)
{
	ari->outBuf = ari->outPtr = outBuf;

	arithDecodeReInit(ari,outBuf-1);
}

void arithDecodeInit(arithInfo * ari,ubyte *outBuf)
{
	ari->outBuf = ari->outPtr = outBuf;

	arithDecodeReInit(ari,outBuf);
}

void arithDecodeReInit(arithInfo * ari,ubyte *outBuf)
{
ulong byte;

	ari->outPtr = outBuf + 1;

	/** the code needs to be kept filled with 31 bits ;
	*	this means we cannot just read in 4 bytes.  We must read in 3,
	*	then the 7 bits of another (EXTRA_BITS == 7) , and save that last
	*	bit in the queue 
	**/

	byte = ari->queue = *(ari->outPtr)++;
	ari->code = byte >> (TAIL_EXTRA_BITS);
	ari->range = 1 << EXTRA_BITS;
}

/** save a repeated divide computation between arithGet and arithDecode **/
static ulong dec_range_over_symtot;

ulong arithGet(arithInfo * ari,ulong symtot)
{
ulong ret,range,code;

	assert( symtot <= CumProbMax );

	arithDecRenorm(ari,&code,&range);

	dec_range_over_symtot = range / symtot;
	ret = code / dec_range_over_symtot;

	ari->range = range;
	ari->code  = code;
		
	//assert( ret < symtot );  // is this safe? ; apparently not!
	ret = ( ret >= symtot ? symtot-1 : ret );

return ret;
}

void arithDecode(arithInfo * ari,ulong symlow,ulong symhigh,ulong symtot)
{

	assert( symlow < symhigh && symhigh <= symtot );
	assert( symtot <= CumProbMax );

#ifdef FAST_ENCODE

	ari->code -= dec_range_over_symtot * symlow;
	ari->range = dec_range_over_symtot * (symhigh - symlow);

#else
{
ulong lowincr;

	lowincr = dec_range_over_symtot * symlow;
	ari->code -= lowincr;
	if ( symhigh == symtot )	ari->range -= lowincr;
	else 						ari->range = dec_range_over_symtot * (symhigh - symlow);
}
#endif

}

uint arithDecBits(arithInfo * ari,uint bits)
{
ulong code,range;
uint val;

	arithDecRenorm(ari,&code,&range);

	range >>= bits;
	val = code / range;

	code -= range * val;
	
	ari->range = range;
	ari->code  = code;

return val;
}

void arithDecodeDone(arithInfo * ari)
{
}

int arithTellEncPos(arithInfo * ari)
{
int ret;

	ret = ari->outPtr - ari->outBuf;
	ret += 1 + ari->overflow_bytes;	// # of bytes in the queue
	// ret += 2;	// flush bytes
return ret;
}
int arithTellDecPos(arithInfo * ari)
{
int ret;
	ret = ari->outPtr - ari->outBuf;
	ret -= CODE_BYTES;
	// ret += 2;
return ret;
}

int arithEncodeFlush(arithInfo * ari)
{
int ret;
ubyte *saveBuf;
	ret = arithEncodeDone(ari);
	saveBuf = ari->outBuf;
	arithEncodeInit(ari,saveBuf+ret);
	ari->outBuf = saveBuf;
return ret;
}

void arithDecodeRestart(arithInfo * ari,ulong pos)
{
ubyte *saveBuf;
	arithDecodeDone(ari);
	saveBuf = ari->outBuf;
	arithDecodeInit(ari,saveBuf+pos);
	ari->outBuf = saveBuf;
}


void arithEncBit(arithInfo * ari,ulong mid,ulong tot,bool bit)
{
ulong code,range;

code    = ari->code;
range   = ari->range;

	/*#*/ { ulong r;

	r = (range / tot) * mid;

	if ( bit )
	{
		code += r;
		range -= r;
	}
	else
	{
		range = r;
	}
	/*#*/ }

	arithEncRenorm(ari,code,range);
}

bool arithDecBit(arithInfo * ari,ulong mid,ulong tot)
{
bool bit;
ulong range,code,r;

	arithDecRenorm(ari,&code,&range);

/**
*
*		r = (range / tot)
*
*	if ( (code / r) >= mid ) bit = 1; else bit = 0;
*
*	we eliminate one divide. this is the savings of the binary coder
*
**/

	r = (range / tot) * mid;

	if ( code >= r )
	{
		bit = 1;
		code -= r;
		range -= r;
	}
	else
	{
		bit = 0;
		range = r;
	}

	ari->range = range;
	ari->code  = code;

return bit;
}

#define BITMODEL_TOTMAX 5000
#define BITMODEL_INC	30

void arithModelEncBit(arithInfo * ari,ulong *p0,ulong *pt,bool bit)
{
ulong code,range;

code    = ari->code;
range   = ari->range;

	{
	ulong r;

		r = (range / (*pt)) * (*p0);

		if ( bit )
		{
			code += r;
			range -= r;
		}
		else
		{
			range = r;
			(*p0) += BITMODEL_INC;
		}
	}

	(*pt) += BITMODEL_INC;
	if ( *pt > BITMODEL_TOTMAX )
	{
		(*p0) >>= 1; 
		(*pt) >>= 1; 
		(*p0) ++; (*pt) += 2; 
	}

	arithEncRenorm(ari,code,range);
}

bool arithModelDecBit(arithInfo * ari,ulong *p0,ulong *pt)
{
bool bit;
ulong range,code,r;

	arithDecRenorm(ari,&code,&range);

	r = (range / (*pt)) * (*p0);

	if ( code >= r )
	{
		bit = 1;
		code -= r;
		range -= r;
	}
	else
	{
		bit = 0;
		range = r;
		(*p0) += BITMODEL_INC;
	}

	(*pt) += BITMODEL_INC;
	if ( (*pt) > BITMODEL_TOTMAX )
	{
		(*p0) >>= 1;
		(*pt) >>= 1; 
		(*p0) ++; (*pt) += 2; 
	}

	ari->range = range;
	ari->code  = code;

return bit;
}


void arithEncBitRaw(arithInfo * ari,bool bit)
{
ulong code,range;

code    = ari->code;
range   = ari->range;

	if ( bit )
	{
		code	+= range >> 1;
		range	-= range >> 1;
	}
	else
	{
		range >>= 1;
	}

	arithEncRenorm(ari,code,range);
}

bool arithDecBitRaw(arithInfo * ari)
{
bool bit;
ulong range,code,r;

	arithDecRenorm(ari,&code,&range);

	r = range >> 1;

	if ( code >= r )
	{
		bit = 1;
		code  -= r;
		range -= r;
	}
	else 
	{
		bit = 0;
		range = r;
	}

	ari->range = range;
	ari->code  = code;

return bit;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?