Addition of T.85 compression to the TIFF file.

This commit is contained in:
Steve Underwood 2013-04-05 00:29:32 +08:00
parent d3dbde63b1
commit cdac39a6e4
5 changed files with 194 additions and 22 deletions

View File

@ -374,10 +374,20 @@ enum
T30_SUPPORT_COMPRESSION_SYCC_T81 = 0x200,
/*! T.88 monochrome JBIG2 compression */
T30_SUPPORT_COMPRESSION_T88 = 0x400,
/*! Gray-scale support by multi-level codecs */
T30_SUPPORT_COMPRESSION_GRAYSCALE = 0x1000000,
/*! Colour support by multi-level codecs */
T30_SUPPORT_COMPRESSION_COLOUR = 0x2000000,
/*! 12 bit mode for gray scale and colour */
T30_SUPPORT_COMPRESSION_12BIT = 0x4000000,
/*! Convert a colour image to a gray-scale one */
T30_SUPPORT_COMPRESSION_COLOUR_TO_GRAY = 0x8000000,
/*! Dither a gray scale image down a simple bilevel image, with rescaling to fit a FAX page */
T30_SUPPORT_GRAY_TO_BILEVEL = 0x10000000,
/*! Dither a colour image down a simple bilevel image, with rescaling to fit a FAX page */
T30_SUPPORT_COLOUR_TO_BILEVEL = 0x20000000
T30_SUPPORT_COLOUR_TO_BILEVEL = 0x20000000,
/*! Rescale an image (except a bi-level image) to fit a permitted FAX width when necessary */
T30_SUPPORT_COMPRESSION_RESCALING = 0x40000000
};
enum

View File

@ -1202,6 +1202,7 @@ int t30_build_dis_or_dtc(t30_state_t *s)
{
/* ECM allowed */
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_ECM_CAPABLE);
/* Only offer the option of fancy compression schemes, if we are
also offering the ECM option needed to support them. */
if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_T6))
@ -1215,6 +1216,9 @@ int t30_build_dis_or_dtc(t30_state_t *s)
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE);
}
if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_COLOUR))
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_FULL_COLOUR_CAPABLE);
if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_T42_T81))
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE);
if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_T43))
@ -1232,6 +1236,15 @@ int t30_build_dis_or_dtc(t30_state_t *s)
}
//if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_T89))
// set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T89_CAPABLE);
if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_12BIT))
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_12BIT_CAPABLE);
//if ((s->supported_compressions & 30_SUPPORT_COMPRESSION_NO_SUBSAMPLING))
// set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NO_SUBSAMPLING);
/* No custom illuminant */
/* No custom gamut range */
}
if ((s->supported_t30_features & T30_SUPPORT_FIELD_NOT_VALID))
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_FNV_CAPABLE);
@ -1262,12 +1275,6 @@ int t30_build_dis_or_dtc(t30_state_t *s)
/* No mode 26 (T.505) */
/* No digital network capability */
/* No duplex operation */
/* No JPEG */
/* No full colour */
/* No 12bits/pel */
/* No sub-sampling (1:1:1) */
/* No custom illuminant */
/* No custom gamut range */
if ((s->supported_image_sizes & T30_SUPPORT_US_LETTER_LENGTH))
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LETTER_CAPABLE);
if ((s->supported_image_sizes & T30_SUPPORT_US_LEGAL_LENGTH))
@ -2329,7 +2336,6 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len)
return -1;
}
}
queue_phase(s, T30_PHASE_B_TX);
/* Try to send something */
if (s->tx_file[0])
@ -2439,9 +2445,26 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len)
s->y_resolution = -1;
//s->current_page_resolution = 0;
x = -1;
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE))
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T81_MODE) || test_ctrl_bit(dcs_frame, T30_DCS_BIT_T43_MODE))
{
/* Gray scale or colour image */
/* Note 35 of Table 2/T.30 */
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE))
{
/* We are going to work in full colour mode */
}
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_12BIT_COMPONENT))
{
/* We are going to work in 12 bit mode */
}
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_NO_SUBSAMPLING))
{
//???? = T30_SUPPORT_COMPRESSION_T42_T81_SUBSAMPLING;
}
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_COLOUR_GRAY_1200_1200))
{
if ((s->supported_colour_resolutions & T30_SUPPORT_RESOLUTION_1200_1200))
@ -2664,7 +2687,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len)
/* Check which compression the far end has decided to use. */
#if defined(SPANDSP_SUPPORT_T42)
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE))
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T81_MODE))
{
s->line_encoding = T4_COMPRESSION_T42_T81;
}
@ -3905,6 +3928,7 @@ static void process_state_r(t30_state_t *s, const uint8_t *msg, int len)
process_rx_dcs(s, msg, len);
break;
case T30_DCN:
/* Received a DCN while waiting for a DIS or DCN */
t30_set_status(s, T30_ERR_RX_DCNWHY);
disconnect(s);
break;

View File

@ -697,12 +697,12 @@ SPAN_DECLARE(int) t30_set_supported_compressions(t30_state_t *s, int supported_c
supported_compressions &= T30_SUPPORT_COMPRESSION_T4_1D
| T30_SUPPORT_COMPRESSION_T4_2D
| T30_SUPPORT_COMPRESSION_T6
| T30_SUPPORT_COMPRESSION_T85
| T30_SUPPORT_COMPRESSION_T85_L0
//| T30_SUPPORT_COMPRESSION_T81
#if defined(SPANDSP_SUPPORT_T43)
| T30_SUPPORT_COMPRESSION_T43
#endif
| T30_SUPPORT_COMPRESSION_T85
| T30_SUPPORT_COMPRESSION_T85_L0
| 0;
s->supported_compressions = supported_compressions;
t30_build_dis_or_dtc(s);
@ -712,6 +712,23 @@ SPAN_DECLARE(int) t30_set_supported_compressions(t30_state_t *s, int supported_c
SPAN_DECLARE(int) t30_set_supported_bilevel_resolutions(t30_state_t *s, int supported_resolutions)
{
supported_resolutions &= T4_RESOLUTION_R8_STANDARD
| T4_RESOLUTION_R8_FINE
| T4_RESOLUTION_R8_SUPERFINE
| T4_RESOLUTION_R16_SUPERFINE
| T4_RESOLUTION_200_100
| T4_RESOLUTION_200_200
| T4_RESOLUTION_200_400
| T4_RESOLUTION_300_300
| T4_RESOLUTION_300_600
| T4_RESOLUTION_400_400
| T4_RESOLUTION_400_800
| T4_RESOLUTION_600_600
| T4_RESOLUTION_600_1200
| T4_RESOLUTION_1200_1200;
/* Make sure anything needed for colour is enabled as a bi-level image, as that is a
rule from T.30. 100x100 is an exception, as it doesn't exist as a bi-level resolution. */
supported_resolutions |= (s->supported_colour_resolutions & ~T4_RESOLUTION_100_100);
s->supported_bilevel_resolutions = supported_resolutions;
t30_build_dis_or_dtc(s);
return 0;
@ -720,7 +737,16 @@ SPAN_DECLARE(int) t30_set_supported_bilevel_resolutions(t30_state_t *s, int supp
SPAN_DECLARE(int) t30_set_supported_colour_resolutions(t30_state_t *s, int supported_resolutions)
{
supported_resolutions &= T4_RESOLUTION_100_100
| T4_RESOLUTION_200_200
| T4_RESOLUTION_300_300
| T4_RESOLUTION_400_400
| T4_RESOLUTION_600_600
| T4_RESOLUTION_1200_1200;
s->supported_colour_resolutions = supported_resolutions;
/* Make sure anything needed for colour is enabled as a bi-level image, as that is a
rule from T.30. 100x100 is an exception, as it doesn't exist as a bi-level resolution. */
s->supported_bilevel_resolutions |= (s->supported_colour_resolutions & ~T4_RESOLUTION_100_100);
t30_build_dis_or_dtc(s);
return 0;
}

View File

@ -81,6 +81,12 @@
/*! The number of centimetres in one inch */
#define CM_PER_INCH 2.54f
typedef struct
{
uint8_t *buf;
int ptr;
} packer_t;
#if defined(SPANDSP_SUPPORT_TIFF_FX)
extern TIFFFieldArray tiff_fx_field_array;
#endif
@ -336,9 +342,30 @@ static int open_tiff_output_file(t4_rx_state_t *s, const char *file)
}
/*- End of function --------------------------------------------------------*/
static int row_read_handler(void *user_data, uint8_t row[], size_t len)
{
packer_t *s;
s = (packer_t *) user_data;
memcpy(row, &s->buf[s->ptr], len);
s->ptr += len;
return len;
}
/*- End of function --------------------------------------------------------*/
static int write_tiff_image(t4_rx_state_t *s)
{
t4_rx_tiff_state_t *t;
uint8_t *buf;
uint8_t *buf2;
int buf_len;
int len;
int len2;
t85_encode_state_t t85;
#if defined(SPANDSP_SUPPORT_T43)
t43_encode_state_t t43;
#endif
packer_t packer;
#if defined(SPANDSP_SUPPORT_TIFF_FX)
uint64_t offset;
#endif
@ -353,8 +380,79 @@ static int write_tiff_image(t4_rx_state_t *s)
if (!TIFFCheckpointDirectory(t->tiff_file))
span_log(&s->logging, SPAN_LOG_WARNING, "%s: Failed to checkpoint directory for page %d.\n", t->file, s->current_page);
/* ...and write out the image... */
if (TIFFWriteEncodedStrip(t->tiff_file, 0, t->image_buffer, t->image_size) < 0)
span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", t->file);
switch (t->output_encoding)
{
case T4_COMPRESSION_T85:
case T4_COMPRESSION_T85_L0:
span_log(&s->logging, SPAN_LOG_WARNING, "%s: TODO need T.85 compression.\n", t->file);
buf_len = 0;
buf = NULL;
packer.buf = t->image_buffer;
packer.ptr = 0;
t85_encode_init(&t85, s->image_width, s->image_length, row_read_handler, &packer);
//if (t->output_encoding == T4_COMPRESSION_T85_L0)
// t85_encode_set_options(&t85, 256, -1, -1);
len2 = 0;
do
{
if (buf_len < len2 + 50000)
{
buf_len += 50000;
if ((buf2 = realloc(buf, buf_len)) == NULL)
{
if (buf)
free(buf);
return -1;
}
buf = buf2;
}
len = t85_encode_get(&t85, &buf[len2], 50000);
len2 += len;
}
while (len > 0);
if (TIFFWriteRawStrip(t->tiff_file, 0, buf, len2) < 0)
span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", t->file);
t85_encode_release(&t85);
free(buf);
break;
#if defined(SPANDSP_SUPPORT_T43)
case T4_COMPRESSION_T43:
span_log(&s->logging, SPAN_LOG_WARNING, "%s: TODO need T.43 compression.\n", t->file);
buf_len = 0;
buf = NULL;
packer.buf = t->image_buffer;
packer.ptr = 0;
t43_encode_init(&t43, s->image_width, s->image_length, row_read_handler, &packer);
len2 = 0;
do
{
if (buf_len < len2 + 50000)
{
buf_len += 50000;
if ((buf2 = realloc(buf, buf_len)) == NULL)
{
if (buf)
free(buf);
return -1;
}
buf = buf2;
}
len = t43_encode_get(&t43, &buf[len2], 50000);
len2 += len;
}
while (len > 0);
if (TIFFWriteRawStrip(t->tiff_file, 0, buf, len2) < 0)
span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", t->file);
t43_encode_release(&t43);
free(buf);
break;
#endif
default:
/* Let libtiff do the compression */
if (TIFFWriteEncodedStrip(t->tiff_file, 0, t->image_buffer, t->image_size) < 0)
span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", t->file);
break;
}
/* ...then finalise the directory entry, and libtiff is happy. */
if (!TIFFWriteDirectory(t->tiff_file))
span_log(&s->logging, SPAN_LOG_WARNING, "%s: Failed to write directory for page %d.\n", t->file, s->current_page);
@ -365,7 +463,9 @@ static int write_tiff_image(t4_rx_state_t *s)
{
TIFFSetField(t->tiff_file, TIFFTAG_FAXPROFILE, PROFILETYPE_G3_FAX);
TIFFSetField(t->tiff_file, TIFFTAG_PROFILETYPE, FAXPROFILE_F);
TIFFSetField(t->tiff_file, TIFFTAG_CODINGMETHODS, CODINGMETHODS_T4_1D | CODINGMETHODS_T4_2D | CODINGMETHODS_T6);
TIFFSetField(t->tiff_file, TIFFTAG_VERSIONYEAR, "1998");
TIFFSetField(t->tiff_file, TIFFTAG_MODENUMBER, 3);
offset = 0;
if (!TIFFWriteCustomDirectory(t->tiff_file, &offset))

View File

@ -86,10 +86,19 @@
/*! The number of centimetres in one inch */
#define CM_PER_INCH 2.54f
typedef struct
{
uint8_t *buf;
int ptr;
int row;
int bit_mask;
} t85_packer_t;
static void t4_tx_set_image_length(t4_tx_state_t *s, int image_length);
#if defined(SPANDSP_SUPPORT_TIFF_FX)
/* TIFF-FX related extensions to the tag set supported by libtiff */
static const TIFFFieldInfo tiff_fx_tiff_field_info[] =
{
{TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, FIELD_CUSTOM, FALSE, FALSE, (char *) "Indexed"},
@ -106,6 +115,7 @@ static const TIFFFieldInfo tiff_fx_tiff_field_info[] =
{TIFFTAG_IMAGELAYER, 2, 2, TIFF_LONG, FIELD_CUSTOM, FALSE, FALSE, (char *) "ImageLayer"},
};
#if 1
static TIFFField tiff_fx_tiff_fields[] =
{
{ TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "Indexed" },
@ -123,6 +133,7 @@ static TIFFField tiff_fx_tiff_fields[] =
};
TIFFFieldArray tiff_fx_field_array = { tfiatOther, 0, 12, tiff_fx_tiff_fields };
#endif
static TIFFExtendProc _ParentExtender = NULL;
@ -177,12 +188,13 @@ static int read_colour_map(t4_tx_state_t *s, int bits_per_sample)
return -1;
/* TODO: This only allows for 8 bit deep maps */
if ((s->colour_map = realloc(s->colour_map, 3*256)) == NULL)
return -1;
span_log(&s->logging, SPAN_LOG_FLOW, "Got a colour map\n");
s->colour_map_entries = 1 << bits_per_sample;
if ((s->colour_map = realloc(s->colour_map, 3*s->colour_map_entries)) == NULL)
return -1;
#if 0
/* Sweep the colormap in the proper order */
for (i = 0; i < (1 << bits_per_sample); i++)
for (i = 0; i < s->colour_map_entries; i++)
{
s->colour_map[3*i + 0] = (map_L[i] >> 8) & 0xFF;
s->colour_map[3*i + 1] = (map_a[i] >> 8) & 0xFF;
@ -191,15 +203,15 @@ static int read_colour_map(t4_tx_state_t *s, int bits_per_sample)
}
#else
/* Sweep the colormap in the order that seems to work for l04x_02x.tif */
for (i = 0; i < (1 << bits_per_sample); i++)
for (i = 0; i < s->colour_map_entries; i++)
{
s->colour_map[0*256 + i] = (map_L[i] >> 8) & 0xFF;
s->colour_map[1*256 + i] = (map_a[i] >> 8) & 0xFF;
s->colour_map[2*256 + i] = (map_b[i] >> 8) & 0xFF;
s->colour_map[0*s->colour_map_entries + i] = (map_L[i] >> 8) & 0xFF;
s->colour_map[1*s->colour_map_entries + i] = (map_a[i] >> 8) & 0xFF;
s->colour_map[2*s->colour_map_entries + i] = (map_b[i] >> 8) & 0xFF;
}
#endif
lab_to_srgb(&s->lab_params, s->colour_map, s->colour_map, 256);
for (i = 0; i < (1 << bits_per_sample); i++)
for (i = 0; i < s->colour_map_entries; i++)
span_log(&s->logging, SPAN_LOG_FLOW, "Map %3d - %5d %5d %5d\n", i, s->colour_map[3*i], s->colour_map[3*i + 1], s->colour_map[3*i + 2]);
return 0;
}