]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Fixed jaggies in image resizing.
authorSteve Underwood <steveu@haswell.coppice.org>
Wed, 21 Aug 2013 12:08:17 +0000 (20:08 +0800)
committerSteve Underwood <steveu@haswell.coppice.org>
Wed, 21 Aug 2013 12:08:17 +0000 (20:08 +0800)
Split naming of T.81/T.42 type JPEG from normal JPEG. This is in preparation
for allowing the selective output of normal JPEG (like most people want)
and the T.81/T.42 type you might want for forwarding as T.37

libs/spandsp/src/image_translate.c
libs/spandsp/src/spandsp/private/t42.h
libs/spandsp/src/spandsp/t4_rx.h
libs/spandsp/src/t30.c
libs/spandsp/src/t42.c
libs/spandsp/src/t4_rx.c
libs/spandsp/src/t4_tx.c
libs/spandsp/tests/fax_tests.c

index 442d188be5d92801b5b20c5c494dfd0c5c80a46a..4c6a5affb899b606328312dc66ecb6690e16dd50 100644 (file)
@@ -337,6 +337,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[])
     double int_part;
     double frac_row;
     double frac_col;
+    double width_scaling;
 #endif
     uint8_t *row8[2];
     uint16_t *row16[2];
@@ -352,17 +353,13 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[])
     input_width = s->input_width - 1;
     input_length = s->input_length - 1;
 
-    skip = s->raw_output_row*input_length/output_length;
+    skip = s->raw_output_row*input_length/output_length + 1;
     if (skip >= s->raw_input_row)
     {
-        skip++;
         while (skip >= s->raw_input_row)
         {
             if (s->raw_input_row >= s->input_length)
-            {
-                s->raw_output_row = -1;
                 break;
-            }
             row_len = get_and_scrunch_row(s, s->raw_pixel_row[0]);
             if (row_len != s->output_width)
             {
@@ -380,6 +377,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[])
     frac_row = ((s->raw_output_row*256*input_length)/output_length) & 0xFF;
 #else
     frac_row = modf((double) s->raw_output_row*input_length/output_length, &int_part);
+    width_scaling = (double) input_width/output_width;
 #endif
 
     switch (s->output_format)
@@ -402,7 +400,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[])
                 buf[3*i + j] = saturateu8(c1 + (((c2 - c1)*frac_row) >> 8));
             }
 #else
-            frac_col = modf((double) i*input_width/output_width, &int_part);
+            frac_col = modf(width_scaling*i, &int_part);
             x = 3*int_part;
             for (j = 0;  j < 3;  j++)
             {
@@ -431,7 +429,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[])
                 buf16[3*i + j] = saturateu16(c1 + (((c2 - c1)*frac_row) >> 8));
             }
 #else
-            frac_col = modf((double) i*input_width/output_width, &int_part);
+            frac_col = modf(width_scaling*i, &int_part);
             x = 3*int_part;
             for (j = 0;  j < 3;  j++)
             {
@@ -456,7 +454,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[])
             c2 = row8[1][x] + (((row8[1][x + 1] - row8[1][x])*frac_col) >> 8);
             buf[i] = saturateu8(c1 + (((c2 - c1)*frac_row) >> 8));
 #else
-            frac_col = modf((double) i*input_width/output_width, &int_part);
+            frac_col = modf(width_scaling*i, &int_part);
             x = int_part;
             c1 = row8[0][x] + (row8[0][x + 1] - row8[0][x])*frac_col;
             c2 = row8[1][x] + (row8[1][x + 1] - row8[1][x])*frac_col;
@@ -478,7 +476,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[])
             c2 = row16[1][x] + (((row16[1][x + 1] - row16[1][x])*frac_col) >> 8);
             buf[i] = saturateu8(c1 + (((c2 - c1)*frac_row) >> 8));
 #else
-            frac_col = modf((double) i*input_width/output_width, &int_part);
+            frac_col = modf(width_scaling*i, &int_part);
             x = int_part;
             c1 = row16[0][x] + (row16[0][x + 1] - row16[0][x])*frac_col;
             c2 = row16[1][x] + (row16[1][x + 1] - row16[1][x])*frac_col;
index 4c1de58ffaf12bdd401a679cc6756653f64bfdfd..e151afc6fcc78111a5054d7b9c24a7e1f102357c 100644 (file)
@@ -40,10 +40,13 @@ struct lab_params_s
     float offset_b;
     int ab_are_signed;
 
-    /* Illuminant */
+    /* Illuminant, forward and reverse */
     float x_n;
     float y_n;
     float z_n;
+    float x_rn;
+    float y_rn;
+    float z_rn;
 };
 
 /* State of a working instance of the T.42 JPEG FAX encoder */
index 0401d108235008313de9691fba4c0e28164d49b8..de6698517e4ac5ae669713851594dc7c4eafb871 100644 (file)
@@ -70,6 +70,12 @@ typedef enum
     T4_COMPRESSION_SYCC_T81 = 0x200,
     /*! T.88 monochrome JBIG2 compression */
     T4_COMPRESSION_T88 = 0x400,
+    /*! Uncompressed image. This compression cannot be used for FAXes. It is provided for specifying
+        output formats for received images. */
+    T4_COMPRESSION_UNCOMPRESSED = 0x1000,
+    /*! Conventional JPEG. This compression cannot be used for FAXes. It is provided for specifying
+        output formats for received images. */
+    T4_COMPRESSION_JPEG = 0x2000,
     /*! Support solour compression without sub-sampling */
     T4_COMPRESSION_NO_SUBSAMPLING = 0x800000,
     /*! Gray-scale support by multi-level codecs */
index 6074f5f5a1f6bb8edf8a1c1d7e118f6931878465..110b5b2e5dd819c4b93b3ae0d4bb0f6e7339de27 100644 (file)
@@ -6706,9 +6706,9 @@ SPAN_DECLARE(t30_state_t *) t30_init(t30_state_t *s,
                              | T4_SUPPORT_LENGTH_A4
                              | T4_SUPPORT_LENGTH_B4
                              | T4_SUPPORT_LENGTH_UNLIMITED;
-    /* Set the output encoding to something safe. Most things get 1D and 2D
-       encoding right. Quite a lot get other things wrong. */
-    s->supported_output_compressions = T4_COMPRESSION_T4_2D | T4_COMPRESSION_T42_T81;
+    /* Set the output encoding to something safe. For bi-level images ost things get
+       1D and 2D encoding right. Quite a lot get other things wrong. */
+    s->supported_output_compressions = T4_COMPRESSION_T4_2D | T4_COMPRESSION_JPEG;
     s->local_min_scan_time_code = T30_MIN_SCAN_0MS;
     span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
     span_log_set_protocol(&s->logging, "T.30");
index 6117cd3f19f931e08257b8a9ea86b3a46b141ecf..1469c389bef61f8e16824fa175d9da1d0560f050 100644 (file)
@@ -309,6 +309,9 @@ SPAN_DECLARE(void) set_lab_illuminant(lab_params_t *lab, float new_xn, float new
         lab->y_n = new_yn;
         lab->z_n = new_zn;
     }
+    lab->x_rn = 1.0f/lab->x_n;
+    lab->y_rn = 1.0f/lab->y_n;
+    lab->z_rn = 1.0f/lab->z_n;
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -475,9 +478,9 @@ SPAN_DECLARE(void) srgb_to_lab(lab_params_t *s, uint8_t lab[], const uint8_t srg
         z = 0.0193f*r + 0.1192f*g + 0.9505f*b;
 
         /* Normalise for the illuminant */
-        x /= s->x_n;
-        y /= s->y_n;
-        z /= s->z_n;
+        x *= s->x_rn;
+        y *= s->y_rn;
+        z *= s->z_rn;
 
         /* XYZ to Lab */
         xx = (x <= 0.008856f)  ?  (7.787f*x + 0.1379f)  :  cbrtf(x);
@@ -946,15 +949,16 @@ SPAN_DECLARE(int) t42_encode_restart(t42_encode_state_t *s, uint32_t image_width
     {
         /* ITU-YCC */
         /* Illuminant D65 */
-        set_lab_illuminant(&s->lab, 95.047f, 100.000f, 108.883f);
+        //set_lab_illuminant(&s->lab, 95.047f, 100.000f, 108.883f);
+        set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f);
         set_lab_gamut(&s->lab, 0, 100, -127, 127, -127, 127, false);
     }
     else
     {
         /* ITULAB */
         /* Illuminant D50 */
-        set_lab_illuminant(&s->lab, 96.422f, 100.000f,  82.521f);
-set_lab_illuminant(&s->lab, 95.047f, 100.000f, 108.883f);
+        //set_lab_illuminant(&s->lab, 96.422f, 100.000f,  82.521f);
+        set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f);
         set_lab_gamut(&s->lab, 0, 100, -85, 85, -75, 125, false);
     }
     s->compressed_image_size = 0;
@@ -1312,15 +1316,16 @@ SPAN_DECLARE(int) t42_decode_restart(t42_decode_state_t *s)
     {
         /* ITU-YCC */
         /* Illuminant D65 */
-        set_lab_illuminant(&s->lab, 95.047f, 100.000f, 108.883f);
+        //set_lab_illuminant(&s->lab, 95.047f, 100.000f, 108.883f);
+        set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f);
         set_lab_gamut(&s->lab, 0, 100, -127, 127, -127, 127, false);
     }
     else
     {
         /* ITULAB */
         /* Illuminant D50 */
-        set_lab_illuminant(&s->lab, 96.422f, 100.000f,  82.521f);
-set_lab_illuminant(&s->lab, 95.047f, 100.000f, 108.883f);
+        //set_lab_illuminant(&s->lab, 96.422f, 100.000f,  82.521f);
+        set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f);
         set_lab_gamut(&s->lab, 0, 100, -85, 85, -75, 125, false);
     }
 
index 1164814355a81382ab3a23bc80332044428171ac..141a6529e9eaf1319299d33610733b22471b856b 100644 (file)
@@ -123,6 +123,11 @@ SPAN_DECLARE(const char *) t4_compression_to_str(int compression)
         return "T.43";
     case T4_COMPRESSION_T45:
         return "T.45";
+    /* Compressions which can only be used in TIFF files */
+    case T4_COMPRESSION_UNCOMPRESSED:
+        return "Uncompressed";
+    case T4_COMPRESSION_JPEG:
+        return "JPEG";
     }
     return "???";
 }
@@ -238,13 +243,27 @@ static int set_tiff_directory_info(t4_rx_state_t *s)
         break;
 #endif
 #if defined(SPANDSP_SUPPORT_T42)
+    case T4_COMPRESSION_JPEG:
+        output_compression = COMPRESSION_JPEG;
+        bits_per_sample = 8;
+        if (t->image_type == T4_IMAGE_TYPE_COLOUR_8BIT)
+        {
+            samples_per_pixel = 3;
+            photometric = PHOTOMETRIC_YCBCR;
+        }
+        else
+        {
+            samples_per_pixel = 1;
+            photometric = PHOTOMETRIC_MINISBLACK;
+        }
+        break;
     case T4_COMPRESSION_T42_T81:
         output_compression = COMPRESSION_JPEG;
         bits_per_sample = 8;
         if (t->image_type == T4_IMAGE_TYPE_COLOUR_8BIT)
         {
             samples_per_pixel = 3;
-            photometric = PHOTOMETRIC_YCBCR; //PHOTOMETRIC_ITULAB;
+            photometric = PHOTOMETRIC_ITULAB;
         }
         else
         {
@@ -306,12 +325,20 @@ static int set_tiff_directory_info(t4_rx_state_t *s)
     TIFFSetField(t->tiff_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
     TIFFSetField(t->tiff_file, TIFFTAG_PHOTOMETRIC, photometric);
     TIFFSetField(t->tiff_file, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB);
-    if (t->compression == T4_COMPRESSION_T42_T81)
+    switch (t->compression)
     {
+    case T4_COMPRESSION_JPEG:
+        TIFFSetField(t->tiff_file, TIFFTAG_YCBCRSUBSAMPLING, 2, 2);
+        //TIFFSetField(t->tiff_file, TIFFTAG_YCBCRSUBSAMPLING, 1, 1);
+        TIFFSetField(t->tiff_file, TIFFTAG_JPEGQUALITY, 75);
+        TIFFSetField(t->tiff_file, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+        break;
+    case T4_COMPRESSION_T42_T81:
         TIFFSetField(t->tiff_file, TIFFTAG_YCBCRSUBSAMPLING, 2, 2);
         //TIFFSetField(t->tiff_file, TIFFTAG_YCBCRSUBSAMPLING, 1, 1);
         TIFFSetField(t->tiff_file, TIFFTAG_JPEGQUALITY, 75);
         TIFFSetField(t->tiff_file, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+        break;
     }
     /* TIFFTAG_STRIPBYTECOUNTS and TIFFTAG_STRIPOFFSETS are added automatically */
 
@@ -815,10 +842,14 @@ static void select_tiff_compression(t4_rx_state_t *s, int output_image_type)
     }
     else
     {
-        if ((s->supported_tiff_compressions & T4_COMPRESSION_T42_T81))
+        if ((s->supported_tiff_compressions & T4_COMPRESSION_JPEG))
+            s->tiff.compression = T4_COMPRESSION_JPEG;
+        else if ((s->supported_tiff_compressions & T4_COMPRESSION_T42_T81))
             s->tiff.compression = T4_COMPRESSION_T42_T81;
         else if ((s->supported_tiff_compressions & T4_COMPRESSION_T43))
             s->tiff.compression = T4_COMPRESSION_T43;
+        else if ((s->supported_tiff_compressions & T4_COMPRESSION_UNCOMPRESSED))
+            s->tiff.compression = T4_COMPRESSION_UNCOMPRESSED;
     }
     s->tiff.image_type = output_image_type;
 }
index 639ddc93dd280efd51a789bf93f167cf0280dc11..0c17b585f23e4a986c47dab2504704629938808b 100644 (file)
@@ -2009,6 +2009,8 @@ SPAN_DECLARE(int) t4_tx_set_tx_image_format(t4_tx_state_t *s,
         /* We can't rework a bilevel image that fits none of the patterns */
         if (s->tiff.image_type == T4_IMAGE_TYPE_BILEVEL)
             return T4_IMAGE_FORMAT_NORESSUPPORT;
+        if (!(supported_compressions & T4_COMPRESSION_RESCALING))
+            return T4_IMAGE_FORMAT_NORESSUPPORT;
         res = T4_IMAGE_FORMAT_OK;
         /* Any other kind of image might be resizable */
         s->metadata.image_width = T4_WIDTH_200_A4;
index 8e417adf9b9608ee9c53a5e8230c415bc415cf69..7cbe61fcfaada36c54035c39352f432a03f45503 100644 (file)
@@ -926,7 +926,7 @@ int main(int argc, char *argv[])
         {
             t30_set_supported_colour_resolutions(t30_state[i], 0);
         }
-        //t30_set_supported_output_compressions(t30_state[i], T4_COMPRESSION_T85);
+        t30_set_supported_output_compressions(t30_state[i], T4_COMPRESSION_T6 | T4_COMPRESSION_JPEG);
         t30_set_ecm_capability(t30_state[i], use_ecm);
         t30_set_supported_compressions(t30_state[i],
                                        T4_COMPRESSION_T4_1D