/* encode.c - implement encoding routines */
static char *rcsid
= "$Header: /f/osi/others/quipu/photo/RCS/encode.c,v 7.4 91/02/22 09:29:14 mrose Interim $";
* $Header: /f/osi/others/quipu/photo/RCS/encode.c,v 7.4 91/02/22 09:29:14 mrose Interim $
* Revision 7.4 91/02/22 09:29:14 mrose
* Revision 1.6 91/01/08 21:56:34 kej
* Correct bug in flush_output; it wasn't writing the last incomplete
* byte to the output stream.
* Revision 1.5 91/01/07 22:20:34 kej
* Fully specify the BIT STRING which contains the G3NonBasicParams.
* Revision 1.4 91/01/07 23:50:25 kej
* Support fax images encoded as a SEQUENCE which contains a SET followed by
* a SEQUENCE of BIT STRING.
* Revision 1.3 91/01/05 23:31:07 kej
* Implement support for specification of all G3-Fax nonbasic parameters.
* Revision 1.2 91/01/05 00:31:34 kej
* ISODE claimed to be creating fax images as ASN.1-encoded BIT STRING's.
* However, the encoding was incorrect. This revision corrects the
* problem, implements 1-d and 2-d encoding of fax images, and it provides
* a backward compatible mechanism for reading the old, broken images.
* Revision 1.1 91/01/02 21:35:28 kej
* Revision 7.1 90/07/09 14:40:25 mrose
* Revision 7.0 89/11/23 22:01:39 mrose
* Acquisition, use, and distribution of this module and related
* materials are subject to the restrictions of a license agreement.
* Consult the Preface in the User's Manual for the full terms of
extern int PIC_LINESIZE
,STOP
,NUMLINES
;
int a0
, a1
, b1
, b2
; /* markers */
* G3-Fax nonbasic parameters.
/* encoding format options */
/* SYNOPSIS: Implements CCITT recommendation T.4.
/* This recomendation is concerned with compressing of bit maps.
/* This routine sets up the data buffers, then calls routines
/* to encode one line of the bit map. A line can be encoded either one
/* dimensionally or two dimensionally depending upon the 'k parameter'.
/* When a line is encoded two dimensionally, the line before is used as a
/* reference. For each line encoded, a record of where the run changes occur
/* are kept. This is the used as the reference.
char * encode_t4 (k_param
, inbuf
, eolnskip
)
bit_string ref_line
; /* Reference line */
bit_string t4_line
; /* Output encoded line */
bit_string code_line
; /* Line we are codeing */
short i
,j
; /* Loop variable */
int run_buf
[LINEBUF
], run_buf2
[LINEBUF
];
ref_line
.run_top
= run_buf
;
code_line
.run_top
= run_buf2
;
code_line
.dbuf_top
= inbuf
;
t4_line
.dbuf_top
= malloc ((PIC_LINESIZE
* NUMLINES
) + 28);
/* Repeat this loop once for every input line expected */
for (i
= 0; i
< NUMLINES
; i
++) {
if (code_line
.run_top
== run_buf
) { /*swap buffers*/
ref_line
.run_top
= run_buf
;
code_line
.run_top
= run_buf2
;
ref_line
.run_top
= run_buf2
;
code_line
.run_top
= run_buf
;
code_line
.run_pos
= code_line
.run_top
;
ref_line
.run_pos
= ref_line
.run_top
;
/* fill buffer for coding line */
code_line
.run_pos
= code_line
.run_top
;
set_bit (&t4_line
); /* tag bit, 1-d line follows */
code_one (&code_line
, &t4_line
);
clr_bit (&t4_line
); /* tag bit, 2-d line follows */
code_two (&ref_line
, &code_line
, &t4_line
);
code_one (&code_line
, &t4_line
);
/* skip any extra eoln bit in orig data */
for (j
= 0; j
< eolnskip
; j
++)
/* now finish with 6 EOL's, as per T.4 */
for (i
= 0; i
< 5; ++i
) {
if (k_param
> 1) set_bit (&t4_line
);
/* flush buffers, write preamble */
return (t4_line
.dbuf_top
);
/* SYNOPSIS: codes one line of a bit map into t4
/* To encode a line one dimensionally, bits are read in until
/* a change is noticed, when this happens, the run_length code for the number
/* of bits read in is found, and written to the output file.
/* A run_length code may consist of two parts if the run is large, a make up
code_one (lineptr
,t4_lineptr
)
bit_string
* lineptr
; /* input line */
bit_string
* t4_lineptr
; /* output line */
char colour
= WHITE
; /* the colour of the current bit */
full_code code
; /* the code for the characters run_length */
int old_pos
= 1; /* the number of bits of the same colur read in */
len
= (forcesize
- PIC_LINESIZE
)/ 2;
code
= get_code ( len
, WHITE
);
if (code
.make
.length
!= 0)
put_code (t4_lineptr
,code
.make
); /* the make code */
put_code (t4_lineptr
, code
.term
); /* the terminal code */
code
= get_code (0,BLACK
);
put_code (t4_lineptr
, code
.term
);
/* get code for next run = pos of current change - pos of last change */
tlen
= *++lineptr
->run_pos
- old_pos
;
code
= get_code (tlen
,colour
);
if (code
.make
.length
!= 0)
put_code (t4_lineptr
,code
.make
); /* the make code */
put_code (t4_lineptr
, code
.term
); /* the terminal code */
old_pos
= *lineptr
->run_pos
;
} while (*lineptr
->run_pos
<= PIC_LINESIZE
);
code
= get_code (0,colour
);
put_code (t4_lineptr
, code
.term
);
code
= get_code ( forcesize
- len
, colour
);
if (code
.make
.length
!= 0)
put_code (t4_lineptr
,code
.make
); /* the make code */
put_code (t4_lineptr
, code
.term
); /* the terminal code */
/* SYNOPSIS: Codes one line of a bit map two dimensionally as
/* described by CCITT T.4.
/* DESCRIPTION: Two lines are compared by looking at the list of run changes.
/* In order to do this, this list has to be created for the line we are about
/* to encode. The encoding procedure then follows the flow chart in the CCITT
/* recommendation. This is summarised as follows:
/* 1. Find the positions a0, a1, b1, b2.
/* 2. Compare to see which mode is required.
/* The positions of a1, b1, b2 are found from the run change list. a0 is known
code_two (ref_lineptr
,code_lineptr
,t4_lineptr
)
bit_string
* ref_lineptr
; /* reference line */
bit_string
* code_lineptr
; /* line to encode */
bit_string
* t4_lineptr
; /* output line */
code_lineptr
->run_pos
= code_lineptr
->run_top
;
while (*code_lineptr
->run_pos
> a0
)
while (*code_lineptr
->run_pos
<= a0
&& *code_lineptr
->run_pos
< STOP
)
a1
= *code_lineptr
->run_pos
;
while (*ref_lineptr
->run_pos
> a0
) {
ref_colour
= 1 - ref_colour
;
while (*ref_lineptr
->run_pos
<= a0
&& *ref_lineptr
->run_pos
< STOP
) {
ref_colour
= 1 - ref_colour
;
if (ref_colour
== colour
&& *ref_lineptr
->run_pos
< STOP
) {
ref_colour
= 1 - ref_colour
;
b1
= *ref_lineptr
->run_pos
;
b2
= *(ref_lineptr
->run_pos
+ 1);
/* select mode and code it */
else if (abs (a1
- b1
) <= 3) {
vertical_mode (t4_lineptr
);
horizontal_mode (code_lineptr
,t4_lineptr
,colour
);
/* SYNOPSIS: Encodes pass_mode
/* DESCRIPTION: When pass mode is detected, the pass mode code is written to
/* the output, and a0 is moved to underneath b2.
static code_word code
= {4,0x0200};
put_code (t4_lineptr
,code
);
/* ROUTINE: Vertical_mode
/* SYNOPSIS: Encodes vertical mode.
/* DESCRIPTION: Vertical mode is encoded by writing a particualr code
/* depending on the offset between a1 and b1.
vertical_mode (t4_lineptr
)
static code_word code
[7] = {
put_code (t4_lineptr
, code
[a1
- b1
+ 3]);
/* ROUTINE: Horizontal_mode
/* SYNOPSIS: Encodes horizontal mode
/* DESCRIPTION: When horizontal mode is detected no further compaction can
/* can take place, so the next two run lengths are written to the output.
/* a0 is moved to after these runs.
horizontal_mode (code_lineptr
,t4_lineptr
,colour
)
bit_string
* code_lineptr
;
static code_word h_code
= {3,0x0400};
if (a0
== 0) /* special case at start of line */
a2
= *(++code_lineptr
->run_pos
);
put_code (t4_lineptr
, h_code
); /* code for horiz mode */
/* get & put first run */
code
= get_code (a1
- a0
, colour
);
if (code
.make
.length
!= 0)
put_code (t4_lineptr
, code
.make
);
put_code (t4_lineptr
, code
.term
);
/* get & put second run */
code
= get_code (a2
- a1
, 1 - colour
);
if (code
.make
.length
!= 0)
put_code (t4_lineptr
, code
.make
);
put_code (t4_lineptr
, code
.term
);
/* ROUTINE: Put_code () */
/* SYNOPSIS: appends the code word to the 'line'. */
mask
= MSB_MASK
; /* set mask to first bit of pattern */
for (i
=0; i
< code
.length
; i
++) {
if ((code
.pattern
& mask
) == WHITE
)
/* SYNOPSIS: Puts an end of line marker at the end of a t4 line. */
/* An end of line (eoln) marker is 11 (or more) zero's */
* SYNOPSIS: set the runs change buffer fo the next input line
* DESCRIPTION: To optimise the input process, sequences of all 1's or 0's
* - the most likely combinations are looked for as special cases, if not
* found the runs are counted as bits.
for (i
= 1; i
<= PIC_LINESIZE
; i
++)
if (get_bit (lineptr
) != colour
) {
*(lineptr
->run_pos
++) = i
;
*lineptr
->run_pos
++ = STOP
;
*lineptr
->run_pos
= STOP
;
* SYNOPSIS: Initialises the output buffers, writes the ENODE id, and
* leaves room for the length (to be filled in later);
lineptr
->dbuf_top
+= 28; /* leave room for ASN.1 preamble */
lineptr
->dbuf
= lineptr
->dbuf_top
;
lineptr
->mask
= BIT_MASK
;
/* ROUTINE: flush_output;
* SYNOPSIS: Flush the output buffer, and set the ASN.1 preamble if
* allowed. The normal preamble consists of a SEQUENCE definition
* which wraps a SET and a SEQUENCE of BIT STRING. The SET
* includes G3-Fax nonbasic parameter indications (such as
* twoDimensional, fineResolution, etc.). Optionally, the
* old BIT STRING-ish preamble may be selected.
if ( lineptr
->mask
!= BIT_MASK
) /* writes last char if necessary */
*lineptr
->dbuf
++ = lineptr
->pos
;
optlen
= lineptr
->dbuf
- lineptr
->dbuf_top
;
/* set byte which indicates unused bits in last byte of image data */
*(--lineptr
->dbuf_top
) = 0x00;
len
= length
= lineptr
->dbuf
- lineptr
->dbuf_top
;
if (length
<= 127) { /* short form length */
*(--lineptr
->dbuf_top
) = length
;
/* see how many bytes needed for length */
/* go back and write this info */
for (i
= 0; i
< count
; i
++)
*(--lineptr
->dbuf_top
) = (length
>> (8 * i
));
*(--lineptr
->dbuf_top
) = 0x80 + count
; /* length marker*/
/* set BIT STRING identifier */
*(--lineptr
->dbuf_top
) = 0x03;
optlen
= lineptr
->dbuf
- lineptr
->dbuf_top
;
/* set length of BIT STRING sequence */
len
= length
= lineptr
->dbuf
- lineptr
->dbuf_top
;
if (length
<= 127) { /* short form length */
*(--lineptr
->dbuf_top
) = length
;
/* see how many bytes needed for length */
/* go back and write this info */
for (i
= 0; i
< count
; i
++)
*(--lineptr
->dbuf_top
) = (length
>> (8 * i
));
*(--lineptr
->dbuf_top
) = 0x80 + count
; /* length marker*/
/* set SEQUENCE identifier */
*(--lineptr
->dbuf_top
) = 0x30;
/* set SET which includes g3NonBasicParams */
*(--lineptr
->dbuf_top
) = uncompressed
? 0x02 : 0x00;
*(--lineptr
->dbuf_top
) = 0;
if (unlimitedLength
) *lineptr
->dbuf_top
|= 0x08;
if (b4Length
) *lineptr
->dbuf_top
|= 0x04;
if (a3Width
) *lineptr
->dbuf_top
|= 0x02;
if (b4Width
) *lineptr
->dbuf_top
|= 0x01;
*(--lineptr
->dbuf_top
) = 0;
if (twoDimensional
) *lineptr
->dbuf_top
|= 0x80;
if (fineResolution
) *lineptr
->dbuf_top
|= 0x40;
*(--lineptr
->dbuf_top
) = 0x00; /* first byte of BIT STRING */
*(--lineptr
->dbuf_top
) = 0x01; /* count of unused bits */
*(--lineptr
->dbuf_top
) = 5; /* BIT STRING length */
*(--lineptr
->dbuf_top
) = 0x81; /* [1] IMPLICIT G3NonBasicParams */
*(--lineptr
->dbuf_top
) = 7; /* length of SET */
*(--lineptr
->dbuf_top
) = 0x31; /* SET */
/* set length of entire sequence */
len
= length
= lineptr
->dbuf
- lineptr
->dbuf_top
;
if (length
<= 127) { /* short form length */
*(--lineptr
->dbuf_top
) = length
;
/* see how many bytes needed for length */
/* go back and write this info */
for (i
= 0; i
< count
; i
++)
*(--lineptr
->dbuf_top
) = (length
>> (8 * i
));
*(--lineptr
->dbuf_top
) = 0x80 + count
; /* length marker*/
/* set [3] IMPLICIT G3Fax identifier */
*(--lineptr
->dbuf_top
) = 0xa3;
optlen
= lineptr
->dbuf
- lineptr
->dbuf_top
;
/* SYNOPSIS: Initialises the input buffers
lineptr
->mask
= BIT_MASK
;
lineptr
->dbuf
= lineptr
->dbuf_top
;
lineptr
->pos
= *lineptr
->dbuf
++;