]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Addition of T.85 compression to the TIFF file.
authorSteve Underwood <steveu@coppice.org>
Thu, 4 Apr 2013 16:29:32 +0000 (00:29 +0800)
committerSteve Underwood <steveu@coppice.org>
Thu, 4 Apr 2013 16:29:32 +0000 (00:29 +0800)
libs/spandsp/src/spandsp/t30.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 7970051f73389efa865bab6c9eb9b8646a2cf6d4..dabedaa6e84f4cc458db3458b9e9d6743c4151df 100644 (file)
@@ -374,10 +374,20 @@ enum
     T30_SUPPORT_COMPRESSION_SYCC_T81 = 0x200,
     /*! T.88 monochrome JBIG2 compression */
     T30_SUPPORT_COMPRESSION_T88 = 0x400,
+    /*! Gray-scale support by multi-level codecs */
+    T30_SUPPORT_COMPRESSION_GRAYSCALE = 0x1000000,
+    /*! Colour support by multi-level codecs */
+    T30_SUPPORT_COMPRESSION_COLOUR = 0x2000000,
+    /*! 12 bit mode for gray scale and colour */
+    T30_SUPPORT_COMPRESSION_12BIT = 0x4000000,
+    /*! Convert a colour image to a gray-scale one */
+    T30_SUPPORT_COMPRESSION_COLOUR_TO_GRAY = 0x8000000,
     /*! Dither a gray scale image down a simple bilevel image, with rescaling to fit a FAX page */
     T30_SUPPORT_GRAY_TO_BILEVEL = 0x10000000,
     /*! Dither a colour image down a simple bilevel image, with rescaling to fit a FAX page */
-    T30_SUPPORT_COLOUR_TO_BILEVEL = 0x20000000
+    T30_SUPPORT_COLOUR_TO_BILEVEL = 0x20000000,
+    /*! Rescale an image (except a bi-level image) to fit a permitted FAX width when necessary */
+    T30_SUPPORT_COMPRESSION_RESCALING = 0x40000000
 };
 
 enum
index c8a16c3d9673e036ad81318e8e93b31bfdd60196..19b8868cce093cbd08ce7dcfe3bade327dac42a2 100644 (file)
@@ -1202,6 +1202,7 @@ int t30_build_dis_or_dtc(t30_state_t *s)
     {
         /* ECM allowed */
         set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_ECM_CAPABLE);
+
         /* Only offer the option of fancy compression schemes, if we are
            also offering the ECM option needed to support them. */
         if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_T6))
@@ -1215,6 +1216,9 @@ int t30_build_dis_or_dtc(t30_state_t *s)
                 set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE);
         }
 
+        if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_COLOUR))
+            set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_FULL_COLOUR_CAPABLE);
+
         if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_T42_T81))
             set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE);
         if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_T43))
@@ -1232,6 +1236,15 @@ int t30_build_dis_or_dtc(t30_state_t *s)
         }
         //if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_T89))
         //    set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T89_CAPABLE);
+
+        if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_12BIT))
+            set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_12BIT_CAPABLE);
+
+        //if ((s->supported_compressions & 30_SUPPORT_COMPRESSION_NO_SUBSAMPLING))
+        //    set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NO_SUBSAMPLING);
+
+        /* No custom illuminant */
+        /* No custom gamut range */
     }
     if ((s->supported_t30_features & T30_SUPPORT_FIELD_NOT_VALID))
         set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_FNV_CAPABLE);
@@ -1262,12 +1275,6 @@ int t30_build_dis_or_dtc(t30_state_t *s)
     /* No mode 26 (T.505) */
     /* No digital network capability */
     /* No duplex operation */
-    /* No JPEG */
-    /* No full colour */
-    /* No 12bits/pel */
-    /* No sub-sampling (1:1:1) */
-    /* No custom illuminant */
-    /* No custom gamut range */
     if ((s->supported_image_sizes & T30_SUPPORT_US_LETTER_LENGTH))
         set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LETTER_CAPABLE);
     if ((s->supported_image_sizes & T30_SUPPORT_US_LEGAL_LENGTH))
@@ -2329,7 +2336,6 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len)
             return -1;
         }
     }
-
     queue_phase(s, T30_PHASE_B_TX);
     /* Try to send something */
     if (s->tx_file[0])
@@ -2439,9 +2445,26 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len)
     s->y_resolution = -1;
     //s->current_page_resolution = 0;
     x = -1;
-    if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE))
+    if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T81_MODE)  ||  test_ctrl_bit(dcs_frame, T30_DCS_BIT_T43_MODE))
     {
         /* Gray scale or colour image */
+
+        /* Note 35 of Table 2/T.30 */
+        if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE))
+        {
+            /* We are going to work in full colour mode */
+        }
+
+        if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_12BIT_COMPONENT))
+        {
+            /* We are going to work in 12 bit mode */
+        }
+
+        if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_NO_SUBSAMPLING))
+        {
+            //???? = T30_SUPPORT_COMPRESSION_T42_T81_SUBSAMPLING;
+        }
+
         if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_COLOUR_GRAY_1200_1200))
         {
             if ((s->supported_colour_resolutions & T30_SUPPORT_RESOLUTION_1200_1200))
@@ -2664,7 +2687,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len)
 
     /* Check which compression the far end has decided to use. */
 #if defined(SPANDSP_SUPPORT_T42)
-    if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE))
+    if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T81_MODE))
     {
         s->line_encoding = T4_COMPRESSION_T42_T81;
     }
@@ -3905,6 +3928,7 @@ static void process_state_r(t30_state_t *s, const uint8_t *msg, int len)
         process_rx_dcs(s, msg, len);
         break;
     case T30_DCN:
+        /* Received a DCN while waiting for a DIS or DCN */
         t30_set_status(s, T30_ERR_RX_DCNWHY);
         disconnect(s);
         break;
index e5326d926e622f829f8ac18045f93b8f8eeacea0..3a60ac80dc2e2fec403018bdbb1fe7d21f997db5 100644 (file)
@@ -697,12 +697,12 @@ SPAN_DECLARE(int) t30_set_supported_compressions(t30_state_t *s, int supported_c
     supported_compressions &= T30_SUPPORT_COMPRESSION_T4_1D
                             | T30_SUPPORT_COMPRESSION_T4_2D
                             | T30_SUPPORT_COMPRESSION_T6
+                            | T30_SUPPORT_COMPRESSION_T85
+                            | T30_SUPPORT_COMPRESSION_T85_L0
                             //| T30_SUPPORT_COMPRESSION_T81
 #if defined(SPANDSP_SUPPORT_T43)
                             | T30_SUPPORT_COMPRESSION_T43
 #endif
-                            | T30_SUPPORT_COMPRESSION_T85
-                            | T30_SUPPORT_COMPRESSION_T85_L0
                             | 0;
     s->supported_compressions = supported_compressions;
     t30_build_dis_or_dtc(s);
@@ -712,6 +712,23 @@ SPAN_DECLARE(int) t30_set_supported_compressions(t30_state_t *s, int supported_c
 
 SPAN_DECLARE(int) t30_set_supported_bilevel_resolutions(t30_state_t *s, int supported_resolutions)
 {
+    supported_resolutions &= T4_RESOLUTION_R8_STANDARD
+                           | T4_RESOLUTION_R8_FINE
+                           | T4_RESOLUTION_R8_SUPERFINE
+                           | T4_RESOLUTION_R16_SUPERFINE
+                           | T4_RESOLUTION_200_100
+                           | T4_RESOLUTION_200_200
+                           | T4_RESOLUTION_200_400
+                           | T4_RESOLUTION_300_300
+                           | T4_RESOLUTION_300_600
+                           | T4_RESOLUTION_400_400
+                           | T4_RESOLUTION_400_800
+                           | T4_RESOLUTION_600_600
+                           | T4_RESOLUTION_600_1200
+                           | T4_RESOLUTION_1200_1200;
+    /* Make sure anything needed for colour is enabled as a bi-level image, as that is a
+       rule from T.30. 100x100 is an exception, as it doesn't exist as a bi-level resolution. */
+    supported_resolutions |= (s->supported_colour_resolutions & ~T4_RESOLUTION_100_100);
     s->supported_bilevel_resolutions = supported_resolutions;
     t30_build_dis_or_dtc(s);
     return 0;
@@ -720,7 +737,16 @@ SPAN_DECLARE(int) t30_set_supported_bilevel_resolutions(t30_state_t *s, int supp
 
 SPAN_DECLARE(int) t30_set_supported_colour_resolutions(t30_state_t *s, int supported_resolutions)
 {
+    supported_resolutions &= T4_RESOLUTION_100_100
+                           | T4_RESOLUTION_200_200
+                           | T4_RESOLUTION_300_300
+                           | T4_RESOLUTION_400_400
+                           | T4_RESOLUTION_600_600
+                           | T4_RESOLUTION_1200_1200;
     s->supported_colour_resolutions = supported_resolutions;
+    /* Make sure anything needed for colour is enabled as a bi-level image, as that is a
+       rule from T.30. 100x100 is an exception, as it doesn't exist as a bi-level resolution. */
+    s->supported_bilevel_resolutions |= (s->supported_colour_resolutions & ~T4_RESOLUTION_100_100);
     t30_build_dis_or_dtc(s);
     return 0;
 }
index 4e0e37a19be197a0d67e098ef15014c51bd5fad5..3c9a5f5e685f3d8337fe6ba4bc3781e490a67926 100644 (file)
 /*! The number of centimetres in one inch */
 #define CM_PER_INCH                 2.54f
 
+typedef struct
+{
+    uint8_t *buf;
+    int ptr;
+} packer_t;
+
 #if defined(SPANDSP_SUPPORT_TIFF_FX)
 extern TIFFFieldArray tiff_fx_field_array;
 #endif
@@ -336,9 +342,30 @@ static int open_tiff_output_file(t4_rx_state_t *s, const char *file)
 }
 /*- End of function --------------------------------------------------------*/
 
+static int row_read_handler(void *user_data, uint8_t row[], size_t len)
+{
+    packer_t *s;
+
+    s = (packer_t *) user_data;
+    memcpy(row, &s->buf[s->ptr], len);
+    s->ptr += len;
+    return len;
+}
+/*- End of function --------------------------------------------------------*/
+
 static int write_tiff_image(t4_rx_state_t *s)
 {
     t4_rx_tiff_state_t *t;
+    uint8_t *buf;
+    uint8_t *buf2;
+    int buf_len;
+    int len;
+    int len2;
+    t85_encode_state_t t85;
+#if defined(SPANDSP_SUPPORT_T43)
+    t43_encode_state_t t43;
+#endif
+    packer_t packer;
 #if defined(SPANDSP_SUPPORT_TIFF_FX)
     uint64_t offset;
 #endif
@@ -353,8 +380,79 @@ static int write_tiff_image(t4_rx_state_t *s)
     if (!TIFFCheckpointDirectory(t->tiff_file))
         span_log(&s->logging, SPAN_LOG_WARNING, "%s: Failed to checkpoint directory for page %d.\n", t->file, s->current_page);
     /* ...and write out the image... */
-    if (TIFFWriteEncodedStrip(t->tiff_file, 0, t->image_buffer, t->image_size) < 0)
-        span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", t->file);
+    switch (t->output_encoding)
+    {
+    case T4_COMPRESSION_T85:
+    case T4_COMPRESSION_T85_L0:
+        span_log(&s->logging, SPAN_LOG_WARNING, "%s: TODO need T.85 compression.\n", t->file);
+        buf_len = 0;
+        buf = NULL;
+        packer.buf = t->image_buffer;
+        packer.ptr = 0;
+        t85_encode_init(&t85, s->image_width, s->image_length, row_read_handler, &packer);
+        //if (t->output_encoding == T4_COMPRESSION_T85_L0)
+        //    t85_encode_set_options(&t85, 256, -1, -1);
+        len2 = 0;
+        do
+        {
+            if (buf_len < len2 + 50000)
+            {
+                buf_len += 50000;
+                if ((buf2 = realloc(buf, buf_len)) == NULL)
+                {
+                    if (buf)
+                        free(buf);
+                    return -1;
+                }
+                buf = buf2;
+            }
+            len = t85_encode_get(&t85, &buf[len2], 50000);
+            len2 += len;
+        }
+        while (len > 0);
+        if (TIFFWriteRawStrip(t->tiff_file, 0, buf, len2) < 0)
+            span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", t->file);
+        t85_encode_release(&t85);
+        free(buf);
+        break;
+#if defined(SPANDSP_SUPPORT_T43)
+    case T4_COMPRESSION_T43:
+        span_log(&s->logging, SPAN_LOG_WARNING, "%s: TODO need T.43 compression.\n", t->file);
+        buf_len = 0;
+        buf = NULL;
+        packer.buf = t->image_buffer;
+        packer.ptr = 0;
+        t43_encode_init(&t43, s->image_width, s->image_length, row_read_handler, &packer);
+        len2 = 0;
+        do
+        {
+            if (buf_len < len2 + 50000)
+            {
+                buf_len += 50000;
+                if ((buf2 = realloc(buf, buf_len)) == NULL)
+                {
+                    if (buf)
+                        free(buf);
+                    return -1;
+                }
+                buf = buf2;
+            }
+            len = t43_encode_get(&t43, &buf[len2], 50000);
+            len2 += len;
+        }
+        while (len > 0);
+        if (TIFFWriteRawStrip(t->tiff_file, 0, buf, len2) < 0)
+            span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", t->file);
+        t43_encode_release(&t43);
+        free(buf);
+        break;
+#endif
+    default:
+        /* Let libtiff do the compression */
+        if (TIFFWriteEncodedStrip(t->tiff_file, 0, t->image_buffer, t->image_size) < 0)
+            span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", t->file);
+        break;
+    }
     /* ...then finalise the directory entry, and libtiff is happy. */
     if (!TIFFWriteDirectory(t->tiff_file))
         span_log(&s->logging, SPAN_LOG_WARNING, "%s: Failed to write directory for page %d.\n", t->file, s->current_page);
@@ -365,7 +463,9 @@ static int write_tiff_image(t4_rx_state_t *s)
         {
             TIFFSetField(t->tiff_file, TIFFTAG_FAXPROFILE, PROFILETYPE_G3_FAX);
             TIFFSetField(t->tiff_file, TIFFTAG_PROFILETYPE, FAXPROFILE_F);
+            TIFFSetField(t->tiff_file, TIFFTAG_CODINGMETHODS, CODINGMETHODS_T4_1D | CODINGMETHODS_T4_2D | CODINGMETHODS_T6);
             TIFFSetField(t->tiff_file, TIFFTAG_VERSIONYEAR, "1998");
+            TIFFSetField(t->tiff_file, TIFFTAG_MODENUMBER, 3);
 
             offset = 0;
             if (!TIFFWriteCustomDirectory(t->tiff_file, &offset))
index 3bb2a03932d0bd392acdfec400e12a991f792a55..a308f53435b1ff2d05ec61024b995b1d46a62521 100644 (file)
 /*! The number of centimetres in one inch */
 #define CM_PER_INCH                 2.54f
 
+typedef struct
+{
+    uint8_t *buf;
+    int ptr;
+    int row;
+    int bit_mask;
+} t85_packer_t;
+
 static void t4_tx_set_image_length(t4_tx_state_t *s, int image_length);
 
 #if defined(SPANDSP_SUPPORT_TIFF_FX)
 /* TIFF-FX related extensions to the tag set supported by libtiff */
+
 static const TIFFFieldInfo tiff_fx_tiff_field_info[] =
 {
     {TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, FIELD_CUSTOM, FALSE, FALSE, (char *) "Indexed"},
@@ -106,6 +115,7 @@ static const TIFFFieldInfo tiff_fx_tiff_field_info[] =
     {TIFFTAG_IMAGELAYER, 2, 2, TIFF_LONG, FIELD_CUSTOM, FALSE, FALSE, (char *) "ImageLayer"},
 };
 
+#if 1
 static TIFFField tiff_fx_tiff_fields[] =
 {
     { TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "Indexed" },
@@ -123,6 +133,7 @@ static TIFFField tiff_fx_tiff_fields[] =
 };
 
 TIFFFieldArray tiff_fx_field_array = { tfiatOther, 0, 12, tiff_fx_tiff_fields };
+#endif
 
 static TIFFExtendProc _ParentExtender = NULL;
 
@@ -177,12 +188,13 @@ static int read_colour_map(t4_tx_state_t *s, int bits_per_sample)
         return -1;
 
     /* TODO: This only allows for 8 bit deep maps */
-    if ((s->colour_map = realloc(s->colour_map, 3*256)) == NULL)
-        return -1;
     span_log(&s->logging, SPAN_LOG_FLOW, "Got a colour map\n");
+    s->colour_map_entries = 1 << bits_per_sample;
+    if ((s->colour_map = realloc(s->colour_map, 3*s->colour_map_entries)) == NULL)
+        return -1;
 #if 0
     /* Sweep the colormap in the proper order */
-    for (i = 0;  i < (1 << bits_per_sample);  i++)
+    for (i = 0;  i < s->colour_map_entries;  i++)
     {
         s->colour_map[3*i + 0] = (map_L[i] >> 8) & 0xFF;
         s->colour_map[3*i + 1] = (map_a[i] >> 8) & 0xFF;
@@ -191,15 +203,15 @@ static int read_colour_map(t4_tx_state_t *s, int bits_per_sample)
     }
 #else
     /* Sweep the colormap in the order that seems to work for l04x_02x.tif */
-    for (i = 0;  i < (1 << bits_per_sample);  i++)
+    for (i = 0;  i < s->colour_map_entries;  i++)
     {
-        s->colour_map[0*256 + i] = (map_L[i] >> 8) & 0xFF;
-        s->colour_map[1*256 + i] = (map_a[i] >> 8) & 0xFF;
-        s->colour_map[2*256 + i] = (map_b[i] >> 8) & 0xFF;
+        s->colour_map[0*s->colour_map_entries + i] = (map_L[i] >> 8) & 0xFF;
+        s->colour_map[1*s->colour_map_entries + i] = (map_a[i] >> 8) & 0xFF;
+        s->colour_map[2*s->colour_map_entries + i] = (map_b[i] >> 8) & 0xFF;
     }
 #endif
     lab_to_srgb(&s->lab_params, s->colour_map, s->colour_map, 256);
-    for (i = 0;  i < (1 << bits_per_sample);  i++)
+    for (i = 0;  i < s->colour_map_entries;  i++)
         span_log(&s->logging, SPAN_LOG_FLOW, "Map %3d - %5d %5d %5d\n", i, s->colour_map[3*i], s->colour_map[3*i + 1], s->colour_map[3*i + 2]);
     return 0;
 }