1735 lines
67 KiB
C
1735 lines
67 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* $XConsortium: ilcompg3g4.c /main/3 1995/10/23 15:42:12 rswiston $ */
|
|
/**---------------------------------------------------------------------
|
|
***
|
|
*** (c)Copyright 1991 Hewlett-Packard Co.
|
|
***
|
|
*** RESTRICTED RIGHTS LEGEND
|
|
*** Use, duplication, or disclosure by the U.S. Government is subject to
|
|
*** restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in
|
|
*** Technical Data and Computer Software clause in DFARS 252.227-7013.
|
|
*** Hewlett-Packard Company
|
|
*** 3000 Hanover Street
|
|
*** Palo Alto, CA 94304 U.S.A.
|
|
*** Rights for non-DOD U.S. Government Departments and Agencies are as set
|
|
*** forth in FAR 52.227-19(c)(1,2).
|
|
***
|
|
***-------------------------------------------------------------------*/
|
|
|
|
#include "ilint.h"
|
|
#include "ilpipelem.h"
|
|
#include "ilcompress.h"
|
|
#include "ilcodec.h"
|
|
#include "ilerrors.h"
|
|
|
|
/* ========================================================================
|
|
Compression private data structure definition
|
|
Used in Both G3 & G4 Compression ...
|
|
======================================================================== */
|
|
|
|
|
|
typedef struct {
|
|
int width; /* width of the image */
|
|
unsigned long compData; /* flags for G4 Compression Options*/
|
|
ilBool white; /* value of the white pixel 0 or 1 */
|
|
unsigned int bitCount; /* # of bits waiting to be output */
|
|
/* compatibility problem with long and unsigned long data fields */
|
|
CARD32 bits; /* bits waiting to be output */
|
|
ilPtr pDstByte; /* ptr to spot for next byte in output buffer */
|
|
ilPtr pDstBufferEnd; /* ptr _past_ last available spot in buffer */
|
|
ilImageInfo *pDstImage; /* ptr to dst image structure */
|
|
ilBool Is_Lsb_First; /* true if LSB is desired */
|
|
ilPtr gpRefLine; /* ptr.to refrence line for 2d coding */
|
|
long nDstLineBytes; /* no.of bytes in the Image */
|
|
} ilCompressG3G4PrivRec, *ilCompressG3G4PrivPtr;
|
|
|
|
|
|
/* define to find out the value of the bit (1 or 0) in the image line */
|
|
#define PIXEL(buf,ix) ((((buf)[(ix)>>3]) >> (7-((ix)&7))) & 1)
|
|
|
|
/* max bytes written after check for room in compressed buffer */
|
|
#define G3_G4_MAX_BUFFER_WRITE 10
|
|
|
|
|
|
/* ========================================================================
|
|
The following are the encode tables for CCITT. The tables are broken
|
|
down by terminating codes, make-up codes, and additional make-up codes.
|
|
There are separate tables for black and white terminating codes and
|
|
make-up codes. The first two columns are for documentation only. The
|
|
first column is the run length represented by the entry. The second
|
|
column is the bit code for the run length, left justified. The third
|
|
column is the hex number for the bit code. The fourth column is the
|
|
number of bits in the code. There is also a table with one entry for
|
|
the end-of-line (eol) code.
|
|
======================================================================== */
|
|
|
|
static unsigned short _ilEncodeWhiteTerms[64][2] = { /* white terminating codes */
|
|
|
|
/* 0: 0011 0101 0000 0000 */ 0x3500, 8,
|
|
/* 1: 0001 1100 0000 0000 */ 0x1C00, 6,
|
|
/* 2: 0111 0000 0000 0000 */ 0x7000, 4,
|
|
/* 3: 1000 0000 0000 0000 */ 0x8000, 4,
|
|
/* 4: 1011 0000 0000 0000 */ 0xB000, 4,
|
|
/* 5: 1100 0000 0000 0000 */ 0xC000, 4,
|
|
/* 6: 1110 0000 0000 0000 */ 0xE000, 4,
|
|
/* 7: 1111 0000 0000 0000 */ 0xF000, 4,
|
|
/* 8: 1001 1000 0000 0000 */ 0x9800, 5,
|
|
/* 9: 1010 0000 0000 0000 */ 0xA000, 5,
|
|
/* 10: 0011 1000 0000 0000 */ 0x3800, 5,
|
|
/* 11: 0100 0000 0000 0000 */ 0x4000, 5,
|
|
/* 12: 0010 0000 0000 0000 */ 0x2000, 6,
|
|
/* 13: 0000 1100 0000 0000 */ 0x0C00, 6,
|
|
/* 14: 1101 0000 0000 0000 */ 0xD000, 6,
|
|
/* 15: 1101 0100 0000 0000 */ 0xD400, 6,
|
|
/* 16: 1010 1000 0000 0000 */ 0xA800, 6,
|
|
/* 17: 1010 1100 0000 0000 */ 0xAC00, 6,
|
|
/* 18: 0100 1110 0000 0000 */ 0x4E00, 7,
|
|
/* 19: 0001 1000 0000 0000 */ 0x1800, 7,
|
|
/* 20: 0001 0000 0000 0000 */ 0x1000, 7,
|
|
/* 21: 0010 1110 0000 0000 */ 0x2E00, 7,
|
|
/* 22: 0000 0110 0000 0000 */ 0x0600, 7,
|
|
/* 23: 0000 1000 0000 0000 */ 0x0800, 7,
|
|
/* 24: 0101 0000 0000 0000 */ 0x5000, 7,
|
|
/* 25: 0101 0110 0000 0000 */ 0x5600, 7,
|
|
/* 26: 0010 0110 0000 0000 */ 0x2600, 7,
|
|
/* 27: 0100 1000 0000 0000 */ 0x4800, 7,
|
|
/* 28: 0011 0000 0000 0000 */ 0x3000, 7,
|
|
/* 29: 0000 0010 0000 0000 */ 0x0200, 8,
|
|
/* 30: 0000 0011 0000 0000 */ 0x0300, 8,
|
|
/* 31: 0001 1010 0000 0000 */ 0x1A00, 8,
|
|
/* 32: 0001 1011 0000 0000 */ 0x1B00, 8,
|
|
/* 33: 0001 0010 0000 0000 */ 0x1200, 8,
|
|
/* 34: 0001 0011 0000 0000 */ 0x1300, 8,
|
|
/* 35: 0001 0100 0000 0000 */ 0x1400, 8,
|
|
/* 36: 0001 0101 0000 0000 */ 0x1500, 8,
|
|
/* 37: 0001 0110 0000 0000 */ 0x1600, 8,
|
|
/* 38: 0001 0111 0000 0000 */ 0x1700, 8,
|
|
/* 39: 0010 1000 0000 0000 */ 0x2800, 8,
|
|
/* 40: 0010 1001 0000 0000 */ 0x2900, 8,
|
|
/* 41: 0010 1010 0000 0000 */ 0x2A00, 8,
|
|
/* 42: 0010 1011 0000 0000 */ 0x2B00, 8,
|
|
/* 43: 0010 1100 0000 0000 */ 0x2C00, 8,
|
|
/* 44: 0010 1101 0000 0000 */ 0x2D00, 8,
|
|
/* 45: 0000 0100 0000 0000 */ 0x0400, 8,
|
|
/* 46: 0000 0101 0000 0000 */ 0x0500, 8,
|
|
/* 47: 0000 1010 0000 0000 */ 0x0A00, 8,
|
|
/* 48: 0000 1011 0000 0000 */ 0x0B00, 8,
|
|
/* 49: 0101 0010 0000 0000 */ 0x5200, 8,
|
|
/* 50: 0101 0011 0000 0000 */ 0x5300, 8,
|
|
/* 51: 0101 0100 0000 0000 */ 0x5400, 8,
|
|
/* 52: 0101 0101 0000 0000 */ 0x5500, 8,
|
|
/* 53: 0010 0100 0000 0000 */ 0x2400, 8,
|
|
/* 54: 0010 0101 0000 0000 */ 0x2500, 8,
|
|
/* 55: 0101 1000 0000 0000 */ 0x5800, 8,
|
|
/* 56: 0101 1001 0000 0000 */ 0x5900, 8,
|
|
/* 57: 0101 1010 0000 0000 */ 0x5A00, 8,
|
|
/* 58: 0101 1011 0000 0000 */ 0x5B00, 8,
|
|
/* 59: 0100 1010 0000 0000 */ 0x4A00, 8,
|
|
/* 60: 0100 1011 0000 0000 */ 0x4B00, 8,
|
|
/* 61: 0011 0010 0000 0000 */ 0x3200, 8,
|
|
/* 62: 0011 0011 0000 0000 */ 0x3300, 8,
|
|
/* 63: 0011 0100 0000 0000 */ 0x3400, 8
|
|
};
|
|
|
|
|
|
static unsigned short _ilEncodeBlackTerms[64][2] = { /* black terminating codes */
|
|
|
|
/* 0: 0000 1101 1100 0000 */ 0x0DC0, 10,
|
|
/* 1: 0100 0000 0000 0000 */ 0x4000, 3,
|
|
/* 2: 1100 0000 0000 0000 */ 0xC000, 2,
|
|
/* 3: 1000 0000 0000 0000 */ 0x8000, 2,
|
|
/* 4: 0110 0000 0000 0000 */ 0x6000, 3,
|
|
/* 5: 0011 0000 0000 0000 */ 0x3000, 4,
|
|
/* 6: 0010 0000 0000 0000 */ 0x2000, 4,
|
|
/* 7: 0001 1000 0000 0000 */ 0x1800, 5,
|
|
/* 8: 0001 0100 0000 0000 */ 0x1400, 6,
|
|
/* 9: 0001 0000 0000 0000 */ 0x1000, 6,
|
|
/* 10: 0000 1000 0000 0000 */ 0x0800, 7,
|
|
/* 11: 0000 1010 0000 0000 */ 0x0A00, 7,
|
|
/* 12: 0000 1110 0000 0000 */ 0x0E00, 7,
|
|
/* 13: 0000 0100 0000 0000 */ 0x0400, 8,
|
|
/* 14: 0000 0111 0000 0000 */ 0x0700, 8,
|
|
/* 15: 0000 1100 0000 0000 */ 0x0C00, 9,
|
|
/* 16: 0000 0101 1100 0000 */ 0x05C0, 10,
|
|
/* 17: 0000 0110 0000 0000 */ 0x0600, 10,
|
|
/* 18: 0000 0010 0000 0000 */ 0x0200, 10,
|
|
/* 19: 0000 1100 1110 0000 */ 0x0CE0, 11,
|
|
/* 20: 0000 1101 0000 0000 */ 0x0D00, 11,
|
|
/* 21: 0000 1101 1000 0000 */ 0x0D80, 11,
|
|
/* 22: 0000 0110 1110 0000 */ 0x06E0, 11,
|
|
/* 23: 0000 0101 0000 0000 */ 0x0500, 11,
|
|
/* 24: 0000 0010 1110 0000 */ 0x02E0, 11,
|
|
/* 25: 0000 0011 0000 0000 */ 0x0300, 11,
|
|
/* 26: 0000 1100 1010 0000 */ 0x0CA0, 12,
|
|
/* 27: 0000 1100 1011 0000 */ 0x0CB0, 12,
|
|
/* 28: 0000 1100 1100 0000 */ 0x0CC0, 12,
|
|
/* 29: 0000 1100 1101 0000 */ 0x0CD0, 12,
|
|
/* 30: 0000 0110 1000 0000 */ 0x0680, 12,
|
|
/* 31: 0000 0110 1001 0000 */ 0x0690, 12,
|
|
/* 32: 0000 0110 1010 0000 */ 0x06A0, 12,
|
|
/* 33: 0000 0110 1011 0000 */ 0x06B0, 12,
|
|
/* 34: 0000 1101 0010 0000 */ 0x0D20, 12,
|
|
/* 35: 0000 1101 0011 0000 */ 0x0D30, 12,
|
|
/* 36: 0000 1101 0100 0000 */ 0x0D40, 12,
|
|
/* 37: 0000 1101 0101 0000 */ 0x0D50, 12,
|
|
/* 38: 0000 1101 0110 0000 */ 0x0D60, 12,
|
|
/* 39: 0000 1101 0111 0000 */ 0x0D70, 12,
|
|
/* 40: 0000 0110 1100 0000 */ 0x06C0, 12,
|
|
/* 41: 0000 0110 1101 0000 */ 0x06D0, 12,
|
|
/* 42: 0000 1101 1010 0000 */ 0x0DA0, 12,
|
|
/* 43: 0000 1101 1011 0000 */ 0x0DB0, 12,
|
|
/* 44: 0000 0101 0100 0000 */ 0x0540, 12,
|
|
/* 45: 0000 0101 0101 0000 */ 0x0550, 12,
|
|
/* 46: 0000 0101 0110 0000 */ 0x0560, 12,
|
|
/* 47: 0000 0101 0111 0000 */ 0x0570, 12,
|
|
/* 48: 0000 0110 0100 0000 */ 0x0640, 12,
|
|
/* 49: 0000 0110 0101 0000 */ 0x0650, 12,
|
|
/* 50: 0000 0101 0010 0000 */ 0x0520, 12,
|
|
/* 51: 0000 0101 0011 0000 */ 0x0530, 12,
|
|
/* 52: 0000 0010 0100 0000 */ 0x0240, 12,
|
|
/* 53: 0000 0011 0111 0000 */ 0x0370, 12,
|
|
/* 54: 0000 0011 1000 0000 */ 0x0380, 12,
|
|
/* 55: 0000 0010 0111 0000 */ 0x0270, 12,
|
|
/* 56: 0000 0010 1000 0000 */ 0x0280, 12,
|
|
/* 57: 0000 0101 1000 0000 */ 0x0580, 12,
|
|
/* 58: 0000 0101 1001 0000 */ 0x0590, 12,
|
|
/* 59: 0000 0010 1011 0000 */ 0x02B0, 12,
|
|
/* 60: 0000 0010 1100 0000 */ 0x02C0, 12,
|
|
/* 61: 0000 0101 1010 0000 */ 0x05A0, 12,
|
|
/* 62: 0000 0110 0110 0000 */ 0x0660, 12,
|
|
/* 63: 0000 0110 0111 0000 */ 0x0670, 12
|
|
};
|
|
|
|
|
|
static unsigned short _ilEncodeWhiteMakeupCodes[27][2] = { /* white make-up codes */
|
|
|
|
/* 64: 1101 1000 0000 0000 */ 0xD800, 5,
|
|
/* 128: 1001 0000 0000 0000 */ 0x9000, 5,
|
|
/* 192: 0101 1100 0000 0000 */ 0x5C00, 6,
|
|
/* 256: 0110 1110 0000 0000 */ 0x6E00, 7,
|
|
/* 320: 0011 0110 0000 0000 */ 0x3600, 8,
|
|
/* 384: 0011 0111 0000 0000 */ 0x3700, 8,
|
|
/* 448: 0110 0100 0000 0000 */ 0x6400, 8,
|
|
/* 512: 0110 0101 0000 0000 */ 0x6500, 8,
|
|
/* 576: 0110 1000 0000 0000 */ 0x6800, 8,
|
|
/* 640: 0110 0111 0000 0000 */ 0x6700, 8,
|
|
/* 704: 0110 0110 0000 0000 */ 0x6600, 9,
|
|
/* 768: 0110 0110 1000 0000 */ 0x6680, 9,
|
|
/* 832: 0110 1001 0000 0000 */ 0x6900, 9,
|
|
/* 896: 0110 1001 1000 0000 */ 0x6980, 9,
|
|
/* 960: 0110 1010 0000 0000 */ 0x6A00, 9,
|
|
/* 1024: 0110 1010 1000 0000 */ 0x6A80, 9,
|
|
/* 1088: 0110 1011 0000 0000 */ 0x6B00, 9,
|
|
/* 1152: 0110 1011 1000 0000 */ 0x6B80, 9,
|
|
/* 1216: 0110 1100 0000 0000 */ 0x6C00, 9,
|
|
/* 1280: 0110 1100 1000 0000 */ 0x6C80, 9,
|
|
/* 1344: 0110 1101 0000 0000 */ 0x6D00, 9,
|
|
/* 1408: 0110 1101 1000 0000 */ 0x6D80, 9,
|
|
/* 1472: 0100 1100 0000 0000 */ 0x4C00, 9,
|
|
/* 1536: 0100 1100 1000 0000 */ 0x4C80, 9,
|
|
/* 1600: 0100 1101 0000 0000 */ 0x4D00, 9,
|
|
/* 1664: 0110 0000 0000 0000 */ 0x6000, 6,
|
|
/* 1728: 0100 1101 1000 0000 */ 0x4D80, 9
|
|
};
|
|
|
|
|
|
static unsigned short _ilEncodeBlackMakeupCodes[27][2] = { /* black make-up codes */
|
|
|
|
/* 64: 0000 0011 1100 0000 */ 0x03C0, 10,
|
|
/* 128: 0000 1100 1000 0000 */ 0x0C80, 12,
|
|
/* 192: 0000 1100 1001 0000 */ 0x0C90, 12,
|
|
/* 256: 0000 0101 1011 0000 */ 0x05B0, 12,
|
|
/* 320: 0000 0011 0011 0000 */ 0x0330, 12,
|
|
/* 384: 0000 0011 0100 0000 */ 0x0340, 12,
|
|
/* 448: 0000 0011 0101 0000 */ 0x0350, 12,
|
|
/* 512: 0000 0011 0110 0000 */ 0x0360, 13,
|
|
/* 576: 0000 0011 0110 1000 */ 0x0368, 13,
|
|
/* 640: 0000 0010 0101 0000 */ 0x0250, 13,
|
|
/* 704: 0000 0010 0101 1000 */ 0x0258, 13,
|
|
/* 768: 0000 0010 0110 0000 */ 0x0260, 13,
|
|
/* 832: 0000 0010 0110 1000 */ 0x0268, 13,
|
|
/* 896: 0000 0011 1001 0000 */ 0x0390, 13,
|
|
/* 960: 0000 0011 1001 1000 */ 0x0398, 13,
|
|
/* 1024: 0000 0011 1010 0000 */ 0x03A0, 13,
|
|
/* 1088: 0000 0011 1010 1000 */ 0x03A8, 13,
|
|
/* 1152: 0000 0011 1011 0000 */ 0x03B0, 13,
|
|
/* 1216: 0000 0011 1011 1000 */ 0x03B8, 13,
|
|
/* 1280: 0000 0010 1001 0000 */ 0x0290, 13,
|
|
/* 1344: 0000 0010 1001 1000 */ 0x0298, 13,
|
|
/* 1408: 0000 0010 1010 0000 */ 0x02A0, 13,
|
|
/* 1472: 0000 0010 1010 1000 */ 0x02A8, 13,
|
|
/* 1536: 0000 0010 1101 0000 */ 0x02D0, 13,
|
|
/* 1600: 0000 0010 1101 1000 */ 0x02D8, 13,
|
|
/* 1664: 0000 0011 0010 0000 */ 0x0320, 13,
|
|
/* 1728: 0000 0011 0010 1000 */ 0x0328, 13
|
|
};
|
|
|
|
|
|
static unsigned short _ilEncodeAdditionalMakeupCodes[13][2] = { /* additional make-up codes */
|
|
|
|
|
|
/* 1792: 0000 0001 0000 0000 */ 0x0100, 11,
|
|
/* 1856: 0000 0001 1000 0000 */ 0x0180, 11,
|
|
/* 1920: 0000 0001 1010 0000 */ 0x01A0, 11,
|
|
/* 1984: 0000 0001 0010 0000 */ 0x0120, 12,
|
|
/* 2048: 0000 0001 0011 0000 */ 0x0130, 12,
|
|
/* 2112: 0000 0001 0100 0000 */ 0x0140, 12,
|
|
/* 2176: 0000 0001 0101 0000 */ 0x0150, 12,
|
|
/* 2240: 0000 0001 0110 0000 */ 0x0160, 12,
|
|
/* 2304: 0000 0001 0111 0000 */ 0x0170, 12,
|
|
/* 2368: 0000 0001 1100 0000 */ 0x01C0, 12,
|
|
/* 2432: 0000 0001 1101 0000 */ 0x01D0, 12,
|
|
/* 2496: 0000 0001 1110 0000 */ 0x01E0, 12,
|
|
/* 2560: 0000 0001 1111 0000 */ 0x01F0, 12
|
|
};
|
|
|
|
|
|
static unsigned short _ilEncodeEndOfLineCode[1][2] = { /* End-of-line code */
|
|
|
|
/* eol: 0000 0000 0001 0000 */ 0x0010, 12
|
|
};
|
|
|
|
/* Table containing (array) the number of consecutive zeros
|
|
from the start (msb first), in chars for 0x00 to 0xff
|
|
for e.g number of consecutive zeros in 0x00 = 8
|
|
in 0x0f = 4 */
|
|
|
|
static unsigned char zeroruns[256] = {
|
|
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x00 - 0x0f */
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 - 0x1f */
|
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x20 - 0x2f */
|
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x30 - 0x3f */
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4f */
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x5f */
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6f */
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x7f */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xf0 - 0xff */
|
|
};
|
|
|
|
|
|
/* Table containing (array) the number of consecutive ones
|
|
from the start (msb first), in chars for 0x00 to 0xff
|
|
for e.g number of consecutive ones in 0x00 = 0
|
|
in 0xff = 8 */
|
|
|
|
|
|
static unsigned char oneruns[256] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x0f */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x6f */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 - 0x8f */
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x90 - 0x9f */
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xa0 - 0xaf */
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xb0 - 0xbf */
|
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xc0 - 0xcf */
|
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xd0 - 0xdf */
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xe0 - 0xef */
|
|
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, /* 0xf0 - 0xff */
|
|
};
|
|
|
|
|
|
|
|
/* ========================================================================
|
|
|
|
-------------------- _ilGetAbsDiff(). --------------------
|
|
Input : the pointer to the pointer to the strings (image Line)
|
|
startPixel from which the diff. is to be found
|
|
endPixel i.e upto which the diff can be checked.
|
|
color of the current pixel (startPixel)
|
|
nTimes - no. of times the counting is to be repeated i.e for
|
|
how many changing elements, the operation is to be
|
|
performed.
|
|
|
|
Does :
|
|
Calculates the count of pixels of the same color and returns the absolute
|
|
position of the next changing element and Returns the Absolute Position
|
|
of the element
|
|
|
|
** used for G4,G3-2d compression and de-comression
|
|
======================================================================== */
|
|
|
|
static int
|
|
_ilGetAbsDiff( unsigned char *sByte,
|
|
int startPixel,
|
|
int endPixel,
|
|
int color,
|
|
int nTimes)
|
|
{
|
|
int rel_diff, abs_diff;
|
|
|
|
unsigned char *bp;
|
|
int ini_diff;
|
|
int n, fin_diff;
|
|
unsigned char *table ;
|
|
|
|
bp = sByte;
|
|
|
|
bp += startPixel>> 3; /* adjust byte offset */
|
|
|
|
do {
|
|
|
|
if ((startPixel == -1) ) {
|
|
fin_diff = 1;
|
|
bp = sByte;
|
|
goto done;
|
|
}
|
|
else {
|
|
|
|
table = (color ? oneruns : zeroruns );
|
|
ini_diff = endPixel- startPixel;
|
|
|
|
/* Find difference in the partial byte on the current Byte */
|
|
|
|
if (ini_diff > 0 && (n = (startPixel & 7))) {
|
|
fin_diff = table[(*bp << n) & 0xff];
|
|
|
|
if (fin_diff > 8-n) /* Consecutive bits extend beyond the current byte */
|
|
fin_diff = 8-n;
|
|
|
|
|
|
/* return the initial differece, if the current byte happens
|
|
to be the last byte of the Imageline and cosecutive bits
|
|
extend beyound that. */
|
|
|
|
if (fin_diff > ini_diff)
|
|
fin_diff = ini_diff;
|
|
|
|
if (n + fin_diff < 8 ) /* Consecutive bits does not go upto the edge, so return the diff */
|
|
goto done;
|
|
ini_diff -= fin_diff;
|
|
bp++;
|
|
} else
|
|
fin_diff = 0;
|
|
|
|
/* Count in the bytes, till opp. color is found
|
|
i.e while the diff >= 8 */
|
|
|
|
while (ini_diff >= 8) {
|
|
n = table[*bp];
|
|
fin_diff += n;
|
|
ini_diff -= n;
|
|
if (n < 8) /* end of run */
|
|
goto done;
|
|
|
|
bp++;
|
|
}
|
|
|
|
/* Find difference in the partial byte on RHS */
|
|
|
|
if (ini_diff > 0) {
|
|
n = table[*bp];
|
|
fin_diff += (n > ini_diff ? ini_diff : n);
|
|
}
|
|
}
|
|
done:
|
|
startPixel += fin_diff;
|
|
color = !color;
|
|
|
|
} while (--nTimes > 0 );
|
|
|
|
return(startPixel);
|
|
|
|
}
|
|
/* --------------- End of _ilGetAbsDiff() ---------------- */
|
|
|
|
/* ========================================================================
|
|
--------------------- _ilCompressG3G4ReallocBuffer -------------------
|
|
Reallocate the output (compressed) buffer and reset pPriv->pDst(BufferEnd).
|
|
======================================================================== */
|
|
|
|
static ilBool _ilCompressG3G4ReallocBuffer (
|
|
ilCompressG3G4PrivPtr pPriv
|
|
)
|
|
{
|
|
unsigned long offset;
|
|
|
|
offset = pPriv->pDstByte - pPriv->pDstImage->plane[0].pPixels;
|
|
if (!_ilReallocCompressedBuffer (pPriv->pDstImage, 0, offset + G3_G4_MAX_BUFFER_WRITE))
|
|
return FALSE;
|
|
pPriv->pDstByte = pPriv->pDstImage->plane[0].pPixels + offset;
|
|
pPriv->pDstBufferEnd = pPriv->pDstImage->plane[0].pPixels +
|
|
(pPriv->pDstImage->plane[0].bufferSize - G3_G4_MAX_BUFFER_WRITE);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* ========================================================================
|
|
|
|
-------------------- _ilPutData() --------------------
|
|
Input : the pointer to the private record ilCompressG3G4PrivPtr;
|
|
i.e the destination Image structre, the coded bits, the counts;
|
|
Does : adjusts the bit (integer to which the codes are put) and puts
|
|
them interms of bytes into the Destination Image.
|
|
Checks for the number of bits coded, and adds the bytes
|
|
accordingly. If LSB first is desired, reverses the bits and puts.
|
|
Checks for sufficient room in the destination buffer.
|
|
Returns : IL_OK, if does not encouter any error in allocating space.
|
|
|
|
** used in G4 compression also.
|
|
======================================================================== */
|
|
static ilError
|
|
_ilPutData (
|
|
ilCompressG3G4PrivPtr pPriv)
|
|
|
|
{
|
|
|
|
/* use local variables here, copy the values from pPriv to local & copy them
|
|
back at the end of the function; this is expected to be faster */
|
|
|
|
unsigned int bitCount; /* # of bits waiting to be output */
|
|
/* compatibility problem with long and unsigned long data fields */
|
|
CARD32 bits; /* bits waiting to be output */
|
|
ilPtr pDstByte; /* ptr to spot for next byte in output buffer */
|
|
ilBool Is_Lsb_First;
|
|
|
|
/* Output 3 bytes; check for room in buffer; realloc if not room.
|
|
*/
|
|
if (pPriv->pDstByte >= pPriv->pDstBufferEnd)
|
|
if (!_ilCompressG3G4ReallocBuffer (pPriv))
|
|
return IL_ERROR_MALLOC;
|
|
|
|
|
|
pDstByte = pPriv->pDstByte ;
|
|
bits = pPriv->bits;
|
|
bitCount = pPriv->bitCount;
|
|
Is_Lsb_First = pPriv->Is_Lsb_First;
|
|
|
|
|
|
if ( bitCount > 24 ){
|
|
|
|
/* If LSbit first is Required, reverse bit order for the Output */
|
|
if ( Is_Lsb_First ) {
|
|
*pDstByte = ilBitReverseTable [(unsigned char)(( bits >> 24) & 0xff)];
|
|
pDstByte++;
|
|
*pDstByte = ilBitReverseTable [(unsigned char)(( bits >> 16) & 0xff)];
|
|
pDstByte++;
|
|
*pDstByte = ilBitReverseTable [(unsigned char)(( bits >> 8) & 0xff)];
|
|
pDstByte++;
|
|
|
|
}
|
|
|
|
else {
|
|
*pDstByte = (unsigned char)(( bits >> 24) & 0xff);
|
|
pDstByte++;
|
|
*pDstByte = (unsigned char)(( bits >> 16) & 0xff);
|
|
pDstByte++;
|
|
*pDstByte = (unsigned char)(( bits >> 8) & 0xff);
|
|
pDstByte++;
|
|
}
|
|
|
|
bits <<= 24;
|
|
bitCount -= 24;
|
|
} /* > 24 */
|
|
|
|
else if ( bitCount > 16 ) {
|
|
|
|
/* If LSbit first is Required, reverse bit order for the Output */
|
|
if ( Is_Lsb_First ) {
|
|
*pDstByte = ilBitReverseTable [(unsigned char)(( bits >> 24) & 0xff)];
|
|
pDstByte++;
|
|
*pDstByte = ilBitReverseTable [(unsigned char)(( bits >> 16) & 0xff)];
|
|
pDstByte++;
|
|
|
|
}
|
|
|
|
else {
|
|
*pDstByte = (unsigned char)(( bits >> 24) & 0xff);
|
|
pDstByte++;
|
|
*pDstByte = (unsigned char)(( bits >> 16) & 0xff);
|
|
pDstByte++;
|
|
}
|
|
|
|
bits <<= 16;
|
|
bitCount -= 16;
|
|
} /* > 16 */
|
|
|
|
else if ( bitCount > 8 ) {
|
|
|
|
/* If LSbit first is Required, reverse bit order for the Output */
|
|
if ( Is_Lsb_First ) {
|
|
*pDstByte = ilBitReverseTable [(unsigned char)(( bits >> 24) & 0xff)];
|
|
pDstByte++;
|
|
}
|
|
|
|
else {
|
|
*pDstByte = (unsigned char)(( bits >> 24) & 0xff);
|
|
pDstByte++;
|
|
}
|
|
|
|
bits <<= 8;
|
|
bitCount -= 8;
|
|
} /* > 8 */
|
|
|
|
pPriv->pDstByte = pDstByte ;
|
|
pPriv->bits = bits ;
|
|
pPriv->bitCount = bitCount ;
|
|
|
|
return(IL_OK);
|
|
}
|
|
|
|
/* ========================================================================
|
|
|
|
-------------------- _ilGetNdPutNewBits() --------------------
|
|
Input : the pointer to the private record ilCompressG3G4PrivPtr;
|
|
i.e the destination Image structre, the coded bits, the counts;
|
|
Count: the number of pixels in the source image for which
|
|
appropriate code is to be found from the tables;
|
|
pixelValue : Color of the pixel : white 0 , black 1 ;
|
|
|
|
Does : depending upon the pixelValue, retrieves the bit sequence
|
|
and the number of bits (from the encodeWhite or Black tables)
|
|
and adds them to the running Bit stream(pPriv->bits);
|
|
The number of maximum bits for a run length could turn out
|
|
to be 37 i.e may exceed 32 the max. no of bits that could
|
|
be put into a unsigned long int; So care is taken to send
|
|
the bits to the destination, if the count exceeds 16, before
|
|
retrieveing the makeup codes.
|
|
|
|
Returns : IL_OK, if does not encouter any error .
|
|
|
|
** used in G4 compression also.
|
|
======================================================================== */
|
|
static ilError
|
|
_ilGetNdPutNewBits(
|
|
ilCompressG3G4PrivPtr pPriv,
|
|
int count,
|
|
ilBool pixelValue
|
|
)
|
|
|
|
{
|
|
|
|
ilBool termFlag ;
|
|
int index ;
|
|
int tnumBits ;
|
|
/* compatibility problem with long and unsigned long data fields */
|
|
CARD32 tnewBits;
|
|
ilError error;
|
|
|
|
/* find the new bit pattern and the number of bits in the tables */
|
|
termFlag = FALSE;
|
|
|
|
while (termFlag == FALSE) {
|
|
|
|
if (count > 2560) { /* write out longest available */
|
|
tnewBits = _ilEncodeAdditionalMakeupCodes[12][0];
|
|
tnumBits = _ilEncodeAdditionalMakeupCodes[12][1];
|
|
count -= 2560;
|
|
}
|
|
|
|
else {
|
|
|
|
if (count > 1791) { /* use additional make-up codes */
|
|
index = (count - 1792) / 64;
|
|
tnewBits = _ilEncodeAdditionalMakeupCodes[index][0];
|
|
tnumBits = _ilEncodeAdditionalMakeupCodes[index][1];
|
|
count = (count - 1792 - (index * 64));
|
|
}
|
|
|
|
else {
|
|
|
|
if (count > 63) {
|
|
index = (count - 64) / 64;
|
|
if (!pixelValue) { /* use white make-up codes */
|
|
tnewBits = _ilEncodeWhiteMakeupCodes[index][0];
|
|
tnumBits = _ilEncodeWhiteMakeupCodes[index][1];
|
|
}
|
|
|
|
else { /* use black make-up codes */
|
|
tnewBits = _ilEncodeBlackMakeupCodes[index][0];
|
|
tnumBits = _ilEncodeBlackMakeupCodes[index][1];
|
|
}
|
|
count = count - 64 - index * 64;
|
|
}
|
|
|
|
else { /* count <= 63 */
|
|
|
|
if (!pixelValue ) { /* use white terminating codes */
|
|
tnewBits = _ilEncodeWhiteTerms[count][0];
|
|
tnumBits = _ilEncodeWhiteTerms[count][1];
|
|
}
|
|
|
|
else { /* use black terminating codes */
|
|
tnewBits = _ilEncodeBlackTerms[count][0];
|
|
tnumBits = _ilEncodeBlackTerms[count][1];
|
|
}
|
|
termFlag = TRUE;
|
|
count = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
tnewBits = tnewBits << 16; /* shift the new bits to the left end */
|
|
tnewBits = tnewBits >> pPriv->bitCount ; /* right shift by the current bitCount */
|
|
pPriv->bits = pPriv->bits | tnewBits; /* add the new bits to the existing bits */
|
|
pPriv->bitCount = pPriv->bitCount + tnumBits; /* reduce the bitCount by no. of bits added*/
|
|
|
|
if (pPriv->bitCount > 16) /* put the data, if count is more */
|
|
if (error = _ilPutData(pPriv))
|
|
return error;
|
|
}
|
|
|
|
return(IL_OK);
|
|
|
|
}
|
|
|
|
|
|
/* ========================= G3 Compression ========================================= */
|
|
|
|
|
|
/* ========================================================================
|
|
-------------------- _ilCompressG3Init -------------------
|
|
Routine defined in ilCompressG3 for initializing CCITT Group3
|
|
compression when the pipe gets executed.
|
|
======================================================================== */
|
|
|
|
static ilError _ilCompressG3Init(
|
|
ilCompressG3G4PrivPtr pPriv,
|
|
ilImageInfo *pSrcImage,
|
|
ilImageInfo *pDstImage
|
|
)
|
|
{
|
|
/* Allocate space for Reference line, needed for 2 dimensional coding */
|
|
|
|
pPriv->gpRefLine = (ilPtr)IL_MALLOC(pPriv->nDstLineBytes );
|
|
if (!pPriv->gpRefLine)
|
|
return IL_ERROR_MALLOC;
|
|
return IL_OK;
|
|
|
|
}
|
|
/* End _ilCompressG3Init() */
|
|
|
|
/* ========================================================================
|
|
-------------------- _ilCompressG3Cleanup -------------------
|
|
Routine defined in ilCompressG3 for Cleaning up CCITT Group3
|
|
compression when the pipe gets executed.
|
|
======================================================================== */
|
|
|
|
static ilError _ilCompressG3Cleanup(
|
|
ilCompressG3G4PrivPtr pPriv,
|
|
ilImageInfo *pSrcImage,
|
|
ilImageInfo *pDstImage
|
|
)
|
|
{
|
|
|
|
if (pPriv->gpRefLine)
|
|
IL_FREE( (ilPtr)pPriv->gpRefLine);
|
|
return IL_OK;
|
|
|
|
}
|
|
/* End _ilCompressG3Cleanup() */
|
|
|
|
/* ========================================================================
|
|
-------------------- _ilCompressG3Line() --------------------
|
|
Input : the pointer to the private record ilCompressG3G4PrivPtr;
|
|
Pointer to the Source Image Line
|
|
Does : calculates the successive no. of white pixels & black pixels
|
|
and put the Codes appropriately into the Destination image.
|
|
|
|
Returns : IL_OK, if does not encouter any error in compression.
|
|
======================================================================== */
|
|
static ilError
|
|
_ilCompressG3Line(
|
|
ilCompressG3G4PrivPtr pPriv,
|
|
ilPtr pSrc
|
|
)
|
|
{
|
|
int a0, b2; /* changing elements pertaining to the pSrcLine */
|
|
ilBool pixelValue; /* value of the pixel 0 or 1 */
|
|
ilError error;
|
|
long width; /* width of the image */
|
|
ilBool white; /* value of the white pixel */
|
|
#ifndef NOINLINEG3
|
|
int ini_diff;
|
|
int n, fin_diff;
|
|
unsigned char *table ;
|
|
ilBool termFlag ;
|
|
int index;
|
|
int tnumBits ;
|
|
int count;
|
|
CARD32 tnewBits;
|
|
#endif
|
|
|
|
width = pPriv->width;
|
|
white = pPriv->white;
|
|
a0 = 0;
|
|
|
|
/* G3 1 D Compression ...
|
|
For eachline, count the number of white pixels, if it is Zero, then put the
|
|
code for zero white Run... The line should always start with a White Run.
|
|
Then count the number or successive black Pixels and put the appropriate
|
|
code..
|
|
Continue this series of white & black runs until the end of line is Reached..
|
|
*/
|
|
|
|
/* Alternate counting white and black pixels, starting with white */
|
|
pixelValue = 0;
|
|
for (;;) {
|
|
|
|
/* Count the white Pixels .... (formerly:
|
|
b2 = _ilGetRelDiff(&pSrcLine, a0, width,white);
|
|
*/
|
|
ini_diff = width - a0;
|
|
table = (white ? oneruns : zeroruns );
|
|
|
|
/* Find difference in the partial byte on the current Byte */
|
|
|
|
if (ini_diff > 0 && (n = (a0 & 7))) {
|
|
b2 = table[(*pSrc << n) & 0xff];
|
|
if (b2 > 8-n) /* Consecutive bits extend beyond the current byte */
|
|
b2 = 8-n;
|
|
|
|
/* return the initial differece, if the current byte happens
|
|
to be the last byte of the Imageline and cosecutive bits
|
|
extend beyound that. */
|
|
|
|
if (b2 > ini_diff)
|
|
b2 = ini_diff;
|
|
|
|
if (n + b2 < 8 ) /* Consecutive bits does not go upto the edge, so return the diff */
|
|
goto done;
|
|
ini_diff -= b2;
|
|
pSrc++;
|
|
} else
|
|
b2 = 0;
|
|
|
|
/* Count in the bytes, till opp. color is found i.e while the diff >= 8 */
|
|
|
|
while (ini_diff >= 8) {
|
|
n = table[*pSrc];
|
|
b2 += n;
|
|
ini_diff -= n;
|
|
if (n < 8) /* end of run */
|
|
goto done;
|
|
pSrc++;
|
|
}
|
|
|
|
/* Find difference in the partial byte on RHS */
|
|
|
|
if (ini_diff > 0) {
|
|
n = table[*pSrc];
|
|
b2 += (n > ini_diff ? ini_diff : n);
|
|
}
|
|
done:
|
|
|
|
/* Inline code for:
|
|
if (error = _ilGetNdPutNewBits( pPriv,b2,pixelValue))
|
|
return error;
|
|
*/
|
|
|
|
/* find the new bit pattern and the number of bits in the tables */
|
|
termFlag = FALSE;
|
|
count = b2;
|
|
|
|
while (termFlag == FALSE) {
|
|
|
|
if (count > 2560) { /* write out longest available */
|
|
tnewBits = _ilEncodeAdditionalMakeupCodes[12][0];
|
|
tnumBits = _ilEncodeAdditionalMakeupCodes[12][1];
|
|
count -= 2560;
|
|
}
|
|
|
|
else {
|
|
|
|
if (count > 1791) { /* use additional make-up codes */
|
|
index = (count - 1792) / 64;
|
|
tnewBits = _ilEncodeAdditionalMakeupCodes[index][0];
|
|
tnumBits = _ilEncodeAdditionalMakeupCodes[index][1];
|
|
count = (count - 1792 - (index * 64));
|
|
}
|
|
|
|
else {
|
|
|
|
if (count > 63) {
|
|
index = (count - 64) / 64;
|
|
if (!pixelValue) { /* use white make-up codes */
|
|
tnewBits = _ilEncodeWhiteMakeupCodes[index][0];
|
|
tnumBits = _ilEncodeWhiteMakeupCodes[index][1];
|
|
}
|
|
|
|
else { /* use black make-up codes */
|
|
tnewBits = _ilEncodeBlackMakeupCodes[index][0];
|
|
tnumBits = _ilEncodeBlackMakeupCodes[index][1];
|
|
}
|
|
count = count - 64 - index * 64;
|
|
}
|
|
|
|
else { /* count <= 63 */
|
|
|
|
if (!pixelValue ) { /* use white terminating codes */
|
|
tnewBits = _ilEncodeWhiteTerms[count][0];
|
|
tnumBits = _ilEncodeWhiteTerms[count][1];
|
|
}
|
|
|
|
else { /* use black terminating codes */
|
|
tnewBits = _ilEncodeBlackTerms[count][0];
|
|
tnumBits = _ilEncodeBlackTerms[count][1];
|
|
}
|
|
termFlag = TRUE;
|
|
count = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
tnewBits = tnewBits << 16; /* shift the new bits to the left end */
|
|
tnewBits = tnewBits >> pPriv->bitCount ; /* right shift by the current bitCount */
|
|
pPriv->bits = pPriv->bits | tnewBits; /* add the new bits to the existing bits */
|
|
pPriv->bitCount = pPriv->bitCount + tnumBits; /* reduce the bitCount by no. of bits added*/
|
|
|
|
if (pPriv->bitCount > 16) /* put the data, if count is more */
|
|
if (error = _ilPutData(pPriv))
|
|
return error;
|
|
}
|
|
|
|
a0 += b2;
|
|
if (a0 >= width)
|
|
break;
|
|
|
|
white = !white; /* reverse sense of white and pixelValue */
|
|
pixelValue = !pixelValue;
|
|
}
|
|
|
|
return(IL_OK);
|
|
}
|
|
|
|
|
|
/* ========================================================================
|
|
-------------------- ilCompressG3Execute() -------------------
|
|
Routine defined in ilCompressG3 for executing CCITT Group3
|
|
compression when the pipe gets executed.
|
|
|
|
|
|
======================================================================== */
|
|
|
|
static ilError _ilCompressG3Execute(
|
|
ilExecuteData *pData,
|
|
unsigned long dstLine,
|
|
unsigned long *pNLines
|
|
)
|
|
{
|
|
|
|
|
|
/* ========================================================================
|
|
ilCompressG3Execute() definitions
|
|
======================================================================== */
|
|
|
|
#define g3_1d 1 /* Tag bit denoting G3 1 d compression */
|
|
#define g3_2d 0 /* Tag bit denoting G3 2 d compression */
|
|
|
|
/* Macro for putting a Byte aligned EOL into the compressed data streame */
|
|
|
|
#define PUT_BYTE_ALIGNED_EOL \
|
|
if (pPriv->bitCount < 5) { \
|
|
pPriv->bits = pPriv->bits | (0x001 << 16); \
|
|
pPriv->bitCount = 16; \
|
|
} \
|
|
else if (pPriv->bitCount < 13) { \
|
|
pPriv->bits = pPriv->bits | (0x001 << 8); \
|
|
pPriv->bitCount = 24; \
|
|
} \
|
|
else { \
|
|
pPriv->bits = pPriv->bits | 0x001; \
|
|
pPriv->bitCount = 32; \
|
|
}
|
|
|
|
/* Macro for putting the Tag Bit after the EOL for G3 2 Dimensional Compression */
|
|
|
|
#define PUT_TAG_BIT \
|
|
pPriv->bits = pPriv->bits | (tag_bit << ( 31 - pPriv->bitCount)); \
|
|
pPriv->bitCount += 1;
|
|
|
|
/* ========================================================================
|
|
ilCompressG3Execute() Declarations
|
|
======================================================================== */
|
|
|
|
unsigned short pixelValue; /* Current Pixel value, white = 0, black = 1 */
|
|
long nLines; /* Number of lines per source image strip */
|
|
ilPtr pSrcLine; /* Pointer to source image data first byte of line */
|
|
unsigned long srcNBytes; /* Number of source image bytes per row */
|
|
ilImagePlaneInfo *pSrcPlane; /* Pointer to the Source Image Plane */
|
|
ilCompressG3G4PrivPtr pPriv; /* Pointer to private image data */
|
|
|
|
ilPtr pRefLine; /* Pointer to first byte of Reference Line */
|
|
int temp; /* some temp var.. */
|
|
ilError error; /* returned error */
|
|
ilBool Is_2DCoding; /* G3 2 D coding is required, if True */
|
|
int k,kmax; /* K factors used for 2 D coding */
|
|
int tag_bit; /* Tag bit, used if 2 D coding is required */
|
|
ilBool Is_EOLs; /* EOL markers are set, and will have to be put */
|
|
|
|
/* ========================================================================
|
|
Set up for execution of compression algorithm code
|
|
======================================================================== */
|
|
|
|
pPriv = (ilCompressG3G4PrivPtr) pData->pPrivate;
|
|
|
|
/* Number of lines of source image data contained in the current strip */
|
|
nLines = *pNLines;
|
|
if (nLines <= 0) return IL_OK;
|
|
|
|
pSrcPlane = &pData->pSrcImage->plane[0];
|
|
srcNBytes = pSrcPlane->nBytesPerRow;
|
|
pSrcLine = pSrcPlane->pPixels + pData->srcLine * srcNBytes;
|
|
|
|
|
|
pPriv->pDstImage = pData->pDstImage;
|
|
if (pPriv->pDstImage->plane[0].bufferSize < G3_G4_MAX_BUFFER_WRITE)
|
|
if (!_ilReallocCompressedBuffer (pPriv->pDstImage, 0, G3_G4_MAX_BUFFER_WRITE))
|
|
return IL_ERROR_MALLOC;
|
|
|
|
|
|
pPriv->pDstByte = pPriv->pDstImage->plane[0].pPixels + *pData->compressed.pDstOffset;
|
|
pPriv->pDstBufferEnd = pPriv->pDstImage->plane[0].pPixels +
|
|
(pPriv->pDstImage->plane[0].bufferSize - G3_G4_MAX_BUFFER_WRITE);
|
|
|
|
Is_EOLs = ( pPriv->compData & IL_G3M_EOL_MARKERS);
|
|
Is_2DCoding = ( pPriv->compData & IL_G3M_2D);
|
|
|
|
/* For G3 - 2D files, EOLs must be present, if not Error in the Compressed
|
|
flags... so check for that */
|
|
if ( (Is_2DCoding) && (!(Is_EOLs)) )
|
|
return IL_ERROR_COMPRESSION ;
|
|
|
|
|
|
kmax = 0;
|
|
|
|
/* If 2 D mode of Compression is required, then allocate space for the Reference
|
|
line, equal to the size of one image line, and set all the bits to that of
|
|
white pixels in the Image.
|
|
|
|
Find out the K factor and set it. K specifies that, in 2 D coding, after coding
|
|
one line 1 dimensionally, the next (K-1) lines should be coded 2 dimensionally,
|
|
and again one line 1 dimen... & (K-1) 2 dimen... ;
|
|
|
|
The default value of K is assumed to be 4 , for every 1 d coding, after that,
|
|
there will be 3 2d coded lines.
|
|
Setting IL_G3M_K_FACTOR_2 in the compData mask bits , will take K = 2.
|
|
*/
|
|
if (Is_2DCoding) {
|
|
|
|
if (pPriv->white)
|
|
memset(pPriv->gpRefLine,0xff,(pSrcPlane->nBytesPerRow ));
|
|
else
|
|
memset(pPriv->gpRefLine,0x00,(pSrcPlane->nBytesPerRow ));
|
|
pRefLine = pPriv->gpRefLine;
|
|
|
|
if ( pPriv->compData & IL_G3M_K_FACTOR_2 )
|
|
kmax = 2;
|
|
else kmax = 4;
|
|
k = kmax - 1 ;
|
|
}
|
|
|
|
|
|
tag_bit = g3_1d;
|
|
pPriv->Is_Lsb_First = ( pPriv->compData & IL_G3M_LSB_FIRST) ;
|
|
pPriv->bitCount = 0;
|
|
pPriv->bits = 0;
|
|
|
|
|
|
/* Compress the Image Strip Using the CCITT Group3 algorithm */
|
|
/* The flow is ...
|
|
for each of the line to be compressed, before compressing, put the
|
|
EOL markers aligned or unaligned as appropriately, And then decide
|
|
whether 1 D coding or 2 D coding should be done, and call
|
|
ilCompressG3Line() or ilCompressG4Line() accordingly.
|
|
|
|
After successful return from ilCompress..Line(), increment the
|
|
Source image & Destn. image .
|
|
*/
|
|
|
|
while (nLines-- > 0) { /* for each line in the Src Image Strip */
|
|
/* call _ilCompressG4Line */
|
|
|
|
if ( Is_EOLs ) {
|
|
|
|
/* add EOL code (0x001) for NON byte-aligned EOL support (CCITT Group3 Type3) */
|
|
if (pPriv->compData & IL_G3M_EOL_UNALIGNED) {
|
|
pPriv->bits = (pPriv->bits | (0x00100000 >> pPriv->bitCount));
|
|
pPriv->bitCount += 12;
|
|
}
|
|
/* add EOL code (0x[xxx xxxx0000 00000001]) for byte-aligned EOL support (Class F) */
|
|
else {
|
|
PUT_BYTE_ALIGNED_EOL
|
|
}
|
|
if (error = _ilPutData(pPriv))
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
if ( Is_2DCoding ) { /* if 2DCoding is required */
|
|
|
|
PUT_TAG_BIT /* add the tag bit after EOL ... */
|
|
if ( tag_bit == g3_1d ) { /* next line must be 1 D coded */
|
|
if (error = _ilCompressG3Line( pPriv,pSrcLine )) /* call 1 D Coding */
|
|
return error;
|
|
tag_bit = g3_2d ;
|
|
} else { /* next line must be 2 D coded */
|
|
if (error = _ilCompressG4Line( pPriv,pSrcLine,pRefLine )) /* call 2 D Coding */
|
|
return error;
|
|
k-- ; /* substract 1 line for 2d coding */
|
|
}
|
|
|
|
if ( k == 0 ) { /* next line must be 1 D coded */
|
|
tag_bit = g3_1d ;
|
|
k = kmax - 1;
|
|
} else
|
|
pRefLine = pSrcLine ; /* set the Current Line as Reference Line */
|
|
|
|
} else { /* Only 1 D coding is Required */
|
|
|
|
if ( !(Is_EOLs) ) { /* if EOLs not specified, then next row of compressed
|
|
data must start from the next byte boudary, so offset */
|
|
if ( ( temp = pPriv->bitCount % 8) != 0 ) {
|
|
pPriv->bits = (pPriv->bits | (0x0000 >> pPriv->bitCount));
|
|
pPriv->bitCount += (8-temp) ;
|
|
}
|
|
} /* Block !(Is_EOLs) */
|
|
if (error = _ilCompressG3Line( pPriv,pSrcLine )) /* call 1 D Coding */
|
|
return error;
|
|
} /* Block Is_2DCoding*/
|
|
|
|
pSrcLine += srcNBytes; /* increment the Source Line */
|
|
if (pPriv->bitCount > 16)
|
|
if (error = _ilPutData(pPriv)) /* Put data, if count > 16 */
|
|
return error;
|
|
} /* while (nLines-- > 0 ) loop */
|
|
if (error = _ilPutData(pPriv))
|
|
return error;
|
|
|
|
/* All data (bits > 8) would have been added to Dstn, by _ilPutData()
|
|
In case if more bits are remaining, add to the Dst Image */
|
|
|
|
if (pPriv->bitCount > 0) {
|
|
|
|
/* If LSbit first is the special of the day, reverse bit order */
|
|
if ( pPriv->Is_Lsb_First ) {
|
|
*pPriv->pDstByte = ilBitReverseTable [(unsigned char)((pPriv->bits >> 24) & 0xff)];
|
|
pPriv->pDstByte++;
|
|
pPriv->bits <<= 8;
|
|
}
|
|
else {
|
|
*pPriv->pDstByte = (unsigned char)((pPriv->bits >> 24) & 0xff);
|
|
pPriv->pDstByte++;
|
|
pPriv->bits <<= 8;
|
|
}
|
|
|
|
}
|
|
|
|
/* Return the number of bytes written, = dst ptr - beginning of dst buffer */
|
|
*pData->compressed.pNBytesWritten = pPriv->pDstByte -
|
|
(pPriv->pDstImage->plane[0].pPixels + *pData->compressed.pDstOffset);
|
|
return IL_OK;
|
|
}
|
|
/* End ilCompressG3Execute() */
|
|
|
|
|
|
|
|
/* ========================================================================
|
|
|
|
-------------------- ilCompressG3() --------------------
|
|
Main body of code for CCITT Group3 . This includes
|
|
image descriptor parameter error checking and function calls for:
|
|
strip handler initialization, adding the filter element to the pipe,
|
|
pipe initialization and execution, compression algorithm.....
|
|
|
|
======================================================================== */
|
|
|
|
IL_PRIVATE
|
|
ilBool _ilCompressG3 (
|
|
ilPipe pipe,
|
|
ilPipeInfo *pinfo,
|
|
ilImageDes *pimdes,
|
|
ilImageFormat *pimformat,
|
|
ilSrcElementData *pSrcData,
|
|
ilPtr pCompData
|
|
)
|
|
{
|
|
ilDstElementData dstdata;
|
|
ilCompressG3G4PrivPtr pPriv;
|
|
unsigned long compData;
|
|
|
|
/* Validate that image is bitonal */
|
|
if (pimdes->type != IL_BITONAL)
|
|
return ilDeclarePipeInvalid (pipe, IL_ERROR_IMAGE_TYPE);
|
|
|
|
/*
|
|
Check for Group3, uncompressed, or any undefined bits on. These
|
|
are not supported!
|
|
*/
|
|
|
|
compData = (pCompData) ? *((unsigned long *)pCompData) : 0;
|
|
if (compData & IL_G3M_UNCOMPRESSED )
|
|
return ilDeclarePipeInvalid (pipe, IL_ERROR_NOT_IMPLEMENTED);
|
|
|
|
/* From check in ilCompress(), pipe image is either uncompressed or G3, in
|
|
which case check variants: if they match, exit with success, otherwise
|
|
force decompression.
|
|
*/
|
|
if (pimdes->compression == IL_G3) {
|
|
if (compData == pimdes->compInfo.g3.flags ) {
|
|
pipe->context->error = IL_OK;
|
|
return TRUE;
|
|
}
|
|
ilGetPipeInfo (pipe, TRUE, pinfo, pimdes, pimformat); /* decompress */
|
|
}
|
|
|
|
/* Validate image bits per pixel */
|
|
if (pimformat->nBitsPerSample[0] != 1)
|
|
if (!ilConvert (pipe, (ilImageDes *)NULL, IL_FORMAT_BIT, 0, (ilPtr)NULL))
|
|
return FALSE;
|
|
|
|
|
|
/* ========================================================================
|
|
The following strip handler initialize code for BITONAL compression
|
|
formats is common for all compression types, yet duplicated where used.
|
|
======================================================================== */
|
|
|
|
/* dstdata describes strips being output to next pipe element */
|
|
dstdata.producerObject = (ilObject) NULL;
|
|
pimdes->compression = IL_G3;
|
|
pimdes->compInfo.g3.flags = compData;
|
|
dstdata.pDes = pimdes;
|
|
dstdata.pFormat = IL_FORMAT_BIT;
|
|
dstdata.width = pinfo->width;
|
|
dstdata.height = pinfo->height;
|
|
dstdata.stripHeight = pSrcData->stripHeight;
|
|
dstdata.constantStrip = pSrcData->constantStrip;
|
|
dstdata.pPalette = (unsigned short *)NULL;
|
|
|
|
dstdata.pCompData = (ilPtr)NULL; /* des.compInfo.g3.flags describes it */
|
|
|
|
|
|
/* ========================================================================
|
|
Add the filter to the pipeline
|
|
======================================================================== */
|
|
|
|
pPriv = (ilCompressG3G4PrivPtr) ilAddPipeElement(pipe, IL_FILTER,
|
|
sizeof(ilCompressG3G4PrivRec),
|
|
0, pSrcData, &dstdata,_ilCompressG3Init,
|
|
_ilCompressG3Cleanup, IL_NPF, _ilCompressG3Execute, 0);
|
|
if (!pPriv) return FALSE;
|
|
|
|
/* save private data */
|
|
pPriv->width = pinfo->width;
|
|
pPriv->compData = compData;
|
|
pPriv->white = ( pimdes->blackIsZero ? 1 : 0 );
|
|
pPriv->nDstLineBytes = (pPriv->width + 7) / 8;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* ============================== G4 Compression ================================= */
|
|
|
|
/* Code for the Modes for Group 4 compression
|
|
Horizontal Mode, Pass Mode Vertical Mode */
|
|
|
|
static unsigned short horizcode[1][2] =
|
|
/* 001 */ { 0x1,3 };
|
|
static unsigned short passcode [1][2] =
|
|
/* 0001 */ { 0x1,4 };
|
|
static unsigned short vcodes[7][2] = {
|
|
/* 0000 011 */ { 0x03,7 },
|
|
/* 0000 11 */ { 0x03,6 },
|
|
/* 011 */ { 0x03,3 },
|
|
/* 1 */ { 0x1 ,1 },
|
|
/* 010 */ { 0x2,3 },
|
|
/* 0000 10 */ { 0x02,6 },
|
|
/* 0000 010 */ { 0x02,7 }
|
|
};
|
|
|
|
|
|
/* ========================================================================
|
|
-------------------- _ilCompressG4Init -------------------
|
|
Routine defined in ilCompressG4 for initializing CCITT Group3
|
|
compression when the pipe gets executed.
|
|
|
|
======================================================================== */
|
|
|
|
static ilError _ilCompressG4Init(
|
|
ilCompressG3G4PrivPtr pPriv,
|
|
ilImageInfo *pSrcImage,
|
|
ilImageInfo *pDstImage
|
|
)
|
|
{
|
|
/* Allocate space for Reference line, needed for 2 dimensional coding */
|
|
|
|
pPriv->gpRefLine = (ilPtr)IL_MALLOC(pPriv->nDstLineBytes );
|
|
if (!pPriv->gpRefLine)
|
|
return IL_ERROR_MALLOC;
|
|
return IL_OK;
|
|
|
|
}
|
|
/* End _ilCompressG4Init() */
|
|
/* ========================================================================
|
|
-------------------- _ilCompressG4Cleanup -------------------
|
|
Routine defined in ilCompressG4 for Cleaning up CCITT Group3
|
|
compression when the pipe gets executed.
|
|
======================================================================== */
|
|
|
|
static ilError _ilCompressG4Cleanup(
|
|
ilCompressG3G4PrivPtr pPriv,
|
|
ilImageInfo *pSrcImage,
|
|
ilImageInfo *pDstImage
|
|
)
|
|
{
|
|
|
|
if (pPriv->gpRefLine)
|
|
IL_FREE( (ilPtr)pPriv->gpRefLine);
|
|
return IL_OK;
|
|
|
|
}
|
|
/* End _ilCompressG4Cleanup() */
|
|
|
|
|
|
|
|
/* ========================================================================
|
|
|
|
-------------------- _ilCompressG4Line() --------------------
|
|
Input : the pointer to the private record ilCompressG3G4PrivPtr;
|
|
i.e the destination Image structre, the coded bits, the counts;
|
|
|
|
pSrcLine : Pointer to the first byte of the Current source
|
|
image line, that is to be coded.
|
|
pRefLine : Pointer to the first byte of the Reference Line
|
|
used for coding the current line.
|
|
|
|
Does : From the Source line and Reference line, calculates the
|
|
Changing elements viz. a0,a1,a2,b1,b2;
|
|
Identifies the Mode to any one of
|
|
Horizontal Mode or Vertical Mode or Pass Mode;
|
|
Gets the codes for these modes and adds to the bitstream
|
|
(pPriv->bits, and increments pPriv->bitCount)
|
|
If Horizontal Mode, further gets the codes for the white
|
|
and black run lengths, and puts the code to the stream;
|
|
Calculates new values for a0,a1,a2,b1,b2 and goes on till
|
|
the value of a0 reaches the end of the Source Line.
|
|
Puts the data to the destination Image (calls _ilPutData())
|
|
|
|
|
|
Returns : IL_OK, if does not encouter any error .
|
|
|
|
** used in G3 compression for 2 Dimensional coding .
|
|
======================================================================== */
|
|
ilError
|
|
_ilCompressG4Line(
|
|
ilCompressG3G4PrivPtr pPriv,
|
|
ilPtr pSrcLine,
|
|
ilPtr pRefLine
|
|
)
|
|
{
|
|
int a0, a1, a2; /* changing elements pertaining to the pSrcLine */
|
|
int b1,b2; /* changing elements pertaining to the pRefLine */
|
|
int d ;
|
|
short numBits; /* the number of bits for the current run length */
|
|
/* compatibility problem with long and unsigned long data fields */
|
|
CARD32 newBits; /* value of the bit code for the run length, left justified */
|
|
ilBool pixelValue; /* value of the pixel 0 or 1 */
|
|
ilError error;
|
|
|
|
|
|
/*************************************************************************
|
|
** From Page 27 of spec:
|
|
** 4.2.1.3.1 Definition of changing picture elements
|
|
** A changing element is defined as an element whose "colour" (i.e., B or W) is
|
|
** different from the of the previous element along the same scan line.
|
|
** a0 The reference or starting changing element on the coding line.
|
|
** At the start of the coding line, a0 is set on an imaginary white
|
|
** changing element siturated just before the first element on the line.
|
|
** During the coding of the coding line, the position of a0 is defined by
|
|
** the previous coding mode.
|
|
** a1 The next changing element to the right of a0 on the coding line.
|
|
** a2 The next changing element to the right of a1 on the coding line.
|
|
** b1 The first chaning element on the reference line to the right of
|
|
** a0 and of opposite colour to a0.
|
|
** b2 The next changing element to the right of b1 on the reference line.
|
|
****************************************************************************/
|
|
|
|
|
|
a0 = 0;
|
|
a1 = (PIXEL(pSrcLine, 0) != pPriv->white ? 0 :
|
|
_ilGetAbsDiff(pSrcLine, 0, pPriv->width,pPriv->white,1));
|
|
a2 = 0;
|
|
b1 = (PIXEL(pRefLine, 0) != pPriv->white ? 0 :
|
|
_ilGetAbsDiff(pRefLine, 0, pPriv->width,pPriv->white,1));
|
|
b2 = 0;
|
|
|
|
for (;;) {
|
|
|
|
b2 = _ilGetAbsDiff(pRefLine, b1, pPriv->width,PIXEL(pRefLine,b1),1);
|
|
|
|
if (b2 >= a1) { /* either Horiz mode or Vert mode */
|
|
/* b2 is not to the left of a1 */
|
|
d = b1 - a1; /* diff of b1 & a1, this determines */
|
|
/* whether H or V mode */
|
|
|
|
|
|
if (!(-3 <= d && d <= 3)) { /* horizontal mode deducted */
|
|
|
|
a2 = _ilGetAbsDiff(pSrcLine, a1, pPriv->width,PIXEL(pSrcLine,a1),1);
|
|
newBits = horizcode[0][0]; /* get the code for Horiz Mode */
|
|
numBits = horizcode[0][1];
|
|
newBits = newBits << ( 32 - ( numBits + pPriv->bitCount)) ;
|
|
pPriv->bits = pPriv->bits | newBits; /* add the new bits to the stream */
|
|
pPriv->bitCount = pPriv->bitCount + numBits;
|
|
|
|
if (pPriv->bitCount > 16) /* put data to the destination */
|
|
if (error = _ilPutData(pPriv))
|
|
return error;
|
|
|
|
if (a0+a1 == 0 || PIXEL(pSrcLine, a0) == pPriv->white ) {
|
|
|
|
pixelValue = 0; /* first white run length 0 for white */
|
|
if (error = _ilGetNdPutNewBits( pPriv,a1-a0,pixelValue)) /* get & put white for a1-a0 */
|
|
return error;
|
|
pixelValue = 1;
|
|
if (error = _ilGetNdPutNewBits( pPriv,a2-a1,pixelValue)) /* get & put black for a2-a1 */
|
|
return error;
|
|
} else {
|
|
|
|
pixelValue = 1; /* first black run length 0 for black */
|
|
if (error = _ilGetNdPutNewBits( pPriv,a1-a0,pixelValue)) /* get & put black for a1-a0 */
|
|
return error;
|
|
pixelValue = 0;
|
|
if (error = _ilGetNdPutNewBits( pPriv,a2-a1,pixelValue)) /* get & put white for a2-a1 */
|
|
return error;
|
|
}
|
|
a0 = a2; /* set a0 to a2 for further coding */
|
|
} else { /* vertical mode deducted a1b1 <= 3 */
|
|
|
|
newBits = vcodes[d+3][0]; /* get the code for Vertical Mode */
|
|
numBits = vcodes[d+3][1];
|
|
newBits = newBits << ( 32 - ( numBits + pPriv->bitCount)) ;
|
|
pPriv->bits = pPriv->bits | newBits; /* add the new bits to the stream */
|
|
pPriv->bitCount = pPriv->bitCount + numBits;
|
|
if (pPriv->bitCount > 16) /* put data to the destination */
|
|
if (error = _ilPutData(pPriv))
|
|
return error;
|
|
|
|
a0 = a1; /* set a0 to a1 for further coding */
|
|
}
|
|
} else { /* pass mode deducted b2 > a1 */
|
|
|
|
|
|
newBits = passcode[0][0]; /* get the code for Vertical Mode */
|
|
numBits = passcode[0][1];
|
|
newBits = newBits << ( 32 - ( numBits + pPriv->bitCount)) ;
|
|
pPriv->bits = pPriv->bits | newBits; /* add the new bits to the stream */
|
|
pPriv->bitCount = pPriv->bitCount + numBits;
|
|
if (pPriv->bitCount > 16) /* put data to the destination */
|
|
if (error = _ilPutData(pPriv))
|
|
return error;
|
|
|
|
a0 = b2; /* set a0 to b2 for further coding */
|
|
}
|
|
|
|
if (a0 >= pPriv->width) /* end of the line, break */
|
|
break;
|
|
a1 = _ilGetAbsDiff(pSrcLine, a0, pPriv->width,PIXEL(pSrcLine,a0),1);
|
|
b1 = _ilGetAbsDiff(pRefLine, a0, pPriv->width,PIXEL(pRefLine,a0),1);
|
|
if (PIXEL(pRefLine, b1) == PIXEL(pSrcLine, a0))
|
|
b1 = _ilGetAbsDiff(pRefLine, b1, pPriv->width,PIXEL(pRefLine,b1),1);
|
|
|
|
newBits = 0;
|
|
numBits = 0;
|
|
} /* for (;;) loop */
|
|
|
|
|
|
return(IL_OK);
|
|
}
|
|
|
|
/* ========================================================================
|
|
|
|
-------------------- _ilCompressG4Execute() -------------------
|
|
Routine defined in ilCompressG4 for executing CCITT Group4
|
|
compression when the pipe gets executed.
|
|
|
|
======================================================================== */
|
|
|
|
static ilError _ilCompressG4Execute(
|
|
ilExecuteData *pData,
|
|
unsigned long dstLine,
|
|
unsigned long *pNLines
|
|
)
|
|
{
|
|
|
|
|
|
/* ========================================================================
|
|
ilCompressG4Execute() Declarations
|
|
======================================================================== */
|
|
|
|
|
|
unsigned short pixelValue; /* Current Pixel value, white = 0, black = 1 */
|
|
long nLines; /* Number of lines per source image strip */
|
|
ilPtr pSrcLine; /* Pointer to source image data first byte of line */
|
|
unsigned long srcNBytes; /* Number of source image bytes per row */
|
|
ilImagePlaneInfo *pSrcPlane; /* Pointer to the Source Image Plane */
|
|
ilCompressG3G4PrivPtr pPriv; /* Pointer to private image data */
|
|
ilPtr pRefLine; /* Pointer to first byte of Reference Line */
|
|
ilError error; /* returned error */
|
|
|
|
/* ========================================================================
|
|
Set up for execution of compression algorithm code
|
|
======================================================================== */
|
|
|
|
pPriv = (ilCompressG3G4PrivPtr) pData->pPrivate;
|
|
|
|
/* Number of lines of source image data contained in the current strip */
|
|
nLines = *pNLines;
|
|
if (nLines <= 0) return IL_OK;
|
|
|
|
pSrcPlane = &pData->pSrcImage->plane[0];
|
|
srcNBytes = pSrcPlane->nBytesPerRow;
|
|
pSrcLine = pSrcPlane->pPixels + pData->srcLine * srcNBytes;
|
|
|
|
/* Make sure dst compressed bufferSize is min # writes in size.
|
|
Set pDst to beginning of dst buffer + dst offset (= 0 unless writing
|
|
to an image, in which case = byte past where last strip was written).
|
|
Set pDstBufferEnd to begin of buffer + bufferSize - max # bytes written,
|
|
so that pDst <= pDstBufferEnd can check for room for writing max # bytes.
|
|
*/
|
|
|
|
|
|
pPriv->pDstImage = pData->pDstImage;
|
|
if (pPriv->pDstImage->plane[0].bufferSize < G3_G4_MAX_BUFFER_WRITE)
|
|
if (!_ilReallocCompressedBuffer (pPriv->pDstImage, 0, G3_G4_MAX_BUFFER_WRITE))
|
|
return IL_ERROR_MALLOC;
|
|
|
|
|
|
pPriv->pDstByte = pPriv->pDstImage->plane[0].pPixels + *pData->compressed.pDstOffset;
|
|
pPriv->pDstBufferEnd = pPriv->pDstImage->plane[0].pPixels +
|
|
(pPriv->pDstImage->plane[0].bufferSize - G3_G4_MAX_BUFFER_WRITE);
|
|
|
|
|
|
/* Set the Reference Line to have white pixels. If the value of
|
|
white pixel is 1, set the line to have bits 1, else set the
|
|
line with zeros; For each strip or block, first, the reference
|
|
line must be taken as white; after coding one line, the coded
|
|
line becomes the reference line for the next line. */
|
|
|
|
if (pPriv->white)
|
|
memset(pPriv->gpRefLine,0xff,(pSrcPlane->nBytesPerRow ));
|
|
else
|
|
memset(pPriv->gpRefLine,0x00,(pSrcPlane->nBytesPerRow ));
|
|
|
|
pRefLine = pPriv->gpRefLine;
|
|
|
|
pPriv->Is_Lsb_First = ( ( pPriv->compData & IL_G4M_LSB_FIRST) ? 1 : 0 );
|
|
|
|
/* Compress the Image Strip Using the G4 algorithm */
|
|
/* G4 Compression uses Two - dimensional coding
|
|
|
|
* Two dimensional coding for bi-level images : - line-by-line
|
|
coding method in which the position of each changing picture
|
|
element on the current coding line is coded with respect to the
|
|
position of a corresponding reference element situated on
|
|
either the coding line or the reference line, which is
|
|
immediately above the coding line.
|
|
|
|
- depending upon the values of the relative positions of changing
|
|
elements, one of the three modes are identified, which are
|
|
Pass mode, Horizontal mode & Vertical mode. Codes for these
|
|
modes along with run length codes (only in case of Horizontal
|
|
mode) are put. And the run-length codes are same as used
|
|
in Group 3 scheme
|
|
|
|
_ilCompressG4Line(.. ) takes the input from pSrcLine & pRefLine
|
|
and compresses/encodes the line and put the output to DstBuffer
|
|
in pPriv record. This function will be used in G3 Compression
|
|
for 2d option G3-2d.
|
|
|
|
After coding all the lines, code for End Of Fascimile Block(EOFB)
|
|
is put, which is two EOL codes.
|
|
*/
|
|
|
|
|
|
pPriv->bitCount = 0;
|
|
pPriv->bits = 0;
|
|
|
|
while (nLines-- > 0) { /* for each line in the Src Image Strip */
|
|
/* call _ilCompressG4Line */
|
|
|
|
if (error = _ilCompressG4Line( pPriv,pSrcLine,pRefLine ))
|
|
return error;
|
|
|
|
if (pPriv->bitCount > 16)
|
|
if (error = _ilPutData(pPriv)) /* Put data, if count > 16 */
|
|
return error;
|
|
|
|
pRefLine = pSrcLine ; /* set the Current Line as Reference Line */
|
|
pSrcLine += srcNBytes; /* Increment the Source Line */
|
|
|
|
} /* while (nLines-- > 0 ) loop */
|
|
|
|
|
|
/* Add the End Of Fascimile Block (EOFB) code to the Destination Image */
|
|
|
|
pPriv->bits = (pPriv->bits | (_ilEncodeEndOfLineCode[0][0] << (16 - pPriv->bitCount) ));
|
|
pPriv->bitCount += _ilEncodeEndOfLineCode[0][1];
|
|
|
|
if (error = _ilPutData(pPriv))
|
|
return error;
|
|
|
|
pPriv->bits = (pPriv->bits | (_ilEncodeEndOfLineCode[0][0] << (16 - pPriv->bitCount) ));
|
|
pPriv->bitCount += _ilEncodeEndOfLineCode[0][1];
|
|
|
|
if (error = _ilPutData(pPriv))
|
|
return error;
|
|
|
|
/* All data (bits > 8) would have been added to Dstn, by _ilPutData()
|
|
In case if more bits are remaining, add to the Dst Image */
|
|
|
|
if (pPriv->bitCount > 0) {
|
|
|
|
/* If LSbit first is Required, reverse bit order for the Output */
|
|
if ( pPriv->Is_Lsb_First ) {
|
|
*pPriv->pDstByte = ilBitReverseTable [(unsigned char)((pPriv->bits >> 24) & 0xff)];
|
|
pPriv->pDstByte++;
|
|
pPriv->bits <<= 8;
|
|
}
|
|
else {
|
|
*pPriv->pDstByte = (unsigned char)((pPriv->bits >> 24) & 0xff);
|
|
pPriv->pDstByte++;
|
|
pPriv->bits <<= 8;
|
|
}
|
|
|
|
}
|
|
|
|
/* Return the number of bytes written, = dst ptr - beginning of dst buffer */
|
|
*pData->compressed.pNBytesWritten = pPriv->pDstByte -
|
|
(pPriv->pDstImage->plane[0].pPixels + *pData->compressed.pDstOffset);
|
|
|
|
return IL_OK;
|
|
}
|
|
|
|
/* End ilCompressG4Execute() */
|
|
|
|
|
|
/* ========================================================================
|
|
|
|
-------------------- ilCompressG4() --------------------
|
|
Main body of code for CCITT Group4 . This includes
|
|
image descriptor parameter error checking and function calls for:
|
|
strip handler initialization, adding the filter element to the pipe,
|
|
pipe initialization and execution, compression algorithm.....
|
|
|
|
======================================================================== */
|
|
|
|
IL_PRIVATE
|
|
ilBool _ilCompressG4 (
|
|
ilPipe pipe,
|
|
ilPipeInfo *pinfo,
|
|
ilImageDes *pimdes,
|
|
ilImageFormat *pimformat,
|
|
ilSrcElementData *pSrcData,
|
|
ilPtr pCompData
|
|
)
|
|
{
|
|
ilDstElementData dstdata;
|
|
ilCompressG3G4PrivPtr pPriv;
|
|
unsigned long compData;
|
|
|
|
/* Validate that image is bitonal */
|
|
if (pimdes->type != IL_BITONAL)
|
|
return ilDeclarePipeInvalid (pipe, IL_ERROR_IMAGE_TYPE);
|
|
|
|
/*
|
|
Check for Group4, uncompressed, or any undefined bits on. These
|
|
are not supported!
|
|
*/
|
|
|
|
compData = (pCompData) ? *((unsigned long *)pCompData) : 0;
|
|
if (compData & IL_G4M_UNCOMPRESSED )
|
|
return ilDeclarePipeInvalid (pipe, IL_ERROR_NOT_IMPLEMENTED);
|
|
|
|
/* From check in ilCompress(), pipe image is either uncompressed or G4, in
|
|
which case check variants: if they match, exit with success, otherwise
|
|
force decompression.
|
|
*/
|
|
if (pimdes->compression == IL_G4) {
|
|
if ((compData & IL_G4M_LSB_FIRST) ==
|
|
(pimdes->compInfo.g4.flags & IL_G4M_LSB_FIRST)) {
|
|
pipe->context->error = IL_OK;
|
|
return TRUE;
|
|
}
|
|
ilGetPipeInfo (pipe, TRUE, pinfo, pimdes, pimformat); /* decompress */
|
|
}
|
|
|
|
/* Validate image bits per pixel */
|
|
if (pimformat->nBitsPerSample[0] != 1)
|
|
if (!ilConvert (pipe, (ilImageDes *)NULL, IL_FORMAT_BIT, 0, (ilPtr)NULL))
|
|
return FALSE;
|
|
|
|
|
|
/* ========================================================================
|
|
The following strip handler initialize code for BITONAL compression
|
|
formats is common for all compression types, yet duplicated where used.
|
|
======================================================================== */
|
|
|
|
/* dstdata describes strips being output to next pipe element */
|
|
dstdata.producerObject = (ilObject) NULL;
|
|
pimdes->compression = IL_G4;
|
|
pimdes->compInfo.g4.flags = compData;
|
|
dstdata.pDes = pimdes;
|
|
dstdata.pFormat = IL_FORMAT_BIT;
|
|
dstdata.width = pinfo->width;
|
|
dstdata.height = pinfo->height;
|
|
dstdata.stripHeight = pSrcData->stripHeight;
|
|
dstdata.constantStrip = pSrcData->constantStrip;
|
|
dstdata.pPalette = (unsigned short *)NULL;
|
|
dstdata.pCompData = (ilPtr)NULL; /* des.compInfo.g4.flags describes it */
|
|
|
|
|
|
/* ========================================================================
|
|
Add the filter to the pipeline
|
|
======================================================================== */
|
|
|
|
pPriv = (ilCompressG3G4PrivPtr) ilAddPipeElement(pipe, IL_FILTER,
|
|
sizeof(ilCompressG3G4PrivRec),
|
|
0, pSrcData, &dstdata,_ilCompressG4Init,
|
|
_ilCompressG4Cleanup, IL_NPF, _ilCompressG4Execute, 0);
|
|
if (!pPriv) return FALSE;
|
|
|
|
/* save private data */
|
|
pPriv->width = pinfo->width;
|
|
pPriv->compData = compData;
|
|
pPriv->white = ( pimdes->blackIsZero ? 1 : 0 );
|
|
pPriv->nDstLineBytes = (pPriv->width + 7) / 8;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|