twain3.0/huagao/TiffG4Compression.cpp

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 */
}