{
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;
}
/*- 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)
}
else
{
- s->tiff.image_size = s->image_length*TIFFScanlineSize(s->tiff.tiff_file);
- if (s->tiff.image_size >= s->tiff.image_buffer_size)
+ /* 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)
{
- if ((t = realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL)
+ 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_buffer_size = s->tiff.image_size;
- s->tiff.image_buffer = t;
- }
- for (i = 0, total_len = 0; total_len < s->tiff.image_size; 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)
+ s->tiff.image_size = s->image_length*((s->image_width + 7)/8);
+ if (s->tiff.image_size >= s->tiff.image_buffer_size)
{
- span_log(&s->logging, SPAN_LOG_WARNING, "%s: Read error.\n", s->tiff.file);
- return -1;
+ 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)
+ {
+ 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;
+ }
+
+ /* 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)
+ {
+ span_log(&s->logging, SPAN_LOG_WARNING, "%s: Read error.\n", s->tiff.file);
+ 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;
}
- 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];
- }
- if (s->tiff.fill_order != FILLORDER_LSB2MSB)
- bit_reverse(s->tiff.image_buffer, s->tiff.image_buffer, s->tiff.image_size);
}
s->tiff.row = 0;
return s->image_length;
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;
}
SPAN_DECLARE(int) t4_tx_set_tx_encoding(t4_tx_state_t *s, int encoding)
{
- switch (encoding)
{
- case T4_COMPRESSION_T4_1D:
- case T4_COMPRESSION_T4_2D:
- case T4_COMPRESSION_T6:
- switch (s->line_encoding)
+ switch (encoding)
{
case T4_COMPRESSION_T4_1D:
case T4_COMPRESSION_T4_2D:
case T4_COMPRESSION_T6:
- break;
- default:
- t4_t6_encode_init(&s->encoder.t4_t6, encoding, s->image_width, s->row_handler, s->row_handler_user_data);
- t4_t6_encode_set_max_2d_rows_per_1d_row(&s->encoder.t4_t6, -s->metadata.y_resolution);
- 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)
- {
+ switch (s->line_encoding)
+ {
+ case T4_COMPRESSION_T4_1D:
+ case T4_COMPRESSION_T4_2D:
+ case T4_COMPRESSION_T6:
+ break;
+ default:
+ t4_t6_encode_init(&s->encoder.t4_t6, encoding, s->image_width, s->row_handler, s->row_handler_user_data);
+ t4_t6_encode_set_max_2d_rows_per_1d_row(&s->encoder.t4_t6, -s->metadata.y_resolution);
+ break;
+ }
+ s->line_encoding = encoding;
+ 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)
+ {
+ case T4_COMPRESSION_T85:
+ case T4_COMPRESSION_T85_L0:
+ break;
+ default:
+ t85_encode_init(&s->encoder.t85, s->image_width, s->image_length, s->row_handler, s->row_handler_user_data);
+ break;
+ }
+ s->line_encoding = encoding;
+ return 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;
+ 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 0;
+ 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
- case T4_COMPRESSION_T85:
- case T4_COMPRESSION_T85_L0:
- switch (s->line_encoding)
- {
- case T4_COMPRESSION_T85:
- case T4_COMPRESSION_T85_L0:
- break;
- default:
- t85_encode_init(&s->encoder.t85, s->image_width, s->image_length, s->row_handler, s->row_handler_user_data);
- break;
}
- s->line_encoding = encoding;
- return 0;
}
return -1;
}
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;
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 --------------------------------------------------------*/
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;
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 --------------------------------------------------------*/
}
/*- 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;
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);
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 --------------------------------------------------------*/
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;
}
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;
}
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;
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)
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;
}