2025-04-27 07:49:33 -04:00

295 lines
6.8 KiB
C

//
// Compress20
//
#ifndef MAX_WORD
#define MAX_WORD 0xFFFF
#endif
#define BAND_PIXEL 4
#define SIZE_HEADER20 10
// DCR:
// #define ADJUST3 // adjust raster data
// DCR:
#if 0 // for BGR888 (not used)
#define MakeCompress20Mode(q) ((WORD) (0x20 + (q)))
#define MakeUncompress20Mode(q) ((WORD) (0x00 + (q)))
#else // for RGB888 (Unidrv uses this format)
#define MakeCompress20Mode(q) ((WORD) (0x20 + 2 - (q)))
#define MakeUncompress20Mode(q) ((WORD) (0x00 + 2 - (q)))
#endif
typedef struct tagCODINGDATA {
PBYTE pCurPtr ;
DWORD leftCount ;
DWORD code ;
WORD codeBits ;
} CODINGDATA ;
static BOOL HufTblInitd = FALSE;
static WORD HufCode[256] ;
static BYTE HufCodeLen[256] ;
/****************************** Internal Functions ****************************/
void WriteDataToBuffer(CODINGDATA * const pCD) ;
void CodeHufmanData(const BYTE d, CODINGDATA * const pCD) ;
void WriteHeader(BYTE *pBuf, DWORD size, WORD width, WORD height, WORD mode) ;
void MakeHufmanTable20(void) ;
BOOL WriteBand(WORD width, WORD height, LONG lDelta, BYTE *pSrc, CODINGDATA *pCD) ;
/******************************************************************************/
__inline void WriteDataToBuffer(CODINGDATA * const pCD)
{
if (pCD->leftCount) {
*(pCD->pCurPtr)++ = (BYTE) pCD->code ;
pCD->leftCount-- ;
pCD->code >>= 8 ;
}
pCD->codeBits -= 8 ;
}
__inline void CodeHufmanData(const BYTE d, CODINGDATA * const pCD)
{
pCD->code |= ((DWORD) HufCode[d]) << pCD->codeBits ;
pCD->codeBits += HufCodeLen[d] ;
while (pCD->codeBits >= 8) WriteDataToBuffer(pCD) ;
}
void MakeHufmanTable20(void)
{
WORD huf, rhuf, temp, i ;
int len, num, j ;
WORD cdn[] = {0, 0, 1, 2, 2, 4, 4, 7, 9, 14, 17, 24, 172} ;
huf = 0 ;
num = 0 ;
for(len = 1 ; len <= 12; len++) {
huf <<= 1;
for(i = 0; i < cdn[len] ; i++) {
rhuf = 0 ;
temp = huf ;
for (j = 0 ; j < len ; j++) {
rhuf = (rhuf << 1) | (temp & 1) ;
temp >>= 1 ;
}
if (num) {
j = (num+1) >> 1 ;
if ((num & 0x1) == 0) j = 256 - j ;
}
else {
j = 0 ;
}
HufCode[j] = rhuf ;
HufCodeLen[j] = (BYTE) len ;
huf ++ ;
num ++ ;
}
}
}
void WriteHeader(BYTE *pBuf, DWORD size, WORD width, WORD height, WORD mode)
{
// Write Size
*pBuf++ = (BYTE) (size >> 24) ;
*pBuf++ = (BYTE) (size >> 16) ;
*pBuf++ = (BYTE) (size >> 8) ;
*pBuf++ = (BYTE) size ;
// Write width
*pBuf++ = (BYTE) (width >> 8) ;
*pBuf++ = (BYTE) width ;
// Write height
*pBuf++ = (BYTE) (height >> 8) ;
*pBuf++ = (BYTE) height ;
// Write mode
*pBuf++ = (BYTE) (mode >> 8) ;
*pBuf++ = (BYTE) mode ;
}
DWORD Compress20(
PBYTE pInBuff,
DWORD dwInBuffLen,
DWORD dwWidthBytes,
PBYTE pOutBuff,
DWORD dwOutBuffLen)
{
PBYTE pSrc ;
LONG lDelta ;
LONG nextBand ;
CODINGDATA cd ;
DWORD dwHeight ;
DWORD y, dwBlock ;
WORD width, ymod ;
if (dwWidthBytes / 3 > MAX_WORD) {
return 0 ;
}
width = (WORD) (dwWidthBytes / 3) ;
dwHeight = dwInBuffLen / dwWidthBytes ;
lDelta = (LONG) dwWidthBytes ;
pSrc = pInBuff ;
if (!HufTblInitd)
{
MakeHufmanTable20() ;
HufTblInitd = TRUE;
}
// Initialize
cd.pCurPtr = pOutBuff ;
cd.leftCount = dwOutBuffLen ;
dwBlock = dwHeight / BAND_PIXEL ;
ymod = (WORD) (dwHeight % BAND_PIXEL) ;
nextBand = lDelta * BAND_PIXEL ;
for (y = 0 ; y < dwBlock ; y++) {
if (WriteBand(width, BAND_PIXEL, lDelta, pSrc, &cd)) return 0 ;
pSrc += nextBand ;
}
if (ymod) {
if (WriteBand(width, ymod, lDelta, pSrc, &cd)) return 0 ;
}
if (cd.leftCount == 0) return 0 ;
return (dwOutBuffLen - cd.leftCount) ;
}
BOOL WriteBand(WORD width, WORD height, LONG lDelta, PBYTE pSrc, CODINGDATA *pCD)
{
DWORD bandLimit ;
PBYTE pBandStart ;
DWORD cntBandStart ;
PBYTE pBand, pPt, pPrePt ;
WORD x, y, i ;
BYTE left ;
#ifdef ADJUST3
WORD cmod3;
#endif
#ifdef ADJUST3
// DCR: begin
// Unidrv might send invalid RasterDataWidthInBytes, so
// lDelta (was RasterDataWidthInBytes) can be non-multiple of 3.
// Minidriver must complement the raster data supplemented with the
// neighbouring pixel.
// Although Unidrv may omit not only at the starting point of the raster
// but at the ending point, mini driver can't know which point is omitted,
// so mini driver always assumes the starting point is omitted.
// When ending point is omitted, the print out result can't help being
// color-shifted.
// DCR: end
// cmod3 is set to non-zero if lDelta is not a multiple of 3.
if (cmod3 = (WORD)(lDelta % 3))
{
cmod3 = 3 - cmod3; // set complementary to reduce calculation
}
// define BYTEADJ3 macro to get a byte data from PBYTE p, adjusted by
// cmod3 and complemented by pseudo raster data;
// where, x is pixel offset in the raster to check starting point condition.
#define BYTEADJ3(p, x) ((!cmod3) ? *(PBYTE)(p) : ((x) ? *((PBYTE)(p) - cmod3) : *((PBYTE)(p) + 3 - cmod3)))
#endif // ADJUST3
bandLimit = (DWORD)width * height + SIZE_HEADER20 ;
for (i = 0 ; i <= 2 ; i++) {
if (pCD->leftCount <= SIZE_HEADER20) return TRUE ;
pBandStart = pCD->pCurPtr ;
cntBandStart = pCD->leftCount ;
pCD->pCurPtr += SIZE_HEADER20 ;
pCD->leftCount -= SIZE_HEADER20 ;
pCD->code = 0 ;
pCD->codeBits = 0 ;
pBand = pSrc + i ;
pPt = pBand ;
left = 0 ;
for (x = 0 ; x < width ; x++) {
#ifndef ADJUST3
CodeHufmanData((BYTE) (*pPt-left), pCD) ;
left = *pPt ;
#else
CodeHufmanData((BYTE) (BYTEADJ3(pPt, x)-left), pCD) ;
left = BYTEADJ3(pPt, x) ;
#endif
pPt += 3 ;
}
for (y = 1 ; y < height ; y++) {
pPrePt = pBand ;
pBand += lDelta ;
pPt = pBand ;
left = 0 ;
for (x = 0 ; x < width ; x++) {
#ifndef ADJUST3
CodeHufmanData((BYTE) (*pPt-((left+*pPrePt)>>1)), pCD) ;
left = *pPt ;
#else
CodeHufmanData((BYTE) (BYTEADJ3(pPt, x)-((left+BYTEADJ3(pPrePt, x))>>1)), pCD) ;
left = BYTEADJ3(pPt, x) ;
#endif
pPt += 3 ;
pPrePt += 3 ;
}
}
if (pCD->codeBits) WriteDataToBuffer(pCD) ;
if (cntBandStart <= pCD->leftCount + bandLimit) {
// Write Block Header
WriteHeader(pBandStart, cntBandStart - pCD->leftCount, width, height, MakeCompress20Mode(i)) ;
}
else {
// Output Un-Compress Data
if (cntBandStart <= bandLimit) return TRUE ;
WriteHeader(pBandStart, bandLimit, width, height, MakeUncompress20Mode(i)) ;
pBandStart += SIZE_HEADER20 ;
pBand = pSrc + i ;
for (y = 0 ; y < height ; y++) {
pPt = pBand ;
pBand += lDelta ;
for (x = 0 ; x < width ; x++) {
#ifndef ADJUST3
*pBandStart++ = *pPt ;
#else
*pBandStart++ = BYTEADJ3(pPt, x) ;
#endif
pPt += 3 ;
}
}
pCD->pCurPtr = pBandStart ;
pCD->leftCount = cntBandStart - bandLimit ;
}
}
return FALSE ;
}