aboutsummaryrefslogblamecommitdiffstats
path: root/src/cnki_jbig_dec.c
blob: 5b262e691a29209abb9f6dcc7d06f975d98d397d (plain) (tree)
1
2
3
4
5
6
7
8
  
                                            



                                      

                    


                   
                                    







                                                                       
 








                                                                       
                                    

















                                              
                                    

















                                              
                                  































                               
                           





                           
 
                                 
                                                
 

                
 




                                
 























































































                                              
                        
 










                                                                               





                                          

                                                                                                       




                                     
                                                    



                                     
                                                    


                                     
         






                                               
 
                                         
 
                                         
 
































                                                                                


                 












                                                    
                                         






                                      
/*
 * Copyright (c) 2022, yzrh <yzrh@noema.org>
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

static const uint16_t _LSZ[0x71] = {
	0x5a1d,
	0x2586, 0x1114, 0x080b, 0x03d8, 0x01da, 0x00e5, 0x006f, 0x0036,
	0x001a, 0x000d, 0x0006, 0x0003, 0x0001, 0x5a7f, 0x3f25, 0x2cf2,
	0x207c, 0x17b9, 0x1182, 0x0cef, 0x09a1, 0x072f, 0x055c, 0x0406,
	0x0303, 0x0240, 0x01b1, 0x0144, 0x00f5, 0x00b7, 0x008a, 0x0068,
	0x004e, 0x003b, 0x002c, 0x5ae1, 0x484c, 0x3a0d, 0x2ef1, 0x261f,
	0x1f33, 0x19a8, 0x1518, 0x1177, 0x0e74, 0x0bfb, 0x09f8, 0x0861,
	0x0706, 0x05cd, 0x04de, 0x040f, 0x0363, 0x02d4, 0x025c, 0x01f8,

	0x01a4, 0x0160, 0x0125, 0x00f6, 0x00cb, 0x00ab, 0x008f, 0x5b12,
	0x4d04, 0x412c, 0x37d8, 0x2fe8, 0x293c, 0x2379, 0x1edf, 0x1aa9,
	0x174e, 0x1424, 0x119c, 0x0f6b, 0x0d51, 0x0bb6, 0x0a40, 0x5832,
	0x4d1c, 0x438e, 0x3bdd, 0x34ee, 0x2eae, 0x299a, 0x2516, 0x5570,
	0x4ca9, 0x44d9, 0x3e22, 0x3824, 0x32b4, 0x2e17, 0x56a8, 0x4f46,
	0x47e5, 0x41cf, 0x3c3d, 0x375e, 0x5231, 0x4c0f, 0x4639, 0x415e,
	0x5627, 0x50e7, 0x4b85, 0x5597, 0x504f, 0x5a10, 0x5522, 0x59eb
};

static const uint8_t _NLPS[0x71] = {
	1,
	14, 16, 18, 20, 23, 25, 28, 30,
	33, 35, 9, 10, 12, 15, 36, 38,
	39, 40, 42, 43, 45, 46, 48, 49,
	51, 52, 54, 56, 57, 59, 60, 62,
	63, 32, 33, 37, 64, 65, 67, 68,
	69, 70, 72, 73, 74, 75, 77, 78,
	79, 48, 50, 50, 51, 52, 53, 54,

	55, 56, 57, 58, 59, 61, 61, 65,
	80, 81, 82, 83, 84, 86, 87, 87,
	72, 72, 74, 74, 75, 77, 77, 80,
	88, 89, 90, 91, 92, 93, 86, 88,
	95, 96, 97, 99, 99, 93, 95, 101,
	102, 103, 104, 99, 105, 106, 107, 103,
	105, 108, 109, 110, 111, 110, 112, 112
};

static const uint8_t _NMPS[0x71] = {
	1,
	2, 3, 4, 5, 6, 7, 8, 9,
	10, 11, 12, 13, 13, 15, 16, 17,
	18, 19, 20, 21, 22, 23, 24, 25,
	26, 27, 28, 29, 30, 31, 32, 33,
	34, 35, 9, 37, 38, 39, 40, 41,
	42, 43, 44, 45, 46, 47, 48, 49,
	50, 51, 52, 53, 54, 55, 56, 57,

	58, 59, 60, 61, 62, 63, 32, 65,
	66, 67, 68, 69, 70, 71, 72, 73,
	74, 75, 76, 77, 78, 79, 48, 81,
	82, 83, 84, 85, 86, 87, 71, 89,
	90, 91, 92, 93, 94, 86, 96, 97,
	98, 99, 100, 93, 102, 103, 104, 99,
	106, 107, 103, 109, 107, 111, 109, 111
};

static const bool _SWTCH[0x71] = {
	1,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 1, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 1, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,

	0, 0, 0, 0, 0, 0, 0, 1,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 1,
	0, 0, 0, 0, 0, 0, 0, 1,
	0, 0, 0, 0, 0, 0, 1, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	1, 0, 0, 0, 0, 1, 0, 1
};

static uint8_t _ct;
static uint8_t _pix;

static uint16_t _reg_a;
static uint32_t _reg_c;
static uint8_t _mps[0x1000];
static uint8_t _st[0x1000];

static int _width;
static int _height;

static int _width_padded;

static int _ret_pos;
static unsigned char *_ret;

static int _scd_size;
static unsigned char *_scd;

static void
_bytein(void)
{
	if (_ret_pos < _scd_size)
		_reg_c += _scd[_ret_pos++] << 8;

	_ct = 8;
}

static void
_initdec(void)
{
	memset(_mps, 0, 0x1000);
	memset(_st, 0, 0x1000);

	_reg_c = 0;
	_bytein();
	_reg_c <<= 8;
	_bytein();
	_reg_c <<= 8;
	_bytein();
	_reg_a = 0x0000;
}

static void
_exchange_lps(uint16_t cx)
{
	uint8_t st_cx = _st[cx];
	uint16_t lsz_st_cx = _LSZ[_st[cx]];

	if (_reg_a < lsz_st_cx) {
		_pix = _mps[cx];
		_st[cx] = _NMPS[st_cx];
	} else {
		_pix = 1 - _mps[cx];

		if (_SWTCH[st_cx])
			_mps[cx] = _pix;

		_st[cx] = _NLPS[st_cx];
	}

	_reg_c -= _reg_a << 16;
	_reg_a = lsz_st_cx;
}

static void
_exchange_mps(uint16_t cx)
{
	uint8_t st_cx = _st[cx];
	uint16_t lsz_st_cx = _LSZ[_st[cx]];

	if (_reg_a < lsz_st_cx) {
		_pix = 1 - _mps[cx];

		if (_SWTCH[st_cx])
			_mps[cx] = _pix;

		_st[cx] = _NLPS[st_cx];
	} else {
		_pix = _mps[cx];
		_st[cx] = _NMPS[st_cx];
	}
}

static void
_renormd(void)
{
	do {
		if (_ct == 0)
			_bytein();

		_reg_a <<= 1;
		_reg_c <<= 1;
		_ct--;
	} while (_reg_a < 0x8000);

	if (_ct == 0)
		_bytein();
}

static void
_decode(uint16_t cx)
{
	_reg_a -= _LSZ[_st[cx]];

	if (_reg_a > _reg_c >> 16) {
		if (_reg_a < 0x8000) {
			_exchange_mps(cx);
			_renormd();
		} else {
			_pix = _mps[cx];
		}
	} else {
		_exchange_lps(cx);
		_renormd();
	}
}

static void
_procline(int line, char *a, char *b, char *c)
{
	/* The encoder must be erroneous */
	uint16_t cx = 0;

	if (line > 0) {
		cx += (_ret[_width_padded * (_height - line)] & 0x20) << 2;
		cx += _ret[_width_padded * (_height - line)] & 0x40;
		cx += (_ret[_width_padded * (_height - line)] & 0x80) >> 2;
	}

	if (line > 1) {
		cx += (_ret[_width_padded * (_height - line + 1)] & 0x40) >> 4;
		cx += (_ret[_width_padded * (_height - line + 1)] & 0x80) >> 6;
	}

	for (int i = 0; i < _width; i++) {
		_decode(cx);

		cx >>= 1;

		if (_pix == 1) {
			_ret[_width_padded * (_height - line - 1) + i / 8] |= _pix << (7 - (i & 0x07));
			c[i] = 1;
			cx |= 0x0200;
		} else {
			cx &= 0xfdff;
		}

		if (i + 2 < _width && a[i + 2] == 1)
			cx |= 0x0004;
		else
			cx &= 0xfffb;

		if (i + 3 < _width && b[i + 3] == 1)
			cx |= 0x0080;
		else
			cx &= 0xff7f;
	}
}

static int
_procstripe(void)
{
	if (_height <= 0 || _width_padded <= 0)
		return 1;

	int pix_size = 8 * _width_padded;

	char *buf = malloc(3 * pix_size);

	if (buf == NULL)
		return 1;

	memset(buf, 0, 3 * pix_size);

	char *a = buf;
	char *b = a + pix_size;
	char *c = b + pix_size;
	char *z;

	for (int i = 0; i < _height; i++) {
		_decode(0x029c);

		if (_pix == 1) {
			if (i > 0)
				memcpy(_ret + _width_padded * (_height - i - 1),
					_ret + _width_padded * (_height - i),
					_width_padded);

			memcpy(c, b, pix_size);
		} else {
			/* line atypical */
			memset(c, 0, pix_size);
			_procline(i, a, b, c);
		}

		z = a;
		a = b;
		b = c;
		c = z;
	}

	free(buf);

	return 0;
}

int
strdec_jbig(char **bitmap, int width, int height,
	const char * restrict jbig, int jbig_size)
{
	_width = width;
	_height = height;

	_width_padded = (_width + 7) / 8;

	memset(*bitmap, 0, _height * _width_padded);

	_ret_pos = 0;
	_ret = (unsigned char *) *bitmap;

	_scd_size = jbig_size;
	_scd = (unsigned char *) jbig;

	_initdec();
	return _procstripe();
}