]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FAX T.6 decompression fixed for images with black in the last pixel of lines.
authorSteve Underwood <steveu@coppice.org>
Fri, 3 Aug 2012 19:45:09 +0000 (03:45 +0800)
committerSteve Underwood <steveu@coppice.org>
Fri, 3 Aug 2012 19:45:09 +0000 (03:45 +0800)
Colour and grey images can down be dithered down to bi-level images for transmission as faxes.
More movement towards T.42 support

29 files changed:
libs/spandsp/src/Makefile.am
libs/spandsp/src/cielab_luts.h
libs/spandsp/src/fax.c
libs/spandsp/src/image_translate.c
libs/spandsp/src/make_cielab_luts.c [new file with mode: 0644]
libs/spandsp/src/spandsp/image_translate.h
libs/spandsp/src/spandsp/private/t42.h
libs/spandsp/src/spandsp/private/t4_tx.h
libs/spandsp/src/spandsp/private/t85.h
libs/spandsp/src/spandsp/t42.h
libs/spandsp/src/spandsp/t4_rx.h
libs/spandsp/src/spandsp/t85.h
libs/spandsp/src/t30.c
libs/spandsp/src/t30_api.c
libs/spandsp/src/t30_logging.c
libs/spandsp/src/t38_gateway.c
libs/spandsp/src/t38_terminal.c
libs/spandsp/src/t42.c
libs/spandsp/src/t42_t43_local.h [new file with mode: 0644]
libs/spandsp/src/t4_rx.c
libs/spandsp/src/t4_t6_decode.c
libs/spandsp/src/t4_t6_encode.c
libs/spandsp/src/t4_tx.c
libs/spandsp/src/t85_decode.c
libs/spandsp/tests/image_translate_tests.c
libs/spandsp/tests/t42_tests.c
libs/spandsp/tests/t4_t6_tests.c
libs/spandsp/tests/t4_tests.c
libs/spandsp/tests/t85_tests.c

index 685e3d932801858fb40e18c0b226a2ac0e8465ea..95e9932c3c239b9afd800a48e87079397bf184b4 100644 (file)
@@ -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
 
index 73e72ac8247570a4c2e3f5c185a3ee4249b1cabb..0a3c69791532c7605f5bc8825ce8f20f89bc8afa 100644 (file)
@@ -1,32 +1,4 @@
-/*
- * SpanDSP - a series of DSP components for telephony
- *
- * cielab_luts.h
- *
- * Written by Steve Underwood <steveu@coppice.org>
- *
- * 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 ------------------------------------------------------------*/
index abe25675ce3cd05e2be1ae2436e8b60eed0f2678..19bf4cf5e6f28e27fa72152c0cd591a9fe04dcf9 100644 (file)
@@ -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)
 #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"
index d21b5b9d815ea987bc1171fd03af1b112985eecc..db6a7adc0e8bba90426c773dccbf0b4efc95d44c 100644 (file)
@@ -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 (file)
index 0000000..9050056
--- /dev/null
@@ -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 <steveu@coppice.org>
+ *
+ * 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 <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <memory.h>
+#if defined(HAVE_TGMATH_H)
+#include <tgmath.h>
+#endif
+#if defined(HAVE_MATH_H)
+#include <math.h>
+#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 ------------------------------------------------------------*/
index b795c705af6b8a38e3a9bcaa0d5003569364e360..80f29f04712d96460d0efef734514dc2ca4b9bc1 100644 (file)
@@ -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);
 
index 7dedfa7ee18e14583a37e414959ae5f46ea8f3da..bfdae884ebe941b5c8b820b1d6d3d15c599101ce 100644 (file)
@@ -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;
 };
index ffa3c342d8b5cfb1a16c468616332dbb8b9cd5a6..b7b5d11eff667d05fdf1199687dfc3a7d6509e9b 100644 (file)
@@ -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;
 
index dac7a3340a37ce3cf3c473f6126bfbd234c49d18..2d180c9baf335fdffb61d2bc30cb5499749e44ac 100644 (file)
@@ -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 */
index d6785cba23588f8130cde153a30aca963d6e204e..e072b074423b1036ad634a8313c6a4b47fdbaaf6 100644 (file)
@@ -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,
index 8ff1e286e0c8a198879e9adb33aa181a6967945e..0d372485932393f6313fcc9fe1ddd9c8e2793a60 100644 (file)
@@ -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.
index 516f6ee0e7756cb918d5c7bca850f80813be7944..3ad36cdfdda147ef4ca8478b4c0f462634635c6b 100644 (file)
@@ -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;
 
index 8a20c3996d0008c4048bdba86f687eefbde55f3e..ec2852ef42df609b4b9d20551e421db4d184959a 100644 (file)
@@ -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,40 +2073,60 @@ 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_T85_L0;
+            s->line_encoding = T4_COMPRESSION_ITU_T4_2D;
         }
         else
         {
-            s->line_encoding = T4_COMPRESSION_ITU_T85;
+            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;
+#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
+        {
+            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;
+            }
+        }
     }
     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;
index 9da3e25bccb6acf6b75bfc2d6632e3c3ad96016b..ad7cb0e71c93c090be986dc44e82e712a313f88a 100644 (file)
@@ -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
index 9c53b0103707776b4215f6d2d9327130f04bf954..9328c9b8f38be53089ed412e96500d9299f2394b 100644 (file)
@@ -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"
index 205bc1b5bb2bcb7aa2608f3192ae2fcbad1f031e..e3c99a634a028665c1f28667de3090492a3269a2 100644 (file)
@@ -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)
 #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"
index 675c895a2ff6e8af6790d12be92cb1308d62e066..d16e3cd5697ff9983b28858257ed4f8fae9b812d 100644 (file)
@@ -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"
index 608341fd4ca6acd4cac887c90b932115ce7d262f..f7f7e1e06270a6d2b5c5fe8322678c1f31430256 100644 (file)
 
 #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;
+    }
+    outsize = 0;
+    if ((out = open_memstream(&outptr, &outsize)) == NULL)
+    {
+        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;
     }
-
-#if defined(HAVE_OPEN_MEMSTREAM)
-    out = open_memstream(&outptr, &outsize);
 #else
-    out = tmpfile();
-#endif
-    if (out == NULL)
+    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)
     {
-        if (emsg[0] == '\0')
-            strcpy(emsg, "Failed to open_memstream().");
+        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;
+    }
+    outsize = 0;
+    if ((out = open_memstream(&outptr, &outsize)) == NULL)
+    {
+        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;
     }
-
-#if defined(HAVE_OPEN_MEMSTREAM)
-    out = open_memstream(&outptr, &outsize);
 #else
-    out = tmpfile();
-#endif
-    if (out == NULL)
+    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)
     {
-        if (emsg[0] == '\0')
-            strcpy(emsg, "Failed to open_memstream().");
+        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);
+    outsize = 0;
+    if ((out = open_memstream(&outptr, &outsize)) == NULL)
+    {
+        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
-    out = tmpfile();
-#endif
-    if (out == NULL)
+    if ((out = tmpfile()) == NULL)
     {
-        if (emsg[0] == '\0')
-            strcpy(emsg, "Failed to open_memstream().");
+        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);
+    outsize = 0;
+    if ((out = open_memstream(&outptr, &outsize)) == NULL)
+    {
+        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
-    out = tmpfile();
-#endif
-    if (out == NULL)
+    if ((out = tmpfile()) == NULL)
     {
-        if (emsg[0] == '\0')
-            strcpy(emsg, "Failed to open_memstream().");
+        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");
+    if ((in = fmemopen(src, srclen, "r")) == NULL)
+    {
+        span_log(logging, SPAN_LOG_FLOW, "Failed to fmemopen().\n");
+        return FALSE;
+    }
 #else
-    in = tmpfile();
-    fwrite(src, 1, srclen, in);
-    rewind(in);
-#endif
-    if (in == NULL)
+    if ((in = tmpfile()) == NULL)
+    {
+        span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n");
+        return FALSE;
+    }
+    if (fwrite(src, 1, srclen, in) != srclen)
     {
-        if (emsg[0] == '\0')
-            strcpy(emsg, "Failed to fmemopen().");
+        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 (file)
index 0000000..6eec67c
--- /dev/null
@@ -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 <steveu@coppice.org>
+ *
+ * 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 ------------------------------------------------------------*/
index 74dd152b7cc2b2a42895b7f3222e42cb4ea2a401..4e096e637136f85b026ebf2af7c064e15d620b9a 100644 (file)
@@ -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 --------------------------------------------------------*/
 
index ceb2af28f618c93a1e346a6101b18d912cfa215d..b3c96222b871a1f7edddc3bf755ff488ba5a4917 100644 (file)
@@ -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)
 #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);
index 51103e522d684b927619e895f9f3a86414ec3eb3..59dbd251e9983a51a1a41d837f241967df60fa9f 100644 (file)
@@ -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)
 #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 --------------------------------------------------------*/
index 3961bfa94d706771ca1b397b959b3d217a3e7bf7..d1060f8a82eae6b5f6a452fb09bb8e92f5401dc0 100644 (file)
@@ -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 ((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)
+        {
+            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);
     }
-
-#if 1
-    for (i = 0, total_len = 0;  total_len < s->tiff.image_size;  i++, total_len += len)
+    else
     {
-        if ((len = TIFFReadEncodedStrip(s->tiff.tiff_file, i, &s->tiff.image_buffer[total_len], s->tiff.image_size - total_len)) < 0)
+        s->tiff.image_size = s->image_length*TIFFScanlineSize(s->tiff.tiff_file);
+        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;
+        }
+
+        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
index ff348a5fdad22843cdd87c03570b34d3fb37b259..2cdee513f7b719552ef31f09e44e37eb37a5d438 100644 (file)
@@ -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 --------------------------------------------------------*/
 
index be0f5ea18c79375467882c7f18fa88d9345fdf17..8c3f55f0776c5f0d90942948b15141afc3a2fb1c 100644 (file)
@@ -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;
index 1ccefed9f066a98f6c4e8687deec3c8dca0a5254..c0d494c8ce9380709a2842635cf4bc4faa3e59b5 100644 (file)
@@ -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();
index 38c4750f21524c759b80bf4a62f542e2e8779821..52eef26c199f59564d79c359ba2b83b983ac3e09 100644 (file)
@@ -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;
index 5bbf0555ac104384d11a296f798390dc0c971234..b47530068d0c565c5d6599bc063e8c03b7c7437b 100644 (file)
@@ -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);
index 832ee816fcb9d6e1c8ca95c70a52a379d75d7847..3e60507c1a9f00f22e36f4b59916b7939566bd8e 100644 (file)
@@ -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",