Allow writing of T.85 format TIFF files
This commit is contained in:
parent
8afd200023
commit
cc795b87c4
|
@ -1,4 +1,4 @@
|
|||
spandsp 0.0.5 - A DSP library for telephony
|
||||
spandsp 0.0.6 - A DSP library for telephony
|
||||
-------------------------------------------
|
||||
|
||||
SpanDSP is a library of DSP functions for telephony, in the 8000 sample per
|
||||
|
|
|
@ -446,13 +446,13 @@ static int test_tiff_directory_info(t4_tx_state_t *s)
|
|||
{
|
||||
uint16_t res_unit;
|
||||
uint32_t parm32;
|
||||
uint16_t bits_per_sample;
|
||||
uint16_t samples_per_pixel;
|
||||
int image_type;
|
||||
int best_x_entry;
|
||||
int best_y_entry;
|
||||
float x_resolution;
|
||||
float y_resolution;
|
||||
uint16_t bits_per_sample;
|
||||
uint16_t samples_per_pixel;
|
||||
int image_type;
|
||||
t4_tx_tiff_state_t *t;
|
||||
|
||||
t = &s->tiff;
|
||||
|
@ -574,12 +574,43 @@ static int row_read(void *user_data, uint8_t buf[], size_t len)
|
|||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int t85_row_write_handler(void *user_data, const uint8_t buf[], size_t len)
|
||||
{
|
||||
t85_packer_t *s;
|
||||
|
||||
s = (t85_packer_t *) user_data;
|
||||
memcpy(&s->buf[s->ptr], buf, len);
|
||||
s->ptr += len;
|
||||
s->row++;
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int t85_comment_handler(void *user_data, const uint8_t buf[], size_t len)
|
||||
{
|
||||
t4_tx_state_t *s;
|
||||
|
||||
s = (t4_tx_state_t *) user_data;
|
||||
if (buf)
|
||||
span_log(&s->logging, SPAN_LOG_WARNING, "T.85 comment (%d): %s\n", (int) len, buf);
|
||||
else
|
||||
span_log(&s->logging, SPAN_LOG_WARNING, "T.85 comment (%d): ---\n", (int) len);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int read_tiff_image(t4_tx_state_t *s)
|
||||
{
|
||||
int total_len;
|
||||
int len;
|
||||
int biggest;
|
||||
int i;
|
||||
int num_strips;
|
||||
int result;
|
||||
uint8_t *t;
|
||||
uint8_t *raw_data;
|
||||
t85_decode_state_t t85;
|
||||
t85_packer_t t85_pack;
|
||||
image_translate_state_t *translator;
|
||||
|
||||
if (s->tiff.image_type != T4_IMAGE_TYPE_BILEVEL)
|
||||
|
@ -625,6 +656,68 @@ static int read_tiff_image(t4_tx_state_t *s)
|
|||
}
|
||||
else
|
||||
{
|
||||
/* The original image is a bi-level one. We can't really rescale it, as that works out
|
||||
really poorly for a bi-level image. It has to be used in its original form. The only
|
||||
practical exception is to conver a superfine resolution image to a fine resolution one,
|
||||
or a fine image to a standard resolution one. We could pad slightly short rows or crop
|
||||
slightly long one, but lets not bother. */
|
||||
switch (s->tiff.compression)
|
||||
{
|
||||
case COMPRESSION_T85:
|
||||
/* Decode the whole image into a buffer */
|
||||
/* libtiff probably cannot decompress T.85, so we must handle it ourselves */
|
||||
/* Size up and allocate the buffer for the raw data */
|
||||
num_strips = TIFFNumberOfStrips(s->tiff.tiff_file);
|
||||
biggest = TIFFRawStripSize(s->tiff.tiff_file, 0);
|
||||
for (i = 1; i < num_strips; i++)
|
||||
{
|
||||
len = TIFFRawStripSize(s->tiff.tiff_file, i);
|
||||
if (len > biggest)
|
||||
biggest = len;
|
||||
}
|
||||
if ((raw_data = malloc(biggest)) == NULL)
|
||||
return -1;
|
||||
|
||||
s->tiff.image_size = s->image_length*((s->image_width + 7)/8);
|
||||
if (s->tiff.image_size >= s->tiff.image_buffer_size)
|
||||
{
|
||||
if ((t = realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL)
|
||||
return -1;
|
||||
s->tiff.image_buffer_size = s->tiff.image_size;
|
||||
s->tiff.image_buffer = t;
|
||||
}
|
||||
|
||||
t85_pack.buf = s->tiff.image_buffer;
|
||||
t85_pack.ptr = 0;
|
||||
t85_pack.row = 0;
|
||||
t85_decode_init(&t85, t85_row_write_handler, &t85_pack);
|
||||
t85_decode_set_comment_handler(&t85, 1000, t85_comment_handler, s);
|
||||
|
||||
total_len = 0;
|
||||
result = -1;
|
||||
for (i = 0; i < num_strips; i++, total_len += len)
|
||||
{
|
||||
len = TIFFRawStripSize(s->tiff.tiff_file, i);
|
||||
if ((len = TIFFReadRawStrip(s->tiff.tiff_file, i, raw_data, len)) < 0)
|
||||
{
|
||||
span_log(&s->logging, SPAN_LOG_WARNING, "%s: ReadRaw error.\n", s->tiff.file);
|
||||
return -1;
|
||||
}
|
||||
result = t85_decode_put(&t85, raw_data, len);
|
||||
if (result != T4_DECODE_MORE_DATA)
|
||||
break;
|
||||
}
|
||||
if (result == T4_DECODE_MORE_DATA)
|
||||
result = t85_decode_put(&t85, NULL, 0);
|
||||
|
||||
len = t85_decode_get_compressed_image_size(&t85);
|
||||
span_log(&s->logging, SPAN_LOG_WARNING, "Compressed image is %d bytes, %d rows\n", len/8, s->image_length);
|
||||
t85_decode_release(&t85);
|
||||
free(raw_data);
|
||||
break;
|
||||
default:
|
||||
/* Decode the whole image into a buffer */
|
||||
/* Let libtiff handle the decompression */
|
||||
s->tiff.image_size = s->image_length*TIFFScanlineSize(s->tiff.tiff_file);
|
||||
if (s->tiff.image_size >= s->tiff.image_buffer_size)
|
||||
{
|
||||
|
@ -634,7 +727,10 @@ static int read_tiff_image(t4_tx_state_t *s)
|
|||
s->tiff.image_buffer = t;
|
||||
}
|
||||
|
||||
for (i = 0, total_len = 0; total_len < s->tiff.image_size; i++, total_len += len)
|
||||
/* Allow for the image being stored in multiple strips, although it is rare to find
|
||||
a stripped image in a T.4 or T.6 encoded file. */
|
||||
num_strips = TIFFNumberOfStrips(s->tiff.tiff_file);
|
||||
for (i = 0, total_len = 0; i < num_strips; i++, total_len += len)
|
||||
{
|
||||
if ((len = TIFFReadEncodedStrip(s->tiff.tiff_file, i, &s->tiff.image_buffer[total_len], s->tiff.image_size - total_len)) < 0)
|
||||
{
|
||||
|
@ -642,14 +738,19 @@ static int read_tiff_image(t4_tx_state_t *s)
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
/* We might need to flip all the bits, so 1 = black and 0 = white. */
|
||||
if (s->tiff.photo_metric != PHOTOMETRIC_MINISWHITE)
|
||||
{
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "%s: Photometric needs swapping.\n", s->tiff.file);
|
||||
for (i = 0; i < s->tiff.image_size; i++)
|
||||
s->tiff.image_buffer[i] = ~s->tiff.image_buffer[i];
|
||||
s->tiff.photo_metric = PHOTOMETRIC_MINISWHITE;
|
||||
}
|
||||
/* We might need to bit reverse each of the bytes of the image. */
|
||||
if (s->tiff.fill_order != FILLORDER_LSB2MSB)
|
||||
bit_reverse(s->tiff.image_buffer, s->tiff.image_buffer, s->tiff.image_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
s->tiff.row = 0;
|
||||
return s->image_length;
|
||||
|
@ -684,15 +785,15 @@ static int set_row_read_handler(t4_tx_state_t *s, t4_row_read_handler_t handler,
|
|||
case T4_COMPRESSION_T4_2D:
|
||||
case T4_COMPRESSION_T6:
|
||||
return t4_t6_encode_set_row_read_handler(&s->encoder.t4_t6, handler, user_data);
|
||||
case T4_COMPRESSION_T85:
|
||||
case T4_COMPRESSION_T85_L0:
|
||||
return t85_encode_set_row_read_handler(&s->encoder.t85, handler, user_data);
|
||||
case T4_COMPRESSION_T42_T81:
|
||||
return t42_encode_set_row_read_handler(&s->encoder.t42, handler, user_data);
|
||||
#if defined(SPANDSP_SUPPORT_T43)
|
||||
case T4_COMPRESSION_T43:
|
||||
return t43_encode_set_row_read_handler(&s->encoder.t43, handler, user_data);
|
||||
#endif
|
||||
case T4_COMPRESSION_T85:
|
||||
case T4_COMPRESSION_T85_L0:
|
||||
return t85_encode_set_row_read_handler(&s->encoder.t85, handler, user_data);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -836,6 +937,7 @@ SPAN_DECLARE(int) t4_tx_set_row_read_handler(t4_tx_state_t *s, t4_row_read_handl
|
|||
|
||||
SPAN_DECLARE(int) t4_tx_set_tx_encoding(t4_tx_state_t *s, int encoding)
|
||||
{
|
||||
{
|
||||
switch (encoding)
|
||||
{
|
||||
case T4_COMPRESSION_T4_1D:
|
||||
|
@ -853,31 +955,9 @@ SPAN_DECLARE(int) t4_tx_set_tx_encoding(t4_tx_state_t *s, int encoding)
|
|||
break;
|
||||
}
|
||||
s->line_encoding = encoding;
|
||||
return t4_t6_encode_set_encoding(&s->encoder.t4_t6, encoding);
|
||||
case T4_COMPRESSION_T42_T81:
|
||||
switch (s->line_encoding)
|
||||
{
|
||||
case T4_COMPRESSION_T42_T81:
|
||||
break;
|
||||
default:
|
||||
t42_encode_init(&s->encoder.t42, s->image_width, s->image_length, s->row_handler, s->row_handler_user_data);
|
||||
break;
|
||||
}
|
||||
s->line_encoding = encoding;
|
||||
return 0;
|
||||
#if defined(SPANDSP_SUPPORT_T43)
|
||||
case T4_COMPRESSION_T43:
|
||||
switch (s->line_encoding)
|
||||
{
|
||||
case T4_COMPRESSION_T43:
|
||||
break;
|
||||
default:
|
||||
t43_encode_init(&s->encoder.t43, s->image_width, s->image_length, s->row_handler, s->row_handler_user_data);
|
||||
break;
|
||||
}
|
||||
s->line_encoding = encoding;
|
||||
return 0;
|
||||
#endif
|
||||
if (t4_t6_encode_set_encoding(&s->encoder.t4_t6, encoding))
|
||||
return -1;
|
||||
return s->line_encoding;
|
||||
case T4_COMPRESSION_T85:
|
||||
case T4_COMPRESSION_T85_L0:
|
||||
switch (s->line_encoding)
|
||||
|
@ -890,7 +970,32 @@ SPAN_DECLARE(int) t4_tx_set_tx_encoding(t4_tx_state_t *s, int encoding)
|
|||
break;
|
||||
}
|
||||
s->line_encoding = encoding;
|
||||
return 0;
|
||||
return s->line_encoding;
|
||||
case T4_COMPRESSION_T42_T81:
|
||||
switch (s->line_encoding)
|
||||
{
|
||||
case T4_COMPRESSION_T42_T81:
|
||||
break;
|
||||
default:
|
||||
t42_encode_init(&s->encoder.t42, s->image_width, s->image_length, s->row_handler, s->row_handler_user_data);
|
||||
break;
|
||||
}
|
||||
s->line_encoding = encoding;
|
||||
return s->line_encoding;
|
||||
#if defined(SPANDSP_SUPPORT_T43)
|
||||
case T4_COMPRESSION_T43:
|
||||
switch (s->line_encoding)
|
||||
{
|
||||
case T4_COMPRESSION_T43:
|
||||
break;
|
||||
default:
|
||||
t43_encode_init(&s->encoder.t43, s->image_width, s->image_length, s->row_handler, s->row_handler_user_data);
|
||||
break;
|
||||
}
|
||||
s->line_encoding = encoding;
|
||||
return s->line_encoding;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -919,6 +1024,10 @@ SPAN_DECLARE(void) t4_tx_set_image_width(t4_tx_state_t *s, int image_width)
|
|||
case T4_COMPRESSION_T6:
|
||||
t4_t6_encode_set_image_width(&s->encoder.t4_t6, image_width);
|
||||
break;
|
||||
case T4_COMPRESSION_T85:
|
||||
case T4_COMPRESSION_T85_L0:
|
||||
t85_encode_set_image_width(&s->encoder.t85, image_width);
|
||||
break;
|
||||
case T4_COMPRESSION_T42_T81:
|
||||
t42_encode_set_image_width(&s->encoder.t42, image_width);
|
||||
break;
|
||||
|
@ -927,10 +1036,6 @@ SPAN_DECLARE(void) t4_tx_set_image_width(t4_tx_state_t *s, int image_width)
|
|||
t43_encode_set_image_width(&s->encoder.t43, image_width);
|
||||
break;
|
||||
#endif
|
||||
case T4_COMPRESSION_T85:
|
||||
case T4_COMPRESSION_T85_L0:
|
||||
t85_encode_set_image_width(&s->encoder.t85, image_width);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
@ -940,6 +1045,10 @@ static void t4_tx_set_image_length(t4_tx_state_t *s, int image_length)
|
|||
s->image_length = image_length;
|
||||
switch (s->line_encoding)
|
||||
{
|
||||
case T4_COMPRESSION_T85:
|
||||
case T4_COMPRESSION_T85_L0:
|
||||
t85_encode_set_image_length(&s->encoder.t85, image_length);
|
||||
break;
|
||||
case T4_COMPRESSION_T42_T81:
|
||||
t42_encode_set_image_length(&s->encoder.t42, image_length);
|
||||
break;
|
||||
|
@ -948,10 +1057,6 @@ static void t4_tx_set_image_length(t4_tx_state_t *s, int image_length)
|
|||
t43_encode_set_image_length(&s->encoder.t43, image_length);
|
||||
break;
|
||||
#endif
|
||||
case T4_COMPRESSION_T85:
|
||||
case T4_COMPRESSION_T85_L0:
|
||||
t85_encode_set_image_length(&s->encoder.t85, image_length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
@ -1011,6 +1116,18 @@ SPAN_DECLARE(int) t4_tx_get_x_resolution(t4_tx_state_t *s)
|
|||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) t4_tx_get_resolution(t4_tx_state_t *s)
|
||||
{
|
||||
return s->metadata.resolution_code;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) t4_tx_get_image_type(t4_tx_state_t *s)
|
||||
{
|
||||
return s->metadata.image_type;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) t4_tx_get_pages_in_file(t4_tx_state_t *s)
|
||||
{
|
||||
int max;
|
||||
|
@ -1056,6 +1173,13 @@ SPAN_DECLARE(void) t4_tx_get_transfer_statistics(t4_tx_state_t *s, t4_stats_t *t
|
|||
t->length = t4_t6_encode_get_image_length(&s->encoder.t4_t6)/s->row_squashing_ratio;
|
||||
t->line_image_size = t4_t6_encode_get_compressed_image_size(&s->encoder.t4_t6)/8;
|
||||
break;
|
||||
case T4_COMPRESSION_T85:
|
||||
case T4_COMPRESSION_T85_L0:
|
||||
t->type = T4_IMAGE_TYPE_BILEVEL;
|
||||
t->width = t85_encode_get_image_width(&s->encoder.t85);
|
||||
t->length = t85_encode_get_image_length(&s->encoder.t85)/s->row_squashing_ratio;
|
||||
t->line_image_size = t85_encode_get_compressed_image_size(&s->encoder.t85)/8;
|
||||
break;
|
||||
case T4_COMPRESSION_T42_T81:
|
||||
t->type = 0;
|
||||
t->width = t42_encode_get_image_width(&s->encoder.t42);
|
||||
|
@ -1070,13 +1194,6 @@ SPAN_DECLARE(void) t4_tx_get_transfer_statistics(t4_tx_state_t *s, t4_stats_t *t
|
|||
t->line_image_size = t43_encode_get_compressed_image_size(&s->encoder.t43)/8;
|
||||
break;
|
||||
#endif
|
||||
case T4_COMPRESSION_T85:
|
||||
case T4_COMPRESSION_T85_L0:
|
||||
t->type = T4_IMAGE_TYPE_BILEVEL;
|
||||
t->width = t85_encode_get_image_width(&s->encoder.t85);
|
||||
t->length = t85_encode_get_image_length(&s->encoder.t85)/s->row_squashing_ratio;
|
||||
t->line_image_size = t85_encode_get_compressed_image_size(&s->encoder.t85)/8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
@ -1089,15 +1206,15 @@ SPAN_DECLARE(int) t4_tx_image_complete(t4_tx_state_t *s)
|
|||
case T4_COMPRESSION_T4_2D:
|
||||
case T4_COMPRESSION_T6:
|
||||
return t4_t6_encode_image_complete(&s->encoder.t4_t6);
|
||||
case T4_COMPRESSION_T85:
|
||||
case T4_COMPRESSION_T85_L0:
|
||||
return t85_encode_image_complete(&s->encoder.t85);
|
||||
case T4_COMPRESSION_T42_T81:
|
||||
return t42_encode_image_complete(&s->encoder.t42);
|
||||
#if defined(SPANDSP_SUPPORT_T43)
|
||||
case T4_COMPRESSION_T43:
|
||||
return t43_encode_image_complete(&s->encoder.t43);
|
||||
#endif
|
||||
case T4_COMPRESSION_T85:
|
||||
case T4_COMPRESSION_T85_L0:
|
||||
return t85_encode_image_complete(&s->encoder.t85);
|
||||
}
|
||||
return SIG_STATUS_END_OF_DATA;
|
||||
}
|
||||
|
@ -1118,15 +1235,15 @@ SPAN_DECLARE(int) t4_tx_get(t4_tx_state_t *s, uint8_t buf[], size_t max_len)
|
|||
case T4_COMPRESSION_T4_2D:
|
||||
case T4_COMPRESSION_T6:
|
||||
return t4_t6_encode_get(&s->encoder.t4_t6, buf, max_len);
|
||||
case T4_COMPRESSION_T85:
|
||||
case T4_COMPRESSION_T85_L0:
|
||||
return t85_encode_get(&s->encoder.t85, buf, max_len);
|
||||
case T4_COMPRESSION_T42_T81:
|
||||
return t42_encode_get(&s->encoder.t42, buf, max_len);
|
||||
#if defined(SPANDSP_SUPPORT_T43)
|
||||
case T4_COMPRESSION_T43:
|
||||
return t43_encode_get(&s->encoder.t43, buf, max_len);
|
||||
#endif
|
||||
case T4_COMPRESSION_T85:
|
||||
case T4_COMPRESSION_T85_L0:
|
||||
return t85_encode_get(&s->encoder.t85, buf, max_len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1157,6 +1274,10 @@ SPAN_DECLARE(int) t4_tx_start_page(t4_tx_state_t *s)
|
|||
case T4_COMPRESSION_T6:
|
||||
t4_t6_encode_restart(&s->encoder.t4_t6, s->image_width);
|
||||
break;
|
||||
case T4_COMPRESSION_T85:
|
||||
case T4_COMPRESSION_T85_L0:
|
||||
t85_encode_restart(&s->encoder.t85, s->image_width, s->image_length);
|
||||
break;
|
||||
case T4_COMPRESSION_T42_T81:
|
||||
t42_encode_restart(&s->encoder.t42, s->image_width, s->image_length);
|
||||
break;
|
||||
|
@ -1165,10 +1286,6 @@ SPAN_DECLARE(int) t4_tx_start_page(t4_tx_state_t *s)
|
|||
t43_encode_restart(&s->encoder.t43, s->image_width, s->image_length);
|
||||
break;
|
||||
#endif
|
||||
case T4_COMPRESSION_T85:
|
||||
case T4_COMPRESSION_T85_L0:
|
||||
t85_encode_restart(&s->encoder.t85, s->image_width, s->image_length);
|
||||
break;
|
||||
}
|
||||
/* If there is a page header, create that first */
|
||||
if (s->tiff.image_type == T4_IMAGE_TYPE_BILEVEL && s->header_info && s->header_info[0] && make_header(s) == 0)
|
||||
|
@ -1279,15 +1396,15 @@ SPAN_DECLARE(int) t4_tx_release(t4_tx_state_t *s)
|
|||
case T4_COMPRESSION_T4_2D:
|
||||
case T4_COMPRESSION_T6:
|
||||
return t4_t6_encode_release(&s->encoder.t4_t6);
|
||||
case T4_COMPRESSION_T85:
|
||||
case T4_COMPRESSION_T85_L0:
|
||||
return t85_encode_release(&s->encoder.t85);
|
||||
case T4_COMPRESSION_T42_T81:
|
||||
return t42_encode_release(&s->encoder.t42);
|
||||
#if defined(SPANDSP_SUPPORT_T43)
|
||||
case T4_COMPRESSION_T43:
|
||||
return t43_encode_release(&s->encoder.t43);
|
||||
#endif
|
||||
case T4_COMPRESSION_T85:
|
||||
case T4_COMPRESSION_T85_L0:
|
||||
return t85_encode_release(&s->encoder.t85);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue