From e523076274847c1282b42150eee56d6ccf7fb2b9 Mon Sep 17 00:00:00 2001 From: Steve Underwood Date: Sat, 4 Aug 2012 03:45:09 +0800 Subject: [PATCH] FAX T.6 decompression fixed for images with black in the last pixel of lines. Colour and grey images can down be dithered down to bi-level images for transmission as faxes. More movement towards T.42 support --- libs/spandsp/src/Makefile.am | 13 + libs/spandsp/src/cielab_luts.h | 39 +- libs/spandsp/src/fax.c | 2 + libs/spandsp/src/image_translate.c | 39 +- libs/spandsp/src/make_cielab_luts.c | 92 ++++ libs/spandsp/src/spandsp/image_translate.h | 9 +- libs/spandsp/src/spandsp/private/t42.h | 11 + libs/spandsp/src/spandsp/private/t4_tx.h | 8 + libs/spandsp/src/spandsp/private/t85.h | 4 +- libs/spandsp/src/spandsp/t42.h | 14 +- libs/spandsp/src/spandsp/t4_rx.h | 17 + libs/spandsp/src/spandsp/t85.h | 18 - libs/spandsp/src/t30.c | 98 ++-- libs/spandsp/src/t30_api.c | 4 +- libs/spandsp/src/t30_logging.c | 2 + libs/spandsp/src/t38_gateway.c | 2 + libs/spandsp/src/t38_terminal.c | 2 + libs/spandsp/src/t42.c | 532 +++++++++++++++------ libs/spandsp/src/t42_t43_local.h | 44 ++ libs/spandsp/src/t4_rx.c | 6 +- libs/spandsp/src/t4_t6_decode.c | 11 +- libs/spandsp/src/t4_t6_encode.c | 18 + libs/spandsp/src/t4_tx.c | 139 ++++-- libs/spandsp/src/t85_decode.c | 60 +-- libs/spandsp/tests/image_translate_tests.c | 42 +- libs/spandsp/tests/t42_tests.c | 85 +--- libs/spandsp/tests/t4_t6_tests.c | 31 +- libs/spandsp/tests/t4_tests.c | 8 +- libs/spandsp/tests/t85_tests.c | 12 +- 29 files changed, 916 insertions(+), 446 deletions(-) create mode 100644 libs/spandsp/src/make_cielab_luts.c create mode 100644 libs/spandsp/src/t42_t43_local.h diff --git a/libs/spandsp/src/Makefile.am b/libs/spandsp/src/Makefile.am index 685e3d9328..95e9932c3c 100644 --- a/libs/spandsp/src/Makefile.am +++ b/libs/spandsp/src/Makefile.am @@ -20,6 +20,7 @@ AM_CFLAGS = $(COMP_VENDOR_CFLAGS) AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS) DISTCLEANFILES = $(srcdir)/at_interpreter_dictionary.h \ + $(srcdir)/cielab_luts.h \ $(srcdir)/math_fixed_tables.h \ $(srcdir)/v17_v32bis_rx_fixed_rrc.h \ $(srcdir)/v17_v32bis_rx_floating_rrc.h \ @@ -58,6 +59,7 @@ EXTRA_DIST = floating_fudge.h \ libtiff.2008.vcproj \ filter_tools.c \ make_at_dictionary.c \ + make_cielab_luts.c \ make_math_fixed_tables.c \ make_modem_filter.c \ msvc/config.h \ @@ -344,6 +346,7 @@ noinst_HEADERS = cielab_luts.h \ mmx_sse_decs.h \ t30_local.h \ t4_t6_decode_states.h \ + t42_t43_local.h \ v17_v32bis_rx_constellation_maps.h \ v17_v32bis_tx_constellation_maps.h \ v29tx_constellation_maps.h @@ -351,6 +354,9 @@ noinst_HEADERS = cielab_luts.h \ make_at_dictionary$(EXEEXT): $(top_srcdir)/src/make_at_dictionary.c $(CC_FOR_BUILD) -o make_at_dictionary$(EXEEXT) $(top_srcdir)/src/make_at_dictionary.c -DHAVE_CONFIG_H -I$(top_builddir)/src +make_cielab_luts$(EXEEXT): $(top_srcdir)/src/make_cielab_luts.c + $(CC_FOR_BUILD) -o make_cielab_luts$(EXEEXT) $(top_srcdir)/src/make_cielab_luts.c -DHAVE_CONFIG_H -I$(top_builddir)/src -lm + make_math_fixed_tables$(EXEEXT): $(top_srcdir)/src/make_math_fixed_tables.c $(CC_FOR_BUILD) -o make_math_fixed_tables$(EXEEXT) $(top_srcdir)/src/make_math_fixed_tables.c -DHAVE_CONFIG_H -I$(top_builddir)/src -lm @@ -378,6 +384,13 @@ t4_rx.$(OBJEXT): spandsp/version.h t4_rx.lo: spandsp/version.h +t42.$(OBJEXT): cielab_luts.h + +t42.lo: cielab_luts.h + +cielab_luts.h: make_cielab_luts$(EXEEXT) + ./make_cielab_luts$(EXEEXT) >cielab_luts.h + V17_V32BIS_RX_INCL = v17_v32bis_rx_fixed_rrc.h \ v17_v32bis_rx_floating_rrc.h diff --git a/libs/spandsp/src/cielab_luts.h b/libs/spandsp/src/cielab_luts.h index 73e72ac824..0a3c697915 100644 --- a/libs/spandsp/src/cielab_luts.h +++ b/libs/spandsp/src/cielab_luts.h @@ -1,32 +1,4 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * cielab_luts.h - * - * Written by Steve Underwood - * - * Copyright (C) 2011 Steve Underwood - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 2.1, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/*! \file */ - -#if defined(T42_USE_LUTS) -static const float sRGB_to_linear[256] = +static const float srgb_to_linear[256] = { 0.000000, 0.000302, @@ -168,7 +140,7 @@ static const float sRGB_to_linear[256] = 0.248036, 0.251995, 0.255990, - 0.260021, + 0.260022, 0.264090, 0.268196, 0.272338, @@ -267,7 +239,7 @@ static const float sRGB_to_linear[256] = 0.831396, 0.839397, 0.847443, - 0.855533, + 0.855534, 0.863669, 0.871850, 0.880075, @@ -285,8 +257,7 @@ static const float sRGB_to_linear[256] = 0.982319, 0.991137 }; - -static const uint8_t linear_to_sRGB[4096] = +static const uint8_t linear_to_srgb[4096] = { 0, 0, @@ -4385,5 +4356,3 @@ static const uint8_t linear_to_sRGB[4096] = 255, 255 }; -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/fax.c b/libs/spandsp/src/fax.c index abe25675ce..19bf4cf5e6 100644 --- a/libs/spandsp/src/fax.c +++ b/libs/spandsp/src/fax.c @@ -74,6 +74,7 @@ #include "spandsp/timezone.h" #include "spandsp/t4_rx.h" #include "spandsp/t4_tx.h" +#include "spandsp/image_translate.h" #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #if defined(SPANDSP_SUPPORT_T42) @@ -118,6 +119,7 @@ #endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" +#include "spandsp/private/image_translate.h" #include "spandsp/private/t4_rx.h" #include "spandsp/private/t4_tx.h" #include "spandsp/private/t30.h" diff --git a/libs/spandsp/src/image_translate.c b/libs/spandsp/src/image_translate.c index d21b5b9d81..db6a7adc0e 100644 --- a/libs/spandsp/src/image_translate.c +++ b/libs/spandsp/src/image_translate.c @@ -80,9 +80,9 @@ #endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" +#include "spandsp/private/image_translate.h" #include "spandsp/private/t4_rx.h" #include "spandsp/private/t4_tx.h" -#include "spandsp/private/image_translate.h" static int image_colour16_to_gray8_row(uint8_t mono[], uint16_t colour[], int pixels) { @@ -154,12 +154,14 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[], size_t le int input_width; int input_length; int x; - double c1; - double c2; #if defined(SPANDSP_USE_FIXED_POINT) + int c1; + int c2; int frac_row; int frac_col; #else + double c1; + double c2; double int_part; double frac_row; double frac_col; @@ -200,15 +202,15 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[], size_t le } #if defined(SPANDSP_USE_FIXED_POINT) - frac_row = s->raw_output_row*input_length/output_length; - frac_row = s->raw_output_row*input_length - frac_row*output_length; + frac_row = ((s->raw_output_row*256*input_length)/output_length) & 0xFF; for (i = 0; i < output_width; i++) { - x = i*input_width/output_width; - frac_col = x - x*output_width; - c1 = s->raw_pixel_row[0][x] + (s->raw_pixel_row[0][x + 1] - s->raw_pixel_row[0][x])*frac_col; - c2 = s->raw_pixel_row[1][x] + (s->raw_pixel_row[1][x + 1] - s->raw_pixel_row[1][x])*frac_col; - buf[i] = saturateu8(c1 + (c2 - c1)*frac_row); + x = i*256*input_width/output_width; + frac_col = x & 0xFF; + x >>= 8; + c1 = s->raw_pixel_row[0][x] + (((s->raw_pixel_row[0][x + 1] - s->raw_pixel_row[0][x])*frac_col) >> 8); + c2 = s->raw_pixel_row[1][x] + (((s->raw_pixel_row[1][x + 1] - s->raw_pixel_row[1][x])*frac_col) >> 8); + buf[i] = saturateu8(c1 + (((c2 - c1)*frac_row) >> 8)); } #else frac_row = modf((double) s->raw_output_row*input_length/output_length, &int_part); @@ -368,6 +370,7 @@ SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_sta int input_width, int input_length, int output_width, + int output_length, t4_row_read_handler_t row_read_handler, void *row_read_user_data) { @@ -385,9 +388,19 @@ SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_sta s->input_width = input_width; s->input_length = input_length; - s->resize = (output_width > 0); - s->output_width = (s->resize) ? output_width : s->input_width; - s->output_length = (s->resize) ? s->input_length*s->output_width/s->input_width : s->input_length; + if ((s->resize = (output_width > 0))) + { + s->output_width = output_width; + if (output_length > 0) + s->output_length = output_length; + else + s->output_length = (s->input_length*s->output_width)/s->input_width; + } + else + { + s->output_width = s->input_width; + s->output_length = s->input_length; + } switch (s->input_format) { diff --git a/libs/spandsp/src/make_cielab_luts.c b/libs/spandsp/src/make_cielab_luts.c new file mode 100644 index 0000000000..905005674f --- /dev/null +++ b/libs/spandsp/src/make_cielab_luts.c @@ -0,0 +1,92 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * make_cielab_luts.c - Create the look up tables for CIELab colour management + * + * Written by Steve Underwood + * + * Copyright (C) 2011 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/*! \file */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif + +typedef struct +{ + float L; + float a; + float b; +} cielab_t; + +int main(int argc, char *argv[]) +{ + float r; + uint8_t srgb; + int i; + + printf("static const float srgb_to_linear[256] =\n"); + printf("{\n"); + for (i = 0; i < 256; i++) + { + /* Start with "i" as the sRGB value */ + r = i/256.0f; + + /* sRGB to Linear RGB */ + r = (r > 0.04045f) ? powf((r + 0.055f)/1.055f, 2.4f) : r/12.92f; + + printf((i < 255) ? " %f,\n" : " %f\n", r); + } + printf("};\n"); + + printf("static const uint8_t linear_to_srgb[4096] =\n"); + printf("{\n"); + for (i = 0; i < 4096; i++) + { + /* Start with "i" as the linear RGB value */ + /* Linear RGB to sRGB */ + r = i/4096.0f; + + r = (r > 0.0031308f) ? (1.055f*powf(r, 1.0f/2.4f) - 0.055f) : r*12.92f; + + r = floorf(r*256.0f); + + srgb = (r < 0) ? 0 : (r <= 255) ? r : 255; + + printf((i < 4095) ? " %d,\n" : " %d\n", srgb); + } + printf("};\n"); + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/image_translate.h b/libs/spandsp/src/spandsp/image_translate.h index b795c705af..80f29f0471 100644 --- a/libs/spandsp/src/spandsp/image_translate.h +++ b/libs/spandsp/src/spandsp/image_translate.h @@ -75,9 +75,11 @@ SPAN_DECLARE(int) image_translate_get_output_length(image_translate_state_t *s); \param input_format x \param input_width The width of the source image, in pixels. \param input_length The length of the source image, in pixels. - \param output_width The width of the output image, in pixels. The length of the output image - will be derived automatically from this and the source image dimension, to main the - geometry of the original image. + \param output_width The width of the output image, in pixels. If this is set <= 0 the image + will not be resized. + \param output_length The length of the output image, in pixels. If this is set to <= 0 the + output length will be derived automatically from the width, to maintain the geometry + of the original image. \param row_read_handler A callback routine used to pull rows of pixels from the source image into the translation process. \param row_read_user_data An opaque point passed to read_row_handler @@ -87,6 +89,7 @@ SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_sta int input_width, int input_length, int output_width, + int output_length, t4_row_read_handler_t row_read_handler, void *row_read_user_data); diff --git a/libs/spandsp/src/spandsp/private/t42.h b/libs/spandsp/src/spandsp/private/t42.h index 7dedfa7ee1..bfdae884eb 100644 --- a/libs/spandsp/src/spandsp/private/t42.h +++ b/libs/spandsp/src/spandsp/private/t42.h @@ -53,6 +53,9 @@ struct t42_encode_state_s lab_params_t lab_params; + /*! \brief The size of the compressed image, in bytes. */ + int compressed_image_size; + /*! \brief Error and flow logging control */ logging_state_t logging; }; @@ -68,6 +71,8 @@ struct t42_decode_state_s t4_row_write_handler_t comment_handler; /*! An opaque pointer passed to comment_handler() */ void *comment_user_data; + /*! The maximum length of comment to be passed to the comment handler */ + uint32_t max_comment_len; lab_params_t lab_params; @@ -78,6 +83,12 @@ struct t42_decode_state_s /*! Length of data pointed to by comment */ size_t comment_len; + /*! \brief The size of the compressed image, in bytes. */ + int compressed_image_size; + + int buf_size; + uint8_t *compressed_buf; + /*! \brief Error and flow logging control */ logging_state_t logging; }; diff --git a/libs/spandsp/src/spandsp/private/t4_tx.h b/libs/spandsp/src/spandsp/private/t4_tx.h index ffa3c342d8..b7b5d11eff 100644 --- a/libs/spandsp/src/spandsp/private/t4_tx.h +++ b/libs/spandsp/src/spandsp/private/t4_tx.h @@ -54,6 +54,12 @@ typedef struct int image_buffer_size; /*! \brief Row counter for playing out the rows of the image. */ int row; + + /*! \brief Image length of the image in the file. This is used when the + image is resized or dithered flat. */ + int image_length; + /*! \brief Row counter used when the image is resized or dithered flat. */ + int raw_row; } t4_tx_tiff_state_t; /*! @@ -132,6 +138,8 @@ struct t4_tx_state_s t85_encode_state_t t85; } encoder; + image_translate_state_t translator; + /* Supporting information, like resolutions, which the backend may want. */ t4_tx_metadata_t metadata; diff --git a/libs/spandsp/src/spandsp/private/t85.h b/libs/spandsp/src/spandsp/private/t85.h index dac7a3340a..2d180c9baf 100644 --- a/libs/spandsp/src/spandsp/private/t85.h +++ b/libs/spandsp/src/spandsp/private/t85.h @@ -123,11 +123,11 @@ struct t85_decode_state_s t4_row_write_handler_t comment_handler; /*! An opaque pointer passed to comment_handler() */ void *comment_user_data; + /*! The maximum length of comment to be passed to the comment handler */ + uint32_t max_comment_len; uint8_t min_bit_planes; uint8_t max_bit_planes; - /*! The maximum length of comment to be passed to the comment handler */ - uint32_t max_comment_len; /*! The maximum permitted width of the full image, in pixels */ uint32_t max_xd; /*! The maximum permitted height of the full image, in pixels */ diff --git a/libs/spandsp/src/spandsp/t42.h b/libs/spandsp/src/spandsp/t42.h index d6785cba23..e072b07442 100644 --- a/libs/spandsp/src/spandsp/t42.h +++ b/libs/spandsp/src/spandsp/t42.h @@ -58,19 +58,15 @@ SPAN_DECLARE(void) set_lab_gamut(lab_params_t *s, int L_min, int L_max, int a_mi SPAN_DECLARE(void) set_lab_gamut2(lab_params_t *s, int L_P, int L_Q, int a_P, int a_Q, int b_P, int b_Q); -SPAN_DECLARE(void) set_illuminant_from_code(lab_params_t *s, const uint8_t code[4]); +SPAN_DECLARE(int) t42_itulab_to_itulab(logging_state_t *logging, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height); -SPAN_DECLARE(void) set_gamut_from_code(lab_params_t *s, const uint8_t code[12]); +SPAN_DECLARE(int) t42_itulab_to_jpeg(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen); -SPAN_DECLARE(int) t42_itulab_to_itulab(tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height, char *emsg, size_t max_emsg_bytes); +SPAN_DECLARE(int) t42_jpeg_to_itulab(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen); -SPAN_DECLARE(int) t42_itulab_to_jpeg(lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, char *emsg, size_t max_emsg_bytes); +SPAN_DECLARE(int) t42_srgb_to_itulab(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height); -SPAN_DECLARE(int) t42_jpeg_to_itulab(lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, char *emsg, size_t max_emsg_bytes); - -SPAN_DECLARE(int) t42_srgb_to_itulab(lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height, char *emsg, size_t max_emsg_bytes); - -SPAN_DECLARE(int) t42_itulab_to_srgb(lab_params_t *s, tdata_t dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t *width, uint32_t *height, char *emsg, size_t max_emsg_bytes); +SPAN_DECLARE(int) t42_itulab_to_srgb(logging_state_t *logging, lab_params_t *s, tdata_t dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t *width, uint32_t *height); SPAN_DECLARE(void) t42_encode_set_options(t42_encode_state_t *s, uint32_t l0, diff --git a/libs/spandsp/src/spandsp/t4_rx.h b/libs/spandsp/src/spandsp/t4_rx.h index 8ff1e286e0..0d37248593 100644 --- a/libs/spandsp/src/spandsp/t4_rx.h +++ b/libs/spandsp/src/spandsp/t4_rx.h @@ -199,6 +199,23 @@ typedef enum T4_LENGTH_1200_US_LEGAL = 0 } t4_image_length_t; +/*! Return values from the T.85 decoder */ +typedef enum +{ + /*! More image data is needed */ + T4_DECODE_MORE_DATA = 0, + /*! Image completed successfully */ + T4_DECODE_OK = -1, + /*! The decoder has interrupted */ + T4_DECODE_INTERRUPT = -2, + /*! An abort was found in the image data */ + T4_DECODE_ABORTED = -3, + /*! A memory allocation error occurred */ + T4_DECODE_NOMEM = -4, + /*! The image data is invalid. */ + T4_DECODE_INVALID_DATA = -5 +} t4_decoder_status_t; + /*! T.4 FAX compression/decompression descriptor. This defines the working state for a single instance of a T.4 FAX compression or decompression channel. diff --git a/libs/spandsp/src/spandsp/t85.h b/libs/spandsp/src/spandsp/t85.h index 516f6ee0e7..3ad36cdfdd 100644 --- a/libs/spandsp/src/spandsp/t85.h +++ b/libs/spandsp/src/spandsp/t85.h @@ -53,24 +53,6 @@ enum T85_LRLTWO = 0x40 }; -/*! Return values from the T.85 decoder */ -enum -{ - /*! More image data is needed */ - T85_MORE_DATA = 0, - /*! Image completed successfully */ - T85_OK = -1, - /*! The decoder has interrupted */ - T85_INTERRUPT = -2, - /*! An abort was found in the image data */ - T85_ABORTED = -3, - /*! A memory allocation error occurred */ - T85_NOMEM = -4, - /*! The image data is invalid. This includes finding values - in the BIH which lie outside the T.85 domain */ - T85_INVALID_DATA = -5 -}; - /*! State of a working instance of the T.85 encoder */ typedef struct t85_encode_state_s t85_encode_state_t; diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c index 8a20c3996d..ec2852ef42 100644 --- a/libs/spandsp/src/t30.c +++ b/libs/spandsp/src/t30.c @@ -61,6 +61,7 @@ #include "spandsp/timezone.h" #include "spandsp/t4_rx.h" #include "spandsp/t4_tx.h" +#include "spandsp/image_translate.h" #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #if defined(SPANDSP_SUPPORT_T42) @@ -89,6 +90,7 @@ #endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" +#include "spandsp/private/image_translate.h" #include "spandsp/private/t4_rx.h" #include "spandsp/private/t4_tx.h" #include "spandsp/private/t30.h" @@ -1179,9 +1181,11 @@ int t30_build_dis_or_dtc(t30_state_t *s) set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SYCC_T81_CAPABLE); if ((s->supported_compressions & T30_SUPPORT_T85_COMPRESSION)) { - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE); + /* Bit 79 set with bit 78 clear is invalid, so only check for L0 + support here. */ if ((s->supported_compressions & T30_SUPPORT_T85_L0_COMPRESSION)) set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE); } //if ((s->supported_compressions & T30_SUPPORT_T89_COMPRESSION)) // set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T89_CAPABLE); @@ -1970,8 +1974,6 @@ static int start_sending_document(t30_state_t *s) if (s->use_own_tz) t4_tx_set_header_tz(&s->t4.tx, &s->tz); - s->x_resolution = t4_tx_get_x_resolution(&s->t4.tx); - s->y_resolution = t4_tx_get_y_resolution(&s->t4.tx); /* The minimum scan time to be used can't be evaluated until we know the Y resolution, and must be evaluated before the minimum scan row bits can be evaluated. */ if ((min_row_bits = set_min_scan_time_code(s)) < 0) @@ -1984,6 +1986,8 @@ static int start_sending_document(t30_state_t *s) if (tx_start_page(s)) return -1; + s->x_resolution = t4_tx_get_x_resolution(&s->t4.tx); + s->y_resolution = t4_tx_get_y_resolution(&s->t4.tx); s->image_width = t4_tx_get_image_width(&s->t4.tx); if (s->error_correcting_mode) { @@ -2069,41 +2073,61 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) /* 256 octets per ECM frame */ s->octets_per_ecm_frame = 256; /* Select the compression to use. */ - if (s->error_correcting_mode - && - (s->supported_compressions & T30_SUPPORT_T85_COMPRESSION) - && - test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE)) + if (!s->error_correcting_mode) { - if (s->supported_compressions & T30_SUPPORT_T85_L0_COMPRESSION + /* Without error correction our choices are very limited */ + if ((s->supported_compressions & T30_SUPPORT_T4_2D_COMPRESSION) && - test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE)) + test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE)) + { + s->line_encoding = T4_COMPRESSION_ITU_T4_2D; + } + else + { + s->line_encoding = T4_COMPRESSION_ITU_T4_1D; + } + } + else + { +#if defined(SPANDSP_SUPPORT_T42x) || defined(SPANDSP_SUPPORT_T43) + /* With error correction colour may be possible/required */ + if (0) { s->line_encoding = T4_COMPRESSION_ITU_T85_L0; } else +#endif { - s->line_encoding = T4_COMPRESSION_ITU_T85; + if ((s->supported_compressions & T30_SUPPORT_T85_L0_COMPRESSION) + && + test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE)) + { + s->line_encoding = T4_COMPRESSION_ITU_T85_L0; + } + else if ((s->supported_compressions & T30_SUPPORT_T85_COMPRESSION) + && + test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE)) + { + s->line_encoding = T4_COMPRESSION_ITU_T85; + } + else if ((s->supported_compressions & T30_SUPPORT_T6_COMPRESSION) + && + test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE)) + { + s->line_encoding = T4_COMPRESSION_ITU_T6; + } + else if ((s->supported_compressions & T30_SUPPORT_T4_2D_COMPRESSION) + && + test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE)) + { + s->line_encoding = T4_COMPRESSION_ITU_T4_2D; + } + else + { + s->line_encoding = T4_COMPRESSION_ITU_T4_1D; + } } } - else if (s->error_correcting_mode - && - (s->supported_compressions & T30_SUPPORT_T6_COMPRESSION) - && - test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE)) - { - s->line_encoding = T4_COMPRESSION_ITU_T6; - } - else if ((s->supported_compressions & T30_SUPPORT_T4_2D_COMPRESSION) - && - test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE)) - { - s->line_encoding = T4_COMPRESSION_ITU_T4_2D; - } - else - { - s->line_encoding = T4_COMPRESSION_ITU_T4_1D; - } span_log(&s->logging, SPAN_LOG_FLOW, "Selected compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding); switch (s->far_dis_dtc_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3)) { @@ -2357,7 +2381,21 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) s->image_width = widths[i][dcs_frame[5] & (DISBIT2 | DISBIT1)]; - /* Check which compression we will use. */ + /* Check which compression the far end has decided to use. */ +#if defined(SPANDSP_SUPPORT_T42x) + if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE)) + { + s->line_encoding = T4_COMPRESSION_ITU_T42; + } + else +#endif +#if defined(SPANDSP_SUPPORT_T43) + if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T43_MODE)) + { + s->line_encoding = T4_COMPRESSION_ITU_T43; + } + else +#endif if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T85_L0_MODE)) { s->line_encoding = T4_COMPRESSION_ITU_T85_L0; diff --git a/libs/spandsp/src/t30_api.c b/libs/spandsp/src/t30_api.c index 9da3e25bcc..ad7cb0e71c 100644 --- a/libs/spandsp/src/t30_api.c +++ b/libs/spandsp/src/t30_api.c @@ -61,6 +61,7 @@ #include "spandsp/timezone.h" #include "spandsp/t4_rx.h" #include "spandsp/t4_tx.h" +#include "spandsp/image_translate.h" #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #if defined(SPANDSP_SUPPORT_T42) @@ -89,6 +90,7 @@ #endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" +#include "spandsp/private/image_translate.h" #include "spandsp/private/t4_rx.h" #include "spandsp/private/t4_tx.h" #include "spandsp/private/t30.h" @@ -700,7 +702,7 @@ SPAN_DECLARE(int) t30_set_supported_compressions(t30_state_t *s, int supported_c | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION #if defined(SPANDSP_SUPPORT_T42) - | T30_SUPPORT_T42_COMPRESSION + //| T30_SUPPORT_T42_COMPRESSION #endif #if defined(SPANDSP_SUPPORT_T43) | T30_SUPPORT_T43_COMPRESSION diff --git a/libs/spandsp/src/t30_logging.c b/libs/spandsp/src/t30_logging.c index 9c53b01037..9328c9b8f3 100644 --- a/libs/spandsp/src/t30_logging.c +++ b/libs/spandsp/src/t30_logging.c @@ -61,6 +61,7 @@ #include "spandsp/timezone.h" #include "spandsp/t4_rx.h" #include "spandsp/t4_tx.h" +#include "spandsp/image_translate.h" #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #if defined(SPANDSP_SUPPORT_T42) @@ -88,6 +89,7 @@ #endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" +#include "spandsp/private/image_translate.h" #include "spandsp/private/t4_rx.h" #include "spandsp/private/t4_tx.h" #include "spandsp/private/t30.h" diff --git a/libs/spandsp/src/t38_gateway.c b/libs/spandsp/src/t38_gateway.c index 205bc1b5bb..e3c99a634a 100644 --- a/libs/spandsp/src/t38_gateway.c +++ b/libs/spandsp/src/t38_gateway.c @@ -74,6 +74,7 @@ #include "spandsp/timezone.h" #include "spandsp/t4_rx.h" #include "spandsp/t4_tx.h" +#include "spandsp/image_translate.h" #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #if defined(SPANDSP_SUPPORT_T42) @@ -116,6 +117,7 @@ #endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" +#include "spandsp/private/image_translate.h" #include "spandsp/private/t4_rx.h" #include "spandsp/private/t4_tx.h" #include "spandsp/private/t30.h" diff --git a/libs/spandsp/src/t38_terminal.c b/libs/spandsp/src/t38_terminal.c index 675c895a2f..d16e3cd569 100644 --- a/libs/spandsp/src/t38_terminal.c +++ b/libs/spandsp/src/t38_terminal.c @@ -64,6 +64,7 @@ #include "spandsp/timezone.h" #include "spandsp/t4_rx.h" #include "spandsp/t4_tx.h" +#include "spandsp/image_translate.h" #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #if defined(SPANDSP_SUPPORT_T42) @@ -94,6 +95,7 @@ #endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" +#include "spandsp/private/image_translate.h" #include "spandsp/private/t4_rx.h" #include "spandsp/private/t4_tx.h" #include "spandsp/private/t30.h" diff --git a/libs/spandsp/src/t42.c b/libs/spandsp/src/t42.c index 608341fd4c..f7f7e1e062 100644 --- a/libs/spandsp/src/t42.c +++ b/libs/spandsp/src/t42.c @@ -61,7 +61,10 @@ #define T42_USE_LUTS +#include "t42_t43_local.h" +#if defined(T42_USE_LUTS) #include "cielab_luts.h" +#endif typedef struct { @@ -197,7 +200,7 @@ SPAN_DECLARE(void) set_lab_gamut2(lab_params_t *s, int L_P, int L_Q, int a_P, in } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) set_illuminant_from_code(lab_params_t *s, const uint8_t code[4]) +void set_illuminant_from_code(logging_state_t *logging, lab_params_t *s, const uint8_t code[4]) { int i; int colour_temp; @@ -205,42 +208,44 @@ SPAN_DECLARE(void) set_illuminant_from_code(lab_params_t *s, const uint8_t code[ if (code[0] == 'C' && code[1] == 'T') { colour_temp = pack_16(&code[2]); - printf("Illuminant colour temp %dK\n", colour_temp); + span_log(logging, SPAN_LOG_FLOW, "Illuminant colour temp %dK\n", colour_temp); return; } for (i = 0; illuminants[i].name[0]; i++) { if (memcmp(code, illuminants[i].tag, 4) == 0) { - printf("Illuminant %s\n", illuminants[i].name); + span_log(logging, SPAN_LOG_FLOW, "Illuminant %s\n", illuminants[i].name); set_lab_illuminant(s, illuminants[i].xn, illuminants[i].yn, illuminants[i].zn); break; } } if (illuminants[i].name[0] == '\0') - printf("Unrecognised illuminant 0x%x 0x%x 0x%x 0x%x\n", code[0], code[1], code[2], code[3]); + span_log(logging, SPAN_LOG_FLOW, "Unrecognised illuminant 0x%x 0x%x 0x%x 0x%x\n", code[0], code[1], code[2], code[3]); } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) set_gamut_from_code(lab_params_t *s, const uint8_t code[12]) +void set_gamut_from_code(logging_state_t *logging, lab_params_t *s, const uint8_t code[12]) { int i; int val[6]; for (i = 0; i < 6; i++) val[i] = pack_16(&code[2*i]); - printf("Gamut L=[%d,%d], a*=[%d,%d], b*=[%d,%d]\n", - val[0], - val[1], - val[2], - val[3], - val[4], - val[5]); + span_log(logging, + SPAN_LOG_FLOW, + "Gamut L=[%d,%d], a*=[%d,%d], b*=[%d,%d]\n", + val[0], + val[1], + val[2], + val[3], + val[4], + val[5]); set_lab_gamut2(s, val[0], val[1], val[2], val[3], val[4], val[5]); } /*- End of function --------------------------------------------------------*/ -static int isITUfax(lab_params_t *s, jpeg_saved_marker_ptr ptr) +static int is_itu_fax(logging_state_t *logging, lab_params_t *s, jpeg_saved_marker_ptr ptr) { const uint8_t *data; int ok; @@ -252,6 +257,11 @@ static int isITUfax(lab_params_t *s, jpeg_saved_marker_ptr ptr) { if (ptr->marker == (JPEG_APP0 + 1) && ptr->data_length >= 6) { + /* Markers are: + JPEG_RST0 + JPEG_EOI + JPEG_APP0 + JPEG_COM */ data = (const uint8_t *) ptr->data; if (strncmp((const char *) data, "G3FAX", 5) == 0) { @@ -260,29 +270,57 @@ static int isITUfax(lab_params_t *s, jpeg_saved_marker_ptr ptr) case 0: for (i = 0; i < 2; i++) val[i] = pack_16(&data[6 + 2*i]); - printf("Version %d, resolution %d dpi\n", val[0], val[1]); + span_log(logging, SPAN_LOG_FLOW, "Version %d, resolution %d dpi\n", val[0], val[1]); ok = TRUE; break; case 1: - printf("Set gamut\n"); - set_gamut_from_code(s, &data[6]); - ok = TRUE; + span_log(logging, SPAN_LOG_FLOW, "Set gamut\n"); + if (ptr->data_length >= 6 + 12) + { + set_gamut_from_code(logging, s, &data[6]); + ok = TRUE; + } + else + { + span_log(logging, SPAN_LOG_FLOW, "Got bad G3FAX1 length - %d\n", ptr->data_length); + } break; case 2: - printf("Set illuminant\n"); - set_illuminant_from_code(s, &data[6]); - ok = TRUE; + span_log(logging, SPAN_LOG_FLOW, "Set illuminant\n"); + if (ptr->data_length >= 6 + 4) + { + set_illuminant_from_code(logging, s, &data[6]); + ok = TRUE; + } + else + { + span_log(logging, SPAN_LOG_FLOW, "Got bad G3FAX2 length - %d\n", ptr->data_length); + } break; case 3: /* Colour palette table */ - printf("Set colour palette\n"); - val[0] = pack_16(&data[6]); - printf("Colour palette %d\n", val[0]); + span_log(logging, SPAN_LOG_FLOW, "Set colour palette\n"); + if (ptr->data_length >= 6 + 2) + { + val[0] = pack_16(&data[6]); + span_log(logging, SPAN_LOG_FLOW, "Colour palette %d\n", val[0]); + } + else + { + span_log(logging, SPAN_LOG_FLOW, "Got bad G3FAX3 length - %d\n", ptr->data_length); + } + break; + default: + span_log(logging, SPAN_LOG_FLOW, "Got unexpected G3FAX%d length - %d\n", data[5], ptr->data_length); break; } } } - + else + { + span_log(logging, SPAN_LOG_FLOW, "Got marker 0x%x, length %d\n", ptr->marker, ptr->data_length); + span_log_buf(logging, SPAN_LOG_FLOW, "Got marker", (const uint8_t *) ptr->data, ptr->data_length); + } ptr = ptr->next; } @@ -290,7 +328,7 @@ static int isITUfax(lab_params_t *s, jpeg_saved_marker_ptr ptr) } /*- End of function --------------------------------------------------------*/ -static void SetITUFax(j_compress_ptr cinfo) +static void set_itu_fax(j_compress_ptr cinfo) { uint8_t marker[10] = { @@ -358,9 +396,9 @@ SPAN_DECLARE(void) srgb_to_lab(lab_params_t *s, uint8_t lab[], const uint8_t srg for (i = 0; i < pixels; i++) { #if defined(T42_USE_LUTS) - r = sRGB_to_linear[srgb[0]]; - g = sRGB_to_linear[srgb[1]]; - b = sRGB_to_linear[srgb[2]]; + r = srgb_to_linear[srgb[0]]; + g = srgb_to_linear[srgb[1]]; + b = srgb_to_linear[srgb[2]]; #else r = srgb[0]/256.0f; g = srgb[1]/256.0f; @@ -436,11 +474,11 @@ SPAN_DECLARE(void) lab_to_srgb(lab_params_t *s, uint8_t srgb[], const uint8_t la #if defined(T42_USE_LUTS) val = r*4096.0f; - srgb[0] = linear_to_sRGB[(val < 0) ? 0 : (val < 4095) ? val : 4095]; + srgb[0] = linear_to_srgb[(val < 0) ? 0 : (val < 4095) ? val : 4095]; val = g*4096.0f; - srgb[1] = linear_to_sRGB[(val < 0) ? 0 : (val < 4095) ? val : 4095]; + srgb[1] = linear_to_srgb[(val < 0) ? 0 : (val < 4095) ? val : 4095]; val = b*4096.0f; - srgb[2] = linear_to_sRGB[(val < 0) ? 0 : (val < 4095) ? val : 4095]; + srgb[2] = linear_to_srgb[(val < 0) ? 0 : (val < 4095) ? val : 4095]; #else /* Linear RGB to sRGB */ r = (r > 0.0031308f) ? (1.055f*powf(r, 1.0f/2.4f) - 0.055f) : r*12.92f; @@ -461,54 +499,77 @@ SPAN_DECLARE(void) lab_to_srgb(lab_params_t *s, uint8_t srgb[], const uint8_t la } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t42_itulab_to_jpeg(lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, char *emsg, size_t max_emsg_bytes) +SPAN_DECLARE(int) t42_itulab_to_jpeg(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen) { struct jpeg_decompress_struct decompressor; struct jpeg_compress_struct compressor; - char *outptr; - size_t outsize; FILE *in; FILE *out; int m; JSAMPROW scan_line_in; JSAMPROW scan_line_out; escape_route_t escape; +#if defined(HAVE_OPEN_MEMSTREAM) + char *outptr; + size_t outsize; +#endif escape.error_message[0] = '\0'; - emsg[0] = '\0'; #if defined(HAVE_OPEN_MEMSTREAM) - in = fmemopen(src, srclen, "r"); -#else - in = tmpfile(); - fwrite(src, 1, srclen, in); - rewind(in); -#endif - if (in == NULL) + if ((in = fmemopen(src, srclen, "r")) == NULL) { - if (emsg[0] == '\0') - strcpy(emsg, "Failed to fmemopen()."); + span_log(logging, SPAN_LOG_FLOW, "Failed to fmemopen().\n"); return FALSE; } - -#if defined(HAVE_OPEN_MEMSTREAM) - out = open_memstream(&outptr, &outsize); -#else - out = tmpfile(); -#endif - if (out == NULL) + outsize = 0; + if ((out = open_memstream(&outptr, &outsize)) == NULL) { - if (emsg[0] == '\0') - strcpy(emsg, "Failed to open_memstream()."); + span_log(logging, SPAN_LOG_FLOW, "Failed to open_memstream().\n"); + fclose(in); return FALSE; } + if (fseek(out, 0, SEEK_SET) != 0) + { + fclose(in); + fclose(out); + return FALSE; + } +#else + if ((in = tmpfile()) == NULL) + { + span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); + return FALSE; + } + if (fwrite(src, 1, srclen, in) != srclen) + { + fclose(in); + return FALSE; + } + if (fseek(in, 0, SEEK_SET) != 0) + { + fclose(in); + return FALSE; + } + if ((out = tmpfile()) == NULL) + { + span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); + fclose(in); + return FALSE; + } +#endif + scan_line_out = NULL; if (setjmp(escape.escape)) { - strncpy(emsg, escape.error_message, max_emsg_bytes - 1); - emsg[max_emsg_bytes - 1] = '\0'; - if (emsg[0] == '\0') - strcpy(emsg, "Unspecified libjpeg error."); + if (escape.error_message[0]) + span_log(logging, SPAN_LOG_FLOW, "%s\n", escape.error_message); + else + span_log(logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n"); + if (scan_line_out) + free(scan_line_out); + fclose(in); + fclose(out); return FALSE; } @@ -532,14 +593,13 @@ SPAN_DECLARE(int) t42_itulab_to_jpeg(lab_params_t *s, tdata_t *dst, tsize_t *dst /* Take the header */ jpeg_read_header(&decompressor, TRUE); - /* Now we can force the input colorspace. For ITULab, we will use YCbCr as a "don't touch" marker */ + /* Now we can force the input colour space. For ITULab, we use YCbCr as a "don't touch" marker */ decompressor.out_color_space = JCS_YCbCr; /* Sanity check and parameter check */ - if (!isITUfax(s, decompressor.marker_list)) + if (!is_itu_fax(logging, s, decompressor.marker_list)) { - if (emsg[0] == '\0') - strcpy(emsg, "Is not ITUFAX."); + span_log(logging, SPAN_LOG_FLOW, "Is not an ITU FAX.\n"); return FALSE; } @@ -552,12 +612,13 @@ SPAN_DECLARE(int) t42_itulab_to_jpeg(lab_params_t *s, tdata_t *dst, tsize_t *dst jpeg_create_compress(&compressor); jpeg_stdio_dest(&compressor, out); - /* Force the destination color space */ + /* Force the destination colour space */ compressor.in_color_space = JCS_RGB; compressor.input_components = 3; jpeg_set_defaults(&compressor); - //jpeg_set_quality(&compressor, quality, TRUE /* limit to baseline-JPEG values */); + /* Limit to baseline-JPEG values */ + //jpeg_set_quality(&compressor, quality, TRUE); /* Copy size, resolution, etc */ jpeg_copy_critical_parameters(&decompressor, &compressor); @@ -592,64 +653,106 @@ SPAN_DECLARE(int) t42_itulab_to_jpeg(lab_params_t *s, tdata_t *dst, tsize_t *dst jpeg_destroy_decompress(&decompressor); jpeg_destroy_compress(&compressor); fclose(in); - fclose(out); +#if defined(HAVE_OPEN_MEMSTREAM) + fclose(out); *dst = outptr; *dstlen = outsize; +#else + *dstlen = ftell(out); + *dst = malloc(*dstlen); + if (fseek(out, 0, SEEK_SET) != 0) + { + fclose(out); + return FALSE; + } + if (fread(*dst, 1, *dstlen, out) != *dstlen) + { + free(*dst); + fclose(out); + return FALSE; + } + fclose(out); +#endif return TRUE; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t42_jpeg_to_itulab(lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, char *emsg, size_t max_emsg_bytes) +SPAN_DECLARE(int) t42_jpeg_to_itulab(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen) { struct jpeg_decompress_struct decompressor; struct jpeg_compress_struct compressor; - char *outptr; - size_t outsize; FILE *in; FILE *out; int m; JSAMPROW scan_line_in; JSAMPROW scan_line_out; escape_route_t escape; +#if defined(HAVE_OPEN_MEMSTREAM) + char *outptr; + size_t outsize; +#endif escape.error_message[0] = '\0'; - emsg[0] = '\0'; #if defined(HAVE_OPEN_MEMSTREAM) - in = fmemopen(src, srclen, "r"); -#else - in = tmpfile(); - fwrite(src, 1, srclen, in); - rewind(in); -#endif - if (in == NULL) + if ((in = fmemopen(src, srclen, "r")) == NULL) { - if (emsg[0] == '\0') - strcpy(emsg, "Failed to fmemopen()."); + span_log(logging, SPAN_LOG_FLOW, "Failed to fmemopen().\n"); return FALSE; } - -#if defined(HAVE_OPEN_MEMSTREAM) - out = open_memstream(&outptr, &outsize); -#else - out = tmpfile(); -#endif - if (out == NULL) + outsize = 0; + if ((out = open_memstream(&outptr, &outsize)) == NULL) { - if (emsg[0] == '\0') - strcpy(emsg, "Failed to open_memstream()."); + span_log(logging, SPAN_LOG_FLOW, "Failed to open_memstream().\n"); + fclose(in); return FALSE; } + if (fseek(out, 0, SEEK_SET) != 0) + { + fclose(in); + fclose(out); + return FALSE; + } +#else + if ((in = tmpfile()) == NULL) + { + span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); + return FALSE; + } + if (fwrite(src, 1, srclen, in) != srclen) + { + fclose(in); + return FALSE; + } + if (fseek(in, 0, SEEK_SET) != 0) + { + fclose(in); + return FALSE; + } + if ((out = tmpfile()) == NULL) + { + span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); + fclose(in); + return FALSE; + } +#endif + scan_line_out = NULL; if (setjmp(escape.escape)) { - strncpy(emsg, escape.error_message, max_emsg_bytes - 1); - emsg[max_emsg_bytes - 1] = '\0'; + if (escape.error_message[0]) + span_log(logging, SPAN_LOG_FLOW, "%s\n", escape.error_message); + else + span_log(logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n"); + if (scan_line_out) + free(scan_line_out); + fclose(in); + fclose(out); return FALSE; } - + /* Create input decompressor. */ decompressor.err = jpeg_std_error(&error_handler); decompressor.client_data = (void *) &escape; error_handler.error_exit = jpg_error_exit; @@ -669,7 +772,7 @@ SPAN_DECLARE(int) t42_jpeg_to_itulab(lab_params_t *s, tdata_t *dst, tsize_t *dst /* Take the header */ jpeg_read_header(&decompressor, TRUE); - /* Now we can force the input colorspace. For ITULab, we will use YCbCr as a "don't touch" marker */ + /* Now we can force the input colour space. For ITULab, we use YCbCr as a "don't touch" marker */ decompressor.out_color_space = JCS_RGB; compressor.err = jpeg_std_error(&error_handler); @@ -680,12 +783,13 @@ SPAN_DECLARE(int) t42_jpeg_to_itulab(lab_params_t *s, tdata_t *dst, tsize_t *dst jpeg_create_compress(&compressor); jpeg_stdio_dest(&compressor, out); - /* Force the destination color space */ + /* Force the destination colour space */ compressor.in_color_space = JCS_YCbCr; compressor.input_components = 3; jpeg_set_defaults(&compressor); - //jpeg_set_quality(&compressor, quality, TRUE /* limit to baseline-JPEG values */); + /* Limit to baseline-JPEG values */ + //jpeg_set_quality(&compressor, quality, TRUE); jpeg_copy_critical_parameters(&decompressor, &compressor); @@ -697,7 +801,7 @@ SPAN_DECLARE(int) t42_jpeg_to_itulab(lab_params_t *s, tdata_t *dst, tsize_t *dst jpeg_start_decompress(&decompressor); jpeg_start_compress(&compressor, TRUE); - SetITUFax(&compressor); + set_itu_fax(&compressor); if ((scan_line_in = (JSAMPROW) malloc(decompressor.output_width*decompressor.num_components)) == NULL) return FALSE; @@ -722,45 +826,77 @@ SPAN_DECLARE(int) t42_jpeg_to_itulab(lab_params_t *s, tdata_t *dst, tsize_t *dst jpeg_destroy_decompress(&decompressor); jpeg_destroy_compress(&compressor); fclose(in); - fclose(out); +#if defined(HAVE_OPEN_MEMSTREAM) + fclose(out); *dst = outptr; *dstlen = outsize; +#else + *dstlen = ftell(out); + *dst = malloc(*dstlen); + if (fseek(out, 0, SEEK_SET) != 0) + { + fclose(out); + return FALSE; + } + if (fread(*dst, 1, *dstlen, out) != *dstlen) + { + free(*dst); + fclose(out); + return FALSE; + } + fclose(out); +#endif return TRUE; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t42_srgb_to_itulab(lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height, char *emsg, size_t max_emsg_bytes) +SPAN_DECLARE(int) t42_srgb_to_itulab(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height) { struct jpeg_compress_struct compressor; FILE *out; - char *outptr; - size_t outsize; JSAMPROW scan_line_out; JSAMPROW scan_line_in; tsize_t pos; escape_route_t escape; +#if defined(HAVE_OPEN_MEMSTREAM) + char *outptr; + size_t outsize; +#endif escape.error_message[0] = '\0'; - emsg[0] = '\0'; #if defined(HAVE_OPEN_MEMSTREAM) - out = open_memstream(&outptr, &outsize); -#else - out = tmpfile(); -#endif - if (out == NULL) + outsize = 0; + if ((out = open_memstream(&outptr, &outsize)) == NULL) { - if (emsg[0] == '\0') - strcpy(emsg, "Failed to open_memstream()."); + span_log(logging, SPAN_LOG_FLOW, "Failed to open_memstream().\n"); return FALSE; } + if (fseek(out, 0, SEEK_SET) != 0) + { + fclose(out); + return FALSE; + } +#else + if ((out = tmpfile()) == NULL) + { + span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); + return FALSE; + } +#endif + scan_line_out = NULL; if (setjmp(escape.escape)) { - strncpy(emsg, escape.error_message, max_emsg_bytes - 1); - emsg[max_emsg_bytes - 1] = '\0'; + if (escape.error_message[0]) + span_log(logging, SPAN_LOG_FLOW, "%s\n", escape.error_message); + else + span_log(logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n"); + if (scan_line_out) + free(scan_line_out); + fclose(out); return FALSE; } @@ -772,12 +908,13 @@ SPAN_DECLARE(int) t42_srgb_to_itulab(lab_params_t *s, tdata_t *dst, tsize_t *dst jpeg_create_compress(&compressor); jpeg_stdio_dest(&compressor, out); - /* Force the destination color space */ + /* Force the destination colour space */ compressor.in_color_space = JCS_YCbCr; compressor.input_components = 3; jpeg_set_defaults(&compressor); - //jpeg_set_quality(&compressor, quality, TRUE /* limit to baseline-JPEG values */); + /* Limit to baseline-JPEG values */ + //jpeg_set_quality(&compressor, quality, TRUE); /* Size, resolution, etc */ compressor.image_width = width; @@ -785,7 +922,7 @@ SPAN_DECLARE(int) t42_srgb_to_itulab(lab_params_t *s, tdata_t *dst, tsize_t *dst jpeg_start_compress(&compressor, TRUE); - SetITUFax(&compressor); + set_itu_fax(&compressor); if ((scan_line_out = (JSAMPROW) malloc(compressor.image_width*compressor.num_components)) == NULL) return FALSE; @@ -800,44 +937,73 @@ SPAN_DECLARE(int) t42_srgb_to_itulab(lab_params_t *s, tdata_t *dst, tsize_t *dst free(scan_line_out); jpeg_finish_compress(&compressor); jpeg_destroy_compress(&compressor); - fclose(out); +#if defined(HAVE_OPEN_MEMSTREAM) + fclose(out); *dst = outptr; *dstlen = outsize; +#else + *dstlen = ftell(out); + *dst = malloc(*dstlen); + if (fseek(out, 0, SEEK_SET) != 0) + { + fclose(out); + return FALSE; + } + if (fread(*dst, 1, *dstlen, out) != *dstlen) + { + free(*dst); + fclose(out); + return FALSE; + } + fclose(out); +#endif return TRUE; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t42_itulab_to_itulab(tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height, char *emsg, size_t max_emsg_bytes) +SPAN_DECLARE(int) t42_itulab_to_itulab(logging_state_t *logging, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height) { struct jpeg_compress_struct compressor; FILE *out; - char *outptr; - size_t outsize; JSAMPROW scan_line_in; tsize_t pos; escape_route_t escape; +#if defined(HAVE_OPEN_MEMSTREAM) + char *outptr; + size_t outsize; +#endif escape.error_message[0] = '\0'; - emsg[0] = '\0'; #if defined(HAVE_OPEN_MEMSTREAM) - out = open_memstream(&outptr, &outsize); -#else - out = tmpfile(); -#endif - if (out == NULL) + outsize = 0; + if ((out = open_memstream(&outptr, &outsize)) == NULL) { - if (emsg[0] == '\0') - strcpy(emsg, "Failed to open_memstream()."); + span_log(logging, SPAN_LOG_FLOW, "Failed to open_memstream().\n"); return FALSE; } + if (fseek(out, 0, SEEK_SET) != 0) + { + fclose(out); + return FALSE; + } +#else + if ((out = tmpfile()) == NULL) + { + span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); + return FALSE; + } +#endif if (setjmp(escape.escape)) { - strncpy(emsg, escape.error_message, max_emsg_bytes - 1); - emsg[max_emsg_bytes - 1] = '\0'; + if (escape.error_message[0]) + span_log(logging, SPAN_LOG_FLOW, "%s\n", escape.error_message); + else + span_log(logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n"); + fclose(out); return FALSE; } @@ -849,12 +1015,13 @@ SPAN_DECLARE(int) t42_itulab_to_itulab(tdata_t *dst, tsize_t *dstlen, tdata_t sr jpeg_create_compress(&compressor); jpeg_stdio_dest(&compressor, out); - /* Force the destination color space */ + /* Force the destination colour space */ compressor.in_color_space = JCS_YCbCr; compressor.input_components = 3; jpeg_set_defaults(&compressor); - //jpeg_set_quality(&compressor, quality, TRUE /* limit to baseline-JPEG values */); + /* Limit to baseline-JPEG values */ + //jpeg_set_quality(&compressor, quality, TRUE); /* Size, resolution, etc */ compressor.image_width = width; @@ -862,7 +1029,7 @@ SPAN_DECLARE(int) t42_itulab_to_itulab(tdata_t *dst, tsize_t *dstlen, tdata_t sr jpeg_start_compress(&compressor, TRUE); - SetITUFax(&compressor); + set_itu_fax(&compressor); for (pos = 0; pos < srclen; pos += compressor.image_width*compressor.num_components) { @@ -872,16 +1039,33 @@ SPAN_DECLARE(int) t42_itulab_to_itulab(tdata_t *dst, tsize_t *dstlen, tdata_t sr jpeg_finish_compress(&compressor); jpeg_destroy_compress(&compressor); - fclose(out); +#if defined(HAVE_OPEN_MEMSTREAM) + fclose(out); *dst = outptr; *dstlen = outsize; +#else + *dstlen = ftell(out); + *dst = malloc(*dstlen); + if (fseek(out, 0, SEEK_SET) != 0) + { + fclose(out); + return FALSE; + } + if (fread(*dst, 1, *dstlen, out) != *dstlen) + { + free(*dst); + fclose(out); + return FALSE; + } + fclose(out); +#endif return TRUE; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t42_itulab_to_srgb(lab_params_t *s, tdata_t dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t *width, uint32_t *height, char *emsg, size_t max_emsg_bytes) +SPAN_DECLARE(int) t42_itulab_to_srgb(logging_state_t *logging, lab_params_t *s, tdata_t dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t *width, uint32_t *height) { struct jpeg_decompress_struct decompressor; JSAMPROW scan_line_out; @@ -892,28 +1076,41 @@ SPAN_DECLARE(int) t42_itulab_to_srgb(lab_params_t *s, tdata_t dst, tsize_t *dstl escape_route_t escape; escape.error_message[0] = '\0'; - emsg[0] = '\0'; #if defined(HAVE_OPEN_MEMSTREAM) - in = fmemopen(src, srclen, "r"); -#else - in = tmpfile(); - fwrite(src, 1, srclen, in); - rewind(in); -#endif - if (in == NULL) + if ((in = fmemopen(src, srclen, "r")) == NULL) { - if (emsg[0] == '\0') - strcpy(emsg, "Failed to fmemopen()."); + span_log(logging, SPAN_LOG_FLOW, "Failed to fmemopen().\n"); return FALSE; } +#else + if ((in = tmpfile()) == NULL) + { + span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); + return FALSE; + } + if (fwrite(src, 1, srclen, in) != srclen) + { + fclose(in); + return FALSE; + } + if (fseek(in, 0, SEEK_SET) != 0) + { + fclose(in); + return FALSE; + } +#endif + scan_line_out = NULL; if (setjmp(escape.escape)) { - strncpy(emsg, escape.error_message, max_emsg_bytes - 1); - emsg[max_emsg_bytes - 1] = '\0'; - if (emsg[0] == '\0') - strcpy(emsg, "Unspecified libjpeg error."); + if (escape.error_message[0]) + span_log(logging, SPAN_LOG_FLOW, "%s\n", escape.error_message); + else + span_log(logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n"); + if (scan_line_out) + free(scan_line_out); + fclose(in); return FALSE; } /* Create input decompressor. */ @@ -932,21 +1129,16 @@ SPAN_DECLARE(int) t42_itulab_to_srgb(lab_params_t *s, tdata_t dst, tsize_t *dstl /* Rewind the file */ if (fseek(in, 0, SEEK_SET) != 0) return FALSE; -printf("XXXX 10\n"); /* Take the header */ jpeg_read_header(&decompressor, FALSE); -printf("XXXX 11\n"); - /* Now we can force the input colorspace. For ITULab, we will use YCbCr as a "don't touch" marker */ + /* Now we can force the input colour space. For ITULab, we use YCbCr as a "don't touch" marker */ decompressor.out_color_space = JCS_YCbCr; -printf("XXXX 12\n"); /* Sanity check and parameter check */ - if (!isITUfax(s, decompressor.marker_list)) + if (!is_itu_fax(logging, s, decompressor.marker_list)) { - if (emsg[0] == '\0') - strcpy(emsg, "Is not ITUFAX."); - //return FALSE; + span_log(logging, SPAN_LOG_FLOW, "Is not an ITU FAX.\n"); + return FALSE; } -printf("XXXX 13\n"); /* Copy size, resolution, etc */ *width = decompressor.image_width; *height = decompressor.image_height; @@ -1030,7 +1222,7 @@ SPAN_DECLARE(uint32_t) t42_encode_get_image_length(t42_encode_state_t *s) SPAN_DECLARE(int) t42_encode_get_compressed_image_size(t42_encode_state_t *s) { - return 0; + return s->compressed_image_size; } /*- End of function --------------------------------------------------------*/ @@ -1044,6 +1236,9 @@ SPAN_DECLARE(int) t42_encode_set_row_read_handler(t42_encode_state_t *s, SPAN_DECLARE(int) t42_encode_restart(t42_encode_state_t *s, uint32_t image_width, uint32_t image_length) { + //s->image_width = image_width; + //s->image_length = image_length; + s->compressed_image_size = 0; return 0; } /*- End of function --------------------------------------------------------*/ @@ -1065,6 +1260,7 @@ SPAN_DECLARE(t42_encode_state_t *) t42_encode_init(t42_encode_state_t *s, s->row_read_handler = handler; s->row_read_user_data = user_data; + t42_encode_restart(s, image_width, image_length); return s; } @@ -1078,7 +1274,11 @@ SPAN_DECLARE(int) t42_encode_release(t42_encode_state_t *s) SPAN_DECLARE(int) t42_encode_free(t42_encode_state_t *s) { - return 0; + int ret; + + ret = t42_encode_release(s); + free(s); + return ret; } /*- End of function --------------------------------------------------------*/ @@ -1097,6 +1297,17 @@ SPAN_DECLARE(int) t42_decode_put_chunk(t42_decode_state_t *s, const uint8_t data[], size_t len) { + uint8_t *buf; + + if (s->compressed_image_size + len > s->buf_size) + { + if ((buf = (uint8_t *) realloc(s->compressed_buf, s->compressed_image_size + 1000)) == NULL) + return -1; + s->buf_size = s->compressed_image_size + 1000; + s->compressed_buf = buf; + } + memcpy(&s->compressed_buf[s->compressed_image_size], data, len); + s->compressed_image_size += len; return 0; } /*- End of function --------------------------------------------------------*/ @@ -1105,6 +1316,8 @@ SPAN_DECLARE(int) t42_decode_set_row_write_handler(t42_decode_state_t *s, t4_row_write_handler_t handler, void *user_data) { + s->row_write_handler = handler; + s->row_write_user_data = user_data; return 0; } /*- End of function --------------------------------------------------------*/ @@ -1114,6 +1327,9 @@ SPAN_DECLARE(int) t42_decode_set_comment_handler(t42_decode_state_t *s, t4_row_write_handler_t handler, void *user_data) { + s->max_comment_len = max_comment_len; + s->comment_handler = handler; + s->comment_user_data = user_data; return 0; } /*- End of function --------------------------------------------------------*/ @@ -1140,7 +1356,7 @@ SPAN_DECLARE(uint32_t) t42_decode_get_image_length(t42_decode_state_t *s) SPAN_DECLARE(int) t42_decode_get_compressed_image_size(t42_decode_state_t *s) { - return 0; + return s->compressed_image_size; } /*- End of function --------------------------------------------------------*/ @@ -1152,6 +1368,7 @@ SPAN_DECLARE(int) t42_decode_new_plane(t42_decode_state_t *s) SPAN_DECLARE(int) t42_decode_restart(t42_decode_state_t *s) { + s->compressed_image_size = 0; return 0; } /*- End of function --------------------------------------------------------*/ @@ -1172,6 +1389,11 @@ SPAN_DECLARE(t42_decode_state_t *) t42_decode_init(t42_decode_state_t *s, s->row_write_handler = handler; s->row_write_user_data = user_data; + s->buf_size = 0; + s->compressed_buf = NULL; + + t42_decode_restart(s); + return s; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t42_t43_local.h b/libs/spandsp/src/t42_t43_local.h new file mode 100644 index 0000000000..6eec67c6b9 --- /dev/null +++ b/libs/spandsp/src/t42_t43_local.h @@ -0,0 +1,44 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * t42_t43_local.h - definitions for T.42 and T.43 shared processing + * + * Written by Steve Underwood + * + * Copyright (C) 2011 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/*! \file */ + +#if !defined(_T42_T43_LOCAL_H_) +#define _T42_T43_LOCAL_H_ + +#if defined(__cplusplus) +extern "C" +{ +#endif + +void set_illuminant_from_code(logging_state_t *logging, lab_params_t *s, const uint8_t code[4]); +void set_gamut_from_code(logging_state_t *logging, lab_params_t *s, const uint8_t code[12]); + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t4_rx.c b/libs/spandsp/src/t4_rx.c index 74dd152b7c..4e096e6371 100644 --- a/libs/spandsp/src/t4_rx.c +++ b/libs/spandsp/src/t4_rx.c @@ -54,6 +54,7 @@ #include "spandsp/timezone.h" #include "spandsp/t4_rx.h" #include "spandsp/t4_tx.h" +#include "spandsp/image_translate.h" #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #if defined(SPANDSP_SUPPORT_T42) @@ -77,6 +78,7 @@ #endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" +#include "spandsp/private/image_translate.h" #include "spandsp/private/t4_rx.h" #include "spandsp/private/t4_tx.h" @@ -374,7 +376,7 @@ SPAN_DECLARE(int) t4_rx_put_byte(t4_rx_state_t *s, uint8_t byte) case T4_COMPRESSION_ITU_T85_L0: return t85_decode_put_byte(&s->decoder.t85, byte); } - return TRUE; + return T4_DECODE_OK; } /*- End of function --------------------------------------------------------*/ @@ -399,7 +401,7 @@ SPAN_DECLARE(int) t4_rx_put_chunk(t4_rx_state_t *s, const uint8_t buf[], int len case T4_COMPRESSION_ITU_T85_L0: return t85_decode_put_chunk(&s->decoder.t85, buf, len); } - return TRUE; + return T4_DECODE_OK; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t4_t6_decode.c b/libs/spandsp/src/t4_t6_decode.c index ceb2af28f6..b3c96222b8 100644 --- a/libs/spandsp/src/t4_t6_decode.c +++ b/libs/spandsp/src/t4_t6_decode.c @@ -85,6 +85,7 @@ #include "spandsp/timezone.h" #include "spandsp/t4_rx.h" #include "spandsp/t4_tx.h" +#include "spandsp/image_translate.h" #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #if defined(SPANDSP_SUPPORT_T42) @@ -107,6 +108,7 @@ #endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" +#include "spandsp/private/image_translate.h" #include "spandsp/private/t4_rx.h" #include "spandsp/private/t4_tx.h" @@ -764,9 +766,9 @@ SPAN_DECLARE(int) t4_t6_decode_put_chunk(t4_t6_decode_state_t *s, const uint8_t s->compressed_image_size += 8; byte = buf[i]; if (put_bits(s, byte & 0xFF, 8)) - return TRUE; + return T4_DECODE_OK; } - return FALSE; + return T4_DECODE_MORE_DATA; } /*- End of function --------------------------------------------------------*/ @@ -875,10 +877,7 @@ SPAN_DECLARE(int) t4_t6_decode_restart(t4_t6_decode_state_t *s, int image_width) if (s->ref_runs) { memset(s->ref_runs, 0, run_space); - s->ref_runs[0] = - s->ref_runs[1] = - s->ref_runs[2] = - s->ref_runs[3] = s->image_width; + s->ref_runs[0] = s->image_width; } if (s->row_buf) memset(s->row_buf, 0, s->bytes_per_row); diff --git a/libs/spandsp/src/t4_t6_encode.c b/libs/spandsp/src/t4_t6_encode.c index 51103e522d..59dbd251e9 100644 --- a/libs/spandsp/src/t4_t6_encode.c +++ b/libs/spandsp/src/t4_t6_encode.c @@ -82,6 +82,7 @@ #include "spandsp/timezone.h" #include "spandsp/t4_rx.h" #include "spandsp/t4_tx.h" +#include "spandsp/image_translate.h" #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #if defined(SPANDSP_SUPPORT_T42) @@ -104,6 +105,7 @@ #endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" +#include "spandsp/private/image_translate.h" #include "spandsp/private/t4_rx.h" #include "spandsp/private/t4_tx.h" @@ -544,6 +546,22 @@ static int row_to_run_lengths(uint32_t list[], const uint8_t row[], int width) list[entry++] = pos; } } +#if defined(T4_STATE_DEBUGGING) + /* Dump the runs of black and white for analysis */ + { + int prev; + int x; + + printf("Runs (%d)", list[entry - 1]); + prev = 0; + for (x = 0; x < entry; x++) + { + printf(" %" PRIu32, list[x] - prev); + prev = list[x]; + } + printf("\n"); + } +#endif return entry; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t4_tx.c b/libs/spandsp/src/t4_tx.c index 3961bfa94d..d1060f8a82 100644 --- a/libs/spandsp/src/t4_tx.c +++ b/libs/spandsp/src/t4_tx.c @@ -54,6 +54,7 @@ #include "spandsp/timezone.h" #include "spandsp/t4_rx.h" #include "spandsp/t4_tx.h" +#include "spandsp/image_translate.h" #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #if defined(SPANDSP_SUPPORT_T42) @@ -76,6 +77,7 @@ #endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" +#include "spandsp/private/image_translate.h" #include "spandsp/private/t4_rx.h" #include "spandsp/private/t4_tx.h" @@ -180,21 +182,39 @@ static int get_tiff_directory_info(t4_tx_state_t *s) float y_resolution; int i; t4_tx_tiff_state_t *t; + uint16_t bits_per_sample; + uint16_t samples_per_pixel; t = &s->tiff; parm16 = 0; TIFFGetField(t->tiff_file, TIFFTAG_BITSPERSAMPLE, &parm16); - if (parm16 != 1) - return -1; + bits_per_sample = parm16; parm16 = 0; TIFFGetField(t->tiff_file, TIFFTAG_SAMPLESPERPIXEL, &parm16); - if (parm16 != 1) + samples_per_pixel = parm16; + if (samples_per_pixel == 1 && bits_per_sample == 1) + t->image_type = T4_IMAGE_TYPE_BILEVEL; + else if (samples_per_pixel == 1 && bits_per_sample == 8) + t->image_type = T4_IMAGE_TYPE_GRAY_8BIT; + else if (samples_per_pixel == 1 && bits_per_sample > 8) + t->image_type = T4_IMAGE_TYPE_GRAY_12BIT; + else if (samples_per_pixel == 3 && bits_per_sample == 8) + t->image_type = T4_IMAGE_TYPE_COLOUR_8BIT; + else if (samples_per_pixel == 3 && bits_per_sample > 8) + t->image_type = T4_IMAGE_TYPE_COLOUR_12BIT; + else return -1; +#if 0 + /* Limit ourselves to plain black and white pages */ + if (t->image_type != T4_IMAGE_TYPE_BILEVEL) + return -1; +#endif parm32 = 0; TIFFGetField(t->tiff_file, TIFFTAG_IMAGEWIDTH, &parm32); s->image_width = parm32; parm32 = 0; TIFFGetField(t->tiff_file, TIFFTAG_IMAGELENGTH, &parm32); + s->tiff.image_length = s->image_length = parm32; x_resolution = 0.0f; TIFFGetField(t->tiff_file, TIFFTAG_XRESOLUTION, &x_resolution); @@ -206,8 +226,6 @@ static int get_tiff_directory_info(t4_tx_state_t *s) TIFFGetField(t->tiff_file, TIFFTAG_PHOTOMETRIC, &t->photo_metric); /* TIFFGetField(t->tiff_file, TIFFTAG_COMPRESSION, &t->????); */ - if (t->photo_metric != PHOTOMETRIC_MINISWHITE) - span_log(&s->logging, SPAN_LOG_FLOW, "%s: Photometric needs swapping.\n", s->tiff.file); t->fill_order = FILLORDER_LSB2MSB; /* Allow a little range for the X resolution in centimeters. The spec doesn't pin down the @@ -388,61 +406,102 @@ static int open_tiff_input_file(t4_tx_state_t *s, const char *file) static int tiff_row_read_handler(void *user_data, uint8_t buf[], size_t len) { t4_tx_state_t *s; - int i; s = (t4_tx_state_t *) user_data; if (s->tiff.row >= s->image_length) return 0; -#if 0 - if (TIFFReadScanline(s->tiff.tiff_file, buf, s->tiff.row, 0) < 0) - span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error reading TIFF row.\n", s->tiff.file); -#else memcpy(buf, &s->tiff.image_buffer[s->tiff.row*len], len); -#endif - if (s->tiff.photo_metric != PHOTOMETRIC_MINISWHITE) - { - for (i = 0; i < len; i++) - buf[i] = ~buf[i]; - } - if (s->tiff.fill_order != FILLORDER_LSB2MSB) - bit_reverse(buf, buf, len); s->tiff.row++; return len; } /*- End of function --------------------------------------------------------*/ +static int row_read(void *user_data, uint8_t buf[], size_t len) +{ + t4_tx_state_t *s; + + s = (t4_tx_state_t *) user_data; + + if (s->tiff.raw_row >= s->tiff.image_length) + return 0; + if (TIFFReadScanline(s->tiff.tiff_file, buf, s->tiff.raw_row, 0) < 0) + return 0; + s->tiff.raw_row++; + return len; +} +/*- End of function --------------------------------------------------------*/ + static int read_tiff_image(t4_tx_state_t *s) { int total_len; int len; - int bytes_per_row; int i; uint8_t *t; + image_translate_state_t *translator; + int mode; - s->image_width = 0; - TIFFGetField(s->tiff.tiff_file, TIFFTAG_IMAGEWIDTH, &s->image_width); - s->image_length = 0; - TIFFGetField(s->tiff.tiff_file, TIFFTAG_IMAGELENGTH, &s->image_length); - bytes_per_row = TIFFScanlineSize(s->tiff.tiff_file); - s->tiff.image_size = s->image_length*bytes_per_row; - if (s->tiff.image_size >= s->tiff.image_buffer_size) + if (s->tiff.image_type != T4_IMAGE_TYPE_BILEVEL) { - if ((t = realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL) + /* We need to dither this image down to pure black and white, possibly resizing it + along the way. */ + if (s->tiff.image_type == T4_IMAGE_TYPE_GRAY_8BIT) + mode = IMAGE_TRANSLATE_FROM_GRAY_8; + else if (s->tiff.image_type == T4_IMAGE_TYPE_GRAY_12BIT) + mode = IMAGE_TRANSLATE_FROM_GRAY_16; + else if (s->tiff.image_type == T4_IMAGE_TYPE_COLOUR_8BIT) + mode = IMAGE_TRANSLATE_FROM_COLOUR_8; + else if (s->tiff.image_type == T4_IMAGE_TYPE_COLOUR_12BIT) + mode = IMAGE_TRANSLATE_FROM_COLOUR_16; + else return -1; - s->tiff.image_buffer_size += s->tiff.image_size; - s->tiff.image_buffer = t; - } - -#if 1 - for (i = 0, total_len = 0; total_len < s->tiff.image_size; i++, total_len += len) - { - if ((len = TIFFReadEncodedStrip(s->tiff.tiff_file, i, &s->tiff.image_buffer[total_len], s->tiff.image_size - total_len)) < 0) + if ((translator = image_translate_init(NULL, mode, s->image_width, s->image_length, 1728, -1, row_read, s)) == NULL) + return -1; + s->image_width = image_translate_get_output_width(translator); + s->image_length = image_translate_get_output_length(translator); + s->metadata.x_resolution = T4_X_RESOLUTION_R8; + s->metadata.y_resolution = T4_Y_RESOLUTION_FINE; + s->tiff.image_size = (s->image_width*s->image_length + 7)/8; + if (s->tiff.image_size >= s->tiff.image_buffer_size) { - span_log(&s->logging, SPAN_LOG_WARNING, "%s: Read error.\n", s->tiff.file); - return -1; + if ((t = realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL) + return -1; + s->tiff.image_buffer_size = s->tiff.image_size; + s->tiff.image_buffer = t; } + s->tiff.raw_row = 0; + total_len = 0; + for (i = 0; i < s->image_length; i++) + total_len += image_translate_row(translator, &s->tiff.image_buffer[total_len], s->image_width/8); + image_translate_free(translator); + } + else + { + s->tiff.image_size = s->image_length*TIFFScanlineSize(s->tiff.tiff_file); + if (s->tiff.image_size >= s->tiff.image_buffer_size) + { + if ((t = realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL) + return -1; + s->tiff.image_buffer_size = s->tiff.image_size; + s->tiff.image_buffer = t; + } + + for (i = 0, total_len = 0; total_len < s->tiff.image_size; i++, total_len += len) + { + if ((len = TIFFReadEncodedStrip(s->tiff.tiff_file, i, &s->tiff.image_buffer[total_len], s->tiff.image_size - total_len)) < 0) + { + span_log(&s->logging, SPAN_LOG_WARNING, "%s: Read error.\n", s->tiff.file); + return -1; + } + } + if (s->tiff.photo_metric != PHOTOMETRIC_MINISWHITE) + { + span_log(&s->logging, SPAN_LOG_FLOW, "%s: Photometric needs swapping.\n", s->tiff.file); + for (i = 0; i < s->tiff.image_size; i++) + s->tiff.image_buffer[i] = ~s->tiff.image_buffer[i]; + } + if (s->tiff.fill_order != FILLORDER_LSB2MSB) + bit_reverse(s->tiff.image_buffer, s->tiff.image_buffer, s->tiff.image_size); } -#endif s->tiff.row = 0; return s->image_length; } @@ -901,8 +960,6 @@ SPAN_DECLARE(int) t4_tx_get_chunk(t4_tx_state_t *s, uint8_t buf[], int max_len) SPAN_DECLARE(int) t4_tx_start_page(t4_tx_state_t *s) { - uint32_t image_length; - span_log(&s->logging, SPAN_LOG_FLOW, "Start tx page %d - compression %s\n", s->current_page, t4_encoding_to_str(s->line_encoding)); if (s->current_page > s->stop_page) return -1; @@ -911,7 +968,7 @@ SPAN_DECLARE(int) t4_tx_start_page(t4_tx_state_t *s) if (!TIFFSetDirectory(s->tiff.tiff_file, (tdir_t) s->current_page)) return -1; get_tiff_directory_info(s); - if ((image_length = read_tiff_image(s)) < 0) + if (read_tiff_image(s) < 0) return -1; } else diff --git a/libs/spandsp/src/t85_decode.c b/libs/spandsp/src/t85_decode.c index ff348a5fda..2cdee513f7 100644 --- a/libs/spandsp/src/t85_decode.c +++ b/libs/spandsp/src/t85_decode.c @@ -286,13 +286,13 @@ static int check_bih(t85_decode_state_t *s) #endif { span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. Fixed bytes do not contain expected values.\n"); - return T85_INVALID_DATA; + return T4_DECODE_INVALID_DATA; } /* P - Number of bit planes */ if (s->buffer[2] < s->min_bit_planes || s->buffer[2] > s->max_bit_planes) { span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. %d bit planes. Should be %d to %d.\n", s->buffer[2], s->min_bit_planes, s->max_bit_planes); - return T85_INVALID_DATA; + return T4_DECODE_INVALID_DATA; } s->bit_planes = s->buffer[2]; s->current_bit_plane = 0; @@ -302,38 +302,38 @@ static int check_bih(t85_decode_state_t *s) if (s->xd == 0 || (s->max_xd && s->xd > s->max_xd)) { span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. Width is %" PRIu32 "\n", s->xd); - return T85_INVALID_DATA; + return T4_DECODE_INVALID_DATA; } /* YD - Vertical image size at layer D */ s->yd = pack_32(&s->buffer[8]); if (s->yd == 0 || (s->max_yd && s->yd > s->max_yd)) { span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. Length is %" PRIu32 "\n", s->yd); - return T85_INVALID_DATA; + return T4_DECODE_INVALID_DATA; } /* L0 - Rows per stripe, at the lowest resolution */ s->l0 = pack_32(&s->buffer[12]); if (s->l0 == 0) { span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. L0 is %" PRIu32 "\n", s->l0); - return T85_INVALID_DATA; + return T4_DECODE_INVALID_DATA; } /* MX - Maximum horizontal offset allowed for AT pixel */ s->mx = s->buffer[16]; if (s->mx > 127) { span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. MX is %d\n", s->mx); - return T85_INVALID_DATA; + return T4_DECODE_INVALID_DATA; } /* Options byte */ s->options = s->buffer[19]; if ((s->options & 0x97)) { span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. Options are 0x%X\n", s->options); - return T85_INVALID_DATA; + return T4_DECODE_INVALID_DATA; } span_log(&s->logging, SPAN_LOG_FLOW, "BIH is OK. Image is %" PRIu32 "x%" PRIu32 " pixels\n", s->xd, s->yd); - return T85_OK; + return T4_DECODE_OK; } /*- End of function --------------------------------------------------------*/ @@ -368,7 +368,7 @@ SPAN_DECLARE(int) t85_decode_put_byte(t85_decode_state_t *s, int byte) if (byte < 0) { t85_decode_rx_status(s, byte); - return (s->y >= s->yd) ? T85_OK : T85_MORE_DATA; + return (s->y >= s->yd) ? T4_DECODE_OK : T4_DECODE_MORE_DATA; } data[0] = byte; return t85_decode_put_chunk(s, data, 1); @@ -399,8 +399,8 @@ SPAN_DECLARE(int) t85_decode_put_chunk(t85_decode_state_t *s, s->bie_len += i; cnt = i; if (s->bie_len < 20) - return T85_MORE_DATA; - if ((ret = check_bih(s)) != T85_OK) + return T4_DECODE_MORE_DATA; + if ((ret = check_bih(s)) != T4_DECODE_OK) return ret; /* Set up the two/three row buffer */ bytes_per_row = (s->xd + 7) >> 3; @@ -409,7 +409,7 @@ SPAN_DECLARE(int) t85_decode_put_chunk(t85_decode_state_t *s, { /* We need to expand the 3 row buffer */ if ((buf = (uint8_t *) realloc(s->row_buf, min_len)) == NULL) - return T85_NOMEM; + return T4_DECODE_NOMEM; s->row_buf = buf; s->row_buf_len = min_len; } @@ -500,11 +500,11 @@ SPAN_DECLARE(int) t85_decode_put_chunk(t85_decode_state_t *s, s->buf_len = 0; if (s->interrupt) - return T85_INTERRUPT; + return T4_DECODE_INTERRUPT; break; case T82_ABORT: s->buf_len = 0; - return T85_ABORTED; + return T4_DECODE_ABORTED; case T82_COMMENT: s->buf_needed = 6; if (s->buf_len < 6) @@ -531,7 +531,7 @@ SPAN_DECLARE(int) t85_decode_put_chunk(t85_decode_state_t *s, s->buf_len = 0; if (s->at_moves >= T85_ATMOVES_MAX) - return T85_INVALID_DATA; + return T4_DECODE_INVALID_DATA; s->at_row[s->at_moves] = pack_32(&s->buffer[2]); s->at_tx[s->at_moves] = s->buffer[6]; if (s->at_tx[s->at_moves] > s->mx @@ -540,7 +540,7 @@ SPAN_DECLARE(int) t85_decode_put_chunk(t85_decode_state_t *s, || s->buffer[7] != 0) { - return T85_INVALID_DATA; + return T4_DECODE_INVALID_DATA; } s->at_moves++; break; @@ -552,12 +552,12 @@ SPAN_DECLARE(int) t85_decode_put_chunk(t85_decode_state_t *s, s->buf_len = 0; if (!(s->options & T85_VLENGTH)) - return T85_INVALID_DATA; + return T4_DECODE_INVALID_DATA; s->options &= ~T85_VLENGTH; y = pack_32(&s->buffer[2]); /* An update to the image length is not allowed to stretch it. */ if (y > s->yd) - return T85_INVALID_DATA; + return T4_DECODE_INVALID_DATA; s->yd = y; break; case T82_SDNORM: @@ -567,12 +567,12 @@ SPAN_DECLARE(int) t85_decode_put_chunk(t85_decode_state_t *s, /* A plain SDNORM or SDRST with no peek ahead required */ s->buf_len = 0; if (finish_sde(s)) - return T85_INTERRUPT; + return T4_DECODE_INTERRUPT; /* Check whether this was the last SDE */ if (s->y >= s->yd) { s->compressed_image_size -= (len - cnt); - return T85_OK; + return T4_DECODE_OK; } break; } @@ -594,12 +594,12 @@ SPAN_DECLARE(int) t85_decode_put_chunk(t85_decode_state_t *s, cnt--; /* Process the T82_SDNORM or T82_SDRST */ if (finish_sde(s)) - return T85_INTERRUPT; + return T4_DECODE_INTERRUPT; /* Check whether this was the last SDE */ if (s->y >= s->yd) { s->compressed_image_size -= (len - cnt); - return T85_OK; + return T4_DECODE_OK; } break; } @@ -613,12 +613,12 @@ SPAN_DECLARE(int) t85_decode_put_chunk(t85_decode_state_t *s, /* Process the T82_SDNORM or T82_SDRST */ if (finish_sde(s)) - return T85_INTERRUPT; + return T4_DECODE_INTERRUPT; /* Check whether this was the last SDE */ if (s->y >= s->yd) { s->compressed_image_size -= (len - cnt); - return T85_OK; + return T4_DECODE_OK; } /* Recycle the two peek-ahead marker sequence bytes to be processed later. */ @@ -639,12 +639,12 @@ SPAN_DECLARE(int) t85_decode_put_chunk(t85_decode_state_t *s, y = pack_32(&s->buffer[4]); /* An update to the image length is not allowed to stretch it. */ if (y > s->yd) - return T85_INVALID_DATA; + return T4_DECODE_INVALID_DATA; /* Things look OK, so accept this new length, and proceed. */ s->yd = y; /* Now process the T82_SDNORM or T82_SDRST */ if (finish_sde(s)) - return T85_INTERRUPT; + return T4_DECODE_INTERRUPT; /* We might be at the end of the image now, but even if we are there should still be a final training T82_SDNORM or T82_SDRST that we should pick up. When we do, we won't wait for further @@ -653,7 +653,7 @@ SPAN_DECLARE(int) t85_decode_put_chunk(t85_decode_state_t *s, break; default: s->buf_len = 0; - return T85_INVALID_DATA; + return T4_DECODE_INVALID_DATA; } } else if (cnt < len && data[cnt] == T82_ESC) @@ -665,15 +665,15 @@ SPAN_DECLARE(int) t85_decode_put_chunk(t85_decode_state_t *s, /* We have found PSCD bytes */ cnt += decode_pscd(s, data + cnt, len - cnt); if (s->interrupt) - return T85_INTERRUPT; + return T4_DECODE_INTERRUPT; /* We should only have stopped processing PSCD if we ran out of data, or hit a T82_ESC */ if (cnt < len && data[cnt] != T82_ESC) - return T85_INVALID_DATA; + return T4_DECODE_INVALID_DATA; } } - return T85_MORE_DATA; + return T4_DECODE_MORE_DATA; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/tests/image_translate_tests.c b/libs/spandsp/tests/image_translate_tests.c index be0f5ea18c..8c3f55f077 100644 --- a/libs/spandsp/tests/image_translate_tests.c +++ b/libs/spandsp/tests/image_translate_tests.c @@ -213,7 +213,7 @@ static void dither_tests_gray16(void) image[i*im.width + j] = j*1200; } - s = image_translate_init(s, IMAGE_TRANSLATE_FROM_GRAY_16, im.width, im.length, -1, row_read, &im); + s = image_translate_init(s, IMAGE_TRANSLATE_FROM_GRAY_16, im.width, im.length, -1, -1, row_read, &im); get_flattened_image(s, TRUE); } /*- End of function --------------------------------------------------------*/ @@ -239,7 +239,7 @@ static void dither_tests_gray8(void) for (j = 0; j < im.width; j++) image[i*im.width + j] = j*1200/256; } - s = image_translate_init(s, IMAGE_TRANSLATE_FROM_GRAY_8, im.width, im.length, -1, row_read, &im); + s = image_translate_init(s, IMAGE_TRANSLATE_FROM_GRAY_8, im.width, im.length, -1, -1, row_read, &im); get_flattened_image(s, TRUE); } /*- End of function --------------------------------------------------------*/ @@ -269,7 +269,7 @@ static void dither_tests_colour16(void) image[i*3*im.width + 3*j + 2] = j*1200; } } - s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_16, im.width, im.length, -1, row_read, &im); + s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_16, im.width, im.length, -1, -1, row_read, &im); get_flattened_image(s, TRUE); } /*- End of function --------------------------------------------------------*/ @@ -300,7 +300,7 @@ static void dither_tests_colour8(void) } } - s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_8, im.width, im.length, -1, row_read, &im); + s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_8, im.width, im.length, -1, -1, row_read, &im); get_flattened_image(s, TRUE); } /*- End of function --------------------------------------------------------*/ @@ -331,13 +331,13 @@ static void grow_tests_colour8(void) } } - s1 = image_translate_init(s1, IMAGE_TRANSLATE_FROM_COLOUR_8, im.width, im.length, 200, row_read, &im); + s1 = image_translate_init(s1, IMAGE_TRANSLATE_FROM_COLOUR_8, im.width, im.length, 200, -1, row_read, &im); get_flattened_image(s1, FALSE); } /*- End of function --------------------------------------------------------*/ -static void lenna_tests(int output_width, const char *file) +static void lenna_tests(int output_width, int output_length_scaling, const char *file) { TIFF *in_file; TIFF *out_file; @@ -355,6 +355,9 @@ static void lenna_tests(int output_width, const char *file) image_translate_state_t bw; image_translate_state_t *s = &bw; image_descriptor_t im; + float x_resolution; + float y_resolution; + uint16_t res_unit; printf("Dithering Lenna from colour to bi-level test\n"); if ((in_file = TIFFOpen(INPUT_TIFF_FILE_NAME, "r")) == NULL) @@ -367,11 +370,17 @@ static void lenna_tests(int output_width, const char *file) TIFFGetField(in_file, TIFFTAG_IMAGELENGTH, &image_length); if (image_length <= 0) return; + x_resolution = 200.0; + TIFFGetField(in_file, TIFFTAG_XRESOLUTION, &x_resolution); + y_resolution = 200.0; + TIFFGetField(in_file, TIFFTAG_YRESOLUTION, &y_resolution); + res_unit = RESUNIT_INCH; + TIFFSetField(in_file, TIFFTAG_RESOLUTIONUNIT, &res_unit); bits_per_sample = 0; TIFFGetField(in_file, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); samples_per_pixel = 0; TIFFGetField(in_file, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel); - printf("Original image is %d x %d, %d bits per sample, %d samples per pixel\n", image_width, image_length, bits_per_sample, samples_per_pixel); + printf("Original image is %d x %d, %f x %f resolution, %d bits per sample, %d samples per pixel\n", image_width, image_length, x_resolution, y_resolution, bits_per_sample, samples_per_pixel); if ((image = malloc(image_width*image_length*samples_per_pixel)) == NULL) return; for (total = 0, i = 0; i < 1000; i++) @@ -389,13 +398,18 @@ static void lenna_tests(int output_width, const char *file) printf("Image size %d %d\n", total, image_width*image_length*samples_per_pixel); TIFFClose(in_file); + if (output_length_scaling > 0) + output_length = (double) image_length*output_length_scaling*output_width/image_width; + else + output_length = -1; + im.image = image; im.width = image_width; im.length = image_length; im.current_row = 0; im.bytes_per_pixel = samples_per_pixel; - s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_8, image_width, image_length, output_width, row_read, &im); + s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_8, image_width, image_length, output_width, output_length, row_read, &im); output_width = image_translate_get_output_width(s); output_length = image_translate_get_output_length(s); @@ -403,6 +417,11 @@ static void lenna_tests(int output_width, const char *file) return; TIFFSetField(out_file, TIFFTAG_IMAGEWIDTH, output_width); TIFFSetField(out_file, TIFFTAG_IMAGELENGTH, output_length); + TIFFSetField(out_file, TIFFTAG_XRESOLUTION, x_resolution); + if (output_length_scaling > 0) + y_resolution *= output_length_scaling; + TIFFSetField(out_file, TIFFTAG_YRESOLUTION, y_resolution); + TIFFSetField(out_file, TIFFTAG_RESOLUTIONUNIT, res_unit); TIFFSetField(out_file, TIFFTAG_BITSPERSAMPLE, 1); TIFFSetField(out_file, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(out_file, TIFFTAG_SAMPLESPERPIXEL, 1); @@ -441,9 +460,10 @@ int main(int argc, char **argv) grow_tests_colour8(); #endif #if 1 - lenna_tests(0, "lenna-bw.tif"); - lenna_tests(1728, "lenna-bw-1728.tif"); - lenna_tests(200, "lenna-bw-200.tif"); + lenna_tests(0, 0, "lenna-bw.tif"); + lenna_tests(200, 0, "lenna-bw-200.tif"); + lenna_tests(1728, 0, "lenna-bw-1728.tif"); + lenna_tests(1728, 2, "lenna-bw-1728-superfine.tif"); #endif printf("Tests passed.\n"); return 0; diff --git a/libs/spandsp/tests/t42_tests.c b/libs/spandsp/tests/t42_tests.c index 1ccefed9f0..c0d494c8ce 100644 --- a/libs/spandsp/tests/t42_tests.c +++ b/libs/spandsp/tests/t42_tests.c @@ -45,7 +45,8 @@ #include "spandsp.h" -#define IN_FILE_NAME "../test-data/itu/t24/F21_200.TIF" +//#define IN_FILE_NAME "../test-data/itu/t24/F21_200.TIF" +#define IN_FILE_NAME "../test-data/itu/t24/F21B400.TIF" #define OUT_FILE_NAME "t42_tests_receive.tif" uint8_t data5[50000000]; @@ -59,55 +60,6 @@ lab_params_t lab_param; int write_row = 0; -typedef struct -{ - float L; - float a; - float b; -} cielab_t; - -#if 0 -static void generate_luts(void) -{ - float r; - uint8_t srgb; - int i; - - printf("static const float srgb_to_linear[256] =\n"); - printf("{\n"); - for (i = 0; i < 256; i++) - { - /* Start with "i" as the sRGB value */ - r = i/256.0f; - - /* sRGB to Linear RGB */ - r = (r > 0.04045f) ? powf((r + 0.055f)/1.055f, 2.4f) : r/12.92f; - - printf((i < 255) ? " %f,\n" : " %f\n", r); - } - printf("};\n"); - - printf("static const uint8_t linear_to_srgb[4096] =\n"); - printf("{\n"); - for (i = 0; i < 4096; i++) - { - /* Start with "i" as the linear RGB value */ - /* Linear RGB to sRGB */ - r = i/4096.0f; - - r = (r > 0.0031308f) ? (1.055f*powf(r, 1.0f/2.4f) - 0.055f) : r*12.92f; - - r = floorf(r*256.0f); - - srgb = (r < 0) ? 0 : (r <= 255) ? r : 255; - - printf((i < 4095) ? " %d,\n" : " %d\n", srgb); - } - printf("};\n"); -} -/*- End of function --------------------------------------------------------*/ -#endif - static __inline__ uint16_t pack_16(uint8_t *s) { uint16_t value; @@ -159,7 +111,6 @@ static int t85_comment_handler(void *user_data, const uint8_t buf[], size_t len) int main(int argc, char *argv[]) { - char kk[256]; TIFF *tif; uint32_t w; uint32_t h; @@ -194,18 +145,17 @@ int main(int argc, char *argv[]) uint16_t *yyya; uint16_t *yyyb; uint16_t *yyyz; + logging_state_t *logging; printf("Demo of ITU/Lab library.\n"); + logging = span_log_init(NULL, SPAN_LOG_FLOW, "T.42"); + TIFF_FX_init(); set_lab_illuminant(&lab_param, 0.9638f, 1.0f, 0.8245f); set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, FALSE); -#if 0 - generate_luts(); -#endif - source_file = (argc > 1) ? argv[1] : IN_FILE_NAME; /* sRGB to ITU */ if ((tif = TIFFOpen(source_file, "r")) == NULL) @@ -307,6 +257,7 @@ int main(int argc, char *argv[]) printf("Unexpected compression %d\n", compression); break; } + if (process_raw) { nstrips = TIFFNumberOfStrips(tif); @@ -337,7 +288,7 @@ int main(int argc, char *argv[]) t85_decode_init(&t85_dec, t85_row_write_handler, NULL); t85_decode_set_comment_handler(&t85_dec, 1000, t85_comment_handler, NULL); result = t85_decode_put_chunk(&t85_dec, data, total_len); - if (result == T85_MORE_DATA) + if (result == T4_DECODE_MORE_DATA) result = t85_decode_put_byte(&t85_dec, SIG_STATUS_END_OF_DATA); len = t85_decode_get_compressed_image_size(&t85_dec); printf("Compressed image is %d bytes, %d rows\n", len/8, write_row); @@ -396,7 +347,7 @@ int main(int argc, char *argv[]) len = t85_decode_get_compressed_image_size(&t85_dec); printf("Compressed image is %d bytes, %d rows\n", len/8, write_row); } - if (result == T85_MORE_DATA) + if (result == T4_DECODE_MORE_DATA) { printf("More\n"); result = t85_decode_put_byte(&t85_dec, SIG_STATUS_END_OF_DATA); @@ -435,7 +386,7 @@ int main(int argc, char *argv[]) TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); TIFFSetField(tif, TIFFTAG_SOFTWARE, "spandsp"); TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, "Test"); - TIFFSetField(tif, TIFFTAG_DATETIME, "2011/02/03 12:30:45"); + TIFFSetField(tif, TIFFTAG_DATETIME, "2012/07/03 12:30:45"); TIFFSetField(tif, TIFFTAG_MAKE, "soft-switch.org"); TIFFSetField(tif, TIFFTAG_MODEL, "spandsp"); TIFFSetField(tif, TIFFTAG_HOSTCOMPUTER, "i7.coppice.org"); @@ -477,9 +428,9 @@ int main(int argc, char *argv[]) { printf("YYY ITULAB\n"); - if (!t42_itulab_to_itulab((tdata_t) &outptr, &outsize, data, off, w, h, kk, 256)) + if (!t42_itulab_to_itulab(logging, (tdata_t) &outptr, &outsize, data, off, w, h)) { - printf("Failed to convert to ITULAB - %s\n", kk); + printf("Failed to convert to ITULAB\n"); return 1; } free(data); @@ -500,9 +451,9 @@ int main(int argc, char *argv[]) set_lab_illuminant(&lab_param, 0.9638f, 1.0f, 0.8245f); set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, FALSE); - if (!t42_srgb_to_itulab(&lab_param, (tdata_t) &outptr, &outsize, data, off, w, h, kk, 256)) + if (!t42_srgb_to_itulab(logging, &lab_param, (tdata_t) &outptr, &outsize, data, off, w, h)) { - printf("Failed to convert to ITULAB - %s\n", kk); + printf("Failed to convert to ITULAB\n"); return 1; } end = rdtscll(); @@ -539,7 +490,7 @@ int main(int argc, char *argv[]) TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); TIFFSetField(tif, TIFFTAG_SOFTWARE, "spandsp"); TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, "Test"); - TIFFSetField(tif, TIFFTAG_DATETIME, "2011/02/03 12:30:45"); + TIFFSetField(tif, TIFFTAG_DATETIME, "2012/07/03 12:30:45"); TIFFSetField(tif, TIFFTAG_MAKE, "soft-switch.org"); TIFFSetField(tif, TIFFTAG_MODEL, "spandsp"); TIFFSetField(tif, TIFFTAG_HOSTCOMPUTER, "i7.coppice.org"); @@ -564,22 +515,22 @@ int main(int argc, char *argv[]) start = rdtscll(); data2 = NULL; totdata = 0; - t42_itulab_to_JPEG(&lab_param, (void **) &data2, &totdata, data, off, kk, 256); + t42_itulab_to_jpeg(logging, &lab_param, (void **) &data2, &totdata, data, off); end = rdtscll(); printf("Duration %" PRIu64 "\n", end - start); printf("Compressed length %d (%p)\n", totdata, data2); if (TIFFWriteRawStrip(tif, 0, data2, totdata) < 0) { - printf("Failed to convert from ITULAB - %s\n", kk); + printf("Failed to convert from ITULAB\n"); return 1; } free(data); #else data2 = malloc(totdata); start = rdtscll(); - if (!t42_itulab_to_srgb(&lab_param, data2, &off, data, off, &w, &h, kk, 256)) + if (!t42_itulab_to_srgb(logging, &lab_param, data2, &off, data, off, &w, &h)) { - printf("Failed to convert from ITULAB - %s\n", kk); + printf("Failed to convert from ITULAB\n"); return 1; } end = rdtscll(); diff --git a/libs/spandsp/tests/t4_t6_tests.c b/libs/spandsp/tests/t4_t6_tests.c index 38c4750f21..52eef26c19 100644 --- a/libs/spandsp/tests/t4_t6_tests.c +++ b/libs/spandsp/tests/t4_t6_tests.c @@ -293,27 +293,32 @@ int main(int argc, char *argv[]) properly. */ min_row_bits = 50; block_size = 0; - while ((opt = getopt(argc, argv, "126b:m:")) != -1) + while ((opt = getopt(argc, argv, "b:c:m:")) != -1) { switch (opt) { - case '1': - compression = T4_COMPRESSION_ITU_T4_1D; - compression_step = -1; - break; - case '2': - compression = T4_COMPRESSION_ITU_T4_2D; - compression_step = -1; - break; - case '6': - compression = T4_COMPRESSION_ITU_T6; - compression_step = -1; - break; case 'b': block_size = atoi(optarg); if (block_size > 1024) block_size = 1024; break; + case 'c': + if (strcmp(optarg, "T41D") == 0) + { + compression = T4_COMPRESSION_ITU_T4_1D; + compression_step = -1; + } + else if (strcmp(optarg, "T42D") == 0) + { + compression = T4_COMPRESSION_ITU_T4_2D; + compression_step = -1; + } + else if (strcmp(optarg, "T6") == 0) + { + compression = T4_COMPRESSION_ITU_T6; + compression_step = -1; + } + break; case 'm': min_row_bits = atoi(optarg); break; diff --git a/libs/spandsp/tests/t4_tests.c b/libs/spandsp/tests/t4_tests.c index 5bbf0555ac..b47530068d 100644 --- a/libs/spandsp/tests/t4_tests.c +++ b/libs/spandsp/tests/t4_tests.c @@ -542,7 +542,7 @@ int main(int argc, char *argv[]) #if 1 printf("Testing image_function->compress->decompress->image_function\n"); /* Send end gets image from a function */ - if (t4_tx_init(&send_state, FALSE, -1, -1) == NULL) + if (t4_tx_init(&send_state, NULL, -1, -1) == NULL) { printf("Failed to init T.4 tx\n"); exit(2); @@ -680,9 +680,6 @@ int main(int argc, char *argv[]) exit(2); } span_log_set_level(&receive_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW); - t4_rx_set_x_resolution(&receive_state, t4_tx_get_x_resolution(&send_state)); - t4_rx_set_y_resolution(&receive_state, t4_tx_get_y_resolution(&send_state)); - t4_rx_set_image_width(&receive_state, t4_tx_get_image_width(&send_state)); /* Now send and receive all the pages in the source TIFF file */ sends = 0; @@ -725,6 +722,9 @@ int main(int argc, char *argv[]) if (t4_tx_start_page(&send_state)) break; + t4_rx_set_x_resolution(&receive_state, t4_tx_get_x_resolution(&send_state)); + t4_rx_set_y_resolution(&receive_state, t4_tx_get_y_resolution(&send_state)); + t4_rx_set_image_width(&receive_state, t4_tx_get_image_width(&send_state)); } t4_rx_start_page(&receive_state); detect_page_end(-1000000, compression); diff --git a/libs/spandsp/tests/t85_tests.c b/libs/spandsp/tests/t85_tests.c index 832ee816fc..3e60507c1a 100644 --- a/libs/spandsp/tests/t85_tests.c +++ b/libs/spandsp/tests/t85_tests.c @@ -262,11 +262,11 @@ static int test_cycle(const char *test_id, t85_decode_set_comment_handler(&t85_dec, 1000, comment_handler, NULL); write_row = 0; result = t85_decode_put_chunk(&t85_dec, testbuf, testbuf_len); - if (result == T85_MORE_DATA) + if (result == T4_DECODE_MORE_DATA) result = t85_decode_put_byte(&t85_dec, SIG_STATUS_END_OF_DATA); cnt_a = t85_encode_get_compressed_image_size(&t85_enc); cnt_b = t85_decode_get_compressed_image_size(&t85_dec); - if (cnt_a != cnt_b || cnt_a != testbuf_len*8 || result != T85_OK) + if (cnt_a != cnt_b || cnt_a != testbuf_len*8 || result != T4_DECODE_OK) { printf("Decode result %d\n", result); printf("%ld/%ld bits of %ld bits of BIE read. %lu lines decoded.\n", @@ -297,19 +297,19 @@ static int test_cycle(const char *test_id, if (comment && comment[0] != 'X') t85_decode_set_comment_handler(&t85_dec, 1000, comment_handler, NULL); write_row = 0; - result = T85_MORE_DATA; + result = T4_DECODE_MORE_DATA; for (l = 0; l < testbuf_len; l++) { result = t85_decode_put_chunk(&t85_dec, &testbuf[l], 1); - if (result != T85_MORE_DATA) + if (result != T4_DECODE_MORE_DATA) { l++; break; } } - if (result == T85_MORE_DATA) + if (result == T4_DECODE_MORE_DATA) result = t85_decode_put_byte(&t85_dec, SIG_STATUS_END_OF_DATA); - if (l != testbuf_len || result != T85_OK) + if (l != testbuf_len || result != T4_DECODE_OK) { printf("Decode result %d\n", result); printf("%ld bytes of %ld bytes of BIE read. %lu lines decoded.\n",