提交 831e5dd4 authored 作者: Steve Underwood's avatar Steve Underwood

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.
上级 83d7f428
...@@ -534,7 +534,7 @@ fi ...@@ -534,7 +534,7 @@ fi
if test "$ac_cv_header_tif_dir_h" = "yes" ; then if test "$ac_cv_header_tif_dir_h" = "yes" ; then
AC_DEFINE([SPANDSP_SUPPORT_TIFF_FX], [1], [Support TIFF/FX in TIFF file handling]) 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 else
SPANDSP_SUPPORT_TIFF_FX="#undef SPANDSP_SUPPORT_TIFF_FX" SPANDSP_SUPPORT_TIFF_FX="#undef SPANDSP_SUPPORT_TIFF_FX"
fi fi
......
...@@ -38,7 +38,7 @@ typedef struct ...@@ -38,7 +38,7 @@ typedef struct
/*! \brief The compression type used in the TIFF file */ /*! \brief The compression type used in the TIFF file */
uint16_t compression; uint16_t compression;
/*! \brief Image type - bilevel, gray, colour */ /*! \brief Image type - bi-level, gray, colour, etc. */
int image_type; int image_type;
/*! \brief The TIFF photometric setting for the current page. */ /*! \brief The TIFF photometric setting for the current page. */
uint16_t photo_metric; uint16_t photo_metric;
...@@ -96,6 +96,11 @@ struct t4_tx_state_s ...@@ -96,6 +96,11 @@ struct t4_tx_state_s
int line_encoding_gray; int line_encoding_gray;
int line_encoding_colour; 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. */ /*! \brief The width of the current page, in pixels. */
uint32_t image_width; uint32_t image_width;
/*! \brief The length of the current page, in pixels. */ /*! \brief The length of the current page, in pixels. */
......
...@@ -342,6 +342,12 @@ SPAN_DECLARE(void) t4_tx_set_header_overlays_image(t4_tx_state_t *s, int header_ ...@@ -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. */ \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); 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. /*! \brief Get the row-to-row (y) resolution of the current page.
\param s The T.4 context. \param s The T.4 context.
\return The resolution, in pixels per metre. */ \return The resolution, in pixels per metre. */
......
...@@ -1308,6 +1308,7 @@ static int build_dcs(t30_state_t *s) ...@@ -1308,6 +1308,7 @@ static int build_dcs(t30_state_t *s)
{ {
int i; int i;
int bad; int bad;
int row_squashing_ratio;
/* Make a DCS frame based on local issues and the latest received DIS/DTC frame. Negotiate /* 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. */ the result based on what both parties can do. */
...@@ -1369,6 +1370,7 @@ static int build_dcs(t30_state_t *s) ...@@ -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_ctrl_bit(s->dcs_frame, T30_DCS_BIT_RECEIVE_FAX_DOCUMENT);
/* Set the Y resolution bits */ /* Set the Y resolution bits */
bad = T30_ERR_OK; bad = T30_ERR_OK;
row_squashing_ratio = 1;
switch (s->y_resolution) switch (s->y_resolution)
{ {
case T4_Y_RESOLUTION_1200: case T4_Y_RESOLUTION_1200:
...@@ -1425,12 +1427,22 @@ static int build_dcs(t30_state_t *s) ...@@ -1425,12 +1427,22 @@ static int build_dcs(t30_state_t *s)
break; break;
} }
break; break;
case T4_Y_RESOLUTION_SUPERFINE: case T4_Y_RESOLUTION_300:
if (!(s->supported_resolutions & T30_SUPPORT_SUPERFINE_RESOLUTION)) switch (s->x_resolution)
{ {
case T4_X_RESOLUTION_300:
if (!(s->supported_resolutions & T30_SUPPORT_300_300_RESOLUTION))
bad = T30_ERR_NORESSUPPORT;
else
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_300_300);
break;
default:
bad = T30_ERR_NORESSUPPORT; bad = T30_ERR_NORESSUPPORT;
break;
} }
else break;
case T4_Y_RESOLUTION_SUPERFINE:
if ((s->supported_resolutions & T30_SUPPORT_SUPERFINE_RESOLUTION))
{ {
switch (s->x_resolution) switch (s->x_resolution)
{ {
...@@ -1444,28 +1456,12 @@ static int build_dcs(t30_state_t *s) ...@@ -1444,28 +1456,12 @@ static int build_dcs(t30_state_t *s)
bad = T30_ERR_NORESSUPPORT; bad = T30_ERR_NORESSUPPORT;
break; break;
} }
}
break;
case T4_Y_RESOLUTION_300:
switch (s->x_resolution)
{
case T4_X_RESOLUTION_300:
if (!(s->supported_resolutions & T30_SUPPORT_300_300_RESOLUTION))
bad = T30_ERR_NORESSUPPORT;
else
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_300_300);
break;
default:
bad = T30_ERR_NORESSUPPORT;
break; break;
} }
break; row_squashing_ratio <<= 1;
/* Fall through */
case T4_Y_RESOLUTION_FINE: case T4_Y_RESOLUTION_FINE:
if (!(s->supported_resolutions & T30_SUPPORT_FINE_RESOLUTION)) if ((s->supported_resolutions & T30_SUPPORT_FINE_RESOLUTION))
{
bad = T30_ERR_NORESSUPPORT;
}
else
{ {
switch (s->x_resolution) switch (s->x_resolution)
{ {
...@@ -1476,8 +1472,10 @@ static int build_dcs(t30_state_t *s) ...@@ -1476,8 +1472,10 @@ static int build_dcs(t30_state_t *s)
bad = T30_ERR_NORESSUPPORT; bad = T30_ERR_NORESSUPPORT;
break; break;
} }
break;
} }
break; row_squashing_ratio <<= 1;
/* Fall through */
default: default:
case T4_Y_RESOLUTION_STANDARD: case T4_Y_RESOLUTION_STANDARD:
switch (s->x_resolution) switch (s->x_resolution)
...@@ -1491,6 +1489,7 @@ static int build_dcs(t30_state_t *s) ...@@ -1491,6 +1489,7 @@ static int build_dcs(t30_state_t *s)
} }
break; break;
} }
t4_tx_set_row_squashing_ratio(&s->t4.tx, row_squashing_ratio);
if (bad != T30_ERR_OK) if (bad != T30_ERR_OK)
{ {
t30_set_status(s, bad); t30_set_status(s, bad);
...@@ -1915,23 +1914,21 @@ static int set_min_scan_time_code(t30_state_t *s) ...@@ -1915,23 +1914,21 @@ static int set_min_scan_time_code(t30_state_t *s)
switch (s->y_resolution) switch (s->y_resolution)
{ {
case T4_Y_RESOLUTION_SUPERFINE: 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); 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];
span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support super-fine resolution.\n"); break;
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]; span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support super-fine resolution. Squashing image.\n");
break; /* Fall through */
case T4_Y_RESOLUTION_FINE: 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); s->min_scan_time_code = translate_min_scan_time[1][min_bits_field];
span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support fine resolution.\n"); break;
return -1;
} }
s->min_scan_time_code = translate_min_scan_time[1][min_bits_field]; span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support fine resolution. Squashing image.\n");
break; /* Fall through */
default: default:
case T4_Y_RESOLUTION_STANDARD: case T4_Y_RESOLUTION_STANDARD:
s->min_scan_time_code = translate_min_scan_time[0][min_bits_field]; 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) ...@@ -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)) switch (s->far_dis_dtc_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3))
{ {
case (DISBIT6 | 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) ...@@ -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; 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)) 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"); 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, ...@@ -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); send_simple_frame(s, T30_RTP);
break; break;
case T30_COPY_QUALITY_BAD: 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) if (s->phase_d_handler)
s->phase_d_handler(s, s->phase_d_user_data, fcf); s->phase_d_handler(s, s->phase_d_user_data, fcf);
set_state(s, T30_STATE_III_Q_RTN); set_state(s, T30_STATE_III_Q_RTN);
send_simple_frame(s, T30_RTN); send_simple_frame(s, T30_RTN);
break; break;
} }
break; break;
case T30_DCN: case T30_DCN:
t30_set_status(s, T30_ERR_RX_DCNFAX); t30_set_status(s, T30_ERR_RX_DCNFAX);
...@@ -6306,9 +6309,13 @@ SPAN_DECLARE(t30_state_t *) t30_init(t30_state_t *s, ...@@ -6306,9 +6309,13 @@ SPAN_DECLARE(t30_state_t *) t30_init(t30_state_t *s,
/* Default to the basic modems. */ /* Default to the basic modems. */
s->supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17; 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_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; | 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; | T30_SUPPORT_215MM_WIDTH;
/* Set the output encoding to something safe. Most things get 1D and 2D /* Set the output encoding to something safe. Most things get 1D and 2D
encoding right. Quite a lot get other things wrong. */ encoding right. Quite a lot get other things wrong. */
......
...@@ -484,12 +484,23 @@ static int open_tiff_input_file(t4_tx_state_t *s, const char *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) static int tiff_row_read_handler(void *user_data, uint8_t buf[], size_t len)
{ {
t4_tx_state_t *s; t4_tx_state_t *s;
int i;
int j;
s = (t4_tx_state_t *) user_data; s = (t4_tx_state_t *) user_data;
if (s->tiff.row >= s->image_length) if (s->tiff.row >= s->image_length)
return 0; return 0;
memcpy(buf, &s->tiff.image_buffer[s->tiff.row*len], len); memcpy(buf, &s->tiff.image_buffer[s->tiff.row*len], len);
s->tiff.row++; 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; return len;
} }
/*- End of function --------------------------------------------------------*/ /*- End of function --------------------------------------------------------*/
...@@ -497,7 +508,7 @@ static int tiff_row_read_handler(void *user_data, uint8_t buf[], size_t len) ...@@ -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) static int row_read(void *user_data, uint8_t buf[], size_t len)
{ {
t4_tx_state_t *s; t4_tx_state_t *s;
s = (t4_tx_state_t *) user_data; s = (t4_tx_state_t *) user_data;
if (s->tiff.raw_row >= s->tiff.image_length) if (s->tiff.raw_row >= s->tiff.image_length)
...@@ -650,7 +661,7 @@ static int make_header(t4_tx_state_t *s) ...@@ -650,7 +661,7 @@ static int make_header(t4_tx_state_t *s)
if ((s->header_text = malloc(132 + 1)) == NULL) if ((s->header_text = malloc(132 + 1)) == NULL)
return -1; 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 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 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 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) ...@@ -711,6 +722,7 @@ static int header_row_read_handler(void *user_data, uint8_t buf[], size_t len)
repeats = 1; repeats = 1;
break; break;
} }
repeats /= s->row_squashing_ratio;
if (s->header_overlays_image) if (s->header_overlays_image)
{ {
/* Read and dump a row of the real image, allowing for the possibility /* 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) ...@@ -721,23 +733,37 @@ static int header_row_read_handler(void *user_data, uint8_t buf[], size_t len)
return len; return len;
} }
} }
row = s->header_row/repeats; switch (s->tiff.image_type)
pos = 0;
for (t = s->header_text; *t && pos <= len - 2; t++)
{ {
pattern = header_font[(uint8_t) *t][row]; case T4_IMAGE_TYPE_BILEVEL:
buf[pos++] = (uint8_t) (pattern >> 8); row = s->header_row/repeats;
buf[pos++] = (uint8_t) (pattern & 0xFF); 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; return len;
} }
/*- End of function --------------------------------------------------------*/ /*- 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_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); 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 ...@@ -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 = tiff_row_read_handler;
s->row_handler_user_data = (void *) s; s->row_handler_user_data = (void *) s;
s->row_squashing_ratio = 1;
if (file) if (file)
{ {
if (open_tiff_input_file(s, file) < 0) if (open_tiff_input_file(s, file) < 0)
......
...@@ -575,7 +575,7 @@ int main(int argc, char *argv[]) ...@@ -575,7 +575,7 @@ int main(int argc, char *argv[])
if (compression < 0 || (block_size == 0 && compression_step >= 3)) if (compression < 0 || (block_size == 0 && compression_step >= 3))
break; 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); t4_rx_set_rx_encoding(&receive_state, compression);
rows_read = 0; rows_read = 0;
...@@ -716,7 +716,7 @@ int main(int argc, char *argv[]) ...@@ -716,7 +716,7 @@ int main(int argc, char *argv[])
compression = compression_sequence[compression_step++]; 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); t4_rx_set_rx_encoding(&receive_state, compression);
if (t4_tx_start_page(&send_state)) if (t4_tx_start_page(&send_state))
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论