diff --git a/libs/spandsp/src/image_translate.c b/libs/spandsp/src/image_translate.c index 442d188be5..4c6a5affb8 100644 --- a/libs/spandsp/src/image_translate.c +++ b/libs/spandsp/src/image_translate.c @@ -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; diff --git a/libs/spandsp/src/spandsp/private/t42.h b/libs/spandsp/src/spandsp/private/t42.h index 4c1de58ffa..e151afc6fc 100644 --- a/libs/spandsp/src/spandsp/private/t42.h +++ b/libs/spandsp/src/spandsp/private/t42.h @@ -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 */ diff --git a/libs/spandsp/src/spandsp/t4_rx.h b/libs/spandsp/src/spandsp/t4_rx.h index 0401d10823..de6698517e 100644 --- a/libs/spandsp/src/spandsp/t4_rx.h +++ b/libs/spandsp/src/spandsp/t4_rx.h @@ -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 */ diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c index 6074f5f5a1..110b5b2e5d 100644 --- a/libs/spandsp/src/t30.c +++ b/libs/spandsp/src/t30.c @@ -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"); diff --git a/libs/spandsp/src/t42.c b/libs/spandsp/src/t42.c index 6117cd3f19..1469c389be 100644 --- a/libs/spandsp/src/t42.c +++ b/libs/spandsp/src/t42.c @@ -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); } diff --git a/libs/spandsp/src/t4_rx.c b/libs/spandsp/src/t4_rx.c index 1164814355..141a6529e9 100644 --- a/libs/spandsp/src/t4_rx.c +++ b/libs/spandsp/src/t4_rx.c @@ -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; } diff --git a/libs/spandsp/src/t4_tx.c b/libs/spandsp/src/t4_tx.c index 639ddc93dd..0c17b585f2 100644 --- a/libs/spandsp/src/t4_tx.c +++ b/libs/spandsp/src/t4_tx.c @@ -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; diff --git a/libs/spandsp/tests/fax_tests.c b/libs/spandsp/tests/fax_tests.c index 8e417adf9b..7cbe61fcfa 100644 --- a/libs/spandsp/tests/fax_tests.c +++ b/libs/spandsp/tests/fax_tests.c @@ -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