From 9eab201f935afa6387222cc35d778323ca8f86dc Mon Sep 17 00:00:00 2001 From: Steve Underwood Date: Thu, 11 Apr 2013 18:08:32 +0800 Subject: [PATCH] More steps towards colour FAX --- libs/spandsp/src/spandsp/private/t30.h | 6 +- .../spandsp/private/t30_dis_dtc_dcs_bits.h | 12 +- libs/spandsp/src/spandsp/private/t4_tx.h | 4 + libs/spandsp/src/spandsp/t4_rx.h | 58 +-- libs/spandsp/src/spandsp/t4_tx.h | 10 + libs/spandsp/src/t30.c | 421 ++++++++++-------- libs/spandsp/src/t30_api.c | 5 +- libs/spandsp/src/t4_rx.c | 154 ++++--- libs/spandsp/src/t4_tx.c | 201 ++++----- 9 files changed, 499 insertions(+), 372 deletions(-) diff --git a/libs/spandsp/src/spandsp/private/t30.h b/libs/spandsp/src/spandsp/private/t30.h index b0c32d5515..c28feafed2 100644 --- a/libs/spandsp/src/spandsp/private/t30.h +++ b/libs/spandsp/src/spandsp/private/t30.h @@ -222,10 +222,12 @@ struct t30_state_s int local_interrupt_pending; /*! \brief The common ground in compression schemes between the local and far ends. */ int mutual_compressions; - /*! \brief The common group supported bi-level image resolutions. */ + /*! \brief The common group of supported bi-level image resolutions. */ int mutual_bilevel_resolutions; - /*! \brief The common group supported colour image resolutions. */ + /*! \brief The common group of supported colour image resolutions. */ int mutual_colour_resolutions; + /*! \brief The common group of supported image sizes. */ + int mutual_image_sizes; /*! \brief The image coding being used on the line. */ int line_encoding; /*! \brief The image coding being used for output files. */ diff --git a/libs/spandsp/src/spandsp/private/t30_dis_dtc_dcs_bits.h b/libs/spandsp/src/spandsp/private/t30_dis_dtc_dcs_bits.h index 5d6cf93adb..52e0ac8dd2 100644 --- a/libs/spandsp/src/spandsp/private/t30_dis_dtc_dcs_bits.h +++ b/libs/spandsp/src/spandsp/private/t30_dis_dtc_dcs_bits.h @@ -80,9 +80,17 @@ /* Standard facsimile terminals conforming to ITU-T Rec. T.4 must have the following capability: Paper length = 297 mm. */ -/* Bits 17, 18 - recording width */ +#define T30_DIS_BIT_215MM_255MM_WIDTH_CAPABLE 17 +#define T30_DCS_BIT_255MM_WIDTH 17 -/* Bits 19, 20 - paper length */ +#define T30_DIS_BIT_215MM_255MM_303MM_WIDTH_CAPABLE 18 +#define T30_DCS_BIT_303MM_WIDTH 18 + +#define T30_DIS_BIT_A4_B4_LENGTH_CAPABLE 19 +#define T30_DCS_BIT_B4_LENGTH 19 + +#define T30_DIS_BIT_UNLIMITED_LENGTH_CAPABLE 20 +#define T30_DCS_BIT_UNLIMITED_LENGTH 20 /* Bits 21, 22, 23 - min scan line time */ diff --git a/libs/spandsp/src/spandsp/private/t4_tx.h b/libs/spandsp/src/spandsp/private/t4_tx.h index 39a21db48e..361ca88871 100644 --- a/libs/spandsp/src/spandsp/private/t4_tx.h +++ b/libs/spandsp/src/spandsp/private/t4_tx.h @@ -82,6 +82,10 @@ typedef struct int x_resolution; /*! \brief Row-to-row (Y) resolution in pixels per metre on the wire. */ int y_resolution; + /*! \brief Code for the combined X and Y resolution of the image in the file. */ + int resolution_code; + /*! \brief Image type - bi-level, gray, colour, etc. */ + int image_type; } t4_tx_metadata_t; /*! diff --git a/libs/spandsp/src/spandsp/t4_rx.h b/libs/spandsp/src/spandsp/t4_rx.h index 4e2e57d14e..6767f902d4 100644 --- a/libs/spandsp/src/spandsp/t4_rx.h +++ b/libs/spandsp/src/spandsp/t4_rx.h @@ -98,11 +98,11 @@ enum T30_SUPPORT_COMPRESSION_GRAYSCALE = 0x1000000, /*! Colour support by multi-level codecs */ T30_SUPPORT_COMPRESSION_COLOUR = 0x2000000, - /*! 12 bit mode for gray scale and colour */ + /*! 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 */ + /*! 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, @@ -141,7 +141,7 @@ typedef enum T4_X_RESOLUTION_200 = 7874, T4_X_RESOLUTION_R8 = 8031, T4_X_RESOLUTION_300 = 11811, - T4_X_RESOLUTION_400 = 15784, + T4_X_RESOLUTION_400 = 15748, T4_X_RESOLUTION_R16 = 16063, T4_X_RESOLUTION_600 = 23622, T4_X_RESOLUTION_800 = 31496, @@ -176,27 +176,27 @@ enum /*! Double FAX resolution 408dpi x 391dpi - bi-level only */ T4_RESOLUTION_R16_SUPERFINE = 4, - /*! 100dpi x 100 dpi - gray-scale and colour only */ + /*! 100dpi x 100dpi - gray-scale and colour only */ T4_RESOLUTION_100_100 = 5, - /*! 200dpi x 100 dpi - bi-level only */ + /*! 200dpi x 100dpi - bi-level only */ T4_RESOLUTION_200_100 = 6, - /*! 200dpi x 200 dpi */ + /*! 200dpi x 200dpi */ T4_RESOLUTION_200_200 = 7, - /*! 200dpi x 400 dpi - bi-level only */ + /*! 200dpi x 400dpi - bi-level only */ T4_RESOLUTION_200_400 = 8, - /*! 300dpi x 300 dpi */ + /*! 300dpi x 300dpi */ T4_RESOLUTION_300_300 = 9, - /*! 300dpi x 600 dpi - bi-level only */ + /*! 300dpi x 600dpi - bi-level only */ T4_RESOLUTION_300_600 = 10, - /*! 400dpi x 400 dpi */ + /*! 400dpi x 400dpi */ T4_RESOLUTION_400_400 = 11, - /*! 400dpi x 800 dpi - bi-level only */ + /*! 400dpi x 800dpi - bi-level only */ T4_RESOLUTION_400_800 = 12, - /*! 600dpi x 600 dpi */ + /*! 600dpi x 600dpi */ T4_RESOLUTION_600_600 = 13, - /*! 600dpi x 1200 dpi - bi-level only */ + /*! 600dpi x 1200dpi - bi-level only */ T4_RESOLUTION_600_1200 = 14, - /*! 1200dpi x 1200 dpi */ + /*! 1200dpi x 1200dpi */ T4_RESOLUTION_1200_1200 = 15 }; @@ -211,27 +211,27 @@ enum /*! Support double FAX resolution 408dpi x 391dpi - bi-level only */ T4_SUPPORT_RESOLUTION_R16_SUPERFINE = 0x8, - /*! Support 100dpi x 100 dpi - gray scale and colour only */ + /*! Support 100dpi x 100dpi - gray-scale and colour only */ T4_SUPPORT_RESOLUTION_100_100 = 0x10, - /*! Support 200dpi x 100 dpi - bi-level only */ + /*! Support 200dpi x 100dpi - bi-level only */ T4_SUPPORT_RESOLUTION_200_100 = 0x20, - /*! Support 200dpi x 200 dpi */ + /*! Support 200dpi x 200dpi */ T4_SUPPORT_RESOLUTION_200_200 = 0x40, - /*! Support 200dpi x 400 dpi - bi-level only */ + /*! Support 200dpi x 400dpi - bi-level only */ T4_SUPPORT_RESOLUTION_200_400 = 0x80, - /*! Support 300dpi x 300 dpi */ + /*! Support 300dpi x 300dpi */ T4_SUPPORT_RESOLUTION_300_300 = 0x100, - /*! Support 300dpi x 600 dpi - bi-level only */ + /*! Support 300dpi x 600dpi - bi-level only */ T4_SUPPORT_RESOLUTION_300_600 = 0x200, - /*! Support 400dpi x 400 dpi */ + /*! Support 400dpi x 400dpi */ T4_SUPPORT_RESOLUTION_400_400 = 0x400, - /*! Support 400dpi x 800 dpi - bi-level only */ + /*! Support 400dpi x 800dpi - bi-level only */ T4_SUPPORT_RESOLUTION_400_800 = 0x800, - /*! Support 600dpi x 600 dpi */ + /*! Support 600dpi x 600dpi */ T4_SUPPORT_RESOLUTION_600_600 = 0x1000, - /*! Support 600dpi x 1200 dpi - bi-level only */ + /*! Support 600dpi x 1200dpi - bi-level only */ T4_SUPPORT_RESOLUTION_600_1200 = 0x2000, - /*! Support 1200dpi x 1200 dpi */ + /*! Support 1200dpi x 1200dpi */ T4_SUPPORT_RESOLUTION_1200_1200 = 0x4000 }; @@ -542,10 +542,16 @@ SPAN_DECLARE(const char *) t4_encoding_to_str(int encoding); /*! Get the short text name of an image format. \brief Get the short text name of an image format. - \param encoding The image format. + \param type The image format. \return A pointer to the string. */ SPAN_DECLARE(const char *) t4_image_type_to_str(int type); +/*! Get the short text name of an image resolution. + \brief Get the short text name of an image resolution. + \param resolution_code The image resolution code. + \return A pointer to the string. */ +SPAN_DECLARE(const char *) t4_image_resolution_to_str(int resolution_code); + /*! Get the logging context associated with a T.4 receive context. \brief Get the logging context associated with a T.4 receive context. \param s The T.4 receive context. diff --git a/libs/spandsp/src/spandsp/t4_tx.h b/libs/spandsp/src/spandsp/t4_tx.h index 5b1989498d..bcf75d6c02 100644 --- a/libs/spandsp/src/spandsp/t4_tx.h +++ b/libs/spandsp/src/spandsp/t4_tx.h @@ -341,11 +341,21 @@ SPAN_DECLARE(int) t4_tx_get_y_resolution(t4_tx_state_t *s); \return The resolution, in pixels per metre. */ SPAN_DECLARE(int) t4_tx_get_x_resolution(t4_tx_state_t *s); +/*! \brief Get the X and Y resolution code of the current page. + \param s The T.4 context. + \return The resolution code,. */ +SPAN_DECLARE(int) t4_tx_get_resolution(t4_tx_state_t *s); + /*! \brief Get the width of the current page, in pixel columns. \param s The T.4 context. \return The number of columns. */ SPAN_DECLARE(int) t4_tx_get_image_width(t4_tx_state_t *s); +/*! \brief Get the type of the current page, in pixel columns. + \param s The T.4 context. + \return The type. */ +SPAN_DECLARE(int) t4_tx_get_image_type(t4_tx_state_t *s); + /*! \brief Get the number of pages in the file. \param s The T.4 context. \return The number of pages, or -1 if there is an error. */ diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c index 7e235e0104..8124ec5bbd 100644 --- a/libs/spandsp/src/t30.c +++ b/libs/spandsp/src/t30.c @@ -1144,6 +1144,29 @@ static int set_dis_or_dtc(t30_state_t *s) } /*- End of function --------------------------------------------------------*/ +static int prune_dis_dtc(t30_state_t *s) +{ + int i; + + /* Find the last octet that is really needed, set the extension bits, and trim the message length */ + for (i = 18; i >= 6; i--) + { + /* Strip the top bit */ + s->local_dis_dtc_frame[i] &= (DISBIT1 | DISBIT2 | DISBIT3 | DISBIT4 | DISBIT5 | DISBIT6 | DISBIT7); + /* Check if there is some real message content here */ + if (s->local_dis_dtc_frame[i]) + break; + } + s->local_dis_dtc_len = i + 1; + /* Fill in any required extension bits */ + s->local_dis_dtc_frame[i] &= ~DISBIT8; + for (i--; i > 4; i--) + s->local_dis_dtc_frame[i] |= DISBIT8; + t30_decode_dis_dtc_dcs(s, s->local_dis_dtc_frame, s->local_dis_dtc_len); + return s->local_dis_dtc_len; +} +/*- End of function --------------------------------------------------------*/ + int t30_build_dis_or_dtc(t30_state_t *s) { int i; @@ -1181,15 +1204,19 @@ int t30_build_dis_or_dtc(t30_state_t *s) /* 215mm wide is always supported */ if ((s->supported_image_sizes & T4_SUPPORT_WIDTH_303MM)) - set_ctrl_bit(s->local_dis_dtc_frame, 18); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_215MM_255MM_303MM_WIDTH_CAPABLE); else if ((s->supported_image_sizes & T4_SUPPORT_WIDTH_255MM)) - set_ctrl_bit(s->local_dis_dtc_frame, 17); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_215MM_255MM_WIDTH_CAPABLE); /* A4 is always supported. */ if ((s->supported_image_sizes & T4_SUPPORT_LENGTH_UNLIMITED)) - set_ctrl_bit(s->local_dis_dtc_frame, 20); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_UNLIMITED_LENGTH_CAPABLE); else if ((s->supported_image_sizes & T4_SUPPORT_LENGTH_B4)) - set_ctrl_bit(s->local_dis_dtc_frame, 19); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_A4_B4_LENGTH_CAPABLE); + if ((s->supported_image_sizes & T4_SUPPORT_LENGTH_US_LETTER)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LETTER_CAPABLE); + if ((s->supported_image_sizes & T4_SUPPORT_LENGTH_US_LEGAL)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LEGAL_CAPABLE); /* No scan-line padding required, but some may be specified by the application. */ set_ctrl_bits(s->local_dis_dtc_frame, s->local_min_scan_time_code, 21); @@ -1240,7 +1267,7 @@ int t30_build_dis_or_dtc(t30_state_t *s) 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)) + //if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_NO_SUBSAMPLING)) // set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NO_SUBSAMPLING); /* No custom illuminant */ @@ -1275,10 +1302,6 @@ int t30_build_dis_or_dtc(t30_state_t *s) /* No mode 26 (T.505) */ /* No digital network capability */ /* No duplex operation */ - if ((s->supported_image_sizes & T4_SUPPORT_LENGTH_US_LETTER)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LETTER_CAPABLE); - if ((s->supported_image_sizes & T4_SUPPORT_LENGTH_US_LEGAL)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LEGAL_CAPABLE); /* No HKM key management */ /* No RSA key management */ /* No override */ @@ -1365,34 +1388,20 @@ int t30_build_dis_or_dtc(t30_state_t *s) } /*- End of function --------------------------------------------------------*/ -static int prune_dis_dtc(t30_state_t *s) -{ - int i; - - /* Find the last octet that is really needed, set the extension bits, and trim the message length */ - for (i = 18; i >= 6; i--) - { - /* Strip the top bit */ - s->local_dis_dtc_frame[i] &= (DISBIT1 | DISBIT2 | DISBIT3 | DISBIT4 | DISBIT5 | DISBIT6 | DISBIT7); - /* Check if there is some real message content here */ - if (s->local_dis_dtc_frame[i]) - break; - } - s->local_dis_dtc_len = i + 1; - /* Fill in any required extension bits */ - s->local_dis_dtc_frame[i] &= ~DISBIT8; - for (i--; i > 4; i--) - s->local_dis_dtc_frame[i] |= DISBIT8; - t30_decode_dis_dtc_dcs(s, s->local_dis_dtc_frame, s->local_dis_dtc_len); - return s->local_dis_dtc_len; -} -/*- End of function --------------------------------------------------------*/ - static int build_dcs(t30_state_t *s) { int i; int bad; int row_squashing_ratio; + int use_bilevel; + //int image_type; + + /* Reacquire page information, in case the image was resized, flattened, etc. */ + s->x_resolution = t4_tx_get_x_resolution(&s->t4.tx); + s->y_resolution = t4_tx_get_y_resolution(&s->t4.tx); + //s->current_page_resolution = t4_tx_get_resolution(&s->t4.tx); + s->image_width = t4_tx_get_image_width(&s->t4.tx); + //image_type = t4_tx_get_image_type(&s->t4.tx); /* 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. */ @@ -1414,17 +1423,35 @@ static int build_dcs(t30_state_t *s) /* Set to required modem rate */ s->dcs_frame[4] |= fallback_sequence[s->current_fallback].dcs_code; + /* We have a file to send, so tell the far end to go into receive mode. */ + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_RECEIVE_FAX_DOCUMENT); + /* Select the compression to use. */ + use_bilevel = TRUE; switch (s->line_encoding) { case T4_COMPRESSION_T42_T81: - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T81_MODE); + //if (image_type == T4_IMAGE_TYPE_COLOUR_8BIT || image_type == T4_IMAGE_TYPE_COLOUR_12BIT) + // set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE); + //if (image_type == T4_IMAGE_TYPE_GRAY_12BIT || image_type == T4_IMAGE_TYPE_COLOUR_12BIT) + // set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_12BIT_COMPONENT); + //if (???????? & T4_COMPRESSION_?????)) + // set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_NO_SUBSAMPLING); set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21); + use_bilevel = FALSE; break; #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_T43: set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T43_MODE); + //if (image_type == T4_IMAGE_TYPE_COLOUR_8BIT || image_type == T4_IMAGE_TYPE_COLOUR_12BIT) + // set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE); + //if (image_type == T4_IMAGE_TYPE_GRAY_12BIT || image_type == T4_IMAGE_TYPE_COLOUR_12BIT) + // set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_12BIT_COMPONENT); + //if (???????? & T4_COMPRESSION_?????)) + // set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_NO_SUBSAMPLING); set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21); + use_bilevel = FALSE; break; #endif case T4_COMPRESSION_T85_L0: @@ -1450,154 +1477,166 @@ static int build_dcs(t30_state_t *s) set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21); break; } - /* We have a file to send, so tell the far end to go into receive mode. */ - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_RECEIVE_FAX_DOCUMENT); + /* Set the Y resolution bits */ bad = T30_ERR_NORESSUPPORT; row_squashing_ratio = 1; - switch (s->y_resolution) + if (use_bilevel) { - case T4_Y_RESOLUTION_1200: - switch (s->x_resolution) + switch (s->y_resolution) { - case T4_X_RESOLUTION_1200: - if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_1200_1200)) + case T4_Y_RESOLUTION_1200: + switch (s->x_resolution) { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_1200_1200); - bad = T30_ERR_OK; + case T4_X_RESOLUTION_1200: + if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_1200_1200)) + { + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_1200_1200); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION); + bad = T30_ERR_OK; + } + break; + case T4_X_RESOLUTION_600: + if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_600_1200)) + { + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_600_1200); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION); + bad = T30_ERR_OK; + } + break; } break; - case T4_X_RESOLUTION_600: - if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_600_1200)) + case T4_Y_RESOLUTION_800: + switch (s->x_resolution) { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_600_1200); - bad = T30_ERR_OK; + case T4_X_RESOLUTION_R16: + if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_400_800)) + { + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_800); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION); + bad = T30_ERR_OK; + } + break; } break; - } - break; - case T4_Y_RESOLUTION_800: - switch (s->x_resolution) - { - case T4_X_RESOLUTION_R16: - if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_400_800)) + case T4_Y_RESOLUTION_600: + switch (s->x_resolution) { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_800); - bad = T30_ERR_OK; + case T4_X_RESOLUTION_600: + if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_600_600)) + { + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_600_600); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION); + bad = T30_ERR_OK; + } + break; + case T4_X_RESOLUTION_300: + if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_300_600)) + { + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_300_600); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION); + bad = T30_ERR_OK; + } + break; } break; - } - break; - case T4_Y_RESOLUTION_600: - switch (s->x_resolution) - { - case T4_X_RESOLUTION_600: - if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_600_600)) + case T4_Y_RESOLUTION_300: + switch (s->x_resolution) { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_600_600); - bad = T30_ERR_OK; + case T4_X_RESOLUTION_300: + if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_300_300)) + { + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_300_300); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION); + bad = T30_ERR_OK; + } + break; } break; - case T4_X_RESOLUTION_300: - if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_300_600)) + case T4_Y_RESOLUTION_SUPERFINE: + case T4_Y_RESOLUTION_400: + if (s->x_resolution == T4_X_RESOLUTION_400 && s->y_resolution == T4_Y_RESOLUTION_400) { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_300_600); - bad = T30_ERR_OK; + if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_400_400)) + { + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_400); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION); + bad = T30_ERR_OK; + break; + } } - break; - } - break; - case T4_Y_RESOLUTION_300: - switch (s->x_resolution) - { - case T4_X_RESOLUTION_300: - if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_300_300)) + else if (s->x_resolution == T4_X_RESOLUTION_R16 && s->y_resolution == T4_Y_RESOLUTION_SUPERFINE) { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_300_300); - bad = T30_ERR_OK; + if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_R16_SUPERFINE)) + { + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_400); + bad = T30_ERR_OK; + break; + } } - break; - } - break; - case T4_Y_RESOLUTION_SUPERFINE: - case T4_Y_RESOLUTION_400: - if (s->x_resolution == T4_X_RESOLUTION_400 && s->y_resolution == T4_Y_RESOLUTION_400) - { - if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_400_400)) + else if (s->x_resolution == T4_X_RESOLUTION_200 && s->y_resolution == T4_Y_RESOLUTION_400) { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_400); + if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_200_400)) + { + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_400); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION); + bad = T30_ERR_OK; + break; + } + } + else if (s->x_resolution == T4_X_RESOLUTION_R8 && s->y_resolution == T4_Y_RESOLUTION_SUPERFINE) + { + if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_R8_SUPERFINE)) + { + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_400); + bad = T30_ERR_OK; + break; + } + } + row_squashing_ratio <<= 1; + /* Fall through */ + case T4_Y_RESOLUTION_FINE: + case T4_Y_RESOLUTION_200: + if (s->x_resolution == T4_X_RESOLUTION_200 && s->y_resolution == T4_Y_RESOLUTION_200) + { + if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_200_200)) + { + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_200); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION); + bad = T30_ERR_OK; + break; + } + } + else if (s->x_resolution == T4_X_RESOLUTION_R8 && s->y_resolution == T4_Y_RESOLUTION_FINE) + { + if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_R8_FINE)) + { + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_200); + bad = T30_ERR_OK; + break; + } + } + row_squashing_ratio <<= 1; + /* Fall through */ + default: + case T4_Y_RESOLUTION_STANDARD: + case T4_Y_RESOLUTION_100: + if (s->x_resolution == T4_X_RESOLUTION_R8 && s->y_resolution == T4_Y_RESOLUTION_STANDARD) + { + /* No bits to set for this */ bad = T30_ERR_OK; break; } - } - else if (s->x_resolution == T4_X_RESOLUTION_R16 && s->y_resolution == T4_Y_RESOLUTION_SUPERFINE) - { - if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_R16_SUPERFINE)) + else if (s->x_resolution == T4_X_RESOLUTION_200 && s->y_resolution == T4_Y_RESOLUTION_100) { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_400); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION); bad = T30_ERR_OK; break; } - } - else if (s->x_resolution == T4_X_RESOLUTION_200 && s->y_resolution == T4_Y_RESOLUTION_400) - { - if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_200_400)) - { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_400); - bad = T30_ERR_OK; - break; - } - } - else if (s->x_resolution == T4_X_RESOLUTION_R8 && s->y_resolution == T4_Y_RESOLUTION_SUPERFINE) - { - if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_R8_SUPERFINE)) - { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_400); - bad = T30_ERR_OK; - break; - } - } - row_squashing_ratio <<= 1; - /* Fall through */ - case T4_Y_RESOLUTION_FINE: - case T4_Y_RESOLUTION_200: - if (s->x_resolution == T4_X_RESOLUTION_200 && s->y_resolution == T4_Y_RESOLUTION_200) - { - if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_200_200)) - { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_200); - bad = T30_ERR_OK; - break; - } - } - else if (s->x_resolution == T4_X_RESOLUTION_R8 && s->y_resolution == T4_Y_RESOLUTION_FINE) - { - if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_R8_FINE)) - { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_200); - bad = T30_ERR_OK; - break; - } - } - row_squashing_ratio <<= 1; - /* Fall through */ - default: - case T4_Y_RESOLUTION_STANDARD: - case T4_Y_RESOLUTION_100: - if (s->x_resolution == T4_X_RESOLUTION_R8 && s->y_resolution == T4_Y_RESOLUTION_STANDARD) - { - /* No bits to set for this */ - bad = T30_ERR_OK; break; } - else if (s->x_resolution == T4_X_RESOLUTION_200 && s->y_resolution == T4_Y_RESOLUTION_100) - { - /* No bits to set for this */ - bad = T30_ERR_OK; - break; - } - break; } + t4_tx_set_row_squashing_ratio(&s->t4.tx, row_squashing_ratio); if (bad != T30_ERR_OK) { @@ -1634,12 +1673,10 @@ static int build_dcs(t30_state_t *s) || ((s->image_width == T4_WIDTH_1200_B4) && (s->x_resolution == T4_X_RESOLUTION_1200))) { - if (((s->far_dis_dtc_frame[5] & (DISBIT2 | DISBIT1)) >= 1) - && - (s->supported_image_sizes & T4_SUPPORT_WIDTH_255MM)) + if ((s->mutual_image_sizes & T4_SUPPORT_WIDTH_255MM)) { span_log(&s->logging, SPAN_LOG_FLOW, "Image width is B4\n"); - set_ctrl_bit(s->dcs_frame, 17); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_255MM_WIDTH); } else { @@ -1657,12 +1694,10 @@ static int build_dcs(t30_state_t *s) || ((s->image_width == T4_WIDTH_1200_A3) && (s->x_resolution == T4_X_RESOLUTION_1200))) { - if (((s->far_dis_dtc_frame[5] & (DISBIT2 | DISBIT1)) >= 2) - && - (s->supported_image_sizes & T4_SUPPORT_WIDTH_303MM)) + if ((s->mutual_image_sizes & T4_SUPPORT_WIDTH_303MM)) { span_log(&s->logging, SPAN_LOG_FLOW, "Image width is A3\n"); - set_ctrl_bit(s->dcs_frame, 18); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_303MM_WIDTH); } else { @@ -1691,10 +1726,10 @@ static int build_dcs(t30_state_t *s) /* Deal with the image length */ /* If the other end supports unlimited length, then use that. Otherwise, if the other end supports B4 use that, as its longer than the default A4 length. */ - if (test_ctrl_bit(s->far_dis_dtc_frame, 20)) - set_ctrl_bit(s->dcs_frame, 20); - else if (test_ctrl_bit(s->far_dis_dtc_frame, 19)) - set_ctrl_bit(s->dcs_frame, 19); + if ((s->mutual_image_sizes & T4_SUPPORT_LENGTH_UNLIMITED)) + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_UNLIMITED_LENGTH); + else if ((s->mutual_image_sizes & T4_SUPPORT_LENGTH_B4)) + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_B4_LENGTH); if (s->error_correcting_mode) set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_ECM_MODE); @@ -2167,9 +2202,11 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) memcpy(s->far_dis_dtc_frame, msg, s->far_dis_dtc_len); if (s->far_dis_dtc_len < T30_MAX_DIS_DTC_DCS_LEN) memset(s->far_dis_dtc_frame + s->far_dis_dtc_len, 0, T30_MAX_DIS_DTC_DCS_LEN - s->far_dis_dtc_len); - s->error_correcting_mode = (s->ecm_allowed && (s->far_dis_dtc_frame[6] & DISBIT3) != 0); + + s->error_correcting_mode = (s->ecm_allowed && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_ECM_CAPABLE)); /* 256 octets per ECM frame */ s->octets_per_ecm_frame = 256; + /* Now we know if we are going to use ECM, select the compressions which we can use. */ s->mutual_compressions = s->supported_compressions; if (!s->error_correcting_mode) @@ -2283,6 +2320,24 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_100_100_CAPABLE)) s->mutual_colour_resolutions &= ~T4_SUPPORT_RESOLUTION_100_100; + s->mutual_image_sizes = s->supported_image_sizes; + /* 215mm wide is always supported */ + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_215MM_255MM_303MM_WIDTH_CAPABLE)) + { + s->mutual_image_sizes &= ~T4_SUPPORT_WIDTH_303MM; + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_215MM_255MM_WIDTH_CAPABLE)) + s->mutual_image_sizes &= ~T4_SUPPORT_WIDTH_255MM; + } + /* A4 is always supported. */ + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_UNLIMITED_LENGTH_CAPABLE)) + s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_UNLIMITED; + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_A4_B4_LENGTH_CAPABLE)) + s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_B4; + if (!test_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LETTER_CAPABLE)) + s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_US_LETTER; + if (!test_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LEGAL_CAPABLE)) + s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_US_LEGAL; + switch (s->far_dis_dtc_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3)) { case (DISBIT6 | DISBIT4 | DISBIT3): @@ -2443,7 +2498,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) s->x_resolution = -1; s->y_resolution = -1; - //s->current_page_resolution = 0; + s->current_page_resolution = 0; x = -1; if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T81_MODE) || test_ctrl_bit(dcs_frame, T30_DCS_BIT_T43_MODE)) { @@ -2471,7 +2526,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_1200; s->y_resolution = T4_Y_RESOLUTION_1200; - //s->current_page_resolution = T4_RESOLUTION_1200_1200; + s->current_page_resolution = T4_RESOLUTION_1200_1200; x = 5; } } @@ -2481,7 +2536,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_600; s->y_resolution = T4_Y_RESOLUTION_600; - //s->current_page_resolution = T4_RESOLUTION_600_600; + s->current_page_resolution = T4_RESOLUTION_600_600; x = 4; } } @@ -2491,7 +2546,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_400; s->y_resolution = T4_Y_RESOLUTION_400; - //s->current_page_resolution = T4_RESOLUTION_400_400; + s->current_page_resolution = T4_RESOLUTION_400_400; x = 3; } } @@ -2501,7 +2556,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_300; s->y_resolution = T4_Y_RESOLUTION_300; - //s->current_page_resolution = T4_RESOLUTION_300_300; + s->current_page_resolution = T4_RESOLUTION_300_300; x = 2; } } @@ -2511,7 +2566,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_200; s->y_resolution = T4_Y_RESOLUTION_200; - //s->current_page_resolution = T4_RESOLUTION_200_200; + s->current_page_resolution = T4_RESOLUTION_200_200; x = 1; } } @@ -2521,7 +2576,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_100; s->y_resolution = T4_Y_RESOLUTION_100; - //s->current_page_resolution = T4_RESOLUTION_100_100; + s->current_page_resolution = T4_RESOLUTION_100_100; x = 0; } } @@ -2535,7 +2590,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_1200; s->y_resolution = T4_Y_RESOLUTION_1200; - //s->current_page_resolution = T4_RESOLUTION_1200_1200; + s->current_page_resolution = T4_RESOLUTION_1200_1200; x = 5; } } @@ -2545,7 +2600,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_600; s->y_resolution = T4_Y_RESOLUTION_1200; - //s->current_page_resolution = T4_RESOLUTION_600_1200; + s->current_page_resolution = T4_RESOLUTION_600_1200; x = 4; } } @@ -2555,7 +2610,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_600; s->y_resolution = T4_Y_RESOLUTION_600; - //s->current_page_resolution = T4_RESOLUTION_600_600; + s->current_page_resolution = T4_RESOLUTION_600_600; x = 4; } } @@ -2565,7 +2620,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_400; s->y_resolution = T4_Y_RESOLUTION_800; - //s->current_page_resolution = T4_RESOLUTION_400_800; + s->current_page_resolution = T4_RESOLUTION_400_800; x = 3; } } @@ -2577,7 +2632,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_400; s->y_resolution = T4_Y_RESOLUTION_400; - //s->current_page_resolution = T4_RESOLUTION_400_400; + s->current_page_resolution = T4_RESOLUTION_400_400; x = 3; } } @@ -2587,7 +2642,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_R16; s->y_resolution = T4_Y_RESOLUTION_SUPERFINE; - //s->current_page_resolution = T4_RESOLUTION_R16_SUPERFINE; + s->current_page_resolution = T4_RESOLUTION_R16_SUPERFINE; x = 3; } } @@ -2598,7 +2653,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_300; s->y_resolution = T4_Y_RESOLUTION_600; - //s->current_page_resolution = T4_RESOLUTION_300_600; + s->current_page_resolution = T4_RESOLUTION_300_600; x = 2; } } @@ -2608,7 +2663,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_300; s->y_resolution = T4_Y_RESOLUTION_300; - //s->current_page_resolution = T4_RESOLUTION_300_300; + s->current_page_resolution = T4_RESOLUTION_300_300; x = 2; } } @@ -2620,7 +2675,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_200; s->y_resolution = T4_Y_RESOLUTION_400; - //s->current_page_resolution = T4_RESOLUTION_200_400; + s->current_page_resolution = T4_RESOLUTION_200_400; x = 1; } } @@ -2630,7 +2685,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_R8; s->y_resolution = T4_Y_RESOLUTION_SUPERFINE; - //s->current_page_resolution = T4_RESOLUTION_R8_SUPERFINE; + s->current_page_resolution = T4_RESOLUTION_R8_SUPERFINE; x = 1; } } @@ -2643,7 +2698,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_200; s->y_resolution = T4_Y_RESOLUTION_200; - //s->current_page_resolution = T4_RESOLUTION_200_200; + s->current_page_resolution = T4_RESOLUTION_200_200; x = 1; } } @@ -2653,7 +2708,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_R8; s->y_resolution = T4_Y_RESOLUTION_FINE; - //s->current_page_resolution = T4_RESOLUTION_R8_FINE; + s->current_page_resolution = T4_RESOLUTION_R8_FINE; x = 1; } } @@ -2664,14 +2719,14 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->x_resolution = T4_X_RESOLUTION_200; s->y_resolution = T4_Y_RESOLUTION_100; - //s->current_page_resolution = T4_RESOLUTION_200_100; + s->current_page_resolution = T4_RESOLUTION_200_100; x = 1; } else { s->x_resolution = T4_X_RESOLUTION_R8; s->y_resolution = T4_Y_RESOLUTION_STANDARD; - //s->current_page_resolution = T4_RESOLUTION_R8_STANDARD; + s->current_page_resolution = T4_RESOLUTION_R8_STANDARD; x = 1; } } diff --git a/libs/spandsp/src/t30_api.c b/libs/spandsp/src/t30_api.c index 138d3f4deb..0282dcc75b 100644 --- a/libs/spandsp/src/t30_api.c +++ b/libs/spandsp/src/t30_api.c @@ -754,7 +754,10 @@ SPAN_DECLARE(int) t30_set_supported_colour_resolutions(t30_state_t *s, int suppo SPAN_DECLARE(int) t30_set_supported_image_sizes(t30_state_t *s, int supported_image_sizes) { - s->supported_image_sizes = supported_image_sizes; + /* Force the sizes which are always available */ + s->supported_image_sizes = supported_image_sizes + | T4_SUPPORT_WIDTH_215MM + | T4_SUPPORT_LENGTH_A4; t30_build_dis_or_dtc(s); return 0; } diff --git a/libs/spandsp/src/t4_rx.c b/libs/spandsp/src/t4_rx.c index 3c9a5f5e68..f2a2929fd1 100644 --- a/libs/spandsp/src/t4_rx.c +++ b/libs/spandsp/src/t4_rx.c @@ -141,6 +141,45 @@ SPAN_DECLARE(const char *) t4_image_type_to_str(int type) } /*- End of function --------------------------------------------------------*/ +SPAN_DECLARE(const char *) t4_image_resolution_to_str(int resolution_code) +{ + switch (resolution_code) + { + case T4_RESOLUTION_R8_STANDARD: + return "204dpi x 98dpi"; + case T4_RESOLUTION_R8_FINE: + return "204dpi x 196dpi"; + case T4_RESOLUTION_R8_SUPERFINE: + return "204dpi x 391dpi"; + case T4_RESOLUTION_R16_SUPERFINE: + return "408dpi x 391dpi"; + case T4_RESOLUTION_100_100: + return "100dpi x 100dpi"; + case T4_RESOLUTION_200_100: + return "200dpi x 100dpi"; + case T4_RESOLUTION_200_200: + return "200dpi x 200dpi"; + case T4_RESOLUTION_200_400: + return "200dpi x 400dpi"; + case T4_RESOLUTION_300_300: + return "300dpi x 300dpi"; + case T4_RESOLUTION_300_600: + return "300dpi x 600dpi"; + case T4_RESOLUTION_400_400: + return "400dpi x 400dpi"; + case T4_RESOLUTION_400_800: + return "400dpi x 800dpi"; + case T4_RESOLUTION_600_600: + return "600dpi x 600dpi"; + case T4_RESOLUTION_600_1200: + return "600dpi x 1200dpi"; + case T4_RESOLUTION_1200_1200: + return "1200dpi x 1200dpi"; + } + return "???"; +} +/*- End of function --------------------------------------------------------*/ + static int set_tiff_directory_info(t4_rx_state_t *s) { time_t now; @@ -175,6 +214,10 @@ static int set_tiff_directory_info(t4_rx_state_t *s) case T4_COMPRESSION_T6: output_compression = COMPRESSION_CCITT_T6; break; + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + output_compression = COMPRESSION_T85; + break; #if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_T42_T81: output_compression = COMPRESSION_JPEG; @@ -191,10 +234,6 @@ static int set_tiff_directory_info(t4_rx_state_t *s) photometric = PHOTOMETRIC_ITULAB; break; #endif - case T4_COMPRESSION_T85: - case T4_COMPRESSION_T85_L0: - output_compression = COMPRESSION_T85; - break; } TIFFSetField(t->tiff_file, TIFFTAG_COMPRESSION, output_compression); @@ -208,6 +247,9 @@ static int set_tiff_directory_info(t4_rx_state_t *s) TIFFSetField(t->tiff_file, TIFFTAG_T6OPTIONS, 0); TIFFSetField(t->tiff_file, TIFFTAG_FAXMODE, FAXMODE_CLASSF); break; + case COMPRESSION_T85: + TIFFSetField(t->tiff_file, TIFFTAG_FAXMODE, FAXMODE_CLASSF); + break; case COMPRESSION_JPEG: TIFFSetField(t->tiff_file, TIFFTAG_FAXMODE, FAXMODE_CLASSF); break; @@ -216,9 +258,6 @@ static int set_tiff_directory_info(t4_rx_state_t *s) TIFFSetField(t->tiff_file, TIFFTAG_FAXMODE, FAXMODE_CLASSF); break; #endif - case COMPRESSION_T85: - TIFFSetField(t->tiff_file, TIFFTAG_FAXMODE, FAXMODE_CLASSF); - break; } TIFFSetField(t->tiff_file, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(t->tiff_file, TIFFTAG_BITSPERSAMPLE, bits_per_sample); @@ -304,6 +343,10 @@ static int set_tiff_directory_info(t4_rx_state_t *s) case T4_COMPRESSION_T6: s->image_length = t4_t6_decode_get_image_length(&s->decoder.t4_t6); break; + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + s->image_length = t85_decode_get_image_length(&s->decoder.t85); + break; case T4_COMPRESSION_T42_T81: s->image_length = t42_decode_get_image_length(&s->decoder.t42); break; @@ -312,10 +355,6 @@ static int set_tiff_directory_info(t4_rx_state_t *s) s->image_length = t43_decode_get_image_length(&s->decoder.t43); break; #endif - case T4_COMPRESSION_T85: - case T4_COMPRESSION_T85_L0: - s->image_length = t85_decode_get_image_length(&s->decoder.t85); - break; } TIFFSetField(t->tiff_file, TIFFTAG_IMAGELENGTH, s->image_length); TIFFSetField(t->tiff_file, TIFFTAG_ROWSPERSTRIP, s->image_length); @@ -384,6 +423,7 @@ static int write_tiff_image(t4_rx_state_t *s) { case T4_COMPRESSION_T85: case T4_COMPRESSION_T85_L0: + /* We need to perform this compression here, as libtiff does not understand it. */ span_log(&s->logging, SPAN_LOG_WARNING, "%s: TODO need T.85 compression.\n", t->file); buf_len = 0; buf = NULL; @@ -417,6 +457,7 @@ static int write_tiff_image(t4_rx_state_t *s) break; #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_T43: + /* We need to perform this compression here, as libtiff does not understand it. */ span_log(&s->logging, SPAN_LOG_WARNING, "%s: TODO need T.43 compression.\n", t->file); buf_len = 0; buf = NULL; @@ -553,15 +594,15 @@ SPAN_DECLARE(int) t4_rx_put(t4_rx_state_t *s, const uint8_t buf[], size_t len) case T4_COMPRESSION_T4_2D: case T4_COMPRESSION_T6: return t4_t6_decode_put(&s->decoder.t4_t6, buf, len); + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + return t85_decode_put(&s->decoder.t85, buf, len); case T4_COMPRESSION_T42_T81: return t42_decode_put(&s->decoder.t42, buf, len); #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_T43: return t43_decode_put(&s->decoder.t43, buf, len); #endif - case T4_COMPRESSION_T85: - case T4_COMPRESSION_T85_L0: - return t85_decode_put(&s->decoder.t85, buf, len); } return T4_DECODE_OK; } @@ -628,6 +669,23 @@ SPAN_DECLARE(int) t4_rx_set_rx_encoding(t4_rx_state_t *s, int encoding) } s->line_encoding = encoding; return t4_t6_decode_set_encoding(&s->decoder.t4_t6, 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_decode_init(&s->decoder.t85, s->row_handler, s->row_handler_user_data); + /* Constrain received images to the maximum width of any FAX. This will + avoid one potential cause of trouble, where a bad received image has + a gigantic dimension that sucks our memory dry. */ + t85_decode_set_image_size_constraints(&s->decoder.t85, T4_WIDTH_1200_A3, 0); + break; + } + s->line_encoding = encoding; + return 0; case T4_COMPRESSION_T42_T81: switch (s->line_encoding) { @@ -660,23 +718,6 @@ SPAN_DECLARE(int) t4_rx_set_rx_encoding(t4_rx_state_t *s, int encoding) s->line_encoding = encoding; return 0; #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_decode_init(&s->decoder.t85, s->row_handler, s->row_handler_user_data); - /* Constrain received images to the maximum width of any FAX. This will - avoid one potential cause of trouble, where a bad received image has - a gigantic dimension that sucks our memory dry. */ - t85_decode_set_image_size_constraints(&s->decoder.t85, T4_WIDTH_1200_A3, 0); - break; - } - s->line_encoding = encoding; - return 0; } return -1; } @@ -698,15 +739,15 @@ SPAN_DECLARE(int) t4_rx_set_row_write_handler(t4_rx_state_t *s, t4_row_write_han case T4_COMPRESSION_T4_2D: case T4_COMPRESSION_T6: return t4_t6_decode_set_row_write_handler(&s->decoder.t4_t6, handler, user_data); + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + return t85_decode_set_row_write_handler(&s->decoder.t85, handler, user_data); case T4_COMPRESSION_T42_T81: return t42_decode_set_row_write_handler(&s->decoder.t42, handler, user_data); #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_T43: return t43_decode_set_row_write_handler(&s->decoder.t43, handler, user_data); #endif - case T4_COMPRESSION_T85: - case T4_COMPRESSION_T85_L0: - return t85_decode_set_row_write_handler(&s->decoder.t85, handler, user_data); } return -1; } @@ -717,6 +758,7 @@ SPAN_DECLARE(void) t4_rx_get_transfer_statistics(t4_rx_state_t *s, t4_stats_t *t memset(t, 0, sizeof(*t)); t->pages_transferred = s->current_page; t->pages_in_file = s->tiff.pages_in_file; + t->image_x_resolution = s->metadata.x_resolution; t->image_y_resolution = s->metadata.y_resolution; t->x_resolution = s->metadata.x_resolution; @@ -737,6 +779,16 @@ SPAN_DECLARE(void) t4_rx_get_transfer_statistics(t4_rx_state_t *s, t4_stats_t *t t->bad_rows = s->decoder.t4_t6.bad_rows; t->longest_bad_row_run = s->decoder.t4_t6.longest_bad_row_run; break; + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + t->type = T4_IMAGE_TYPE_BILEVEL; + t->width = t85_decode_get_image_width(&s->decoder.t85); + t->length = t85_decode_get_image_length(&s->decoder.t85); + t->image_type = t->type; + t->image_width = t->width; + t->image_length = t->length; + t->line_image_size = t85_decode_get_compressed_image_size(&s->decoder.t85)/8; + break; case T4_COMPRESSION_T42_T81: t->type = 0; t->width = t42_decode_get_image_width(&s->decoder.t42); @@ -757,16 +809,6 @@ SPAN_DECLARE(void) t4_rx_get_transfer_statistics(t4_rx_state_t *s, t4_stats_t *t t->line_image_size = t43_decode_get_compressed_image_size(&s->decoder.t43)/8; break; #endif - case T4_COMPRESSION_T85: - case T4_COMPRESSION_T85_L0: - t->type = T4_IMAGE_TYPE_BILEVEL; - t->width = t85_decode_get_image_width(&s->decoder.t85); - t->length = t85_decode_get_image_length(&s->decoder.t85); - t->image_type = t->type; - t->image_width = t->width; - t->image_length = t->length; - t->line_image_size = t85_decode_get_compressed_image_size(&s->decoder.t85)/8; - break; } } /*- End of function --------------------------------------------------------*/ @@ -782,6 +824,10 @@ SPAN_DECLARE(int) t4_rx_start_page(t4_rx_state_t *s) case T4_COMPRESSION_T6: t4_t6_decode_restart(&s->decoder.t4_t6, s->image_width); break; + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + t85_decode_restart(&s->decoder.t85); + break; case T4_COMPRESSION_T42_T81: t42_decode_restart(&s->decoder.t42); break; @@ -790,10 +836,6 @@ SPAN_DECLARE(int) t4_rx_start_page(t4_rx_state_t *s) t43_decode_restart(&s->decoder.t43); break; #endif - case T4_COMPRESSION_T85: - case T4_COMPRESSION_T85_L0: - t85_decode_restart(&s->decoder.t85); - break; } s->line_image_size = 0; s->tiff.image_size = 0; @@ -839,6 +881,11 @@ SPAN_DECLARE(int) t4_rx_end_page(t4_rx_state_t *s) t4_t6_decode_put(&s->decoder.t4_t6, NULL, 0); length = t4_t6_decode_get_image_length(&s->decoder.t4_t6); break; + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + t85_decode_put(&s->decoder.t85, NULL, 0); + length = t85_decode_get_image_length(&s->decoder.t85); + break; case T4_COMPRESSION_T42_T81: t42_decode_put(&s->decoder.t42, NULL, 0); length = t42_decode_get_image_length(&s->decoder.t42); @@ -849,11 +896,6 @@ SPAN_DECLARE(int) t4_rx_end_page(t4_rx_state_t *s) length = t43_decode_get_image_length(&s->decoder.t43); break; #endif - case T4_COMPRESSION_T85: - case T4_COMPRESSION_T85_L0: - t85_decode_put(&s->decoder.t85, NULL, 0); - length = t85_decode_get_image_length(&s->decoder.t85); - break; } if (length == 0) @@ -939,15 +981,15 @@ SPAN_DECLARE(int) t4_rx_release(t4_rx_state_t *s) case T4_COMPRESSION_T4_2D: case T4_COMPRESSION_T6: return t4_t6_decode_release(&s->decoder.t4_t6); + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + return t85_decode_release(&s->decoder.t85); case T4_COMPRESSION_T42_T81: return t42_decode_release(&s->decoder.t42); #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_T43: return t43_decode_release(&s->decoder.t43); #endif - case T4_COMPRESSION_T85: - case T4_COMPRESSION_T85_L0: - return t85_decode_release(&s->decoder.t85); } return -1; } diff --git a/libs/spandsp/src/t4_tx.c b/libs/spandsp/src/t4_tx.c index b547eefcdd..7c404f23c9 100644 --- a/libs/spandsp/src/t4_tx.c +++ b/libs/spandsp/src/t4_tx.c @@ -94,8 +94,58 @@ typedef struct int bit_mask; } t85_packer_t; +typedef struct +{ + float resolution; + int code; +} res_table_t; + static void t4_tx_set_image_length(t4_tx_state_t *s, int image_length); +static const res_table_t x_res_table[] = +{ + //{ 100.0f/CM_PER_INCH, T4_X_RESOLUTION_100}, + { 102.0f/CM_PER_INCH, T4_X_RESOLUTION_R4}, + //{ 200.0f/CM_PER_INCH, T4_X_RESOLUTION_200}, + { 204.0f/CM_PER_INCH, T4_X_RESOLUTION_R8}, + { 300.0f/CM_PER_INCH, T4_X_RESOLUTION_300}, + //{ 400.0f/CM_PER_INCH, T4_X_RESOLUTION_400}, + { 408.0f/CM_PER_INCH, T4_X_RESOLUTION_R16}, + { 600.0f/CM_PER_INCH, T4_X_RESOLUTION_600}, + { 800.0f/CM_PER_INCH, T4_X_RESOLUTION_800}, + {1200.0f/CM_PER_INCH, T4_X_RESOLUTION_1200}, + { -1.00f, -1} +}; + +static const res_table_t y_res_table[] = +{ + { 38.50f, T4_Y_RESOLUTION_STANDARD}, + //{ 100.0f/CM_PER_INCH, T4_Y_RESOLUTION_100}, + { 77.00f, T4_Y_RESOLUTION_FINE}, + //{ 200.0f/CM_PER_INCH, T4_Y_RESOLUTION_200}, + { 300.0f/CM_PER_INCH, T4_Y_RESOLUTION_300}, + { 154.00f, T4_Y_RESOLUTION_SUPERFINE}, + //{ 400.0f/CM_PER_INCH, T4_Y_RESOLUTION_400}, + { 600.0f/CM_PER_INCH, T4_Y_RESOLUTION_600}, + { 800.0f/CM_PER_INCH, T4_Y_RESOLUTION_800}, + {1200.0f/CM_PER_INCH, T4_Y_RESOLUTION_1200}, + { -1.00f, -1} +}; + +static const int resolution_map[10][10] = +{ + { 0, 0, 0, T4_RESOLUTION_R8_STANDARD, 0, 0, 0, 0, 0, 0}, + {T4_RESOLUTION_100_100, 0, T4_RESOLUTION_200_100, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, T4_RESOLUTION_R8_FINE, 0, 0, 0, 0, 0, 0}, + { 0, 0, T4_RESOLUTION_200_200, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, T4_RESOLUTION_300_300, 0, 0, 0, 0, 0}, + { 0, 0, 0, T4_RESOLUTION_R8_SUPERFINE, 0, 0, T4_RESOLUTION_R16_SUPERFINE, 0, 0, 0}, + { 0, 0, T4_RESOLUTION_200_400, 0, 0, T4_RESOLUTION_400_400, 0, 0, 0, 0}, + { 0, 0, 0, 0, T4_RESOLUTION_300_600, 0, 0, T4_RESOLUTION_600_600, 0, 0}, + { 0, 0, 0, 0, 0, T4_RESOLUTION_400_800, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, T4_RESOLUTION_600_1200, 0, T4_RESOLUTION_1200_1200}, +}; + #if defined(SPANDSP_SUPPORT_TIFF_FX) /* TIFF-FX related extensions to the tag set supported by libtiff */ @@ -163,15 +213,39 @@ SPAN_DECLARE(void) TIFF_FX_init(void) /*- End of function --------------------------------------------------------*/ #endif -static int test_resolution(int res_unit, float actual, float expected) +static int match_resolution(int res_unit, float actual, const res_table_t table[]) { + int i; + int best_entry; + float best_ratio; + float ratio; + + if (actual == 0.0f) + return -1; + if (res_unit == RESUNIT_INCH) - actual *= 1.0f/CM_PER_INCH; - return (expected*0.95f <= actual && actual <= expected*1.05f); + actual /= CM_PER_INCH; + best_ratio = 0.0f; + best_entry = -1; + for (i = 0; table[i].code > 0; i++) + { + if (actual > table[i].resolution) + ratio = table[i].resolution/actual; + else + ratio = actual/table[i].resolution; + if (ratio > best_ratio) + { + best_entry = i; + best_ratio = ratio; + } + } + if (best_ratio < 0.95f) + return -1; + return best_entry; } /*- End of function --------------------------------------------------------*/ -#if defined(SPANDSP_SUPPORT_TIFF_FX) +#if 0 //defined(SPANDSP_SUPPORT_TIFF_FX) static int read_colour_map(t4_tx_state_t *s, int bits_per_sample) { int i; @@ -220,36 +294,6 @@ static int read_colour_map(t4_tx_state_t *s, int bits_per_sample) static int get_tiff_directory_info(t4_tx_state_t *s) { - static const struct - { - float resolution; - int code; - } x_res_table[] = - { - { 102.0f/CM_PER_INCH, T4_X_RESOLUTION_R4}, - { 204.0f/CM_PER_INCH, T4_X_RESOLUTION_R8}, - { 300.0f/CM_PER_INCH, T4_X_RESOLUTION_300}, - { 408.0f/CM_PER_INCH, T4_X_RESOLUTION_R16}, - { 600.0f/CM_PER_INCH, T4_X_RESOLUTION_600}, - { 800.0f/CM_PER_INCH, T4_X_RESOLUTION_800}, - {1200.0f/CM_PER_INCH, T4_X_RESOLUTION_1200}, - { -1.00f, -1} - }; - static const struct - { - float resolution; - int code; - } y_res_table[] = - { - { 38.50f, T4_Y_RESOLUTION_STANDARD}, - { 77.00f, T4_Y_RESOLUTION_FINE}, - { 300.0f/CM_PER_INCH, T4_Y_RESOLUTION_300}, - { 154.00f, T4_Y_RESOLUTION_SUPERFINE}, - { 600.0f/CM_PER_INCH, T4_Y_RESOLUTION_600}, - { 800.0f/CM_PER_INCH, T4_Y_RESOLUTION_800}, - {1200.0f/CM_PER_INCH, T4_Y_RESOLUTION_1200}, - { -1.00f, -1} - }; #if defined(SPANDSP_SUPPORT_TIFF_FX) static const char *tiff_fx_fax_profiles[] = { @@ -265,12 +309,12 @@ static int get_tiff_directory_info(t4_tx_state_t *s) char uu[10]; uint64_t diroff; uint8_t parm8; - uint16_t parm16; #endif uint32_t parm32; + int best_x_entry; + int best_y_entry; float x_resolution; float y_resolution; - int i; t4_tx_tiff_state_t *t; uint16_t bits_per_sample; uint16_t samples_per_pixel; @@ -324,36 +368,24 @@ static int get_tiff_directory_info(t4_tx_state_t *s) TIFFGetField(t->tiff_file, TIFFTAG_COMPRESSION, &t->compression); t->fill_order = FILLORDER_LSB2MSB; - /* Allow a little range for the X resolution in centimeters. The spec doesn't pin down the - precise value. The other value should be exact. */ - /* Treat everything we can't match as R8. Most FAXes are this resolution anyway. */ - s->metadata.x_resolution = T4_X_RESOLUTION_R8; - for (i = 0; x_res_table[i].code > 0; i++) - { - if (test_resolution(res_unit, x_resolution, x_res_table[i].resolution)) - { - s->metadata.x_resolution = x_res_table[i].code; - break; - } - } if (res_unit == RESUNIT_INCH) t->image_x_resolution = x_resolution*100.0f/CM_PER_INCH; else t->image_x_resolution = x_resolution*100.0f; + /* Treat everything we can't match as R8. Most FAXes are this resolution anyway. */ + if ((best_x_entry = match_resolution(res_unit, x_resolution, x_res_table)) < 0) + best_x_entry = 3; + s->metadata.x_resolution = x_res_table[best_x_entry].code; - s->metadata.y_resolution = T4_Y_RESOLUTION_STANDARD; - for (i = 0; y_res_table[i].code > 0; i++) - { - if (test_resolution(res_unit, y_resolution, y_res_table[i].resolution)) - { - s->metadata.y_resolution = y_res_table[i].code; - break; - } - } if (res_unit == RESUNIT_INCH) t->image_y_resolution = y_resolution*100.0f/CM_PER_INCH; else t->image_y_resolution = y_resolution*100.0f; + if ((best_y_entry = match_resolution(res_unit, y_resolution, y_res_table)) < 0) + best_y_entry = 0; + s->metadata.y_resolution = y_res_table[best_y_entry].code; + + //s->metadata.resolution_code = resolution_map[best_y_entry][best_x_entry]; t4_tx_set_image_width(s, s->image_width); t4_tx_set_image_length(s, s->image_length); @@ -412,44 +444,15 @@ static int get_tiff_directory_info(t4_tx_state_t *s) static int test_tiff_directory_info(t4_tx_state_t *s) { - static const struct - { - float resolution; - int code; - } x_res_table[] = - { - { 102.0f/CM_PER_INCH, T4_X_RESOLUTION_R4}, - { 204.0f/CM_PER_INCH, T4_X_RESOLUTION_R8}, - { 300.0f/CM_PER_INCH, T4_X_RESOLUTION_300}, - { 408.0f/CM_PER_INCH, T4_X_RESOLUTION_R16}, - { 600.0f/CM_PER_INCH, T4_X_RESOLUTION_600}, - { 800.0f/CM_PER_INCH, T4_X_RESOLUTION_800}, - {1200.0f/CM_PER_INCH, T4_X_RESOLUTION_1200}, - { -1.00f, -1} - }; - static const struct - { - float resolution; - int code; - } y_res_table[] = - { - { 38.50f, T4_Y_RESOLUTION_STANDARD}, - { 77.00f, T4_Y_RESOLUTION_FINE}, - { 300.0f/CM_PER_INCH, T4_Y_RESOLUTION_300}, - { 154.00f, T4_Y_RESOLUTION_SUPERFINE}, - { 600.0f/CM_PER_INCH, T4_Y_RESOLUTION_600}, - { 800.0f/CM_PER_INCH, T4_Y_RESOLUTION_800}, - {1200.0f/CM_PER_INCH, T4_Y_RESOLUTION_1200}, - { -1.00f, -1} - }; uint16_t res_unit; uint32_t parm32; + 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; - int i; t4_tx_tiff_state_t *t; t = &s->tiff; @@ -490,23 +493,17 @@ static int test_tiff_directory_info(t4_tx_state_t *s) res_unit = RESUNIT_INCH; TIFFGetField(t->tiff_file, TIFFTAG_RESOLUTIONUNIT, &res_unit); - /* Allow a little range for the X resolution in centimeters. The spec doesn't pin down the - precise value. The other value should be exact. */ /* Treat everything we can't match as R8. Most FAXes are this resolution anyway. */ - for (i = 0; x_res_table[i].code > 0; i++) - { - if (test_resolution(res_unit, x_resolution, x_res_table[i].resolution)) - break; - } - if (s->metadata.x_resolution != x_res_table[i].code) + if ((best_x_entry = match_resolution(res_unit, x_resolution, x_res_table)) < 0) return 1; - for (i = 0; y_res_table[i].code > 0; i++) - { - if (test_resolution(res_unit, y_resolution, y_res_table[i].resolution)) - break; - } - if (s->metadata.y_resolution != y_res_table[i].code) + if (s->metadata.x_resolution != x_res_table[best_x_entry].code) return 1; + + if ((best_y_entry = match_resolution(res_unit, y_resolution, y_res_table)) < 0) + return 1; + if (s->metadata.y_resolution != y_res_table[best_y_entry].code) + return 1; + return 0; } /*- End of function --------------------------------------------------------*/