Addition of T.85 compression to the TIFF file.
This commit is contained in:
parent
d3dbde63b1
commit
cdac39a6e4
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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... */
|
||||
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))
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue