]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
More steps towards colour FAX
authorSteve Underwood <steveu@x100e.coppice.org>
Thu, 11 Apr 2013 10:08:32 +0000 (18:08 +0800)
committerSteve Underwood <steveu@x100e.coppice.org>
Thu, 11 Apr 2013 10:08:32 +0000 (18:08 +0800)
libs/spandsp/src/spandsp/private/t30.h
libs/spandsp/src/spandsp/private/t30_dis_dtc_dcs_bits.h
libs/spandsp/src/spandsp/private/t4_tx.h
libs/spandsp/src/spandsp/t4_rx.h
libs/spandsp/src/spandsp/t4_tx.h
libs/spandsp/src/t30.c
libs/spandsp/src/t30_api.c
libs/spandsp/src/t4_rx.c
libs/spandsp/src/t4_tx.c

index b0c32d5515c025a9a82d4c5fbde596e1afbbada0..c28feafed2f42535a391efe0fa8f5628c17a99b9 100644 (file)
@@ -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. */
index 5d6cf93adb18ff32611150a380095583bbf219b9..52e0ac8dd2d0f20dfac24997b8a4918c57d6a404 100644 (file)
 /* 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 */
 
index 39a21db48e803ce13ccf8dee7c5eec364abc9476..361ca888712259c3adb7bf57e5362fbd97952483 100644 (file)
@@ -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;
 
 /*!
index 4e2e57d14e671d8816665e39d74bf330cdc76ef2..6767f902d41e6670dbbf8b2875d7757cde70e4db 100644 (file)
@@ -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.
index 5b1989498d1378b13474a8cc5244dfce13cd51ad..bcf75d6c0251e22fbad4e7119557a97b8e740597 100644 (file)
@@ -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. */
index 7e235e0104538f54bafc407d375d78bbaede2c9e..8124ec5bbd33fd62f8b813ca4aeb7725a09799ea 100644 (file)
@@ -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);
-                bad = T30_ERR_OK;
-                break;
+                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_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_R8  &&  s->y_resolution == T4_Y_RESOLUTION_SUPERFINE)
             {
-                set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_400);
-                bad = T30_ERR_OK;
-                break;
+                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;
+                }
             }
-        }
-        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))
+            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)
             {
-                set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_400);
-                bad = T30_ERR_OK;
-                break;
+                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_SUPERFINE)
-        {
-            if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_R8_SUPERFINE))
+            else if (s->x_resolution == T4_X_RESOLUTION_R8  &&  s->y_resolution == T4_Y_RESOLUTION_FINE)
             {
-                set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_400);
-                bad = T30_ERR_OK;
-                break;
+                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 */
-    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))
+            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)
             {
-                set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_200);
+                /* No bits to set for this */
                 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))
+            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_200_200);
+                set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
                 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;
             }
         }
index 138d3f4debc1534a14211c3a4fd64f243ec821ea..0282dcc75b04586a4e9bc951a47f7dae23facb3a 100644 (file)
@@ -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;
 }
index 3c9a5f5e685f3d8337fe6ba4bc3781e490a67926..f2a2929fd1ff48ef9d4a7bc5cb78e48d0da9c2b1 100644 (file)
@@ -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,55 +669,55 @@ 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_T42_T81:
+    case T4_COMPRESSION_T85:
+    case T4_COMPRESSION_T85_L0:
         switch (s->line_encoding)
         {
-        case T4_COMPRESSION_T42_T81:
+        case T4_COMPRESSION_T85:
+        case T4_COMPRESSION_T85_L0:
             break;
         default:
-            t42_decode_init(&s->decoder.t42, s->row_handler, s->row_handler_user_data);
+            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. */
-            t42_decode_set_image_size_constraints(&s->decoder.t42, T4_WIDTH_1200_A3, 0);
+            t85_decode_set_image_size_constraints(&s->decoder.t85, T4_WIDTH_1200_A3, 0);
             break;
         }
         s->line_encoding = encoding;
         return 0;
-#if defined(SPANDSP_SUPPORT_T43)
-    case T4_COMPRESSION_T43:
+    case T4_COMPRESSION_T42_T81:
         switch (s->line_encoding)
         {
-        case T4_COMPRESSION_T43:
+        case T4_COMPRESSION_T42_T81:
             break;
         default:
-            t43_decode_init(&s->decoder.t43, s->row_handler, s->row_handler_user_data);
+            t42_decode_init(&s->decoder.t42, 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. */
-            t43_decode_set_image_size_constraints(&s->decoder.t43, T4_WIDTH_1200_A3, 0);
+            t42_decode_set_image_size_constraints(&s->decoder.t42, T4_WIDTH_1200_A3, 0);
             break;
         }
         s->line_encoding = encoding;
         return 0;
-#endif
-    case T4_COMPRESSION_T85:
-    case T4_COMPRESSION_T85_L0:
+#if defined(SPANDSP_SUPPORT_T43)
+    case T4_COMPRESSION_T43:
         switch (s->line_encoding)
         {
-        case T4_COMPRESSION_T85:
-        case T4_COMPRESSION_T85_L0:
+        case T4_COMPRESSION_T43:
             break;
         default:
-            t85_decode_init(&s->decoder.t85, s->row_handler, s->row_handler_user_data);
+            t43_decode_init(&s->decoder.t43, 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);
+            t43_decode_set_image_size_constraints(&s->decoder.t43, T4_WIDTH_1200_A3, 0);
             break;
         }
         s->line_encoding = encoding;
         return 0;
+#endif
     }
     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;
 }
index b547eefcdd4a6e7cb3c924a2dfc0e2feba6a7caa..7c404f23c9afb6f67de7e6c0fb8a12a752b03cf8 100644 (file)
@@ -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 --------------------------------------------------------*/