diff --git a/libs/spandsp/src/spandsp/image_translate.h b/libs/spandsp/src/spandsp/image_translate.h
index 7f91c2db0a..d98848f369 100644
--- a/libs/spandsp/src/spandsp/image_translate.h
+++ b/libs/spandsp/src/spandsp/image_translate.h
@@ -34,6 +34,11 @@
 /*! \page image_translate_page Image translation
 \section image_translate_page_sec_1 What does it do?
 
+The image translate functions allow an image to be translated and resized between
+various colour an monochrome formats. It also allows a colour or gray-scale image
+to be reduced to a bi-level monochrome image. This is useful for preparing images
+to be sent as traditional bi-level FAX pages.
+
 \section image_translate_page_sec_2 How does it work?
 
 \section image_translate_page_sec_3 How do I use it?
diff --git a/libs/spandsp/src/spandsp/private/fax_modems.h b/libs/spandsp/src/spandsp/private/fax_modems.h
index e9adaa47b6..b0df18c00c 100644
--- a/libs/spandsp/src/spandsp/private/fax_modems.h
+++ b/libs/spandsp/src/spandsp/private/fax_modems.h
@@ -115,9 +115,15 @@ struct fax_modems_state_s
 
     /*! \brief The current receive signal handler */
     span_rx_handler_t rx_handler;
+    /*! \brief The current receive signal handler. Actual receiving hops between this
+               and a dummy receive routine. */
+    span_rx_handler_t base_rx_handler;
     void *rx_user_data;
     /*! \brief The current receive missing signal fill-in handler */
     span_rx_fillin_handler_t rx_fillin_handler;
+    /*! \brief The current receive signal fillin handler. Actual receiving hops between this
+               and a dummy receive routine. */
+    span_rx_fillin_handler_t base_rx_fillin_handler;
     void *rx_fillin_user_data;
 
     /*! \brief The current transmit signal handler */
diff --git a/libs/spandsp/src/spandsp/private/t38_gateway.h b/libs/spandsp/src/spandsp/private/t38_gateway.h
index af72e78213..fbe1409322 100644
--- a/libs/spandsp/src/spandsp/private/t38_gateway.h
+++ b/libs/spandsp/src/spandsp/private/t38_gateway.h
@@ -59,10 +59,6 @@ typedef struct
 {
     /*! \brief The FAX modem set for the audio side fo the gateway. */
     fax_modems_state_t modems;
-    /*! \brief The current receive signal handler. Actual receiving hops between this
-               and a dummy receive routine. */
-    span_rx_handler_t base_rx_handler;
-    span_rx_fillin_handler_t base_rx_fillin_handler;
 } t38_gateway_audio_state_t;
 
 /*!
diff --git a/libs/spandsp/src/spandsp/private/t85.h b/libs/spandsp/src/spandsp/private/t85.h
index 2d180c9baf..c3e62e8c83 100644
--- a/libs/spandsp/src/spandsp/private/t85.h
+++ b/libs/spandsp/src/spandsp/private/t85.h
@@ -62,7 +62,7 @@ struct t85_encode_state_s
     uint32_t xd;
     /*! The height of the full image, in pixels */
     uint32_t yd;
-    /*! Then number of rows per stripe */
+    /*! The number of rows per stripe */
     uint32_t l0;
     /*! Maximum ATMOVE window size (0 - 127) */
     int mx;
diff --git a/libs/spandsp/src/spandsp/t85.h b/libs/spandsp/src/spandsp/t85.h
index d599626eed..07dd88931f 100644
--- a/libs/spandsp/src/spandsp/t85.h
+++ b/libs/spandsp/src/spandsp/t85.h
@@ -87,6 +87,12 @@ SPAN_DECLARE(int) t85_encode_set_row_read_handler(t85_encode_state_t *s,
                                                   t4_row_read_handler_t handler,
                                                   void *user_data);
 
+/*! Get the logging context associated with a T.85 encode context.
+    \brief Get the logging context associated with a T.85 encode context.
+    \param s The T.85 encode context.
+    \return A pointer to the logging context */
+SPAN_DECLARE(logging_state_t *) t85_encode_get_logging_state(t85_encode_state_t *s);
+
 /*! \brief Prepare to encode an image in T.85 format.
     \param s The T.85 context.
     \param image_width Image width, in pixels.
@@ -164,6 +170,12 @@ SPAN_DECLARE(int) t85_encode_get_compressed_image_size(t85_encode_state_t *s);
     \param s The T.85 context. */
 SPAN_DECLARE(void) t85_encode_abort(t85_encode_state_t *s);
 
+/*! Get the logging context associated with a T.85 decode context.
+    \brief Get the logging context associated with a T.85 decode context.
+    \param s The T.85 decode context.
+    \return A pointer to the logging context */
+SPAN_DECLARE(logging_state_t *) t85_decode_get_logging_state(t85_decode_state_t *s);
+
 /*! \brief Prepare to decode an image in T.85 format.
     \param s The T.85 context.
     \param handler A callback routine to handle decoded image rows.
diff --git a/libs/spandsp/src/t38_gateway.c b/libs/spandsp/src/t38_gateway.c
index 570cbdc625..a4a5873e52 100644
--- a/libs/spandsp/src/t38_gateway.c
+++ b/libs/spandsp/src/t38_gateway.c
@@ -196,43 +196,31 @@ static void non_ecm_remove_fill_and_put_bit(void *user_data, int bit);
 static void non_ecm_push_residue(t38_gateway_state_t *s);
 static void tone_detected(void *user_data, int tone, int level, int delay);
 
-static void set_rx_handler(t38_gateway_state_t *s,
+static void set_rx_handler(fax_modems_state_t *s,
                            span_rx_handler_t handler,
                            void *user_data,
                            span_rx_fillin_handler_t fillin_handler,
-                           void *rx_fillin_user_data)
+                           void *fillin_user_data)
 {
-    if (s->audio.modems.rx_handler != span_dummy_rx)
-    {
-        s->audio.modems.rx_handler = handler;
-        s->audio.modems.rx_fillin_handler = fillin_handler;
-    }
+    /* Only update the actual handlers if they are not currently sidelined to dummy targets */
+    if (s->rx_handler != span_dummy_rx)
+        s->rx_handler = handler;
     /*endif*/
-    s->audio.base_rx_handler = handler;
-    s->audio.base_rx_fillin_handler = fillin_handler;
-    s->audio.modems.rx_user_data = user_data;
-    s->audio.modems.rx_fillin_user_data = rx_fillin_user_data;
-}
-/*- End of function --------------------------------------------------------*/
+    s->base_rx_handler = handler;
+    s->rx_user_data = user_data;
 
-static void set_tx_handler(t38_gateway_state_t *s, span_tx_handler_t handler, void *user_data)
-{
-    s->audio.modems.tx_handler = handler;
-    s->audio.modems.tx_user_data = user_data;
-}
-/*- End of function --------------------------------------------------------*/
-
-static void set_next_tx_handler(t38_gateway_state_t *s, span_tx_handler_t handler, void *user_data)
-{
-    s->audio.modems.next_tx_handler = handler;
-    s->audio.modems.next_tx_user_data = user_data;
+    if (s->rx_fillin_handler != span_dummy_rx_fillin)
+        s->rx_fillin_handler = fillin_handler;
+    /*endif*/
+    s->base_rx_fillin_handler = fillin_handler;
+    s->rx_fillin_user_data = fillin_user_data;
 }
 /*- End of function --------------------------------------------------------*/
 
 static void set_rx_active(t38_gateway_state_t *s, int active)
 {
-    s->audio.modems.rx_handler = (active)  ?  s->audio.base_rx_handler  :  span_dummy_rx;
-    s->audio.modems.rx_fillin_handler = (active)  ?  s->audio.base_rx_fillin_handler  :  span_dummy_rx_fillin;
+    s->audio.modems.rx_handler = (active)  ?  s->audio.modems.base_rx_handler  :  span_dummy_rx;
+    s->audio.modems.rx_fillin_handler = (active)  ?  s->audio.modems.base_rx_fillin_handler  :  span_dummy_rx_fillin;
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -259,18 +247,17 @@ static int v17_v21_rx(void *user_data, const int16_t amp[], int len)
     v17_rx(&s->fast_modems.v17_rx, amp, len);
     if (s->rx_trained)
     {
-        /* The fast modem has trained, so we no longer need to run the slow
-           one in parallel. */
-        span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.17 + V.21 to V.17 (%.2fdBm0)\n", v17_rx_signal_power(&s->fast_modems.v17_rx));
-        set_rx_handler(t, (span_rx_handler_t) &v17_rx, &s->fast_modems.v17_rx, (span_rx_fillin_handler_t) &v17_rx_fillin, &s->fast_modems.v17_rx);
+        /* The fast modem has trained, so we no longer need to run the slow one in parallel. */
+        span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.17 + V.21 to V.17 (%.2fdBm0)\n", v17_rx_signal_power(&s->fast_modems.v17_rx));
+        set_rx_handler(s, (span_rx_handler_t) &v17_rx, &s->fast_modems.v17_rx, (span_rx_fillin_handler_t) &v17_rx_fillin, &s->fast_modems.v17_rx);
     }
     else
     {
         fsk_rx(&s->v21_rx, amp, len);
         if (s->rx_signal_present)
         {
-            span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.17 + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
-            set_rx_handler(t, (span_rx_handler_t) &fsk_rx, &s->v21_rx, (span_rx_fillin_handler_t) &fsk_rx_fillin, &s->v21_rx);
+            span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.17 + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
+            set_rx_handler(s, (span_rx_handler_t) &fsk_rx, &s->v21_rx, (span_rx_fillin_handler_t) &fsk_rx_fillin, &s->v21_rx);
         }
         /*endif*/
     }
@@ -302,18 +289,17 @@ static int v27ter_v21_rx(void *user_data, const int16_t amp[], int len)
     v27ter_rx(&s->fast_modems.v27ter_rx, amp, len);
     if (s->rx_trained)
     {
-        /* The fast modem has trained, so we no longer need to run the slow
-           one in parallel. */
-        span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.27ter + V.21 to V.27ter (%.2fdBm0)\n", v27ter_rx_signal_power(&s->fast_modems.v27ter_rx));
-        set_rx_handler(t, (span_rx_handler_t) &v27ter_rx, &s->fast_modems.v27ter_rx, (span_rx_fillin_handler_t) &v27ter_v21_rx_fillin, &s->fast_modems.v27ter_rx);
+        /* The fast modem has trained, so we no longer need to run the slow one in parallel. */
+        span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.27ter + V.21 to V.27ter (%.2fdBm0)\n", v27ter_rx_signal_power(&s->fast_modems.v27ter_rx));
+        set_rx_handler(s, (span_rx_handler_t) &v27ter_rx, &s->fast_modems.v27ter_rx, (span_rx_fillin_handler_t) &v27ter_v21_rx_fillin, &s->fast_modems.v27ter_rx);
     }
     else
     {
         fsk_rx(&s->v21_rx, amp, len);
         if (s->rx_signal_present)
         {
-            span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.27ter + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
-            set_rx_handler(t, (span_rx_handler_t) &fsk_rx, &s->v21_rx, (span_rx_fillin_handler_t) &fsk_rx_fillin, &s->v21_rx);
+            span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.27ter + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
+            set_rx_handler(s, (span_rx_handler_t) &fsk_rx, &s->v21_rx, (span_rx_fillin_handler_t) &fsk_rx_fillin, &s->v21_rx);
         }
         /*endif*/
     }
@@ -345,18 +331,17 @@ static int v29_v21_rx(void *user_data, const int16_t amp[], int len)
     v29_rx(&s->fast_modems.v29_rx, amp, len);
     if (s->rx_trained)
     {
-        /* The fast modem has trained, so we no longer need to run the slow
-           one in parallel. */
-        span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.29 + V.21 to V.29 (%.2fdBm0)\n", v29_rx_signal_power(&s->fast_modems.v29_rx));
-        set_rx_handler(t, (span_rx_handler_t) &v29_rx, &s->fast_modems.v29_rx, (span_rx_fillin_handler_t) &v29_rx_fillin, &s->fast_modems.v29_rx);
+        /* The fast modem has trained, so we no longer need to run the slow one in parallel. */
+        span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.29 + V.21 to V.29 (%.2fdBm0)\n", v29_rx_signal_power(&s->fast_modems.v29_rx));
+        set_rx_handler(s, (span_rx_handler_t) &v29_rx, &s->fast_modems.v29_rx, (span_rx_fillin_handler_t) &v29_rx_fillin, &s->fast_modems.v29_rx);
     }
     else
     {
         fsk_rx(&s->v21_rx, amp, len);
         if (s->rx_signal_present)
         {
-            span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.29 + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
-            set_rx_handler(t, (span_rx_handler_t) &fsk_rx, &s->v21_rx, (span_rx_fillin_handler_t) &fsk_rx_fillin, &s->v21_rx);
+            span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.29 + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
+            set_rx_handler(s, (span_rx_handler_t) &fsk_rx, &s->v21_rx, (span_rx_fillin_handler_t) &fsk_rx_fillin, &s->v21_rx);
         }
         /*endif*/
     }
@@ -434,8 +419,8 @@ static int set_next_tx_type(t38_gateway_state_t *s)
     if (t->next_tx_handler)
     {
         /* There is a handler queued, so that is the next one. */
-        set_tx_handler(s, t->next_tx_handler, t->next_tx_user_data);
-        set_next_tx_handler(s, NULL, NULL);
+        fax_modems_set_tx_handler(t, t->next_tx_handler, t->next_tx_user_data);
+        fax_modems_set_next_tx_handler(t, NULL, NULL);
         if (t->tx_handler == (span_tx_handler_t) &silence_gen
             ||
             t->tx_handler == (span_tx_handler_t) &tone_gen)
@@ -485,23 +470,23 @@ static int set_next_tx_type(t38_gateway_state_t *s)
         t->tx_bit_rate = 0;
         /* Impose 75ms minimum on transmitted silence */
         //silence_gen_set(&t->silence_gen, ms_to_samples(75));
-        set_tx_handler(s, (span_tx_handler_t) &silence_gen, &t->silence_gen);
-        set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL);
+        fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen);
+        fax_modems_set_next_tx_handler(t, (span_tx_handler_t) NULL, NULL);
         set_rx_active(s, TRUE);
         break;
     case T38_IND_CNG:
         t->tx_bit_rate = 0;
         modem_connect_tones_tx_init(&t->connect_tx, MODEM_CONNECT_TONES_FAX_CNG);
-        set_tx_handler(s, (span_tx_handler_t) &modem_connect_tones_tx, &t->connect_tx);
+        fax_modems_set_tx_handler(t, (span_tx_handler_t) &modem_connect_tones_tx, &t->connect_tx);
         silence_gen_set(&t->silence_gen, 0);
-        set_next_tx_handler(s, (span_tx_handler_t) &silence_gen, &t->silence_gen);
+        fax_modems_set_next_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen);
         set_rx_active(s, TRUE);
         break;
     case T38_IND_CED:
         t->tx_bit_rate = 0;
         modem_connect_tones_tx_init(&t->connect_tx, MODEM_CONNECT_TONES_FAX_CED);
-        set_tx_handler(s, (span_tx_handler_t) &modem_connect_tones_tx, &t->connect_tx);
-        set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL);
+        fax_modems_set_tx_handler(t, (span_tx_handler_t) &modem_connect_tones_tx, &t->connect_tx);
+        fax_modems_set_next_tx_handler(t, (span_tx_handler_t) NULL, NULL);
         set_rx_active(s, TRUE);
         break;
     case T38_IND_V21_PREAMBLE:
@@ -511,8 +496,8 @@ static int set_next_tx_type(t38_gateway_state_t *s)
         silence_gen_alter(&t->silence_gen, ms_to_samples(75));
         u->buf[u->in].len = 0;
         fsk_tx_init(&t->v21_tx, &preset_fsk_specs[FSK_V21CH2], (get_bit_func_t) hdlc_tx_get_bit, &t->hdlc_tx);
-        set_tx_handler(s, (span_tx_handler_t) &silence_gen, &t->silence_gen);
-        set_next_tx_handler(s, (span_tx_handler_t) &fsk_tx, &t->v21_tx);
+        fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen);
+        fax_modems_set_next_tx_handler(t, (span_tx_handler_t) &fsk_tx, &t->v21_tx);
         set_rx_active(s, TRUE);
         break;
     case T38_IND_V27TER_2400_TRAINING:
@@ -522,8 +507,8 @@ static int set_next_tx_type(t38_gateway_state_t *s)
         silence_gen_alter(&t->silence_gen, ms_to_samples(75));
         v27ter_tx_restart(&t->fast_modems.v27ter_tx, t->tx_bit_rate, t->use_tep);
         v27ter_tx_set_get_bit(&t->fast_modems.v27ter_tx, get_bit_func, get_bit_user_data);
-        set_tx_handler(s, (span_tx_handler_t) &silence_gen, &t->silence_gen);
-        set_next_tx_handler(s, (span_tx_handler_t) &v27ter_tx, &t->fast_modems.v27ter_tx);
+        fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen);
+        fax_modems_set_next_tx_handler(t, (span_tx_handler_t) &v27ter_tx, &t->fast_modems.v27ter_tx);
         set_rx_active(s, TRUE);
         break;
     case T38_IND_V29_7200_TRAINING:
@@ -533,8 +518,8 @@ static int set_next_tx_type(t38_gateway_state_t *s)
         silence_gen_alter(&t->silence_gen, ms_to_samples(75));
         v29_tx_restart(&t->fast_modems.v29_tx, t->tx_bit_rate, t->use_tep);
         v29_tx_set_get_bit(&t->fast_modems.v29_tx, get_bit_func, get_bit_user_data);
-        set_tx_handler(s, (span_tx_handler_t) &silence_gen, &t->silence_gen);
-        set_next_tx_handler(s, (span_tx_handler_t) &v29_tx, &t->fast_modems.v29_tx);
+        fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen);
+        fax_modems_set_next_tx_handler(t, (span_tx_handler_t) &v29_tx, &t->fast_modems.v29_tx);
         set_rx_active(s, TRUE);
         break;
     case T38_IND_V17_7200_SHORT_TRAINING:
@@ -582,8 +567,8 @@ static int set_next_tx_type(t38_gateway_state_t *s)
         silence_gen_alter(&t->silence_gen, ms_to_samples(75));
         v17_tx_restart(&t->fast_modems.v17_tx, t->tx_bit_rate, t->use_tep, short_train);
         v17_tx_set_get_bit(&t->fast_modems.v17_tx, get_bit_func, get_bit_user_data);
-        set_tx_handler(s, (span_tx_handler_t) &silence_gen, &t->silence_gen);
-        set_next_tx_handler(s, (span_tx_handler_t) &v17_tx, &t->fast_modems.v17_tx);
+        fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen);
+        fax_modems_set_next_tx_handler(t, (span_tx_handler_t) &v17_tx, &t->fast_modems.v17_tx);
         set_rx_active(s, TRUE);
         break;
     case T38_IND_V8_ANSAM:
@@ -2150,23 +2135,23 @@ static int restart_rx_modem(t38_gateway_state_t *s)
     case FAX_MODEM_V27TER_RX:
         v27ter_rx_restart(&t->fast_modems.v27ter_rx, s->core.fast_bit_rate, FALSE);
         v27ter_rx_set_put_bit(&t->fast_modems.v27ter_rx, put_bit_func, put_bit_user_data);
-        set_rx_handler(s, &v27ter_v21_rx, s, &v27ter_v21_rx_fillin, s);
+        set_rx_handler(t, &v27ter_v21_rx, s, &v27ter_v21_rx_fillin, s);
         s->core.fast_rx_active = FAX_MODEM_V27TER_RX;
         break;
     case FAX_MODEM_V29_RX:
         v29_rx_restart(&t->fast_modems.v29_rx, s->core.fast_bit_rate, FALSE);
         v29_rx_set_put_bit(&t->fast_modems.v29_rx, put_bit_func, put_bit_user_data);
-        set_rx_handler(s, &v29_v21_rx, s, &v29_v21_rx_fillin, s);
+        set_rx_handler(t, &v29_v21_rx, s, &v29_v21_rx_fillin, s);
         s->core.fast_rx_active = FAX_MODEM_V29_RX;
         break;
     case FAX_MODEM_V17_RX:
         v17_rx_restart(&t->fast_modems.v17_rx, s->core.fast_bit_rate, s->core.short_train);
         v17_rx_set_put_bit(&t->fast_modems.v17_rx, put_bit_func, put_bit_user_data);
-        set_rx_handler(s, &v17_v21_rx, s, &v17_v21_rx_fillin, s);
+        set_rx_handler(t, &v17_v21_rx, s, &v17_v21_rx_fillin, s);
         s->core.fast_rx_active = FAX_MODEM_V17_RX;
         break;
     default:
-        set_rx_handler(s, (span_rx_handler_t) &fsk_rx, &t->v21_rx, (span_rx_fillin_handler_t) &fsk_rx_fillin, &t->v21_rx);
+        set_rx_handler(t, (span_rx_handler_t) &fsk_rx, &t->v21_rx, (span_rx_fillin_handler_t) &fsk_rx_fillin, &t->v21_rx);
         s->core.fast_rx_active = FAX_MODEM_NONE;
         break;
     }
diff --git a/libs/spandsp/src/t4_tx.c b/libs/spandsp/src/t4_tx.c
index 37bffa23bf..f33effb577 100644
--- a/libs/spandsp/src/t4_tx.c
+++ b/libs/spandsp/src/t4_tx.c
@@ -260,14 +260,7 @@ static int get_tiff_directory_info(t4_tx_state_t *s)
     }
     t4_tx_set_image_width(s, s->image_width);
     t4_tx_set_image_length(s, s->image_length);
-    switch (s->line_encoding)
-    {
-    case T4_COMPRESSION_ITU_T4_1D:
-    case T4_COMPRESSION_ITU_T4_2D:
-    case T4_COMPRESSION_ITU_T6:
-        t4_t6_encode_set_max_2d_rows_per_1d_row(&s->encoder.t4_t6, -s->metadata.y_resolution);
-        break;
-    }
+    t4_tx_set_max_2d_rows_per_1d_row(s, -s->metadata.y_resolution);
 #if defined(SPANDSP_SUPPORT_TIFF_FX)
     if (TIFFGetField(t->tiff_file, TIFFTAG_PROFILETYPE, &parm32))
         span_log(&s->logging, SPAN_LOG_FLOW, "Profile type %u\n", parm32);