]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Minor tweaks from cleaning up spandsp
authorSteve Underwood <steveu@coppice.org>
Fri, 31 May 2013 17:05:08 +0000 (01:05 +0800)
committerSteve Underwood <steveu@coppice.org>
Fri, 31 May 2013 17:05:08 +0000 (01:05 +0800)
13 files changed:
libs/spandsp/configure.ac
libs/spandsp/src/g722.c
libs/spandsp/src/spandsp/g722.h
libs/spandsp/src/t30_api.c
libs/spandsp/src/t42.c
libs/spandsp/src/t43.c
libs/spandsp/tests/Makefile.am
libs/spandsp/tests/fax_tests.c
libs/spandsp/tests/fax_tests.sh
libs/spandsp/tests/image_translate_tests.c
libs/spandsp/tests/t42_tests.c
libs/spandsp/tests/t43_tests.c [new file with mode: 0644]
libs/spandsp/tests/udptl.c

index 63bca1dd7fd6f81e78ad9926d06aee6aabb83a64..bfdf80381e9e985708f9860501a141f6ad890b14 100644 (file)
@@ -257,10 +257,10 @@ then
     esac
 fi
 
-#AC_DEFINE([SPANDSP_SUPPORT_T42], [1], [Support T.42 JPEG compression])
-SPANDSP_SUPPORT_T42="#undef SPANDSP_SUPPORT_T42"
-#AC_DEFINE([SPANDSP_SUPPORT_T43], [1], [Support T.43 JBIG gray and colour compression])
-SPANDSP_SUPPORT_T43="#undef SPANDSP_SUPPORT_T43"
+AC_DEFINE([SPANDSP_SUPPORT_T42], [1], [Support T.42 JPEG compression])
+SPANDSP_SUPPORT_T42="#define SPANDSP_SUPPORT_T42 1"
+AC_DEFINE([SPANDSP_SUPPORT_T43], [1], [Support T.43 JBIG gray and colour compression])
+SPANDSP_SUPPORT_T43="#define SPANDSP_SUPPORT_T43 1"
 #AC_DEFINE([SPANDSP_SUPPORT_V32BIS], [1], [Support the V.32bis modem])
 SPANDSP_SUPPORT_V32BIS="#undef SPANDSP_SUPPORT_V32BIS"
 #AC_DEFINE([SPANDSP_SUPPORT_V34], [1], [Support the V.34 FAX modem])
index f223592dc8dd2ae121aa906a350fda2f1448d1dc..22715cfa4acb076f687d9cc9642a73b7eaa6a133 100644 (file)
  * 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.
- *
- * Based in part on a single channel G.722 codec which is:
- *
- * Copyright (c) CMU 1993
- * Computer Science, Speech Group
- * Chengxiang Lu and Alex Hauptmann
  */
 
 /*! \file */
index 1716e0a0dbda0e3747ed4192a60ea8c04be1b673..ee36c456ca250a5a73bafefd653cb98a43aa1c06 100644 (file)
  * 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.
- *
- * Based on a single channel G.722 codec which is:
- *
- *****    Copyright (c) CMU    1993      *****
- * Computer Science, Speech Group
- * Chengxiang Lu and Alex Hauptmann
  */
 
-
 /*! \file */
 
 #if !defined(_SPANDSP_G722_H_)
index 9f16eec14160c98627aab354a3937f6be15d43cc..af90452d91232b0fcc411b7e3a1041402aaad97c 100644 (file)
@@ -690,9 +690,24 @@ SPAN_DECLARE(int) t30_set_supported_compressions(t30_state_t *s, int supported_c
                             | T4_SUPPORT_COMPRESSION_T6
                             | T4_SUPPORT_COMPRESSION_T85
                             | T4_SUPPORT_COMPRESSION_T85_L0
+#if defined(SPANDSP_SUPPORT_T88)
+                            | T4_SUPPORT_COMPRESSION_T88
+#endif
                             //| T4_SUPPORT_COMPRESSION_T81
 #if defined(SPANDSP_SUPPORT_T43)
                             | T4_SUPPORT_COMPRESSION_T43
+#endif
+#if defined(SPANDSP_SUPPORT_T45)
+                            | T4_SUPPORT_COMPRESSION_T45
+#endif
+#if 0
+                            | T4_SUPPORT_COMPRESSION_GRAYSCALE
+                            | T4_SUPPORT_COMPRESSION_COLOUR
+                            | T4_SUPPORT_COMPRESSION_12BIT
+                            | T4_SUPPORT_COMPRESSION_COLOUR_TO_GRAY
+                            | T4_SUPPORT_COMPRESSION_GRAY_TO_BILEVEL
+                            | T4_SUPPORT_COMPRESSION_COLOUR_TO_BILEVEL
+                            | T4_SUPPORT_COMPRESSION_RESCALING
 #endif
                             | 0;
     s->supported_compressions = supported_compressions;
index a1547a6f8545ea01ef33756d2a58d97014c3acf3..8d0023f7d7fd69c35ee8595dfc6ec66257747d1b 100644 (file)
@@ -48,7 +48,6 @@
 #include "floating_fudge.h"
 #include <tiffio.h>
 #include <assert.h>
-#include <jpeglib.h>
 
 #include "spandsp/telephony.h"
 #include "spandsp/fast_convert.h"
@@ -719,15 +718,17 @@ static void jpg_encode_error_exit(j_common_ptr cinfo)
 /*- End of function --------------------------------------------------------*/
 
 /* This is the error catcher */
-#ifndef WIN32
 static struct jpeg_error_mgr encode_error_handler =
 {
+#if defined(_MSC_VER)  ||  defined(__sunos)  ||  defined(__solaris)  ||  defined(__sun)
+    jpg_encode_error_exit,
+    0,
+    jpg_encode_error_exit
+#else
     .error_exit = jpg_encode_error_exit,
     .output_message = jpg_encode_error_exit
-};
-#else
-static struct jpeg_error_mgr encode_error_handler = {jpg_encode_error_exit,0,jpg_encode_error_exit};
 #endif
+};
 
 static int t42_srgb_to_itulab_jpeg(t42_encode_state_t *s)
 {
@@ -1032,15 +1033,17 @@ static void jpg_decode_error_exit(j_common_ptr cinfo)
 /*- End of function --------------------------------------------------------*/
 
 /* This is the error catcher */
-#ifndef WIN32
 static struct jpeg_error_mgr decode_error_handler =
 {
+#if defined(_MSC_VER)  ||  defined(__sunos)  ||  defined(__solaris)  ||  defined(__sun)
+    jpg_decode_error_exit,
+    0,
+    jpg_decode_error_exit
+#else
     .error_exit = jpg_decode_error_exit,
     .output_message = jpg_decode_error_exit
-};
-#else
-static struct jpeg_error_mgr decode_error_handler = {jpg_decode_error_exit,0,jpg_decode_error_exit};
 #endif
+};
 
 static int t42_itulab_jpeg_to_srgb(t42_decode_state_t *s)
 {
index d81e8da25c969d6ba8ad22671ac8bd6c676058c3..b0e1abffb9c847bca7a2984fa8ac8b8823bac3e6 100644 (file)
@@ -41,7 +41,6 @@
 #endif
 #include <time.h>
 #include "floating_fudge.h"
-#include <jpeglib.h>
 #include <setjmp.h>
 
 #include "spandsp/telephony.h"
index 651c82f33ccaa3c925e4eb9daedbb53d107383bd..e35408c3b7a87649f40cd4575df4dbf775353aa9 100644 (file)
@@ -112,6 +112,7 @@ noinst_PROGRAMS =   ademco_contactid_tests \
                     t4_tests \
                     t4_t6_tests \
                     t42_tests \
+                    t43_tests \
                     t81_t82_arith_coding_tests \
                     t85_tests \
                     time_scale_tests \
@@ -325,6 +326,9 @@ t4_t6_tests_LDADD = $(LIBDIR) -lspandsp
 t42_tests_SOURCES = t42_tests.c
 t42_tests_LDADD = $(LIBDIR) -lspandsp
 
+t43_tests_SOURCES = t43_tests.c
+t43_tests_LDADD = $(LIBDIR) -lspandsp
+
 t81_t82_arith_coding_tests_SOURCES = t81_t82_arith_coding_tests.c
 t81_t82_arith_coding_tests_LDADD = $(LIBDIR) -lspandsp
 
index 49958571a9f47b7580aab48d262c495782574938..bea71ca2db4a826984e2f7238bafe0de555ecbbf 100644 (file)
@@ -490,6 +490,7 @@ int main(int argc, char *argv[])
     int noise_level;
     int code_to_look_up;
     int scan_line_time;
+    int colour_enabled;
     t38_stats_t t38_stats;
     t30_stats_t t30_stats;
     logging_state_t *logging;
@@ -528,14 +529,18 @@ int main(int argc, char *argv[])
     scan_line_time = 0;
     decode_file_name = NULL;
     code_to_look_up = -1;
+    colour_enabled = FALSE;
     t38_transport = T38_TRANSPORT_UDPTL;
-    while ((opt = getopt(argc, argv, "c:d:D:efFgH:i:Ilm:M:n:p:s:S:tT:u:v:z:")) != -1)
+    while ((opt = getopt(argc, argv, "c:Cd:D:efFgH:i:Ilm:M:n:p:s:S:tT:u:v:z:")) != -1)
     {
         switch (opt)
         {
         case 'c':
             code_to_look_up = atoi(optarg);
             break;
+        case 'C':
+            colour_enabled = TRUE;
+            break;
         case 'd':
             decode_file_name = optarg;
             break;
@@ -845,7 +850,7 @@ int main(int argc, char *argv[])
                                     | T4_SUPPORT_LENGTH_US_LETTER
                                     | T4_SUPPORT_LENGTH_US_LEGAL
                                     | T4_SUPPORT_LENGTH_UNLIMITED);
-#if 0
+#if 1
         t30_set_supported_bilevel_resolutions(t30_state[i],
                                               T4_SUPPORT_RESOLUTION_R8_STANDARD
                                             | T4_SUPPORT_RESOLUTION_R8_FINE
@@ -880,17 +885,20 @@ int main(int argc, char *argv[])
                                             | T4_SUPPORT_RESOLUTION_600_1200
                                             | T4_SUPPORT_RESOLUTION_1200_1200);
 #endif
-#if 1
-        t30_set_supported_colour_resolutions(t30_state[i], 0);
-#else
-        t30_set_supported_colour_resolutions(t30_state[i],
-                                             T4_SUPPORT_RESOLUTION_100_100
-                                           | T4_SUPPORT_RESOLUTION_200_200
-                                           | T4_SUPPORT_RESOLUTION_300_300
-                                           | T4_SUPPORT_RESOLUTION_400_400
-                                           | T4_SUPPORT_RESOLUTION_600_600
-                                           | T4_SUPPORT_RESOLUTION_1200_1200);
-#endif
+        if (colour_enabled)
+        {
+            t30_set_supported_colour_resolutions(t30_state[i],
+                                                 T4_SUPPORT_RESOLUTION_100_100
+                                               | T4_SUPPORT_RESOLUTION_200_200
+                                               | T4_SUPPORT_RESOLUTION_300_300
+                                               | T4_SUPPORT_RESOLUTION_400_400
+                                               | T4_SUPPORT_RESOLUTION_600_600
+                                               | T4_SUPPORT_RESOLUTION_1200_1200);
+        }
+        else
+        {
+            t30_set_supported_colour_resolutions(t30_state[i], 0);
+        }
         t30_set_supported_output_compressions(t30_state[i], T4_SUPPORT_COMPRESSION_T4_2D);
         t30_set_ecm_capability(t30_state[i], use_ecm);
         t30_set_supported_compressions(t30_state[i],
index 4e0c078c625d4287409787333410387900f246df..4d4d1bc4e54f2eafebcd524342a33a840635decc 100755 (executable)
@@ -17,7 +17,7 @@
 
 run_fax_test()
 {
-    rm -f fax_tests_1.tif
+    rm -f fax_tests.tif
     echo ./fax_tests ${OPTS} -i ${FILE}
     ./fax_tests ${OPTS} -i ${FILE} >xyzzy 2>xyzzy2
     RETVAL=$?
@@ -35,12 +35,87 @@ run_fax_test()
         echo fax_tests failed!
         exit $RETVAL
     fi
-    rm -f fax_tests_1.tif
+    rm -f fax_tests.tif
     echo tested ${FILE}
 }
 
+run_colour_fax_test()
+{
+    rm -f fax_tests.tif
+    echo ./fax_tests ${OPTS} -i ${IN_FILE}
+    ./fax_tests ${OPTS} -i ${IN_FILE} >xyzzy 2>xyzzy2
+    RETVAL=$?
+    if [ $RETVAL != 0 ]
+    then
+        echo fax_tests failed!
+        exit $RETVAL
+    fi
+    # Now use tiffcmp to check the results. It will return non-zero if any page images differ. The -t
+    # option means the normal differences in tags will be ignored.
+    tiffcmp -t ${OUT_FILE} fax_tests.tif >/dev/null
+    RETVAL=$?
+    if [ $RETVAL != 0 ]
+    then
+        echo fax_tests failed!
+        exit $RETVAL
+    fi
+    rm -f fax_tests.tif
+    echo tested ${IN_FILE} to ${OUT_FILE}
+}
+
 ITUTESTS_DIR=../test-data/itu/fax
+TIFFFX_DIR=../test-data/itu/tiff-fx
+LOCALTESTS_DIR=../test-data/local
+
+# Colour/gray -> bilevel by not allowing ECM
+for OPTS in "-p AA" "-p TT" "-p GG" "-p TG" "-p GT"
+do
+    IN_FILE="${LOCALTESTS_DIR}/lenna-colour.tif"
+    OUT_FILE="${LOCALTESTS_DIR}/lenna-colour-bilevel.tif"
+    run_colour_fax_test
+
+    IN_FILE="${LOCALTESTS_DIR}/lenna-bw.tif"
+    OUT_FILE="${LOCALTESTS_DIR}/lenna-bw-bilevel.tif"
+    run_colour_fax_test
+
+    IN_FILE="${TIFFFX_DIR}/c03x_02x.tif"
+    OUT_FILE="${TIFFFX_DIR}/c03x_02x.tif"
+    run_colour_fax_test
+
+    IN_FILE="${TIFFFX_DIR}/l02x_02x.tif"
+    OUT_FILE="${TIFFFX_DIR}/l02x_02x.tif"
+    run_colour_fax_test
+
+    IN_FILE="${TIFFFX_DIR}/l04x_02x.tif"
+    OUT_FILE="${TIFFFX_DIR}/l04x_02x.tif"
+    run_colour_fax_test
+done
+
+# Colour/gray -> colour/gray by allowing ECM
+for OPTS in "-p AA -C -e" "-p TT -C -e" "-p GG -C -e" "-p TG -C -e" "-p GT -C -e"
+do
+    IN_FILE="${LOCALTESTS_DIR}/lenna-colour.tif"
+    OUT_FILE="${LOCALTESTS_DIR}/lenna-colour.tif"
+    run_colour_fax_test
+
+    IN_FILE="${LOCALTESTS_DIR}/lenna-bw.tif"
+    OUT_FILE="${LOCALTESTS_DIR}/lenna-bw.tif"
+    run_colour_fax_test
+
+    IN_FILE="${TIFFFX_DIR}/c03x_02x.tif"
+    OUT_FILE="${TIFFFX_DIR}/c03x_02x.tif"
+    run_colour_fax_test
+
+    IN_FILE="${TIFFFX_DIR}/l02x_02x.tif"
+    OUT_FILE="${TIFFFX_DIR}/l02x_02x.tif"
+    run_colour_fax_test
+
+    IN_FILE="${TIFFFX_DIR}/l04x_02x.tif"
+    OUT_FILE="${TIFFFX_DIR}/l04x_02x.tif"
+    run_colour_fax_test
+done
 
+# Bi-level tests
 for OPTS in "-p AA" "-p AA -e" "-p TT" "-p TT -e" "-p GG" "-p GG -e" "-p TG" "-p TG -e" "-p GT" "-p GT -e"
 do
     FILE="${ITUTESTS_DIR}/itutests.tif"
index c1afd4ebfadcfa942c15363d88d856d80830d00c..51807f10c76a2fcc8e9b1f2e51d07996eec817ea 100644 (file)
@@ -78,6 +78,7 @@ static void create_undithered_50_by_50(image_descriptor_t *im, uint8_t buf[], in
     unsigned int j;
     uint8_t *image8;
     uint16_t *image16;
+    int samples_per_pixel;
 
     im->image = (const uint8_t *) buf;
     im->width = 50;
@@ -88,53 +89,99 @@ static void create_undithered_50_by_50(image_descriptor_t *im, uint8_t buf[], in
     switch (bytes_per_pixel)
     {
     case 1:
+        samples_per_pixel = 1;
         image8 = buf;
-        for (i = 0;  i < 50;  i++)
+        for (i = 0;  i < im->length;  i++)
         {
-            for (j = 0;  j < 50;  j++)
-                image8[50*i + j] = ((i + j)*655) >> 8;
+            for (j = 0;  j < im->width;  j++)
+                image8[im->width*i + j] = ((i + j)*655) >> 8;
         }
         break;
     case 2:
+        samples_per_pixel = 1;
         image16 = (uint16_t *) buf;
-        for (i = 0;  i < 50;  i++)
+        for (i = 0;  i < im->length;  i++)
         {
-            for (j = 0;  j < 50;  j++)
-                image16[50*i + j] = (i + j)*655;
+            for (j = 0;  j < im->width;  j++)
+                image16[im->width*i + j] = (i + j)*655;
         }
         break;
     case 3:
+        samples_per_pixel = 3;
         image8 = buf;
-        for (i = 0;  i < 50;  i++)
+        for (i = 0;  i < im->length;  i++)
         {
-            for (j = 0;  j < 50;  j++)
+            for (j = 0;  j < im->width;  j++)
+            {
+#if 0
+                image8[samples_per_pixel*(im->width*i + j) + 0] = ((i + j)*655) >> 8;
+                image8[samples_per_pixel*(im->width*i + j) + 1] = ((i + j)*655) >> 8;
+                image8[samples_per_pixel*(im->width*i + j) + 2] = ((i + j)*655) >> 8;
+#else
+                image8[samples_per_pixel*(im->width*i + j) + 0] = saturateu8((((i + j)*655U)*36532U) >> 23);
+                image8[samples_per_pixel*(im->width*i + j) + 1] = saturateu8((((i + j)*655U)*37216U) >> 24);
+                image8[samples_per_pixel*(im->width*i + j) + 2] = saturateu8((((i + j)*655U)*47900U) >> 22);
+#endif
+            }
+        }
+        break;
+    case 4:
+        samples_per_pixel = 4;
+        image8 = buf;
+        for (i = 0;  i < im->length;  i++)
+        {
+            for (j = 0;  j < im->width;  j++)
             {
 #if 0
-                image8[50*3*i + 3*j + 0] = ((i + j)*655) >> 8;
-                image8[50*3*i + 3*j + 1] = ((i + j)*655) >> 8;
-                image8[50*3*i + 3*j + 2] = ((i + j)*655) >> 8;
+                image8[samples_per_pixel*(im->width*i + j) + 0] = ((i + j)*655) >> 8;
+                image8[samples_per_pixel*(im->width*i + j) + 1] = ((i + j)*655) >> 8;
+                image8[samples_per_pixel*(im->width*i + j) + 2] = ((i + j)*655) >> 8;
+                image8[samples_per_pixel*(im->width*i + j) + 3] = 0;
 #else
-                image8[50*3*i + 3*j + 0] = saturateu8((((i + j)*655U)*36532U) >> 23);
-                image8[50*3*i + 3*j + 1] = saturateu8((((i + j)*655U)*37216U) >> 24);
-                image8[50*3*i + 3*j + 2] = saturateu8((((i + j)*655U)*47900U) >> 22);
+                image8[samples_per_pixel*(im->width*i + j) + 0] = saturateu8((((i + j)*655U)*36532U) >> 23);
+                image8[samples_per_pixel*(im->width*i + j) + 1] = saturateu8((((i + j)*655U)*37216U) >> 24);
+                image8[samples_per_pixel*(im->width*i + j) + 2] = saturateu8((((i + j)*655U)*47900U) >> 22);
+                image8[samples_per_pixel*(im->width*i + j) + 3] = 0;
 #endif
             }
         }
         break;
     case 6:
+        samples_per_pixel = 3;
         image16 = (uint16_t *) buf;
-        for (i = 0;  i < 50;  i++)
+        for (i = 0;  i < im->length;  i++)
         {
-            for (j = 0;  j < 50;  j++)
+            for (j = 0;  j < im->width;  j++)
             {
 #if 0
-                image16[50*3*i + 3*j + 0] = (i + j)*655;
-                image16[50*3*i + 3*j + 1] = (i + j)*655;
-                image16[50*3*i + 3*j + 2] = (i + j)*655;
+                image16[samples_per_pixel*(im->width*i + j) + 0] = (i + j)*655;
+                image16[samples_per_pixel*(im->width*i + j) + 1] = (i + j)*655;
+                image16[samples_per_pixel*(im->width*i + j) + 2] = (i + j)*655;
 #else
-                image16[50*3*i + 3*j + 0] = saturateu16((((i + j)*655U)*36532U) >> 15);
-                image16[50*3*i + 3*j + 1] = saturateu16((((i + j)*655U)*37216U) >> 16);
-                image16[50*3*i + 3*j + 2] = saturateu16((((i + j)*655U)*47900U) >> 14);
+                image16[samples_per_pixel*(im->width*i + j) + 0] = saturateu16((((i + j)*655U)*36532U) >> 15);
+                image16[samples_per_pixel*(im->width*i + j) + 1] = saturateu16((((i + j)*655U)*37216U) >> 16);
+                image16[samples_per_pixel*(im->width*i + j) + 2] = saturateu16((((i + j)*655U)*47900U) >> 14);
+#endif
+            }
+        }
+        break;
+    case 8:
+        samples_per_pixel = 4;
+        image16 = (uint16_t *) buf;
+        for (i = 0;  i < im->length;  i++)
+        {
+            for (j = 0;  j < im->width;  j++)
+            {
+#if 0
+                image16[samples_per_pixel*(im->width*i + j) + 0] = (i + j)*655;
+                image16[samples_per_pixel*(im->width*i + j) + 1] = (i + j)*655;
+                image16[samples_per_pixel*(im->width*i + j) + 2] = (i + j)*655;
+                image16[samples_per_pixel*(im->width*i + j) + 3] = 0;
+#else
+                image16[samples_per_pixel*(im->width*i + j) + 0] = saturateu16((((i + j)*655U)*36532U) >> 15);
+                image16[samples_per_pixel*(im->width*i + j) + 1] = saturateu16((((i + j)*655U)*37216U) >> 16);
+                image16[samples_per_pixel*(im->width*i + j) + 2] = saturateu16((((i + j)*655U)*47900U) >> 14);
+                image16[samples_per_pixel*(im->width*i + j) + 3] = 0;
 #endif
             }
         }
@@ -232,7 +279,7 @@ static void get_bilevel_image(image_translate_state_t *s, int compare)
 {
     int i;
     int len;
-    uint8_t row_buf[5000];
+    uint8_t row_buf[s->output_length*s->output_width/8];
 
     for (i = 0;  i < s->output_length;  i++)
     {
@@ -264,7 +311,7 @@ static void get_gray8_image(image_translate_state_t *s, int compare)
     unsigned int i;
     unsigned int j;
     int len;
-    uint8_t row_buf[5000];
+    uint8_t row_buf[s->output_length*s->output_width];
 
     for (i = 0;  i < s->output_length;  i++)
     {
@@ -298,7 +345,7 @@ static void get_gray16_image(image_translate_state_t *s, int compare)
     unsigned int i;
     unsigned int j;
     int len;
-    uint16_t row_buf[5000];
+    uint16_t row_buf[s->output_length*s->output_width];
 
     for (i = 0;  i < s->output_length;  i++)
     {
@@ -309,7 +356,7 @@ static void get_gray16_image(image_translate_state_t *s, int compare)
         }
         if (compare)
         {
-            for (j = 0;  j < 50;  j++)
+            for (j = 0;  j < s->output_width;  j++)
             {
                 if (row_buf[j] != (i + j)*655)
                 {
@@ -331,22 +378,24 @@ static void get_colour8_image(image_translate_state_t *s, int compare)
 {
     unsigned int i;
     unsigned int j;
+    int samples_per_pixel;
     int len;
     int r;
     int g;
     int b;
-    uint8_t row_buf[5000];
+    uint8_t row_buf[3*s->output_length*s->output_width];
 
+    samples_per_pixel = 3;
     for (i = 0;  i < s->output_length;  i++)
     {
-        if ((len = image_translate_row(s, row_buf, 3*s->output_width)) != 3*s->output_width)
+        if ((len = image_translate_row(s, row_buf, samples_per_pixel*s->output_width)) != samples_per_pixel*s->output_width)
         {
-            printf("Image finished early - %d %d\n", len, 3*s->output_width);
+            printf("Image finished early - %d %d\n", len, samples_per_pixel*s->output_width);
             exit(2);
         }
         if (compare)
         {
-            for (j = 0;  j < 50;  j++)
+            for (j = 0;  j < s->output_width;  j++)
             {
 #if 0
                 r = ((i + j)*655) >> 8;
@@ -357,20 +406,24 @@ static void get_colour8_image(image_translate_state_t *s, int compare)
                 g = saturateu8((((i + j)*655U)*37216U) >> 24);
                 b = saturateu8((((i + j)*655U)*47900U) >> 22);
 #endif
-                if (row_buf[3*j + 0] != r  ||  row_buf[3*j + 1] != g  ||  row_buf[3*j + 2] != b)
+                if (row_buf[samples_per_pixel*j + 0] != r
+                    ||
+                    row_buf[samples_per_pixel*j + 1] != g
+                    ||
+                    row_buf[samples_per_pixel*j + 2] != b)
                 {
                     printf("Image mismatch - %dx%d - (%d %d %d) (%d %d %d)\n",
                            j, i,
                            r, g, b,
-                           row_buf[3*j + 0], row_buf[3*j + 1], row_buf[3*j + 2]);
+                           row_buf[samples_per_pixel*j + 0], row_buf[samples_per_pixel*j + 1], row_buf[samples_per_pixel*j + 2]);
                     //exit(2);
                 }
             }
         }
     }
-    if ((len = image_translate_row(s, row_buf, 2*s->output_width)) != 0)
+    if ((len = image_translate_row(s, row_buf, samples_per_pixel*s->output_width)) != 0)
     {
-        printf("Image finished late - %d %d\n", len, 3*s->output_width);
+        printf("Image finished late - %d %d\n", len, samples_per_pixel*s->output_width);
         exit(2);
     }
 }
@@ -380,22 +433,24 @@ static void get_colour16_image(image_translate_state_t *s, int compare)
 {
     unsigned int i;
     unsigned int j;
+    int samples_per_pixel;
     int len;
     int r;
     int g;
     int b;
-    uint16_t row_buf[5000];
+    uint16_t row_buf[3*s->output_length*s->output_width];
 
+    samples_per_pixel = 3;
     for (i = 0;  i < s->output_length;  i++)
     {
-        if ((len = image_translate_row(s, (uint8_t *) row_buf, 6*s->output_width)) != 6*s->output_width)
+        if ((len = image_translate_row(s, (uint8_t *) row_buf, 2*samples_per_pixel*s->output_width)) != 2*samples_per_pixel*s->output_width)
         {
-            printf("Image finished early - %d %d\n", len, 6*s->output_width);
+            printf("Image finished early - %d %d\n", len, 2*samples_per_pixel*s->output_width);
             exit(2);
         }
         if (compare)
         {
-            for (j = 0;  j < 50;  j++)
+            for (j = 0;  j < s->output_width;  j++)
             {
 #if 0
                 r = (i + j)*655;
@@ -406,60 +461,29 @@ static void get_colour16_image(image_translate_state_t *s, int compare)
                 g = saturateu16((((i + j)*655U)*37216U) >> 16);
                 b = saturateu16((((i + j)*655U)*47900U) >> 14);
 #endif
-                if (row_buf[3*j + 0] != r  ||  row_buf[3*j + 1] != g  ||  row_buf[3*j + 2] != b)
+                if (row_buf[samples_per_pixel*j + 0] != r
+                    ||
+                    row_buf[samples_per_pixel*j + 1] != g
+                    ||
+                    row_buf[samples_per_pixel*j + 2] != b)
                 {
                     printf("Image mismatch - %dx%d - (%d %d %d) (%d %d %d)\n",
                            j, i,
                            r, g, b,
-                           row_buf[3*j + 0], row_buf[3*j + 1], row_buf[3*j + 2]);
+                           row_buf[samples_per_pixel*j + 0], row_buf[samples_per_pixel*j + 1], row_buf[samples_per_pixel*j + 2]);
                     //exit(2);
                 }
             }
         }
     }
-    if ((len = image_translate_row(s, (uint8_t *) row_buf, 6*s->output_width)) != 0)
+    if ((len = image_translate_row(s, (uint8_t *) row_buf, 2*samples_per_pixel*s->output_width)) != 0)
     {
-        printf("Image finished late - %d %d\n", len, 6*s->output_width);
+        printf("Image finished late - %d %d\n", len, 2*samples_per_pixel*s->output_width);
         exit(2);
     }
 }
 /*- End of function --------------------------------------------------------*/
 
-static void translate_tests_gray16(void)
-{
-    image_translate_state_t *s;
-    uint16_t image[50*50];
-    image_descriptor_t im;
-
-    printf("Dithering from a 16 bit per sample gray scale to bi-level\n");
-    create_undithered_50_by_50(&im, (uint8_t *) image, 2);
-    s = image_translate_init(NULL, T4_IMAGE_TYPE_BILEVEL, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, row_read, &im);
-    get_bilevel_image(s, TRUE);
-
-    printf("Scrunching from a 16 bit per sample gray scale to 8 bit per sample gray scale\n");
-    create_undithered_50_by_50(&im, (uint8_t *) image, 2);
-    s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_8BIT, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, row_read, &im);
-    get_gray8_image(s, TRUE);
-
-    printf("Scrunching from a 16 bit per sample gray scale to 16 bit per sample gray scale\n");
-    create_undithered_50_by_50(&im, (uint8_t *) image, 2);
-    s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_12BIT, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, row_read, &im);
-    get_gray16_image(s, TRUE);
-
-    printf("Scrunching from a 16 bit per sample gray scale to 3x8 bit per sample colour\n");
-    create_undithered_50_by_50(&im, (uint8_t *) image, 2);
-    s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_8BIT, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, row_read, &im);
-    get_colour8_image(s, TRUE);
-
-    printf("Scrunching from a 16 bit per sample gray scale to 3x16 bit per sample colour\n");
-    create_undithered_50_by_50(&im, (uint8_t *) image, 2);
-    s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, row_read, &im);
-    get_colour16_image(s, TRUE);
-
-    image_translate_free(s);
-}
-/*- End of function --------------------------------------------------------*/
-
 static void translate_tests_gray8(void)
 {
     image_translate_state_t *s;
@@ -495,35 +519,35 @@ static void translate_tests_gray8(void)
 }
 /*- End of function --------------------------------------------------------*/
 
-static void translate_tests_colour16(void)
+static void translate_tests_gray16(void)
 {
     image_translate_state_t *s;
-    uint16_t image[50*50*3];
+    uint16_t image[50*50];
     image_descriptor_t im;
 
-    printf("Dithering from a 3x16 bit per sample colour to bi-level\n");
-    create_undithered_50_by_50(&im, (uint8_t *) image, 6);
-    s = image_translate_init(NULL, T4_IMAGE_TYPE_BILEVEL, -1, -1, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, row_read, &im);
+    printf("Dithering from a 16 bit per sample gray scale to bi-level\n");
+    create_undithered_50_by_50(&im, (uint8_t *) image, 2);
+    s = image_translate_init(NULL, T4_IMAGE_TYPE_BILEVEL, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, row_read, &im);
     get_bilevel_image(s, TRUE);
 
-    printf("Scrunching from a 3x16 bit per sample colour to 8 bit per sample gray scale\n");
-    create_undithered_50_by_50(&im, (uint8_t *) image, 6);
-    s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_8BIT, -1, -1, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, row_read, &im);
+    printf("Scrunching from a 16 bit per sample gray scale to 8 bit per sample gray scale\n");
+    create_undithered_50_by_50(&im, (uint8_t *) image, 2);
+    s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_8BIT, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, row_read, &im);
     get_gray8_image(s, TRUE);
 
-    printf("Scrunching from a 3x16 bit per sample colour to 16 bit per sample gray scale\n");
-    create_undithered_50_by_50(&im, (uint8_t *) image, 6);
-    s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_12BIT, -1, -1, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, row_read, &im);
+    printf("Scrunching from a 16 bit per sample gray scale to 16 bit per sample gray scale\n");
+    create_undithered_50_by_50(&im, (uint8_t *) image, 2);
+    s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_12BIT, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, row_read, &im);
     get_gray16_image(s, TRUE);
 
-    printf("Scrunching from a 3x16 bit per sample colour to 3x8 bit per sample colour\n");
-    create_undithered_50_by_50(&im, (uint8_t *) image, 6);
-    s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_8BIT, -1, -1, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, row_read, &im);
+    printf("Scrunching from a 16 bit per sample gray scale to 3x8 bit per sample colour\n");
+    create_undithered_50_by_50(&im, (uint8_t *) image, 2);
+    s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_8BIT, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, row_read, &im);
     get_colour8_image(s, TRUE);
 
-    printf("Scrunching from a 3x16 bit per sample colour to 3x16 bit per sample colour\n");
-    create_undithered_50_by_50(&im, (uint8_t *) image, 6);
-    s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, -1, -1, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, row_read, &im);
+    printf("Scrunching from a 16 bit per sample gray scale to 3x16 bit per sample colour\n");
+    create_undithered_50_by_50(&im, (uint8_t *) image, 2);
+    s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, row_read, &im);
     get_colour16_image(s, TRUE);
 
     image_translate_free(s);
@@ -533,7 +557,7 @@ static void translate_tests_colour16(void)
 static void translate_tests_colour8(void)
 {
     image_translate_state_t *s;
-    uint8_t image[50*50*3];
+    uint8_t image[3*50*50];
     image_descriptor_t im;
 
     printf("Dithering from a 3x8 bit per sample colour to bi-level\n");
@@ -565,10 +589,45 @@ static void translate_tests_colour8(void)
 }
 /*- End of function --------------------------------------------------------*/
 
+static void translate_tests_colour16(void)
+{
+    image_translate_state_t *s;
+    uint16_t image[3*50*50];
+    image_descriptor_t im;
+
+    printf("Dithering from a 3x16 bit per sample colour to bi-level\n");
+    create_undithered_50_by_50(&im, (uint8_t *) image, 6);
+    s = image_translate_init(NULL, T4_IMAGE_TYPE_BILEVEL, -1, -1, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, row_read, &im);
+    get_bilevel_image(s, TRUE);
+
+    printf("Scrunching from a 3x16 bit per sample colour to 8 bit per sample gray scale\n");
+    create_undithered_50_by_50(&im, (uint8_t *) image, 6);
+    s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_8BIT, -1, -1, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, row_read, &im);
+    get_gray8_image(s, TRUE);
+
+    printf("Scrunching from a 3x16 bit per sample colour to 16 bit per sample gray scale\n");
+    create_undithered_50_by_50(&im, (uint8_t *) image, 6);
+    s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_12BIT, -1, -1, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, row_read, &im);
+    get_gray16_image(s, TRUE);
+
+    printf("Scrunching from a 3x16 bit per sample colour to 3x8 bit per sample colour\n");
+    create_undithered_50_by_50(&im, (uint8_t *) image, 6);
+    s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_8BIT, -1, -1, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, row_read, &im);
+    get_colour8_image(s, TRUE);
+
+    printf("Scrunching from a 3x16 bit per sample colour to 3x16 bit per sample colour\n");
+    create_undithered_50_by_50(&im, (uint8_t *) image, 6);
+    s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, -1, -1, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, row_read, &im);
+    get_colour16_image(s, TRUE);
+
+    image_translate_free(s);
+}
+/*- End of function --------------------------------------------------------*/
+
 static void grow_tests_colour8(void)
 {
     image_translate_state_t *s;
-    uint8_t image[50*50*3];
+    uint8_t image[3*50*50];
     image_descriptor_t im;
 
     printf("Image growth tests\n");
@@ -597,20 +656,20 @@ static void lenna_tests(int output_width, int output_length_scaling, const char
     int image_width;
     int image_length;
     int output_length;
-    uint8_t *image;
-    uint8_t *image2;
     int len;
     int total;
-    int16_t bits_per_sample;
-    int16_t samples_per_pixel;
     int i;
     int n;
+    uint8_t *image;
+    uint8_t *image2;
+    int16_t bits_per_sample;
+    int16_t samples_per_pixel;
+    uint16_t res_unit;
     image_translate_state_t *s;
     image_translate_state_t *s2;
     image_descriptor_t im;
     float x_resolution;
     float y_resolution;
-    uint16_t res_unit;
 
     if (output_length_scaling >= 0)
         printf("Dithering Lenna from colour to bi-level test\n");
@@ -651,7 +710,7 @@ static void lenna_tests(int output_width, int output_length_scaling, const char
             break;
         }
     }
-    printf("Image size %d %d\n", total, image_width*image_length*samples_per_pixel);
+    printf("Input image size %d %d\n", total, image_width*image_length*samples_per_pixel);
     TIFFClose(in_file);
 
     if (output_length_scaling > 0)
index 712c80242b9de06658c3d16376766d5b71e6561b..105ce60371963ed48a610d7fc3a9bfad63fab6a5 100644 (file)
@@ -157,7 +157,8 @@ int main(int argc, char *argv[])
     TIFF_FX_init();
 #endif
 
-    set_lab_illuminant(&lab_param, 0.9638f, 1.0f, 0.8245f);
+    /* The default luminant is D50 */
+    set_lab_illuminant(&lab_param, 96.422f, 100.000f,  82.521f);
     set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, FALSE);
 
     source_file = (argc > 1)  ?  argv[1]  :  IN_FILE_NAME;
@@ -218,7 +219,8 @@ int main(int argc, char *argv[])
 #endif
         lab_params_t lab;
 
-        set_lab_illuminant(&lab, 0.9638f, 1.0f, 0.8245f);
+        /* The default luminant is D50 */
+        set_lab_illuminant(&lab, 96.422f, 100.000f,  82.521f);
         set_lab_gamut(&lab, 0, 100, -85, 85, -75, 125, FALSE);
         lab_to_srgb(&lab, colour_map, colour_map, 256);
         for (i = 0;  i < (1 << bits_per_pixel);  i++)
@@ -447,12 +449,13 @@ int main(int argc, char *argv[])
         if (photometric == PHOTOMETRIC_ITULAB)
         {
             printf("YYY ITULAB\n");
-
-            if (!t42_itulab_to_itulab(logging, (tdata_t) &outptr, &outsize, data, off, w, h))
+#if 0
+            if (!t42_itulab_to_itulab(logging, (tdata_t) &outptr, &outsize, data, off, w, h, 3))
             {
                 printf("Failed to convert to ITULAB\n");
                 return 1;
             }
+#endif
             free(data);
             data = (uint8_t *) outptr;
             off = outsize;
@@ -470,11 +473,12 @@ int main(int argc, char *argv[])
                 lab_to_srgb(&lab_param, data, data, w*h);
                 break;
             case PHOTOMETRIC_ITULAB:
-                set_lab_illuminant(&lab_param, 0.9638f, 1.0f, 0.8245f);
+                /* The default luminant is D50 */
+                set_lab_illuminant(&lab_param, 96.422f, 100.000f,  82.521f);
                 set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, FALSE);
                 break;
             }
-            if (!t42_srgb_to_itulab(logging, &lab_param, (tdata_t) &outptr, &outsize, data, off, w, h))
+            //if (!t42_srgb_to_itulab_jpeg(logging, &lab_param, (tdata_t) &outptr, &outsize, data, off, w, h, 3))
             {
                 printf("Failed to convert to ITULAB\n");
                 return 1;
@@ -532,7 +536,8 @@ int main(int argc, char *argv[])
         bytes_per_row = (bits_per_pixel + 7)/8;
         bytes_per_row *= w*samples_per_pixel;
         totdata = h*bytes_per_row;
-        set_lab_illuminant(&lab_param, 0.9638f, 1.0f, 0.8245f);
+        /* The default luminant is D50 */
+        set_lab_illuminant(&lab_param, 96.422f, 100.000f,  82.521f);
         set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, FALSE);
 #if 0
         start = rdtscll();
@@ -551,7 +556,7 @@ int main(int argc, char *argv[])
 #else
         data2 = malloc(totdata);
         start = rdtscll();
-        if (!t42_itulab_to_srgb(logging, &lab_param, data2, &off, data, off, &w, &h))
+        //if (!t42_itulab_jpeg_to_srgb(logging, &lab_param, data2, &off, data, off, &w, &h, &samples_per_pixel))
         {
             printf("Failed to convert from ITULAB\n");
             return 1;
diff --git a/libs/spandsp/tests/t43_tests.c b/libs/spandsp/tests/t43_tests.c
new file mode 100644 (file)
index 0000000..e436991
--- /dev/null
@@ -0,0 +1,1401 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * t43_tests.c - ITU T.43 JBIG for grey and colour FAX image processing
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2011, 2013 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 */
+
+/*! \page t43_tests_page T.43 tests
+\section t43_tests_page_sec_1 What does it do
+*/
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <memory.h>
+
+#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
+
+#include "spandsp.h"
+
+#if defined(SPANDSP_SUPPORT_TIFF_FX)
+#include <tif_dir.h>
+#endif
+
+#define IN_FILE_NAME    "../test-data/itu/tiff-fx/l04x_02x.tif"
+#define OUT_FILE_NAME   "t43_tests_receive.tif"
+
+t43_decode_state_t t43;
+t85_decode_state_t t85;
+
+lab_params_t lab_param;
+
+int write_row = 0;
+
+typedef struct
+{
+    uint8_t *buf;
+    int ptr;
+} packer_t;
+
+#if defined(SPANDSP_SUPPORT_TIFF_FX)
+/* TIFF-FX related extensions to the tag set supported by libtiff */
+static const TIFFFieldInfo tiff_fx_tiff_field_info[] =
+{
+    {TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, FIELD_CUSTOM, FALSE, FALSE, (char *) "Indexed"},
+       {TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, FIELD_CUSTOM, FALSE, FALSE, (char *) "GlobalParametersIFD"},
+    {TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, FIELD_CUSTOM, FALSE, FALSE, (char *) "ProfileType"},
+    {TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, FIELD_CUSTOM, FALSE, FALSE, (char *) "FaxProfile"},
+    {TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, FIELD_CUSTOM, FALSE, FALSE, (char *) "CodingMethods"},
+    {TIFFTAG_VERSIONYEAR, 4, 4, TIFF_BYTE, FIELD_CUSTOM, FALSE, FALSE, (char *) "VersionYear"},
+    {TIFFTAG_MODENUMBER, 1, 1, TIFF_BYTE, FIELD_CUSTOM, FALSE, FALSE, (char *) "ModeNumber"},
+    {TIFFTAG_DECODE, TIFF_VARIABLE, TIFF_VARIABLE, TIFF_SRATIONAL, FIELD_CUSTOM, FALSE, TRUE, (char *) "Decode"},
+    {TIFFTAG_IMAGEBASECOLOR, TIFF_VARIABLE, TIFF_VARIABLE, TIFF_SHORT, FIELD_CUSTOM, FALSE, TRUE, (char *) "ImageBaseColor"},
+    {TIFFTAG_T82OPTIONS, 1, 1, TIFF_LONG, FIELD_CUSTOM, FALSE, FALSE, (char *) "T82Options"},
+    {TIFFTAG_STRIPROWCOUNTS, TIFF_VARIABLE, TIFF_VARIABLE, TIFF_LONG, FIELD_CUSTOM, FALSE, TRUE, (char *) "StripRowCounts"},
+    {TIFFTAG_IMAGELAYER, 2, 2, TIFF_LONG, FIELD_CUSTOM, FALSE, FALSE, (char *) "ImageLayer"},
+};
+
+static TIFFFieldArray tifffxFieldArray;
+
+static TIFFField tiff_fx_tiff_fields[] =
+{
+    { TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "Indexed" },
+       { TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, (char *) "GlobalParametersIFD", &tifffxFieldArray },
+    { TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "ProfileType", NULL },
+    { TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "FaxProfile", NULL },
+    { TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "CodingMethods", NULL },
+    { TIFFTAG_VERSIONYEAR, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "VersionYear", NULL },
+    { TIFFTAG_MODENUMBER, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "ModeNumber", NULL },
+    { TIFFTAG_DECODE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, (char *) "Decode", NULL },
+    { TIFFTAG_IMAGEBASECOLOR, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, (char *) "ImageBaseColor", NULL },
+    { TIFFTAG_T82OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "T82Options", NULL },
+    { TIFFTAG_STRIPROWCOUNTS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, (char *) "StripRowCounts", NULL },
+    { TIFFTAG_IMAGELAYER, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "ImageLayer", NULL },
+};
+
+static TIFFFieldArray tiff_fx_field_array = { tfiatOther, 0, 12, tiff_fx_tiff_fields };
+#endif
+
+typedef struct
+{
+    TIFF *tif;
+    int pre_compressed;
+    uint32_t compressed_image_len;
+    uint32_t image_width;
+    uint32_t image_length;
+    float x_resolution;
+    float y_resolution;
+    uint16_t resolution_unit;
+    uint16_t bits_per_sample;
+    uint16_t samples_per_pixel;
+    uint16_t compression;
+    uint16_t photometric;
+    int16_t YCbCrSubsampleHoriz;
+    int16_t YCbCrSubsampleVert;
+    int16_t planar_config;
+    int32_t tile_width;
+    int32_t tile_length;
+    uint8_t *colour_map;
+    float lmin;
+    float lmax;
+    float amin;
+    float amax;
+    float bmin;
+    float bmax;
+} meta_t;
+
+int write_file(meta_t *meta, int page, const uint8_t buf[]);
+int read_file(meta_t *meta, int page);
+int read_compressed_image(meta_t *meta, uint8_t **buf);
+int read_decompressed_image(meta_t *meta, uint8_t **buf);
+
+static int row_write_handler(void *user_data, const uint8_t buf[], size_t len)
+{
+    packer_t *s;
+
+    s = (packer_t *) user_data;
+    memcpy(&s->buf[s->ptr], buf, len);
+    s->ptr += len;
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int t85_comment_handler(void *user_data, const uint8_t buf[], size_t len)
+{
+    if (buf)
+        printf("Comment (%lu): %s\n", (unsigned long int) len, buf);
+    else
+        printf("Comment (%lu): ---\n", (unsigned long int) len);
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int row_read_handler(void *user_data, uint8_t row[], size_t len)
+{
+    packer_t *s;
+
+    s = (packer_t *) user_data;
+    memcpy(row, &s->buf[s->ptr], len);
+    s->ptr += len;
+    return len;
+}
+/*- End of function --------------------------------------------------------*/
+
+int write_file(meta_t *meta, int page, const uint8_t buf[])
+{
+    TIFF *tif;
+    int off;
+    int i;
+    time_t now;
+    struct tm *tm;
+    char date_buf[50 + 1];
+    int bytes_per_row;
+    t85_encode_state_t t85;
+    t43_encode_state_t t43;
+    int out_buf_len;
+    int out_len;
+    int chunk_len;
+    uint8_t *out_buf;
+    uint8_t *out_buf2;
+    packer_t packer;
+#if defined(SPANDSP_SUPPORT_TIFF_FX)
+    uint64_t offset;
+#endif
+
+    tif = meta->tif;
+    TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
+    TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, meta->image_width);
+    /* libtiff requires IMAGELENGTH to be set before SAMPLESPERPIXEL,
+       or StripOffsets and StripByteCounts will have SAMPLESPERPIXEL values */
+    TIFFSetField(tif, TIFFTAG_IMAGELENGTH, meta->image_length);
+    TIFFSetField(tif, TIFFTAG_COMPRESSION, meta->compression);
+    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, meta->bits_per_sample);
+    TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, meta->samples_per_pixel);
+    TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+    TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+    TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, meta->image_length);
+    TIFFSetField(tif, TIFFTAG_XRESOLUTION, meta->x_resolution);
+    TIFFSetField(tif, TIFFTAG_YRESOLUTION, meta->y_resolution);
+    TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, meta->resolution_unit);
+    TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, meta->photometric);
+    if (meta->samples_per_pixel > 1  &&  (meta->YCbCrSubsampleHoriz  ||  meta->YCbCrSubsampleVert))
+        TIFFSetField(tif, TIFFTAG_YCBCRSUBSAMPLING, meta->YCbCrSubsampleHoriz, meta->YCbCrSubsampleVert);
+    TIFFSetField(tif, TIFFTAG_SOFTWARE, "spandsp");
+    TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, "Test");
+    time(&now);
+    tm = localtime(&now);
+    sprintf(date_buf,
+            "%4d/%02d/%02d %02d:%02d:%02d",
+            tm->tm_year + 1900,
+            tm->tm_mon + 1,
+            tm->tm_mday,
+            tm->tm_hour,
+            tm->tm_min,
+            tm->tm_sec);
+    TIFFSetField(tif, TIFFTAG_DATETIME, date_buf);
+    TIFFSetField(tif, TIFFTAG_MAKE, "soft-switch.org");
+    TIFFSetField(tif, TIFFTAG_MODEL, "spandsp");
+    TIFFSetField(tif, TIFFTAG_HOSTCOMPUTER, "i7.coppice.org");
+#if defined(SPANDSP_SUPPORT_TIFF_FX)
+    /* Make space for this to be filled in later */
+    TIFFSetField(tif, TIFFTAG_GLOBALPARAMETERSIFD, 0);
+#endif
+
+    if (meta->pre_compressed)
+    {
+        if (TIFFWriteRawStrip(tif, 0, (tdata_t) buf, meta->compressed_image_len) < 0)
+            printf("Error writing TIFF strip.\n");
+    }
+    else
+    {
+        switch (meta->compression)
+        {
+        case COMPRESSION_T85:
+            packer.buf = (uint8_t *) buf;
+            packer.ptr = 0;
+            t85_encode_init(&t85, meta->image_width, meta->image_length, row_read_handler, &packer);
+            //if (meta->compression == T4_COMPRESSION_T85_L0)
+            //    t85_encode_set_options(&t85, 256, -1, -1);
+            out_len = 0;
+            out_buf_len = 0;
+            out_buf = NULL;
+            do
+            {
+                if (out_buf_len < out_len + 50000)
+                {
+                    out_buf_len += 50000;
+                    if ((out_buf2 = realloc(out_buf, out_buf_len)) == NULL)
+                    {
+                        if (out_buf)
+                            free(out_buf);
+                        return -1;
+                    }
+                    out_buf = out_buf2;
+                }
+                chunk_len = t85_encode_get(&t85, &out_buf[out_len], 50000);
+                out_len += chunk_len;
+            }
+            while (chunk_len > 0);
+            if (TIFFWriteRawStrip(tif, 0, out_buf, out_len) < 0)
+                printf("Error writing TIFF strip.\n");
+            t85_encode_release(&t85);
+            free(out_buf);
+            break;
+        case COMPRESSION_T43:
+            packer.buf = (uint8_t *) buf;
+            packer.ptr = 0;
+            t43_encode_init(&t43, meta->image_width, meta->image_length, row_read_handler, &packer);
+            out_len = 0;
+            out_buf_len = 0;
+            out_buf = NULL;
+            do
+            {
+                if (out_buf_len < out_len + 50000)
+                {
+                    out_buf_len += 50000;
+                    if ((out_buf2 = realloc(out_buf, out_buf_len)) == NULL)
+                    {
+                        if (out_buf)
+                            free(out_buf);
+                        return -1;
+                    }
+                    out_buf = out_buf2;
+                }
+                chunk_len = t43_encode_get(&t43, &out_buf[out_len], 50000);
+                out_len += chunk_len;
+            }
+            while (chunk_len > 0);
+            if (TIFFWriteRawStrip(tif, 0, out_buf, out_len) < 0)
+                printf("Error writing TIFF strip.\n");
+            t43_encode_release(&t43);
+            free(out_buf);
+            break;
+        default:
+            bytes_per_row = TIFFScanlineSize(tif);
+            for (off = 0, i = 0;  i < meta->image_length;  off += bytes_per_row, i++)
+            {
+                if (TIFFWriteScanline(tif, (tdata_t) &buf[off], i, 0) < 0)
+                    printf("Error writing TIFF scan line.\n");
+            }
+            break;
+        }
+    }
+
+    if (!TIFFWriteDirectory(tif))
+        printf("Failed to write directory.\n");
+
+#if defined(SPANDSP_SUPPORT_TIFF_FX)
+    if (!TIFFCreateCustomDirectory(tif, &tiff_fx_field_array))
+    {
+        TIFFSetField(tif, TIFFTAG_PROFILETYPE, PROFILETYPE_G3_FAX);
+        TIFFSetField(tif, TIFFTAG_FAXPROFILE, FAXPROFILE_F);
+        TIFFSetField(tif, TIFFTAG_CODINGMETHODS, CODINGMETHODS_T4_1D | CODINGMETHODS_T4_2D | CODINGMETHODS_T6);
+        TIFFSetField(tif, TIFFTAG_VERSIONYEAR, "1998");
+        TIFFSetField(tif, TIFFTAG_MODENUMBER, 3);
+
+        offset = 0;
+        if (!TIFFWriteCustomDirectory(tif, &offset))
+            printf("Failed to write custom directory.\n");
+
+        if (!TIFFSetDirectory(tif, (tdir_t) page))
+            printf("Failed to set directory.\n");
+        if (!TIFFSetField(tif, TIFFTAG_GLOBALPARAMETERSIFD, offset))
+            printf("Failed to set global parameters IFD.\n");
+        if (!TIFFWriteDirectory(tif))
+            printf("Failed to write directory.\n");
+    }
+#endif
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+int read_file(meta_t *meta, int page)
+{
+#if defined(SPANDSP_SUPPORT_TIFF_FX)
+    static const char *tiff_fx_fax_profiles[] =
+    {
+        "???",
+        "profile S",
+        "profile F",
+        "profile J",
+        "profile C",
+        "profile L",
+        "profile M"
+    };
+    uint8_t parm8;
+    uint16_t parm16;
+    uint32_t parm32;
+    float *fl_parms;
+    char uu[10];
+    char *u;
+    uint64_t offset;
+#endif
+    TIFF *tif;
+    uint16_t *map_L;
+    uint16_t *map_a;
+    uint16_t *map_b;
+    uint16_t *map_z;
+    lab_params_t lab;
+    int entries;
+    int i;
+
+    tif = meta->tif;
+    printf("Read %d\n", page);
+    if (!TIFFSetDirectory(tif, (tdir_t) page))
+    {
+        printf("Unable to set TIFF directory %d!\n", page);
+        return -1;
+    }
+    meta->image_width = 0;
+    TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &meta->image_width);
+    meta->image_length = 0;
+    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &meta->image_length);
+    meta->x_resolution = 200.0f;
+    TIFFGetField(tif, TIFFTAG_XRESOLUTION, &meta->x_resolution);
+    meta->y_resolution = 200.0f;
+    TIFFGetField(tif, TIFFTAG_YRESOLUTION, &meta->y_resolution);
+    meta->resolution_unit = RESUNIT_INCH;
+    TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &meta->resolution_unit);
+    meta->bits_per_sample = 0;
+    TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &meta->bits_per_sample);
+    meta->samples_per_pixel = 0;
+    TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &meta->samples_per_pixel);
+    meta->compression = 0;
+    TIFFGetField(tif, TIFFTAG_COMPRESSION, &meta->compression);
+    meta->photometric = 0;
+    TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &meta->photometric);
+    meta->YCbCrSubsampleHoriz = 0;
+    meta->YCbCrSubsampleVert = 0;
+    TIFFGetField(tif, TIFFTAG_YCBCRSUBSAMPLING, &meta->YCbCrSubsampleHoriz, &meta->YCbCrSubsampleVert);
+    meta->planar_config = PLANARCONFIG_CONTIG;
+    TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &meta->planar_config);
+    meta->tile_width = 0;
+    TIFFGetField(tif, TIFFTAG_TILEWIDTH, &meta->tile_width);
+    meta->tile_length = 0;
+    TIFFGetField(tif, TIFFTAG_TILELENGTH, &meta->tile_length);
+
+    switch (meta->photometric)
+    {
+    case PHOTOMETRIC_ITULAB:
+        meta->lmin = 0.0f;
+        meta->lmax = 100.0f;
+        meta->amin = -21760.0f/255.0f;  // For 12 bit -348160.0f/4095.0f
+        meta->amax = 21590.0f/255.0f;   // For 12 bit 347990.0f/4095.0f
+        meta->bmin = -19200.0f/255.0f;  // For 12 bit -307200.0f/4095.0f
+        meta->bmax = 31800.0f/255.0f;   // For 12 bit 511800.0f/4095.0f
+        break;
+    default:
+        meta->lmin = 0.0f;
+        meta->lmax = 0.0f;
+        meta->amin = 0.0f;
+        meta->amax = 0.0f;
+        meta->bmin = 0.0f;
+        meta->bmax = 0.0f;
+        break;
+    }
+#if defined(SPANDSP_SUPPORT_TIFF_FX)
+    if (TIFFGetField(tif, TIFFTAG_DECODE, &parm16, &fl_parms))
+    {
+        meta->lmin = fl_parms[0];
+        meta->lmax = fl_parms[1];
+        meta->amin = fl_parms[2];
+        meta->amax = fl_parms[3];
+        meta->bmin = fl_parms[4];
+        meta->bmax = fl_parms[5];
+        printf("Got decode tag %f %f %f %f %f %f\n", meta->lmin, meta->lmax, meta->amin, meta->amax, meta->bmin, meta->bmax);
+    }
+#endif
+
+#if defined(SPANDSP_SUPPORT_TIFF_FX)
+    printf("Trying to get global parameters\n");
+    if (TIFFGetField(tif, TIFFTAG_GLOBALPARAMETERSIFD, &offset))
+    {
+        printf("Got global parameters - %" PRIu64 "\n", offset);
+        if (!TIFFReadCustomDirectory(tif, offset, &tiff_fx_field_array))
+        {
+            printf("Failed to set global parameters IFD.\n");
+        }
+        else
+        {
+            if (TIFFGetField(tif, TIFFTAG_PROFILETYPE, &parm32))
+                printf("  Profile type %u\n", parm32);
+            if (TIFFGetField(tif, TIFFTAG_FAXPROFILE, &parm8))
+                printf("  FAX profile %s (%u)\n", tiff_fx_fax_profiles[parm8], parm8);
+            if (TIFFGetField(tif, TIFFTAG_CODINGMETHODS, &parm32))
+                printf("  Coding methods 0x%x\n", parm32);
+            if (TIFFGetField(tif, TIFFTAG_VERSIONYEAR, &u))
+            {
+                memcpy(uu, u, 4);
+                uu[4] = '\0';
+                printf("  Version year \"%s\"\n", uu);
+            }
+            if (TIFFGetField(tif, TIFFTAG_MODENUMBER, &parm8))
+                printf("  Mode number %u\n", parm8);
+        }
+        TIFFSetDirectory(tif, (tdir_t) page);
+    }
+
+    if (TIFFGetField(tif, TIFFTAG_PROFILETYPE, &parm32))
+        printf("Profile type %u\n", parm32);
+    if (TIFFGetField(tif, TIFFTAG_FAXPROFILE, &parm8))
+        printf("FAX profile %s (%u)\n", tiff_fx_fax_profiles[parm8], parm8);
+    if (TIFFGetField(tif, TIFFTAG_CODINGMETHODS, &parm32))
+        printf("Coding methods 0x%x\n", parm32);
+    if (TIFFGetField(tif, TIFFTAG_VERSIONYEAR, &u))
+    {
+        memcpy(uu, u, 4);
+        uu[4] = '\0';
+        printf("Version year \"%s\"\n", uu);
+    }
+    if (TIFFGetField(tif, TIFFTAG_MODENUMBER, &parm8))
+        printf("Mode number %u\n", parm8);
+    if (TIFFGetField(tif, TIFFTAG_T82OPTIONS, &parm32))
+        printf("T.82 options 0x%x\n", parm32);
+#endif
+
+    map_L = NULL;
+    map_a = NULL;
+    map_b = NULL;
+    map_z = NULL;
+    if (TIFFGetField(tif, TIFFTAG_COLORMAP, &map_L, &map_a, &map_b, &map_z))
+    {
+        entries = 1 << meta->bits_per_sample;
+        meta->colour_map = malloc(3*entries);
+        if (meta->colour_map)
+        {
+#if 0
+            /* Sweep the colormap in the proper order */
+            for (i = 0;  i < entries;  i++)
+            {
+                meta->colour_map[3*i] = (map_L[i] >> 8) & 0xFF;
+                meta->colour_map[3*i + 1] = (map_a[i] >> 8) & 0xFF;
+                meta->colour_map[3*i + 2] = (map_b[i] >> 8) & 0xFF;
+                printf("Map %3d - %5d %5d %5d\n", i, meta->colour_map[3*i], meta->colour_map[3*i + 1], meta->colour_map[3*i + 2]);
+            }
+#else
+            /* Sweep the colormap in the order that seems to work for l04x_02x.tif */
+            for (i = 0;  i < entries;  i++)
+            {
+                meta->colour_map[i] = (map_L[i] >> 8) & 0xFF;
+                meta->colour_map[256 + i] = (map_a[i] >> 8) & 0xFF;
+                meta->colour_map[2*256 + i] = (map_b[i] >> 8) & 0xFF;
+            }
+#endif
+            /* The default luminant is D50 */
+            set_lab_illuminant(&lab_param, 96.422f, 100.000f,  82.521f);
+            set_lab_gamut(&lab, 0, 100, -85, 85, -75, 125, FALSE);
+            lab_to_srgb(&lab, meta->colour_map, meta->colour_map, 256);
+            for (i = 0;  i < entries;  i++)
+                printf("Map %3d - %5d %5d %5d\n", i, meta->colour_map[3*i], meta->colour_map[3*i + 1], meta->colour_map[3*i + 2]);
+        }
+    }
+    meta->tif = tif;
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+int read_compressed_image(meta_t *meta, uint8_t **buf)
+{
+    int i;
+    int len;
+    int total_len;
+    int read_len;
+    int num_strips;
+    uint8_t *data;
+
+    num_strips = TIFFNumberOfStrips(meta->tif);
+    for (i = 0, total_len = 0;  i < num_strips;  i++)
+    {
+        total_len += TIFFRawStripSize(meta->tif, i);
+    }
+    if ((data = malloc(total_len)) == NULL)
+        return -1;
+    for (i = 0, read_len = 0;  i < num_strips;  i++, read_len += len)
+    {
+        if ((len = TIFFReadRawStrip(meta->tif, i, &data[read_len], total_len - read_len)) < 0)
+        {
+            printf("TIFF read error.\n");
+            return -1;
+        }
+    }
+    *buf = data;
+    return total_len;
+}
+/*- End of function --------------------------------------------------------*/
+
+int read_decompressed_image(meta_t *meta, uint8_t **buf)
+{
+    int bytes_per_row;
+    tsize_t off;
+    int x;
+    int y;
+    int xx;
+    int yy;
+    int xxx;
+    int yyy;
+    int i;
+    int j;
+    uint32_t w;
+    uint32_t h;
+    uint16_t samples_per_pixel;
+    int result;
+    int total_raw;
+    int total_data;
+    uint8_t *raw_buf;
+    uint8_t *image_buf;
+    uint8_t *jpeg_table;
+    uint32_t jpeg_table_len;
+    t85_decode_state_t t85;
+    t43_decode_state_t t43;
+    packer_t pack;
+    logging_state_t *logging;
+    logging_state_t logging2;
+
+    image_buf = NULL;
+    total_data = 0;
+    switch (meta->compression)
+    {
+    case COMPRESSION_T85:
+        bytes_per_row = (meta->image_width + 7)/8;
+        total_data = meta->image_length*bytes_per_row;
+        printf("Total decompressed data %d, %d per row\n", total_data, bytes_per_row);
+
+        /* Read the image into memory. */
+        if ((image_buf = malloc(total_data)) == NULL)
+        {
+            printf("Failed to allocated image buffer\n");
+            return -1;
+        }
+        total_raw = read_compressed_image(meta, &raw_buf);
+        t85_decode_init(&t85, row_write_handler, &pack);
+        t85_decode_set_comment_handler(&t85, 1000, t85_comment_handler, NULL);
+        logging = t85_decode_get_logging_state(&t85);
+        span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
+
+        pack.buf = image_buf;
+        pack.ptr = 0;
+
+        result = t85_decode_put(&t85, raw_buf, total_raw);
+        if (result == T4_DECODE_MORE_DATA)
+            result = t85_decode_put(&t85, NULL, 0);
+        total_data = t85_decode_get_compressed_image_size(&t85);
+        printf("Compressed image is %d/%d bytes, %d rows\n", total_raw, total_data/8, write_row);
+        t85_decode_release(&t85);
+        free(raw_buf);
+        break;
+    case COMPRESSION_T43:
+        bytes_per_row = meta->samples_per_pixel*meta->image_width;
+        total_data = meta->image_length*bytes_per_row;
+        printf("Total decompressed data %d, %d per row\n", total_data, bytes_per_row);
+
+total_data *= 8;
+        /* Read the image into memory. */
+        if ((image_buf = malloc(total_data)) == NULL)
+            printf("Failed to allocated image buffer\n");
+
+        total_raw = read_compressed_image(meta, &raw_buf);
+        t43_decode_init(&t43, row_write_handler, &pack);
+        t43_decode_set_comment_handler(&t43, 1000, t85_comment_handler, NULL);
+        logging = t43_decode_get_logging_state(&t43);
+        span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
+
+        pack.buf = image_buf;
+        pack.ptr = 0;
+
+        result = t43_decode_put(&t43, raw_buf, total_raw);
+        if (result == T4_DECODE_MORE_DATA)
+            result = t43_decode_put(&t43, NULL, 0);
+        t43_decode_release(&t43);
+        free(raw_buf);
+
+        meta->samples_per_pixel = 1;
+        meta->photometric = PHOTOMETRIC_RGB;
+        printf("Image %d x %d pixels\n", meta->image_width, meta->image_length);
+        break;
+    case COMPRESSION_JPEG:
+        if (meta->photometric == PHOTOMETRIC_ITULAB)
+        {
+            printf(" ITULAB");
+
+            span_log_init(&logging2, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW, "lab");
+            bytes_per_row = TIFFScanlineSize(meta->tif);
+            total_data = meta->image_length*bytes_per_row;
+            printf("Total decompressed data %d, %d per row\n", total_data, bytes_per_row);
+
+            /* Read the image into memory. */
+            if ((image_buf = malloc(total_data)) == NULL)
+                printf("Failed to allocated image buffer\n");
+
+            jpeg_table_len = 0;
+#if 0
+            if (TIFFGetField(meta->tif, TIFFTAG_JPEGTABLES, &jpeg_table_len, &jpeg_table))
+            {
+                total_image_len += (jpeg_table_len - 4);
+                printf("JPEG tables %u\n", jpeg_table_len);
+{
+int ii;
+printf("YYY1 %d - ", jpeg_table_len);
+for (ii = 0;  ii < jpeg_table_len;  ii++)
+    printf(" %02x", jpeg_table[ii]);
+printf("\n");
+}
+            }
+#endif
+            total_raw = read_compressed_image(meta, &raw_buf);
+            //if (!t42_itulab_jpeg_to_srgb(&logging2, &lab_param, (tdata_t) image_buf, &off, raw_buf, total_raw, &w, &h, &samples_per_pixel))
+            {
+                printf("Failed to convert from ITULAB.\n");
+                return 1;
+            }
+            meta->photometric = PHOTOMETRIC_RGB;
+
+#if 0
+            total_len = 0;
+            if (jpeg_table_len > 0)
+                total_len += jpeg_table_len - 4;
+
+printf("nstrips %d\n", nstrips);
+            data2 = NULL;
+            for (i = 0;  i < nstrips;  i++, total_len += len)
+            {
+                total_len = 0;
+                if (jpeg_table_len > 0)
+                    total_len += jpeg_table_len - 4;
+                if ((len = TIFFReadRawStrip(tif, i, &data[total_len], total_image_len - total_len)) < 0)
+                {
+                    printf("TIFF read error.\n");
+                    return -1;
+                }
+                if (jpeg_table_len > 0)
+                {
+                    memcpy(data, jpeg_table, jpeg_table_len - 2);
+printf("%02x %02x %02x %02x\n", data[total_len], data[total_len + 1], data[total_len + 2], data[total_len + 3]);
+                }
+                totdata = meta->image_width*3000*meta->samples_per_pixel;
+                data2 = realloc(data2, totdata);
+                off = total_len;
+                if (!t42_itulab_jpeg_to_srgb(&logging2, &lab_param, data2, &off, data, off, &w, &h, &samples_per_pixel))
+                {
+                    printf("Failed to convert from ITULAB.\n");
+                    return 1;
+                }
+            }
+            if (data2)
+                free(data2);
+            //exit(2);
+            if (jpeg_table_len > 0)
+                memcpy(data, jpeg_table, jpeg_table_len - 2);
+
+            if (total_len != total_image_len)
+                printf("Size mismatch %d %d\n", (int) total_len, (int) total_image_len);
+{
+int ii;
+
+printf("YYY2 %d - ", jpeg_table_len);
+for (ii = 0;  ii < 800;  ii++)
+    printf(" %02x", data[ii]);
+printf("\n");
+}
+            off = total_len;
+            len = total_len;
+#endif
+            break;
+        }
+        /* Fall through */
+    default:
+        if (meta->tile_width > 0)
+        {
+            /* The image is tiled, so we need to patch together a bunch of tiles */
+            switch (meta->planar_config)
+            {
+            case PLANARCONFIG_CONTIG:
+                bytes_per_row = TIFFScanlineSize(meta->tif);
+                total_data = meta->image_length*bytes_per_row;
+                printf("Total decompressed data %d, %d per row\n", total_data, bytes_per_row);
+
+                /* Read the image into memory. */
+                if ((image_buf = malloc(total_data)) == NULL)
+                    printf("Failed to allocated image buffer\n");
+
+                for (y = 0;  y < meta->image_length;  y += meta->tile_length)
+                {
+                    for (x = 0;  x < meta->image_width;  x += meta->tile_width)
+                    {
+                        uint8_t data[meta->tile_width*meta->tile_length*meta->samples_per_pixel];
+
+                        TIFFReadTile(meta->tif, data, x, y, 0, 0);
+                        yyy = meta->tile_length;
+                        if (y + meta->tile_length > meta->image_length)
+                            yyy = meta->image_length - y;
+                        xxx = meta->tile_width;
+                        if (x + meta->tile_width > meta->image_width)
+                            xxx = meta->image_width - x;
+                        for (yy = 0;  yy < yyy;  yy++)
+                        {
+                            for (xx = 0;  xx < xxx;  xx++)
+                            {
+                                for (j = 0;  j < meta->samples_per_pixel;  j++)
+                                    image_buf[meta->samples_per_pixel*((y + yy)*meta->image_width + x + xx) + j] = data[meta->samples_per_pixel*(yy*meta->tile_width + xx) + j];
+                            }
+                        }
+                    }
+                }
+                break;
+            case PLANARCONFIG_SEPARATE:
+                bytes_per_row = TIFFScanlineSize(meta->tif);
+                total_data = meta->samples_per_pixel*meta->image_length*bytes_per_row;
+                printf("Total decompressed data %d, %d per row\n", total_data, bytes_per_row);
+
+                /* Read the image into memory. */
+                if ((image_buf = malloc(total_data)) == NULL)
+                    printf("Failed to allocated image buffer\n");
+
+                for (j = 0;  j < meta->samples_per_pixel;  j++)
+                {
+                    for (y = 0;  y < meta->image_length;  y += meta->tile_length)
+                    {
+                        for (x = 0;  x < meta->image_width;  x += meta->tile_width)
+                        {
+                            uint8_t data[meta->tile_width*meta->tile_length*meta->samples_per_pixel];
+
+                            TIFFReadTile(meta->tif, data, x, y, 0, j);
+                            yyy = meta->tile_length;
+                            if (y + meta->tile_length > meta->image_length)
+                                yyy = meta->image_length - y;
+                            xxx = meta->tile_width;
+                            if (x + meta->tile_width > meta->image_width)
+                                xxx = meta->image_width - x;
+                            for (yy = 0;  yy < yyy;  yy++)
+                            {
+                                for (xx = 0;  xx < xxx;  xx++)
+                                {
+                                    image_buf[meta->samples_per_pixel*((y + yy)*meta->image_width + x + xx) + j] = data[yy*meta->tile_width + xx];
+                                }
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+        }
+        else
+        {
+            /* There is no tiling to worry about, but we might have planar issues to resolve */
+            switch (meta->planar_config)
+            {
+            case PLANARCONFIG_CONTIG:
+                bytes_per_row = TIFFScanlineSize(meta->tif);
+                total_data = meta->image_length*bytes_per_row;
+                printf("Total decompressed data %d, %d per row\n", total_data, bytes_per_row);
+
+                /* Read the image into memory. */
+                if ((image_buf = malloc(total_data)) == NULL)
+                    printf("Failed to allocated image buffer\n");
+
+                for (y = 0;  y < meta->image_length;  y++)
+                {
+                    if (TIFFReadScanline(meta->tif, &image_buf[y*bytes_per_row], y, 0) < 0)
+                        return 1;
+                }
+                break;
+            case PLANARCONFIG_SEPARATE:
+                bytes_per_row = TIFFScanlineSize(meta->tif);
+                total_data = meta->samples_per_pixel*meta->image_length*bytes_per_row;
+                printf("Total decompressed data %d, %d per row\n", total_data, bytes_per_row);
+
+                /* Read the image into memory. */
+                if ((image_buf = malloc(total_data)) == NULL)
+                    printf("Failed to allocated image buffer\n");
+
+                for (j = 0;  j < meta->samples_per_pixel;  j++)
+                {
+                    uint8_t data[bytes_per_row];
+
+                    for (y = 0;  y < meta->image_length;  y++)
+                    {
+                        if (TIFFReadScanline(meta->tif, data, y, j) < 0)
+                            return 1;
+                        for (x = 0;  x < meta->image_width;  x++)
+                            image_buf[meta->samples_per_pixel*(y*bytes_per_row + x) + j] = data[x];
+                    }
+                }
+                break;
+            }
+        }
+        break;
+    }
+    /* Normalise bi-level images, so they are always in PHOTOMETRIC_MINISWHITE form */
+    if (image_buf  &&  meta->samples_per_pixel == 1  &&  meta->bits_per_sample == 1)
+    {
+        if (meta->photometric != PHOTOMETRIC_MINISWHITE)
+        {
+            for (i = 0;  i < total_data;  i++)
+                image_buf[i] = ~image_buf[i];
+            meta->photometric = PHOTOMETRIC_MINISWHITE;
+        }
+    }
+
+    *buf = image_buf;
+    return total_data;
+}
+/*- End of function --------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+    const char *source_file;
+    const char *destination_file;
+    TIFF *tif;
+    tstrip_t nstrips;
+    uint32_t totdata;
+    tsize_t off;
+    uint8_t *data;
+    uint8_t *data2;
+    int row;
+    int bytes_per_row;
+    tsize_t outsize;
+    char *outptr;
+    int i;
+    int k;
+    int x;
+    int y;
+    uint64_t start;
+    uint64_t end;
+    logging_state_t logging2;
+    meta_t in_meta;
+    meta_t meta;
+    int output_compression;
+    int page_no;
+#if defined(SPANDSP_SUPPORT_TIFF_FX)
+    uint64_t offset;
+#endif
+
+    source_file = (argc > 1)  ?  argv[1]  :  IN_FILE_NAME;
+    printf("Processing '%s'\n", source_file);
+    destination_file = OUT_FILE_NAME;
+    output_compression = (argc > 2)  ?  atoi(argv[2]) : COMPRESSION_CCITT_T6;
+
+#if defined(SPANDSP_SUPPORT_TIFF_FX)
+    TIFF_FX_init();
+#endif
+
+    if ((in_meta.tif = TIFFOpen(source_file, "r")) == NULL)
+    {
+        printf("Unable to open '%s'!\n", source_file);
+        return 1;
+    }
+
+    if ((meta.tif = TIFFOpen(destination_file, "w")) == NULL)
+    {
+        printf("Unable to open '%s'!\n", destination_file);
+        return 1;
+    }
+    span_log_init(&logging2, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW, "lab");
+
+    /* The default luminant is D50 */
+    set_lab_illuminant(&lab_param, 96.422f, 100.000f,  82.521f);
+    set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, FALSE);
+
+    for (page_no = 0;   ;  page_no++)
+    {
+        if (read_file(&in_meta, page_no) < 0)
+        {
+            printf("Failed to read from %s\n", source_file);
+            TIFFClose(in_meta.tif);
+            TIFFClose(meta.tif);
+            exit(2);
+        }
+
+        tif = in_meta.tif;
+
+        nstrips = TIFFNumberOfStrips(tif);
+        if (in_meta.compression == output_compression  &&  nstrips == 1  &&  in_meta.tile_width == 0)
+        {
+            /* There might be no need to re-compress the image */
+        }
+        else
+        {
+            /* It looks like we need to decompress and recompress the image */
+        }
+
+        printf("Width %d, height %d, bits %d, samples %d\n", in_meta.image_width, in_meta.image_length, in_meta.bits_per_sample, in_meta.samples_per_pixel);
+
+        totdata = read_decompressed_image(&in_meta, &data);
+        off = totdata;
+
+        bytes_per_row = TIFFScanlineSize(tif);
+
+        printf("bits_per_sample %d, samples_per_pixel %d, w %d, h %d\n", in_meta.bits_per_sample, in_meta.samples_per_pixel, in_meta.image_width, in_meta.image_length);
+
+
+        printf("total %d, off %d\n", totdata, (int) off);
+
+        switch (in_meta.samples_per_pixel)
+        {
+        case 1:
+            if (in_meta.bits_per_sample == 1)
+            {
+                printf("Bi-level\n");
+
+                /* We have finished acquiring the image. Now we need to push it out */
+                meta.pre_compressed = FALSE;
+                meta.image_width = in_meta.image_width;
+                meta.image_length = in_meta.image_length;
+                meta.x_resolution = in_meta.x_resolution;
+                meta.y_resolution = in_meta.y_resolution;
+                meta.resolution_unit = in_meta.resolution_unit;
+                meta.bits_per_sample = in_meta.bits_per_sample;
+                meta.samples_per_pixel = in_meta.samples_per_pixel;
+                meta.compression = COMPRESSION_CCITT_T6;
+                meta.photometric = PHOTOMETRIC_MINISWHITE;
+
+                write_file(&meta, page_no, data);
+            }
+            else
+            {
+                printf("Gray scale, %d bits\n", in_meta.bits_per_sample);
+                if (in_meta.bits_per_sample == 8)
+                {
+                    /* Nothing needs to be done */
+                }
+                else if (in_meta.bits_per_sample == 16)
+                {
+                    if ((outptr = malloc(in_meta.image_width*in_meta.image_length)) == NULL)
+                        printf("Failed to allocate buffer\n");
+                    for (i = 0;  i < in_meta.image_width*in_meta.image_length;  i++)
+                        outptr[i] = data[2*i];
+                    free(data);
+                    data = (uint8_t *) outptr;
+                }
+                else
+                {
+                    uint32_t bitstream;
+                    int bits;
+                    int j;
+
+                    /* Deal with the messy cases where the number of bits is not a whole
+                       number of bytes. */                
+                    if ((outptr = malloc(in_meta.image_width*in_meta.image_length)) == NULL)
+                        printf("Failed to allocate buffer\n");
+                    bitstream = 0;
+                    bits = 0;
+                    j = 0;
+                    for (i = 0;  i < in_meta.image_width*in_meta.image_length;  i++)
+                    {
+                        while (bits < in_meta.bits_per_sample)
+                        {
+                            bitstream = (bitstream << 8) | data[j++];
+                            bits += 8;
+                        }
+                        outptr[i] = bitstream >> (bits - 8);
+                        bits -= in_meta.bits_per_sample;
+                    }
+                    free(data);
+                    data = (uint8_t *) outptr;
+                }
+                off = in_meta.samples_per_pixel*in_meta.image_width*in_meta.image_length;
+
+                /* We have finished acquiring the image. Now we need to push it out */
+                meta.pre_compressed = FALSE;
+                meta.image_width = in_meta.image_width;
+                meta.image_length = in_meta.image_length;
+                meta.x_resolution = in_meta.x_resolution;
+                meta.y_resolution = in_meta.y_resolution;
+                meta.resolution_unit = in_meta.resolution_unit;
+                meta.bits_per_sample = 8;
+                meta.samples_per_pixel = in_meta.samples_per_pixel;
+                meta.compression = COMPRESSION_JPEG;
+                meta.photometric = PHOTOMETRIC_MINISBLACK;
+
+                write_file(&meta, page_no, data);
+            }
+            break;
+        case 3:
+            printf("Photometric is %d\n", in_meta.photometric);
+
+            /* We now have the image in memory in RGB form */
+
+            if (in_meta.photometric == PHOTOMETRIC_ITULAB)
+            {
+                printf("ITU Lab\n");
+                /* We are already in the ITULAB color space */
+                if ((outptr = malloc(totdata)) == NULL)
+                    printf("Failed to allocate buffer\n");
+                lab_to_srgb(&lab_param, (tdata_t) outptr, data, totdata/3);
+                free(data);
+                data = (uint8_t *) outptr;
+
+                meta.pre_compressed = FALSE;
+                meta.image_width = in_meta.image_width;
+                meta.image_length = in_meta.image_length;
+                meta.x_resolution = in_meta.x_resolution;
+                meta.y_resolution = in_meta.y_resolution;
+                meta.resolution_unit = in_meta.resolution_unit;
+                meta.bits_per_sample = 8;
+                meta.samples_per_pixel = in_meta.samples_per_pixel;
+                meta.compression = COMPRESSION_JPEG;
+                meta.photometric = PHOTOMETRIC_RGB;
+            }
+            else
+            {
+#if 1
+                start = rdtscll();
+                switch (in_meta.photometric)
+                {
+                case PHOTOMETRIC_CIELAB:
+                    printf("CIELAB\n");
+                    /* Convert this to sRGB first */
+                    /* The default luminant is D50 */
+                    set_lab_illuminant(&lab_param, 96.422f, 100.000f,  82.521f);
+                    set_lab_gamut(&lab_param, 0, 100, -128, 127, -128, 127, TRUE);
+                    lab_to_srgb(&lab_param, data, data, in_meta.image_width*in_meta.image_length);
+                    break;
+                case PHOTOMETRIC_RGB:
+                    printf("RGB\n");
+                    if (in_meta.bits_per_sample == 8)
+                    {
+                    }
+                    else if (in_meta.bits_per_sample == 16)
+                    {
+                        printf("Pack %d to %d\n", totdata, in_meta.samples_per_pixel*in_meta.image_width*in_meta.image_length);
+                        if ((outptr = malloc(in_meta.samples_per_pixel*in_meta.image_width*in_meta.image_length)) == NULL)
+                            printf("Failed to allocate buffer\n");
+                        for (i = 0;  i < in_meta.image_width*in_meta.image_length;  i++)
+                        {
+                            outptr[in_meta.samples_per_pixel*i + 0] = (data[in_meta.samples_per_pixel*2*i + 1] << 4) | (data[in_meta.samples_per_pixel*2*i + 0] >> 4);
+                            outptr[in_meta.samples_per_pixel*i + 1] = (data[in_meta.samples_per_pixel*2*i + 3] << 4) | (data[in_meta.samples_per_pixel*2*i + 2] >> 4);
+                            outptr[in_meta.samples_per_pixel*i + 2] = (data[in_meta.samples_per_pixel*2*i + 5] << 4) | (data[in_meta.samples_per_pixel*2*i + 4] >> 4);
+                        }
+                        free(data);
+                        data = (uint8_t *) outptr;
+                        off = in_meta.samples_per_pixel*in_meta.image_width*in_meta.image_length;
+                        in_meta.bits_per_sample = 8;
+                    }
+                    else
+                    {
+                        uint32_t bitstream;
+                        int bits;
+                        int j;
+
+                        /* Deal with the messy cases where the number of bits is not a whole number of bytes. */                
+                        printf("Pack %d to %d\n", totdata, in_meta.samples_per_pixel*in_meta.image_width*in_meta.image_length);
+                        if ((outptr = malloc(in_meta.samples_per_pixel*in_meta.image_width*in_meta.image_length)) == NULL)
+                            printf("Failed to allocate buffer\n");
+                        bitstream = 0;
+                        bits = 0;
+                        j = 0;
+                        for (i = 0;  i < in_meta.image_width*in_meta.image_length;  i++)
+                        {
+                            for (k = 0;  k < in_meta.samples_per_pixel;  k++)
+                            {
+                                while (bits < in_meta.bits_per_sample)
+                                {
+                                    bitstream = (bitstream << 8) | data[j++];
+                                    bits += 8;
+                                }
+                                outptr[in_meta.samples_per_pixel*i + k] = bitstream >> (bits - 8);
+                                bits -= in_meta.bits_per_sample;
+                            }
+                        }
+                        free(data);
+                        data = (uint8_t *) outptr;
+                        off = in_meta.samples_per_pixel*in_meta.image_width*in_meta.image_length;
+                        in_meta.bits_per_sample = 8;
+                    }
+                    break;
+                }
+#if 0
+                /* The default luminant is D50 */
+                set_lab_illuminant(&lab_param, 96.422f, 100.000f,  82.521f);
+                set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, FALSE);
+                if (!t42_srgb_to_itulab_jpeg(&logging2, &lab_param, (tdata_t) &outptr, &outsize, data, off, in_meta.image_width, in_meta.image_length, 3))
+                {
+                    printf("Failed to convert to ITULAB (B).\n");
+                    return 1;
+                }
+                end = rdtscll();
+                printf("Duration %" PRIu64 "\n", end - start);
+                free(data);
+                data = (uint8_t *) outptr;
+                off = outsize;
+#endif
+#endif
+                meta.pre_compressed = FALSE;
+                meta.image_width = in_meta.image_width;
+                meta.image_length = in_meta.image_length;
+                meta.x_resolution = in_meta.x_resolution;
+                meta.y_resolution = in_meta.y_resolution;
+                meta.resolution_unit = in_meta.resolution_unit;
+                meta.bits_per_sample = 8;
+                meta.samples_per_pixel = in_meta.samples_per_pixel;
+                meta.compression = COMPRESSION_JPEG;
+                meta.photometric = PHOTOMETRIC_RGB;
+            }
+            write_file(&meta, page_no, data);
+            break;
+        case 4:
+            printf("Photometric is %d\n", in_meta.photometric);
+
+            /* We now have the image in memory in RGB form */
+
+            if (in_meta.photometric == PHOTOMETRIC_ITULAB)
+            {
+                /* We are already in the ITULAB color space */
+#if 0
+                if (!t42_itulab_to_itulab(&logging2, (tdata_t) &outptr, &outsize, data, off, in_meta.image_width, in_meta.image_length, 3))
+                {
+                    printf("Failed to convert to ITULAB (C).\n");
+                    return 1;
+                }
+#endif
+                free(data);
+                data = (uint8_t *) outptr;
+                off = outsize;
+            }
+            else
+            {
+                start = rdtscll();
+                switch (in_meta.photometric)
+                {
+                case PHOTOMETRIC_CIELAB:
+                    printf("CIELAB\n");
+                    /* TODO: This doesn't work yet */
+                    /* Convert this to sRGB first */
+                    /* The default luminant is D50 */
+                    set_lab_illuminant(&lab_param, 96.422f, 100.000f,  82.521f);
+                    set_lab_gamut(&lab_param, 0, 100, -128, 127, -128, 127, TRUE);
+                    lab_to_srgb(&lab_param, data, data, in_meta.image_width*in_meta.image_length);
+                    break;
+                case PHOTOMETRIC_SEPARATED:
+                    for (y = 0;  y < in_meta.image_length;  y++)
+                    {
+                        for (x = 0;  x < in_meta.image_width;  x++)
+                        {
+                            k = data[(y*in_meta.image_width + x)*4 + 0] + data[(y*in_meta.image_width + x)*4 + 3];
+                            if (k > 255)
+                                k = 255;
+                            data[(y*in_meta.image_width + x)*3 + 0] = 255 - k;
+                            k = data[(y*in_meta.image_width + x)*4 + 1] + data[(y*in_meta.image_width + x)*4 + 3];
+                            if (k > 255)
+                                k = 255;
+                            data[(y*in_meta.image_width + x)*3 + 1] = 255 - k;
+                            k = data[(y*in_meta.image_width + x)*4 + 2] + data[(y*in_meta.image_width + x)*4 + 3];
+                            if (k > 255)
+                                k = 255;
+                            data[(y*in_meta.image_width + x)*3 + 2] = 255 - k;
+                        }
+                    }
+                    off = 3*in_meta.image_width*in_meta.image_length;
+                    in_meta.bits_per_sample = 8;
+                    break;
+                }
+
+                /* The default luminant is D50 */
+                set_lab_illuminant(&lab_param, 96.422f, 100.000f,  82.521f);
+                set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, FALSE);
+                //if (!t42_srgb_to_itulab_jpeg(&logging2, &lab_param, (tdata_t) &outptr, &outsize, data, off, in_meta.image_width, in_meta.image_length, 3))
+                {
+                    printf("Failed to convert to ITULAB (D).\n");
+                    return 1;
+                }
+                end = rdtscll();
+                printf("Duration %" PRIu64 "\n", end - start);
+                off = outsize;
+                in_meta.bits_per_sample = 8;
+            }
+            meta.pre_compressed = FALSE;
+            meta.image_width = in_meta.image_width;
+            meta.image_length = in_meta.image_length;
+            meta.x_resolution = in_meta.x_resolution;
+            meta.y_resolution = in_meta.y_resolution;
+            meta.resolution_unit = in_meta.resolution_unit;
+            meta.bits_per_sample = 8;
+            meta.samples_per_pixel = 3;
+            meta.compression = COMPRESSION_JPEG;
+            meta.photometric = PHOTOMETRIC_RGB;
+
+            write_file(&meta, page_no, data);
+            break;
+        }
+    }
+
+
+
+    printf("XXX - image is %d by %d, %d bytes\n", in_meta.image_width, in_meta.image_length, (int) off);
+
+    /* We now have the image in memory in ITULAB form */
+
+    meta.pre_compressed = FALSE;
+    meta.compressed_image_len = off;
+    meta.image_width = in_meta.image_width;
+    meta.image_length = in_meta.image_length;
+    meta.x_resolution = in_meta.x_resolution;
+    meta.y_resolution = in_meta.y_resolution;
+    meta.resolution_unit = in_meta.resolution_unit;
+    meta.bits_per_sample = 8;
+    meta.samples_per_pixel = 3;
+    meta.compression = COMPRESSION_JPEG;
+#if 1
+    meta.photometric = PHOTOMETRIC_RGB;
+#elif 1
+    /* Most image processors won't know what to do with the ITULAB colorspace.
+       So we'll be converting it to RGB for portability. */
+    /* If PHOTOMETRIC_ITULAB is not available the admin cannot enable color fax anyway.
+       This is done so that older libtiffs without it can build fine. */
+    meta.photometric = PHOTOMETRIC_ITULAB;
+#else
+    meta.photometric = PHOTOMETRIC_YCBCR;
+#endif
+    meta.YCbCrSubsampleHoriz = in_meta.YCbCrSubsampleHoriz;
+    meta.YCbCrSubsampleVert = in_meta.YCbCrSubsampleVert;
+
+    if ((tif = TIFFOpen(destination_file, "w")) == NULL)
+    {
+        printf("Unable to open '%s'!\n", destination_file);
+        return 1;
+    }
+    TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
+    TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, meta.image_width);
+    /* libtiff requires IMAGELENGTH to be set before SAMPLESPERPIXEL,
+       or StripOffsets and StripByteCounts will have SAMPLESPERPIXEL values */
+    TIFFSetField(tif, TIFFTAG_IMAGELENGTH, meta.image_length);
+    TIFFSetField(tif, TIFFTAG_COMPRESSION, meta.compression);
+    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, meta.bits_per_sample);
+    TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, meta.samples_per_pixel);
+    TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+    TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+    TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, meta.image_length);
+    TIFFSetField(tif, TIFFTAG_XRESOLUTION, meta.x_resolution);
+    TIFFSetField(tif, TIFFTAG_YRESOLUTION, meta.y_resolution);
+    TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, meta.resolution_unit);
+    TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, meta.photometric);
+    if (meta.samples_per_pixel > 1  &&  (meta.YCbCrSubsampleHoriz  ||  meta.YCbCrSubsampleVert))
+        TIFFSetField(tif, TIFFTAG_YCBCRSUBSAMPLING, meta.YCbCrSubsampleHoriz, meta.YCbCrSubsampleVert);
+    TIFFSetField(tif, TIFFTAG_SOFTWARE, "spandsp");
+    TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, "Test");
+    TIFFSetField(tif, TIFFTAG_DATETIME, "2011/02/03 12:30:45");
+    TIFFSetField(tif, TIFFTAG_MAKE, "soft-switch.org");
+    TIFFSetField(tif, TIFFTAG_MODEL, "spandsp");
+    TIFFSetField(tif, TIFFTAG_HOSTCOMPUTER, "i7.coppice.org");
+#if defined(SPANDSP_SUPPORT_TIFF_FX)
+    /* Make space for this to be filled in later */
+    TIFFSetField(tif, TIFFTAG_GLOBALPARAMETERSIFD, 0);
+#endif
+
+    if (meta.pre_compressed)
+    {
+        if (TIFFWriteRawStrip(tif, 0, (tdata_t) data, meta.compressed_image_len) == -1)
+        {
+            printf("Write error to TIFF file\n");
+            return 1;
+        }
+        free(data);
+    }
+    else
+    {
+        if (in_meta.samples_per_pixel > 1)
+        {
+            bytes_per_row = ((meta.bits_per_sample + 7)/8)*meta.image_width*meta.samples_per_pixel;
+            totdata = meta.image_length*bytes_per_row;
+            /* The default luminant is D50 */
+            set_lab_illuminant(&lab_param, 96.422f, 100.000f,  82.521f);
+            set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, FALSE);
+#if 0
+            start = rdtscll();
+            data2 = NULL;
+            totdata = 0;
+            if (!t42_itulab_to_JPEG(&logging2, &lab_param, (void **) &data2, &totdata, data, off))
+            {
+                printf("Failed to convert from ITULAB (A).\n");
+                return 1;
+            }
+            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 (B).\n");
+                return 1;
+            }
+            free(data);
+            data = data2;
+#elif 1
+            data2 = malloc(totdata);
+            start = rdtscll();
+            //if (!t42_itulab_jpeg_to_srgb(&logging2, &lab_param, data2, &off, data, off, &meta.image_width, &meta.image_length, &meta.samples_per_pixel))
+            {
+                printf("Failed to convert from ITULAB.\n");
+                return 1;
+            }
+            end = rdtscll();
+            printf("Duration %" PRIu64 "\n", end - start);
+            free(data);
+            data = data2;
+#endif
+        }
+        off = 0;
+        bytes_per_row = ((meta.bits_per_sample + 7)/8)*meta.image_width*meta.samples_per_pixel;
+        for (row = 0;  row < meta.image_length;  row++)
+        {
+            if (TIFFWriteScanline(tif, &data[off], row, 0) < 0)
+                return 1;
+            off += bytes_per_row;
+        }
+        free(data);
+    }
+
+    if (!TIFFWriteDirectory(tif))
+        printf("Failed to write directory.\n");
+
+#if defined(SPANDSP_SUPPORT_TIFF_FX)
+    if (!TIFFCreateCustomDirectory(tif, &tiff_fx_field_array))
+    {
+        TIFFSetField(tif, TIFFTAG_PROFILETYPE, PROFILETYPE_G3_FAX);
+        TIFFSetField(tif, TIFFTAG_FAXPROFILE, FAXPROFILE_F);
+        TIFFSetField(tif, TIFFTAG_CODINGMETHODS, CODINGMETHODS_T4_1D | CODINGMETHODS_T4_2D | CODINGMETHODS_T6);
+        TIFFSetField(tif, TIFFTAG_VERSIONYEAR, "1998");
+        TIFFSetField(tif, TIFFTAG_MODENUMBER, 3);
+
+        offset = 0;
+        if (!TIFFWriteCustomDirectory(tif, &offset))
+            printf("Failed to write custom directory.\n");
+
+        if (!TIFFSetDirectory(tif, (tdir_t) page_no))
+            printf("Failed to set directory.\n");
+        if (!TIFFSetField(tif, TIFFTAG_GLOBALPARAMETERSIFD, offset))
+            printf("Failed to set global parameters IFD.\n");
+        if (!TIFFWriteDirectory(tif))
+            printf("Failed to write directory.\n");
+    }
+#endif
+    TIFFClose(tif);
+    printf("Done!\n");
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
index 96f2c251627a01f949da5a0c5b70f8fb60787c79..c153a6c8031d5e489ea8c74a09186d506d6cfdca 100644 (file)
 
 #include "udptl.h"
 
+#if !defined(FALSE)
 #define FALSE 0
+#endif
+#if !defined(TRUE)
 #define TRUE (!FALSE)
+#endif
 
 static int decode_length(const uint8_t *buf, int limit, int *len, int *pvalue)
 {
@@ -58,7 +62,7 @@ static int decode_length(const uint8_t *buf, int limit, int *len, int *pvalue)
         return 0;
     }
     *pvalue = (buf[(*len)++] & 0x3F) << 14;
-    /* Indicate we have a fragment */
+    /* Indicate that we have a fragment */
     return 1;
 }
 /*- End of function --------------------------------------------------------*/
@@ -66,11 +70,13 @@ static int decode_length(const uint8_t *buf, int limit, int *len, int *pvalue)
 static int decode_open_type(const uint8_t *buf, int limit, int *len, const uint8_t **p_object, int *p_num_octets)
 {
     int octet_cnt;
+#if 0
     int octet_idx;
     int stat;
     const uint8_t **pbuf;
 
-    for (octet_idx = 0, *p_num_octets = 0;  ;  octet_idx += octet_cnt)
+    *p_num_octets = 0;
+    for (octet_idx = 0;  ;  octet_idx += octet_cnt)
     {
         if ((stat = decode_length(buf, limit, len, &octet_cnt)) < 0)
             return -1;
@@ -89,6 +95,21 @@ static int decode_open_type(const uint8_t *buf, int limit, int *len, const uint8
         if (stat == 0)
             break;
     }
+#else
+    /* We do not deal with fragments, so there is no point in looping through them. Just say that something
+       fragmented is bad. */
+    if (decode_length(buf, limit, len, &octet_cnt) != 0)
+        return -1;
+    *p_num_octets = octet_cnt;
+    if (octet_cnt > 0)
+    {
+        /* Make sure the buffer contains at least the number of bits requested */
+        if ((*len + octet_cnt) > limit)
+            return -1;
+        *p_object = &buf[*len];
+        *len += octet_cnt;
+    }
+#endif
     return 0;
 }
 /*- End of function --------------------------------------------------------*/
@@ -153,7 +174,6 @@ static int encode_open_type(uint8_t *buf, int *len, const uint8_t *data, int num
 int udptl_rx_packet(udptl_state_t *s, const uint8_t buf[], int len)
 {
     int stat;
-    int stat2;
     int i;
     int j;
     int k;
@@ -216,16 +236,16 @@ int udptl_rx_packet(udptl_state_t *s, const uint8_t buf[], int len)
         total_count = 0;
         do
         {
-            if ((stat2 = decode_length(buf, len, &ptr, &count)) < 0)
+            if ((stat = decode_length(buf, len, &ptr, &count)) < 0)
                 return -1;
             for (i = 0;  i < count;  i++)
             {
-                if ((stat = decode_open_type(buf, len, &ptr, &bufs[total_count + i], &lengths[total_count + i])) != 0)
+                if (decode_open_type(buf, len, &ptr, &bufs[total_count + i], &lengths[total_count + i]) != 0)
                     return -1;
             }
             total_count += count;
         }
-        while (stat2 > 0);
+        while (stat > 0);
         /* We should now be exactly at the end of the packet. If not, this is a fault. */
         if (ptr != len)
             return -1;
@@ -246,7 +266,8 @@ int udptl_rx_packet(udptl_state_t *s, const uint8_t buf[], int len)
                     /* Save the new packet. Redundancy mode won't use this, but some systems will switch into
                        FEC mode after sending some redundant packets, and this may then be important. */
                     x = (seq_no - i) & UDPTL_BUF_MASK;
-                    memcpy(s->rx[x].buf, bufs[i - 1], lengths[i - 1]);
+                    if (lengths[i - 1] > 0)
+                        memcpy(s->rx[x].buf, bufs[i - 1], lengths[i - 1]);
                     s->rx[x].buf_len = lengths[i - 1];
                     s->rx[x].fec_len[0] = 0;
                     s->rx[x].fec_span = 0;