Colour and grey images can down be dithered down to bi-level images for transmission as faxes.
More movement towards T.42 support
AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS)
DISTCLEANFILES = $(srcdir)/at_interpreter_dictionary.h \
+ $(srcdir)/cielab_luts.h \
$(srcdir)/math_fixed_tables.h \
$(srcdir)/v17_v32bis_rx_fixed_rrc.h \
$(srcdir)/v17_v32bis_rx_floating_rrc.h \
libtiff.2008.vcproj \
filter_tools.c \
make_at_dictionary.c \
+ make_cielab_luts.c \
make_math_fixed_tables.c \
make_modem_filter.c \
msvc/config.h \
mmx_sse_decs.h \
t30_local.h \
t4_t6_decode_states.h \
+ t42_t43_local.h \
v17_v32bis_rx_constellation_maps.h \
v17_v32bis_tx_constellation_maps.h \
v29tx_constellation_maps.h
make_at_dictionary$(EXEEXT): $(top_srcdir)/src/make_at_dictionary.c
$(CC_FOR_BUILD) -o make_at_dictionary$(EXEEXT) $(top_srcdir)/src/make_at_dictionary.c -DHAVE_CONFIG_H -I$(top_builddir)/src
+make_cielab_luts$(EXEEXT): $(top_srcdir)/src/make_cielab_luts.c
+ $(CC_FOR_BUILD) -o make_cielab_luts$(EXEEXT) $(top_srcdir)/src/make_cielab_luts.c -DHAVE_CONFIG_H -I$(top_builddir)/src -lm
+
make_math_fixed_tables$(EXEEXT): $(top_srcdir)/src/make_math_fixed_tables.c
$(CC_FOR_BUILD) -o make_math_fixed_tables$(EXEEXT) $(top_srcdir)/src/make_math_fixed_tables.c -DHAVE_CONFIG_H -I$(top_builddir)/src -lm
t4_rx.lo: spandsp/version.h
+t42.$(OBJEXT): cielab_luts.h
+
+t42.lo: cielab_luts.h
+
+cielab_luts.h: make_cielab_luts$(EXEEXT)
+ ./make_cielab_luts$(EXEEXT) >cielab_luts.h
+
V17_V32BIS_RX_INCL = v17_v32bis_rx_fixed_rrc.h \
v17_v32bis_rx_floating_rrc.h
-/*
- * SpanDSP - a series of DSP components for telephony
- *
- * cielab_luts.h
- *
- * Written by Steve Underwood <steveu@coppice.org>
- *
- * Copyright (C) 2011 Steve Underwood
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License version 2.1,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*! \file */
-
-#if defined(T42_USE_LUTS)
-static const float sRGB_to_linear[256] =
+static const float srgb_to_linear[256] =
{
0.000000,
0.000302,
0.248036,
0.251995,
0.255990,
- 0.260021,
+ 0.260022,
0.264090,
0.268196,
0.272338,
0.831396,
0.839397,
0.847443,
- 0.855533,
+ 0.855534,
0.863669,
0.871850,
0.880075,
0.982319,
0.991137
};
-
-static const uint8_t linear_to_sRGB[4096] =
+static const uint8_t linear_to_srgb[4096] =
{
0,
0,
255,
255
};
-#endif
-/*- End of file ------------------------------------------------------------*/
#include "spandsp/timezone.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
+#include "spandsp/image_translate.h"
#include "spandsp/t81_t82_arith_coding.h"
#include "spandsp/t85.h"
#if defined(SPANDSP_SUPPORT_T42)
#endif
#include "spandsp/private/t4_t6_decode.h"
#include "spandsp/private/t4_t6_encode.h"
+#include "spandsp/private/image_translate.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
#include "spandsp/private/t30.h"
#endif
#include "spandsp/private/t4_t6_decode.h"
#include "spandsp/private/t4_t6_encode.h"
+#include "spandsp/private/image_translate.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
-#include "spandsp/private/image_translate.h"
static int image_colour16_to_gray8_row(uint8_t mono[], uint16_t colour[], int pixels)
{
int input_width;
int input_length;
int x;
- double c1;
- double c2;
#if defined(SPANDSP_USE_FIXED_POINT)
+ int c1;
+ int c2;
int frac_row;
int frac_col;
#else
+ double c1;
+ double c2;
double int_part;
double frac_row;
double frac_col;
}
#if defined(SPANDSP_USE_FIXED_POINT)
- frac_row = s->raw_output_row*input_length/output_length;
- frac_row = s->raw_output_row*input_length - frac_row*output_length;
+ frac_row = ((s->raw_output_row*256*input_length)/output_length) & 0xFF;
for (i = 0; i < output_width; i++)
{
- x = i*input_width/output_width;
- frac_col = x - x*output_width;
- c1 = s->raw_pixel_row[0][x] + (s->raw_pixel_row[0][x + 1] - s->raw_pixel_row[0][x])*frac_col;
- c2 = s->raw_pixel_row[1][x] + (s->raw_pixel_row[1][x + 1] - s->raw_pixel_row[1][x])*frac_col;
- buf[i] = saturateu8(c1 + (c2 - c1)*frac_row);
+ x = i*256*input_width/output_width;
+ frac_col = x & 0xFF;
+ x >>= 8;
+ c1 = s->raw_pixel_row[0][x] + (((s->raw_pixel_row[0][x + 1] - s->raw_pixel_row[0][x])*frac_col) >> 8);
+ c2 = s->raw_pixel_row[1][x] + (((s->raw_pixel_row[1][x + 1] - s->raw_pixel_row[1][x])*frac_col) >> 8);
+ buf[i] = saturateu8(c1 + (((c2 - c1)*frac_row) >> 8));
}
#else
frac_row = modf((double) s->raw_output_row*input_length/output_length, &int_part);
int input_width,
int input_length,
int output_width,
+ int output_length,
t4_row_read_handler_t row_read_handler,
void *row_read_user_data)
{
s->input_width = input_width;
s->input_length = input_length;
- s->resize = (output_width > 0);
- s->output_width = (s->resize) ? output_width : s->input_width;
- s->output_length = (s->resize) ? s->input_length*s->output_width/s->input_width : s->input_length;
+ if ((s->resize = (output_width > 0)))
+ {
+ s->output_width = output_width;
+ if (output_length > 0)
+ s->output_length = output_length;
+ else
+ s->output_length = (s->input_length*s->output_width)/s->input_width;
+ }
+ else
+ {
+ s->output_width = s->input_width;
+ s->output_length = s->input_length;
+ }
switch (s->input_format)
{
--- /dev/null
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * make_cielab_luts.c - Create the look up tables for CIELab colour management
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2011 Steve Underwood
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*! \file */
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <memory.h>
+#if defined(HAVE_TGMATH_H)
+#include <tgmath.h>
+#endif
+#if defined(HAVE_MATH_H)
+#include <math.h>
+#endif
+
+typedef struct
+{
+ float L;
+ float a;
+ float b;
+} cielab_t;
+
+int main(int argc, char *argv[])
+{
+ float r;
+ uint8_t srgb;
+ int i;
+
+ printf("static const float srgb_to_linear[256] =\n");
+ printf("{\n");
+ for (i = 0; i < 256; i++)
+ {
+ /* Start with "i" as the sRGB value */
+ r = i/256.0f;
+
+ /* sRGB to Linear RGB */
+ r = (r > 0.04045f) ? powf((r + 0.055f)/1.055f, 2.4f) : r/12.92f;
+
+ printf((i < 255) ? " %f,\n" : " %f\n", r);
+ }
+ printf("};\n");
+
+ printf("static const uint8_t linear_to_srgb[4096] =\n");
+ printf("{\n");
+ for (i = 0; i < 4096; i++)
+ {
+ /* Start with "i" as the linear RGB value */
+ /* Linear RGB to sRGB */
+ r = i/4096.0f;
+
+ r = (r > 0.0031308f) ? (1.055f*powf(r, 1.0f/2.4f) - 0.055f) : r*12.92f;
+
+ r = floorf(r*256.0f);
+
+ srgb = (r < 0) ? 0 : (r <= 255) ? r : 255;
+
+ printf((i < 4095) ? " %d,\n" : " %d\n", srgb);
+ }
+ printf("};\n");
+ return 0;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
\param input_format x
\param input_width The width of the source image, in pixels.
\param input_length The length of the source image, in pixels.
- \param output_width The width of the output image, in pixels. The length of the output image
- will be derived automatically from this and the source image dimension, to main the
- geometry of the original image.
+ \param output_width The width of the output image, in pixels. If this is set <= 0 the image
+ will not be resized.
+ \param output_length The length of the output image, in pixels. If this is set to <= 0 the
+ output length will be derived automatically from the width, to maintain the geometry
+ of the original image.
\param row_read_handler A callback routine used to pull rows of pixels from the source image
into the translation process.
\param row_read_user_data An opaque point passed to read_row_handler
int input_width,
int input_length,
int output_width,
+ int output_length,
t4_row_read_handler_t row_read_handler,
void *row_read_user_data);
lab_params_t lab_params;
+ /*! \brief The size of the compressed image, in bytes. */
+ int compressed_image_size;
+
/*! \brief Error and flow logging control */
logging_state_t logging;
};
t4_row_write_handler_t comment_handler;
/*! An opaque pointer passed to comment_handler() */
void *comment_user_data;
+ /*! The maximum length of comment to be passed to the comment handler */
+ uint32_t max_comment_len;
lab_params_t lab_params;
/*! Length of data pointed to by comment */
size_t comment_len;
+ /*! \brief The size of the compressed image, in bytes. */
+ int compressed_image_size;
+
+ int buf_size;
+ uint8_t *compressed_buf;
+
/*! \brief Error and flow logging control */
logging_state_t logging;
};
int image_buffer_size;
/*! \brief Row counter for playing out the rows of the image. */
int row;
+
+ /*! \brief Image length of the image in the file. This is used when the
+ image is resized or dithered flat. */
+ int image_length;
+ /*! \brief Row counter used when the image is resized or dithered flat. */
+ int raw_row;
} t4_tx_tiff_state_t;
/*!
t85_encode_state_t t85;
} encoder;
+ image_translate_state_t translator;
+
/* Supporting information, like resolutions, which the backend may want. */
t4_tx_metadata_t metadata;
t4_row_write_handler_t comment_handler;
/*! An opaque pointer passed to comment_handler() */
void *comment_user_data;
+ /*! The maximum length of comment to be passed to the comment handler */
+ uint32_t max_comment_len;
uint8_t min_bit_planes;
uint8_t max_bit_planes;
- /*! The maximum length of comment to be passed to the comment handler */
- uint32_t max_comment_len;
/*! The maximum permitted width of the full image, in pixels */
uint32_t max_xd;
/*! The maximum permitted height of the full image, in pixels */
SPAN_DECLARE(void) set_lab_gamut2(lab_params_t *s, int L_P, int L_Q, int a_P, int a_Q, int b_P, int b_Q);
-SPAN_DECLARE(void) set_illuminant_from_code(lab_params_t *s, const uint8_t code[4]);
+SPAN_DECLARE(int) t42_itulab_to_itulab(logging_state_t *logging, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height);
-SPAN_DECLARE(void) set_gamut_from_code(lab_params_t *s, const uint8_t code[12]);
+SPAN_DECLARE(int) t42_itulab_to_jpeg(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen);
-SPAN_DECLARE(int) t42_itulab_to_itulab(tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height, char *emsg, size_t max_emsg_bytes);
+SPAN_DECLARE(int) t42_jpeg_to_itulab(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen);
-SPAN_DECLARE(int) t42_itulab_to_jpeg(lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, char *emsg, size_t max_emsg_bytes);
+SPAN_DECLARE(int) t42_srgb_to_itulab(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height);
-SPAN_DECLARE(int) t42_jpeg_to_itulab(lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, char *emsg, size_t max_emsg_bytes);
-
-SPAN_DECLARE(int) t42_srgb_to_itulab(lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height, char *emsg, size_t max_emsg_bytes);
-
-SPAN_DECLARE(int) t42_itulab_to_srgb(lab_params_t *s, tdata_t dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t *width, uint32_t *height, char *emsg, size_t max_emsg_bytes);
+SPAN_DECLARE(int) t42_itulab_to_srgb(logging_state_t *logging, lab_params_t *s, tdata_t dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t *width, uint32_t *height);
SPAN_DECLARE(void) t42_encode_set_options(t42_encode_state_t *s,
uint32_t l0,
T4_LENGTH_1200_US_LEGAL = 0
} t4_image_length_t;
+/*! Return values from the T.85 decoder */
+typedef enum
+{
+ /*! More image data is needed */
+ T4_DECODE_MORE_DATA = 0,
+ /*! Image completed successfully */
+ T4_DECODE_OK = -1,
+ /*! The decoder has interrupted */
+ T4_DECODE_INTERRUPT = -2,
+ /*! An abort was found in the image data */
+ T4_DECODE_ABORTED = -3,
+ /*! A memory allocation error occurred */
+ T4_DECODE_NOMEM = -4,
+ /*! The image data is invalid. */
+ T4_DECODE_INVALID_DATA = -5
+} t4_decoder_status_t;
+
/*!
T.4 FAX compression/decompression descriptor. This defines the working state
for a single instance of a T.4 FAX compression or decompression channel.
T85_LRLTWO = 0x40
};
-/*! Return values from the T.85 decoder */
-enum
-{
- /*! More image data is needed */
- T85_MORE_DATA = 0,
- /*! Image completed successfully */
- T85_OK = -1,
- /*! The decoder has interrupted */
- T85_INTERRUPT = -2,
- /*! An abort was found in the image data */
- T85_ABORTED = -3,
- /*! A memory allocation error occurred */
- T85_NOMEM = -4,
- /*! The image data is invalid. This includes finding values
- in the BIH which lie outside the T.85 domain */
- T85_INVALID_DATA = -5
-};
-
/*! State of a working instance of the T.85 encoder */
typedef struct t85_encode_state_s t85_encode_state_t;
#include "spandsp/timezone.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
+#include "spandsp/image_translate.h"
#include "spandsp/t81_t82_arith_coding.h"
#include "spandsp/t85.h"
#if defined(SPANDSP_SUPPORT_T42)
#endif
#include "spandsp/private/t4_t6_decode.h"
#include "spandsp/private/t4_t6_encode.h"
+#include "spandsp/private/image_translate.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
#include "spandsp/private/t30.h"
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SYCC_T81_CAPABLE);
if ((s->supported_compressions & T30_SUPPORT_T85_COMPRESSION))
{
- set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE);
+ /* Bit 79 set with bit 78 clear is invalid, so only check for L0
+ support here. */
if ((s->supported_compressions & T30_SUPPORT_T85_L0_COMPRESSION))
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE);
+ set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE);
}
//if ((s->supported_compressions & T30_SUPPORT_T89_COMPRESSION))
// set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T89_CAPABLE);
if (s->use_own_tz)
t4_tx_set_header_tz(&s->t4.tx, &s->tz);
- s->x_resolution = t4_tx_get_x_resolution(&s->t4.tx);
- s->y_resolution = t4_tx_get_y_resolution(&s->t4.tx);
/* The minimum scan time to be used can't be evaluated until we know the Y resolution, and
must be evaluated before the minimum scan row bits can be evaluated. */
if ((min_row_bits = set_min_scan_time_code(s)) < 0)
if (tx_start_page(s))
return -1;
+ s->x_resolution = t4_tx_get_x_resolution(&s->t4.tx);
+ s->y_resolution = t4_tx_get_y_resolution(&s->t4.tx);
s->image_width = t4_tx_get_image_width(&s->t4.tx);
if (s->error_correcting_mode)
{
/* 256 octets per ECM frame */
s->octets_per_ecm_frame = 256;
/* Select the compression to use. */
- if (s->error_correcting_mode
- &&
- (s->supported_compressions & T30_SUPPORT_T85_COMPRESSION)
- &&
- test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE))
+ if (!s->error_correcting_mode)
{
- if (s->supported_compressions & T30_SUPPORT_T85_L0_COMPRESSION
+ /* Without error correction our choices are very limited */
+ if ((s->supported_compressions & T30_SUPPORT_T4_2D_COMPRESSION)
&&
- test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE))
+ test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE))
{
- s->line_encoding = T4_COMPRESSION_ITU_T85_L0;
+ s->line_encoding = T4_COMPRESSION_ITU_T4_2D;
}
else
{
- s->line_encoding = T4_COMPRESSION_ITU_T85;
+ s->line_encoding = T4_COMPRESSION_ITU_T4_1D;
}
}
- else if (s->error_correcting_mode
- &&
- (s->supported_compressions & T30_SUPPORT_T6_COMPRESSION)
- &&
- test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE))
- {
- s->line_encoding = T4_COMPRESSION_ITU_T6;
- }
- else if ((s->supported_compressions & T30_SUPPORT_T4_2D_COMPRESSION)
- &&
- test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE))
- {
- s->line_encoding = T4_COMPRESSION_ITU_T4_2D;
- }
else
{
- s->line_encoding = T4_COMPRESSION_ITU_T4_1D;
+#if defined(SPANDSP_SUPPORT_T42x) || defined(SPANDSP_SUPPORT_T43)
+ /* With error correction colour may be possible/required */
+ if (0)
+ {
+ s->line_encoding = T4_COMPRESSION_ITU_T85_L0;
+ }
+ else
+#endif
+ {
+ if ((s->supported_compressions & T30_SUPPORT_T85_L0_COMPRESSION)
+ &&
+ test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE))
+ {
+ s->line_encoding = T4_COMPRESSION_ITU_T85_L0;
+ }
+ else if ((s->supported_compressions & T30_SUPPORT_T85_COMPRESSION)
+ &&
+ test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE))
+ {
+ s->line_encoding = T4_COMPRESSION_ITU_T85;
+ }
+ else if ((s->supported_compressions & T30_SUPPORT_T6_COMPRESSION)
+ &&
+ test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE))
+ {
+ s->line_encoding = T4_COMPRESSION_ITU_T6;
+ }
+ else if ((s->supported_compressions & T30_SUPPORT_T4_2D_COMPRESSION)
+ &&
+ test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE))
+ {
+ s->line_encoding = T4_COMPRESSION_ITU_T4_2D;
+ }
+ else
+ {
+ s->line_encoding = T4_COMPRESSION_ITU_T4_1D;
+ }
+ }
}
span_log(&s->logging, SPAN_LOG_FLOW, "Selected compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding);
switch (s->far_dis_dtc_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3))
s->image_width = widths[i][dcs_frame[5] & (DISBIT2 | DISBIT1)];
- /* Check which compression we will use. */
+ /* Check which compression the far end has decided to use. */
+#if defined(SPANDSP_SUPPORT_T42x)
+ if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE))
+ {
+ s->line_encoding = T4_COMPRESSION_ITU_T42;
+ }
+ else
+#endif
+#if defined(SPANDSP_SUPPORT_T43)
+ if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T43_MODE))
+ {
+ s->line_encoding = T4_COMPRESSION_ITU_T43;
+ }
+ else
+#endif
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T85_L0_MODE))
{
s->line_encoding = T4_COMPRESSION_ITU_T85_L0;
#include "spandsp/timezone.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
+#include "spandsp/image_translate.h"
#include "spandsp/t81_t82_arith_coding.h"
#include "spandsp/t85.h"
#if defined(SPANDSP_SUPPORT_T42)
#endif
#include "spandsp/private/t4_t6_decode.h"
#include "spandsp/private/t4_t6_encode.h"
+#include "spandsp/private/image_translate.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
#include "spandsp/private/t30.h"
| T30_SUPPORT_T4_2D_COMPRESSION
| T30_SUPPORT_T6_COMPRESSION
#if defined(SPANDSP_SUPPORT_T42)
- | T30_SUPPORT_T42_COMPRESSION
+ //| T30_SUPPORT_T42_COMPRESSION
#endif
#if defined(SPANDSP_SUPPORT_T43)
| T30_SUPPORT_T43_COMPRESSION
#include "spandsp/timezone.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
+#include "spandsp/image_translate.h"
#include "spandsp/t81_t82_arith_coding.h"
#include "spandsp/t85.h"
#if defined(SPANDSP_SUPPORT_T42)
#endif
#include "spandsp/private/t4_t6_decode.h"
#include "spandsp/private/t4_t6_encode.h"
+#include "spandsp/private/image_translate.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
#include "spandsp/private/t30.h"
#include "spandsp/timezone.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
+#include "spandsp/image_translate.h"
#include "spandsp/t81_t82_arith_coding.h"
#include "spandsp/t85.h"
#if defined(SPANDSP_SUPPORT_T42)
#endif
#include "spandsp/private/t4_t6_decode.h"
#include "spandsp/private/t4_t6_encode.h"
+#include "spandsp/private/image_translate.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
#include "spandsp/private/t30.h"
#include "spandsp/timezone.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
+#include "spandsp/image_translate.h"
#include "spandsp/t81_t82_arith_coding.h"
#include "spandsp/t85.h"
#if defined(SPANDSP_SUPPORT_T42)
#endif
#include "spandsp/private/t4_t6_decode.h"
#include "spandsp/private/t4_t6_encode.h"
+#include "spandsp/private/image_translate.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
#include "spandsp/private/t30.h"
#define T42_USE_LUTS
+#include "t42_t43_local.h"
+#if defined(T42_USE_LUTS)
#include "cielab_luts.h"
+#endif
typedef struct
{
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE(void) set_illuminant_from_code(lab_params_t *s, const uint8_t code[4])
+void set_illuminant_from_code(logging_state_t *logging, lab_params_t *s, const uint8_t code[4])
{
int i;
int colour_temp;
if (code[0] == 'C' && code[1] == 'T')
{
colour_temp = pack_16(&code[2]);
- printf("Illuminant colour temp %dK\n", colour_temp);
+ span_log(logging, SPAN_LOG_FLOW, "Illuminant colour temp %dK\n", colour_temp);
return;
}
for (i = 0; illuminants[i].name[0]; i++)
{
if (memcmp(code, illuminants[i].tag, 4) == 0)
{
- printf("Illuminant %s\n", illuminants[i].name);
+ span_log(logging, SPAN_LOG_FLOW, "Illuminant %s\n", illuminants[i].name);
set_lab_illuminant(s, illuminants[i].xn, illuminants[i].yn, illuminants[i].zn);
break;
}
}
if (illuminants[i].name[0] == '\0')
- printf("Unrecognised illuminant 0x%x 0x%x 0x%x 0x%x\n", code[0], code[1], code[2], code[3]);
+ span_log(logging, SPAN_LOG_FLOW, "Unrecognised illuminant 0x%x 0x%x 0x%x 0x%x\n", code[0], code[1], code[2], code[3]);
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE(void) set_gamut_from_code(lab_params_t *s, const uint8_t code[12])
+void set_gamut_from_code(logging_state_t *logging, lab_params_t *s, const uint8_t code[12])
{
int i;
int val[6];
for (i = 0; i < 6; i++)
val[i] = pack_16(&code[2*i]);
- printf("Gamut L=[%d,%d], a*=[%d,%d], b*=[%d,%d]\n",
- val[0],
- val[1],
- val[2],
- val[3],
- val[4],
- val[5]);
+ span_log(logging,
+ SPAN_LOG_FLOW,
+ "Gamut L=[%d,%d], a*=[%d,%d], b*=[%d,%d]\n",
+ val[0],
+ val[1],
+ val[2],
+ val[3],
+ val[4],
+ val[5]);
set_lab_gamut2(s, val[0], val[1], val[2], val[3], val[4], val[5]);
}
/*- End of function --------------------------------------------------------*/
-static int isITUfax(lab_params_t *s, jpeg_saved_marker_ptr ptr)
+static int is_itu_fax(logging_state_t *logging, lab_params_t *s, jpeg_saved_marker_ptr ptr)
{
const uint8_t *data;
int ok;
{
if (ptr->marker == (JPEG_APP0 + 1) && ptr->data_length >= 6)
{
+ /* Markers are:
+ JPEG_RST0
+ JPEG_EOI
+ JPEG_APP0
+ JPEG_COM */
data = (const uint8_t *) ptr->data;
if (strncmp((const char *) data, "G3FAX", 5) == 0)
{
case 0:
for (i = 0; i < 2; i++)
val[i] = pack_16(&data[6 + 2*i]);
- printf("Version %d, resolution %d dpi\n", val[0], val[1]);
+ span_log(logging, SPAN_LOG_FLOW, "Version %d, resolution %d dpi\n", val[0], val[1]);
ok = TRUE;
break;
case 1:
- printf("Set gamut\n");
- set_gamut_from_code(s, &data[6]);
- ok = TRUE;
+ span_log(logging, SPAN_LOG_FLOW, "Set gamut\n");
+ if (ptr->data_length >= 6 + 12)
+ {
+ set_gamut_from_code(logging, s, &data[6]);
+ ok = TRUE;
+ }
+ else
+ {
+ span_log(logging, SPAN_LOG_FLOW, "Got bad G3FAX1 length - %d\n", ptr->data_length);
+ }
break;
case 2:
- printf("Set illuminant\n");
- set_illuminant_from_code(s, &data[6]);
- ok = TRUE;
+ span_log(logging, SPAN_LOG_FLOW, "Set illuminant\n");
+ if (ptr->data_length >= 6 + 4)
+ {
+ set_illuminant_from_code(logging, s, &data[6]);
+ ok = TRUE;
+ }
+ else
+ {
+ span_log(logging, SPAN_LOG_FLOW, "Got bad G3FAX2 length - %d\n", ptr->data_length);
+ }
break;
case 3:
/* Colour palette table */
- printf("Set colour palette\n");
- val[0] = pack_16(&data[6]);
- printf("Colour palette %d\n", val[0]);
+ span_log(logging, SPAN_LOG_FLOW, "Set colour palette\n");
+ if (ptr->data_length >= 6 + 2)
+ {
+ val[0] = pack_16(&data[6]);
+ span_log(logging, SPAN_LOG_FLOW, "Colour palette %d\n", val[0]);
+ }
+ else
+ {
+ span_log(logging, SPAN_LOG_FLOW, "Got bad G3FAX3 length - %d\n", ptr->data_length);
+ }
+ break;
+ default:
+ span_log(logging, SPAN_LOG_FLOW, "Got unexpected G3FAX%d length - %d\n", data[5], ptr->data_length);
break;
}
}
}
-
+ else
+ {
+ span_log(logging, SPAN_LOG_FLOW, "Got marker 0x%x, length %d\n", ptr->marker, ptr->data_length);
+ span_log_buf(logging, SPAN_LOG_FLOW, "Got marker", (const uint8_t *) ptr->data, ptr->data_length);
+ }
ptr = ptr->next;
}
}
/*- End of function --------------------------------------------------------*/
-static void SetITUFax(j_compress_ptr cinfo)
+static void set_itu_fax(j_compress_ptr cinfo)
{
uint8_t marker[10] =
{
for (i = 0; i < pixels; i++)
{
#if defined(T42_USE_LUTS)
- r = sRGB_to_linear[srgb[0]];
- g = sRGB_to_linear[srgb[1]];
- b = sRGB_to_linear[srgb[2]];
+ r = srgb_to_linear[srgb[0]];
+ g = srgb_to_linear[srgb[1]];
+ b = srgb_to_linear[srgb[2]];
#else
r = srgb[0]/256.0f;
g = srgb[1]/256.0f;
#if defined(T42_USE_LUTS)
val = r*4096.0f;
- srgb[0] = linear_to_sRGB[(val < 0) ? 0 : (val < 4095) ? val : 4095];
+ srgb[0] = linear_to_srgb[(val < 0) ? 0 : (val < 4095) ? val : 4095];
val = g*4096.0f;
- srgb[1] = linear_to_sRGB[(val < 0) ? 0 : (val < 4095) ? val : 4095];
+ srgb[1] = linear_to_srgb[(val < 0) ? 0 : (val < 4095) ? val : 4095];
val = b*4096.0f;
- srgb[2] = linear_to_sRGB[(val < 0) ? 0 : (val < 4095) ? val : 4095];
+ srgb[2] = linear_to_srgb[(val < 0) ? 0 : (val < 4095) ? val : 4095];
#else
/* Linear RGB to sRGB */
r = (r > 0.0031308f) ? (1.055f*powf(r, 1.0f/2.4f) - 0.055f) : r*12.92f;
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE(int) t42_itulab_to_jpeg(lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, char *emsg, size_t max_emsg_bytes)
+SPAN_DECLARE(int) t42_itulab_to_jpeg(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen)
{
struct jpeg_decompress_struct decompressor;
struct jpeg_compress_struct compressor;
- char *outptr;
- size_t outsize;
FILE *in;
FILE *out;
int m;
JSAMPROW scan_line_in;
JSAMPROW scan_line_out;
escape_route_t escape;
+#if defined(HAVE_OPEN_MEMSTREAM)
+ char *outptr;
+ size_t outsize;
+#endif
escape.error_message[0] = '\0';
- emsg[0] = '\0';
#if defined(HAVE_OPEN_MEMSTREAM)
- in = fmemopen(src, srclen, "r");
-#else
- in = tmpfile();
- fwrite(src, 1, srclen, in);
- rewind(in);
-#endif
- if (in == NULL)
+ if ((in = fmemopen(src, srclen, "r")) == NULL)
{
- if (emsg[0] == '\0')
- strcpy(emsg, "Failed to fmemopen().");
+ span_log(logging, SPAN_LOG_FLOW, "Failed to fmemopen().\n");
+ return FALSE;
+ }
+ outsize = 0;
+ if ((out = open_memstream(&outptr, &outsize)) == NULL)
+ {
+ span_log(logging, SPAN_LOG_FLOW, "Failed to open_memstream().\n");
+ fclose(in);
+ return FALSE;
+ }
+ if (fseek(out, 0, SEEK_SET) != 0)
+ {
+ fclose(in);
+ fclose(out);
return FALSE;
}
-
-#if defined(HAVE_OPEN_MEMSTREAM)
- out = open_memstream(&outptr, &outsize);
#else
- out = tmpfile();
-#endif
- if (out == NULL)
+ if ((in = tmpfile()) == NULL)
+ {
+ span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n");
+ return FALSE;
+ }
+ if (fwrite(src, 1, srclen, in) != srclen)
+ {
+ fclose(in);
+ return FALSE;
+ }
+ if (fseek(in, 0, SEEK_SET) != 0)
{
- if (emsg[0] == '\0')
- strcpy(emsg, "Failed to open_memstream().");
+ fclose(in);
return FALSE;
}
+ if ((out = tmpfile()) == NULL)
+ {
+ span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n");
+ fclose(in);
+ return FALSE;
+ }
+#endif
+ scan_line_out = NULL;
if (setjmp(escape.escape))
{
- strncpy(emsg, escape.error_message, max_emsg_bytes - 1);
- emsg[max_emsg_bytes - 1] = '\0';
- if (emsg[0] == '\0')
- strcpy(emsg, "Unspecified libjpeg error.");
+ if (escape.error_message[0])
+ span_log(logging, SPAN_LOG_FLOW, "%s\n", escape.error_message);
+ else
+ span_log(logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n");
+ if (scan_line_out)
+ free(scan_line_out);
+ fclose(in);
+ fclose(out);
return FALSE;
}
/* Take the header */
jpeg_read_header(&decompressor, TRUE);
- /* Now we can force the input colorspace. For ITULab, we will use YCbCr as a "don't touch" marker */
+ /* Now we can force the input colour space. For ITULab, we use YCbCr as a "don't touch" marker */
decompressor.out_color_space = JCS_YCbCr;
/* Sanity check and parameter check */
- if (!isITUfax(s, decompressor.marker_list))
+ if (!is_itu_fax(logging, s, decompressor.marker_list))
{
- if (emsg[0] == '\0')
- strcpy(emsg, "Is not ITUFAX.");
+ span_log(logging, SPAN_LOG_FLOW, "Is not an ITU FAX.\n");
return FALSE;
}
jpeg_create_compress(&compressor);
jpeg_stdio_dest(&compressor, out);
- /* Force the destination color space */
+ /* Force the destination colour space */
compressor.in_color_space = JCS_RGB;
compressor.input_components = 3;
jpeg_set_defaults(&compressor);
- //jpeg_set_quality(&compressor, quality, TRUE /* limit to baseline-JPEG values */);
+ /* Limit to baseline-JPEG values */
+ //jpeg_set_quality(&compressor, quality, TRUE);
/* Copy size, resolution, etc */
jpeg_copy_critical_parameters(&decompressor, &compressor);
jpeg_destroy_decompress(&decompressor);
jpeg_destroy_compress(&compressor);
fclose(in);
- fclose(out);
+#if defined(HAVE_OPEN_MEMSTREAM)
+ fclose(out);
*dst = outptr;
*dstlen = outsize;
+#else
+ *dstlen = ftell(out);
+ *dst = malloc(*dstlen);
+ if (fseek(out, 0, SEEK_SET) != 0)
+ {
+ fclose(out);
+ return FALSE;
+ }
+ if (fread(*dst, 1, *dstlen, out) != *dstlen)
+ {
+ free(*dst);
+ fclose(out);
+ return FALSE;
+ }
+ fclose(out);
+#endif
return TRUE;
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE(int) t42_jpeg_to_itulab(lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, char *emsg, size_t max_emsg_bytes)
+SPAN_DECLARE(int) t42_jpeg_to_itulab(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen)
{
struct jpeg_decompress_struct decompressor;
struct jpeg_compress_struct compressor;
- char *outptr;
- size_t outsize;
FILE *in;
FILE *out;
int m;
JSAMPROW scan_line_in;
JSAMPROW scan_line_out;
escape_route_t escape;
+#if defined(HAVE_OPEN_MEMSTREAM)
+ char *outptr;
+ size_t outsize;
+#endif
escape.error_message[0] = '\0';
- emsg[0] = '\0';
#if defined(HAVE_OPEN_MEMSTREAM)
- in = fmemopen(src, srclen, "r");
-#else
- in = tmpfile();
- fwrite(src, 1, srclen, in);
- rewind(in);
-#endif
- if (in == NULL)
+ if ((in = fmemopen(src, srclen, "r")) == NULL)
{
- if (emsg[0] == '\0')
- strcpy(emsg, "Failed to fmemopen().");
+ span_log(logging, SPAN_LOG_FLOW, "Failed to fmemopen().\n");
+ return FALSE;
+ }
+ outsize = 0;
+ if ((out = open_memstream(&outptr, &outsize)) == NULL)
+ {
+ span_log(logging, SPAN_LOG_FLOW, "Failed to open_memstream().\n");
+ fclose(in);
+ return FALSE;
+ }
+ if (fseek(out, 0, SEEK_SET) != 0)
+ {
+ fclose(in);
+ fclose(out);
return FALSE;
}
-
-#if defined(HAVE_OPEN_MEMSTREAM)
- out = open_memstream(&outptr, &outsize);
#else
- out = tmpfile();
-#endif
- if (out == NULL)
+ if ((in = tmpfile()) == NULL)
+ {
+ span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n");
+ return FALSE;
+ }
+ if (fwrite(src, 1, srclen, in) != srclen)
+ {
+ fclose(in);
+ return FALSE;
+ }
+ if (fseek(in, 0, SEEK_SET) != 0)
+ {
+ fclose(in);
+ return FALSE;
+ }
+ if ((out = tmpfile()) == NULL)
{
- if (emsg[0] == '\0')
- strcpy(emsg, "Failed to open_memstream().");
+ span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n");
+ fclose(in);
return FALSE;
}
+#endif
+ scan_line_out = NULL;
if (setjmp(escape.escape))
{
- strncpy(emsg, escape.error_message, max_emsg_bytes - 1);
- emsg[max_emsg_bytes - 1] = '\0';
+ if (escape.error_message[0])
+ span_log(logging, SPAN_LOG_FLOW, "%s\n", escape.error_message);
+ else
+ span_log(logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n");
+ if (scan_line_out)
+ free(scan_line_out);
+ fclose(in);
+ fclose(out);
return FALSE;
}
-
+ /* Create input decompressor. */
decompressor.err = jpeg_std_error(&error_handler);
decompressor.client_data = (void *) &escape;
error_handler.error_exit = jpg_error_exit;
/* Take the header */
jpeg_read_header(&decompressor, TRUE);
- /* Now we can force the input colorspace. For ITULab, we will use YCbCr as a "don't touch" marker */
+ /* Now we can force the input colour space. For ITULab, we use YCbCr as a "don't touch" marker */
decompressor.out_color_space = JCS_RGB;
compressor.err = jpeg_std_error(&error_handler);
jpeg_create_compress(&compressor);
jpeg_stdio_dest(&compressor, out);
- /* Force the destination color space */
+ /* Force the destination colour space */
compressor.in_color_space = JCS_YCbCr;
compressor.input_components = 3;
jpeg_set_defaults(&compressor);
- //jpeg_set_quality(&compressor, quality, TRUE /* limit to baseline-JPEG values */);
+ /* Limit to baseline-JPEG values */
+ //jpeg_set_quality(&compressor, quality, TRUE);
jpeg_copy_critical_parameters(&decompressor, &compressor);
jpeg_start_decompress(&decompressor);
jpeg_start_compress(&compressor, TRUE);
- SetITUFax(&compressor);
+ set_itu_fax(&compressor);
if ((scan_line_in = (JSAMPROW) malloc(decompressor.output_width*decompressor.num_components)) == NULL)
return FALSE;
jpeg_destroy_decompress(&decompressor);
jpeg_destroy_compress(&compressor);
fclose(in);
- fclose(out);
+#if defined(HAVE_OPEN_MEMSTREAM)
+ fclose(out);
*dst = outptr;
*dstlen = outsize;
+#else
+ *dstlen = ftell(out);
+ *dst = malloc(*dstlen);
+ if (fseek(out, 0, SEEK_SET) != 0)
+ {
+ fclose(out);
+ return FALSE;
+ }
+ if (fread(*dst, 1, *dstlen, out) != *dstlen)
+ {
+ free(*dst);
+ fclose(out);
+ return FALSE;
+ }
+ fclose(out);
+#endif
return TRUE;
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE(int) t42_srgb_to_itulab(lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height, char *emsg, size_t max_emsg_bytes)
+SPAN_DECLARE(int) t42_srgb_to_itulab(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height)
{
struct jpeg_compress_struct compressor;
FILE *out;
- char *outptr;
- size_t outsize;
JSAMPROW scan_line_out;
JSAMPROW scan_line_in;
tsize_t pos;
escape_route_t escape;
+#if defined(HAVE_OPEN_MEMSTREAM)
+ char *outptr;
+ size_t outsize;
+#endif
escape.error_message[0] = '\0';
- emsg[0] = '\0';
#if defined(HAVE_OPEN_MEMSTREAM)
- out = open_memstream(&outptr, &outsize);
+ outsize = 0;
+ if ((out = open_memstream(&outptr, &outsize)) == NULL)
+ {
+ span_log(logging, SPAN_LOG_FLOW, "Failed to open_memstream().\n");
+ return FALSE;
+ }
+ if (fseek(out, 0, SEEK_SET) != 0)
+ {
+ fclose(out);
+ return FALSE;
+ }
#else
- out = tmpfile();
-#endif
- if (out == NULL)
+ if ((out = tmpfile()) == NULL)
{
- if (emsg[0] == '\0')
- strcpy(emsg, "Failed to open_memstream().");
+ span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n");
return FALSE;
}
+#endif
+ scan_line_out = NULL;
if (setjmp(escape.escape))
{
- strncpy(emsg, escape.error_message, max_emsg_bytes - 1);
- emsg[max_emsg_bytes - 1] = '\0';
+ if (escape.error_message[0])
+ span_log(logging, SPAN_LOG_FLOW, "%s\n", escape.error_message);
+ else
+ span_log(logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n");
+ if (scan_line_out)
+ free(scan_line_out);
+ fclose(out);
return FALSE;
}
jpeg_create_compress(&compressor);
jpeg_stdio_dest(&compressor, out);
- /* Force the destination color space */
+ /* Force the destination colour space */
compressor.in_color_space = JCS_YCbCr;
compressor.input_components = 3;
jpeg_set_defaults(&compressor);
- //jpeg_set_quality(&compressor, quality, TRUE /* limit to baseline-JPEG values */);
+ /* Limit to baseline-JPEG values */
+ //jpeg_set_quality(&compressor, quality, TRUE);
/* Size, resolution, etc */
compressor.image_width = width;
jpeg_start_compress(&compressor, TRUE);
- SetITUFax(&compressor);
+ set_itu_fax(&compressor);
if ((scan_line_out = (JSAMPROW) malloc(compressor.image_width*compressor.num_components)) == NULL)
return FALSE;
free(scan_line_out);
jpeg_finish_compress(&compressor);
jpeg_destroy_compress(&compressor);
- fclose(out);
+#if defined(HAVE_OPEN_MEMSTREAM)
+ fclose(out);
*dst = outptr;
*dstlen = outsize;
+#else
+ *dstlen = ftell(out);
+ *dst = malloc(*dstlen);
+ if (fseek(out, 0, SEEK_SET) != 0)
+ {
+ fclose(out);
+ return FALSE;
+ }
+ if (fread(*dst, 1, *dstlen, out) != *dstlen)
+ {
+ free(*dst);
+ fclose(out);
+ return FALSE;
+ }
+ fclose(out);
+#endif
return TRUE;
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE(int) t42_itulab_to_itulab(tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height, char *emsg, size_t max_emsg_bytes)
+SPAN_DECLARE(int) t42_itulab_to_itulab(logging_state_t *logging, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height)
{
struct jpeg_compress_struct compressor;
FILE *out;
- char *outptr;
- size_t outsize;
JSAMPROW scan_line_in;
tsize_t pos;
escape_route_t escape;
+#if defined(HAVE_OPEN_MEMSTREAM)
+ char *outptr;
+ size_t outsize;
+#endif
escape.error_message[0] = '\0';
- emsg[0] = '\0';
#if defined(HAVE_OPEN_MEMSTREAM)
- out = open_memstream(&outptr, &outsize);
+ outsize = 0;
+ if ((out = open_memstream(&outptr, &outsize)) == NULL)
+ {
+ span_log(logging, SPAN_LOG_FLOW, "Failed to open_memstream().\n");
+ return FALSE;
+ }
+ if (fseek(out, 0, SEEK_SET) != 0)
+ {
+ fclose(out);
+ return FALSE;
+ }
#else
- out = tmpfile();
-#endif
- if (out == NULL)
+ if ((out = tmpfile()) == NULL)
{
- if (emsg[0] == '\0')
- strcpy(emsg, "Failed to open_memstream().");
+ span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n");
return FALSE;
}
+#endif
if (setjmp(escape.escape))
{
- strncpy(emsg, escape.error_message, max_emsg_bytes - 1);
- emsg[max_emsg_bytes - 1] = '\0';
+ if (escape.error_message[0])
+ span_log(logging, SPAN_LOG_FLOW, "%s\n", escape.error_message);
+ else
+ span_log(logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n");
+ fclose(out);
return FALSE;
}
jpeg_create_compress(&compressor);
jpeg_stdio_dest(&compressor, out);
- /* Force the destination color space */
+ /* Force the destination colour space */
compressor.in_color_space = JCS_YCbCr;
compressor.input_components = 3;
jpeg_set_defaults(&compressor);
- //jpeg_set_quality(&compressor, quality, TRUE /* limit to baseline-JPEG values */);
+ /* Limit to baseline-JPEG values */
+ //jpeg_set_quality(&compressor, quality, TRUE);
/* Size, resolution, etc */
compressor.image_width = width;
jpeg_start_compress(&compressor, TRUE);
- SetITUFax(&compressor);
+ set_itu_fax(&compressor);
for (pos = 0; pos < srclen; pos += compressor.image_width*compressor.num_components)
{
jpeg_finish_compress(&compressor);
jpeg_destroy_compress(&compressor);
- fclose(out);
+#if defined(HAVE_OPEN_MEMSTREAM)
+ fclose(out);
*dst = outptr;
*dstlen = outsize;
+#else
+ *dstlen = ftell(out);
+ *dst = malloc(*dstlen);
+ if (fseek(out, 0, SEEK_SET) != 0)
+ {
+ fclose(out);
+ return FALSE;
+ }
+ if (fread(*dst, 1, *dstlen, out) != *dstlen)
+ {
+ free(*dst);
+ fclose(out);
+ return FALSE;
+ }
+ fclose(out);
+#endif
return TRUE;
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE(int) t42_itulab_to_srgb(lab_params_t *s, tdata_t dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t *width, uint32_t *height, char *emsg, size_t max_emsg_bytes)
+SPAN_DECLARE(int) t42_itulab_to_srgb(logging_state_t *logging, lab_params_t *s, tdata_t dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t *width, uint32_t *height)
{
struct jpeg_decompress_struct decompressor;
JSAMPROW scan_line_out;
escape_route_t escape;
escape.error_message[0] = '\0';
- emsg[0] = '\0';
#if defined(HAVE_OPEN_MEMSTREAM)
- in = fmemopen(src, srclen, "r");
+ if ((in = fmemopen(src, srclen, "r")) == NULL)
+ {
+ span_log(logging, SPAN_LOG_FLOW, "Failed to fmemopen().\n");
+ return FALSE;
+ }
#else
- in = tmpfile();
- fwrite(src, 1, srclen, in);
- rewind(in);
-#endif
- if (in == NULL)
+ if ((in = tmpfile()) == NULL)
+ {
+ span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n");
+ return FALSE;
+ }
+ if (fwrite(src, 1, srclen, in) != srclen)
{
- if (emsg[0] == '\0')
- strcpy(emsg, "Failed to fmemopen().");
+ fclose(in);
return FALSE;
}
+ if (fseek(in, 0, SEEK_SET) != 0)
+ {
+ fclose(in);
+ return FALSE;
+ }
+#endif
+ scan_line_out = NULL;
if (setjmp(escape.escape))
{
- strncpy(emsg, escape.error_message, max_emsg_bytes - 1);
- emsg[max_emsg_bytes - 1] = '\0';
- if (emsg[0] == '\0')
- strcpy(emsg, "Unspecified libjpeg error.");
+ if (escape.error_message[0])
+ span_log(logging, SPAN_LOG_FLOW, "%s\n", escape.error_message);
+ else
+ span_log(logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n");
+ if (scan_line_out)
+ free(scan_line_out);
+ fclose(in);
return FALSE;
}
/* Create input decompressor. */
/* Rewind the file */
if (fseek(in, 0, SEEK_SET) != 0)
return FALSE;
-printf("XXXX 10\n");
/* Take the header */
jpeg_read_header(&decompressor, FALSE);
-printf("XXXX 11\n");
- /* Now we can force the input colorspace. For ITULab, we will use YCbCr as a "don't touch" marker */
+ /* Now we can force the input colour space. For ITULab, we use YCbCr as a "don't touch" marker */
decompressor.out_color_space = JCS_YCbCr;
-printf("XXXX 12\n");
/* Sanity check and parameter check */
- if (!isITUfax(s, decompressor.marker_list))
+ if (!is_itu_fax(logging, s, decompressor.marker_list))
{
- if (emsg[0] == '\0')
- strcpy(emsg, "Is not ITUFAX.");
- //return FALSE;
+ span_log(logging, SPAN_LOG_FLOW, "Is not an ITU FAX.\n");
+ return FALSE;
}
-printf("XXXX 13\n");
/* Copy size, resolution, etc */
*width = decompressor.image_width;
*height = decompressor.image_height;
SPAN_DECLARE(int) t42_encode_get_compressed_image_size(t42_encode_state_t *s)
{
- return 0;
+ return s->compressed_image_size;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t42_encode_restart(t42_encode_state_t *s, uint32_t image_width, uint32_t image_length)
{
+ //s->image_width = image_width;
+ //s->image_length = image_length;
+ s->compressed_image_size = 0;
return 0;
}
/*- End of function --------------------------------------------------------*/
s->row_read_handler = handler;
s->row_read_user_data = user_data;
+ t42_encode_restart(s, image_width, image_length);
return s;
}
SPAN_DECLARE(int) t42_encode_free(t42_encode_state_t *s)
{
- return 0;
+ int ret;
+
+ ret = t42_encode_release(s);
+ free(s);
+ return ret;
}
/*- End of function --------------------------------------------------------*/
const uint8_t data[],
size_t len)
{
+ uint8_t *buf;
+
+ if (s->compressed_image_size + len > s->buf_size)
+ {
+ if ((buf = (uint8_t *) realloc(s->compressed_buf, s->compressed_image_size + 1000)) == NULL)
+ return -1;
+ s->buf_size = s->compressed_image_size + 1000;
+ s->compressed_buf = buf;
+ }
+ memcpy(&s->compressed_buf[s->compressed_image_size], data, len);
+ s->compressed_image_size += len;
return 0;
}
/*- End of function --------------------------------------------------------*/
t4_row_write_handler_t handler,
void *user_data)
{
+ s->row_write_handler = handler;
+ s->row_write_user_data = user_data;
return 0;
}
/*- End of function --------------------------------------------------------*/
t4_row_write_handler_t handler,
void *user_data)
{
+ s->max_comment_len = max_comment_len;
+ s->comment_handler = handler;
+ s->comment_user_data = user_data;
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t42_decode_get_compressed_image_size(t42_decode_state_t *s)
{
- return 0;
+ return s->compressed_image_size;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t42_decode_restart(t42_decode_state_t *s)
{
+ s->compressed_image_size = 0;
return 0;
}
/*- End of function --------------------------------------------------------*/
s->row_write_handler = handler;
s->row_write_user_data = user_data;
+ s->buf_size = 0;
+ s->compressed_buf = NULL;
+
+ t42_decode_restart(s);
+
return s;
}
/*- End of function --------------------------------------------------------*/
--- /dev/null
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * t42_t43_local.h - definitions for T.42 and T.43 shared processing
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2011 Steve Underwood
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*! \file */
+
+#if !defined(_T42_T43_LOCAL_H_)
+#define _T42_T43_LOCAL_H_
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+void set_illuminant_from_code(logging_state_t *logging, lab_params_t *s, const uint8_t code[4]);
+void set_gamut_from_code(logging_state_t *logging, lab_params_t *s, const uint8_t code[12]);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
+/*- End of file ------------------------------------------------------------*/
#include "spandsp/timezone.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
+#include "spandsp/image_translate.h"
#include "spandsp/t81_t82_arith_coding.h"
#include "spandsp/t85.h"
#if defined(SPANDSP_SUPPORT_T42)
#endif
#include "spandsp/private/t4_t6_decode.h"
#include "spandsp/private/t4_t6_encode.h"
+#include "spandsp/private/image_translate.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
case T4_COMPRESSION_ITU_T85_L0:
return t85_decode_put_byte(&s->decoder.t85, byte);
}
- return TRUE;
+ return T4_DECODE_OK;
}
/*- End of function --------------------------------------------------------*/
case T4_COMPRESSION_ITU_T85_L0:
return t85_decode_put_chunk(&s->decoder.t85, buf, len);
}
- return TRUE;
+ return T4_DECODE_OK;
}
/*- End of function --------------------------------------------------------*/
#include "spandsp/timezone.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
+#include "spandsp/image_translate.h"
#include "spandsp/t81_t82_arith_coding.h"
#include "spandsp/t85.h"
#if defined(SPANDSP_SUPPORT_T42)
#endif
#include "spandsp/private/t4_t6_decode.h"
#include "spandsp/private/t4_t6_encode.h"
+#include "spandsp/private/image_translate.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
s->compressed_image_size += 8;
byte = buf[i];
if (put_bits(s, byte & 0xFF, 8))
- return TRUE;
+ return T4_DECODE_OK;
}
- return FALSE;
+ return T4_DECODE_MORE_DATA;
}
/*- End of function --------------------------------------------------------*/
if (s->ref_runs)
{
memset(s->ref_runs, 0, run_space);
- s->ref_runs[0] =
- s->ref_runs[1] =
- s->ref_runs[2] =
- s->ref_runs[3] = s->image_width;
+ s->ref_runs[0] = s->image_width;
}
if (s->row_buf)
memset(s->row_buf, 0, s->bytes_per_row);
#include "spandsp/timezone.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
+#include "spandsp/image_translate.h"
#include "spandsp/t81_t82_arith_coding.h"
#include "spandsp/t85.h"
#if defined(SPANDSP_SUPPORT_T42)
#endif
#include "spandsp/private/t4_t6_decode.h"
#include "spandsp/private/t4_t6_encode.h"
+#include "spandsp/private/image_translate.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
list[entry++] = pos;
}
}
+#if defined(T4_STATE_DEBUGGING)
+ /* Dump the runs of black and white for analysis */
+ {
+ int prev;
+ int x;
+
+ printf("Runs (%d)", list[entry - 1]);
+ prev = 0;
+ for (x = 0; x < entry; x++)
+ {
+ printf(" %" PRIu32, list[x] - prev);
+ prev = list[x];
+ }
+ printf("\n");
+ }
+#endif
return entry;
}
/*- End of function --------------------------------------------------------*/
#include "spandsp/timezone.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
+#include "spandsp/image_translate.h"
#include "spandsp/t81_t82_arith_coding.h"
#include "spandsp/t85.h"
#if defined(SPANDSP_SUPPORT_T42)
#endif
#include "spandsp/private/t4_t6_decode.h"
#include "spandsp/private/t4_t6_encode.h"
+#include "spandsp/private/image_translate.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
float y_resolution;
int i;
t4_tx_tiff_state_t *t;
+ uint16_t bits_per_sample;
+ uint16_t samples_per_pixel;
t = &s->tiff;
parm16 = 0;
TIFFGetField(t->tiff_file, TIFFTAG_BITSPERSAMPLE, &parm16);
- if (parm16 != 1)
- return -1;
+ bits_per_sample = parm16;
parm16 = 0;
TIFFGetField(t->tiff_file, TIFFTAG_SAMPLESPERPIXEL, &parm16);
- if (parm16 != 1)
+ samples_per_pixel = parm16;
+ if (samples_per_pixel == 1 && bits_per_sample == 1)
+ t->image_type = T4_IMAGE_TYPE_BILEVEL;
+ else if (samples_per_pixel == 1 && bits_per_sample == 8)
+ t->image_type = T4_IMAGE_TYPE_GRAY_8BIT;
+ else if (samples_per_pixel == 1 && bits_per_sample > 8)
+ t->image_type = T4_IMAGE_TYPE_GRAY_12BIT;
+ else if (samples_per_pixel == 3 && bits_per_sample == 8)
+ t->image_type = T4_IMAGE_TYPE_COLOUR_8BIT;
+ else if (samples_per_pixel == 3 && bits_per_sample > 8)
+ t->image_type = T4_IMAGE_TYPE_COLOUR_12BIT;
+ else
return -1;
+#if 0
+ /* Limit ourselves to plain black and white pages */
+ if (t->image_type != T4_IMAGE_TYPE_BILEVEL)
+ return -1;
+#endif
parm32 = 0;
TIFFGetField(t->tiff_file, TIFFTAG_IMAGEWIDTH, &parm32);
s->image_width = parm32;
parm32 = 0;
TIFFGetField(t->tiff_file, TIFFTAG_IMAGELENGTH, &parm32);
+ s->tiff.image_length =
s->image_length = parm32;
x_resolution = 0.0f;
TIFFGetField(t->tiff_file, TIFFTAG_XRESOLUTION, &x_resolution);
TIFFGetField(t->tiff_file, TIFFTAG_PHOTOMETRIC, &t->photo_metric);
/* TIFFGetField(t->tiff_file, TIFFTAG_COMPRESSION, &t->????); */
- if (t->photo_metric != PHOTOMETRIC_MINISWHITE)
- span_log(&s->logging, SPAN_LOG_FLOW, "%s: Photometric needs swapping.\n", s->tiff.file);
t->fill_order = FILLORDER_LSB2MSB;
/* Allow a little range for the X resolution in centimeters. The spec doesn't pin down the
static int tiff_row_read_handler(void *user_data, uint8_t buf[], size_t len)
{
t4_tx_state_t *s;
- int i;
s = (t4_tx_state_t *) user_data;
if (s->tiff.row >= s->image_length)
return 0;
-#if 0
- if (TIFFReadScanline(s->tiff.tiff_file, buf, s->tiff.row, 0) < 0)
- span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error reading TIFF row.\n", s->tiff.file);
-#else
memcpy(buf, &s->tiff.image_buffer[s->tiff.row*len], len);
-#endif
- if (s->tiff.photo_metric != PHOTOMETRIC_MINISWHITE)
- {
- for (i = 0; i < len; i++)
- buf[i] = ~buf[i];
- }
- if (s->tiff.fill_order != FILLORDER_LSB2MSB)
- bit_reverse(buf, buf, len);
s->tiff.row++;
return len;
}
/*- End of function --------------------------------------------------------*/
+static int row_read(void *user_data, uint8_t buf[], size_t len)
+{
+ t4_tx_state_t *s;
+
+ s = (t4_tx_state_t *) user_data;
+
+ if (s->tiff.raw_row >= s->tiff.image_length)
+ return 0;
+ if (TIFFReadScanline(s->tiff.tiff_file, buf, s->tiff.raw_row, 0) < 0)
+ return 0;
+ s->tiff.raw_row++;
+ return len;
+}
+/*- End of function --------------------------------------------------------*/
+
static int read_tiff_image(t4_tx_state_t *s)
{
int total_len;
int len;
- int bytes_per_row;
int i;
uint8_t *t;
+ image_translate_state_t *translator;
+ int mode;
- s->image_width = 0;
- TIFFGetField(s->tiff.tiff_file, TIFFTAG_IMAGEWIDTH, &s->image_width);
- s->image_length = 0;
- TIFFGetField(s->tiff.tiff_file, TIFFTAG_IMAGELENGTH, &s->image_length);
- bytes_per_row = TIFFScanlineSize(s->tiff.tiff_file);
- s->tiff.image_size = s->image_length*bytes_per_row;
- if (s->tiff.image_size >= s->tiff.image_buffer_size)
+ if (s->tiff.image_type != T4_IMAGE_TYPE_BILEVEL)
{
- if ((t = realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL)
+ /* We need to dither this image down to pure black and white, possibly resizing it
+ along the way. */
+ if (s->tiff.image_type == T4_IMAGE_TYPE_GRAY_8BIT)
+ mode = IMAGE_TRANSLATE_FROM_GRAY_8;
+ else if (s->tiff.image_type == T4_IMAGE_TYPE_GRAY_12BIT)
+ mode = IMAGE_TRANSLATE_FROM_GRAY_16;
+ else if (s->tiff.image_type == T4_IMAGE_TYPE_COLOUR_8BIT)
+ mode = IMAGE_TRANSLATE_FROM_COLOUR_8;
+ else if (s->tiff.image_type == T4_IMAGE_TYPE_COLOUR_12BIT)
+ mode = IMAGE_TRANSLATE_FROM_COLOUR_16;
+ else
return -1;
- s->tiff.image_buffer_size += s->tiff.image_size;
- s->tiff.image_buffer = t;
+ if ((translator = image_translate_init(NULL, mode, s->image_width, s->image_length, 1728, -1, row_read, s)) == NULL)
+ return -1;
+ s->image_width = image_translate_get_output_width(translator);
+ s->image_length = image_translate_get_output_length(translator);
+ s->metadata.x_resolution = T4_X_RESOLUTION_R8;
+ s->metadata.y_resolution = T4_Y_RESOLUTION_FINE;
+ s->tiff.image_size = (s->image_width*s->image_length + 7)/8;
+ if (s->tiff.image_size >= s->tiff.image_buffer_size)
+ {
+ if ((t = realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL)
+ return -1;
+ s->tiff.image_buffer_size = s->tiff.image_size;
+ s->tiff.image_buffer = t;
+ }
+ s->tiff.raw_row = 0;
+ total_len = 0;
+ for (i = 0; i < s->image_length; i++)
+ total_len += image_translate_row(translator, &s->tiff.image_buffer[total_len], s->image_width/8);
+ image_translate_free(translator);
}
-
-#if 1
- for (i = 0, total_len = 0; total_len < s->tiff.image_size; i++, total_len += len)
+ else
{
- if ((len = TIFFReadEncodedStrip(s->tiff.tiff_file, i, &s->tiff.image_buffer[total_len], s->tiff.image_size - total_len)) < 0)
+ s->tiff.image_size = s->image_length*TIFFScanlineSize(s->tiff.tiff_file);
+ if (s->tiff.image_size >= s->tiff.image_buffer_size)
{
- span_log(&s->logging, SPAN_LOG_WARNING, "%s: Read error.\n", s->tiff.file);
- return -1;
+ if ((t = realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL)
+ return -1;
+ s->tiff.image_buffer_size = s->tiff.image_size;
+ s->tiff.image_buffer = t;
+ }
+
+ for (i = 0, total_len = 0; total_len < s->tiff.image_size; i++, total_len += len)
+ {
+ if ((len = TIFFReadEncodedStrip(s->tiff.tiff_file, i, &s->tiff.image_buffer[total_len], s->tiff.image_size - total_len)) < 0)
+ {
+ span_log(&s->logging, SPAN_LOG_WARNING, "%s: Read error.\n", s->tiff.file);
+ return -1;
+ }
}
+ if (s->tiff.photo_metric != PHOTOMETRIC_MINISWHITE)
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "%s: Photometric needs swapping.\n", s->tiff.file);
+ for (i = 0; i < s->tiff.image_size; i++)
+ s->tiff.image_buffer[i] = ~s->tiff.image_buffer[i];
+ }
+ if (s->tiff.fill_order != FILLORDER_LSB2MSB)
+ bit_reverse(s->tiff.image_buffer, s->tiff.image_buffer, s->tiff.image_size);
}
-#endif
s->tiff.row = 0;
return s->image_length;
}
SPAN_DECLARE(int) t4_tx_start_page(t4_tx_state_t *s)
{
- uint32_t image_length;
-
span_log(&s->logging, SPAN_LOG_FLOW, "Start tx page %d - compression %s\n", s->current_page, t4_encoding_to_str(s->line_encoding));
if (s->current_page > s->stop_page)
return -1;
if (!TIFFSetDirectory(s->tiff.tiff_file, (tdir_t) s->current_page))
return -1;
get_tiff_directory_info(s);
- if ((image_length = read_tiff_image(s)) < 0)
+ if (read_tiff_image(s) < 0)
return -1;
}
else
#endif
{
span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. Fixed bytes do not contain expected values.\n");
- return T85_INVALID_DATA;
+ return T4_DECODE_INVALID_DATA;
}
/* P - Number of bit planes */
if (s->buffer[2] < s->min_bit_planes || s->buffer[2] > s->max_bit_planes)
{
span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. %d bit planes. Should be %d to %d.\n", s->buffer[2], s->min_bit_planes, s->max_bit_planes);
- return T85_INVALID_DATA;
+ return T4_DECODE_INVALID_DATA;
}
s->bit_planes = s->buffer[2];
s->current_bit_plane = 0;
if (s->xd == 0 || (s->max_xd && s->xd > s->max_xd))
{
span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. Width is %" PRIu32 "\n", s->xd);
- return T85_INVALID_DATA;
+ return T4_DECODE_INVALID_DATA;
}
/* YD - Vertical image size at layer D */
s->yd = pack_32(&s->buffer[8]);
if (s->yd == 0 || (s->max_yd && s->yd > s->max_yd))
{
span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. Length is %" PRIu32 "\n", s->yd);
- return T85_INVALID_DATA;
+ return T4_DECODE_INVALID_DATA;
}
/* L0 - Rows per stripe, at the lowest resolution */
s->l0 = pack_32(&s->buffer[12]);
if (s->l0 == 0)
{
span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. L0 is %" PRIu32 "\n", s->l0);
- return T85_INVALID_DATA;
+ return T4_DECODE_INVALID_DATA;
}
/* MX - Maximum horizontal offset allowed for AT pixel */
s->mx = s->buffer[16];
if (s->mx > 127)
{
span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. MX is %d\n", s->mx);
- return T85_INVALID_DATA;
+ return T4_DECODE_INVALID_DATA;
}
/* Options byte */
s->options = s->buffer[19];
if ((s->options & 0x97))
{
span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. Options are 0x%X\n", s->options);
- return T85_INVALID_DATA;
+ return T4_DECODE_INVALID_DATA;
}
span_log(&s->logging, SPAN_LOG_FLOW, "BIH is OK. Image is %" PRIu32 "x%" PRIu32 " pixels\n", s->xd, s->yd);
- return T85_OK;
+ return T4_DECODE_OK;
}
/*- End of function --------------------------------------------------------*/
if (byte < 0)
{
t85_decode_rx_status(s, byte);
- return (s->y >= s->yd) ? T85_OK : T85_MORE_DATA;
+ return (s->y >= s->yd) ? T4_DECODE_OK : T4_DECODE_MORE_DATA;
}
data[0] = byte;
return t85_decode_put_chunk(s, data, 1);
s->bie_len += i;
cnt = i;
if (s->bie_len < 20)
- return T85_MORE_DATA;
- if ((ret = check_bih(s)) != T85_OK)
+ return T4_DECODE_MORE_DATA;
+ if ((ret = check_bih(s)) != T4_DECODE_OK)
return ret;
/* Set up the two/three row buffer */
bytes_per_row = (s->xd + 7) >> 3;
{
/* We need to expand the 3 row buffer */
if ((buf = (uint8_t *) realloc(s->row_buf, min_len)) == NULL)
- return T85_NOMEM;
+ return T4_DECODE_NOMEM;
s->row_buf = buf;
s->row_buf_len = min_len;
}
s->buf_len = 0;
if (s->interrupt)
- return T85_INTERRUPT;
+ return T4_DECODE_INTERRUPT;
break;
case T82_ABORT:
s->buf_len = 0;
- return T85_ABORTED;
+ return T4_DECODE_ABORTED;
case T82_COMMENT:
s->buf_needed = 6;
if (s->buf_len < 6)
s->buf_len = 0;
if (s->at_moves >= T85_ATMOVES_MAX)
- return T85_INVALID_DATA;
+ return T4_DECODE_INVALID_DATA;
s->at_row[s->at_moves] = pack_32(&s->buffer[2]);
s->at_tx[s->at_moves] = s->buffer[6];
if (s->at_tx[s->at_moves] > s->mx
||
s->buffer[7] != 0)
{
- return T85_INVALID_DATA;
+ return T4_DECODE_INVALID_DATA;
}
s->at_moves++;
break;
s->buf_len = 0;
if (!(s->options & T85_VLENGTH))
- return T85_INVALID_DATA;
+ return T4_DECODE_INVALID_DATA;
s->options &= ~T85_VLENGTH;
y = pack_32(&s->buffer[2]);
/* An update to the image length is not allowed to stretch it. */
if (y > s->yd)
- return T85_INVALID_DATA;
+ return T4_DECODE_INVALID_DATA;
s->yd = y;
break;
case T82_SDNORM:
/* A plain SDNORM or SDRST with no peek ahead required */
s->buf_len = 0;
if (finish_sde(s))
- return T85_INTERRUPT;
+ return T4_DECODE_INTERRUPT;
/* Check whether this was the last SDE */
if (s->y >= s->yd)
{
s->compressed_image_size -= (len - cnt);
- return T85_OK;
+ return T4_DECODE_OK;
}
break;
}
cnt--;
/* Process the T82_SDNORM or T82_SDRST */
if (finish_sde(s))
- return T85_INTERRUPT;
+ return T4_DECODE_INTERRUPT;
/* Check whether this was the last SDE */
if (s->y >= s->yd)
{
s->compressed_image_size -= (len - cnt);
- return T85_OK;
+ return T4_DECODE_OK;
}
break;
}
/* Process the T82_SDNORM or T82_SDRST */
if (finish_sde(s))
- return T85_INTERRUPT;
+ return T4_DECODE_INTERRUPT;
/* Check whether this was the last SDE */
if (s->y >= s->yd)
{
s->compressed_image_size -= (len - cnt);
- return T85_OK;
+ return T4_DECODE_OK;
}
/* Recycle the two peek-ahead marker sequence bytes to
be processed later. */
y = pack_32(&s->buffer[4]);
/* An update to the image length is not allowed to stretch it. */
if (y > s->yd)
- return T85_INVALID_DATA;
+ return T4_DECODE_INVALID_DATA;
/* Things look OK, so accept this new length, and proceed. */
s->yd = y;
/* Now process the T82_SDNORM or T82_SDRST */
if (finish_sde(s))
- return T85_INTERRUPT;
+ return T4_DECODE_INTERRUPT;
/* We might be at the end of the image now, but even if we are
there should still be a final training T82_SDNORM or T82_SDRST
that we should pick up. When we do, we won't wait for further
break;
default:
s->buf_len = 0;
- return T85_INVALID_DATA;
+ return T4_DECODE_INVALID_DATA;
}
}
else if (cnt < len && data[cnt] == T82_ESC)
/* We have found PSCD bytes */
cnt += decode_pscd(s, data + cnt, len - cnt);
if (s->interrupt)
- return T85_INTERRUPT;
+ return T4_DECODE_INTERRUPT;
/* We should only have stopped processing PSCD if
we ran out of data, or hit a T82_ESC */
if (cnt < len && data[cnt] != T82_ESC)
- return T85_INVALID_DATA;
+ return T4_DECODE_INVALID_DATA;
}
}
- return T85_MORE_DATA;
+ return T4_DECODE_MORE_DATA;
}
/*- End of function --------------------------------------------------------*/
image[i*im.width + j] = j*1200;
}
- s = image_translate_init(s, IMAGE_TRANSLATE_FROM_GRAY_16, im.width, im.length, -1, row_read, &im);
+ s = image_translate_init(s, IMAGE_TRANSLATE_FROM_GRAY_16, im.width, im.length, -1, -1, row_read, &im);
get_flattened_image(s, TRUE);
}
/*- End of function --------------------------------------------------------*/
for (j = 0; j < im.width; j++)
image[i*im.width + j] = j*1200/256;
}
- s = image_translate_init(s, IMAGE_TRANSLATE_FROM_GRAY_8, im.width, im.length, -1, row_read, &im);
+ s = image_translate_init(s, IMAGE_TRANSLATE_FROM_GRAY_8, im.width, im.length, -1, -1, row_read, &im);
get_flattened_image(s, TRUE);
}
/*- End of function --------------------------------------------------------*/
image[i*3*im.width + 3*j + 2] = j*1200;
}
}
- s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_16, im.width, im.length, -1, row_read, &im);
+ s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_16, im.width, im.length, -1, -1, row_read, &im);
get_flattened_image(s, TRUE);
}
/*- End of function --------------------------------------------------------*/
}
}
- s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_8, im.width, im.length, -1, row_read, &im);
+ s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_8, im.width, im.length, -1, -1, row_read, &im);
get_flattened_image(s, TRUE);
}
/*- End of function --------------------------------------------------------*/
}
}
- s1 = image_translate_init(s1, IMAGE_TRANSLATE_FROM_COLOUR_8, im.width, im.length, 200, row_read, &im);
+ s1 = image_translate_init(s1, IMAGE_TRANSLATE_FROM_COLOUR_8, im.width, im.length, 200, -1, row_read, &im);
get_flattened_image(s1, FALSE);
}
/*- End of function --------------------------------------------------------*/
-static void lenna_tests(int output_width, const char *file)
+static void lenna_tests(int output_width, int output_length_scaling, const char *file)
{
TIFF *in_file;
TIFF *out_file;
image_translate_state_t bw;
image_translate_state_t *s = &bw;
image_descriptor_t im;
+ float x_resolution;
+ float y_resolution;
+ uint16_t res_unit;
printf("Dithering Lenna from colour to bi-level test\n");
if ((in_file = TIFFOpen(INPUT_TIFF_FILE_NAME, "r")) == NULL)
TIFFGetField(in_file, TIFFTAG_IMAGELENGTH, &image_length);
if (image_length <= 0)
return;
+ x_resolution = 200.0;
+ TIFFGetField(in_file, TIFFTAG_XRESOLUTION, &x_resolution);
+ y_resolution = 200.0;
+ TIFFGetField(in_file, TIFFTAG_YRESOLUTION, &y_resolution);
+ res_unit = RESUNIT_INCH;
+ TIFFSetField(in_file, TIFFTAG_RESOLUTIONUNIT, &res_unit);
bits_per_sample = 0;
TIFFGetField(in_file, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
samples_per_pixel = 0;
TIFFGetField(in_file, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel);
- printf("Original image is %d x %d, %d bits per sample, %d samples per pixel\n", image_width, image_length, bits_per_sample, samples_per_pixel);
+ printf("Original image is %d x %d, %f x %f resolution, %d bits per sample, %d samples per pixel\n", image_width, image_length, x_resolution, y_resolution, bits_per_sample, samples_per_pixel);
if ((image = malloc(image_width*image_length*samples_per_pixel)) == NULL)
return;
for (total = 0, i = 0; i < 1000; i++)
printf("Image size %d %d\n", total, image_width*image_length*samples_per_pixel);
TIFFClose(in_file);
+ if (output_length_scaling > 0)
+ output_length = (double) image_length*output_length_scaling*output_width/image_width;
+ else
+ output_length = -1;
+
im.image = image;
im.width = image_width;
im.length = image_length;
im.current_row = 0;
im.bytes_per_pixel = samples_per_pixel;
- s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_8, image_width, image_length, output_width, row_read, &im);
+ s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_8, image_width, image_length, output_width, output_length, row_read, &im);
output_width = image_translate_get_output_width(s);
output_length = image_translate_get_output_length(s);
return;
TIFFSetField(out_file, TIFFTAG_IMAGEWIDTH, output_width);
TIFFSetField(out_file, TIFFTAG_IMAGELENGTH, output_length);
+ TIFFSetField(out_file, TIFFTAG_XRESOLUTION, x_resolution);
+ if (output_length_scaling > 0)
+ y_resolution *= output_length_scaling;
+ TIFFSetField(out_file, TIFFTAG_YRESOLUTION, y_resolution);
+ TIFFSetField(out_file, TIFFTAG_RESOLUTIONUNIT, res_unit);
TIFFSetField(out_file, TIFFTAG_BITSPERSAMPLE, 1);
TIFFSetField(out_file, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
TIFFSetField(out_file, TIFFTAG_SAMPLESPERPIXEL, 1);
grow_tests_colour8();
#endif
#if 1
- lenna_tests(0, "lenna-bw.tif");
- lenna_tests(1728, "lenna-bw-1728.tif");
- lenna_tests(200, "lenna-bw-200.tif");
+ lenna_tests(0, 0, "lenna-bw.tif");
+ lenna_tests(200, 0, "lenna-bw-200.tif");
+ lenna_tests(1728, 0, "lenna-bw-1728.tif");
+ lenna_tests(1728, 2, "lenna-bw-1728-superfine.tif");
#endif
printf("Tests passed.\n");
return 0;
#include "spandsp.h"
-#define IN_FILE_NAME "../test-data/itu/t24/F21_200.TIF"
+//#define IN_FILE_NAME "../test-data/itu/t24/F21_200.TIF"
+#define IN_FILE_NAME "../test-data/itu/t24/F21B400.TIF"
#define OUT_FILE_NAME "t42_tests_receive.tif"
uint8_t data5[50000000];
int write_row = 0;
-typedef struct
-{
- float L;
- float a;
- float b;
-} cielab_t;
-
-#if 0
-static void generate_luts(void)
-{
- float r;
- uint8_t srgb;
- int i;
-
- printf("static const float srgb_to_linear[256] =\n");
- printf("{\n");
- for (i = 0; i < 256; i++)
- {
- /* Start with "i" as the sRGB value */
- r = i/256.0f;
-
- /* sRGB to Linear RGB */
- r = (r > 0.04045f) ? powf((r + 0.055f)/1.055f, 2.4f) : r/12.92f;
-
- printf((i < 255) ? " %f,\n" : " %f\n", r);
- }
- printf("};\n");
-
- printf("static const uint8_t linear_to_srgb[4096] =\n");
- printf("{\n");
- for (i = 0; i < 4096; i++)
- {
- /* Start with "i" as the linear RGB value */
- /* Linear RGB to sRGB */
- r = i/4096.0f;
-
- r = (r > 0.0031308f) ? (1.055f*powf(r, 1.0f/2.4f) - 0.055f) : r*12.92f;
-
- r = floorf(r*256.0f);
-
- srgb = (r < 0) ? 0 : (r <= 255) ? r : 255;
-
- printf((i < 4095) ? " %d,\n" : " %d\n", srgb);
- }
- printf("};\n");
-}
-/*- End of function --------------------------------------------------------*/
-#endif
-
static __inline__ uint16_t pack_16(uint8_t *s)
{
uint16_t value;
int main(int argc, char *argv[])
{
- char kk[256];
TIFF *tif;
uint32_t w;
uint32_t h;
uint16_t *yyya;
uint16_t *yyyb;
uint16_t *yyyz;
+ logging_state_t *logging;
printf("Demo of ITU/Lab library.\n");
+ logging = span_log_init(NULL, SPAN_LOG_FLOW, "T.42");
+
TIFF_FX_init();
set_lab_illuminant(&lab_param, 0.9638f, 1.0f, 0.8245f);
set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, FALSE);
-#if 0
- generate_luts();
-#endif
-
source_file = (argc > 1) ? argv[1] : IN_FILE_NAME;
/* sRGB to ITU */
if ((tif = TIFFOpen(source_file, "r")) == NULL)
printf("Unexpected compression %d\n", compression);
break;
}
+
if (process_raw)
{
nstrips = TIFFNumberOfStrips(tif);
t85_decode_init(&t85_dec, t85_row_write_handler, NULL);
t85_decode_set_comment_handler(&t85_dec, 1000, t85_comment_handler, NULL);
result = t85_decode_put_chunk(&t85_dec, data, total_len);
- if (result == T85_MORE_DATA)
+ if (result == T4_DECODE_MORE_DATA)
result = t85_decode_put_byte(&t85_dec, SIG_STATUS_END_OF_DATA);
len = t85_decode_get_compressed_image_size(&t85_dec);
printf("Compressed image is %d bytes, %d rows\n", len/8, write_row);
len = t85_decode_get_compressed_image_size(&t85_dec);
printf("Compressed image is %d bytes, %d rows\n", len/8, write_row);
}
- if (result == T85_MORE_DATA)
+ if (result == T4_DECODE_MORE_DATA)
{
printf("More\n");
result = t85_decode_put_byte(&t85_dec, SIG_STATUS_END_OF_DATA);
TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
TIFFSetField(tif, TIFFTAG_SOFTWARE, "spandsp");
TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, "Test");
- TIFFSetField(tif, TIFFTAG_DATETIME, "2011/02/03 12:30:45");
+ TIFFSetField(tif, TIFFTAG_DATETIME, "2012/07/03 12:30:45");
TIFFSetField(tif, TIFFTAG_MAKE, "soft-switch.org");
TIFFSetField(tif, TIFFTAG_MODEL, "spandsp");
TIFFSetField(tif, TIFFTAG_HOSTCOMPUTER, "i7.coppice.org");
{
printf("YYY ITULAB\n");
- if (!t42_itulab_to_itulab((tdata_t) &outptr, &outsize, data, off, w, h, kk, 256))
+ if (!t42_itulab_to_itulab(logging, (tdata_t) &outptr, &outsize, data, off, w, h))
{
- printf("Failed to convert to ITULAB - %s\n", kk);
+ printf("Failed to convert to ITULAB\n");
return 1;
}
free(data);
set_lab_illuminant(&lab_param, 0.9638f, 1.0f, 0.8245f);
set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, FALSE);
- if (!t42_srgb_to_itulab(&lab_param, (tdata_t) &outptr, &outsize, data, off, w, h, kk, 256))
+ if (!t42_srgb_to_itulab(logging, &lab_param, (tdata_t) &outptr, &outsize, data, off, w, h))
{
- printf("Failed to convert to ITULAB - %s\n", kk);
+ printf("Failed to convert to ITULAB\n");
return 1;
}
end = rdtscll();
TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
TIFFSetField(tif, TIFFTAG_SOFTWARE, "spandsp");
TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, "Test");
- TIFFSetField(tif, TIFFTAG_DATETIME, "2011/02/03 12:30:45");
+ TIFFSetField(tif, TIFFTAG_DATETIME, "2012/07/03 12:30:45");
TIFFSetField(tif, TIFFTAG_MAKE, "soft-switch.org");
TIFFSetField(tif, TIFFTAG_MODEL, "spandsp");
TIFFSetField(tif, TIFFTAG_HOSTCOMPUTER, "i7.coppice.org");
start = rdtscll();
data2 = NULL;
totdata = 0;
- t42_itulab_to_JPEG(&lab_param, (void **) &data2, &totdata, data, off, kk, 256);
+ t42_itulab_to_jpeg(logging, &lab_param, (void **) &data2, &totdata, data, off);
end = rdtscll();
printf("Duration %" PRIu64 "\n", end - start);
printf("Compressed length %d (%p)\n", totdata, data2);
if (TIFFWriteRawStrip(tif, 0, data2, totdata) < 0)
{
- printf("Failed to convert from ITULAB - %s\n", kk);
+ printf("Failed to convert from ITULAB\n");
return 1;
}
free(data);
#else
data2 = malloc(totdata);
start = rdtscll();
- if (!t42_itulab_to_srgb(&lab_param, data2, &off, data, off, &w, &h, kk, 256))
+ if (!t42_itulab_to_srgb(logging, &lab_param, data2, &off, data, off, &w, &h))
{
- printf("Failed to convert from ITULAB - %s\n", kk);
+ printf("Failed to convert from ITULAB\n");
return 1;
}
end = rdtscll();
properly. */
min_row_bits = 50;
block_size = 0;
- while ((opt = getopt(argc, argv, "126b:m:")) != -1)
+ while ((opt = getopt(argc, argv, "b:c:m:")) != -1)
{
switch (opt)
{
- case '1':
- compression = T4_COMPRESSION_ITU_T4_1D;
- compression_step = -1;
- break;
- case '2':
- compression = T4_COMPRESSION_ITU_T4_2D;
- compression_step = -1;
- break;
- case '6':
- compression = T4_COMPRESSION_ITU_T6;
- compression_step = -1;
- break;
case 'b':
block_size = atoi(optarg);
if (block_size > 1024)
block_size = 1024;
break;
+ case 'c':
+ if (strcmp(optarg, "T41D") == 0)
+ {
+ compression = T4_COMPRESSION_ITU_T4_1D;
+ compression_step = -1;
+ }
+ else if (strcmp(optarg, "T42D") == 0)
+ {
+ compression = T4_COMPRESSION_ITU_T4_2D;
+ compression_step = -1;
+ }
+ else if (strcmp(optarg, "T6") == 0)
+ {
+ compression = T4_COMPRESSION_ITU_T6;
+ compression_step = -1;
+ }
+ break;
case 'm':
min_row_bits = atoi(optarg);
break;
#if 1
printf("Testing image_function->compress->decompress->image_function\n");
/* Send end gets image from a function */
- if (t4_tx_init(&send_state, FALSE, -1, -1) == NULL)
+ if (t4_tx_init(&send_state, NULL, -1, -1) == NULL)
{
printf("Failed to init T.4 tx\n");
exit(2);
exit(2);
}
span_log_set_level(&receive_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW);
- t4_rx_set_x_resolution(&receive_state, t4_tx_get_x_resolution(&send_state));
- t4_rx_set_y_resolution(&receive_state, t4_tx_get_y_resolution(&send_state));
- t4_rx_set_image_width(&receive_state, t4_tx_get_image_width(&send_state));
/* Now send and receive all the pages in the source TIFF file */
sends = 0;
if (t4_tx_start_page(&send_state))
break;
+ t4_rx_set_x_resolution(&receive_state, t4_tx_get_x_resolution(&send_state));
+ t4_rx_set_y_resolution(&receive_state, t4_tx_get_y_resolution(&send_state));
+ t4_rx_set_image_width(&receive_state, t4_tx_get_image_width(&send_state));
}
t4_rx_start_page(&receive_state);
detect_page_end(-1000000, compression);
t85_decode_set_comment_handler(&t85_dec, 1000, comment_handler, NULL);
write_row = 0;
result = t85_decode_put_chunk(&t85_dec, testbuf, testbuf_len);
- if (result == T85_MORE_DATA)
+ if (result == T4_DECODE_MORE_DATA)
result = t85_decode_put_byte(&t85_dec, SIG_STATUS_END_OF_DATA);
cnt_a = t85_encode_get_compressed_image_size(&t85_enc);
cnt_b = t85_decode_get_compressed_image_size(&t85_dec);
- if (cnt_a != cnt_b || cnt_a != testbuf_len*8 || result != T85_OK)
+ if (cnt_a != cnt_b || cnt_a != testbuf_len*8 || result != T4_DECODE_OK)
{
printf("Decode result %d\n", result);
printf("%ld/%ld bits of %ld bits of BIE read. %lu lines decoded.\n",
if (comment && comment[0] != 'X')
t85_decode_set_comment_handler(&t85_dec, 1000, comment_handler, NULL);
write_row = 0;
- result = T85_MORE_DATA;
+ result = T4_DECODE_MORE_DATA;
for (l = 0; l < testbuf_len; l++)
{
result = t85_decode_put_chunk(&t85_dec, &testbuf[l], 1);
- if (result != T85_MORE_DATA)
+ if (result != T4_DECODE_MORE_DATA)
{
l++;
break;
}
}
- if (result == T85_MORE_DATA)
+ if (result == T4_DECODE_MORE_DATA)
result = t85_decode_put_byte(&t85_dec, SIG_STATUS_END_OF_DATA);
- if (l != testbuf_len || result != T85_OK)
+ if (l != testbuf_len || result != T4_DECODE_OK)
{
printf("Decode result %d\n", result);
printf("%ld bytes of %ld bytes of BIE read. %lu lines decoded.\n",