]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Image translate moves forward a little, towards colour support
authorSteve Underwood <steveu@coppice.org>
Wed, 8 Aug 2012 13:26:06 +0000 (21:26 +0800)
committerSteve Underwood <steveu@coppice.org>
Wed, 8 Aug 2012 13:26:06 +0000 (21:26 +0800)
libs/spandsp/src/image_translate.c
libs/spandsp/src/spandsp/image_translate.h
libs/spandsp/src/spandsp/private/image_translate.h
libs/spandsp/tests/image_translate_tests.c

index 785997def5e95a31635b51f9f74d87382b9bd914..54037990fc5e76c9c72a0b3bbe09f729c00991df 100644 (file)
@@ -2,8 +2,9 @@
  * SpanDSP - a series of DSP components for telephony
  *
  * image_translate.c - Image translation routines for reworking colour
- *                     and gray scale images to be bi-level images of an
- *                     appropriate size to be FAX compatible.
+ *                     and gray scale images to be colour, gray scale or
+ *                     bi-level images of an appropriate size to be FAX
+ *                     compatible.
  *
  * Written by Steve Underwood <steveu@coppice.org>
  *
 #include "spandsp/private/t4_rx.h"
 #include "spandsp/private/t4_tx.h"
 
-static int image_colour16_to_gray8_row(uint8_t mono[], uint16_t colour[], int pixels)
+static int image_colour16_to_colour8_row(uint8_t colour8[], uint16_t colour16[], int pixels)
+{
+    int i;
+
+    for (i = 0;  i < 3*pixels;  i++)
+        colour8[i] = colour16[i] >> 8;
+    return pixels;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int image_colour16_to_gray16_row(uint16_t gray16[], uint16_t colour16[], int pixels)
 {
     int i;
     uint32_t gray;
 
     for (i = 0;  i < pixels;  i++)
     {
-        gray = colour[3*i]*19595 + colour[3*i + 1]*38469 + colour[3*i + 2]*7472;
-        mono[i] = saturateu8(gray >> 24);
+        gray = colour16[3*i]*19595 + colour16[3*i + 1]*38469 + colour16[3*i + 2]*7472;
+        gray16[i] = saturateu16(gray >> 16);
     }
     return pixels;
 }
 /*- End of function --------------------------------------------------------*/
 
-static int image_colour8_to_gray8_row(uint8_t mono[], uint8_t colour[], int pixels)
+static int image_colour16_to_gray8_row(uint8_t gray8[], uint16_t colour16[], int pixels)
 {
     int i;
     uint32_t gray;
 
     for (i = 0;  i < pixels;  i++)
     {
-        gray = colour[3*i]*19595 + colour[3*i + 1]*38469 + colour[3*i + 2]*7472;
-        mono[i] = saturateu8(gray >> 16);
+        gray = colour16[3*i]*19595 + colour16[3*i + 1]*38469 + colour16[3*i + 2]*7472;
+        gray8[i] = saturateu8(gray >> 24);
     }
     return pixels;
 }
 /*- End of function --------------------------------------------------------*/
 
-static int image_gray16_to_gray8_row(uint8_t mono[], uint16_t gray[], int pixels)
+static int image_colour8_to_gray16_row(uint16_t gray16[], uint8_t colour8[], int pixels)
 {
     int i;
+    uint32_t gray;
 
     for (i = 0;  i < pixels;  i++)
-        mono[i] = gray[i] >> 8;
+    {
+        gray = colour8[3*i]*19595 + colour8[3*i + 1]*38469 + colour8[3*i + 2]*7472;
+        gray16[i] = saturateu16(gray >> 8);
+    }
     return pixels;
 }
 /*- End of function --------------------------------------------------------*/
 
-static int get_and_scrunch_row(image_translate_state_t *s, uint8_t buf[], size_t len)
+static int image_colour8_to_gray8_row(uint8_t gray8[], uint8_t colour8[], int pixels)
 {
-    int row_len;
+    int i;
+    uint32_t gray;
+
+    for (i = 0;  i < pixels;  i++)
+    {
+        gray = colour8[3*i]*19595 + colour8[3*i + 1]*38469 + colour8[3*i + 2]*7472;
+        gray8[i] = saturateu8(gray >> 16);
+    }
+    return pixels;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int image_colour8_to_colour16_row(uint16_t colour16[], uint8_t colour8[], int pixels)
+{
+    int i;
+
+    for (i = 3*pixels - 1;  i >= 0;  i--)
+        colour16[i] = colour8[i] << 8;
+    return pixels;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int image_gray16_to_colour16_row(uint16_t colour16[], uint16_t gray16[], int pixels)
+{
+    int i;
+
+    for (i = pixels - 1;  i >= 0;  i--)
+    {
+        /* TODO: need to balance the colours */
+        colour16[3*i] = gray16[i];
+        colour16[3*i + 1] = gray16[i];
+        colour16[3*i + 2] = gray16[i];
+    }
+    return pixels;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int image_gray16_to_colour8_row(uint8_t colour8[], uint16_t gray16[], int pixels)
+{
+    int i;
+
+    for (i = pixels - 1;  i >= 0;  i--)
+    {
+        /* TODO: need to balance the colours */
+        colour8[3*i] = gray16[i] >> 8;
+        colour8[3*i + 1] = gray16[i] >> 8;
+        colour8[3*i + 2] = gray16[i] >> 8;
+    }
+    return pixels;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int image_gray16_to_gray8_row(uint8_t gray8[], uint16_t gray16[], int pixels)
+{
+    int i;
+
+    for (i = 0;  i < pixels;  i++)
+        gray8[i] = gray16[i] >> 8;
+    return pixels;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int image_gray8_to_colour16_row(uint16_t colour16[], uint8_t gray8[], int pixels)
+{
+    int i;
+
+    for (i = pixels - 1;  i >= 0;  i--)
+    {
+        /* TODO: need to balance the colours */
+        colour16[3*i] = gray8[i] << 8;
+        colour16[3*i + 1] = gray8[i] << 8;
+        colour16[3*i + 2] = gray8[i] << 8;
+    }
+    return pixels;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int image_gray8_to_colour8_row(uint8_t colour8[], uint8_t gray8[], int pixels)
+{
+    int i;
+
+    for (i = pixels - 1;  i >= 0;  i--)
+    {
+        /* TODO: need to balance the colours */
+        colour8[3*i] = gray8[i];
+        colour8[3*i + 1] = gray8[i];
+        colour8[3*i + 2] = gray8[i];
+    }
+    return pixels;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int image_gray8_to_gray16_row(uint16_t gray16[], uint8_t gray8[], int pixels)
+{
+    int i;
+
+    for (i = pixels - 1;  i >= 0;  i--)
+        gray16[i] = gray8[i] << 8;
+    return pixels;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int get_and_scrunch_row(image_translate_state_t *s, uint8_t buf[])
+{
+    int input_row_len;
 
-    row_len = (*s->row_read_handler)(s->row_read_user_data, buf, s->input_width*s->bytes_per_pixel);
-    if (row_len != s->input_width*s->bytes_per_pixel)
+    input_row_len = (*s->row_read_handler)(s->row_read_user_data, buf, s->input_width*s->input_bytes_per_pixel);
+    if (input_row_len != s->input_width*s->input_bytes_per_pixel)
         return 0;
-    /* Scrunch colour down to gray, and scrunch 16 bit pixels down to 8 bit pixels */
+    /* Scrunch colour down to gray, vice versa. Scrunch 16 bit pixels down to 8 bit pixels, or vice versa. */
     switch (s->input_format)
     {
     case T4_IMAGE_TYPE_GRAY_12BIT:
-        image_gray16_to_gray8_row(buf, (uint16_t *) buf, s->input_width);
+        switch (s->output_format)
+        {
+        case T4_IMAGE_TYPE_BILEVEL:
+        case T4_IMAGE_TYPE_GRAY_8BIT:
+            image_gray16_to_gray8_row(buf, (uint16_t *) buf, s->input_width);
+            break;
+        case T4_IMAGE_TYPE_COLOUR_12BIT:
+            image_gray16_to_colour16_row((uint16_t *) buf, (uint16_t *) buf, s->input_width);
+            break;
+        case T4_IMAGE_TYPE_COLOUR_8BIT:
+            image_gray16_to_colour8_row(buf, (uint16_t *) buf, s->input_width);
+            break;
+        }
+        break;
+    case T4_IMAGE_TYPE_GRAY_8BIT:
+        switch (s->output_format)
+        {
+        case T4_IMAGE_TYPE_GRAY_12BIT:
+            image_gray8_to_gray16_row((uint16_t *) buf, buf, s->input_width);
+            break;
+        case T4_IMAGE_TYPE_COLOUR_12BIT:
+            image_gray8_to_colour16_row((uint16_t *) buf, buf, s->input_width);
+            break;
+        case T4_IMAGE_TYPE_COLOUR_8BIT:
+            image_gray8_to_colour8_row(buf, buf, s->input_width);
+            break;
+        }
         break;
     case T4_IMAGE_TYPE_COLOUR_12BIT:
-        image_colour16_to_gray8_row(buf, (uint16_t *) buf, s->input_width);
+        switch (s->output_format)
+        {
+        case T4_IMAGE_TYPE_GRAY_12BIT:
+            image_colour16_to_gray16_row((uint16_t *) buf, (uint16_t *) buf, s->input_width);
+            break;
+        case T4_IMAGE_TYPE_BILEVEL:
+        case T4_IMAGE_TYPE_GRAY_8BIT:
+            image_colour16_to_gray8_row(buf, (uint16_t *) buf, s->input_width);
+            break;
+        case T4_IMAGE_TYPE_COLOUR_8BIT:
+            image_colour16_to_colour8_row(buf, (uint16_t *) buf, s->input_width);
+            break;
+        }
         break;
     case T4_IMAGE_TYPE_COLOUR_8BIT:
-        image_colour8_to_gray8_row(buf, buf, s->input_width);
+        switch (s->output_format)
+        {
+        case T4_IMAGE_TYPE_GRAY_12BIT:
+            image_colour8_to_gray16_row((uint16_t *) buf, buf, s->input_width);
+            break;
+        case T4_IMAGE_TYPE_BILEVEL:
+        case T4_IMAGE_TYPE_GRAY_8BIT:
+            image_colour8_to_gray8_row(buf, buf, s->input_width);
+            break;
+        case T4_IMAGE_TYPE_COLOUR_12BIT:
+            image_colour8_to_colour16_row((uint16_t *) buf, buf, s->input_width);
+            break;
+        }
         break;
     }
-    return row_len;
+    return s->output_width;
 }
 /*- End of function --------------------------------------------------------*/
 
-static int image_resize_row(image_translate_state_t *s, uint8_t buf[], size_t len)
+static int image_resize_row(image_translate_state_t *s, uint8_t buf[])
 {
     int i;
     int output_width;
@@ -184,8 +353,8 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[], size_t le
                 s->raw_output_row = -1;
                 break;
             }
-            row_len = get_and_scrunch_row(s, s->raw_pixel_row[0], s->input_width*s->bytes_per_pixel);
-            if (row_len != s->input_width*s->bytes_per_pixel)
+            row_len = get_and_scrunch_row(s, s->raw_pixel_row[0]);
+            if (row_len != s->output_width)
             {
                 s->raw_output_row = -1;
                 return 0;
@@ -221,7 +390,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[], size_t le
 #endif
     if (++s->raw_output_row >= s->output_length)
         s->raw_output_row = -1;
-    return len;
+    return s->output_width;
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -335,6 +504,7 @@ SPAN_DECLARE(int) image_translate_row(image_translate_state_t *s, uint8_t buf[],
            - At the last row we dither and output, without getting an extra row in. */
     for (i = (y == 0)  ?  0  :  1;  i < 2;  i++)
     {
+        /* Swap the row buffers */
         p = s->pixel_row[0];
         s->pixel_row[0] = s->pixel_row[1];
         s->pixel_row[1] = p;
@@ -344,17 +514,24 @@ SPAN_DECLARE(int) image_translate_row(image_translate_state_t *s, uint8_t buf[],
            will fail, with the end of image condition (i.e. returning zero length) */
         if (s->resize)
         {
-            if (image_resize_row(s, s->pixel_row[1], s->output_width*s->bytes_per_pixel) != s->output_width*s->bytes_per_pixel)
+            if (image_resize_row(s, s->pixel_row[1]) != s->output_width)
                 s->output_row = -1;
         }
         else
         {
-            if (get_and_scrunch_row(s, s->pixel_row[1], s->output_width*s->bytes_per_pixel) != s->output_width*s->bytes_per_pixel)
+            if (get_and_scrunch_row(s, s->pixel_row[1]) != s->output_width)
                 s->output_row = -1;
         }
     }
     if (s->output_format == T4_IMAGE_TYPE_BILEVEL)
+    {
         i = floyd_steinberg_dither_row(s, buf, y);
+    }
+    else
+    {
+        i = s->output_width*s->output_bytes_per_pixel;
+        memcpy(buf, s->pixel_row[1], i);
+    }
     return i;
 }
 /*- End of function --------------------------------------------------------*/
@@ -413,19 +590,38 @@ SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_sta
     switch (s->input_format)
     {
     case T4_IMAGE_TYPE_GRAY_8BIT:
-        s->bytes_per_pixel = 1;
+        s->input_bytes_per_pixel = 1;
+        break;
+    case T4_IMAGE_TYPE_GRAY_12BIT:
+        s->input_bytes_per_pixel = 2;
+        break;
+    case T4_IMAGE_TYPE_COLOUR_8BIT:
+        s->input_bytes_per_pixel = 3;
+        break;
+    case T4_IMAGE_TYPE_COLOUR_12BIT:
+        s->input_bytes_per_pixel = 6;
+        break;
+    default:
+        s->input_bytes_per_pixel = 1;
+        break;
+    }
+
+    switch (s->output_format)
+    {
+    case T4_IMAGE_TYPE_GRAY_8BIT:
+        s->output_bytes_per_pixel = 1;
         break;
     case T4_IMAGE_TYPE_GRAY_12BIT:
-        s->bytes_per_pixel = 2;
+        s->output_bytes_per_pixel = 2;
         break;
     case T4_IMAGE_TYPE_COLOUR_8BIT:
-        s->bytes_per_pixel = 3;
+        s->output_bytes_per_pixel = 3;
         break;
     case T4_IMAGE_TYPE_COLOUR_12BIT:
-        s->bytes_per_pixel = 6;
+        s->output_bytes_per_pixel = 6;
         break;
     default:
-        s->bytes_per_pixel = 1;
+        s->output_bytes_per_pixel = 1;
         break;
     }
 
@@ -434,9 +630,9 @@ SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_sta
     {
         for (i = 0;  i < 2;  i++)
         {
-            if ((s->raw_pixel_row[i] = (uint8_t *) malloc(s->input_width*s->bytes_per_pixel)) == NULL)
+            if ((s->raw_pixel_row[i] = (uint8_t *) malloc(s->input_width*s->input_bytes_per_pixel)) == NULL)
                 return NULL;
-            memset(s->raw_pixel_row[i], 0, s->input_width*s->bytes_per_pixel);
+            memset(s->raw_pixel_row[i], 0, s->input_width*s->input_bytes_per_pixel);
             if ((s->pixel_row[i] = (uint8_t *) malloc(s->output_width*sizeof(uint8_t))) == NULL)
                 return NULL;
             memset(s->pixel_row[i], 0, s->output_width*sizeof(uint8_t));
@@ -446,9 +642,9 @@ SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_sta
     {
         for (i = 0;  i < 2;  i++)
         {
-            if ((s->pixel_row[i] = (uint8_t *) malloc(s->output_width*s->bytes_per_pixel)) == NULL)
+            if ((s->pixel_row[i] = (uint8_t *) malloc(s->output_width*s->input_bytes_per_pixel)) == NULL)
                 return NULL;
-            memset(s->pixel_row[i], 0, s->output_width*s->bytes_per_pixel);
+            memset(s->pixel_row[i], 0, s->output_width*s->input_bytes_per_pixel);
         }
     }
 
index 31f13d28458c668284b159666367f4114f4f6560..7f91c2db0ad40bc828f53c9683038774d986b3a2 100644 (file)
@@ -2,8 +2,9 @@
  * SpanDSP - a series of DSP components for telephony
  *
  * image_translate.h - Image translation routines for reworking colour
- *                     and gray scale images to be bi-level images of an
- *                     appropriate size to be FAX compatible.
+ *                     and gray scale images to be colour, gray scale or
+ *                     bi-level images of an appropriate size to be FAX
+ *                     compatible.
  *
  * Written by Steve Underwood <steveu@coppice.org>
  *
index e473a0f644ca13a6c1609e779f015e02202b0292..02a13506df71f3bed549819820b6fa55f6770101 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SpanDSP - a series of DSP components for telephony
  *
- * private/image_translate.c - Image translation routines for reworking colour
+ * private/image_translate.h - Image translation routines for reworking colour
  *                             and gray scale images to be bi-level images of an
  *                             appropriate size to be FAX compatible.
  *
@@ -33,11 +33,12 @@ struct image_translate_state_s
     int input_format;
     int input_width;
     int input_length;
+    int input_bytes_per_pixel;
     int output_format;
     int output_width;
     int output_length;
+    int output_bytes_per_pixel;
     int resize;
-    int bytes_per_pixel;
     int raw_input_row;
     int raw_output_row;
     int output_row;
index b57fe3965b8a7c62d43a4014ef2bcf54100e9bdf..b1930c12a3edfa79d7711d16efff730937b62f82 100644 (file)
@@ -159,7 +159,7 @@ static int row_read(void *user_data, uint8_t buf[], size_t len)
 }
 /*- End of function --------------------------------------------------------*/
 
-static void get_flattened_image(image_translate_state_t *s, int compare)
+static void get_bilevel_image(image_translate_state_t *s, int compare)
 {
     int i;
     int len;
@@ -191,12 +191,147 @@ static void get_flattened_image(image_translate_state_t *s, int compare)
 }
 /*- End of function --------------------------------------------------------*/
 
+static void get_gray8_image(image_translate_state_t *s, int compare)
+{
+    int i;
+    int j;
+    int len;
+    uint8_t row_buf[5000];
+
+    for (i = 0;  i < s->output_length;  i++)
+    {
+        if ((len = image_translate_row(s, row_buf, s->output_width)) != s->output_width)
+        {
+            printf("Image finished early - %d %d\n", len, s->output_width);
+            exit(2);
+        }
+        if (compare)
+        {
+            for (j = 0;  j < 50;  j++)
+            {
+                if (row_buf[j] != j*1200/256)
+                {
+                    printf("Image mismatch - %d - %d\n", j, row_buf[3*j]);
+                    exit(2);
+                }
+            }
+        }
+    }
+    if ((len = image_translate_row(s, row_buf, s->output_width)) != 0)
+    {
+        printf("Image finished late - %d %d\n", len, s->output_width);
+        exit(2);
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static void get_gray16_image(image_translate_state_t *s, int compare)
+{
+    int i;
+    int j;
+    int len;
+    uint16_t row_buf[5000];
+
+    for (i = 0;  i < s->output_length;  i++)
+    {
+        if ((len = image_translate_row(s, (uint8_t *) row_buf, 2*s->output_width)) != 2*s->output_width)
+        {
+            printf("Image finished early - %d %d\n", len, 2*s->output_width);
+            exit(2);
+        }
+        if (compare)
+        {
+            for (j = 0;  j < 50;  j++)
+            {
+                if (row_buf[j] != j*1200)
+                {
+                    printf("Image mismatch - %d - %d\n", j, row_buf[j]);
+                    exit(2);
+                }
+            }
+        }
+    }
+    if ((len = image_translate_row(s, (uint8_t *) row_buf, 2*s->output_width)) != 0)
+    {
+        printf("Image finished late - %d %d\n", len, 2*s->output_width);
+        exit(2);
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static void get_colour8_image(image_translate_state_t *s, int compare)
+{
+    int i;
+    int j;
+    int len;
+    uint8_t row_buf[5000];
+
+    for (i = 0;  i < s->output_length;  i++)
+    {
+        if ((len = image_translate_row(s, row_buf, 3*s->output_width)) != 3*s->output_width)
+        {
+            printf("Image finished early - %d %d\n", len, 3*s->output_width);
+            exit(2);
+        }
+        if (compare)
+        {
+            for (j = 0;  j < 50;  j++)
+            {
+                if (row_buf[3*j + 0] != j*1200/256  ||  row_buf[3*j + 1] != j*1200/256  ||  row_buf[3*j + 2] != j*1200/256)
+                {
+                    printf("Image mismatch - %d - %d %d %d\n", j, row_buf[3*j + 0], row_buf[3*j + 1], row_buf[3*j + 2]);
+                    exit(2);
+                }
+            }
+        }
+    }
+    if ((len = image_translate_row(s, row_buf, 2*s->output_width)) != 0)
+    {
+        printf("Image finished late - %d %d\n", len, 3*s->output_width);
+        exit(2);
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static void get_colour16_image(image_translate_state_t *s, int compare)
+{
+    int i;
+    int j;
+    int len;
+    uint16_t row_buf[5000];
+
+    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)
+        {
+            printf("Image finished early - %d %d\n", len, 6*s->output_width);
+            exit(2);
+        }
+        if (compare)
+        {
+            for (j = 0;  j < 50;  j++)
+            {
+                if (row_buf[3*j + 0] != j*1200  ||  row_buf[3*j + 1] != j*1200  ||  row_buf[3*j + 2] != j*1200)
+                {
+                    printf("Image mismatch - %d - %d %d %d\n", j, row_buf[3*j + 0], row_buf[3*j + 1], row_buf[3*j + 2]);
+                    exit(2);
+                }
+            }
+        }
+    }
+    if ((len = image_translate_row(s, (uint8_t *) row_buf, 6*s->output_width)) != 0)
+    {
+        printf("Image finished late - %d %d\n", len, 6*s->output_width);
+        exit(2);
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
 static void dither_tests_gray16(void)
 {
     int i;
     int j;
-    image_translate_state_t bw;
-    image_translate_state_t *s = &bw;
+    image_translate_state_t *s;
     uint16_t image[50*50];
     image_descriptor_t im;
 
@@ -213,8 +348,9 @@ static void dither_tests_gray16(void)
             image[i*im.width + j] = j*1200;
     }
 
-    s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im);
-    get_flattened_image(s, TRUE);
+    s = image_translate_init(NULL, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im);
+    get_bilevel_image(s, TRUE);
+    image_translate_free(s);
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -222,8 +358,7 @@ static void dither_tests_gray8(void)
 {
     int i;
     int j;
-    image_translate_state_t bw;
-    image_translate_state_t *s = &bw;
+    image_translate_state_t *s;
     uint8_t image[50*50];
     image_descriptor_t im;
 
@@ -239,8 +374,10 @@ static void dither_tests_gray8(void)
         for (j = 0;  j < im.width;  j++)
             image[i*im.width + j] = j*1200/256;
     }
-    s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_8BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im);
-    get_flattened_image(s, TRUE);
+
+    s = image_translate_init(NULL, T4_IMAGE_TYPE_GRAY_8BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im);
+    get_bilevel_image(s, TRUE);
+    image_translate_free(s);
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -248,8 +385,7 @@ static void dither_tests_colour16(void)
 {
     int i;
     int j;
-    image_translate_state_t bw;
-    image_translate_state_t *s = &bw;
+    image_translate_state_t *s;
     uint16_t image[50*50*3];
     image_descriptor_t im;
 
@@ -264,13 +400,96 @@ static void dither_tests_colour16(void)
     {
         for (j = 0;  j < im.width;  j++)
         {
-            image[i*3*im.width + 3*j + 0] = j*1200;
-            image[i*3*im.width + 3*j + 1] = j*1200;
-            image[i*3*im.width + 3*j + 2] = j*1200;
+            image[i*3*im.width + 3*j + 0] = j*1200 + i;
+            image[i*3*im.width + 3*j + 1] = j*1200 + i;
+            image[i*3*im.width + 3*j + 2] = j*1200 + i;
+        }
+    }
+
+    s = image_translate_init(NULL, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, 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");
+    im.image = (const uint8_t *) image;
+    im.width = 50;
+    im.length = 50;
+    im.bytes_per_pixel = 6;
+    im.current_row = 0;
+
+    for (i = 0;  i < im.length;  i++)
+    {
+        for (j = 0;  j < im.width;  j++)
+        {
+            image[i*3*im.width + 3*j + 0] = j*1200 + i;
+            image[i*3*im.width + 3*j + 1] = j*1200 + i;
+            image[i*3*im.width + 3*j + 2] = j*1200 + i;
         }
     }
-    s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im);
-    get_flattened_image(s, TRUE);
+
+    s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, T4_IMAGE_TYPE_GRAY_8BIT, -1, -1, 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");
+    im.image = (const uint8_t *) image;
+    im.width = 50;
+    im.length = 50;
+    im.bytes_per_pixel = 6;
+    im.current_row = 0;
+
+    for (i = 0;  i < im.length;  i++)
+    {
+        for (j = 0;  j < im.width;  j++)
+        {
+            image[i*3*im.width + 3*j + 0] = j*1200 + i;
+            image[i*3*im.width + 3*j + 1] = j*1200 + i;
+            image[i*3*im.width + 3*j + 2] = j*1200 + i;
+        }
+    }
+
+    s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, T4_IMAGE_TYPE_GRAY_12BIT, -1, -1, row_read, &im);
+    get_gray16_image(s, TRUE);
+
+    printf("Scrunching from a 3x16 bit per sample colour to 3x8 bit per sample colour\n");
+    im.image = (const uint8_t *) image;
+    im.width = 50;
+    im.length = 50;
+    im.bytes_per_pixel = 6;
+    im.current_row = 0;
+
+    for (i = 0;  i < im.length;  i++)
+    {
+        for (j = 0;  j < im.width;  j++)
+        {
+            image[i*3*im.width + 3*j + 0] = j*1200 + i;
+            image[i*3*im.width + 3*j + 1] = j*1200 + i;
+            image[i*3*im.width + 3*j + 2] = j*1200 + i;
+        }
+    }
+
+    s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, T4_IMAGE_TYPE_COLOUR_8BIT, -1, -1, row_read, &im);
+    get_colour8_image(s, TRUE);
+
+    printf("Scrunching from a 3x16 bit per sample colour to 3x16 bit per sample colour\n");
+    im.image = (const uint8_t *) image;
+    im.width = 50;
+    im.length = 50;
+    im.bytes_per_pixel = 6;
+    im.current_row = 0;
+
+    for (i = 0;  i < im.length;  i++)
+    {
+        for (j = 0;  j < im.width;  j++)
+        {
+            image[i*3*im.width + 3*j + 0] = j*1200 + i;
+            image[i*3*im.width + 3*j + 1] = j*1200 + i;
+            image[i*3*im.width + 3*j + 2] = j*1200 + i;
+        }
+    }
+
+    s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, T4_IMAGE_TYPE_COLOUR_12BIT, -1, -1, row_read, &im);
+    get_colour16_image(s, TRUE);
+
+    image_translate_free(s);
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -278,8 +497,7 @@ static void dither_tests_colour8(void)
 {
     int i;
     int j;
-    image_translate_state_t bw;
-    image_translate_state_t *s = &bw;
+    image_translate_state_t *s;
     uint8_t image[50*50*3];
     image_descriptor_t im;
 
@@ -294,14 +512,15 @@ static void dither_tests_colour8(void)
     {
         for (j = 0;  j < im.width;  j++)
         {
-            image[i*3*im.width + 3*j + 0] = j*1200/256;
-            image[i*3*im.width + 3*j + 1] = j*1200/256;
-            image[i*3*im.width + 3*j + 2] = j*1200/256;
+            image[i*3*im.width + 3*j + 0] = j*1200/256 + i;
+            image[i*3*im.width + 3*j + 1] = j*1200/256 + i;
+            image[i*3*im.width + 3*j + 2] = j*1200/256 + i;
         }
     }
 
-    s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im);
-    get_flattened_image(s, TRUE);
+    s = image_translate_init(NULL, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im);
+    get_bilevel_image(s, TRUE);
+    image_translate_free(s);
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -309,8 +528,7 @@ static void grow_tests_colour8(void)
 {
     int i;
     int j;
-    image_translate_state_t resize;
-    image_translate_state_t *s1 = &resize;
+    image_translate_state_t *s;
     uint8_t image[50*50*3];
     image_descriptor_t im;
 
@@ -325,15 +543,15 @@ static void grow_tests_colour8(void)
     {
         for (j = 0;  j < im.width;  j++)
         {
-            image[i*3*im.width + 3*j + 0] = j*1200/256;
-            image[i*3*im.width + 3*j + 1] = j*1200/256;
-            image[i*3*im.width + 3*j + 2] = j*1200/256;
+            image[i*3*im.width + 3*j + 0] = j*1200/256 + i;
+            image[i*3*im.width + 3*j + 1] = j*1200/256 + i;
+            image[i*3*im.width + 3*j + 2] = j*1200/256 + i;
         }
     }
 
-    s1 = image_translate_init(s1, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, 200, -1, row_read, &im);
-
-    get_flattened_image(s1, FALSE);
+    s = image_translate_init(NULL, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, 200, -1, row_read, &im);
+    get_bilevel_image(s, FALSE);
+    image_translate_free(s);
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -352,8 +570,7 @@ static void lenna_tests(int output_width, int output_length_scaling, const char
     int16_t samples_per_pixel;
     int i;
     int n;
-    image_translate_state_t bw;
-    image_translate_state_t *s = &bw;
+    image_translate_state_t *s;
     image_descriptor_t im;
     float x_resolution;
     float y_resolution;
@@ -375,7 +592,7 @@ static void lenna_tests(int output_width, int output_length_scaling, const char
     y_resolution = 200.0;
     TIFFGetField(in_file, TIFFTAG_YRESOLUTION, &y_resolution);
     res_unit = RESUNIT_INCH;
-    TIFFSetField(in_file, TIFFTAG_RESOLUTIONUNIT, &res_unit);
+    TIFFGetField(in_file, TIFFTAG_RESOLUTIONUNIT, &res_unit);
     bits_per_sample = 0;
     TIFFGetField(in_file, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
     samples_per_pixel = 0;
@@ -409,7 +626,7 @@ static void lenna_tests(int output_width, int output_length_scaling, const char
     im.current_row = 0;
     im.bytes_per_pixel = samples_per_pixel;
 
-    s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_8BIT, image_width, image_length, T4_IMAGE_TYPE_BILEVEL, output_width, output_length, row_read, &im);
+    s = image_translate_init(NULL, T4_IMAGE_TYPE_COLOUR_8BIT, image_width, image_length, T4_IMAGE_TYPE_BILEVEL, output_width, output_length, row_read, &im);
     output_width = image_translate_get_output_width(s);
     output_length = image_translate_get_output_length(s);
 
@@ -445,6 +662,7 @@ static void lenna_tests(int output_width, int output_length_scaling, const char
     TIFFWriteEncodedStrip(out_file, 0, image2, output_width*output_length/8);
     TIFFWriteDirectory(out_file);
     TIFFClose(out_file);
+    image_translate_free(s);
 }
 /*- End of function --------------------------------------------------------*/