Add image squashing feature to the FAX engine so a superfine image or fine

image can be sent to a machine which has those resolutions inhibited.
This commit is contained in:
Steve Underwood 2012-09-14 00:24:19 +08:00
parent 83d7f4282c
commit 831e5dd4d9
6 changed files with 105 additions and 59 deletions

View File

@ -534,7 +534,7 @@ fi
if test "$ac_cv_header_tif_dir_h" = "yes" ; then
AC_DEFINE([SPANDSP_SUPPORT_TIFF_FX], [1], [Support TIFF/FX in TIFF file handling])
SPANDSP_SUPPORT_TIFF_FX="#define SPANDSP_SUPPORT_TIFF_FX"
SPANDSP_SUPPORT_TIFF_FX="#define SPANDSP_SUPPORT_TIFF_FX 1"
else
SPANDSP_SUPPORT_TIFF_FX="#undef SPANDSP_SUPPORT_TIFF_FX"
fi

View File

@ -38,7 +38,7 @@ typedef struct
/*! \brief The compression type used in the TIFF file */
uint16_t compression;
/*! \brief Image type - bilevel, gray, colour */
/*! \brief Image type - bi-level, gray, colour, etc. */
int image_type;
/*! \brief The TIFF photometric setting for the current page. */
uint16_t photo_metric;
@ -96,6 +96,11 @@ struct t4_tx_state_s
int line_encoding_gray;
int line_encoding_colour;
/*! \brief When superfine and fine resolution images need to be squahed vertically
to a lower resolution, this value sets the number of source rows which
must be squashed to form each row on the wire. */
int row_squashing_ratio;
/*! \brief The width of the current page, in pixels. */
uint32_t image_width;
/*! \brief The length of the current page, in pixels. */

View File

@ -342,6 +342,12 @@ SPAN_DECLARE(void) t4_tx_set_header_overlays_image(t4_tx_state_t *s, int header_
\return 0 for success, otherwise -1. */
SPAN_DECLARE(int) t4_tx_set_row_read_handler(t4_tx_state_t *s, t4_row_read_handler_t handler, void *user_data);
/*! \brief Set the row squashing ratio, for adjusting row-to-row (y) resolution of bi-level
images for a T.4 transmit context.
\param s The T.4 transmit context.
\param row_squashing_ratio Vertical squashing ratio. */
SPAN_DECLARE(void) t4_tx_set_row_squashing_ratio(t4_tx_state_t *s, int row_squashing_ratio);
/*! \brief Get the row-to-row (y) resolution of the current page.
\param s The T.4 context.
\return The resolution, in pixels per metre. */

View File

@ -1308,6 +1308,7 @@ static int build_dcs(t30_state_t *s)
{
int i;
int bad;
int row_squashing_ratio;
/* Make a DCS frame based on local issues and the latest received DIS/DTC frame. Negotiate
the result based on what both parties can do. */
@ -1369,6 +1370,7 @@ static int build_dcs(t30_state_t *s)
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_RECEIVE_FAX_DOCUMENT);
/* Set the Y resolution bits */
bad = T30_ERR_OK;
row_squashing_ratio = 1;
switch (s->y_resolution)
{
case T4_Y_RESOLUTION_1200:
@ -1425,27 +1427,6 @@ static int build_dcs(t30_state_t *s)
break;
}
break;
case T4_Y_RESOLUTION_SUPERFINE:
if (!(s->supported_resolutions & T30_SUPPORT_SUPERFINE_RESOLUTION))
{
bad = T30_ERR_NORESSUPPORT;
}
else
{
switch (s->x_resolution)
{
case T4_X_RESOLUTION_R8:
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_400);
break;
case T4_X_RESOLUTION_R16:
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_400);
break;
default:
bad = T30_ERR_NORESSUPPORT;
break;
}
}
break;
case T4_Y_RESOLUTION_300:
switch (s->x_resolution)
{
@ -1460,12 +1441,27 @@ static int build_dcs(t30_state_t *s)
break;
}
break;
case T4_Y_RESOLUTION_FINE:
if (!(s->supported_resolutions & T30_SUPPORT_FINE_RESOLUTION))
case T4_Y_RESOLUTION_SUPERFINE:
if ((s->supported_resolutions & T30_SUPPORT_SUPERFINE_RESOLUTION))
{
bad = T30_ERR_NORESSUPPORT;
switch (s->x_resolution)
{
case T4_X_RESOLUTION_R8:
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_400);
break;
case T4_X_RESOLUTION_R16:
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_400);
break;
default:
bad = T30_ERR_NORESSUPPORT;
break;
}
break;
}
else
row_squashing_ratio <<= 1;
/* Fall through */
case T4_Y_RESOLUTION_FINE:
if ((s->supported_resolutions & T30_SUPPORT_FINE_RESOLUTION))
{
switch (s->x_resolution)
{
@ -1476,8 +1472,10 @@ static int build_dcs(t30_state_t *s)
bad = T30_ERR_NORESSUPPORT;
break;
}
break;
}
break;
row_squashing_ratio <<= 1;
/* Fall through */
default:
case T4_Y_RESOLUTION_STANDARD:
switch (s->x_resolution)
@ -1491,6 +1489,7 @@ static int build_dcs(t30_state_t *s)
}
break;
}
t4_tx_set_row_squashing_ratio(&s->t4.tx, row_squashing_ratio);
if (bad != T30_ERR_OK)
{
t30_set_status(s, bad);
@ -1915,23 +1914,21 @@ static int set_min_scan_time_code(t30_state_t *s)
switch (s->y_resolution)
{
case T4_Y_RESOLUTION_SUPERFINE:
if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_400_CAPABLE))
if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_400_CAPABLE))
{
t30_set_status(s, T30_ERR_NORESSUPPORT);
span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support super-fine resolution.\n");
return -1;
s->min_scan_time_code = translate_min_scan_time[(test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_MIN_SCAN_TIME_HALVES)) ? 2 : 1][min_bits_field];
break;
}
s->min_scan_time_code = translate_min_scan_time[(test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_MIN_SCAN_TIME_HALVES)) ? 2 : 1][min_bits_field];
break;
span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support super-fine resolution. Squashing image.\n");
/* Fall through */
case T4_Y_RESOLUTION_FINE:
if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE))
if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE))
{
t30_set_status(s, T30_ERR_NORESSUPPORT);
span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support fine resolution.\n");
return -1;
s->min_scan_time_code = translate_min_scan_time[1][min_bits_field];
break;
}
s->min_scan_time_code = translate_min_scan_time[1][min_bits_field];
break;
span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support fine resolution. Squashing image.\n");
/* Fall through */
default:
case T4_Y_RESOLUTION_STANDARD:
s->min_scan_time_code = translate_min_scan_time[0][min_bits_field];
@ -2122,7 +2119,7 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len)
}
}
}
span_log(&s->logging, SPAN_LOG_FLOW, "Selected compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding);
span_log(&s->logging, SPAN_LOG_FLOW, "Choose compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding);
switch (s->far_dis_dtc_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3))
{
case (DISBIT6 | DISBIT4 | DISBIT3):
@ -2410,7 +2407,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len)
{
s->line_encoding = T4_COMPRESSION_ITU_T4_1D;
}
span_log(&s->logging, SPAN_LOG_FLOW, "Selected compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding);
span_log(&s->logging, SPAN_LOG_FLOW, "Far end selected compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding);
if (!test_ctrl_bit(dcs_frame, T30_DCS_BIT_RECEIVE_FAX_DOCUMENT))
span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Remote is not requesting receive in DCS\n");
@ -3389,12 +3386,18 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg,
send_simple_frame(s, T30_RTP);
break;
case T30_COPY_QUALITY_BAD:
#if 0
/* Some people want to keep even the bad pages */
if (s->keep_bad_pages)
rx_end_page(s);
#endif
if (s->phase_d_handler)
s->phase_d_handler(s, s->phase_d_user_data, fcf);
set_state(s, T30_STATE_III_Q_RTN);
send_simple_frame(s, T30_RTN);
break;
}
break;
case T30_DCN:
t30_set_status(s, T30_ERR_RX_DCNFAX);
@ -6306,9 +6309,13 @@ SPAN_DECLARE(t30_state_t *) t30_init(t30_state_t *s,
/* Default to the basic modems. */
s->supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17;
s->supported_compressions = T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION;
s->supported_resolutions = T30_SUPPORT_STANDARD_RESOLUTION | T30_SUPPORT_FINE_RESOLUTION | T30_SUPPORT_SUPERFINE_RESOLUTION
s->supported_resolutions = T30_SUPPORT_STANDARD_RESOLUTION
| T30_SUPPORT_FINE_RESOLUTION
| T30_SUPPORT_SUPERFINE_RESOLUTION
| T30_SUPPORT_R8_RESOLUTION;
s->supported_image_sizes = T30_SUPPORT_US_LETTER_LENGTH | T30_SUPPORT_US_LEGAL_LENGTH | T30_SUPPORT_UNLIMITED_LENGTH
s->supported_image_sizes = T30_SUPPORT_US_LETTER_LENGTH
| T30_SUPPORT_US_LEGAL_LENGTH
| T30_SUPPORT_UNLIMITED_LENGTH
| T30_SUPPORT_215MM_WIDTH;
/* Set the output encoding to something safe. Most things get 1D and 2D
encoding right. Quite a lot get other things wrong. */

View File

@ -484,12 +484,23 @@ static int open_tiff_input_file(t4_tx_state_t *s, const char *file)
static int tiff_row_read_handler(void *user_data, uint8_t buf[], size_t len)
{
t4_tx_state_t *s;
int i;
int j;
s = (t4_tx_state_t *) user_data;
if (s->tiff.row >= s->image_length)
return 0;
memcpy(buf, &s->tiff.image_buffer[s->tiff.row*len], len);
s->tiff.row++;
/* If this is a bi-level image which has more vertical resolution than the
far end will accept, we need to squash it down to size. */
for (i = 1; i < s->row_squashing_ratio && s->tiff.row < s->image_length; i++)
{
for (j = 0; j < s->image_width/8; j++)
buf[j] |= s->tiff.image_buffer[s->tiff.row*len + j];
s->tiff.row++;
}
return len;
}
/*- End of function --------------------------------------------------------*/
@ -497,7 +508,7 @@ static int tiff_row_read_handler(void *user_data, uint8_t buf[], size_t len)
static int row_read(void *user_data, uint8_t buf[], size_t len)
{
t4_tx_state_t *s;
s = (t4_tx_state_t *) user_data;
if (s->tiff.raw_row >= s->tiff.image_length)
@ -650,7 +661,7 @@ static int make_header(t4_tx_state_t *s)
if ((s->header_text = malloc(132 + 1)) == NULL)
return -1;
}
/* This is very English oriented, but then most FAX machines are, too. Some
/* This is very English oriented, but then most FAX machines are. Some
measure of i18n in the time and date, and even the header_info string, is
entirely possible, although the font area would need some serious work to
properly deal with East Asian script. There is no spec for what the header
@ -711,6 +722,7 @@ static int header_row_read_handler(void *user_data, uint8_t buf[], size_t len)
repeats = 1;
break;
}
repeats /= s->row_squashing_ratio;
if (s->header_overlays_image)
{
/* Read and dump a row of the real image, allowing for the possibility
@ -721,23 +733,37 @@ static int header_row_read_handler(void *user_data, uint8_t buf[], size_t len)
return len;
}
}
row = s->header_row/repeats;
pos = 0;
for (t = s->header_text; *t && pos <= len - 2; t++)
switch (s->tiff.image_type)
{
pattern = header_font[(uint8_t) *t][row];
buf[pos++] = (uint8_t) (pattern >> 8);
buf[pos++] = (uint8_t) (pattern & 0xFF);
case T4_IMAGE_TYPE_BILEVEL:
row = s->header_row/repeats;
pos = 0;
for (t = s->header_text; *t && pos <= len - 2; t++)
{
pattern = header_font[(uint8_t) *t][row];
buf[pos++] = (uint8_t) (pattern >> 8);
buf[pos++] = (uint8_t) (pattern & 0xFF);
}
while (pos < len)
buf[pos++] = 0;
s->header_row++;
if (s->header_row >= 16*repeats)
{
/* End of header. Change to normal image row data. */
set_row_read_handler(s, s->row_handler, s->row_handler_user_data);
}
break;
}
while (pos < len)
buf[pos++] = 0;
s->header_row++;
if (s->header_row >= 16*repeats)
set_row_read_handler(s, s->row_handler, s->row_handler_user_data);
return len;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) t4_tx_set_row_squashing_ratio(t4_tx_state_t *s, int row_squashing_ratio)
{
s->row_squashing_ratio = row_squashing_ratio;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t4_tx_next_page_has_different_format(t4_tx_state_t *s)
{
span_log(&s->logging, SPAN_LOG_FLOW, "Checking for the existence of page %d\n", s->current_page + 1);
@ -1143,6 +1169,8 @@ SPAN_DECLARE(t4_tx_state_t *) t4_tx_init(t4_tx_state_t *s, const char *file, int
s->row_handler = tiff_row_read_handler;
s->row_handler_user_data = (void *) s;
s->row_squashing_ratio = 1;
if (file)
{
if (open_tiff_input_file(s, file) < 0)

View File

@ -575,7 +575,7 @@ int main(int argc, char *argv[])
if (compression < 0 || (block_size == 0 && compression_step >= 3))
break;
}
t4_tx_set_tx_encoding(&send_state, compression, T4_COMPRESSION_NONE);
t4_tx_set_tx_encoding(&send_state, compression);
t4_rx_set_rx_encoding(&receive_state, compression);
rows_read = 0;
@ -716,7 +716,7 @@ int main(int argc, char *argv[])
compression = compression_sequence[compression_step++];
}
}
t4_tx_set_tx_encoding(&send_state, compression, T4_COMPRESSION_NONE);
t4_tx_set_tx_encoding(&send_state, compression);
t4_rx_set_rx_encoding(&receive_state, compression);
if (t4_tx_start_page(&send_state))