T.85 compression has now been added to the FAX engine in spandsp
This commit is contained in:
parent
232fe67722
commit
4bcdafec68
|
@ -262,8 +262,6 @@ fi
|
|||
SPANDSP_SUPPORT_T42="#undef SPANDSP_SUPPORT_T42"
|
||||
#AC_DEFINE([SPANDSP_SUPPORT_T43], [1], [Support T.43 JBIG gray and colour compression])
|
||||
SPANDSP_SUPPORT_T43="#undef SPANDSP_SUPPORT_T43"
|
||||
#AC_DEFINE([SPANDSP_SUPPORT_T85], [1], [Support T.85 JBIG compression])
|
||||
SPANDSP_SUPPORT_T85="#undef SPANDSP_SUPPORT_T85"
|
||||
#AC_DEFINE([SPANDSP_SUPPORT_V34], [1], [Support the V.34 FAX modem])
|
||||
SPANDSP_SUPPORT_V34="#undef SPANDSP_SUPPORT_V34"
|
||||
|
||||
|
@ -550,7 +548,6 @@ AC_SUBST(SPANDSP_MISALIGNED_ACCESS_FAILS)
|
|||
AC_SUBST(SPANDSP_USE_EXPORT_CAPABILITY)
|
||||
AC_SUBST(SPANDSP_SUPPORT_T42)
|
||||
AC_SUBST(SPANDSP_SUPPORT_T43)
|
||||
AC_SUBST(SPANDSP_SUPPORT_T85)
|
||||
AC_SUBST(SPANDSP_SUPPORT_V34)
|
||||
AC_SUBST(INSERT_INTTYPES_HEADER)
|
||||
AC_SUBST(INSERT_STDINT_HEADER)
|
||||
|
|
|
@ -143,6 +143,8 @@ libspandsp_la_SOURCES = ademco_contactid.c \
|
|||
super_tone_rx.c \
|
||||
super_tone_tx.c \
|
||||
swept_tone.c \
|
||||
t4_t6_decode.c \
|
||||
t4_t6_encode.c \
|
||||
t4_rx.c \
|
||||
t4_tx.c \
|
||||
t30.c \
|
||||
|
@ -153,10 +155,10 @@ libspandsp_la_SOURCES = ademco_contactid.c \
|
|||
t38_core.c \
|
||||
t38_gateway.c \
|
||||
t38_non_ecm_buffer.c \
|
||||
t38_terminal.c \
|
||||
t81_t82_arith_coding.c \
|
||||
t85_decode.c \
|
||||
t85_encode.c \
|
||||
t38_terminal.c \
|
||||
testcpuid.c \
|
||||
time_scale.c \
|
||||
timezone.c \
|
||||
|
|
|
@ -372,9 +372,9 @@ SPAN_DECLARE(void) dtmf_rx_set_realtime_callback(dtmf_rx_state_t *s,
|
|||
|
||||
SPAN_DECLARE(void) dtmf_rx_parms(dtmf_rx_state_t *s,
|
||||
int filter_dialtone,
|
||||
int twist,
|
||||
int reverse_twist,
|
||||
int threshold)
|
||||
float twist,
|
||||
float reverse_twist,
|
||||
float threshold)
|
||||
{
|
||||
float x;
|
||||
|
||||
|
|
|
@ -74,12 +74,8 @@
|
|||
#include "spandsp/timezone.h"
|
||||
#include "spandsp/t4_rx.h"
|
||||
#include "spandsp/t4_tx.h"
|
||||
#if defined(SPANDSP_SUPPORT_T42) || defined(SPANDSP_SUPPORT_T43) || defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/t81_t82_arith_coding.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/t85.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
#include "spandsp/t42.h"
|
||||
#endif
|
||||
|
@ -112,12 +108,8 @@
|
|||
#include "spandsp/private/hdlc.h"
|
||||
#include "spandsp/private/fax_modems.h"
|
||||
#include "spandsp/private/timezone.h"
|
||||
#if defined(SPANDSP_SUPPORT_T42) || defined(SPANDSP_SUPPORT_T43) || defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/private/t81_t82_arith_coding.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/private/t85.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
#include "spandsp/private/t42.h"
|
||||
#endif
|
||||
|
@ -547,6 +539,16 @@ static void fax_set_tx_type(void *user_data, int type, int bit_rate, int short_t
|
|||
fax_modems_set_next_tx_handler(s, (span_tx_handler_t) &fsk_tx, &t->v21_tx);
|
||||
t->transmit = TRUE;
|
||||
break;
|
||||
case T30_MODEM_V17:
|
||||
silence_gen_alter(&t->silence_gen, ms_to_samples(75));
|
||||
/* For any fast modem, set 200ms of preamble flags */
|
||||
hdlc_tx_flags(&t->hdlc_tx, bit_rate/(8*5));
|
||||
v17_tx_restart(&t->fast_modems.v17_tx, bit_rate, t->use_tep, short_train);
|
||||
v17_tx_set_get_bit(&t->fast_modems.v17_tx, get_bit_func, get_bit_user_data);
|
||||
fax_modems_set_tx_handler(s, (span_tx_handler_t) &silence_gen, &t->silence_gen);
|
||||
fax_modems_set_next_tx_handler(s, (span_tx_handler_t) &v17_tx, &t->fast_modems.v17_tx);
|
||||
t->transmit = TRUE;
|
||||
break;
|
||||
case T30_MODEM_V27TER:
|
||||
silence_gen_alter(&t->silence_gen, ms_to_samples(75));
|
||||
/* For any fast modem, set 200ms of preamble flags */
|
||||
|
@ -567,16 +569,6 @@ static void fax_set_tx_type(void *user_data, int type, int bit_rate, int short_t
|
|||
fax_modems_set_next_tx_handler(s, (span_tx_handler_t) &v29_tx, &t->fast_modems.v29_tx);
|
||||
t->transmit = TRUE;
|
||||
break;
|
||||
case T30_MODEM_V17:
|
||||
silence_gen_alter(&t->silence_gen, ms_to_samples(75));
|
||||
/* For any fast modem, set 200ms of preamble flags */
|
||||
hdlc_tx_flags(&t->hdlc_tx, bit_rate/(8*5));
|
||||
v17_tx_restart(&t->fast_modems.v17_tx, bit_rate, t->use_tep, short_train);
|
||||
v17_tx_set_get_bit(&t->fast_modems.v17_tx, get_bit_func, get_bit_user_data);
|
||||
fax_modems_set_tx_handler(s, (span_tx_handler_t) &silence_gen, &t->silence_gen);
|
||||
fax_modems_set_next_tx_handler(s, (span_tx_handler_t) &v17_tx, &t->fast_modems.v17_tx);
|
||||
t->transmit = TRUE;
|
||||
break;
|
||||
case T30_MODEM_DONE:
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "FAX exchange complete\n");
|
||||
/* Fall through */
|
||||
|
|
|
@ -95,13 +95,13 @@ SPAN_DECLARE_NONSTD(int) fax_modems_v17_v21_rx(void *user_data, const int16_t am
|
|||
fsk_rx(&s->v21_rx, amp, len);
|
||||
if (s->rx_frame_received)
|
||||
{
|
||||
/* We have received something, and the fast modem has not trained. We must
|
||||
be receiving valid V.21 */
|
||||
/* We have received something, and the fast modem has not trained. We must be receiving valid V.21 */
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.17 + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
|
||||
s->rx_handler = (span_rx_handler_t) &fsk_rx;
|
||||
s->rx_fillin_handler = (span_rx_fillin_handler_t) &fsk_rx_fillin;
|
||||
s->rx_user_data = &s->v21_rx;
|
||||
}
|
||||
/*endif*/
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
@ -126,13 +126,13 @@ SPAN_DECLARE_NONSTD(int) fax_modems_v27ter_v21_rx(void *user_data, const int16_t
|
|||
fsk_rx(&s->v21_rx, amp, len);
|
||||
if (s->rx_frame_received)
|
||||
{
|
||||
/* We have received something, and the fast modem has not trained. We must
|
||||
be receiving valid V.21 */
|
||||
/* We have received something, and the fast modem has not trained. We must be receiving valid V.21 */
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.27ter + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
|
||||
s->rx_handler = (span_rx_handler_t) &fsk_rx;
|
||||
s->rx_fillin_handler = (span_rx_fillin_handler_t) &fsk_rx_fillin;
|
||||
s->rx_user_data = &s->v21_rx;
|
||||
}
|
||||
/*endif*/
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
@ -157,13 +157,13 @@ SPAN_DECLARE_NONSTD(int) fax_modems_v29_v21_rx(void *user_data, const int16_t am
|
|||
fsk_rx(&s->v21_rx, amp, len);
|
||||
if (s->rx_frame_received)
|
||||
{
|
||||
/* We have received something, and the fast modem has not trained. We must
|
||||
be receiving valid V.21 */
|
||||
/* We have received something, and the fast modem has not trained. We must be receiving valid V.21 */
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.29 + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
|
||||
s->rx_handler = (span_rx_handler_t) &fsk_rx;
|
||||
s->rx_fillin_handler = (span_rx_fillin_handler_t) &fsk_rx_fillin;
|
||||
s->rx_user_data = &s->v21_rx;
|
||||
}
|
||||
/*endif*/
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
@ -203,6 +203,7 @@ static void v17_rx_status_handler(void *user_data, int status)
|
|||
s->rx_user_data = &s->fast_modems.v17_rx;
|
||||
break;
|
||||
}
|
||||
/*endswitch*/
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
|
@ -220,6 +221,7 @@ static void v27ter_rx_status_handler(void *user_data, int status)
|
|||
s->rx_user_data = &s->fast_modems.v27ter_rx;
|
||||
break;
|
||||
}
|
||||
/*endswitch*/
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
|
@ -237,6 +239,7 @@ static void v29_rx_status_handler(void *user_data, int status)
|
|||
s->rx_user_data = &s->fast_modems.v29_rx;
|
||||
break;
|
||||
}
|
||||
/*endswitch*/
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
|
@ -254,6 +257,7 @@ SPAN_DECLARE(void) fax_modems_start_rx_modem(fax_modems_state_t *s, int which)
|
|||
v29_rx_set_modem_status_handler(&s->fast_modems.v29_rx, v29_rx_status_handler, s);
|
||||
break;
|
||||
}
|
||||
/*endswitch*/
|
||||
fsk_rx_set_modem_status_handler(&s->v21_rx, v21_rx_status_handler, s);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
@ -290,6 +294,7 @@ SPAN_DECLARE(fax_modems_state_t *) fax_modems_init(fax_modems_state_t *s,
|
|||
if ((s = (fax_modems_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
/*endif*/
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->use_tep = use_tep;
|
||||
|
||||
|
@ -314,6 +319,7 @@ SPAN_DECLARE(fax_modems_state_t *) fax_modems_init(fax_modems_state_t *s,
|
|||
tone_callback,
|
||||
user_data);
|
||||
}
|
||||
/*endif*/
|
||||
dc_restore_init(&s->dc_restore);
|
||||
|
||||
s->rx_signal_present = FALSE;
|
||||
|
|
|
@ -57,12 +57,8 @@
|
|||
#include "spandsp/timezone.h"
|
||||
#include "spandsp/t4_rx.h"
|
||||
#include "spandsp/t4_tx.h"
|
||||
#if defined(SPANDSP_SUPPORT_T42) || defined(SPANDSP_SUPPORT_T43) || defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/t81_t82_arith_coding.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/t85.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
#include "spandsp/t42.h"
|
||||
#endif
|
||||
|
@ -74,12 +70,8 @@
|
|||
#include "spandsp/image_translate.h"
|
||||
|
||||
#include "spandsp/private/logging.h"
|
||||
#if defined(SPANDSP_SUPPORT_T42) || defined(SPANDSP_SUPPORT_T43) || defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/private/t81_t82_arith_coding.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/private/t85.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
#include "spandsp/private/t42.h"
|
||||
#endif
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
|
||||
@SPANDSP_SUPPORT_T42@
|
||||
@SPANDSP_SUPPORT_T43@
|
||||
@SPANDSP_SUPPORT_T85@
|
||||
@SPANDSP_SUPPORT_V34@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
|
|
@ -152,15 +152,15 @@ SPAN_DECLARE(void) dtmf_rx_set_realtime_callback(dtmf_rx_state_t *s,
|
|||
\param s The DTMF receiver context.
|
||||
\param filter_dialtone TRUE to enable filtering of dialtone, FALSE
|
||||
to disable, < 0 to leave unchanged.
|
||||
\param twist Acceptable twist, in dB. < 0 to leave unchanged.
|
||||
\param reverse_twist Acceptable reverse twist, in dB. < 0 to leave unchanged.
|
||||
\param twist Acceptable twist, in dB. < 0.0 to leave unchanged.
|
||||
\param reverse_twist Acceptable reverse twist, in dB. < 0.0 to leave unchanged.
|
||||
\param threshold The minimum acceptable tone level for detection, in dBm0.
|
||||
<= -99 to leave unchanged. */
|
||||
<= -99.0 to leave unchanged. */
|
||||
SPAN_DECLARE(void) dtmf_rx_parms(dtmf_rx_state_t *s,
|
||||
int filter_dialtone,
|
||||
int twist,
|
||||
int reverse_twist,
|
||||
int threshold);
|
||||
float twist,
|
||||
float reverse_twist,
|
||||
float threshold);
|
||||
|
||||
/*! Process a block of received DTMF audio samples.
|
||||
\brief Process a block of received DTMF audio samples.
|
||||
|
|
|
@ -88,7 +88,7 @@ struct fsk_rx_state_s
|
|||
int buf_ptr;
|
||||
|
||||
int frame_state;
|
||||
int frame_bits;
|
||||
unsigned int frame_bits;
|
||||
int baud_phase;
|
||||
int last_bit;
|
||||
int scaling_shift;
|
||||
|
|
|
@ -37,8 +37,8 @@ struct t30_state_s
|
|||
/*! \brief T.4 context for reading or writing image data. */
|
||||
union
|
||||
{
|
||||
t4_state_t rx;
|
||||
t4_state_t tx;
|
||||
t4_rx_state_t rx;
|
||||
t4_tx_state_t tx;
|
||||
} t4;
|
||||
/*! \brief The type of FAX operation currently in progress */
|
||||
int operation_in_progress;
|
||||
|
|
|
@ -36,37 +36,97 @@ typedef struct
|
|||
/*! \brief The libtiff context for the current TIFF file */
|
||||
TIFF *tiff_file;
|
||||
|
||||
/*! Image type - bilevel, gray, colour */
|
||||
int image_type;
|
||||
/*! \brief The compression type for output to the TIFF file. */
|
||||
int32_t output_compression;
|
||||
int output_encoding;
|
||||
/*! \brief The TIFF photometric setting for the current page. */
|
||||
uint16_t photo_metric;
|
||||
/*! \brief The TIFF fill order setting for the current page. */
|
||||
uint16_t fill_order;
|
||||
/*! \brief The TIFF G3 FAX options. */
|
||||
int32_t output_t4_options;
|
||||
|
||||
/*! \brief The number of pages in the current image file. */
|
||||
int pages_in_file;
|
||||
|
||||
/*! \brief The time at which handling of the current page began. */
|
||||
time_t page_start_time;
|
||||
|
||||
/*! \brief A point to the image buffer. */
|
||||
uint8_t *image_buffer;
|
||||
/*! \brief The size of the image in the image buffer, in bytes. */
|
||||
int image_size;
|
||||
/*! \brief The current size of the image buffer. */
|
||||
int image_buffer_size;
|
||||
} t4_rx_tiff_state_t;
|
||||
|
||||
/*!
|
||||
T.4 FAX decompression metadata descriptor. This contains information about the image
|
||||
which may be relevant to the backend, but is not relevant to the image decoding process.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/*! \brief Column-to-column (X) resolution in pixels per metre. */
|
||||
int x_resolution;
|
||||
/*! \brief Row-to-row (Y) resolution in pixels per metre. */
|
||||
int y_resolution;
|
||||
|
||||
/* "Background" information about the FAX, which can be stored in the image file. */
|
||||
/*! \brief The vendor of the machine which produced the file. */
|
||||
const char *vendor;
|
||||
/*! \brief The model of machine which produced the file. */
|
||||
const char *model;
|
||||
/*! \brief The local ident string. */
|
||||
const char *local_ident;
|
||||
/*! \brief The remote end's ident string. */
|
||||
const char *far_ident;
|
||||
/*! \brief The FAX sub-address. */
|
||||
const char *sub_address;
|
||||
/*! \brief The FAX DCS information, as an ASCII hex string. */
|
||||
const char *dcs;
|
||||
} t4_rx_metadata_t;
|
||||
|
||||
/*! \brief The first page to transfer. -1 to start at the beginning of the file. */
|
||||
int start_page;
|
||||
/*! \brief The last page to transfer. -1 to continue to the end of the file. */
|
||||
int stop_page;
|
||||
} t4_tiff_state_t;
|
||||
/*!
|
||||
T.4 FAX decompression descriptor. This defines the working state
|
||||
for a single instance of a T.4 FAX decompression channel.
|
||||
*/
|
||||
struct t4_rx_state_s
|
||||
{
|
||||
/*! \brief Callback function to write a row of pixels to the image destination. */
|
||||
t4_row_write_handler_t row_handler;
|
||||
/*! \brief Opaque pointer passed to row_write_handler. */
|
||||
void *row_handler_user_data;
|
||||
|
||||
/*! \brief The number of pages transferred to date. */
|
||||
int current_page;
|
||||
|
||||
/*! \brief The size of the compressed image on the line side, in bits. */
|
||||
int line_image_size;
|
||||
|
||||
/*! \brief The type of compression used between the FAX machines. */
|
||||
int line_encoding;
|
||||
|
||||
/*! \brief The width of the current page, in pixels. */
|
||||
uint32_t image_width;
|
||||
|
||||
union
|
||||
{
|
||||
t4_t6_decode_state_t t4_t6;
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
t42_decode_state_t t42;
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T43)
|
||||
t43_decode_state_t t43;
|
||||
#endif
|
||||
t85_decode_state_t t85;
|
||||
} decoder;
|
||||
|
||||
/* Supporting information, like resolutions, which the backend may want. */
|
||||
t4_rx_metadata_t metadata;
|
||||
|
||||
/*! \brief All TIFF file specific state information for the T.4 context. */
|
||||
t4_rx_tiff_state_t tiff;
|
||||
|
||||
/*! \brief Error and flow logging control */
|
||||
logging_state_t logging;
|
||||
};
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
|
|
|
@ -31,18 +31,36 @@
|
|||
*/
|
||||
struct t4_t6_decode_state_s
|
||||
{
|
||||
/*! \brief The type of compression used between the FAX machines. */
|
||||
//int encoding;
|
||||
/*! \brief Width of the current page, in pixels. */
|
||||
//int image_width;
|
||||
|
||||
/*! \brief Callback function to write a row of pixels to the image destination. */
|
||||
t4_row_write_handler_t row_write_handler;
|
||||
/*! \brief Opaque pointer passed to row_write_handler. */
|
||||
void *row_write_user_data;
|
||||
|
||||
/*! \brief A pointer into the image buffer indicating where the last row begins */
|
||||
int last_row_starts_at;
|
||||
/*! \brief The type of compression used between the FAX machines. */
|
||||
int encoding;
|
||||
/*! \brief Width of the current page, in pixels. */
|
||||
int image_width;
|
||||
|
||||
/*! \brief Length of the current page, in pixels. */
|
||||
int image_length;
|
||||
/*! \brief The current number of bytes per row of uncompressed image data. */
|
||||
int bytes_per_row;
|
||||
|
||||
/*! \brief The current number of bits in the current encoded row. */
|
||||
int row_bits;
|
||||
/*! \brief Pointer to the buffer for the current pixel row. */
|
||||
uint8_t *row_buf;
|
||||
|
||||
/*! \brief This variable is set if we are treating the current row as a 2D encoded
|
||||
one. */
|
||||
int row_is_2d;
|
||||
/*! \brief The current length of the current row. */
|
||||
int row_len;
|
||||
|
||||
/*! \brief Black and white run-lengths for the current row. */
|
||||
uint32_t *cur_runs;
|
||||
/*! \brief Black and white run-lengths for the reference row. */
|
||||
uint32_t *ref_runs;
|
||||
|
||||
/*! \brief This variable is used to count the consecutive EOLS we have seen. If it
|
||||
reaches six, this is the end of the image. It is initially set to -1 for
|
||||
|
@ -64,7 +82,7 @@ struct t4_t6_decode_state_s
|
|||
/*! \brief 2D horizontal mode control. */
|
||||
int black_white;
|
||||
/*! \brief TRUE if the current run is black */
|
||||
int its_black;
|
||||
int in_black;
|
||||
|
||||
/*! \brief The current step into the current row run-lengths buffer. */
|
||||
int a_cursor;
|
||||
|
@ -78,14 +96,18 @@ struct t4_t6_decode_state_s
|
|||
/*! \brief The number of bits to be skipped before trying to match the next code word. */
|
||||
int rx_skip_bits;
|
||||
|
||||
/*! \brief Decoded pixel buffer. */
|
||||
//uint32_t pixel_stream;
|
||||
/*! \brief The number of bits currently in pixel_stream. */
|
||||
//int tx_bits;
|
||||
/*! \brief Decoded pixel stream buffer. */
|
||||
uint32_t pixel_stream;
|
||||
/*! \brief The number of pixels currently in pixel_stream. */
|
||||
int pixels;
|
||||
|
||||
/*! \brief Current pixel row number. */
|
||||
//int row;
|
||||
/*! \brief The minimum bits in any row of the current page. For monitoring only. */
|
||||
int min_row_bits;
|
||||
/*! \brief The maximum bits in any row of the current page. For monitoring only. */
|
||||
int max_row_bits;
|
||||
|
||||
/*! \brief The size of the compressed image, in bits. */
|
||||
int compressed_image_size;
|
||||
/*! \brief The current number of consecutive bad rows. */
|
||||
int curr_bad_row_run;
|
||||
/*! \brief The longest run of consecutive bad rows seen in the current page. */
|
||||
|
@ -94,7 +116,7 @@ struct t4_t6_decode_state_s
|
|||
int bad_rows;
|
||||
|
||||
/*! \brief Error and flow logging control */
|
||||
//logging_state_t logging;
|
||||
logging_state_t logging;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -31,28 +31,66 @@
|
|||
*/
|
||||
struct t4_t6_encode_state_s
|
||||
{
|
||||
/*! \brief Callback function to read a row of pixels from the image source. */
|
||||
t4_row_read_handler_t row_read_handler;
|
||||
/*! \brief Opaque pointer passed to row_read_handler. */
|
||||
void *row_read_user_data;
|
||||
|
||||
/*! \brief The type of compression used. */
|
||||
int encoding;
|
||||
/*! \brief Width of the current page, in pixels. */
|
||||
int image_width;
|
||||
/*! \brief The minimum number of encoded bits per row. This is a timing thing
|
||||
for hardware FAX machines. */
|
||||
int min_bits_per_row;
|
||||
/*! \brief The current maximum contiguous rows that may be 2D encoded. */
|
||||
int max_rows_to_next_1d_row;
|
||||
|
||||
/*! \brief Length of the current page, in pixels. */
|
||||
int image_length;
|
||||
/*! \brief The current number of bytes per row of uncompressed image data. */
|
||||
int bytes_per_row;
|
||||
|
||||
/*! \brief Number of rows left that can be 2D encoded, before a 1D encoded row
|
||||
must be used. */
|
||||
int rows_to_next_1d_row;
|
||||
/*! \brief The current number of bits in the current encoded row. */
|
||||
int row_bits;
|
||||
|
||||
/*! \brief This variable is set if we are treating the current row as a 2D encoded
|
||||
one. */
|
||||
int row_is_2d;
|
||||
|
||||
/*! \brief Encoded data bits buffer. */
|
||||
uint32_t tx_bitstream;
|
||||
/*! \brief The number of bits currently in tx_bitstream. */
|
||||
int tx_bits;
|
||||
/*! \brief The working chunk of the output bit stream */
|
||||
uint8_t *bitstream;
|
||||
/*! \brief Input pointer to the output bit stream buffer. */
|
||||
int bitstream_iptr;
|
||||
/*! \brief Output pointer to the output bit stream buffer. */
|
||||
int bitstream_optr;
|
||||
/*! \brief Pointer to the bit within the byte containing the next image bit to transmit. */
|
||||
int bit_pos;
|
||||
|
||||
/*! \brief Black and white run-lengths for the current row. */
|
||||
uint32_t *cur_runs;
|
||||
/*! \brief Black and white run-lengths for the reference row. */
|
||||
uint32_t *ref_runs;
|
||||
/*! \brief The number of runs currently in the reference row. */
|
||||
int ref_steps;
|
||||
|
||||
/*! \brief Pointer to the byte containing the next image bit to transmit. */
|
||||
int bit_pos;
|
||||
/*! \brief Pointer to the bit within the byte containing the next image bit to transmit. */
|
||||
int bit_ptr;
|
||||
/*! \brief The minimum bits in any row of the current page. For monitoring only. */
|
||||
int min_row_bits;
|
||||
/*! \brief The maximum bits in any row of the current page. For monitoring only. */
|
||||
int max_row_bits;
|
||||
|
||||
/*! \brief Callback function to read a row of pixels from the image source. */
|
||||
t4_row_read_handler_t row_read_handler;
|
||||
/*! \brief Opaque pointer passed to row_read_handler. */
|
||||
void *row_read_user_data;
|
||||
/*! \brief The size of the compressed image, in bits. */
|
||||
int compressed_image_size;
|
||||
|
||||
/*! \brief Error and flow logging control */
|
||||
logging_state_t logging;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,20 +27,75 @@
|
|||
#define _SPANDSP_PRIVATE_T4_TX_H_
|
||||
|
||||
/*!
|
||||
T.4 FAX compression/decompression descriptor. This defines the working state
|
||||
for a single instance of a T.4 FAX compression or decompression channel.
|
||||
TIFF specific state information to go with T.4 compression or decompression handling.
|
||||
*/
|
||||
struct t4_state_s
|
||||
typedef struct
|
||||
{
|
||||
/*! \brief The same structure is used for T.4 transmit and receive. This variable
|
||||
records which mode is in progress. */
|
||||
int rx;
|
||||
/*! \brief The current file name. */
|
||||
const char *file;
|
||||
/*! \brief The libtiff context for the current TIFF file */
|
||||
TIFF *tiff_file;
|
||||
|
||||
/*! Image type - bilevel, gray, colour */
|
||||
int image_type;
|
||||
/*! \brief The TIFF photometric setting for the current page. */
|
||||
uint16_t photo_metric;
|
||||
/*! \brief The TIFF fill order setting for the current page. */
|
||||
uint16_t fill_order;
|
||||
|
||||
/*! \brief The number of pages in the current image file. */
|
||||
int pages_in_file;
|
||||
|
||||
/*! \brief A pointer to the image buffer. */
|
||||
uint8_t *image_buffer;
|
||||
/*! \brief The size of the image in the image buffer, in bytes. */
|
||||
int image_size;
|
||||
/*! \brief The current size of the image buffer. */
|
||||
int image_buffer_size;
|
||||
/*! \brief Row counter for playing out the rows of the image. */
|
||||
int row;
|
||||
} t4_tx_tiff_state_t;
|
||||
|
||||
/*!
|
||||
T.4 FAX compression metadata descriptor. This contains information about the image
|
||||
which may be relevant to the backend, but is not generally relevant to the image
|
||||
encoding process. The exception here is the y-resolution, which is used in T.4 2-D
|
||||
encoding for non-ECM applications, to optimise the balance of density and robustness.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/*! \brief Column-to-column (X) resolution in pixels per metre. */
|
||||
int x_resolution;
|
||||
/*! \brief Row-to-row (Y) resolution in pixels per metre. */
|
||||
int y_resolution;
|
||||
} t4_tx_metadata_t;
|
||||
|
||||
/*!
|
||||
T.4 FAX compression descriptor. This defines the working state
|
||||
for a single instance of a T.4 FAX compression channel.
|
||||
*/
|
||||
struct t4_tx_state_s
|
||||
{
|
||||
/*! \brief Callback function to read a row of pixels from the image source. */
|
||||
t4_row_read_handler_t row_handler;
|
||||
/*! \brief Opaque pointer passed to row_read_handler. */
|
||||
void *row_handler_user_data;
|
||||
|
||||
/*! \brief The type of compression used between the FAX machines. */
|
||||
int line_encoding;
|
||||
|
||||
/*! \brief The time at which handling of the current page began. */
|
||||
time_t page_start_time;
|
||||
/*! \brief The width of the current page, in pixels. */
|
||||
uint32_t image_width;
|
||||
/*! \brief The length of the current page, in pixels. */
|
||||
uint32_t image_length;
|
||||
|
||||
/*! \brief The size of the compressed image on the line side, in bits. */
|
||||
int line_image_size;
|
||||
|
||||
/*! \brief The first page to transfer. -1 to start at the beginning of the file. */
|
||||
int start_page;
|
||||
/*! \brief The last page to transfer. -1 to continue to the end of the file. */
|
||||
int stop_page;
|
||||
|
||||
/*! \brief TRUE for FAX page headers to overlay (i.e. replace) the beginning of the
|
||||
page image. FALSE for FAX page headers to add to the overall length of
|
||||
|
@ -49,66 +104,42 @@ struct t4_state_s
|
|||
/*! \brief The text which will be used in FAX page header. No text results
|
||||
in no header line. */
|
||||
const char *header_info;
|
||||
/*! \brief Optional per instance time zone for the FAX page header timestamp. */
|
||||
struct tz_s *tz;
|
||||
|
||||
/*! \brief The size of the compressed image on the line side, in bits. */
|
||||
int line_image_size;
|
||||
|
||||
/*! \brief The current number of bytes per row of uncompressed image data. */
|
||||
int bytes_per_row;
|
||||
/*! \brief The size of the image in the image buffer, in bytes. */
|
||||
int image_size;
|
||||
/*! \brief The current size of the image buffer. */
|
||||
int image_buffer_size;
|
||||
/*! \brief A point to the image buffer. */
|
||||
uint8_t *image_buffer;
|
||||
|
||||
/*! \brief The number of pages transferred to date. */
|
||||
/*! \brief The local ident string. This is used with header_info to form a
|
||||
page header line. */
|
||||
const char *local_ident;
|
||||
/*! \brief The page number of current page. The first page is zero. If FAX page
|
||||
headers are used, the page number in the header will be one more than
|
||||
this value (i.e. they start from 1). */
|
||||
int current_page;
|
||||
/*! \brief Column-to-column (X) resolution in pixels per metre. */
|
||||
int x_resolution;
|
||||
/*! \brief Row-to-row (Y) resolution in pixels per metre. */
|
||||
int y_resolution;
|
||||
/*! \brief Width of the current page, in pixels. */
|
||||
int image_width;
|
||||
/*! \brief Length of the current page, in pixels. */
|
||||
int image_length;
|
||||
/*! \brief Current pixel row number. */
|
||||
int row;
|
||||
|
||||
/*! \brief This variable is set if we are treating the current row as a 2D encoded
|
||||
one. */
|
||||
int row_is_2d;
|
||||
/*! \brief The current length of the current row. */
|
||||
int row_len;
|
||||
/*! \brief The composed text of the FAX page header, if there is one. */
|
||||
char *header_text;
|
||||
/*! \brief Optional per instance time zone for the FAX page header timestamp. */
|
||||
tz_t *tz;
|
||||
|
||||
/*! \brief Black and white run-lengths for the current row. */
|
||||
uint32_t *cur_runs;
|
||||
/*! \brief Black and white run-lengths for the reference row. */
|
||||
uint32_t *ref_runs;
|
||||
/*! \brief Pointer to the buffer for the current pixel row. */
|
||||
uint8_t *row_buf;
|
||||
/*! \brief Row counter for playing out the rows of the header line. */
|
||||
int header_row;
|
||||
|
||||
/*! \brief Encoded data bits buffer. */
|
||||
uint32_t tx_bitstream;
|
||||
/*! \brief The number of bits currently in tx_bitstream. */
|
||||
int tx_bits;
|
||||
union
|
||||
{
|
||||
t4_t6_encode_state_t t4_t6;
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
t42_encode_state_t t42;
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T43)
|
||||
t43_encode_state_t t43;
|
||||
#endif
|
||||
t85_encode_state_t t85;
|
||||
} encoder;
|
||||
|
||||
/*! \brief The current number of bits in the current encoded row. */
|
||||
int row_bits;
|
||||
/*! \brief The minimum bits in any row of the current page. For monitoring only. */
|
||||
int min_row_bits;
|
||||
/*! \brief The maximum bits in any row of the current page. For monitoring only. */
|
||||
int max_row_bits;
|
||||
/* Supporting information, like resolutions, which the backend may want. */
|
||||
t4_tx_metadata_t metadata;
|
||||
|
||||
/*! \brief All TIFF file specific state information for the T.4 context. */
|
||||
t4_tx_tiff_state_t tiff;
|
||||
|
||||
/*! \brief Error and flow logging control */
|
||||
logging_state_t logging;
|
||||
|
||||
/*! \brief All TIFF file specific state information for the T.4 context. */
|
||||
t4_tiff_state_t tiff;
|
||||
t4_t6_decode_state_t t4_t6_rx;
|
||||
t4_t6_encode_state_t t4_t6_tx;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -203,7 +203,7 @@ typedef enum
|
|||
T.4 FAX compression/decompression descriptor. This defines the working state
|
||||
for a single instance of a T.4 FAX compression or decompression channel.
|
||||
*/
|
||||
typedef struct t4_state_s t4_state_t;
|
||||
typedef struct t4_rx_state_s t4_rx_state_t;
|
||||
|
||||
/*!
|
||||
T.4 FAX compression/decompression statistics.
|
||||
|
@ -241,108 +241,109 @@ extern "C" {
|
|||
\param file The name of the file to be received.
|
||||
\param output_encoding The output encoding.
|
||||
\return A pointer to the context, or NULL if there was a problem. */
|
||||
SPAN_DECLARE(t4_state_t *) t4_rx_init(t4_state_t *s, const char *file, int output_encoding);
|
||||
SPAN_DECLARE(t4_rx_state_t *) t4_rx_init(t4_rx_state_t *s, const char *file, int output_encoding);
|
||||
|
||||
/*! \brief Prepare to receive the next page of the current document.
|
||||
\param s The T.4 context.
|
||||
\return zero for success, -1 for failure. */
|
||||
SPAN_DECLARE(int) t4_rx_start_page(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_rx_start_page(t4_rx_state_t *s);
|
||||
|
||||
/*! \brief Put a bit of the current document page.
|
||||
\param s The T.4 context.
|
||||
\param bit The data bit.
|
||||
\return TRUE when the bit ends the document page, otherwise FALSE. */
|
||||
SPAN_DECLARE(int) t4_rx_put_bit(t4_state_t *s, int bit);
|
||||
SPAN_DECLARE(int) t4_rx_put_bit(t4_rx_state_t *s, int bit);
|
||||
|
||||
/*! \brief Put a byte of the current document page.
|
||||
\param s The T.4 context.
|
||||
\param byte The data byte.
|
||||
\return TRUE when the byte ends the document page, otherwise FALSE. */
|
||||
SPAN_DECLARE(int) t4_rx_put_byte(t4_state_t *s, uint8_t byte);
|
||||
SPAN_DECLARE(int) t4_rx_put_byte(t4_rx_state_t *s, uint8_t byte);
|
||||
|
||||
/*! \brief Put a byte of the current document page.
|
||||
\param s The T.4 context.
|
||||
\param buf The buffer containing the chunk.
|
||||
\param len The length of the chunk.
|
||||
\return TRUE when the byte ends the document page, otherwise FALSE. */
|
||||
SPAN_DECLARE(int) t4_rx_put_chunk(t4_state_t *s, const uint8_t buf[], int len);
|
||||
SPAN_DECLARE(int) t4_rx_put_chunk(t4_rx_state_t *s, const uint8_t buf[], int len);
|
||||
|
||||
/*! \brief Complete the reception of a page.
|
||||
\param s The T.4 receive context.
|
||||
\return 0 for success, otherwise -1. */
|
||||
SPAN_DECLARE(int) t4_rx_end_page(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_rx_end_page(t4_rx_state_t *s);
|
||||
|
||||
/*! \brief End reception of a document. Tidy up and close the file.
|
||||
This should be used to end T.4 reception started with
|
||||
t4_rx_init.
|
||||
\param s The T.4 receive context.
|
||||
\return 0 for success, otherwise -1. */
|
||||
SPAN_DECLARE(int) t4_rx_release(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_rx_release(t4_rx_state_t *s);
|
||||
|
||||
/*! \brief End reception of a document. Tidy up, close the file and
|
||||
free the context. This should be used to end T.4 reception
|
||||
started with t4_rx_init.
|
||||
\param s The T.4 receive context.
|
||||
\return 0 for success, otherwise -1. */
|
||||
SPAN_DECLARE(int) t4_rx_free(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_rx_free(t4_rx_state_t *s);
|
||||
|
||||
/*! \brief Set the row write handler for a T.4 receive context.
|
||||
\param s The T.4 receive context.
|
||||
\param handler A pointer to the handler routine.
|
||||
\param user_data An opaque pointer passed to the handler routine.
|
||||
\return 0 for success, otherwise -1. */
|
||||
SPAN_DECLARE(int) t4_rx_set_row_write_handler(t4_state_t *s, t4_row_write_handler_t handler, void *user_data);
|
||||
SPAN_DECLARE(int) t4_rx_set_row_write_handler(t4_rx_state_t *s, t4_row_write_handler_t handler, void *user_data);
|
||||
|
||||
/*! \brief Set the encoding for the received data.
|
||||
\param s The T.4 context.
|
||||
\param encoding The encoding. */
|
||||
SPAN_DECLARE(void) t4_rx_set_rx_encoding(t4_state_t *s, int encoding);
|
||||
\param encoding The encoding.
|
||||
\return 0 for success, otherwise -1. */
|
||||
SPAN_DECLARE(int) t4_rx_set_rx_encoding(t4_rx_state_t *s, int encoding);
|
||||
|
||||
/*! \brief Set the expected width of the received image, in pixel columns.
|
||||
\param s The T.4 context.
|
||||
\param width The number of pixels across the image. */
|
||||
SPAN_DECLARE(void) t4_rx_set_image_width(t4_state_t *s, int width);
|
||||
SPAN_DECLARE(void) t4_rx_set_image_width(t4_rx_state_t *s, int width);
|
||||
|
||||
/*! \brief Set the row-to-row (y) resolution to expect for a received image.
|
||||
\param s The T.4 context.
|
||||
\param resolution The resolution, in pixels per metre. */
|
||||
SPAN_DECLARE(void) t4_rx_set_y_resolution(t4_state_t *s, int resolution);
|
||||
SPAN_DECLARE(void) t4_rx_set_y_resolution(t4_rx_state_t *s, int resolution);
|
||||
|
||||
/*! \brief Set the column-to-column (x) resolution to expect for a received image.
|
||||
\param s The T.4 context.
|
||||
\param resolution The resolution, in pixels per metre. */
|
||||
SPAN_DECLARE(void) t4_rx_set_x_resolution(t4_state_t *s, int resolution);
|
||||
SPAN_DECLARE(void) t4_rx_set_x_resolution(t4_rx_state_t *s, int resolution);
|
||||
|
||||
/*! \brief Set the DCS information of the fax, for inclusion in the file.
|
||||
\param s The T.4 context.
|
||||
\param dcs The DCS information, formatted as an ASCII string. */
|
||||
SPAN_DECLARE(void) t4_rx_set_dcs(t4_state_t *s, const char *dcs);
|
||||
SPAN_DECLARE(void) t4_rx_set_dcs(t4_rx_state_t *s, const char *dcs);
|
||||
|
||||
/*! \brief Set the sub-address of the fax, for inclusion in the file.
|
||||
\param s The T.4 context.
|
||||
\param sub_address The sub-address string. */
|
||||
SPAN_DECLARE(void) t4_rx_set_sub_address(t4_state_t *s, const char *sub_address);
|
||||
SPAN_DECLARE(void) t4_rx_set_sub_address(t4_rx_state_t *s, const char *sub_address);
|
||||
|
||||
/*! \brief Set the identity of the remote machine, for inclusion in the file.
|
||||
\param s The T.4 context.
|
||||
\param ident The identity string. */
|
||||
SPAN_DECLARE(void) t4_rx_set_far_ident(t4_state_t *s, const char *ident);
|
||||
SPAN_DECLARE(void) t4_rx_set_far_ident(t4_rx_state_t *s, const char *ident);
|
||||
|
||||
/*! \brief Set the vendor of the remote machine, for inclusion in the file.
|
||||
\param s The T.4 context.
|
||||
\param vendor The vendor string, or NULL. */
|
||||
SPAN_DECLARE(void) t4_rx_set_vendor(t4_state_t *s, const char *vendor);
|
||||
SPAN_DECLARE(void) t4_rx_set_vendor(t4_rx_state_t *s, const char *vendor);
|
||||
|
||||
/*! \brief Set the model of the remote machine, for inclusion in the file.
|
||||
\param s The T.4 context.
|
||||
\param model The model string, or NULL. */
|
||||
SPAN_DECLARE(void) t4_rx_set_model(t4_state_t *s, const char *model);
|
||||
SPAN_DECLARE(void) t4_rx_set_model(t4_rx_state_t *s, const char *model);
|
||||
|
||||
/*! Get the current image transfer statistics.
|
||||
\brief Get the current transfer statistics.
|
||||
\param s The T.4 context.
|
||||
\param t A pointer to a statistics structure. */
|
||||
SPAN_DECLARE(void) t4_rx_get_transfer_statistics(t4_state_t *s, t4_stats_t *t);
|
||||
SPAN_DECLARE(void) t4_rx_get_transfer_statistics(t4_rx_state_t *s, t4_stats_t *t);
|
||||
|
||||
/*! Get the short text name of an encoding format.
|
||||
\brief Get the short text name of an encoding format.
|
||||
|
|
|
@ -45,6 +45,72 @@ typedef struct t4_t6_decode_state_s t4_t6_decode_state_t;
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \brief Put a bit of the current document page.
|
||||
\param s The T.4/T.6 context.
|
||||
\param bit The data bit.
|
||||
\return TRUE when the bit ends the document page, otherwise FALSE. */
|
||||
SPAN_DECLARE(int) t4_t6_decode_put_bit(t4_t6_decode_state_t *s, int bit);
|
||||
|
||||
/*! \brief Put a byte of the current document page.
|
||||
\param s The T.4/T.6 context.
|
||||
\param byte The data byte.
|
||||
\return TRUE when the byte ends the document page, otherwise FALSE. */
|
||||
SPAN_DECLARE(int) t4_t6_decode_put_byte(t4_t6_decode_state_t *s, int byte);
|
||||
|
||||
/*! \brief Put a byte of the current document page.
|
||||
\param s The T.4/T.6 context.
|
||||
\param buf The buffer containing the chunk.
|
||||
\param len The length of the chunk.
|
||||
\return TRUE when the byte ends the document page, otherwise FALSE. */
|
||||
SPAN_DECLARE(int) t4_t6_decode_put_chunk(t4_t6_decode_state_t *s, const uint8_t buf[], int len);
|
||||
|
||||
/*! \brief Set the row write handler for a T.4/T.6 decode context.
|
||||
\param s The T.4/T.6 context.
|
||||
\param handler A pointer to the handler routine.
|
||||
\param user_data An opaque pointer passed to the handler routine.
|
||||
\return 0 for success, otherwise -1. */
|
||||
SPAN_DECLARE(int) t4_t6_decode_set_row_write_handler(t4_t6_decode_state_t *s, t4_row_write_handler_t handler, void *user_data);
|
||||
|
||||
/*! \brief Set the encoding for the encoded data.
|
||||
\param s The T.4/T.6 context.
|
||||
\param encoding The encoding.
|
||||
\return 0 for success, otherwise -1. */
|
||||
SPAN_DECLARE(int) t4_t6_decode_set_encoding(t4_t6_decode_state_t *s, int encoding);
|
||||
|
||||
/*! \brief Get the width of the image.
|
||||
\param s The T.4/T.6 context.
|
||||
\return The width of the image, in pixels. */
|
||||
SPAN_DECLARE(uint32_t) t4_t6_decode_get_image_width(t4_t6_decode_state_t *s);
|
||||
|
||||
/*! \brief Get the length of the image.
|
||||
\param s The T.4/T.6 context.
|
||||
\return The length of the image, in pixels. */
|
||||
SPAN_DECLARE(uint32_t) t4_t6_decode_get_image_length(t4_t6_decode_state_t *s);
|
||||
|
||||
/*! \brief Get the size of the compressed image, in bits.
|
||||
\param s The T.4/T.6 context.
|
||||
\return The size of the compressed image, in bits. */
|
||||
SPAN_DECLARE(int) t4_t6_decode_get_compressed_image_size(t4_t6_decode_state_t *s);
|
||||
|
||||
SPAN_DECLARE(int) t4_t6_decode_restart(t4_t6_decode_state_t *s, int image_width);
|
||||
|
||||
/*! \brief Prepare to decode an image in T.4 or T.6 format.
|
||||
\param s The T.4/T.6 context.
|
||||
\param encoding The encoding mode.
|
||||
\param image width The image width, in pixels.
|
||||
\param handler A callback routine to handle decoded image rows.
|
||||
\param user_data An opaque pointer passed to handler.
|
||||
\return A pointer to the context, or NULL if there was a problem. */
|
||||
SPAN_DECLARE(t4_t6_decode_state_t *) t4_t6_decode_init(t4_t6_decode_state_t *s,
|
||||
int encoding,
|
||||
int image_width,
|
||||
t4_row_write_handler_t handler,
|
||||
void *user_data);
|
||||
|
||||
SPAN_DECLARE(int) t4_t6_decode_release(t4_t6_decode_state_t *s);
|
||||
|
||||
SPAN_DECLARE(int) t4_t6_decode_free(t4_t6_decode_state_t *s);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -34,6 +34,111 @@ typedef struct t4_t6_encode_state_s t4_t6_encode_state_t;
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \brief Return the next bit of the current document page, without actually
|
||||
moving forward in the buffer. The document will be padded for the
|
||||
current minimum scan line time.
|
||||
\param s The T.4/T.6 context.
|
||||
\return The next bit (i.e. 0 or 1). For the last bit of data, bit 1 is
|
||||
set (i.e. the returned value is 2 or 3). */
|
||||
SPAN_DECLARE(int) t4_t6_encode_check_bit(t4_t6_encode_state_t *s);
|
||||
|
||||
/*! \brief Get the next bit of the current image. The image will
|
||||
be padded for the current minimum scan line time.
|
||||
\param s The T.4/T.6 context.
|
||||
\return The next bit (i.e. 0 or 1). For the last bit of data, bit 1 is
|
||||
set (i.e. the returned value is 2 or 3). */
|
||||
SPAN_DECLARE(int) t4_t6_encode_get_bit(t4_t6_encode_state_t *s);
|
||||
|
||||
/*! \brief Get the next byte of the current document page. The document will
|
||||
be padded for the current minimum scan line time.
|
||||
\param s The T.4/T.6 context.
|
||||
\return The next byte. For the last byte of data, bit 8 is
|
||||
set. In this case, one or more bits of the byte may be padded with
|
||||
zeros, to complete the byte. */
|
||||
SPAN_DECLARE(int) t4_t6_encode_get_byte(t4_t6_encode_state_t *s);
|
||||
|
||||
/*! \brief Get the next chunk of the current document page. The document will
|
||||
be padded for the current minimum scan line time.
|
||||
\param s The T.4/T.6 context.
|
||||
\param buf The buffer into which the chunk is to written.
|
||||
\param max_len The maximum length of the chunk.
|
||||
\return The actual length of the chunk. If this is less than max_len it
|
||||
indicates that the end of the document has been reached. */
|
||||
SPAN_DECLARE(int) t4_t6_encode_get_chunk(t4_t6_encode_state_t *s, uint8_t buf[], int max_len);
|
||||
|
||||
/*! \brief Set the row read handler for a T.4/T.6 encode context.
|
||||
\param s The T.4/T.6 context.
|
||||
\param handler A pointer to the handler routine.
|
||||
\param user_data An opaque pointer passed to the handler routine.
|
||||
\return 0 for success, otherwise -1. */
|
||||
SPAN_DECLARE(int) t4_t6_encode_set_row_read_handler(t4_t6_encode_state_t *s,
|
||||
t4_row_read_handler_t handler,
|
||||
void *user_data);
|
||||
|
||||
/*! \brief Set the encoding for the encoded data.
|
||||
\param s The T.4/T.6 context.
|
||||
\param encoding The encoding.
|
||||
\return 0 for success, otherwise -1. */
|
||||
SPAN_DECLARE(int) t4_t6_encode_set_encoding(t4_t6_encode_state_t *s, int encoding);
|
||||
|
||||
/*! \brief Set the width of the image.
|
||||
\param s The T.4/T.6 context.
|
||||
\param image_width The image width, in pixels.
|
||||
\return 0 for success, otherwise -1. */
|
||||
SPAN_DECLARE(int) t4_t6_encode_set_image_width(t4_t6_encode_state_t *s, int image_width);
|
||||
|
||||
/*! \brief Get the width of the image.
|
||||
\param s The T.4/T.6 context.
|
||||
\return The width of the image, in pixels. */
|
||||
SPAN_DECLARE(uint32_t) t4_t6_encode_get_image_width(t4_t6_encode_state_t *s);
|
||||
|
||||
/*! \brief Get the length of the image.
|
||||
\param s The T.4/T.6 context.
|
||||
\return The length of the image, in pixels. */
|
||||
SPAN_DECLARE(uint32_t) t4_t6_encode_get_image_length(t4_t6_encode_state_t *s);
|
||||
|
||||
/*! \brief Get the size of the compressed image, in bits.
|
||||
\param s The T.4/T.6 context.
|
||||
\return The size of the compressed image, in bits. */
|
||||
SPAN_DECLARE(int) t4_t6_encode_get_compressed_image_size(t4_t6_encode_state_t *s);
|
||||
|
||||
/*! \brief Set the minimum number of encoded bits per row. This allows the
|
||||
makes the encoding process to be set to comply with the minimum row
|
||||
time specified by a remote receiving machine.
|
||||
\param s The T.4/T.6 context.
|
||||
\param bits The minimum number of bits per row. */
|
||||
SPAN_DECLARE(void) t4_t6_encode_set_min_bits_per_row(t4_t6_encode_state_t *s, int bits);
|
||||
|
||||
/*! \brief Set the maximum number of 2D encoded rows between 1D encoded rows. This
|
||||
is only valid for T.4 2D encoding.
|
||||
\param s The T.4/T.6 context.
|
||||
\param max The "K" parameter defined in the T.4 specification. This means the value is one
|
||||
greater than the maximum number of 2D rows between each 1D row. */
|
||||
SPAN_DECLARE(void) t4_t6_encode_set_max_2d_rows_per_1d_row(t4_t6_encode_state_t *s, int max);
|
||||
|
||||
/*! \brief Restart a T.4 or T.6 encode context.
|
||||
\param s The T.4/T.6 context.
|
||||
\param image width The image width, in pixels.
|
||||
\return 0 for success, otherwise -1. */
|
||||
SPAN_DECLARE(int) t4_t6_encode_restart(t4_t6_encode_state_t *s, int image_width);
|
||||
|
||||
/*! \brief Prepare to encode an image in T.4 or T.6 format.
|
||||
\param s The T.4/T.6 context.
|
||||
\param encoding The encoding mode.
|
||||
\param image width The image width, in pixels.
|
||||
\param handler A callback routine to handle decoded image rows.
|
||||
\param user_data An opaque pointer passed to handler.
|
||||
\return A pointer to the context, or NULL if there was a problem. */
|
||||
SPAN_DECLARE(t4_t6_encode_state_t *) t4_t6_encode_init(t4_t6_encode_state_t *s,
|
||||
int encoding,
|
||||
int image_width,
|
||||
t4_row_read_handler_t handler,
|
||||
void *user_data);
|
||||
|
||||
SPAN_DECLARE(int) t4_t6_encode_release(t4_t6_encode_state_t *s);
|
||||
|
||||
SPAN_DECLARE(int) t4_t6_encode_free(t4_t6_encode_state_t *s);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -28,13 +28,19 @@
|
|||
#if !defined(_SPANDSP_T4_TX_H_)
|
||||
#define _SPANDSP_T4_TX_H_
|
||||
|
||||
//#define SPANDSP_SUPPORT_TIFF_FX
|
||||
#define SPANDSP_SUPPORT_TIFF_FX
|
||||
|
||||
/*! This function is a callback from the image decoders, to read the unencoded bi-level image,
|
||||
row by row. It is called for each row, with len set to the number of bytes per row expected.
|
||||
\return len for OK, or zero to indicate the end of the image data. */
|
||||
typedef int (*t4_row_read_handler_t)(void *user_data, uint8_t buf[], size_t len);
|
||||
|
||||
/*!
|
||||
T.4 FAX compression/decompression descriptor. This defines the working state
|
||||
for a single instance of a T.4 FAX compression or decompression channel.
|
||||
*/
|
||||
typedef struct t4_tx_state_s t4_tx_state_t;
|
||||
|
||||
#if defined(SPANDSP_SUPPORT_TIFF_FX)
|
||||
/* TIFF-FX related extensions to the tag set supported by libtiff */
|
||||
|
||||
|
@ -217,17 +223,17 @@ SPAN_DECLARE(void) TIFF_FX_init(void);
|
|||
\param start_page The first page to send. -1 for no restriction.
|
||||
\param stop_page The last page to send. -1 for no restriction.
|
||||
\return A pointer to the context, or NULL if there was a problem. */
|
||||
SPAN_DECLARE(t4_state_t *) t4_tx_init(t4_state_t *s, const char *file, int start_page, int stop_page);
|
||||
SPAN_DECLARE(t4_tx_state_t *) t4_tx_init(t4_tx_state_t *s, const char *file, int start_page, int stop_page);
|
||||
|
||||
/*! \brief Prepare to send the next page of the current document.
|
||||
\param s The T.4 context.
|
||||
\return zero for success, -1 for failure. */
|
||||
SPAN_DECLARE(int) t4_tx_start_page(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_tx_start_page(t4_tx_state_t *s);
|
||||
|
||||
/*! \brief Prepare the current page for a resend.
|
||||
\param s The T.4 context.
|
||||
\return zero for success, -1 for failure. */
|
||||
SPAN_DECLARE(int) t4_tx_restart_page(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_tx_restart_page(t4_tx_state_t *s);
|
||||
|
||||
/*! \brief Check for the existance of the next page, and whether its format is like the
|
||||
current one. This information can be needed before it is determined that the current
|
||||
|
@ -236,12 +242,12 @@ SPAN_DECLARE(int) t4_tx_restart_page(t4_state_t *s);
|
|||
\return 0 for next page found with the same format as the current page.
|
||||
1 for next page found with different format from the current page.
|
||||
-1 for no page found, or file failure. */
|
||||
SPAN_DECLARE(int) t4_tx_next_page_has_different_format(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_tx_next_page_has_different_format(t4_tx_state_t *s);
|
||||
|
||||
/*! \brief Complete the sending of a page.
|
||||
\param s The T.4 context.
|
||||
\return zero for success, -1 for failure. */
|
||||
SPAN_DECLARE(int) t4_tx_end_page(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_tx_end_page(t4_tx_state_t *s);
|
||||
|
||||
/*! \brief Return the next bit of the current document page, without actually
|
||||
moving forward in the buffer. The document will be padded for the
|
||||
|
@ -249,14 +255,14 @@ SPAN_DECLARE(int) t4_tx_end_page(t4_state_t *s);
|
|||
\param s The T.4 context.
|
||||
\return The next bit (i.e. 0 or 1). For the last bit of data, bit 1 is
|
||||
set (i.e. the returned value is 2 or 3). */
|
||||
SPAN_DECLARE(int) t4_tx_check_bit(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_tx_check_bit(t4_tx_state_t *s);
|
||||
|
||||
/*! \brief Get the next bit of the current document page. The document will
|
||||
be padded for the current minimum scan line time.
|
||||
\param s The T.4 context.
|
||||
\return The next bit (i.e. 0 or 1). For the last bit of data, bit 1 is
|
||||
set (i.e. the returned value is 2 or 3). */
|
||||
SPAN_DECLARE(int) t4_tx_get_bit(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_tx_get_bit(t4_tx_state_t *s);
|
||||
|
||||
/*! \brief Get the next byte of the current document page. The document will
|
||||
be padded for the current minimum scan line time.
|
||||
|
@ -264,7 +270,7 @@ SPAN_DECLARE(int) t4_tx_get_bit(t4_state_t *s);
|
|||
\return The next byte. For the last byte of data, bit 8 is
|
||||
set. In this case, one or more bits of the byte may be padded with
|
||||
zeros, to complete the byte. */
|
||||
SPAN_DECLARE(int) t4_tx_get_byte(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_tx_get_byte(t4_tx_state_t *s);
|
||||
|
||||
/*! \brief Get the next chunk of the current document page. The document will
|
||||
be padded for the current minimum scan line time.
|
||||
|
@ -273,37 +279,49 @@ SPAN_DECLARE(int) t4_tx_get_byte(t4_state_t *s);
|
|||
\param max_len The maximum length of the chunk.
|
||||
\return The actual length of the chunk. If this is less than max_len it
|
||||
indicates that the end of the document has been reached. */
|
||||
SPAN_DECLARE(int) t4_tx_get_chunk(t4_state_t *s, uint8_t buf[], int max_len);
|
||||
SPAN_DECLARE(int) t4_tx_get_chunk(t4_tx_state_t *s, uint8_t buf[], int max_len);
|
||||
|
||||
/*! \brief End the transmission of a document. Tidy up and close the file.
|
||||
This should be used to end T.4 transmission started with t4_tx_init.
|
||||
\param s The T.4 context.
|
||||
\return 0 for success, otherwise -1. */
|
||||
SPAN_DECLARE(int) t4_tx_release(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_tx_release(t4_tx_state_t *s);
|
||||
|
||||
/*! \brief End the transmission of a document. Tidy up, close the file and
|
||||
free the context. This should be used to end T.4 transmission
|
||||
started with t4_tx_init.
|
||||
\param s The T.4 context.
|
||||
\return 0 for success, otherwise -1. */
|
||||
SPAN_DECLARE(int) t4_tx_free(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_tx_free(t4_tx_state_t *s);
|
||||
|
||||
/*! \brief Set the encoding for the encoded data.
|
||||
\param s The T.4 context.
|
||||
\param encoding The encoding. */
|
||||
SPAN_DECLARE(void) t4_tx_set_tx_encoding(t4_state_t *s, int encoding);
|
||||
\param encoding The encoding.
|
||||
\return 0 for success, otherwise -1. */
|
||||
SPAN_DECLARE(int) t4_tx_set_tx_encoding(t4_tx_state_t *s, int encoding);
|
||||
|
||||
/*! \brief Set the minimum number of encoded bits per row. This allows the
|
||||
makes the encoding process to be set to comply with the minimum row
|
||||
time specified by a remote receiving machine.
|
||||
\param s The T.4 context.
|
||||
\param bits The minimum number of bits per row. */
|
||||
SPAN_DECLARE(void) t4_tx_set_min_bits_per_row(t4_state_t *s, int bits);
|
||||
SPAN_DECLARE(void) t4_tx_set_min_bits_per_row(t4_tx_state_t *s, int bits);
|
||||
|
||||
/*! \brief Set the width of the image.
|
||||
\param s The T.4 context.
|
||||
\param image_width The image width, in pixels. */
|
||||
SPAN_DECLARE(void) t4_tx_set_image_width(t4_tx_state_t *s, int image_width);
|
||||
|
||||
/*! \brief Set the maximum number of 2D encoded rows between 1D encoded rows. This
|
||||
is only valid for T.4 2D encoding.
|
||||
\param s The T.4 context.
|
||||
\param max The maximum number of 2D rows. */
|
||||
SPAN_DECLARE(void) t4_tx_set_max_2d_rows_per_1d_row(t4_tx_state_t *s, int max);
|
||||
|
||||
/*! \brief Set the identity of the local machine, for inclusion in page headers.
|
||||
\param s The T.4 context.
|
||||
\param ident The identity string. */
|
||||
SPAN_DECLARE(void) t4_tx_set_local_ident(t4_state_t *s, const char *ident);
|
||||
SPAN_DECLARE(void) t4_tx_set_local_ident(t4_tx_state_t *s, const char *ident);
|
||||
|
||||
/*! Set the info field, included in the header line included in each page of an encoded
|
||||
FAX. This is a string of up to 50 characters. Other information (date, local ident, etc.)
|
||||
|
@ -312,58 +330,58 @@ SPAN_DECLARE(void) t4_tx_set_local_ident(t4_state_t *s, const char *ident);
|
|||
\brief Set the header info.
|
||||
\param s The T.4 context.
|
||||
\param info A string, of up to 50 bytes, which will form the info field. */
|
||||
SPAN_DECLARE(void) t4_tx_set_header_info(t4_state_t *s, const char *info);
|
||||
SPAN_DECLARE(void) t4_tx_set_header_info(t4_tx_state_t *s, const char *info);
|
||||
|
||||
/*! Set the time zone for the time stamp in page header lines. If this function is not used
|
||||
the current time zone of the program's environment is used.
|
||||
\brief Set the header timezone.
|
||||
\param s The T.4 context.
|
||||
\param tz A time zone descriptor. */
|
||||
SPAN_DECLARE(void) t4_tx_set_header_tz(t4_state_t *s, tz_t *tz);
|
||||
SPAN_DECLARE(void) t4_tx_set_header_tz(t4_tx_state_t *s, tz_t *tz);
|
||||
|
||||
/*! Set page header extends or overlays the image mode.
|
||||
\brief Set page header overlay mode.
|
||||
\param s The T.4 context.
|
||||
\param header_overlays_image TRUE for overlay, or FALSE for extend the page. */
|
||||
SPAN_DECLARE(void) t4_tx_set_header_overlays_image(t4_state_t *s, int header_overlays_image);
|
||||
SPAN_DECLARE(void) t4_tx_set_header_overlays_image(t4_tx_state_t *s, int header_overlays_image);
|
||||
|
||||
/*! \brief Set the row read handler for a T.4 transmit context.
|
||||
\param s The T.4 transmit context.
|
||||
\param handler A pointer to the handler routine.
|
||||
\param user_data An opaque pointer passed to the handler routine.
|
||||
\return 0 for success, otherwise -1. */
|
||||
SPAN_DECLARE(int) t4_tx_set_row_read_handler(t4_state_t *s, t4_row_read_handler_t handler, void *user_data);
|
||||
SPAN_DECLARE(int) t4_tx_set_row_read_handler(t4_tx_state_t *s, t4_row_read_handler_t handler, void *user_data);
|
||||
|
||||
/*! \brief Get the row-to-row (y) resolution of the current page.
|
||||
\param s The T.4 context.
|
||||
\return The resolution, in pixels per metre. */
|
||||
SPAN_DECLARE(int) t4_tx_get_y_resolution(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_tx_get_y_resolution(t4_tx_state_t *s);
|
||||
|
||||
/*! \brief Get the column-to-column (x) resolution of the current page.
|
||||
\param s The T.4 context.
|
||||
\return The resolution, in pixels per metre. */
|
||||
SPAN_DECLARE(int) t4_tx_get_x_resolution(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_tx_get_x_resolution(t4_tx_state_t *s);
|
||||
|
||||
/*! \brief Get the width of the current page, in pixel columns.
|
||||
\param s The T.4 context.
|
||||
\return The number of columns. */
|
||||
SPAN_DECLARE(int) t4_tx_get_image_width(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_tx_get_image_width(t4_tx_state_t *s);
|
||||
|
||||
/*! \brief Get the number of pages in the file.
|
||||
\param s The T.4 context.
|
||||
\return The number of pages, or -1 if there is an error. */
|
||||
SPAN_DECLARE(int) t4_tx_get_pages_in_file(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_tx_get_pages_in_file(t4_tx_state_t *s);
|
||||
|
||||
/*! \brief Get the currnet page number in the file.
|
||||
\param s The T.4 context.
|
||||
\return The page number, or -1 if there is an error. */
|
||||
SPAN_DECLARE(int) t4_tx_get_current_page_in_file(t4_state_t *s);
|
||||
SPAN_DECLARE(int) t4_tx_get_current_page_in_file(t4_tx_state_t *s);
|
||||
|
||||
/*! Get the current image transfer statistics.
|
||||
\brief Get the current transfer statistics.
|
||||
\param s The T.4 context.
|
||||
\param t A pointer to a statistics structure. */
|
||||
SPAN_DECLARE(void) t4_tx_get_transfer_statistics(t4_state_t *s, t4_stats_t *t);
|
||||
SPAN_DECLARE(void) t4_tx_get_transfer_statistics(t4_tx_state_t *s, t4_stats_t *t);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
|
|
@ -39,24 +39,59 @@ typedef struct v18_state_s v18_state_t;
|
|||
enum
|
||||
{
|
||||
V18_MODE_NONE = 0,
|
||||
/* V.18 Annex A - Weitbrecht TDD at 45.45bps, half-duplex, 5 bit baudot. */
|
||||
/* V.18 Annex A - Weitbrecht TDD at 45.45bps (US TTY), half-duplex, 5 bit baudot (USA). */
|
||||
V18_MODE_5BIT_45 = 1,
|
||||
/* V.18 Annex A - Weitbrecht TDD at 50bps, half-duplex, 5 bit baudot. */
|
||||
/* V.18 Annex A - Weitbrecht TDD at 50bps (International TTY), half-duplex, 5 bit baudot (UK, Australia and others). */
|
||||
V18_MODE_5BIT_50 = 2,
|
||||
/* V.18 Annex B - DTMF encoding of ASCII. */
|
||||
/* V.18 Annex B - DTMF encoding of ASCII (Denmark, Holland and others). */
|
||||
V18_MODE_DTMF = 3,
|
||||
/* V.18 Annex C - EDT 110bps, V.21, half-duplex, ASCII. */
|
||||
/* V.18 Annex C - EDT (European Deaf Telephone) 110bps, V.21, half-duplex, ASCII (Germany, Austria, Switzerland and others). */
|
||||
V18_MODE_EDT = 4,
|
||||
/* V.18 Annex D - 300bps, Bell 103, duplex, ASCII. */
|
||||
/* V.18 Annex D - 300bps, Bell 103, duplex, ASCII (USA). */
|
||||
V18_MODE_BELL103 = 5,
|
||||
/* V.18 Annex E - 1200bps Videotex terminals, ASCII. */
|
||||
/* V.18 Annex E - 1200bps Videotex terminals, ASCII (France). */
|
||||
V18_MODE_V23VIDEOTEX = 6,
|
||||
/* V.18 Annex F - V.21 text telephone, V.21, duplex, ASCII. */
|
||||
/* V.18 Annex F - V.21 text telephone, V.21, duplex, ASCII (Sweden, Norway and Finland). */
|
||||
V18_MODE_V21TEXTPHONE = 7,
|
||||
/* V.18 Annex G - V.18 text telephone mode. */
|
||||
V18_MODE_V18TEXTPHONE = 8
|
||||
};
|
||||
|
||||
/* Automoding sequences for different countries */
|
||||
enum
|
||||
{
|
||||
/* 5-bit, V.21, V.23, EDT, DTMF, Bell 103 */
|
||||
V18_AUTOMODING_AUSTRALIA,
|
||||
V18_AUTOMODING_IRELAND,
|
||||
|
||||
/* EDT, V.21, V.23, 5-bit, DTMF, Bell 103 */
|
||||
V18_AUTOMODING_GERMANY,
|
||||
V18_AUTOMODING_SWITZERLAND,
|
||||
V18_AUTOMODING_ITALY,
|
||||
V18_AUTOMODING_SPAIN,
|
||||
V18_AUTOMODING_AUSTRIA,
|
||||
|
||||
/* DTMF, V.21, V.23, 5-bit, EDT, Bell 103 */
|
||||
V18_AUTOMODING_NETHERLANDS,
|
||||
|
||||
/* V.21, DTMF, 5-bit, EDT, V.23, Bell 103 */
|
||||
V18_AUTOMODING_ICELAND,
|
||||
V18_AUTOMODING_NORWAY,
|
||||
V18_AUTOMODING_SWEDEN,
|
||||
V18_AUTOMODING_FINALND,
|
||||
V18_AUTOMODING_DENMARK,
|
||||
|
||||
/* V.21, 5-bit, V.23, EDT, DTMF, Bell 103 */
|
||||
V18_AUTOMODING_UK,
|
||||
|
||||
/* 5-bit, Bell 103, V.21, V.23, EDT, DTMF */
|
||||
V18_AUTOMODING_USA,
|
||||
|
||||
/* V.23, EDT, DTMF, 5-bit, V.21, Bell 103 */
|
||||
V18_AUTOMODING_FRANCE,
|
||||
V18_AUTOMODING_BELGIUM
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
|
|
|
@ -61,12 +61,8 @@
|
|||
#include "spandsp/timezone.h"
|
||||
#include "spandsp/t4_rx.h"
|
||||
#include "spandsp/t4_tx.h"
|
||||
#if defined(SPANDSP_SUPPORT_T42) || defined(SPANDSP_SUPPORT_T43) || defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/t81_t82_arith_coding.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/t85.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
#include "spandsp/t42.h"
|
||||
#endif
|
||||
|
@ -83,12 +79,8 @@
|
|||
|
||||
#include "spandsp/private/logging.h"
|
||||
#include "spandsp/private/timezone.h"
|
||||
#if defined(SPANDSP_SUPPORT_T42) || defined(SPANDSP_SUPPORT_T43) || defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/private/t81_t82_arith_coding.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/private/t85.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
#include "spandsp/private/t42.h"
|
||||
#endif
|
||||
|
@ -398,8 +390,9 @@ static const struct
|
|||
static void queue_phase(t30_state_t *s, int phase);
|
||||
static void set_phase(t30_state_t *s, int phase);
|
||||
static void set_state(t30_state_t *s, int state);
|
||||
static void send_simple_frame(t30_state_t *s, int type);
|
||||
static void shut_down_hdlc_tx(t30_state_t *s);
|
||||
static void send_frame(t30_state_t *s, const uint8_t *fr, int frlen);
|
||||
static void send_simple_frame(t30_state_t *s, int type);
|
||||
static void send_dcn(t30_state_t *s);
|
||||
static void repeat_last_command(t30_state_t *s);
|
||||
static void disconnect(t30_state_t *s);
|
||||
|
@ -834,6 +827,13 @@ static void print_frame(t30_state_t *s, const char *io, const uint8_t *msg, int
|
|||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void shut_down_hdlc_tx(t30_state_t *s)
|
||||
{
|
||||
if (s->send_hdlc_handler)
|
||||
s->send_hdlc_handler(s->send_hdlc_user_data, NULL, 0);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void send_frame(t30_state_t *s, const uint8_t *msg, int len)
|
||||
{
|
||||
print_frame(s, "Tx: ", msg, len);
|
||||
|
@ -1344,7 +1344,6 @@ static int build_dcs(t30_state_t *s)
|
|||
set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21);
|
||||
break;
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
case T4_COMPRESSION_ITU_T85:
|
||||
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T85_MODE);
|
||||
clr_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T85_L0_MODE);
|
||||
|
@ -1355,7 +1354,6 @@ static int build_dcs(t30_state_t *s)
|
|||
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T85_L0_MODE);
|
||||
set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21);
|
||||
break;
|
||||
#endif
|
||||
case T4_COMPRESSION_ITU_T6:
|
||||
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T6_MODE);
|
||||
set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21);
|
||||
|
@ -1750,9 +1748,7 @@ static int send_dis_or_dtc_sequence(t30_state_t *s, int start)
|
|||
break;
|
||||
case 3:
|
||||
s->step++;
|
||||
/* Shut down HDLC transmission. */
|
||||
if (s->send_hdlc_handler)
|
||||
s->send_hdlc_handler(s->send_hdlc_user_data, NULL, 0);
|
||||
shut_down_hdlc_tx(s);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
|
@ -1805,9 +1801,7 @@ static int send_dis_or_dtc_sequence(t30_state_t *s, int start)
|
|||
break;
|
||||
case 8:
|
||||
s->step++;
|
||||
/* Shut down HDLC transmission. */
|
||||
if (s->send_hdlc_handler)
|
||||
s->send_hdlc_handler(s->send_hdlc_user_data, NULL, 0);
|
||||
shut_down_hdlc_tx(s);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
|
@ -1866,9 +1860,7 @@ static int send_dcs_sequence(t30_state_t *s, int start)
|
|||
break;
|
||||
case 7:
|
||||
s->step++;
|
||||
/* Shut down HDLC transmission. */
|
||||
if (s->send_hdlc_handler)
|
||||
s->send_hdlc_handler(s->send_hdlc_user_data, NULL, 0);
|
||||
shut_down_hdlc_tx(s);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
|
@ -2683,10 +2675,14 @@ static void process_rx_ppr(t30_state_t *s, const uint8_t *msg, int len)
|
|||
int frame_no;
|
||||
uint8_t frame[4];
|
||||
|
||||
if (len != 3 + 32)
|
||||
if (len != 3 + 256/8)
|
||||
{
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for PPR bits - %d\n", len);
|
||||
/* TODO: probably should send DCN */
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for PPR bits - %d\n", (len - 3)*8);
|
||||
/* This frame didn't get corrupted in transit, because its CRC is OK. It was sent bad
|
||||
and there is little possibility that causing a retransmission will help. It is best
|
||||
to just give up. */
|
||||
t30_set_status(s, T30_ERR_TX_ECMPHD);
|
||||
disconnect(s);
|
||||
return;
|
||||
}
|
||||
/* Check which frames are OK, and mark them as OK. */
|
||||
|
@ -5866,9 +5862,7 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status)
|
|||
case T30_STATE_F_CFR:
|
||||
if (s->step == 0)
|
||||
{
|
||||
/* Shut down HDLC transmission. */
|
||||
if (s->send_hdlc_handler)
|
||||
s->send_hdlc_handler(s->send_hdlc_user_data, NULL, 0);
|
||||
shut_down_hdlc_tx(s);
|
||||
s->step++;
|
||||
}
|
||||
else
|
||||
|
@ -5890,9 +5884,7 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status)
|
|||
case T30_STATE_F_FTT:
|
||||
if (s->step == 0)
|
||||
{
|
||||
/* Shut down HDLC transmission. */
|
||||
if (s->send_hdlc_handler)
|
||||
s->send_hdlc_handler(s->send_hdlc_user_data, NULL, 0);
|
||||
shut_down_hdlc_tx(s);
|
||||
s->step++;
|
||||
}
|
||||
else
|
||||
|
@ -5908,9 +5900,7 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status)
|
|||
case T30_STATE_F_POST_RCP_MCF:
|
||||
if (s->step == 0)
|
||||
{
|
||||
/* Shut down HDLC transmission. */
|
||||
if (s->send_hdlc_handler)
|
||||
s->send_hdlc_handler(s->send_hdlc_user_data, NULL, 0);
|
||||
shut_down_hdlc_tx(s);
|
||||
s->step++;
|
||||
}
|
||||
else
|
||||
|
@ -5962,9 +5952,7 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status)
|
|||
case T30_STATE_IV_CTC:
|
||||
if (s->step == 0)
|
||||
{
|
||||
/* Shut down HDLC transmission. */
|
||||
if (s->send_hdlc_handler)
|
||||
s->send_hdlc_handler(s->send_hdlc_user_data, NULL, 0);
|
||||
shut_down_hdlc_tx(s);
|
||||
s->step++;
|
||||
}
|
||||
else
|
||||
|
@ -5987,9 +5975,7 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status)
|
|||
case T30_STATE_C:
|
||||
if (s->step == 0)
|
||||
{
|
||||
/* Shut down HDLC transmission. */
|
||||
if (s->send_hdlc_handler)
|
||||
s->send_hdlc_handler(s->send_hdlc_user_data, NULL, 0);
|
||||
shut_down_hdlc_tx(s);
|
||||
s->step++;
|
||||
}
|
||||
else
|
||||
|
@ -6047,9 +6033,7 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status)
|
|||
{
|
||||
if (send_next_ecm_frame(s))
|
||||
{
|
||||
/* Shut down HDLC transmission. */
|
||||
if (s->send_hdlc_handler)
|
||||
s->send_hdlc_handler(s->send_hdlc_user_data, NULL, 0);
|
||||
shut_down_hdlc_tx(s);
|
||||
s->step++;
|
||||
}
|
||||
}
|
||||
|
@ -6068,9 +6052,7 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status)
|
|||
/* This should be the end of a CTR being sent. */
|
||||
if (s->step == 0)
|
||||
{
|
||||
/* Shut down HDLC transmission. */
|
||||
if (s->send_hdlc_handler)
|
||||
s->send_hdlc_handler(s->send_hdlc_user_data, NULL, 0);
|
||||
shut_down_hdlc_tx(s);
|
||||
s->step++;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -61,12 +61,8 @@
|
|||
#include "spandsp/timezone.h"
|
||||
#include "spandsp/t4_rx.h"
|
||||
#include "spandsp/t4_tx.h"
|
||||
#if defined(SPANDSP_SUPPORT_T42) || defined(SPANDSP_SUPPORT_T43) || defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/t81_t82_arith_coding.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/t85.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
#include "spandsp/t42.h"
|
||||
#endif
|
||||
|
@ -83,12 +79,8 @@
|
|||
|
||||
#include "spandsp/private/logging.h"
|
||||
#include "spandsp/private/timezone.h"
|
||||
#if defined(SPANDSP_SUPPORT_T42) || defined(SPANDSP_SUPPORT_T43) || defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/private/t81_t82_arith_coding.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/private/t85.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
#include "spandsp/private/t42.h"
|
||||
#endif
|
||||
|
@ -713,10 +705,8 @@ SPAN_DECLARE(int) t30_set_supported_compressions(t30_state_t *s, int supported_c
|
|||
#if defined(SPANDSP_SUPPORT_T43)
|
||||
| T30_SUPPORT_T43_COMPRESSION
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
| T30_SUPPORT_T85_COMPRESSION
|
||||
| T30_SUPPORT_T85_L0_COMPRESSION
|
||||
#endif
|
||||
| 0;
|
||||
s->supported_compressions = supported_compressions & mask;
|
||||
t30_build_dis_or_dtc(s);
|
||||
|
|
|
@ -61,12 +61,8 @@
|
|||
#include "spandsp/timezone.h"
|
||||
#include "spandsp/t4_rx.h"
|
||||
#include "spandsp/t4_tx.h"
|
||||
#if defined(SPANDSP_SUPPORT_T42) || defined(SPANDSP_SUPPORT_T43) || defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/t81_t82_arith_coding.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/t85.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
#include "spandsp/t42.h"
|
||||
#endif
|
||||
|
@ -82,12 +78,8 @@
|
|||
|
||||
#include "spandsp/private/logging.h"
|
||||
#include "spandsp/private/timezone.h"
|
||||
#if defined(SPANDSP_SUPPORT_T42) || defined(SPANDSP_SUPPORT_T43) || defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/private/t81_t82_arith_coding.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/private/t85.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
#include "spandsp/private/t42.h"
|
||||
#endif
|
||||
|
|
|
@ -74,12 +74,8 @@
|
|||
#include "spandsp/timezone.h"
|
||||
#include "spandsp/t4_rx.h"
|
||||
#include "spandsp/t4_tx.h"
|
||||
#if defined(SPANDSP_SUPPORT_T42) || defined(SPANDSP_SUPPORT_T43) || defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/t81_t82_arith_coding.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/t85.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
#include "spandsp/t42.h"
|
||||
#endif
|
||||
|
@ -110,12 +106,8 @@
|
|||
#include "spandsp/private/hdlc.h"
|
||||
#include "spandsp/private/fax_modems.h"
|
||||
#include "spandsp/private/timezone.h"
|
||||
#if defined(SPANDSP_SUPPORT_T42) || defined(SPANDSP_SUPPORT_T43) || defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/private/t81_t82_arith_coding.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/private/t85.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
#include "spandsp/private/t42.h"
|
||||
#endif
|
||||
|
|
|
@ -64,12 +64,8 @@
|
|||
#include "spandsp/timezone.h"
|
||||
#include "spandsp/t4_rx.h"
|
||||
#include "spandsp/t4_tx.h"
|
||||
#if defined(SPANDSP_SUPPORT_T42) || defined(SPANDSP_SUPPORT_T43) || defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/t81_t82_arith_coding.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/t85.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
#include "spandsp/t42.h"
|
||||
#endif
|
||||
|
@ -88,12 +84,8 @@
|
|||
|
||||
#include "spandsp/private/logging.h"
|
||||
#include "spandsp/private/timezone.h"
|
||||
#if defined(SPANDSP_SUPPORT_T42) || defined(SPANDSP_SUPPORT_T43) || defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/private/t81_t82_arith_coding.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/private/t85.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
#include "spandsp/private/t42.h"
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,929 @@
|
|||
//#define T4_STATE_DEBUGGING
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* t4_t6_encode.c - ITU T.4 and T.6 FAX image decompression
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2003, 2007 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file has origins in the T.4 and T.6 support in libtiff, which requires
|
||||
* the following notice in any derived source code:
|
||||
*
|
||||
* Copyright (c) 1990-1997 Sam Leffler
|
||||
* Copyright (c) 1991-1997 Silicon Graphics, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that (i) the above copyright notices and this permission notice appear in
|
||||
* all copies of the software and related documentation, and (ii) the names of
|
||||
* Sam Leffler and Silicon Graphics may not be used in any advertising or
|
||||
* publicity relating to the software without the specific, prior written
|
||||
* permission of Sam Leffler and Silicon Graphics.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
||||
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
|
||||
* ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
|
||||
* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
* WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
|
||||
* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*
|
||||
* Decoder support is derived from code in Frank Cringle's viewfax program;
|
||||
* Copyright (C) 1990, 1995 Frank D. Cringle.
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#if defined(HAVE_MATH_H)
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include "floating_fudge.h"
|
||||
#include <tiffio.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/logging.h"
|
||||
#include "spandsp/bit_operations.h"
|
||||
#include "spandsp/async.h"
|
||||
#include "spandsp/timezone.h"
|
||||
#include "spandsp/t4_rx.h"
|
||||
#include "spandsp/t4_tx.h"
|
||||
#include "spandsp/t81_t82_arith_coding.h"
|
||||
#include "spandsp/t85.h"
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
#include "spandsp/t42.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T43)
|
||||
#include "spandsp/t43.h"
|
||||
#endif
|
||||
#include "spandsp/t4_t6_decode.h"
|
||||
#include "spandsp/t4_t6_encode.h"
|
||||
|
||||
#include "spandsp/private/logging.h"
|
||||
#include "spandsp/private/t81_t82_arith_coding.h"
|
||||
#include "spandsp/private/t85.h"
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
#include "spandsp/private/t42.h"
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T43)
|
||||
#include "spandsp/private/t43.h"
|
||||
#endif
|
||||
#include "spandsp/private/t4_t6_decode.h"
|
||||
#include "spandsp/private/t4_t6_encode.h"
|
||||
#include "spandsp/private/t4_rx.h"
|
||||
#include "spandsp/private/t4_tx.h"
|
||||
|
||||
/*! The number of centimetres in one inch */
|
||||
#define CM_PER_INCH 2.54f
|
||||
|
||||
/*! The number of EOLs to expect at the end of a T.4 page */
|
||||
#define EOLS_TO_END_ANY_RX_PAGE 6
|
||||
/*! The number of EOLs to check at the end of a T.4 page */
|
||||
#define EOLS_TO_END_T4_RX_PAGE 5
|
||||
/*! The number of EOLs to check at the end of a T.6 page */
|
||||
#define EOLS_TO_END_T6_RX_PAGE 2
|
||||
|
||||
#include "t4_t6_decode_states.h"
|
||||
|
||||
#if defined(T4_STATE_DEBUGGING)
|
||||
static void STATE_TRACE(const char *format, ...)
|
||||
{
|
||||
va_list arg_ptr;
|
||||
|
||||
va_start(arg_ptr, format);
|
||||
vprintf(format, arg_ptr);
|
||||
va_end(arg_ptr);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
#else
|
||||
#define STATE_TRACE(...) /**/
|
||||
#endif
|
||||
|
||||
static int free_buffers(t4_t6_decode_state_t *s)
|
||||
{
|
||||
if (s->cur_runs)
|
||||
{
|
||||
free(s->cur_runs);
|
||||
s->cur_runs = NULL;
|
||||
}
|
||||
if (s->ref_runs)
|
||||
{
|
||||
free(s->ref_runs);
|
||||
s->ref_runs = NULL;
|
||||
}
|
||||
if (s->row_buf)
|
||||
{
|
||||
free(s->row_buf);
|
||||
s->row_buf = NULL;
|
||||
}
|
||||
s->bytes_per_row = 0;
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__powerpc__)
|
||||
static __inline__ int run_length(unsigned int bits)
|
||||
{
|
||||
return 7 - top_bit(bits);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
#else
|
||||
static __inline__ int run_length(unsigned int bits)
|
||||
{
|
||||
static const uint8_t run_len[256] =
|
||||
{
|
||||
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x00 - 0x0F */
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 - 0x1F */
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x20 - 0x2F */
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x30 - 0x3F */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4F */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x5F */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6F */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x7F */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9F */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xAF */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 - 0xBF */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC0 - 0xCF */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0 - 0xDF */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0 - 0xEF */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xF0 - 0xFF */
|
||||
};
|
||||
|
||||
return run_len[bits];
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
#endif
|
||||
|
||||
static __inline__ void add_run_to_row(t4_t6_decode_state_t *s)
|
||||
{
|
||||
if (s->run_length >= 0)
|
||||
{
|
||||
s->row_len += s->run_length;
|
||||
/* Don't allow rows to grow too long, and overflow the buffers */
|
||||
if (s->row_len <= s->image_width)
|
||||
s->cur_runs[s->a_cursor++] = s->run_length;
|
||||
}
|
||||
s->run_length = 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static __inline__ void update_row_bit_info(t4_t6_decode_state_t *s)
|
||||
{
|
||||
if (s->row_bits > s->max_row_bits)
|
||||
s->max_row_bits = s->row_bits;
|
||||
if (s->row_bits < s->min_row_bits)
|
||||
s->min_row_bits = s->row_bits;
|
||||
s->row_bits = 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int put_decoded_row(t4_t6_decode_state_t *s)
|
||||
{
|
||||
static const int msbmask[9] =
|
||||
{
|
||||
0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
|
||||
};
|
||||
uint32_t i;
|
||||
uint32_t *p;
|
||||
int fudge;
|
||||
int x;
|
||||
int j;
|
||||
int row_pos;
|
||||
|
||||
if (s->run_length)
|
||||
add_run_to_row(s);
|
||||
update_row_bit_info(s);
|
||||
#if defined(T4_STATE_DEBUGGING)
|
||||
/* Dump the runs of black and white for analysis */
|
||||
{
|
||||
int total;
|
||||
|
||||
total = 0;
|
||||
for (x = 0; x < s->b_cursor; x++)
|
||||
total += s->ref_runs[x];
|
||||
printf("Ref (%d)", total);
|
||||
for (x = 0; x < s->b_cursor; x++)
|
||||
printf(" %" PRIu32, s->ref_runs[x]);
|
||||
printf("\n");
|
||||
total = 0;
|
||||
for (x = 0; x < s->a_cursor; x++)
|
||||
total += s->cur_runs[x];
|
||||
printf("Cur (%d)", total);
|
||||
for (x = 0; x < s->a_cursor; x++)
|
||||
printf(" %" PRIu32, s->cur_runs[x]);
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
row_pos = 0;
|
||||
if (s->row_len == s->image_width)
|
||||
{
|
||||
STATE_TRACE("%d Good row - %d %s\n", s->image_length, s->row_len, (s->row_is_2d) ? "2D" : "1D");
|
||||
if (s->curr_bad_row_run)
|
||||
{
|
||||
if (s->curr_bad_row_run > s->longest_bad_row_run)
|
||||
s->longest_bad_row_run = s->curr_bad_row_run;
|
||||
s->curr_bad_row_run = 0;
|
||||
}
|
||||
/* Convert the runs to a bit image of the row */
|
||||
/* White/black/white... runs, always starting with white. That means the first run could be
|
||||
zero length. */
|
||||
for (x = 0, fudge = 0; x < s->a_cursor; x++, fudge ^= 0xFF)
|
||||
{
|
||||
i = s->cur_runs[x];
|
||||
if ((int) i >= s->pixels)
|
||||
{
|
||||
s->pixel_stream = (s->pixel_stream << s->pixels) | (msbmask[s->pixels] & fudge);
|
||||
for (i += (8 - s->pixels); i >= 8; i -= 8)
|
||||
{
|
||||
s->pixels = 8;
|
||||
s->row_buf[row_pos++] = (uint8_t) s->pixel_stream;
|
||||
s->pixel_stream = fudge;
|
||||
}
|
||||
}
|
||||
s->pixel_stream = (s->pixel_stream << i) | (msbmask[i] & fudge);
|
||||
s->pixels -= i;
|
||||
}
|
||||
s->image_length++;
|
||||
}
|
||||
else
|
||||
{
|
||||
STATE_TRACE("%d Bad row - %d %s\n", s->image_length, s->row_len, (s->row_is_2d) ? "2D" : "1D");
|
||||
/* Try to clean up the bad runs, and produce something reasonable as the reference
|
||||
row for the next row. Use a copy of the previous good row as the actual current
|
||||
row. If the row only fell apart near the end, reusing it might be the best
|
||||
solution. */
|
||||
for (j = 0, fudge = 0; j < s->a_cursor && fudge < s->image_width; j++)
|
||||
fudge += s->cur_runs[j];
|
||||
if (fudge < s->image_width)
|
||||
{
|
||||
/* Try to pad with white, and avoid black, to minimise mess on the image. */
|
||||
if ((s->a_cursor & 1))
|
||||
{
|
||||
/* We currently finish in white. We could extend that, but it is probably of
|
||||
the right length. Changing it would only further mess up what happens in the
|
||||
next row. It seems better to add a black spot, and an extra white run. */
|
||||
s->cur_runs[s->a_cursor++] = 1;
|
||||
fudge++;
|
||||
if (fudge < s->image_width)
|
||||
s->cur_runs[s->a_cursor++] = s->image_width - fudge;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We currently finish on black, so we add an extra white run to fill out the line. */
|
||||
s->cur_runs[s->a_cursor++] = s->image_width - fudge;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Trim the last element to align with the proper image width */
|
||||
s->cur_runs[s->a_cursor] += (s->image_width - fudge);
|
||||
}
|
||||
/* Ensure there is a previous line to copy from. */
|
||||
/* Reuse the previous row as the current one. If this is the first row
|
||||
the row buffer will already contain a suitable white row */
|
||||
s->image_length++;
|
||||
s->bad_rows++;
|
||||
s->curr_bad_row_run++;
|
||||
}
|
||||
|
||||
/* Pad the row as it becomes the reference row, so there are no odd runs to pick up if we
|
||||
step off the end of the list. */
|
||||
s->cur_runs[s->a_cursor] = 0;
|
||||
s->cur_runs[s->a_cursor + 1] = 0;
|
||||
|
||||
/* Swap the buffers */
|
||||
p = s->cur_runs;
|
||||
s->cur_runs = s->ref_runs;
|
||||
s->ref_runs = p;
|
||||
|
||||
s->b_cursor = 1;
|
||||
s->a_cursor = 0;
|
||||
s->b1 = s->ref_runs[0];
|
||||
s->a0 = 0;
|
||||
|
||||
s->run_length = 0;
|
||||
if (s->row_write_handler)
|
||||
return s->row_write_handler(s->row_write_user_data, s->row_buf, s->bytes_per_row);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static __inline__ void drop_rx_bits(t4_t6_decode_state_t *s, int bits)
|
||||
{
|
||||
/* Only remove one bit right now. The rest need to be removed step by step,
|
||||
checking for a misaligned EOL along the way. This is time consuming, but
|
||||
if we don't do it a single bit error can severely damage an image. */
|
||||
s->row_bits += bits;
|
||||
s->rx_skip_bits += (bits - 1);
|
||||
s->rx_bits--;
|
||||
s->rx_bitstream >>= 1;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static __inline__ void force_drop_rx_bits(t4_t6_decode_state_t *s, int bits)
|
||||
{
|
||||
/* This should only be called to drop the bits of an EOL, as that is the
|
||||
only place where it is safe to drop them all at once. */
|
||||
s->row_bits += bits;
|
||||
s->rx_skip_bits = 0;
|
||||
s->rx_bits -= bits;
|
||||
s->rx_bitstream >>= bits;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int put_bits(t4_t6_decode_state_t *s, uint32_t bit_string, int quantity)
|
||||
{
|
||||
int bits;
|
||||
int old_a0;
|
||||
|
||||
/* We decompress bit by bit, as the data stream is received. We need to
|
||||
scan continuously for EOLs, so we might as well work this way. */
|
||||
s->rx_bitstream |= (bit_string << s->rx_bits);
|
||||
/* The longest item we need to scan for is 13 bits long (a 2D EOL), so we
|
||||
need a minimum of 13 bits in the buffer to proceed with any bit stream
|
||||
analysis. */
|
||||
if ((s->rx_bits += quantity) < 13)
|
||||
return FALSE;
|
||||
if (s->consecutive_eols)
|
||||
{
|
||||
/* Check if the image has already terminated. */
|
||||
if (s->consecutive_eols >= EOLS_TO_END_ANY_RX_PAGE)
|
||||
return TRUE;
|
||||
/* Check if the image hasn't even started. */
|
||||
if (s->consecutive_eols < 0)
|
||||
{
|
||||
/* We are waiting for the very first EOL (1D or 2D only). */
|
||||
/* We need to take this bit by bit, as the EOL could be anywhere,
|
||||
and any junk could preceed it. */
|
||||
while ((s->rx_bitstream & 0xFFF) != 0x800)
|
||||
{
|
||||
s->rx_bitstream >>= 1;
|
||||
if (--s->rx_bits < 13)
|
||||
return FALSE;
|
||||
}
|
||||
/* We have an EOL, so now the page begins and we can proceed to
|
||||
process the bit stream as image data. */
|
||||
s->consecutive_eols = 0;
|
||||
if (s->encoding == T4_COMPRESSION_ITU_T4_1D)
|
||||
{
|
||||
s->row_is_2d = FALSE;
|
||||
force_drop_rx_bits(s, 12);
|
||||
}
|
||||
else
|
||||
{
|
||||
s->row_is_2d = !(s->rx_bitstream & 0x1000);
|
||||
force_drop_rx_bits(s, 13);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (s->rx_bits >= 13)
|
||||
{
|
||||
/* We need to check for EOLs bit by bit through the whole stream. If
|
||||
we just try looking between code words, we will miss an EOL when a bit
|
||||
error has throw the code words completely out of step. The can mean
|
||||
recovery takes many lines, and the image gets really messed up. */
|
||||
/* Although EOLs are not inserted at the end of each row of a T.6 image,
|
||||
they are still perfectly valid, and can terminate an image. */
|
||||
if ((s->rx_bitstream & 0x0FFF) == 0x0800)
|
||||
{
|
||||
STATE_TRACE("EOL\n");
|
||||
if (s->row_len == 0)
|
||||
{
|
||||
/* A zero length row - i.e. 2 consecutive EOLs - is distinctly
|
||||
the end of page condition. That's all we actually get on a
|
||||
T.6 page. However, there are a minimum of 6 EOLs at the end of
|
||||
any T.4 page. We can look for more than 2 EOLs in case bit
|
||||
errors simulate the end of page condition at the wrong point.
|
||||
Such robust checking is irrelevant for a T.6 page, as it should
|
||||
be error free. */
|
||||
/* Note that for a T.6 page we should get here on the very first
|
||||
EOL, as the row length should be zero at that point. Therefore
|
||||
we should count up both EOLs, unless there is some bogus partial
|
||||
row ahead of them. */
|
||||
s->consecutive_eols++;
|
||||
if (s->encoding == T4_COMPRESSION_ITU_T6)
|
||||
{
|
||||
if (s->consecutive_eols >= EOLS_TO_END_T6_RX_PAGE)
|
||||
{
|
||||
s->consecutive_eols = EOLS_TO_END_ANY_RX_PAGE;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s->consecutive_eols >= EOLS_TO_END_T4_RX_PAGE)
|
||||
{
|
||||
s->consecutive_eols = EOLS_TO_END_ANY_RX_PAGE;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The EOLs are not back-to-back, so they are not part of the
|
||||
end of page condition. */
|
||||
if (s->run_length > 0)
|
||||
add_run_to_row(s);
|
||||
s->consecutive_eols = 0;
|
||||
if (put_decoded_row(s))
|
||||
return TRUE;
|
||||
}
|
||||
if (s->encoding == T4_COMPRESSION_ITU_T4_2D)
|
||||
{
|
||||
s->row_is_2d = !(s->rx_bitstream & 0x1000);
|
||||
force_drop_rx_bits(s, 13);
|
||||
}
|
||||
else
|
||||
{
|
||||
force_drop_rx_bits(s, 12);
|
||||
}
|
||||
s->in_black = FALSE;
|
||||
s->black_white = 0;
|
||||
s->run_length = 0;
|
||||
s->row_len = 0;
|
||||
continue;
|
||||
}
|
||||
if (s->rx_skip_bits)
|
||||
{
|
||||
/* We are clearing out the remaining bits of the last code word we
|
||||
absorbed. */
|
||||
s->rx_skip_bits--;
|
||||
s->rx_bits--;
|
||||
s->rx_bitstream >>= 1;
|
||||
continue;
|
||||
}
|
||||
if (s->row_is_2d && s->black_white == 0)
|
||||
{
|
||||
bits = s->rx_bitstream & 0x7F;
|
||||
STATE_TRACE("State %d, %d - ",
|
||||
t4_2d_table[bits].state,
|
||||
t4_2d_table[bits].width);
|
||||
if (s->row_len >= s->image_width)
|
||||
{
|
||||
drop_rx_bits(s, t4_2d_table[bits].width);
|
||||
continue;
|
||||
}
|
||||
if (s->a_cursor)
|
||||
{
|
||||
/* Move past a0, always staying on the current colour */
|
||||
for ( ; s->b1 <= s->a0; s->b_cursor += 2)
|
||||
s->b1 += (s->ref_runs[s->b_cursor] + s->ref_runs[s->b_cursor + 1]);
|
||||
}
|
||||
switch (t4_2d_table[bits].state)
|
||||
{
|
||||
case S_Horiz:
|
||||
STATE_TRACE("Horiz %d %d %d\n",
|
||||
s->image_width,
|
||||
s->a0,
|
||||
s->a_cursor);
|
||||
/* We now need to extract a white/black or black/white pair of runs, using the 1D
|
||||
method. If the first of the pair takes us exactly to the end of the row, there
|
||||
should still be a zero length element for the second of the pair. */
|
||||
s->in_black = s->a_cursor & 1;
|
||||
s->black_white = 2;
|
||||
break;
|
||||
case S_Vert:
|
||||
STATE_TRACE("Vert[%d] %d %d %d %d\n",
|
||||
t4_2d_table[bits].param,
|
||||
s->image_width,
|
||||
s->a0,
|
||||
s->b1,
|
||||
s->run_length);
|
||||
old_a0 = s->a0;
|
||||
s->a0 = s->b1 + t4_2d_table[bits].param;
|
||||
/* We need to check if a bad or malicious image is failing to move forward along the row.
|
||||
Going back is obviously bad. We also need to avoid a stall on the spot, except for the
|
||||
special case of the start of the row. Zero movement as the very first element in the
|
||||
row is perfectly normal. */
|
||||
if (s->a0 <= old_a0)
|
||||
{
|
||||
if (s->a0 < old_a0 || s->b_cursor > 1)
|
||||
{
|
||||
/* Undo the update we just started, and carry on as if this code does not exist */
|
||||
/* TODO: we really should record that something wasn't right at this point. */
|
||||
s->a0 = old_a0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
s->run_length += (s->a0 - old_a0);
|
||||
add_run_to_row(s);
|
||||
/* We need to move one step in one direction or the other, to change to the
|
||||
opposite colour */
|
||||
if (t4_2d_table[bits].param >= 0)
|
||||
{
|
||||
s->b1 += s->ref_runs[s->b_cursor++];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s->b_cursor)
|
||||
s->b1 -= s->ref_runs[--s->b_cursor];
|
||||
}
|
||||
break;
|
||||
case S_Pass:
|
||||
STATE_TRACE("Pass %d %d %d %d %d\n",
|
||||
s->image_width,
|
||||
s->a0,
|
||||
s->b1,
|
||||
s->ref_runs[s->b_cursor],
|
||||
s->ref_runs[s->b_cursor + 1]);
|
||||
s->b1 += s->ref_runs[s->b_cursor++];
|
||||
old_a0 = s->a0;
|
||||
s->a0 = s->b1;
|
||||
s->run_length += (s->a0 - old_a0);
|
||||
s->b1 += s->ref_runs[s->b_cursor++];
|
||||
break;
|
||||
case S_Ext:
|
||||
/* We do not currently handle any kind of extension */
|
||||
STATE_TRACE("Ext %d %d %d 0x%x\n",
|
||||
s->image_width,
|
||||
s->a0,
|
||||
((s->rx_bitstream >> t4_2d_table[bits].width) & 0x7),
|
||||
s->rx_bitstream);
|
||||
/* TODO: The uncompressed option should be implemented. */
|
||||
break;
|
||||
case S_Null:
|
||||
STATE_TRACE("Null\n");
|
||||
break;
|
||||
default:
|
||||
STATE_TRACE("Unexpected T.4 state\n");
|
||||
span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected T.4 state %d\n", t4_2d_table[bits].state);
|
||||
break;
|
||||
}
|
||||
drop_rx_bits(s, t4_2d_table[bits].width);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s->in_black)
|
||||
{
|
||||
bits = s->rx_bitstream & 0x1FFF;
|
||||
STATE_TRACE("State %d, %d - Black %d %d %d\n",
|
||||
t4_1d_black_table[bits].state,
|
||||
t4_1d_black_table[bits].width,
|
||||
s->image_width,
|
||||
s->a0,
|
||||
t4_1d_black_table[bits].param);
|
||||
switch (t4_1d_black_table[bits].state)
|
||||
{
|
||||
case S_MakeUpB:
|
||||
case S_MakeUp:
|
||||
s->run_length += t4_1d_black_table[bits].param;
|
||||
s->a0 += t4_1d_black_table[bits].param;
|
||||
break;
|
||||
case S_TermB:
|
||||
s->in_black = FALSE;
|
||||
if (s->row_len < s->image_width)
|
||||
{
|
||||
s->run_length += t4_1d_black_table[bits].param;
|
||||
s->a0 += t4_1d_black_table[bits].param;
|
||||
add_run_to_row(s);
|
||||
}
|
||||
if (s->black_white)
|
||||
s->black_white--;
|
||||
break;
|
||||
default:
|
||||
/* Bad black */
|
||||
s->black_white = 0;
|
||||
break;
|
||||
}
|
||||
drop_rx_bits(s, t4_1d_black_table[bits].width);
|
||||
}
|
||||
else
|
||||
{
|
||||
bits = s->rx_bitstream & 0xFFF;
|
||||
STATE_TRACE("State %d, %d - White %d %d %d\n",
|
||||
t4_1d_white_table[bits].state,
|
||||
t4_1d_white_table[bits].width,
|
||||
s->image_width,
|
||||
s->a0,
|
||||
t4_1d_white_table[bits].param);
|
||||
switch (t4_1d_white_table[bits].state)
|
||||
{
|
||||
case S_MakeUpW:
|
||||
case S_MakeUp:
|
||||
s->run_length += t4_1d_white_table[bits].param;
|
||||
s->a0 += t4_1d_white_table[bits].param;
|
||||
break;
|
||||
case S_TermW:
|
||||
s->in_black = TRUE;
|
||||
if (s->row_len < s->image_width)
|
||||
{
|
||||
s->run_length += t4_1d_white_table[bits].param;
|
||||
s->a0 += t4_1d_white_table[bits].param;
|
||||
add_run_to_row(s);
|
||||
}
|
||||
if (s->black_white)
|
||||
s->black_white--;
|
||||
break;
|
||||
default:
|
||||
/* Bad white */
|
||||
s->black_white = 0;
|
||||
break;
|
||||
}
|
||||
drop_rx_bits(s, t4_1d_white_table[bits].width);
|
||||
}
|
||||
}
|
||||
if (s->a0 >= s->image_width)
|
||||
s->a0 = s->image_width - 1;
|
||||
|
||||
if (s->encoding == T4_COMPRESSION_ITU_T6)
|
||||
{
|
||||
/* T.6 has no EOL markers. We sense the end of a line by its length alone. */
|
||||
/* The last test here is a backstop protection, so a corrupt image cannot
|
||||
cause us to do bad things. Bad encoders have actually been seen, which
|
||||
demand such protection. */
|
||||
if (s->black_white == 0 && s->row_len >= s->image_width)
|
||||
{
|
||||
STATE_TRACE("EOL T.6\n");
|
||||
if (s->run_length > 0)
|
||||
add_run_to_row(s);
|
||||
if (put_decoded_row(s))
|
||||
return TRUE;
|
||||
s->in_black = FALSE;
|
||||
s->black_white = 0;
|
||||
s->run_length = 0;
|
||||
s->row_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void t4_t6_decode_rx_status(t4_t6_decode_state_t *s, int status)
|
||||
{
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Signal status is %s (%d)\n", signal_status_to_str(status), status);
|
||||
switch (status)
|
||||
{
|
||||
case SIG_STATUS_TRAINING_IN_PROGRESS:
|
||||
case SIG_STATUS_TRAINING_FAILED:
|
||||
case SIG_STATUS_TRAINING_SUCCEEDED:
|
||||
case SIG_STATUS_CARRIER_UP:
|
||||
/* Ignore these */
|
||||
break;
|
||||
case SIG_STATUS_CARRIER_DOWN:
|
||||
case SIG_STATUS_END_OF_DATA:
|
||||
/* Finalise the image */
|
||||
if (s->consecutive_eols != EOLS_TO_END_ANY_RX_PAGE)
|
||||
{
|
||||
/* Push enough zeros (13) through the decoder to flush out any remaining codes */
|
||||
put_bits(s, 0, 8);
|
||||
put_bits(s, 0, 5);
|
||||
}
|
||||
if (s->curr_bad_row_run)
|
||||
{
|
||||
if (s->curr_bad_row_run > s->longest_bad_row_run)
|
||||
s->longest_bad_row_run = s->curr_bad_row_run;
|
||||
s->curr_bad_row_run = 0;
|
||||
}
|
||||
/* Don't worry about the return value here. We are finishing anyway. */
|
||||
if (s->row_write_handler)
|
||||
s->row_write_handler(s->row_write_user_data, NULL, 0);
|
||||
s->rx_bits = 0;
|
||||
s->rx_skip_bits = 0;
|
||||
s->rx_bitstream = 0;
|
||||
s->consecutive_eols = EOLS_TO_END_ANY_RX_PAGE;
|
||||
break;
|
||||
default:
|
||||
span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected rx status - %d!\n", status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) t4_t6_decode_put_bit(t4_t6_decode_state_t *s, int bit)
|
||||
{
|
||||
if (bit < 0)
|
||||
{
|
||||
t4_t6_decode_rx_status(s, bit);
|
||||
return TRUE;
|
||||
}
|
||||
s->compressed_image_size++;
|
||||
return put_bits(s, bit & 1, 1);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) t4_t6_decode_put_byte(t4_t6_decode_state_t *s, int byte)
|
||||
{
|
||||
if (byte < 0)
|
||||
{
|
||||
t4_t6_decode_rx_status(s, byte);
|
||||
return TRUE;
|
||||
}
|
||||
s->compressed_image_size += 8;
|
||||
return put_bits(s, byte & 0xFF, 8);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) t4_t6_decode_put_chunk(t4_t6_decode_state_t *s, const uint8_t buf[], int len)
|
||||
{
|
||||
int i;
|
||||
uint8_t byte;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
s->compressed_image_size += 8;
|
||||
byte = buf[i];
|
||||
if (put_bits(s, byte & 0xFF, 8))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) t4_t6_decode_set_row_write_handler(t4_t6_decode_state_t *s,
|
||||
t4_row_write_handler_t handler,
|
||||
void *user_data)
|
||||
{
|
||||
s->row_write_handler = handler;
|
||||
s->row_write_user_data = user_data;
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) t4_t6_decode_set_encoding(t4_t6_decode_state_t *s, int encoding)
|
||||
{
|
||||
switch (encoding)
|
||||
{
|
||||
case T4_COMPRESSION_ITU_T4_1D:
|
||||
case T4_COMPRESSION_ITU_T4_2D:
|
||||
case T4_COMPRESSION_ITU_T6:
|
||||
s->encoding = encoding;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(uint32_t) t4_t6_decode_get_image_width(t4_t6_decode_state_t *s)
|
||||
{
|
||||
return s->image_width;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(uint32_t) t4_t6_decode_get_image_length(t4_t6_decode_state_t *s)
|
||||
{
|
||||
return s->image_length;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) t4_t6_decode_get_compressed_image_size(t4_t6_decode_state_t *s)
|
||||
{
|
||||
return s->compressed_image_size;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) t4_t6_decode_restart(t4_t6_decode_state_t *s, int image_width)
|
||||
{
|
||||
int bytes_per_row;
|
||||
int run_space;
|
||||
uint32_t *bufptr;
|
||||
uint8_t *bufptr8;
|
||||
|
||||
/* Calculate the scanline/tile width. */
|
||||
run_space = (image_width + 4)*sizeof(uint32_t);
|
||||
if (s->bytes_per_row == 0 || image_width != s->image_width)
|
||||
{
|
||||
/* Allocate the space required for decoding the new row length. */
|
||||
if ((bufptr = (uint32_t *) realloc(s->cur_runs, run_space)) == NULL)
|
||||
return -1;
|
||||
s->cur_runs = bufptr;
|
||||
if ((bufptr = (uint32_t *) realloc(s->ref_runs, run_space)) == NULL)
|
||||
return -1;
|
||||
s->ref_runs = bufptr;
|
||||
s->image_width = image_width;
|
||||
}
|
||||
bytes_per_row = (image_width + 7)/8;
|
||||
if (bytes_per_row != s->bytes_per_row)
|
||||
{
|
||||
if ((bufptr8 = (uint8_t *) realloc(s->row_buf, bytes_per_row)) == NULL)
|
||||
return -1;
|
||||
s->row_buf = bufptr8;
|
||||
s->bytes_per_row = bytes_per_row;
|
||||
}
|
||||
|
||||
s->rx_bits = 0;
|
||||
s->rx_skip_bits = 0;
|
||||
s->rx_bitstream = 0;
|
||||
s->row_bits = 0;
|
||||
s->min_row_bits = INT_MAX;
|
||||
s->max_row_bits = 0;
|
||||
|
||||
s->compressed_image_size = 0;
|
||||
s->bad_rows = 0;
|
||||
s->longest_bad_row_run = 0;
|
||||
s->curr_bad_row_run = 0;
|
||||
s->image_length = 0;
|
||||
s->pixel_stream = 0;
|
||||
s->pixels = 8;
|
||||
|
||||
s->row_len = 0;
|
||||
s->in_black = FALSE;
|
||||
s->black_white = 0;
|
||||
s->b_cursor = 1;
|
||||
s->a_cursor = 0;
|
||||
s->b1 = s->image_width;
|
||||
s->a0 = 0;
|
||||
s->run_length = 0;
|
||||
s->row_is_2d = (s->encoding == T4_COMPRESSION_ITU_T6);
|
||||
/* We start at -1 EOLs for 1D and 2D decoding, as an indication we are waiting for the
|
||||
first EOL. T.6 coding starts without any preamble. */
|
||||
s->consecutive_eols = (s->encoding == T4_COMPRESSION_ITU_T6) ? 0 : -1;
|
||||
|
||||
if (s->cur_runs)
|
||||
memset(s->cur_runs, 0, run_space);
|
||||
/* Initialise the reference line to all white */
|
||||
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;
|
||||
}
|
||||
if (s->row_buf)
|
||||
memset(s->row_buf, 0, s->bytes_per_row);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(t4_t6_decode_state_t *) t4_t6_decode_init(t4_t6_decode_state_t *s,
|
||||
int encoding,
|
||||
int image_width,
|
||||
t4_row_write_handler_t handler,
|
||||
void *user_data)
|
||||
{
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (t4_t6_decode_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
|
||||
span_log_set_protocol(&s->logging, "T.4/T.6");
|
||||
|
||||
s->encoding = encoding;
|
||||
s->row_write_handler = handler;
|
||||
s->row_write_user_data = user_data;
|
||||
t4_t6_decode_restart(s, image_width);
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) t4_t6_decode_release(t4_t6_decode_state_t *s)
|
||||
{
|
||||
free_buffers(s);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) t4_t6_decode_free(t4_t6_decode_state_t *s)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = t4_t6_decode_release(s);
|
||||
free(s);
|
||||
return ret;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -109,6 +109,7 @@ noinst_PROGRAMS = ademco_contactid_tests \
|
|||
t38_decode \
|
||||
t38_non_ecm_buffer_tests \
|
||||
t4_tests \
|
||||
t4_t6_tests \
|
||||
t81_t82_arith_coding_tests \
|
||||
t85_tests \
|
||||
time_scale_tests \
|
||||
|
@ -125,8 +126,7 @@ noinst_PROGRAMS = ademco_contactid_tests \
|
|||
v42bis_tests \
|
||||
v8_tests \
|
||||
vector_float_tests \
|
||||
vector_int_tests \
|
||||
tsb85_tests
|
||||
vector_int_tests
|
||||
|
||||
noinst_HEADERS = echo_monitor.h \
|
||||
fax_tester.h \
|
||||
|
@ -314,6 +314,9 @@ t38_non_ecm_buffer_tests_LDADD = $(LIBDIR) -lspandsp
|
|||
t4_tests_SOURCES = t4_tests.c
|
||||
t4_tests_LDADD = $(LIBDIR) -lspandsp
|
||||
|
||||
t4_t6_tests_SOURCES = t4_t6_tests.c
|
||||
t4_t6_tests_LDADD = $(LIBDIR) -lspandsp
|
||||
|
||||
t81_t82_arith_coding_tests_SOURCES = t81_t82_arith_coding_tests.c
|
||||
t81_t82_arith_coding_tests_LDADD = $(LIBDIR) -lspandsp
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ int decode_test = FALSE;
|
|||
int rx_bits = 0;
|
||||
|
||||
t30_state_t t30_dummy;
|
||||
t4_state_t t4_rx_state;
|
||||
t4_rx_state_t t4_rx_state;
|
||||
int t4_up = FALSE;
|
||||
|
||||
hdlc_rx_state_t hdlcrx;
|
||||
|
|
|
@ -508,19 +508,18 @@ then
|
|||
fi
|
||||
echo t4_tests completed OK
|
||||
|
||||
#rm -f t4_t6_tests_receive.tif
|
||||
#./t4_t6_tests >$STDOUT_DEST 2>$STDERR_DEST
|
||||
#RETVAL=$?
|
||||
#if [ $RETVAL != 0 ]
|
||||
#then
|
||||
# echo t4_t6_tests failed!
|
||||
# exit $RETVAL
|
||||
#fi
|
||||
#echo t4_t6_tests completed OK
|
||||
echo t4_t6_tests not enabled
|
||||
rm -f t4_t6_tests_receive.tif
|
||||
./t4_t6_tests >$STDOUT_DEST 2>$STDERR_DEST
|
||||
RETVAL=$?
|
||||
if [ $RETVAL != 0 ]
|
||||
then
|
||||
echo t4_t6_tests failed!
|
||||
exit $RETVAL
|
||||
fi
|
||||
echo t4_t6_tests completed OK
|
||||
|
||||
rm -f t81_t82_arith_coding_tests_receive.tif
|
||||
./t4_tests >$STDOUT_DEST 2>$STDERR_DEST
|
||||
./t81_t82_arith_coding_tests >$STDOUT_DEST 2>$STDERR_DEST
|
||||
RETVAL=$?
|
||||
if [ $RETVAL != 0 ]
|
||||
then
|
||||
|
@ -578,6 +577,22 @@ echo tone_detect_tests not enabled
|
|||
#echo tone_generate_tests completed OK
|
||||
echo tone_generate_tests not enabled
|
||||
|
||||
./tsb85_tests.sh >/dev/null
|
||||
RETVAL=$?
|
||||
if [ $RETVAL != 0 ]
|
||||
then
|
||||
echo ./tsb85_tests.sh failed!
|
||||
exit $RETVAL
|
||||
fi
|
||||
./tsb85_extra_tests.sh
|
||||
RETVAL=$?
|
||||
if [ $RETVAL != 0 ]
|
||||
then
|
||||
echo ./tsb85_extra_tests.sh failed!
|
||||
exit $RETVAL
|
||||
fi
|
||||
echo tsb85_tests.sh completed OK
|
||||
|
||||
for OPTS in "-b 14400 -s -42 -n -66" "-b 12000 -s -42 -n -61" "-b 9600 -s -42 -n -59" "-b 7200 -s -42 -n -56"
|
||||
do
|
||||
./v17_tests ${OPTS} >$STDOUT_DEST 2>$STDERR_DEST
|
||||
|
@ -615,7 +630,7 @@ do
|
|||
done
|
||||
echo v27ter_tests completed OK
|
||||
|
||||
for OPTS in "-b 9600 -s -42 -n -62" "-b 7200 -s -42 -n -59" "-b 4800 -s -42 -n -55"
|
||||
for OPTS in "-b 9600 -s -42 -n -62" "-b 7200 -s -42 -n -59" "-b 4800 -s -42 -n -54"
|
||||
do
|
||||
./v29_tests ${OPTS} >$STDOUT_DEST 2>$STDERR_DEST
|
||||
RETVAL=$?
|
||||
|
|
|
@ -0,0 +1,439 @@
|
|||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* t4_t6_tests.c - ITU T.4 and T.6 FAX image compression and decompression tests
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2003, 2009 Steve Underwood
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
/*! \page t4_t6_tests_page T.4 and T.6 image compress and decompression tests
|
||||
\section t4_t6_tests_page_sec_1 What does it do
|
||||
These tests exercise the image compression and decompression methods defined
|
||||
in ITU specifications T.4 and T.6.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <memory.h>
|
||||
|
||||
//#if defined(WITH_SPANDSP_INTERNALS)
|
||||
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
|
||||
//#endif
|
||||
|
||||
#include "spandsp.h"
|
||||
|
||||
#define XSIZE 1728
|
||||
|
||||
t4_t6_encode_state_t send_state;
|
||||
t4_t6_decode_state_t receive_state;
|
||||
|
||||
/* The following are some test cases from T.4 */
|
||||
#define FILL_70 " "
|
||||
#define FILL_80 " "
|
||||
#define FILL_100 " "
|
||||
#define FILL_670 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_70
|
||||
#define FILL_980 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_80
|
||||
|
||||
#define TEST_ROWS 16
|
||||
static const char t4_t6_test_patterns[TEST_ROWS][XSIZE + 1] =
|
||||
{
|
||||
"XXXXXX " FILL_980 " XXX XXX X " FILL_670 " XXXX",
|
||||
"XXXXXX " FILL_980 " XXX X " FILL_670 " XXXX",
|
||||
/* Line start should code to V(0). Line middle codes to VR(3) VL(2) V(0). Line end should code to V(0) V(0). */
|
||||
|
||||
" XXXX " FILL_980 " XXXXXXX " FILL_670 " XX ",
|
||||
"XXXXX " FILL_980 "XX XX " FILL_670 " XXXX",
|
||||
/* Line start should code to VL(1). Line middle codes to H(7,2). Line end should code to V(0) VR(2) */
|
||||
|
||||
"XXX " FILL_980 " XX XX XX XXX " FILL_670 " X ",
|
||||
" " FILL_980 " X XXX XXXX " FILL_670 " X XX",
|
||||
/* Line start should code to P. Line middle codes to P VL(1) V(0) H(3,4) P. Line end codes to V(0) VL(2) V(0). */
|
||||
|
||||
"XXXXX " FILL_980 " " FILL_670 " XXXX",
|
||||
" XXX " FILL_980 " " FILL_670 " XX ",
|
||||
/* Line start should code to VR(2). Line end codes to V(0) VL(2) V(0). */
|
||||
|
||||
" XX " FILL_980 " " FILL_670 " X XXX",
|
||||
"XXX X " FILL_980 " " FILL_670 " X ",
|
||||
/* Line start should code to H(0,3) VR(1). Line end codes to V(0) VR(3). */
|
||||
|
||||
" " FILL_980 " " FILL_670 " XX ",
|
||||
" " FILL_980 " " FILL_670 " ",
|
||||
/* Line end codes to P V(0) a'0. */
|
||||
|
||||
" " FILL_980 " " FILL_670 " XXXXXXXXXX",
|
||||
" " FILL_980 " " FILL_670 " XXXXXX XXXXXX",
|
||||
/* Line end codes to H(2,6). */
|
||||
|
||||
" " FILL_980 " " FILL_670 " XX XXXXX",
|
||||
" " FILL_980 " " FILL_670 " XX ",
|
||||
/* Line end codes to V(0) H(7,0). */
|
||||
};
|
||||
|
||||
#if 0
|
||||
static void dump_image_as_xxx(const uint8_t buf[], int bytes_per_row, int len)
|
||||
{
|
||||
const uint8_t *s;
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
|
||||
/* Dump the entire image as text 'X's and spaces */
|
||||
printf("Image (%d pixels x %d pixels):\n", bytes_per_row*8, len/bytes_per_row);
|
||||
s = buf;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
for (j = 0; j < bytes_per_row; j++)
|
||||
{
|
||||
for (k = 0; k < 8; k++)
|
||||
printf((buf[i*bytes_per_row + j] & (0x80 >> k)) ? "X" : " ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
#endif
|
||||
|
||||
static int row_read_handler(void *user_data, uint8_t buf[], size_t len)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
const char *s;
|
||||
static int row = 0;
|
||||
|
||||
/* Send the test pattern. */
|
||||
if (row >= TEST_ROWS)
|
||||
{
|
||||
row = 0;
|
||||
return 0;
|
||||
}
|
||||
s = t4_t6_test_patterns[row++];
|
||||
memset(buf, 0, len);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
if (*s++ != ' ')
|
||||
buf[i] |= (0x80 >> j);
|
||||
}
|
||||
}
|
||||
if (*s)
|
||||
printf("Oops - '%c' at end of row %d\n", *s, row);
|
||||
return len;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int row_write_handler(void *user_data, const uint8_t buf[], size_t len)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
const char *s;
|
||||
static int row = 0;
|
||||
uint8_t ref[8192];
|
||||
|
||||
/* Verify that what is received matches the test pattern. */
|
||||
//printf("Row %d\n", row);
|
||||
if (len == 0)
|
||||
return 0;
|
||||
s = t4_t6_test_patterns[row++];
|
||||
if (row >= TEST_ROWS)
|
||||
row = 0;
|
||||
memset(ref, 0, len);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
if (*s++ != ' ')
|
||||
ref[i] |= (0x80 >> j);
|
||||
}
|
||||
}
|
||||
if (*s)
|
||||
printf("Oops - '%c' at end of row %d\n", *s, row);
|
||||
if (memcmp(buf, ref, len))
|
||||
{
|
||||
printf("Test failed at row %d\n", row);
|
||||
exit(2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int detect_page_end(int bit, int page_ended)
|
||||
{
|
||||
static int consecutive_eols;
|
||||
static int max_consecutive_eols;
|
||||
static int consecutive_zeros;
|
||||
static int consecutive_ones;
|
||||
static int eol_zeros;
|
||||
static int eol_ones;
|
||||
static int expected_eols;
|
||||
static int end_marks;
|
||||
|
||||
/* Check the EOLs are added properly to the end of an image. We can't rely on the
|
||||
decoder giving the right answer, as a full set of EOLs is not needed for the
|
||||
decoder to work. */
|
||||
if (bit == -1000000)
|
||||
{
|
||||
/* Reset */
|
||||
consecutive_eols = 0;
|
||||
max_consecutive_eols = 0;
|
||||
consecutive_zeros = 0;
|
||||
consecutive_ones = 0;
|
||||
end_marks = 0;
|
||||
|
||||
eol_zeros = 11;
|
||||
eol_ones = (page_ended == T4_COMPRESSION_ITU_T4_2D) ? 2 : 1;
|
||||
expected_eols = (page_ended == T4_COMPRESSION_ITU_T6) ? 2 : 6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Monitor whether the EOLs are there in the correct amount */
|
||||
if (bit == 0)
|
||||
{
|
||||
consecutive_zeros++;
|
||||
consecutive_ones = 0;
|
||||
}
|
||||
else if (bit == 1)
|
||||
{
|
||||
if (++consecutive_ones == eol_ones)
|
||||
{
|
||||
if (consecutive_eols == 0 && consecutive_zeros >= eol_zeros)
|
||||
consecutive_eols++;
|
||||
else if (consecutive_zeros == eol_zeros)
|
||||
consecutive_eols++;
|
||||
else
|
||||
consecutive_eols = 0;
|
||||
consecutive_zeros = 0;
|
||||
consecutive_ones = 0;
|
||||
}
|
||||
if (max_consecutive_eols < consecutive_eols)
|
||||
max_consecutive_eols = consecutive_eols;
|
||||
}
|
||||
else if (bit == SIG_STATUS_END_OF_DATA)
|
||||
{
|
||||
if (end_marks == 0)
|
||||
{
|
||||
if (max_consecutive_eols != expected_eols)
|
||||
{
|
||||
printf("Only %d EOLs (should be %d)\n", max_consecutive_eols, expected_eols);
|
||||
return 2;
|
||||
}
|
||||
consecutive_zeros = 0;
|
||||
consecutive_eols = 0;
|
||||
max_consecutive_eols = 0;
|
||||
}
|
||||
if (!page_ended)
|
||||
{
|
||||
/* We might need to push a few bits to get the receiver to report the
|
||||
end of page condition (at least with T.6). */
|
||||
if (++end_marks > 50)
|
||||
{
|
||||
printf("Receiver missed the end of page mark\n");
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
static const int compression_sequence[] =
|
||||
{
|
||||
T4_COMPRESSION_ITU_T4_1D,
|
||||
T4_COMPRESSION_ITU_T4_2D,
|
||||
T4_COMPRESSION_ITU_T6,
|
||||
-1
|
||||
};
|
||||
int bit;
|
||||
int end_of_page;
|
||||
int end_marks;
|
||||
int compression;
|
||||
int compression_step;
|
||||
int min_row_bits;
|
||||
int opt;
|
||||
int tests_failed;
|
||||
int block_size;
|
||||
int len;
|
||||
int res;
|
||||
uint8_t chunk_buf[1024];
|
||||
|
||||
tests_failed = 0;
|
||||
compression = -1;
|
||||
compression_step = 0;
|
||||
/* Use a non-zero default minimum row length to ensure we test the consecutive EOLs part
|
||||
properly. */
|
||||
min_row_bits = 50;
|
||||
block_size = 0;
|
||||
while ((opt = getopt(argc, argv, "126b: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 'm':
|
||||
min_row_bits = atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
//usage();
|
||||
exit(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Create a send and a receive end */
|
||||
memset(&send_state, 0, sizeof(send_state));
|
||||
memset(&receive_state, 0, sizeof(receive_state));
|
||||
|
||||
end_of_page = FALSE;
|
||||
#if 1
|
||||
printf("Testing image_function->compress->decompress->image_function\n");
|
||||
/* Send end gets image from a function */
|
||||
if (t4_t6_encode_init(&send_state, compression, 1728, row_read_handler, NULL) == NULL)
|
||||
{
|
||||
printf("Failed to init T.4/T.6 encoder\n");
|
||||
exit(2);
|
||||
}
|
||||
span_log_set_level(&send_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
|
||||
t4_t6_encode_set_min_bits_per_row(&send_state, min_row_bits);
|
||||
t4_t6_encode_set_max_2d_rows_per_1d_row(&send_state, 2);
|
||||
|
||||
/* Receive end puts TIFF to a function. */
|
||||
if (t4_t6_decode_init(&receive_state, compression, 1728, row_write_handler, NULL) == NULL)
|
||||
{
|
||||
printf("Failed to init T.4/T.6 decoder\n");
|
||||
exit(2);
|
||||
}
|
||||
span_log_set_level(&receive_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
|
||||
|
||||
/* Now send and receive the test data with all compression modes. */
|
||||
/* If we are stepping around the compression schemes, reset to the start of the sequence. */
|
||||
if (compression_step > 0)
|
||||
compression_step = 0;
|
||||
for (;;)
|
||||
{
|
||||
end_marks = 0;
|
||||
if (compression_step >= 0)
|
||||
{
|
||||
compression = compression_sequence[compression_step++];
|
||||
if (compression < 0)
|
||||
break;
|
||||
}
|
||||
t4_t6_encode_set_encoding(&send_state, compression);
|
||||
t4_t6_decode_set_encoding(&receive_state, compression);
|
||||
|
||||
if (t4_t6_encode_restart(&send_state, 1728))
|
||||
break;
|
||||
if (t4_t6_decode_restart(&receive_state, 1728))
|
||||
break;
|
||||
detect_page_end(-1000000, compression);
|
||||
switch (block_size)
|
||||
{
|
||||
case 0:
|
||||
end_of_page = FALSE;
|
||||
for (;;)
|
||||
{
|
||||
bit = t4_t6_encode_get_bit(&send_state);
|
||||
if ((res = detect_page_end(bit, end_of_page)))
|
||||
{
|
||||
if (res != 1)
|
||||
{
|
||||
printf("Test failed\n");
|
||||
exit(2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!end_of_page)
|
||||
end_of_page = t4_t6_decode_put_bit(&receive_state, bit & 1);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
do
|
||||
{
|
||||
bit = t4_t6_encode_get_byte(&send_state);
|
||||
if ((bit & 0x100))
|
||||
{
|
||||
if (++end_marks > 50)
|
||||
{
|
||||
printf("Receiver missed the end of page mark\n");
|
||||
tests_failed++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
end_of_page = t4_t6_decode_put_byte(&receive_state, bit & 0xFF);
|
||||
}
|
||||
while (!end_of_page);
|
||||
break;
|
||||
default:
|
||||
do
|
||||
{
|
||||
len = t4_t6_encode_get_chunk(&send_state, chunk_buf, block_size);
|
||||
if (len == 0)
|
||||
{
|
||||
if (++end_marks > 50)
|
||||
{
|
||||
printf("Receiver missed the end of page mark\n");
|
||||
tests_failed++;
|
||||
break;
|
||||
}
|
||||
chunk_buf[0] = 0xFF;
|
||||
len = 1;
|
||||
}
|
||||
end_of_page = t4_t6_decode_put_chunk(&receive_state, chunk_buf, len);
|
||||
}
|
||||
while (!end_of_page);
|
||||
break;
|
||||
}
|
||||
if (compression_step < 0)
|
||||
break;
|
||||
}
|
||||
t4_t6_encode_release(&send_state);
|
||||
t4_t6_decode_release(&receive_state);
|
||||
#endif
|
||||
printf("Tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
|
@ -52,8 +52,8 @@ in ITU specifications T.4 and T.6.
|
|||
|
||||
#define XSIZE 1728
|
||||
|
||||
t4_state_t send_state;
|
||||
t4_state_t receive_state;
|
||||
t4_tx_state_t send_state;
|
||||
t4_rx_state_t receive_state;
|
||||
|
||||
/* The following are some test cases from T.4 */
|
||||
#define FILL_70 " "
|
||||
|
@ -100,27 +100,31 @@ static const char t4_t6_test_patterns[][1728 + 1] =
|
|||
int rows_written = 0;
|
||||
int rows_read = 0;
|
||||
|
||||
static void dump_image_as_xxx(t4_state_t *state)
|
||||
static void dump_image_as_xxx(t4_rx_state_t *state)
|
||||
{
|
||||
#if 0
|
||||
uint8_t *s;
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
|
||||
/* Dump the entire image as text 'X's and spaces */
|
||||
printf("Image (%d x %d):\n", receive_state.image_width, receive_state.image_length);
|
||||
for (i = 0; i < state->image_length; i++)
|
||||
printf("Image (%d x %d):\n", state->t4_t6.image_width, state->t4_t6.image_length);
|
||||
s = state->image_buffer;
|
||||
for (i = 0; i < state->t4_t6.image_length; i++)
|
||||
{
|
||||
for (j = 0; j < state->bytes_per_row; j++)
|
||||
for (j = 0; j < state->t4_t6.bytes_per_row; j++)
|
||||
{
|
||||
for (k = 0; k < 8; k++)
|
||||
printf((state->image_buffer[i*state->bytes_per_row + j] & (0x80 >> k)) ? "X" : " ");
|
||||
printf((state->image_buffer[i*state->t4_t6.bytes_per_row + j] & (0x80 >> k)) ? "X" : " ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void display_page_stats(t4_state_t *s)
|
||||
static void display_page_stats(t4_rx_state_t *s)
|
||||
{
|
||||
t4_stats_t stats;
|
||||
|
||||
|
@ -132,7 +136,7 @@ static void display_page_stats(t4_state_t *s)
|
|||
printf("Image resolution = %d pels/m x %d pels/m\n", stats.x_resolution, stats.y_resolution);
|
||||
printf("Bad rows = %d\n", stats.bad_rows);
|
||||
printf("Longest bad row run = %d\n", stats.longest_bad_row_run);
|
||||
printf("Bits per row - min %d, max %d\n", s->min_row_bits, s->max_row_bits);
|
||||
printf("Bits per row - min %d, max %d\n", s->decoder.t4_t6.min_row_bits, s->decoder.t4_t6.max_row_bits);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
|
@ -288,10 +292,8 @@ int main(int argc, char *argv[])
|
|||
#if defined(SPANDSP_SUPPORT_T43x)
|
||||
T4_COMPRESSION_ITU_T43,
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
T4_COMPRESSION_ITU_T85,
|
||||
T4_COMPRESSION_ITU_T85_L0,
|
||||
#endif
|
||||
//T4_COMPRESSION_ITU_T45,
|
||||
-1
|
||||
};
|
||||
|
@ -303,7 +305,7 @@ int main(int argc, char *argv[])
|
|||
int compression;
|
||||
int compression_step;
|
||||
int add_page_headers;
|
||||
//int overlay_page_headers;
|
||||
int overlay_page_headers;
|
||||
int min_row_bits;
|
||||
int restart_pages;
|
||||
int block_size;
|
||||
|
@ -327,7 +329,7 @@ int main(int argc, char *argv[])
|
|||
compression = -1;
|
||||
compression_step = 0;
|
||||
add_page_headers = FALSE;
|
||||
//overlay_page_headers = FALSE;
|
||||
overlay_page_headers = FALSE;
|
||||
restart_pages = FALSE;
|
||||
in_file_name = IN_FILE_NAME;
|
||||
decode_file_name = NULL;
|
||||
|
@ -377,13 +379,11 @@ int main(int argc, char *argv[])
|
|||
compression_step = -1;
|
||||
}
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
else if (strcmp(optarg, "T85") == 0)
|
||||
{
|
||||
compression = T4_COMPRESSION_ITU_T85;
|
||||
compression_step = -1;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 'd':
|
||||
decode_file_name = optarg;
|
||||
|
@ -393,11 +393,11 @@ int main(int argc, char *argv[])
|
|||
break;
|
||||
case 'h':
|
||||
add_page_headers = TRUE;
|
||||
//overlay_page_headers = FALSE;
|
||||
overlay_page_headers = FALSE;
|
||||
break;
|
||||
case 'H':
|
||||
add_page_headers = TRUE;
|
||||
//overlay_page_headers = TRUE;
|
||||
overlay_page_headers = TRUE;
|
||||
break;
|
||||
case 'r':
|
||||
restart_pages = TRUE;
|
||||
|
@ -542,18 +542,19 @@ int main(int argc, char *argv[])
|
|||
#if 1
|
||||
printf("Testing image_function->compress->decompress->image_function\n");
|
||||
/* Send end gets image from a function */
|
||||
if (t4_tx_init(&send_state, in_file_name, -1, -1) == NULL)
|
||||
if (t4_tx_init(&send_state, FALSE, -1, -1) == NULL)
|
||||
{
|
||||
printf("Failed to init T.4 tx\n");
|
||||
exit(2);
|
||||
}
|
||||
span_log_set_level(&send_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW);
|
||||
t4_tx_set_row_read_handler(&send_state, row_read_handler, NULL);
|
||||
t4_tx_set_image_width(&send_state, 1728);
|
||||
t4_tx_set_min_bits_per_row(&send_state, min_row_bits);
|
||||
t4_tx_set_local_ident(&send_state, "111 2222 3333");
|
||||
t4_tx_set_max_2d_rows_per_1d_row(&send_state, 2);
|
||||
|
||||
/* Receive end puts TIFF to a function. */
|
||||
if (t4_rx_init(&receive_state, OUT_FILE_NAME, T4_COMPRESSION_ITU_T4_2D) == NULL)
|
||||
if (t4_rx_init(&receive_state, NULL, T4_COMPRESSION_ITU_T4_2D) == NULL)
|
||||
{
|
||||
printf("Failed to init T.4 rx\n");
|
||||
exit(2);
|
||||
|
@ -701,7 +702,7 @@ int main(int argc, char *argv[])
|
|||
if (tz_init(&tz, page_header_tz))
|
||||
t4_tx_set_header_tz(&send_state, &tz);
|
||||
}
|
||||
//t4_tx_set_header_overlays_image(&send_state, overlay_page_headers);
|
||||
t4_tx_set_header_overlays_image(&send_state, overlay_page_headers);
|
||||
if (restart_pages && (sends & 1))
|
||||
{
|
||||
/* Use restart, to send the page a second time */
|
||||
|
|
|
@ -630,7 +630,7 @@ static int next_step(faxtester_state_t *s)
|
|||
int compression_type;
|
||||
int timer;
|
||||
int len;
|
||||
t4_state_t t4_tx_state;
|
||||
t4_tx_state_t t4_tx_state;
|
||||
t30_state_t *t30;
|
||||
|
||||
if (s->cur == NULL)
|
||||
|
|
|
@ -104,18 +104,12 @@ do
|
|||
run_tsb85_test
|
||||
done
|
||||
|
||||
#OTEN02 fails because ?????
|
||||
|
||||
#for TEST in OTEN01 OTEN02 OTEN03 OTEN04 OTEN05 OTEN06
|
||||
for TEST in OTEN01 OTEN03 OTEN04 OTEN05 OTEN06
|
||||
for TEST in OTEN01 OTEN02 OTEN03 OTEN04 OTEN05 OTEN06
|
||||
do
|
||||
run_tsb85_test
|
||||
done
|
||||
|
||||
#MTGX02 fails because ?????
|
||||
|
||||
#for TEST in MTGX01 MTGX02 MTGX03 MTGX04 MTGX05 MTGX06 MTGX07 MTGX08
|
||||
for TEST in MTGX01 MTGX03 MTGX04 MTGX05 MTGX06 MTGX07 MTGX08
|
||||
for TEST in MTGX01 MTGX02 MTGX03 MTGX04 MTGX05 MTGX06 MTGX07 MTGX08
|
||||
do
|
||||
run_tsb85_test
|
||||
done
|
||||
|
|
Loading…
Reference in New Issue