mirror of http://192.168.1.51:8099/lmh188/twain3.0
517 lines
13 KiB
C++
517 lines
13 KiB
C++
#include "TiffG4Compression.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string>
|
|
|
|
#ifdef TIME
|
|
struct timeval t1, t2;
|
|
struct timezone tz;
|
|
#endif
|
|
|
|
TiffG4Compression::TiffG4Compression()
|
|
{
|
|
}
|
|
|
|
|
|
TiffG4Compression::~TiffG4Compression()
|
|
{
|
|
}
|
|
|
|
int TiffG4Compression::G4Compress(unsigned char * indata, int inbytes, int width, int height, unsigned char * outdata, int * outbytes)
|
|
{
|
|
struct uncompressed_descriptor uncompressed;
|
|
struct compressed_descriptor compressed;
|
|
|
|
uncompressed.pixels_per_line = width;
|
|
uncompressed.number_of_lines = height;
|
|
uncompressed.data = indata;
|
|
comp_alloc_flag = NOALLOC;
|
|
comp_write_init_flag = 1;
|
|
read_uncompressed_file_into_memory(&uncompressed);
|
|
compressed.data = outdata;
|
|
control_compression(&uncompressed, &compressed);
|
|
*outbytes = compressed.length_in_bytes;
|
|
return *outbytes;
|
|
}
|
|
|
|
void TiffG4Compression::control_compression(uncompressed_descriptor * uncompressed, compressed_descriptor * compressed)
|
|
{
|
|
struct parameters sole_parameters;
|
|
struct parameters *params = &sole_parameters;
|
|
|
|
#ifdef TIME
|
|
SHORT i;
|
|
tz.tz_minuteswest = 0;
|
|
tz.tz_dsttime = 0;
|
|
gettimeofday(&t1, &tz);
|
|
#endif
|
|
|
|
prepare_to_compress(uncompressed, compressed, params);
|
|
compress_image(uncompressed, compressed, params);
|
|
/* memory deallocation added by Michael D. Garris 2/26/90 */
|
|
free(params->reference_line);
|
|
free(params->coding_line);
|
|
#ifdef TIME
|
|
gettimeofday(&t2, &tz);
|
|
printf("\ntime difference: %ld:%ld\n", t2.tv_sec - t1.tv_sec,
|
|
t2.tv_usec - t1.tv_usec);
|
|
for (i = 0; i < 5; i++) printf("%c", '\07'); */
|
|
#endif
|
|
}
|
|
|
|
void TiffG4Compression::read_uncompressed_file_into_memory(uncompressed_descriptor * uncompressed)
|
|
{
|
|
int file_size;
|
|
|
|
if (comp_alloc_flag)
|
|
{
|
|
file_size = uncompressed->pixels_per_line * uncompressed->number_of_lines
|
|
/ Pixels_per_byte;
|
|
if ((uncompressed->data = (unsigned char *)calloc(file_size, sizeof(char))) == NULL)
|
|
{
|
|
printf("\nCannot allocate enough memory for uncomp file.\n");
|
|
}
|
|
}
|
|
else if (uncompressed->data == NULL)
|
|
{
|
|
printf("\nNo memory allocated for input data!\n");
|
|
}
|
|
}
|
|
|
|
void TiffG4Compression::prepare_to_compress(uncompressed_descriptor * uncompressed, compressed_descriptor * compressed, parameters * params)
|
|
{
|
|
params->max_pixel = uncompressed->pixels_per_line;
|
|
compressed->pixels_per_line = uncompressed->pixels_per_line;
|
|
compressed->number_of_lines = uncompressed->number_of_lines;
|
|
|
|
set_up_first_line_c(params);
|
|
prepare_to_write_bits_c(compressed);
|
|
}
|
|
|
|
void TiffG4Compression::compress_image(uncompressed_descriptor * uncompressed, compressed_descriptor * compressed, parameters * params)
|
|
{
|
|
SHORT line;
|
|
for (line = 0; line < uncompressed->number_of_lines; line++)
|
|
{
|
|
make_array_of_changing_elements(params, uncompressed, line);
|
|
set_up_first_and_last_changing_elements_c(params);
|
|
compress_line(params);
|
|
prepare_to_compress_next_line(params);
|
|
} /* end for each line loop */
|
|
write_bits_c(const_cast<char*>("000000000001000000000001"));
|
|
compressed->length_in_bytes = flush_buffer();
|
|
}
|
|
|
|
void TiffG4Compression::make_array_of_changing_elements(parameters * params, uncompressed_descriptor * uncompressed, SHORT line_number)
|
|
{
|
|
SHORT bytes_per_line;
|
|
int line_offset;
|
|
SHORT byte_offset;
|
|
|
|
bytes_per_line = params->max_pixel / Pixels_per_byte;
|
|
line_offset = bytes_per_line * line_number;
|
|
for (byte_offset = 0; byte_offset < bytes_per_line; byte_offset++)
|
|
{
|
|
process_char(*(uncompressed->data + line_offset + byte_offset), params);
|
|
}
|
|
}
|
|
|
|
void TiffG4Compression::set_up_first_and_last_changing_elements_c(parameters * params)
|
|
{
|
|
*(params->coding_line) = Invalid;
|
|
*(params->coding_line + ++params->index) = params->max_pixel;
|
|
*(params->coding_line + ++params->index) = params->max_pixel;
|
|
*(params->coding_line + ++params->index) = params->max_pixel;
|
|
}
|
|
|
|
void TiffG4Compression::prepare_to_compress_next_line(parameters * params)
|
|
{
|
|
SHORT *temp;
|
|
|
|
/* swap the reference and unchanged coding lines */
|
|
|
|
temp = params->reference_line;
|
|
params->reference_line = params->coding_line;
|
|
params->coding_line = temp;
|
|
|
|
params->pixel = 0;
|
|
params->index = 0;
|
|
params->previous_color = White;
|
|
}
|
|
|
|
void TiffG4Compression::set_up_first_line_c(parameters * params)
|
|
{
|
|
params->reference_line =
|
|
(SHORT *)malloc((params->max_pixel + Extra_positions) * sizeof(SHORT));
|
|
params->coding_line =
|
|
(SHORT *)malloc((params->max_pixel + Extra_positions) * sizeof(SHORT));
|
|
|
|
*(params->reference_line + 0) = Invalid;
|
|
*(params->reference_line + 1) = params->max_pixel;
|
|
*(params->reference_line + 2) = params->max_pixel;
|
|
*(params->reference_line + 3) = params->max_pixel;
|
|
|
|
/* initialize first changing element on coding line (A0 = -1) */
|
|
*(params->coding_line) = Invalid;
|
|
|
|
params->pixel = 0;
|
|
params->index = 0;
|
|
params->previous_color = White;
|
|
}
|
|
|
|
void TiffG4Compression::compress_line(parameters * params)
|
|
{
|
|
#if Debug
|
|
static SHORT line = 0;
|
|
printf("\nLINE %d. ", line);
|
|
line++;
|
|
#endif
|
|
|
|
A_0 = Invalid; /* set A0 equal to imaginary first array element */
|
|
A0_color = White;
|
|
A_1 = 1;
|
|
initialize_b1(params);
|
|
b2 = b1 + 1;
|
|
|
|
#if Debug
|
|
printf("\nA0:%d A1:%d b1:%d b2:%d ",
|
|
A0, *(params->coding_line + A1),
|
|
*(params->reference_line + b1), *(params->reference_line + b2));
|
|
#endif
|
|
|
|
do {
|
|
if (*(params->reference_line + b2) < *(params->coding_line + A_1))
|
|
{
|
|
pass_mode_c(params);
|
|
continue;
|
|
}
|
|
else
|
|
if (abs(*(params->coding_line + A_1) - *(params->reference_line + b1)) <= 3)
|
|
vertical_mode_c(params);
|
|
else
|
|
horizontal_mode_c(params);
|
|
#if Debug
|
|
printf("\nA0:%d A1:%d b1:%d b2:%d ", A0, *(params->coding_line + A1),
|
|
*(params->reference_line + b1), *(params->reference_line + b2));
|
|
#endif
|
|
|
|
} while (A_0 < params->max_pixel);
|
|
}
|
|
|
|
void TiffG4Compression::initialize_b1(parameters * params)
|
|
{
|
|
SHORT last_bit_of_b1;
|
|
|
|
b1 = 1;
|
|
last_bit_of_b1 = b1 & Last_bit_mask;
|
|
|
|
while (((*(params->reference_line + b1) <= A_0) || (A0_color == last_bit_of_b1))
|
|
&& (*(params->reference_line + b1) < params->max_pixel))
|
|
{
|
|
b1++;
|
|
last_bit_of_b1 = b1 & Last_bit_mask;
|
|
} /* end while loop */
|
|
|
|
#if Debug
|
|
printf("\nb1:%d :%d, A0:%d", b1, *(params->reference_line + b1), A0);
|
|
#endif
|
|
}
|
|
|
|
void TiffG4Compression::pass_mode_c(parameters * params)
|
|
{
|
|
write_bits_c(const_cast<char*>("0001"));
|
|
|
|
#if Debug
|
|
printf(" P ");
|
|
#endif
|
|
|
|
/*
|
|
* Reset the value A0 points to to a'0 (the value that b2 points to).
|
|
*/
|
|
|
|
A_0 = *(params->reference_line + b2);
|
|
|
|
/*
|
|
* Since A0 is now greater than the pixel b1 points to, both b1 and b2
|
|
* must be advanced twice to maintain the color difference between A0 and
|
|
* b1, and the positional requirement that b1 point to a pixel greater than
|
|
* the one A0 points to.
|
|
*/
|
|
|
|
b1 += 2;
|
|
b2 += 2;
|
|
|
|
/*
|
|
* Note that the b's can be advanced by two positions without fear of
|
|
* moving them beyond the last changing element because pass_mode cannot
|
|
* occur if b2 is already pointing to max_pixel.
|
|
*/
|
|
}
|
|
|
|
void TiffG4Compression::vertical_mode_c(parameters * params)
|
|
{
|
|
SHORT difference;
|
|
|
|
difference = *(params->coding_line + A_1) - *(params->reference_line + b1);
|
|
A_0 = *(params->coding_line + A_1);
|
|
A0_color = !A0_color;
|
|
A_1++;
|
|
|
|
#if Debug
|
|
printf(" V%d ", difference);
|
|
#endif
|
|
switch (difference) {
|
|
case 0:
|
|
write_bits_c(const_cast<char*>("1"));
|
|
if (*(params->reference_line + b1) != params->max_pixel)
|
|
{
|
|
b1++;
|
|
b2++;
|
|
} /* end if b1 is not on the last changing element */
|
|
break;
|
|
|
|
case 1:
|
|
write_bits_c(const_cast<char*>("011"));
|
|
b1++;
|
|
b2++;
|
|
if ((*(params->reference_line + b1) <= A_0) &&
|
|
(*(params->reference_line + b1) != params->max_pixel))
|
|
{
|
|
b1 += 2;
|
|
b2 += 2;
|
|
}
|
|
break;
|
|
|
|
case -1:
|
|
write_bits_c(const_cast<char*>("010"));
|
|
if (*(params->reference_line + b1) != params->max_pixel)
|
|
{
|
|
b1++;
|
|
b2++;
|
|
} /* end if b1 is not on the last changing element */
|
|
break;
|
|
|
|
case 2:
|
|
write_bits_c(const_cast<char*>("000011"));
|
|
b1++;
|
|
b2++;
|
|
if ((*(params->reference_line + b1) <= A_0) &&
|
|
(*(params->reference_line + b1) != params->max_pixel))
|
|
{
|
|
b1 += 2;
|
|
b2 += 2;
|
|
}
|
|
break;
|
|
|
|
case -2:
|
|
write_bits_c(const_cast<char*>("000010"));
|
|
if (*(params->reference_line + b1 - 1) > A_0)
|
|
{
|
|
b1--;
|
|
b2--;
|
|
}
|
|
else if (*(params->reference_line + b1) != params->max_pixel)
|
|
{
|
|
b1++;
|
|
b2++;
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
write_bits_c(const_cast<char*>("0000011"));
|
|
b1++;
|
|
b2++;
|
|
while ((*(params->reference_line + b1) <= A_0) &&
|
|
(*(params->reference_line + b1) != params->max_pixel))
|
|
{
|
|
b1 += 2;
|
|
b2 += 2;
|
|
}
|
|
break;
|
|
|
|
case -3:
|
|
write_bits_c(const_cast<char*>("0000010"));
|
|
if (*(params->reference_line + b1 - 1) > A_0)
|
|
{
|
|
b1--;
|
|
b2--;
|
|
}
|
|
else if (*(params->reference_line + b1) != params->max_pixel)
|
|
{
|
|
b1++;
|
|
b2++;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
printf("ERROR in vertical_mode_c() ");
|
|
|
|
} /* end case of difference */
|
|
}
|
|
|
|
void TiffG4Compression::horizontal_mode_c(parameters * params)
|
|
{
|
|
SHORT run_length;
|
|
|
|
#if Debug
|
|
printf(" a2:%d H ", *(params->coding_line + a2));
|
|
#endif
|
|
|
|
a2 = A_1 + 1;
|
|
write_bits_c(const_cast<char*>("001"));
|
|
|
|
if (A_0 == Invalid) /* on imaginary first pixel */
|
|
run_length = *(params->coding_line + A_1);
|
|
else
|
|
run_length = *(params->coding_line + A_1) - A_0;
|
|
write_run_length(run_length, A0_color);
|
|
/* the last bit contains the color of the changing element */
|
|
|
|
run_length = *(params->coding_line + a2) - *(params->coding_line + A_1);
|
|
write_run_length(run_length, !A0_color);
|
|
|
|
/*
|
|
* Must use !A0_color instead of A1 because in cases in which A1 occurs
|
|
* on max_pixel, its color is bogus.
|
|
*/
|
|
|
|
/* NOTE: is the above statement true? if A1 were on max_pixel, you should
|
|
not get horizontal mode. */
|
|
|
|
|
|
A_0 = *(params->coding_line + a2);
|
|
A_1 = a2 + 1;
|
|
|
|
while ((*(params->reference_line + b1) <= *(params->coding_line + a2)) &&
|
|
(*(params->reference_line + b1) < params->max_pixel))
|
|
{
|
|
b1 += 2; /* must move ahead by 2 to maintain color difference with */
|
|
b2 += 2; /* A0, whose color does not change in this mode. */
|
|
}
|
|
|
|
}
|
|
|
|
void TiffG4Compression::prepare_to_write_bits_c(compressed_descriptor * compressed)
|
|
{
|
|
if (comp_alloc_flag) {
|
|
compressed->data = (unsigned char*)calloc((compressed->pixels_per_line *
|
|
compressed->number_of_lines / Pixels_per_byte), sizeof(unsigned char));
|
|
}
|
|
/*
|
|
* This allocation is usually very wasteful, but because there is no
|
|
* way of knowing how much space is needed, I decided to be generous.
|
|
*/
|
|
|
|
if (compressed->data == NULL) {
|
|
printf("\nMemory allocation error for compressed output data.\n");
|
|
//crash_c();
|
|
}
|
|
output_area = (char*)compressed->data;
|
|
}
|
|
|
|
void TiffG4Compression::write_bits_c(char * string_ptr)
|
|
{
|
|
/* global switch added by Michael D. Garris 2/26/90 */
|
|
if (comp_write_init_flag)
|
|
{
|
|
bit_place_mark = 0;
|
|
byte_place_mark = 0;
|
|
comp_write_init_flag = 0;
|
|
}
|
|
while (*string_ptr != '\0')
|
|
{
|
|
if (*string_ptr == '1')
|
|
*(output_area + byte_place_mark) |= write_one[bit_place_mark];
|
|
else
|
|
*(output_area + byte_place_mark) &= write_zero[bit_place_mark];
|
|
if (bit_place_mark == Last_bit_in_a_byte)
|
|
{
|
|
bit_place_mark = 0;
|
|
byte_place_mark++;
|
|
} /* end if byte is full */
|
|
else
|
|
bit_place_mark++;
|
|
string_ptr++;
|
|
} /* end while */
|
|
}
|
|
|
|
unsigned int TiffG4Compression::flush_buffer()
|
|
{
|
|
SHORT i;
|
|
|
|
if (bit_place_mark != 0) {
|
|
for (i = bit_place_mark; i < Pixels_per_byte; i++)
|
|
*(output_area + byte_place_mark) &= write_zero[i];
|
|
/*
|
|
* pad the rest of the last byte with '0' bits.
|
|
*/
|
|
++byte_place_mark;
|
|
}
|
|
return byte_place_mark;
|
|
}
|
|
|
|
void TiffG4Compression::write_run_length(SHORT length, SHORT color)
|
|
{
|
|
SHORT multiples_of_largest_code, i,
|
|
make_up_code_index, remainder;
|
|
|
|
multiples_of_largest_code = length / Largest_code;
|
|
length %= Largest_code;
|
|
for (i = 0; i < multiples_of_largest_code; i++)
|
|
write_bits_c(const_cast<char*>(largest_colorless_code));
|
|
|
|
remainder = length % Size_of_make_up_code_increments;
|
|
|
|
/* remainder in the range 0 - 63 */
|
|
|
|
make_up_code_index = length / Size_of_make_up_code_increments;
|
|
|
|
/*
|
|
* make_up_code_index in the range 0 - 39, and represents a run length
|
|
* of 64 times its value (i.e. 0 - 2496). To translate this value into
|
|
* an index into the arrays that store the bit sequence that represents
|
|
* the appropriate run length, 1 must be subtracted from make_up_code_
|
|
* index. If this results in the value -1, no make up code should be
|
|
* written.
|
|
*/
|
|
|
|
make_up_code_index--;
|
|
|
|
if (make_up_code_index != Invalid) {
|
|
if (color == White)
|
|
write_bits_c(const_cast<char*>(white_make_up_code[make_up_code_index]));
|
|
else
|
|
write_bits_c(const_cast<char*>(black_make_up_code[make_up_code_index]));
|
|
}
|
|
|
|
if (color == White)
|
|
write_bits_c(const_cast<char*>(white_terminating_code[remainder]));
|
|
else
|
|
write_bits_c(const_cast<char*>(black_terminating_code[remainder]));
|
|
}
|
|
|
|
void TiffG4Compression::process_char(unsigned char data_byte, parameters * params)
|
|
{
|
|
static char color = 0;
|
|
SHORT i = 0;
|
|
|
|
color = -(data_byte & Last_bit_mask);
|
|
data_byte ^= params->previous_color;
|
|
|
|
/* if the previous color is black - which is contrary to our assumptions -
|
|
* the bits in the byte must all be changed so that the result, when used
|
|
* as an index into the array 'bytes,' yields the correct result. In the
|
|
* above operation, if the previous color is black (11111111b), all bits
|
|
* are changed; if the previous color is white (00000000b), no bits are
|
|
* changed. */
|
|
|
|
while (table[data_byte].pixel[i] != Invalid)
|
|
*(params->coding_line + ++params->index) =
|
|
params->pixel + table[data_byte].pixel[i++];
|
|
|
|
params->pixel += Pixels_per_byte;
|
|
params->previous_color = color;
|
|
|
|
/* 'color' is a temporary holding place for the value of previous color */
|
|
}
|