📄 imppm.c
字号:
//#define NO_PPM
//#define DEBUG
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <crbinc/inc.h>
#include <crbinc/bbitio.h>
#include <crbinc/arithc.h>
#include <crbinc/memutil.h>
#include <crbinc/mempool.h>
extern int tune_param;
#ifdef DEBUG
#define dprintf3(a,b,c,d) printf(a,b,c,d)
#else
#define dprintf3(a,b,c,d)
#endif
/**** primary config ****/
#define HASH_BITS 14
#define PPMQ_CNTX_BITS 5
#define PPMQ_SMTH_BITS 2 // helps a miniscule amount (0.002 bpb)
#define PPMQ_SMTH_DIV 0
/**** secondary config ****/
#define HASH_SIZE (1<<HASH_BITS)
#define HASH(cntx) ((cntx ^ (cntx>>11)) & (HASH_SIZE - 1))
#define PPMQ_SIZE (1<<(PPMQ_CNTX_BITS + PPMQ_SMTH_BITS))
#define PPMQ_CNTX_MAX ((1<<PPMQ_CNTX_BITS)-1)
#define PPMQ_CNTX_HASH(cntx) (((cntx>>3)^cntx)&PPMQ_CNTX_MAX)
#define PPMQ_SMTH_MAX ((1<<PPMQ_SMTH_BITS)-1)
#define PPMQ_HASH(cntx,smth) ((PPMQ_CNTX_HASH(cntx) << PPMQ_SMTH_BITS) + min((smth>>PPMQ_SMTH_DIV),PPMQ_SMTH_MAX))
#define BAD_PRED 0xFFFF
#define TOT_SCALEDOWN 8000
typedef struct _imcontext {
struct _imcontext *next;
ulong cntx1,cntx2;
uword pred;
} imcontext;
typedef struct Image_PPM_Info {
struct FAI * arith;
MemPool * contextPool;
imcontext * contexts[HASH_SIZE]; // easy to add more orders, if you like
uword ppmq_tot[PPMQ_SIZE],ppmq_esc[PPMQ_SIZE];
} imppmi;
/**********************/
imppmi * iOpen(struct FAI * FAI);
int iDecode(imppmi *ipi,ulong cntx1,ulong cntx2,uword smoothness); // -1 for none
void iDecodeGot(imppmi *ipi,ulong cntx1,ulong cntx2,uword value);
bool iEncode(imppmi *ipi,ulong cntx1,ulong cntx2,uword value,uword smoothness); // coded/not
int imppmDecode(imppmi *ipi,ulong cntx1,ulong cntx2,imcontext *contexts[],uword smoothness);
bool imppmEncode(imppmi *ipi,ulong cntx1,ulong cntx2,imcontext *contexts[],uword value,uword smoothness);
void imppmAddC(imppmi *ipi,ulong cntx1,ulong cntx2,imcontext *contexts[],uword value);
imcontext * imppmFind(imppmi *ipi,ulong cntx1,ulong cntx2,imcontext *contexts[]);
/*********************/
imppmi * iOpen(struct FAI * FAI)
{
imppmi * ipi;
int i;
if ( (ipi = new(imppmi) ) == NULL )
return(NULL);
ipi->arith = FAI;
if ( (ipi->contextPool = AllocPool(sizeof(imcontext),1024,1024)) == NULL )
{ iFree(ipi); return(NULL); }
for(i=0;i<PPMQ_SIZE;i++) {
ipi->ppmq_esc[i] = 1;
ipi->ppmq_tot[i] = 2;
}
return(ipi);
}
extern void iFree(imppmi *ipi)
{
if ( ipi->contextPool ) FreePool(ipi->contextPool);
free(ipi);
}
imcontext * imppmFind(imppmi *ipi,ulong cntx1,ulong cntx2,imcontext *contexts[])
{
imcontext *c;
ulong hash;
hash = HASH(cntx1);
c = contexts[hash];
while( c ) {
if ( c->cntx1 == cntx1 )
if ( c->cntx2 == cntx2 )
return(c);
c = c->next;
}
return NULL;
}
bool iEncode(imppmi *ipi,ulong cntx1,ulong cntx2,uword value,uword smoothness)
{
#ifdef NO_PPM
return false;
#endif
dprintf3("%08X %08X : %d\n",cntx1,cntx2,value);
if ( ! imppmEncode(ipi,cntx1,cntx2,ipi->contexts,value,smoothness) )
return false;
return true;
}
int iDecode(imppmi *ipi,ulong cntx1,ulong cntx2,uword smoothness)
{
int value;
#ifdef NO_PPM
return -1;
#endif
if ( (value = imppmDecode(ipi,cntx1,cntx2,ipi->contexts,smoothness)) == -1 ) {
return -1;
}
dprintf3("%08X %08X : %d\n",cntx1,cntx2,value);
return value;
}
void iDecodeGot(imppmi *ipi,ulong cntx1,ulong cntx2,uword value)
{
#ifdef NO_PPM
return;
#endif
dprintf3("%08X %08X : %d a\n",cntx1,cntx2,value);
imppmAddC(ipi,cntx1,cntx2,ipi->contexts,value);
}
bool imppmEncode(imppmi *ipi,ulong cntx1,ulong cntx2,imcontext *contexts[],
uword value,uword smoothness) // bool : coded
{
imcontext *c;
ulong hash,esc,tot;
bool ret;
if ( (c = imppmFind(ipi,cntx1,cntx2,contexts)) == NULL ) {
c = (imcontext *) GetPoolHunk(ipi->contextPool,TRUE);
hash = HASH(cntx1);
c->next = contexts[hash];
contexts[hash] = c;
c->cntx1 = cntx1; c->cntx2 = cntx2;
c->pred = value;
return false;
}
if ( c->pred == BAD_PRED ) // made a bad pred
return false;
hash = PPMQ_HASH(cntx1,smoothness);
tot = ipi->ppmq_tot[hash];
esc = ipi->ppmq_esc[hash];
if ( value == c->pred ) {
arithEncode(ipi->arith,esc,tot,tot);
ret = true;
} else {
arithEncode(ipi->arith,0,esc,tot);
c->pred = BAD_PRED; // never use this context again
ret = false;
ipi->ppmq_esc[hash]++;
}
if ( ++(ipi->ppmq_tot[hash]) > TOT_SCALEDOWN ) {
ipi->ppmq_tot[hash] >>= 1; ipi->ppmq_esc[hash] >>= 1;
ipi->ppmq_tot[hash] ++;
if ( ipi->ppmq_esc[hash] > 1 ) ipi->ppmq_esc[hash] = 1;
}
return ret;
}
int imppmDecode(imppmi *ipi,ulong cntx1,ulong cntx2,imcontext *contexts[],
uword smoothness) // -1 is an escape
{
imcontext *c;
ulong hash,got,esc,tot;
int ret;
if ( (c = imppmFind(ipi,cntx1,cntx2,contexts)) == NULL ) {
return -1;
}
if ( c->pred == BAD_PRED ) // made a bad pred
return -1;
hash = PPMQ_HASH(cntx1,smoothness);
tot = ipi->ppmq_tot[hash];
esc = ipi->ppmq_esc[hash];
got = arithGet(ipi->arith,tot);
if ( got < esc ) { //escape
arithDecode(ipi->arith,0,esc,tot);
c->pred = BAD_PRED;
ret = -1;
ipi->ppmq_esc[hash] ++;
} else {
arithDecode(ipi->arith,esc,tot,tot);
ret = c->pred;
}
if ( ++(ipi->ppmq_tot[hash]) > TOT_SCALEDOWN ) {
ipi->ppmq_tot[hash] >>= 1; ipi->ppmq_esc[hash] >>= 1;
ipi->ppmq_tot[hash] ++;
if ( ipi->ppmq_esc[hash] > 1 ) ipi->ppmq_esc[hash] = 1;
}
return ret;
}
void imppmAddC(imppmi *ipi,ulong cntx1,ulong cntx2,imcontext *contexts[],uword value)
{
imcontext *c;
if ( (c = imppmFind(ipi,cntx1,cntx2,contexts)) == NULL ) {
ulong hash;
c = (imcontext *) GetPoolHunk(ipi->contextPool,TRUE);
hash = HASH(cntx1);
c->next = contexts[hash];
contexts[hash] = c;
c->cntx1 = cntx1; c->cntx2 = cntx2;
c->pred = value;
} else {
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -