mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-04-16 16:58:35 +00:00
Added some new files for spandsp
This commit is contained in:
parent
f029f7ef7c
commit
ccbee25641
96
libs/spandsp/spandsp/fax-tests.xml
Normal file
96
libs/spandsp/spandsp/fax-tests.xml
Normal file
@ -0,0 +1,96 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE fax-tests SYSTEM "./fax-tests.dtd">
|
||||
<fax-tests>
|
||||
<config>
|
||||
<path type="IMAGE" value="../test-data/etsi/fax"/>
|
||||
</config>
|
||||
<messages>
|
||||
<!-- TCF = 2700 bytes at 14400, 2250 at 12000, 1800 at 9600, 1350 at 7200, 900 at 4800 or 450 at 2400 -->
|
||||
<!-- Bad TCF == 10101010.... -->
|
||||
<!-- slow HDLC preamble == 37 flag bytes -->
|
||||
<!-- slow HDLC inter-frame flag sequence == 1 flag byte -->
|
||||
<!-- slow HDLC end flag sequence == 5 flag bytes -->
|
||||
<!-- synchronisation sequence == 250ms of zeros. = 450 bytes at 14400, 375 at 12000, 300 at 9600, 225 at 7200, 150 at 4800 or 75 at 2400 -->
|
||||
<!-- fast HDLC inter-frame flag sequence == 1 flag byte -->
|
||||
<!-- fast HDLC end flag sequence == 10 flag bytes -->
|
||||
<!-- STAIRSTEP image is 1728x1728 pixels. Its is about 15k, so an average of 68.2 bits per row. To
|
||||
cook it as a 31k page requires a min_bits of 141. To cook it as a 63k page requires a min_bits of
|
||||
286. To cook it as a 64k page requires a min_bits of 291 -->
|
||||
</messages>
|
||||
<test-group name="Supplementary">
|
||||
<test name="PPS-MPS-lost-PPS">
|
||||
<!-- Tester calls DUT and sends one 31k byte STAIRSTEP page and one 15k byte STAIRSTEP page. -->
|
||||
<step type="CALL"/>
|
||||
|
||||
<!--<step dir="T" type="CNG"/>-->
|
||||
|
||||
<step dir="R" type="CED"/>
|
||||
<step dir="R" type="HDLC" modem="V.21" tag="DIS" value="FF C8 01 ..." timeout="60000"/>
|
||||
<step dir="R" type="SILENCE"/>
|
||||
|
||||
<step type="WAIT" value="75"/>
|
||||
<step dir="T" type="PREAMBLE" modem="V.21"/>
|
||||
<step dir="T" type="HDLC" tag="DCS" value="FF C8 41 00 50 1F 30"/>
|
||||
<step dir="T" type="POSTAMBLE"/>
|
||||
<step type="WAIT" value="75"/>
|
||||
<step dir="T" type="TCF" modem="V.27ter/4800" value="900"/>
|
||||
|
||||
<step dir="R" type="HDLC" modem="V.21" tag="CFR" value="FF C8 21"/>
|
||||
<step dir="R" type="SILENCE"/>
|
||||
|
||||
<step type="WAIT" value="75"/>
|
||||
<step dir="T" type="PREAMBLE" modem="V.27ter/4800"/>
|
||||
<step dir="T" type="PP" value="etsi_300_242_a4_stairstep.tif" min_bits="141"/>
|
||||
<step dir="T" type="POSTAMBLE"/>
|
||||
<step type="WAIT" value="75"/>
|
||||
<step dir="T" type="PREAMBLE" modem="V.21"/>
|
||||
<step dir="T" type="HDLC" tag="PPS-NULL" value="FF C8 7D 00 00 00 08"/>
|
||||
<step dir="T" type="POSTAMBLE"/>
|
||||
|
||||
<step dir="R" type="HDLC" modem="V.21" tag="MCF" value="FF C8 31"/>
|
||||
<step dir="R" type="SILENCE"/>
|
||||
|
||||
<step type="WAIT" value="75"/>
|
||||
<step dir="T" type="PREAMBLE" modem="V.27ter/4800"/>
|
||||
<step dir="T" type="PP" value="etsi_300_242_a4_stairstep.tif"/>
|
||||
<step dir="T" type="POSTAMBLE"/>
|
||||
<step type="WAIT" value="75"/>
|
||||
<step dir="T" type="PREAMBLE" modem="V.21"/>
|
||||
<step dir="T" type="HDLC" tag="PPS-MPS" value="FF C8 7D 72 00 80 08"/>
|
||||
<step dir="T" type="POSTAMBLE"/>
|
||||
|
||||
<step dir="R" type="HDLC" modem="V.21" tag="MCF" value="FF C8 31"/>
|
||||
<step dir="R" type="SILENCE"/>
|
||||
|
||||
<!-- Repeat the last chunk, as though we missed the MCF -->
|
||||
<step type="WAIT" value="75"/>
|
||||
<step dir="T" type="PREAMBLE" modem="V.27ter/4800"/>
|
||||
<step dir="T" type="PP" value="etsi_300_242_a4_stairstep.tif"/>
|
||||
<step dir="T" type="POSTAMBLE"/>
|
||||
<step type="WAIT" value="75"/>
|
||||
<step dir="T" type="PREAMBLE" modem="V.21"/>
|
||||
<step dir="T" type="HDLC" tag="PPS-MPS" value="FF C8 7D 72 00 80 08"/>
|
||||
<step dir="T" type="POSTAMBLE"/>
|
||||
|
||||
<step dir="R" type="HDLC" modem="V.21" tag="MCF" value="FF C8 31"/>
|
||||
<step dir="R" type="SILENCE"/>
|
||||
|
||||
<step type="WAIT" value="75"/>
|
||||
<step dir="T" type="PREAMBLE" modem="V.27ter/4800"/>
|
||||
<step dir="T" type="PP" value="etsi_300_242_a4_white.tif"/>
|
||||
<step dir="T" type="POSTAMBLE"/>
|
||||
<step type="WAIT" value="75"/>
|
||||
<step dir="T" type="PREAMBLE" modem="V.21"/>
|
||||
<step dir="T" type="HDLC" tag="PPS-MPS" value="FF C8 7D 72 80 00 08"/>
|
||||
<step dir="T" type="POSTAMBLE"/>
|
||||
|
||||
<step dir="R" type="HDLC" modem="V.21" tag="MCF" value="FF C8 31"/>
|
||||
<step dir="R" type="SILENCE"/>
|
||||
|
||||
<step type="WAIT" value="75"/>
|
||||
<step dir="T" type="PREAMBLE" modem="V.21"/>
|
||||
<step dir="T" type="HDLC" tag="DCN" value="FF C8 5F"/>
|
||||
<step dir="T" type="POSTAMBLE"/>
|
||||
</test>
|
||||
</test-group>
|
||||
</fax-tests>
|
466
libs/spandsp/src/image_translate.c
Normal file
466
libs/spandsp/src/image_translate.c
Normal file
@ -0,0 +1,466 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* image_translate.c - Image translation routines for reworking colour
|
||||
* and gray scale images to be bi-level images of an
|
||||
* appropriate size to be FAX compatible.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 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 */
|
||||
|
||||
#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 <assert.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/fast_convert.h"
|
||||
#include "spandsp/logging.h"
|
||||
#include "spandsp/saturated.h"
|
||||
#include "spandsp/t4_rx.h"
|
||||
#include "spandsp/t4_tx.h"
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/t81_t82_arith_coding.h"
|
||||
#include "spandsp/t85.h"
|
||||
#endif
|
||||
#include "spandsp/t4_t6_decode.h"
|
||||
#include "spandsp/t4_t6_encode.h"
|
||||
#include "spandsp/image_translate.h"
|
||||
|
||||
#include "spandsp/private/logging.h"
|
||||
#if defined(SPANDSP_SUPPORT_T85)
|
||||
#include "spandsp/private/t81_t82_arith_coding.h"
|
||||
#include "spandsp/private/t85.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"
|
||||
#include "spandsp/private/image_translate.h"
|
||||
|
||||
static int image_colour16_to_gray8_row(uint8_t mono[], uint16_t colour[], int pixels)
|
||||
{
|
||||
int i;
|
||||
uint32_t gray;
|
||||
|
||||
for (i = 0; i < pixels; i++)
|
||||
{
|
||||
gray = colour[3*i]*19595 + colour[3*i + 1]*38469 + colour[3*i + 2]*7472;
|
||||
mono[i] = saturateu8(gray >> 24);
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int image_colour8_to_gray8_row(uint8_t mono[], uint8_t colour[], int pixels)
|
||||
{
|
||||
int i;
|
||||
uint32_t gray;
|
||||
|
||||
for (i = 0; i < pixels; i++)
|
||||
{
|
||||
gray = colour[3*i]*19595 + colour[3*i + 1]*38469 + colour[3*i + 2]*7472;
|
||||
mono[i] = saturateu8(gray >> 16);
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int image_gray16_to_gray8_row(uint8_t mono[], uint16_t gray[], int pixels)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pixels; i++)
|
||||
mono[i] = gray[i] >> 8;
|
||||
return pixels;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int get_and_scrunch_row(image_translate_state_t *s, uint8_t buf[], size_t len)
|
||||
{
|
||||
int row_len;
|
||||
|
||||
row_len = (*s->row_read_handler)(s->row_read_user_data, buf, s->input_width*s->bytes_per_pixel);
|
||||
if (row_len != s->input_width*s->bytes_per_pixel)
|
||||
return 0;
|
||||
/* Scrunch colour down to gray, and scrunch 16 bit pixels down to 8 bit pixels */
|
||||
switch (s->input_format)
|
||||
{
|
||||
case IMAGE_TRANSLATE_FROM_GRAY_16:
|
||||
image_gray16_to_gray8_row(buf, (uint16_t *) buf, s->input_width);
|
||||
break;
|
||||
case IMAGE_TRANSLATE_FROM_COLOUR_16:
|
||||
image_colour16_to_gray8_row(buf, (uint16_t *) buf, s->input_width);
|
||||
break;
|
||||
case IMAGE_TRANSLATE_FROM_COLOUR_8:
|
||||
image_colour8_to_gray8_row(buf, buf, s->input_width);
|
||||
break;
|
||||
}
|
||||
return row_len;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int image_resize_row(image_translate_state_t *s, uint8_t buf[], size_t len)
|
||||
{
|
||||
int i;
|
||||
int output_width;
|
||||
int output_length;
|
||||
int input_width;
|
||||
int input_length;
|
||||
double c1;
|
||||
double c2;
|
||||
double int_part;
|
||||
int x;
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
int frac_row;
|
||||
int frac_col;
|
||||
#else
|
||||
double frac_row;
|
||||
double frac_col;
|
||||
#endif
|
||||
int row_len;
|
||||
int skip;
|
||||
uint8_t *p;
|
||||
|
||||
if (s->raw_output_row < 0)
|
||||
return 0;
|
||||
output_width = s->output_width - 1;
|
||||
output_length = s->output_length - 1;
|
||||
input_width = s->input_width - 1;
|
||||
input_length = s->input_length - 1;
|
||||
|
||||
skip = s->raw_output_row*input_length/output_length;
|
||||
if (skip >= s->raw_input_row)
|
||||
{
|
||||
skip++;
|
||||
while (skip >= s->raw_input_row)
|
||||
{
|
||||
if (s->raw_input_row >= s->input_length)
|
||||
{
|
||||
s->raw_output_row = -1;
|
||||
break;
|
||||
}
|
||||
row_len = get_and_scrunch_row(s, s->raw_pixel_row[0], s->input_width*s->bytes_per_pixel);
|
||||
if (row_len != s->input_width*s->bytes_per_pixel)
|
||||
{
|
||||
s->raw_output_row = -1;
|
||||
return 0;
|
||||
}
|
||||
s->raw_input_row++;
|
||||
p = s->raw_pixel_row[0];
|
||||
s->raw_pixel_row[0] = s->raw_pixel_row[1];
|
||||
s->raw_pixel_row[1] = p;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
frac_row = s->raw_output_row*input_length/output_length;
|
||||
frac_row = s->raw_output_row*input_length - frac_row*output_length;
|
||||
for (i = 0; i < output_width; i++)
|
||||
{
|
||||
x = i*input_width/output_width;
|
||||
frac_col = x - x*output_width;
|
||||
c1 = s->raw_pixel_row[0][x] + (s->raw_pixel_row[0][x + 1] - s->raw_pixel_row[0][x])*frac_col;
|
||||
c1 = s->raw_pixel_row[1][x] + (s->raw_pixel_row[1][x + 1] - s->raw_pixel_row[1][x])*frac_col;
|
||||
buf[i] = saturateu8(c1 + (c2 - c1)*frac_row);
|
||||
}
|
||||
#else
|
||||
frac_row = modf((double) s->raw_output_row*input_length/output_length, &int_part);
|
||||
for (i = 0; i < output_width; i++)
|
||||
{
|
||||
frac_col = modf((double) i*input_width/output_width, &int_part);
|
||||
x = int_part;
|
||||
c1 = s->raw_pixel_row[0][x] + (s->raw_pixel_row[0][x + 1] - s->raw_pixel_row[0][x])*frac_col;
|
||||
c2 = s->raw_pixel_row[1][x] + (s->raw_pixel_row[1][x + 1] - s->raw_pixel_row[1][x])*frac_col;
|
||||
buf[i] = saturateu8(c1 + (c2 - c1)*frac_row);
|
||||
}
|
||||
#endif
|
||||
if (++s->raw_output_row >= s->output_length)
|
||||
s->raw_output_row = -1;
|
||||
return len;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static __inline__ uint8_t find_closest_palette_color(int in)
|
||||
{
|
||||
return (in >= 128) ? 255 : 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) image_translate_row(image_translate_state_t *s, uint8_t buf[], size_t len)
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int i;
|
||||
int j;
|
||||
int limit;
|
||||
int old_pixel;
|
||||
int new_pixel;
|
||||
int quant_error;
|
||||
uint8_t *p;
|
||||
uint8_t xx;
|
||||
|
||||
if (s->output_row < 0)
|
||||
return 0;
|
||||
y = s->output_row++;
|
||||
/* This algorithm works over two rows, and outputs the earlier of the two. To
|
||||
make this work:
|
||||
- At row 0 we grab and scrunch two rows.
|
||||
- From row 1 up to the last row we grab one new additional row each time.
|
||||
- At the last row we dither and output, without getting an extra row in. */
|
||||
for (i = (y == 0) ? 0 : 1; i < 2; i++)
|
||||
{
|
||||
p = s->pixel_row[0];
|
||||
s->pixel_row[0] = s->pixel_row[1];
|
||||
s->pixel_row[1] = p;
|
||||
|
||||
/* If this is the end of the image just ignore that there is now rubbish in pixel_row[1].
|
||||
Mark that the end has occurred. This row will be properly output, and the next one
|
||||
will fail, with the end of image condition (i.e. returning zero length) */
|
||||
if (s->resize)
|
||||
{
|
||||
if (image_resize_row(s, s->pixel_row[1], s->output_width*s->bytes_per_pixel) != s->output_width*s->bytes_per_pixel)
|
||||
s->output_row = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (get_and_scrunch_row(s, s->pixel_row[1], s->output_width*s->bytes_per_pixel) != s->output_width*s->bytes_per_pixel)
|
||||
s->output_row = -1;
|
||||
}
|
||||
}
|
||||
/* Apply Floyd-Steinberg dithering to the 8 bit pixels, using a bustrophodontic
|
||||
scan, to reduce the grayscale image to pure black and white */
|
||||
/* The first and last pixels in each row need special treatment, so we do not
|
||||
step outside the row. */
|
||||
if ((y & 1))
|
||||
{
|
||||
x = s->output_width - 1;
|
||||
old_pixel = s->pixel_row[0][x];
|
||||
new_pixel = find_closest_palette_color(old_pixel);
|
||||
quant_error = old_pixel - new_pixel;
|
||||
s->pixel_row[0][x + 0] = new_pixel;
|
||||
s->pixel_row[0][x - 1] = saturateu8(s->pixel_row[0][x - 1] + (7*quant_error)/16);
|
||||
s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16);
|
||||
s->pixel_row[1][x - 1] = saturateu8(s->pixel_row[1][x - 1] + (1*quant_error)/16);
|
||||
for ( ; x > 0; x--)
|
||||
{
|
||||
old_pixel = s->pixel_row[0][x];
|
||||
new_pixel = find_closest_palette_color(old_pixel);
|
||||
quant_error = old_pixel - new_pixel;
|
||||
s->pixel_row[0][x + 0] = new_pixel;
|
||||
s->pixel_row[0][x - 1] = saturateu8(s->pixel_row[0][x - 1] + (7*quant_error)/16);
|
||||
s->pixel_row[1][x + 1] = saturateu8(s->pixel_row[1][x + 1] + (3*quant_error)/16);
|
||||
s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16);
|
||||
s->pixel_row[1][x - 1] = saturateu8(s->pixel_row[1][x - 1] + (1*quant_error)/16);
|
||||
}
|
||||
old_pixel = s->pixel_row[0][x];
|
||||
new_pixel = find_closest_palette_color(old_pixel);
|
||||
quant_error = old_pixel - new_pixel;
|
||||
s->pixel_row[0][x + 0] = new_pixel;
|
||||
s->pixel_row[1][x + 1] = saturateu8(s->pixel_row[1][x + 1] + (3*quant_error)/16);
|
||||
s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16);
|
||||
}
|
||||
else
|
||||
{
|
||||
x = 0;
|
||||
old_pixel = s->pixel_row[0][x];
|
||||
new_pixel = find_closest_palette_color(old_pixel);
|
||||
quant_error = old_pixel - new_pixel;
|
||||
s->pixel_row[0][x + 0] = new_pixel;
|
||||
s->pixel_row[0][x + 1] = saturateu8(s->pixel_row[0][x + 1] + (7*quant_error)/16);
|
||||
s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16);
|
||||
s->pixel_row[1][x + 1] = saturateu8(s->pixel_row[1][x + 1] + (1*quant_error)/16);
|
||||
for ( ; x < s->output_width - 1; x++)
|
||||
{
|
||||
old_pixel = s->pixel_row[0][x];
|
||||
new_pixel = find_closest_palette_color(old_pixel);
|
||||
quant_error = old_pixel - new_pixel;
|
||||
s->pixel_row[0][x + 0] = new_pixel;
|
||||
s->pixel_row[0][x + 1] = saturateu8(s->pixel_row[0][x + 1] + (7*quant_error)/16);
|
||||
s->pixel_row[1][x - 1] = saturateu8(s->pixel_row[1][x - 1] + (3*quant_error)/16);
|
||||
s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16);
|
||||
s->pixel_row[1][x + 1] = saturateu8(s->pixel_row[1][x + 1] + (1*quant_error)/16);
|
||||
}
|
||||
old_pixel = s->pixel_row[0][x];
|
||||
new_pixel = find_closest_palette_color(old_pixel);
|
||||
quant_error = old_pixel - new_pixel;
|
||||
s->pixel_row[0][x + 0] = new_pixel;
|
||||
s->pixel_row[1][x - 1] = saturateu8(s->pixel_row[1][x - 1] + (3*quant_error)/16);
|
||||
s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16);
|
||||
}
|
||||
/* Now bit pack the pixel per byte row into a pixel per bit row. */
|
||||
for (i = 0, x = 0; x < s->output_width; i++, x += 8)
|
||||
{
|
||||
xx = 0;
|
||||
/* Allow for the possibility that the width is not a multiple of 8 */
|
||||
limit = (8 <= s->output_width - x) ? 8 : (s->output_width - x);
|
||||
for (j = 0; j < limit; j++)
|
||||
{
|
||||
if (s->pixel_row[0][x + j] <= 128)
|
||||
xx |= (1 << (7 - j));
|
||||
}
|
||||
buf[i] = xx;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) image_translate_get_output_width(image_translate_state_t *s)
|
||||
{
|
||||
return s->output_width;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) image_translate_get_output_length(image_translate_state_t *s)
|
||||
{
|
||||
return s->output_length;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_state_t *s,
|
||||
int input_format,
|
||||
int input_width,
|
||||
int input_length,
|
||||
int output_width,
|
||||
t4_row_read_handler_t row_read_handler,
|
||||
void *row_read_user_data)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (image_translate_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
s->input_format = input_format;
|
||||
|
||||
s->input_width = input_width;
|
||||
s->input_length = input_length;
|
||||
|
||||
s->resize = (output_width > 0);
|
||||
s->output_width = (s->resize) ? output_width : s->input_width;
|
||||
s->output_length = (s->resize) ? s->input_length*s->output_width/s->input_width : s->input_length;
|
||||
|
||||
switch (s->input_format)
|
||||
{
|
||||
case IMAGE_TRANSLATE_FROM_GRAY_8:
|
||||
s->bytes_per_pixel = 1;
|
||||
break;
|
||||
case IMAGE_TRANSLATE_FROM_GRAY_16:
|
||||
s->bytes_per_pixel = 2;
|
||||
break;
|
||||
case IMAGE_TRANSLATE_FROM_COLOUR_8:
|
||||
s->bytes_per_pixel = 3;
|
||||
break;
|
||||
case IMAGE_TRANSLATE_FROM_COLOUR_16:
|
||||
s->bytes_per_pixel = 6;
|
||||
break;
|
||||
default:
|
||||
s->bytes_per_pixel = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Allocate the two row buffers we need, using the space requirements we now have */
|
||||
if (s->resize)
|
||||
{
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
if ((s->raw_pixel_row[i] = (uint8_t *) malloc(s->input_width*s->bytes_per_pixel)) == NULL)
|
||||
return NULL;
|
||||
memset(s->raw_pixel_row[i], 0, s->input_width*s->bytes_per_pixel);
|
||||
if ((s->pixel_row[i] = (uint8_t *) malloc(s->output_width*sizeof(uint8_t))) == NULL)
|
||||
return NULL;
|
||||
memset(s->pixel_row[i], 0, s->output_width*sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
if ((s->pixel_row[i] = (uint8_t *) malloc(s->output_width*s->bytes_per_pixel)) == NULL)
|
||||
return NULL;
|
||||
memset(s->pixel_row[i], 0, s->output_width*s->bytes_per_pixel);
|
||||
}
|
||||
}
|
||||
|
||||
s->row_read_handler = row_read_handler;
|
||||
s->row_read_user_data = row_read_user_data;
|
||||
|
||||
s->raw_input_row = 0;
|
||||
s->raw_output_row = 0;
|
||||
s->output_row = 0;
|
||||
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) image_translate_release(image_translate_state_t *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
if (s->raw_pixel_row[i])
|
||||
{
|
||||
free(s->raw_pixel_row[i]);
|
||||
s->raw_pixel_row[i] = NULL;
|
||||
}
|
||||
if (s->pixel_row[i])
|
||||
{
|
||||
free(s->pixel_row[i]);
|
||||
s->pixel_row[i] = NULL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) image_translate_free(image_translate_state_t *s)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = image_translate_release(s);
|
||||
free(s);
|
||||
return res;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
108
libs/spandsp/src/spandsp/image_translate.h
Normal file
108
libs/spandsp/src/spandsp/image_translate.h
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* image_translate.h - Image translation routines for reworking colour
|
||||
* and gray scale images to be bi-level images of an
|
||||
* appropriate size to be FAX compatible.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 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 Lesser General Public License version 2.1,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if !defined(_SPANDSP_IMAGE_TRANSLATE_H_)
|
||||
#define _SPANDSP_IMAGE_TRANSLATE_H_
|
||||
|
||||
/*! \page image_translate_page Image translation
|
||||
\section image_translate_page_sec_1 What does it do?
|
||||
|
||||
\section image_translate_page_sec_2 How does it work?
|
||||
|
||||
\section image_translate_page_sec_3 How do I use it?
|
||||
*/
|
||||
|
||||
typedef struct image_translate_state_s image_translate_state_t;
|
||||
|
||||
enum
|
||||
{
|
||||
IMAGE_TRANSLATE_FROM_MONO = 1,
|
||||
IMAGE_TRANSLATE_FROM_GRAY_8 = 2,
|
||||
IMAGE_TRANSLATE_FROM_GRAY_16 = 3,
|
||||
IMAGE_TRANSLATE_FROM_COLOUR_8 = 4,
|
||||
IMAGE_TRANSLATE_FROM_COLOUR_16 = 5
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/*! \brief Get the next row of a translated image.
|
||||
\param s The image translation context.
|
||||
\return the length of the row buffer, in bytes */
|
||||
SPAN_DECLARE(int) image_translate_row(image_translate_state_t *s, uint8_t buf[], size_t len);
|
||||
|
||||
/*! \brief Get the width of the image being produced by an image translation context.
|
||||
\param s The image translation context.
|
||||
\return The width of the output image, in pixel. */
|
||||
SPAN_DECLARE(int) image_translate_get_output_width(image_translate_state_t *s);
|
||||
|
||||
/*! \brief Get the length of the image being produced by an image translation context.
|
||||
\param s The image translation context.
|
||||
\return The length of the output image, in pixel. */
|
||||
SPAN_DECLARE(int) image_translate_get_output_length(image_translate_state_t *s);
|
||||
|
||||
/*! \brief Initialise an image translation context for rescaling and squashing a gray scale
|
||||
or colour image to a bi-level FAX type image.
|
||||
\param s The image translation context.
|
||||
\param input_format x
|
||||
\param input_width The width of the source image, in pixels.
|
||||
\param input_length The length of the source image, in pixels.
|
||||
\param output_width The width of the output image, in pixels. The length of the output image
|
||||
will be derived automatically from this and the source image dimension, to main the
|
||||
geometry of the original image.
|
||||
\param row_read_handler A callback routine used to pull rows of pixels from the source image
|
||||
into the translation process.
|
||||
\param row_read_user_data An opaque point passed to read_row_handler
|
||||
\return A pointer to the context, or NULL if there was a problem. */
|
||||
SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_state_t *s,
|
||||
int input_format,
|
||||
int input_width,
|
||||
int input_length,
|
||||
int output_width,
|
||||
t4_row_read_handler_t row_read_handler,
|
||||
void *row_read_user_data);
|
||||
|
||||
/*! \brief Release the resources associated with an image translation context.
|
||||
\param s The image translation context.
|
||||
\return 0 for success, otherwise -1. */
|
||||
SPAN_DECLARE(int) image_translate_release(image_translate_state_t *s);
|
||||
|
||||
/*! \brief Free the resources associated with an image translation context.
|
||||
\param s The image translation context.
|
||||
\return 0 for success, otherwise -1. */
|
||||
SPAN_DECLARE(int) image_translate_free(image_translate_state_t *s);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
52
libs/spandsp/src/spandsp/private/image_translate.h
Normal file
52
libs/spandsp/src/spandsp/private/image_translate.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* private/image_translate.c - Image translation routines for reworking colour
|
||||
* and gray scale images to be bi-level images of an
|
||||
* appropriate size to be FAX compatible.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 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 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.
|
||||
*/
|
||||
|
||||
#if !defined(_SPANDSP_PRIVATE_IMAGE_TRANSLATE_H_)
|
||||
#define _SPANDSP_PRIVATE_IMAGE_TRANSLATE_H_
|
||||
|
||||
struct image_translate_state_s
|
||||
{
|
||||
int input_format;
|
||||
int input_width;
|
||||
int input_length;
|
||||
int output_width;
|
||||
int output_length;
|
||||
int resize;
|
||||
int bytes_per_pixel;
|
||||
int raw_input_row;
|
||||
int raw_output_row;
|
||||
int output_row;
|
||||
|
||||
uint8_t *raw_pixel_row[2];
|
||||
uint8_t *pixel_row[2];
|
||||
|
||||
t4_row_read_handler_t row_read_handler;
|
||||
void *row_read_user_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
101
libs/spandsp/src/spandsp/private/t4_t6_decode.h
Normal file
101
libs/spandsp/src/spandsp/private/t4_t6_decode.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* private/t4_t6_decode.h - definitions for T.4/T.6 fax decoding
|
||||
*
|
||||
* 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 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.
|
||||
*/
|
||||
|
||||
#if !defined(_SPANDSP_PRIVATE_T4_T6_DECODE_H_)
|
||||
#define _SPANDSP_PRIVATE_T4_T6_DECODE_H_
|
||||
|
||||
/*!
|
||||
T.4 1D, T4 2D and T6 decompressor state.
|
||||
*/
|
||||
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 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
|
||||
1D and 2D decoding, as an indicator that we must wait for the first EOL,
|
||||
before decoding any image data. */
|
||||
int consecutive_eols;
|
||||
|
||||
/*! \brief The reference or starting changing element on the coding line. At the
|
||||
start of the coding line, a0 is set on an imaginary white changing element
|
||||
situated just before the first element on the line. During the coding of
|
||||
the coding line, the position of a0 is defined by the previous coding mode.
|
||||
(See T.4/4.2.1.3.2.). */
|
||||
int a0;
|
||||
/*! \brief The first changing element on the reference line to the right of a0 and of
|
||||
opposite colour to a0. */
|
||||
int b1;
|
||||
/*! \brief The length of the in-progress run of black or white. */
|
||||
int run_length;
|
||||
/*! \brief 2D horizontal mode control. */
|
||||
int black_white;
|
||||
/*! \brief TRUE if the current run is black */
|
||||
int its_black;
|
||||
|
||||
/*! \brief The current step into the current row run-lengths buffer. */
|
||||
int a_cursor;
|
||||
/*! \brief The current step into the reference row run-lengths buffer. */
|
||||
int b_cursor;
|
||||
|
||||
/*! \brief Incoming bit buffer for decompression. */
|
||||
uint32_t rx_bitstream;
|
||||
/*! \brief The number of bits currently in rx_bitstream. */
|
||||
int rx_bits;
|
||||
/*! \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 Current pixel row number. */
|
||||
//int row;
|
||||
|
||||
/*! \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. */
|
||||
int longest_bad_row_run;
|
||||
/*! \brief The total number of bad rows in the current page. */
|
||||
int bad_rows;
|
||||
|
||||
/*! \brief Error and flow logging control */
|
||||
//logging_state_t logging;
|
||||
};
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
59
libs/spandsp/src/spandsp/private/t4_t6_encode.h
Normal file
59
libs/spandsp/src/spandsp/private/t4_t6_encode.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* private/t4_t6_encode.h - definitions for T.4/T.6 fax compression
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2003 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.
|
||||
*/
|
||||
|
||||
#if !defined(_SPANDSP_PRIVATE_T4_T6_ENCODE_H_)
|
||||
#define _SPANDSP_PRIVATE_T4_T6_ENCODE_H_
|
||||
|
||||
/*!
|
||||
T.4 1D, T4 2D and T6 compressor state.
|
||||
*/
|
||||
struct t4_t6_encode_state_s
|
||||
{
|
||||
/*! \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 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 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 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;
|
||||
};
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
90
libs/spandsp/src/spandsp/private/timezone.h
Normal file
90
libs/spandsp/src/spandsp/private/timezone.h
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* private/timezone.h - Timezone handling for time interpretation
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
#if !defined(_SPANDSP_PRIVATE_TIMEZONE_H_)
|
||||
#define _SPANDSP_PRIVATE_TIMEZONE_H_
|
||||
|
||||
#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
|
||||
|
||||
#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
|
||||
|
||||
#define TZNAME_MAX 255
|
||||
|
||||
/* The TZ_MAX_TIMES value below is enough to handle a bit more than a
|
||||
* year's worth of solar time (corrected daily to the nearest second) or
|
||||
* 138 years of Pacific Presidential Election time
|
||||
* (where there are three time zone transitions every fourth year). */
|
||||
#define TZ_MAX_TIMES 370
|
||||
|
||||
#if !defined(NOSOLAR)
|
||||
#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
|
||||
#else
|
||||
/* Must be at least 14 for Europe/Riga as of Jan 12 1995,
|
||||
* as noted by Earl Chew <earl@hpato.aus.hp.com>. */
|
||||
#define TZ_MAX_TYPES 20 /* Maximum number of local time types */
|
||||
#endif
|
||||
|
||||
#define TZ_BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
/* Time type information */
|
||||
struct tz_ttinfo_s
|
||||
{
|
||||
int32_t gmtoff; /* UTC offset in seconds */
|
||||
int isdst; /* Used to set tm_isdst */
|
||||
int abbrind; /* Abbreviation list index */
|
||||
int ttisstd; /* TRUE if transition is std time */
|
||||
int ttisgmt; /* TRUE if transition is UTC */
|
||||
};
|
||||
|
||||
/* Leap second information */
|
||||
struct tz_lsinfo_s
|
||||
{
|
||||
time_t trans; /* Transition time */
|
||||
int32_t corr; /* Correction to apply */
|
||||
};
|
||||
|
||||
struct tz_state_s
|
||||
{
|
||||
int leapcnt;
|
||||
int timecnt;
|
||||
int typecnt;
|
||||
int charcnt;
|
||||
time_t ats[TZ_MAX_TIMES];
|
||||
uint8_t types[TZ_MAX_TIMES];
|
||||
struct tz_ttinfo_s ttis[TZ_MAX_TYPES];
|
||||
char chars[TZ_BIGGEST(TZ_MAX_CHARS + 1, (2*(TZNAME_MAX + 1)))];
|
||||
struct tz_lsinfo_s lsis[TZ_MAX_LEAPS];
|
||||
};
|
||||
|
||||
struct tz_s
|
||||
{
|
||||
struct tz_state_s state;
|
||||
char lcl_tzname[TZNAME_MAX + 1];
|
||||
int lcl_is_set;
|
||||
const char *tzname[2];
|
||||
};
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
53
libs/spandsp/src/spandsp/t4_t6_decode.h
Normal file
53
libs/spandsp/src/spandsp/t4_t6_decode.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* t4_t6_decode.h - definitions for T.4/T.6 fax decoding
|
||||
*
|
||||
* 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 Lesser General Public License version 2.1,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if !defined(_SPANDSP_T4_T6_DECODE_H_)
|
||||
#define _SPANDSP_T4_T6_DECODE_H_
|
||||
|
||||
/*! \page t4_t6_decode_page T.4 and T.6 FAX image decompression
|
||||
|
||||
\section t4_t6_decode_page_sec_1 What does it do?
|
||||
The T.4 image compression and decompression routines implement the 1D and 2D
|
||||
encoding methods defined in ITU specification T.4. They also implement the pure
|
||||
2D encoding method defined in T.6. These are image compression algorithms used
|
||||
for FAX transmission.
|
||||
|
||||
\section t4_t6_decode_page_sec_1 How does it work?
|
||||
*/
|
||||
|
||||
typedef struct t4_t6_decode_state_s t4_t6_decode_state_t;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
42
libs/spandsp/src/spandsp/t4_t6_encode.h
Normal file
42
libs/spandsp/src/spandsp/t4_t6_encode.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* t4_t6_encode.h - definitions for T.4/T.6 fax encoding
|
||||
*
|
||||
* 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 Lesser General Public License version 2.1,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if !defined(_SPANDSP_T4_T6_ENCODE_H_)
|
||||
#define _SPANDSP_T4_T6_ENCODE_H_
|
||||
|
||||
typedef struct t4_t6_encode_state_s t4_t6_encode_state_t;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
88
libs/spandsp/src/spandsp/timezone.h
Normal file
88
libs/spandsp/src/spandsp/timezone.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* timezone.h - Timezone handling for time interpretation
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2010 Steve Underwood
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if !defined(_SPANDSP_TIMEZONE_H_)
|
||||
#define _SPANDSP_TIMEZONE_H_
|
||||
|
||||
/*! \page timezone_page Timezone handling
|
||||
|
||||
\section timezone_sec_1 What does it do?
|
||||
|
||||
\section timezone_sec_2 How does it work?
|
||||
|
||||
*/
|
||||
|
||||
typedef struct tz_s tz_t;
|
||||
|
||||
enum
|
||||
{
|
||||
TM_SUNDAY = 0,
|
||||
TM_MONDAY,
|
||||
TM_TUESDAY,
|
||||
TM_WEDNESDAY,
|
||||
TM_THURSDAY,
|
||||
TM_FRIDAY,
|
||||
TM_SATURDAY
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TM_JANUARY = 0,
|
||||
TM_FEBRUARY,
|
||||
TM_MARCH,
|
||||
TM_APRIL,
|
||||
TM_MAY,
|
||||
TM_JUNE,
|
||||
TM_JULY,
|
||||
TM_AUGUST,
|
||||
TM_SEPTEMBER,
|
||||
TM_OCTOBER,
|
||||
TM_NOVEMBER,
|
||||
TM_DECEMBER
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
SPAN_DECLARE(tz_t *) tz_init(tz_t *tz, const char *tzstring);
|
||||
|
||||
SPAN_DECLARE(int) tz_release(tz_t *tz);
|
||||
|
||||
SPAN_DECLARE(int) tz_free(tz_t *tz);
|
||||
|
||||
SPAN_DECLARE(int) tz_localtime(tz_t *tz, struct tm *tm, time_t t);
|
||||
|
||||
SPAN_DECLARE(const char *) tz_tzname(tz_t *tz, int isdst);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
822
libs/spandsp/src/timezone.c
Normal file
822
libs/spandsp/src/timezone.c
Normal file
@ -0,0 +1,822 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* timezone.c - Timezone handling for time interpretation
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2010 Steve Underwood
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
/* Timezone processing might not seem like a DSP activity, but getting the headers
|
||||
right on FAXes demands it. We need to handle multiple time zones within a process,
|
||||
for FAXes related to different parts of the globe, so the system timezone handling
|
||||
is not adequate. */
|
||||
|
||||
/* This timezone handling is derived from public domain software by Arthur David Olson
|
||||
<arthur_david_olson@nih.gov> which you may download from ftp://elsie.nci.nih.gov/pub
|
||||
at the time of writing. */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "spandsp/telephony.h"
|
||||
#include "spandsp/timezone.h"
|
||||
|
||||
#include "spandsp/private/timezone.h"
|
||||
|
||||
#if !defined(FALSE)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#if !defined(TRUE)
|
||||
#define TRUE (!FALSE)
|
||||
#endif
|
||||
|
||||
#define SECS_PER_MIN 60
|
||||
#define MINS_PER_HOUR 60
|
||||
#define HOURS_PER_DAY 24
|
||||
#define DAYS_PER_WEEK 7
|
||||
#define DAYS_PER_NON_LEAP_YEAR 365
|
||||
#define DAYS_PER_LEAP_YEAR 366
|
||||
#define SECS_PER_HOUR (SECS_PER_MIN*MINS_PER_HOUR)
|
||||
#define SECS_PER_DAY ((long int) SECS_PER_HOUR*HOURS_PER_DAY)
|
||||
#define MONTHS_PER_YEAR 12
|
||||
|
||||
#define TM_YEAR_BASE 1900
|
||||
|
||||
#define EPOCH_YEAR 1970
|
||||
#define EPOCH_WDAY TM_THURSDAY
|
||||
|
||||
#define isleap(y) (((y)%4) == 0 && (((y)%100) != 0 || ((y)%400) == 0))
|
||||
|
||||
#define isleap_sum(a, b) isleap((a)%400 + (b)%400)
|
||||
|
||||
/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
|
||||
#define is_digit(c) ((unsigned int) (c) - '0' <= 9)
|
||||
|
||||
#define TZ_DEF_RULE_STRING ",M4.1.0,M10.5.0"
|
||||
|
||||
#define JULIAN_DAY 0 /* Jn - Julian day */
|
||||
#define DAY_OF_YEAR 1 /* n - day of year */
|
||||
#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
|
||||
|
||||
static const char wildabbr[] = " ";
|
||||
|
||||
static const char gmt[] = "GMT";
|
||||
|
||||
struct tz_rule_s
|
||||
{
|
||||
int r_type; /* Type of rule--see below */
|
||||
int r_day; /* Day number of rule */
|
||||
int r_week; /* Week number of rule */
|
||||
int r_mon; /* Month number of rule */
|
||||
long int r_time; /* Transition time of rule */
|
||||
};
|
||||
|
||||
static const int mon_lengths[2][MONTHS_PER_YEAR] =
|
||||
{
|
||||
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
|
||||
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
|
||||
};
|
||||
|
||||
static const int year_lengths[2] =
|
||||
{
|
||||
DAYS_PER_NON_LEAP_YEAR,
|
||||
DAYS_PER_LEAP_YEAR
|
||||
};
|
||||
|
||||
static int increment_overflow(int *number, int delta)
|
||||
{
|
||||
int number0;
|
||||
|
||||
number0 = *number;
|
||||
*number += delta;
|
||||
return (*number < number0) != (delta < 0);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void set_tzname(tz_t *tz)
|
||||
{
|
||||
struct tz_state_s *sp;
|
||||
const struct tz_ttinfo_s *ttisp;
|
||||
int i;
|
||||
|
||||
sp = &tz->state;
|
||||
tz->tzname[0] = wildabbr;
|
||||
tz->tzname[1] = wildabbr;
|
||||
for (i = 0; i < sp->typecnt; i++)
|
||||
{
|
||||
ttisp = &sp->ttis[i];
|
||||
tz->tzname[ttisp->isdst] = &sp->chars[ttisp->abbrind];
|
||||
}
|
||||
for (i = 0; i < sp->timecnt; i++)
|
||||
{
|
||||
ttisp = &sp->ttis[sp->types[i]];
|
||||
tz->tzname[ttisp->isdst] = &sp->chars[ttisp->abbrind];
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
/* Return the number of leap years through the end of the given year
|
||||
where, to make the math easy, the answer for year zero is defined as zero. */
|
||||
static int leaps_thru_end_of(const int y)
|
||||
{
|
||||
return (y >= 0) ? (y/4 - y/100 + y/400) : -(leaps_thru_end_of(-(y + 1)) + 1);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static struct tm *time_sub(const time_t * const timep, const long int offset, const struct tz_state_s * const sp, struct tm * const tmp)
|
||||
{
|
||||
const struct tz_lsinfo_s *lp;
|
||||
time_t tdays;
|
||||
const int *ip;
|
||||
int32_t corr;
|
||||
int32_t seconds;
|
||||
int32_t rem;
|
||||
int idays;
|
||||
int y;
|
||||
int hit;
|
||||
int i;
|
||||
|
||||
corr = 0;
|
||||
hit = 0;
|
||||
i = sp->leapcnt;
|
||||
while (--i >= 0)
|
||||
{
|
||||
lp = &sp->lsis[i];
|
||||
if (*timep >= lp->trans)
|
||||
{
|
||||
if (*timep == lp->trans)
|
||||
{
|
||||
hit = ((i == 0 && lp->corr > 0) || lp->corr > sp->lsis[i - 1].corr);
|
||||
if (hit)
|
||||
{
|
||||
while (i > 0
|
||||
&&
|
||||
sp->lsis[i].trans == sp->lsis[i - 1].trans + 1
|
||||
&&
|
||||
sp->lsis[i].corr == sp->lsis[i - 1].corr + 1)
|
||||
{
|
||||
hit++;
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
corr = lp->corr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
y = EPOCH_YEAR;
|
||||
tdays = *timep/SECS_PER_DAY;
|
||||
rem = *timep - tdays*SECS_PER_DAY;
|
||||
while (tdays < 0 || tdays >= year_lengths[isleap(y)])
|
||||
{
|
||||
int newy;
|
||||
time_t tdelta;
|
||||
int idelta;
|
||||
int leapdays;
|
||||
|
||||
tdelta = tdays / DAYS_PER_LEAP_YEAR;
|
||||
idelta = tdelta;
|
||||
if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
|
||||
return NULL;
|
||||
if (idelta == 0)
|
||||
idelta = (tdays < 0) ? -1 : 1;
|
||||
newy = y;
|
||||
if (increment_overflow(&newy, idelta))
|
||||
return NULL;
|
||||
leapdays = leaps_thru_end_of(newy - 1) - leaps_thru_end_of(y - 1);
|
||||
tdays -= ((time_t) newy - y)*DAYS_PER_NON_LEAP_YEAR;
|
||||
tdays -= leapdays;
|
||||
y = newy;
|
||||
}
|
||||
seconds = tdays*SECS_PER_DAY;
|
||||
tdays = seconds/SECS_PER_DAY;
|
||||
rem += seconds - tdays*SECS_PER_DAY;
|
||||
/* Given the range, we can now fearlessly cast... */
|
||||
idays = tdays;
|
||||
rem += (offset - corr);
|
||||
while (rem < 0)
|
||||
{
|
||||
rem += SECS_PER_DAY;
|
||||
idays--;
|
||||
}
|
||||
while (rem >= SECS_PER_DAY)
|
||||
{
|
||||
rem -= SECS_PER_DAY;
|
||||
idays++;
|
||||
}
|
||||
while (idays < 0)
|
||||
{
|
||||
if (increment_overflow(&y, -1))
|
||||
return NULL;
|
||||
idays += year_lengths[isleap(y)];
|
||||
}
|
||||
while (idays >= year_lengths[isleap(y)])
|
||||
{
|
||||
idays -= year_lengths[isleap(y)];
|
||||
if (increment_overflow(&y, 1))
|
||||
return NULL;
|
||||
}
|
||||
tmp->tm_year = y;
|
||||
if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
|
||||
return NULL;
|
||||
tmp->tm_yday = idays;
|
||||
/* The "extra" mods below avoid overflow problems. */
|
||||
tmp->tm_wday = EPOCH_WDAY
|
||||
+ ((y - EPOCH_YEAR) % DAYS_PER_WEEK)*(DAYS_PER_NON_LEAP_YEAR % DAYS_PER_WEEK)
|
||||
+ leaps_thru_end_of(y - 1)
|
||||
- leaps_thru_end_of(EPOCH_YEAR - 1)
|
||||
+ idays;
|
||||
tmp->tm_wday %= DAYS_PER_WEEK;
|
||||
if (tmp->tm_wday < 0)
|
||||
tmp->tm_wday += DAYS_PER_WEEK;
|
||||
tmp->tm_hour = (int) (rem/SECS_PER_HOUR);
|
||||
rem %= SECS_PER_HOUR;
|
||||
tmp->tm_min = (int) (rem/SECS_PER_MIN);
|
||||
/* A positive leap second requires a special
|
||||
* representation. This uses "... ??:59:60" et seq. */
|
||||
tmp->tm_sec = (int) (rem%SECS_PER_MIN) + hit;
|
||||
ip = mon_lengths[isleap(y)];
|
||||
for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; (tmp->tm_mon)++)
|
||||
idays -= ip[tmp->tm_mon];
|
||||
tmp->tm_mday = (int) (idays + 1);
|
||||
tmp->tm_isdst = 0;
|
||||
return tmp;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
/* Given a pointer into a time zone string, scan until a character that is not
|
||||
* a valid character in a zone name is found. Return a pointer to that
|
||||
* character. */
|
||||
static const char *get_tzname(const char *strp)
|
||||
{
|
||||
char c;
|
||||
|
||||
while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && c != '+')
|
||||
strp++;
|
||||
return strp;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
/* Given a pointer into a time zone string, extract a number from that string.
|
||||
* Check that the number is within a specified range; if it is not, return
|
||||
* NULL.
|
||||
* Otherwise, return a pointer to the first character not part of the number. */
|
||||
static const char *get_num(const char *strp, int * const nump, const int min, const int max)
|
||||
{
|
||||
char c;
|
||||
int num;
|
||||
|
||||
if (strp == NULL || !is_digit(c = *strp))
|
||||
return NULL;
|
||||
num = 0;
|
||||
do
|
||||
{
|
||||
num = num*10 + (c - '0');
|
||||
if (num > max)
|
||||
return NULL; /* Illegal value */
|
||||
c = *++strp;
|
||||
}
|
||||
while (is_digit(c));
|
||||
if (num < min)
|
||||
return NULL; /* Illegal value */
|
||||
*nump = num;
|
||||
return strp;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
/* Given a pointer into a time zone string, extract a number of seconds,
|
||||
* in hh[:mm[:ss]] form, from the string.
|
||||
* If any error occurs, return NULL.
|
||||
* Otherwise, return a pointer to the first character not part of the number
|
||||
* of seconds. */
|
||||
static const char *get_secs(const char *strp, long int * const secsp)
|
||||
{
|
||||
int num;
|
||||
|
||||
/* HOURS_PER_DAY*DAYS_PER_WEEK - 1 allows quasi-Posix rules like
|
||||
* "M10.4.6/26", which does not conform to Posix,
|
||||
* but which specifies the equivalent of
|
||||
* "02:00 on the first Sunday on or after 23 Oct". */
|
||||
strp = get_num(strp, &num, 0, HOURS_PER_DAY*DAYS_PER_WEEK - 1);
|
||||
if (strp == NULL)
|
||||
return NULL;
|
||||
*secsp = num*(long int) SECS_PER_HOUR;
|
||||
if (*strp == ':')
|
||||
{
|
||||
strp = get_num(strp + 1, &num, 0, MINS_PER_HOUR - 1);
|
||||
if (strp == NULL)
|
||||
return NULL;
|
||||
*secsp += num*SECS_PER_MIN;
|
||||
if (*strp == ':')
|
||||
{
|
||||
/* SECS_PER_MIN allows for leap seconds. */
|
||||
strp = get_num(strp + 1, &num, 0, SECS_PER_MIN);
|
||||
if (strp == NULL)
|
||||
return NULL;
|
||||
*secsp += num;
|
||||
}
|
||||
}
|
||||
return strp;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
/* Given a pointer into a time zone string, extract an offset, in
|
||||
* [+-]hh[:mm[:ss]] form, from the string.
|
||||
* If any error occurs, return NULL.
|
||||
* Otherwise, return a pointer to the first character not part of the time. */
|
||||
static const char *get_offset(const char *strp, long int * const offsetp)
|
||||
{
|
||||
int neg = 0;
|
||||
|
||||
if (*strp == '-')
|
||||
{
|
||||
neg = 1;
|
||||
strp++;
|
||||
}
|
||||
else if (*strp == '+')
|
||||
{
|
||||
strp++;
|
||||
}
|
||||
strp = get_secs(strp, offsetp);
|
||||
if (strp == NULL)
|
||||
return NULL; /* Illegal time */
|
||||
if (neg)
|
||||
*offsetp = -*offsetp;
|
||||
return strp;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
/* Given a pointer into a time zone string, extract a rule in the form
|
||||
* date[/time]. See POSIX section 8 for the format of "date" and "time".
|
||||
* If a valid rule is not found, return NULL.
|
||||
* Otherwise, return a pointer to the first character not part of the rule. */
|
||||
static const char *get_rule(const char *strp, struct tz_rule_s * const rulep)
|
||||
{
|
||||
if (*strp == 'J')
|
||||
{
|
||||
/* Julian day. */
|
||||
rulep->r_type = JULIAN_DAY;
|
||||
strp = get_num(strp + 1, &rulep->r_day, 1, DAYS_PER_NON_LEAP_YEAR);
|
||||
}
|
||||
else if (*strp == 'M')
|
||||
{
|
||||
/* Month, week, day. */
|
||||
rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
|
||||
strp = get_num(strp + 1, &rulep->r_mon, 1, MONTHS_PER_YEAR);
|
||||
if (strp == NULL || *strp++ != '.')
|
||||
return NULL;
|
||||
strp = get_num(strp, &rulep->r_week, 1, 5);
|
||||
if (strp == NULL || *strp++ != '.')
|
||||
return NULL;
|
||||
strp = get_num(strp, &rulep->r_day, 0, DAYS_PER_WEEK - 1);
|
||||
}
|
||||
else if (is_digit(*strp))
|
||||
{
|
||||
/* Day of the year. */
|
||||
rulep->r_type = DAY_OF_YEAR;
|
||||
strp = get_num(strp, &rulep->r_day, 0, DAYS_PER_LEAP_YEAR - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid format */
|
||||
return NULL;
|
||||
}
|
||||
if (strp == NULL)
|
||||
return NULL;
|
||||
if (*strp == '/')
|
||||
{
|
||||
/* Time specified. */
|
||||
strp = get_secs(strp + 1, &rulep->r_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Default = 2:00:00 */
|
||||
rulep->r_time = 2*SECS_PER_HOUR;
|
||||
}
|
||||
return strp;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
/* Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
|
||||
* year, a rule, and the offset from UTC at the time that rule takes effect,
|
||||
* calculate the Epoch-relative time that rule takes effect. */
|
||||
static time_t trans_time(const time_t janfirst, const int year, const struct tz_rule_s * const rulep, const long int offset)
|
||||
{
|
||||
int leapyear;
|
||||
time_t value;
|
||||
int i;
|
||||
int d;
|
||||
int m1;
|
||||
int yy0;
|
||||
int yy1;
|
||||
int yy2;
|
||||
int dow;
|
||||
|
||||
value = 0;
|
||||
leapyear = isleap(year);
|
||||
switch (rulep->r_type)
|
||||
{
|
||||
case JULIAN_DAY:
|
||||
/* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
|
||||
* years.
|
||||
* In non-leap years, or if the day number is 59 or less, just
|
||||
* add SECS_PER_DAY times the day number-1 to the time of
|
||||
* January 1, midnight, to get the day. */
|
||||
value = janfirst + (rulep->r_day - 1)*SECS_PER_DAY;
|
||||
if (leapyear && rulep->r_day >= 60)
|
||||
value += SECS_PER_DAY;
|
||||
break;
|
||||
case DAY_OF_YEAR:
|
||||
/* n - day of year.
|
||||
* Just add SECS_PER_DAY times the day number to the time of
|
||||
* January 1, midnight, to get the day. */
|
||||
value = janfirst + rulep->r_day * SECS_PER_DAY;
|
||||
break;
|
||||
case MONTH_NTH_DAY_OF_WEEK:
|
||||
/* Mm.n.d - nth "dth day" of month m. */
|
||||
value = janfirst;
|
||||
for (i = 0; i < rulep->r_mon - 1; i++)
|
||||
value += mon_lengths[leapyear][i]*SECS_PER_DAY;
|
||||
|
||||
/* Use Zeller's Congruence to get day-of-week of first day of month. */
|
||||
m1 = (rulep->r_mon + 9)%12 + 1;
|
||||
yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
|
||||
yy1 = yy0/100;
|
||||
yy2 = yy0%100;
|
||||
dow = ((26*m1 - 2)/10 + 1 + yy2 + yy2/4 + yy1/4 - 2*yy1)%7;
|
||||
if (dow < 0)
|
||||
dow += DAYS_PER_WEEK;
|
||||
|
||||
/* "dow" is the day-of-week of the first day of the month. Get
|
||||
* the day-of-month (zero-origin) of the first "dow" day of the
|
||||
* month. */
|
||||
d = rulep->r_day - dow;
|
||||
if (d < 0)
|
||||
d += DAYS_PER_WEEK;
|
||||
for (i = 1; i < rulep->r_week; i++)
|
||||
{
|
||||
if (d + DAYS_PER_WEEK >= mon_lengths[leapyear][rulep->r_mon - 1])
|
||||
break;
|
||||
d += DAYS_PER_WEEK;
|
||||
}
|
||||
|
||||
/* "d" is the day-of-month (zero-origin) of the day we want. */
|
||||
value += d*SECS_PER_DAY;
|
||||
break;
|
||||
}
|
||||
|
||||
/* "value" is the Epoch-relative time of 00:00:00 UTC on the day in
|
||||
* question. To get the Epoch-relative time of the specified local
|
||||
* time on that day, add the transition time and the current offset
|
||||
* from UTC. */
|
||||
return value + rulep->r_time + offset;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
/* Given a POSIX section 8-style TZ string, fill in the rule tables as
|
||||
appropriate. */
|
||||
static int tzparse(const char *name, struct tz_state_s * const sp, const int lastditch)
|
||||
{
|
||||
const char *stdname;
|
||||
const char *dstname;
|
||||
size_t stdlen;
|
||||
size_t dstlen;
|
||||
long int stdoffset;
|
||||
long int dstoffset;
|
||||
long int theirstdoffset;
|
||||
long int theirdstoffset;
|
||||
long int theiroffset;
|
||||
unsigned char *typep;
|
||||
char *cp;
|
||||
int load_result;
|
||||
int isdst;
|
||||
int i;
|
||||
int j;
|
||||
int year;
|
||||
struct tz_rule_s start;
|
||||
struct tz_rule_s end;
|
||||
time_t *atp;
|
||||
time_t janfirst;
|
||||
time_t starttime;
|
||||
time_t endtime;
|
||||
|
||||
dstname = NULL;
|
||||
stdname = name;
|
||||
if (lastditch)
|
||||
{
|
||||
stdlen = strlen(name); /* Length of standard zone name */
|
||||
name += stdlen;
|
||||
if (stdlen >= sizeof(sp->chars))
|
||||
stdlen = sizeof(sp->chars) - 1;
|
||||
stdoffset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
name = get_tzname(name);
|
||||
stdlen = name - stdname;
|
||||
if (stdlen < 3)
|
||||
return -1;
|
||||
if (*name == '\0')
|
||||
return -1;
|
||||
name = get_offset(name, &stdoffset);
|
||||
if (name == NULL)
|
||||
return -1;
|
||||
}
|
||||
load_result = -1;
|
||||
if (load_result != 0)
|
||||
sp->leapcnt = 0; /* So, we're off a little */
|
||||
if (*name != '\0')
|
||||
{
|
||||
dstname = name;
|
||||
name = get_tzname(name);
|
||||
dstlen = name - dstname; /* Length of DST zone name */
|
||||
if (dstlen < 3)
|
||||
return -1;
|
||||
if (*name != '\0' && *name != ',' && *name != ';')
|
||||
{
|
||||
if ((name = get_offset(name, &dstoffset)) == NULL)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dstoffset = stdoffset - SECS_PER_HOUR;
|
||||
}
|
||||
if (*name == '\0' && load_result != 0)
|
||||
name = TZ_DEF_RULE_STRING;
|
||||
if (*name == ',' || *name == ';')
|
||||
{
|
||||
if ((name = get_rule(name + 1, &start)) == NULL)
|
||||
return -1;
|
||||
if (*name++ != ',')
|
||||
return -1;
|
||||
if ((name = get_rule(name, &end)) == NULL)
|
||||
return -1;
|
||||
if (*name != '\0')
|
||||
return -1;
|
||||
sp->typecnt = 2; /* Standard time and DST */
|
||||
/* Two transitions per year, from EPOCH_YEAR to 2037. */
|
||||
sp->timecnt = 2*(2037 - EPOCH_YEAR + 1);
|
||||
if (sp->timecnt > TZ_MAX_TIMES)
|
||||
return -1;
|
||||
sp->ttis[0].gmtoff = -dstoffset;
|
||||
sp->ttis[0].isdst = 1;
|
||||
sp->ttis[0].abbrind = stdlen + 1;
|
||||
sp->ttis[1].gmtoff = -stdoffset;
|
||||
sp->ttis[1].isdst = 0;
|
||||
sp->ttis[1].abbrind = 0;
|
||||
atp = sp->ats;
|
||||
typep = sp->types;
|
||||
janfirst = 0;
|
||||
for (year = EPOCH_YEAR; year <= 2037; year++)
|
||||
{
|
||||
starttime = trans_time(janfirst, year, &start, stdoffset);
|
||||
endtime = trans_time(janfirst, year, &end, dstoffset);
|
||||
if (starttime > endtime)
|
||||
{
|
||||
*atp++ = endtime;
|
||||
*typep++ = 1; /* DST ends */
|
||||
*atp++ = starttime;
|
||||
*typep++ = 0; /* DST begins */
|
||||
}
|
||||
else
|
||||
{
|
||||
*atp++ = starttime;
|
||||
*typep++ = 0; /* DST begins */
|
||||
*atp++ = endtime;
|
||||
*typep++ = 1; /* DST ends */
|
||||
}
|
||||
janfirst += year_lengths[isleap(year)]*SECS_PER_DAY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*name != '\0')
|
||||
return -1;
|
||||
/* Initial values of theirstdoffset and theirdstoffset. */
|
||||
theirstdoffset = 0;
|
||||
for (i = 0; i < sp->timecnt; i++)
|
||||
{
|
||||
j = sp->types[i];
|
||||
if (!sp->ttis[j].isdst)
|
||||
{
|
||||
theirstdoffset = -sp->ttis[j].gmtoff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
theirdstoffset = 0;
|
||||
for (i = 0; i < sp->timecnt; i++)
|
||||
{
|
||||
j = sp->types[i];
|
||||
if (sp->ttis[j].isdst)
|
||||
{
|
||||
theirdstoffset = -sp->ttis[j].gmtoff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Initially we're assumed to be in standard time. */
|
||||
isdst = FALSE;
|
||||
theiroffset = theirstdoffset;
|
||||
/* Now juggle transition times and types tracking offsets as you do. */
|
||||
for (i = 0; i < sp->timecnt; i++)
|
||||
{
|
||||
j = sp->types[i];
|
||||
sp->types[i] = sp->ttis[j].isdst;
|
||||
if (sp->ttis[j].ttisgmt)
|
||||
{
|
||||
/* No adjustment to transition time */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If summer time is in effect, and the
|
||||
* transition time was not specified as
|
||||
* standard time, add the summer time
|
||||
* offset to the transition time;
|
||||
* otherwise, add the standard time
|
||||
* offset to the transition time. */
|
||||
/* Transitions from DST to DDST
|
||||
* will effectively disappear since
|
||||
* POSIX provides for only one DST
|
||||
* offset. */
|
||||
if (isdst && !sp->ttis[j].ttisstd)
|
||||
sp->ats[i] += (dstoffset - theirdstoffset);
|
||||
else
|
||||
sp->ats[i] += (stdoffset - theirstdoffset);
|
||||
}
|
||||
theiroffset = -sp->ttis[j].gmtoff;
|
||||
if (sp->ttis[j].isdst)
|
||||
theirdstoffset = theiroffset;
|
||||
else
|
||||
theirstdoffset = theiroffset;
|
||||
}
|
||||
/* Finally, fill in ttis. ttisstd and ttisgmt need not be handled. */
|
||||
sp->ttis[0].gmtoff = -stdoffset;
|
||||
sp->ttis[0].isdst = FALSE;
|
||||
sp->ttis[0].abbrind = 0;
|
||||
sp->ttis[1].gmtoff = -dstoffset;
|
||||
sp->ttis[1].isdst = TRUE;
|
||||
sp->ttis[1].abbrind = stdlen + 1;
|
||||
sp->typecnt = 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dstlen = 0;
|
||||
sp->typecnt = 1; /* Only standard time */
|
||||
sp->timecnt = 0;
|
||||
sp->ttis[0].gmtoff = -stdoffset;
|
||||
sp->ttis[0].isdst = 0;
|
||||
sp->ttis[0].abbrind = 0;
|
||||
}
|
||||
sp->charcnt = stdlen + 1;
|
||||
if (dstlen != 0)
|
||||
sp->charcnt += dstlen + 1;
|
||||
if ((size_t) sp->charcnt > sizeof(sp->chars))
|
||||
return -1;
|
||||
cp = sp->chars;
|
||||
strncpy(cp, stdname, stdlen);
|
||||
cp += stdlen;
|
||||
*cp++ = '\0';
|
||||
if (dstlen != 0)
|
||||
{
|
||||
strncpy(cp, dstname, dstlen);
|
||||
cp[dstlen] = '\0';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void tz_set(tz_t *tz, const char *tzstring)
|
||||
{
|
||||
const char *name = "";
|
||||
struct tz_state_s *lclptr = &tz->state;
|
||||
|
||||
if (tzstring)
|
||||
name = tzstring;
|
||||
|
||||
/* See if we are already set OK */
|
||||
if (tz->lcl_is_set > 0 && strcmp(tz->lcl_tzname, name) == 0)
|
||||
return;
|
||||
tz->lcl_is_set = strlen(name) < sizeof(tz->lcl_tzname);
|
||||
if (tz->lcl_is_set)
|
||||
strcpy(tz->lcl_tzname, name);
|
||||
|
||||
if (name[0] == '\0')
|
||||
{
|
||||
/* User wants it fast rather than right, so, we're off a little. */
|
||||
lclptr->leapcnt = 0;
|
||||
lclptr->timecnt = 0;
|
||||
lclptr->typecnt = 0;
|
||||
lclptr->ttis[0].isdst = 0;
|
||||
lclptr->ttis[0].gmtoff = 0;
|
||||
lclptr->ttis[0].abbrind = 0;
|
||||
strcpy(lclptr->chars, gmt);
|
||||
}
|
||||
else if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
|
||||
{
|
||||
tzparse(gmt, lclptr, TRUE);
|
||||
}
|
||||
set_tzname(tz);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) tz_localtime(tz_t *tz, struct tm *tmp, time_t t)
|
||||
{
|
||||
struct tz_state_s *sp;
|
||||
const struct tz_ttinfo_s *ttisp;
|
||||
int i;
|
||||
|
||||
sp = &tz->state;
|
||||
|
||||
if (sp->timecnt == 0 || t < sp->ats[0])
|
||||
{
|
||||
i = 0;
|
||||
while (sp->ttis[i].isdst)
|
||||
{
|
||||
if (++i >= sp->typecnt)
|
||||
{
|
||||
i = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 1; i < sp->timecnt; i++)
|
||||
{
|
||||
if (t < sp->ats[i])
|
||||
break;
|
||||
}
|
||||
i = (int) sp->types[i - 1];
|
||||
}
|
||||
ttisp = &sp->ttis[i];
|
||||
time_sub(&t, ttisp->gmtoff, sp, tmp);
|
||||
tmp->tm_isdst = ttisp->isdst;
|
||||
tz->tzname[tmp->tm_isdst] = &sp->chars[ttisp->abbrind];
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(const char *) tz_tzname(tz_t *tz, int isdst)
|
||||
{
|
||||
return tz->tzname[(!isdst) ? 0 : 1];
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(tz_t *) tz_init(tz_t *tz, const char *tzstring)
|
||||
{
|
||||
if (tz == NULL)
|
||||
{
|
||||
if ((tz = (tz_t *) malloc(sizeof(*tz))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
memset(tz, 0, sizeof(*tz));
|
||||
tz->tzname[0] =
|
||||
tz->tzname[1] = wildabbr;
|
||||
tz_set(tz, tzstring);
|
||||
return tz;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) tz_release(tz_t *tz)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) tz_free(tz_t *tz)
|
||||
{
|
||||
if (tz)
|
||||
free(tz);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
123
libs/spandsp/test-data/itu/fax/generate_striped_pages.c
Normal file
123
libs/spandsp/test-data/itu/fax/generate_striped_pages.c
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* generate_striped_pages.c
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2010 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 */
|
||||
|
||||
/*
|
||||
This program generates an TIFF image as a number of small image striped, rather than
|
||||
the usual all in one page FAX images usually consist of in TIFF files.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.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 <tiffio.h>
|
||||
|
||||
#include "spandsp.h"
|
||||
|
||||
#define IMAGE_WIDTH 1728
|
||||
#define IMAGE_LENGTH 2600
|
||||
#define ROWS_PER_STRIPE 37
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
TIFF *tiff_file;
|
||||
uint8_t image_buffer[10000];
|
||||
int image_size;
|
||||
time_t now;
|
||||
struct tm *tm;
|
||||
char buf[256 + 1];
|
||||
int i;
|
||||
|
||||
if ((tiff_file = TIFFOpen("striped.tif", "w")) == NULL)
|
||||
return -1;
|
||||
|
||||
TIFFSetField(tiff_file, TIFFTAG_COMPRESSION, COMPRESSION_CCITT_T6);
|
||||
TIFFSetField(tiff_file, TIFFTAG_BITSPERSAMPLE, 1);
|
||||
TIFFSetField(tiff_file, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
|
||||
TIFFSetField(tiff_file, TIFFTAG_SAMPLESPERPIXEL, 1);
|
||||
TIFFSetField(tiff_file, TIFFTAG_ROWSPERSTRIP, (int32_t) ROWS_PER_STRIPE);
|
||||
TIFFSetField(tiff_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
||||
TIFFSetField(tiff_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
|
||||
TIFFSetField(tiff_file, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB);
|
||||
TIFFSetField(tiff_file, TIFFTAG_XRESOLUTION, 204.0f);
|
||||
TIFFSetField(tiff_file, TIFFTAG_YRESOLUTION, 196.0f);
|
||||
TIFFSetField(tiff_file, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
|
||||
TIFFSetField(tiff_file, TIFFTAG_SOFTWARE, "Spandsp");
|
||||
TIFFSetField(tiff_file, TIFFTAG_HOSTCOMPUTER, "host");
|
||||
TIFFSetField(tiff_file, TIFFTAG_FAXSUBADDRESS, "1111");
|
||||
TIFFSetField(tiff_file, TIFFTAG_IMAGEDESCRIPTION, "Image in stripes");
|
||||
TIFFSetField(tiff_file, TIFFTAG_MAKE, "spandsp");
|
||||
TIFFSetField(tiff_file, TIFFTAG_MODEL, "testy");
|
||||
|
||||
time(&now);
|
||||
tm = localtime(&now);
|
||||
sprintf(buf,
|
||||
"%4d/%02d/%02d %02d:%02d:%02d",
|
||||
tm->tm_year + 1900,
|
||||
tm->tm_mon + 1,
|
||||
tm->tm_mday,
|
||||
tm->tm_hour,
|
||||
tm->tm_min,
|
||||
tm->tm_sec);
|
||||
TIFFSetField(tiff_file, TIFFTAG_DATETIME, buf);
|
||||
TIFFSetField(tiff_file, TIFFTAG_FAXRECVTIME, 10);
|
||||
TIFFSetField(tiff_file, TIFFTAG_IMAGEWIDTH, IMAGE_WIDTH);
|
||||
TIFFSetField(tiff_file, TIFFTAG_IMAGELENGTH, IMAGE_LENGTH);
|
||||
TIFFSetField(tiff_file, TIFFTAG_PAGENUMBER, 0, 1);
|
||||
|
||||
image_size = IMAGE_WIDTH*ROWS_PER_STRIPE/8;
|
||||
memset(image_buffer, 0x18, image_size);
|
||||
|
||||
for (i = 0; i < IMAGE_LENGTH/ROWS_PER_STRIPE; i++)
|
||||
{
|
||||
if (IMAGE_LENGTH > (i + 1)*ROWS_PER_STRIPE)
|
||||
image_size = IMAGE_WIDTH*ROWS_PER_STRIPE/8;
|
||||
else
|
||||
image_size = IMAGE_WIDTH*(IMAGE_LENGTH - i*ROWS_PER_STRIPE)/8;
|
||||
if (TIFFWriteEncodedStrip(tiff_file, i, image_buffer, image_size) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
TIFFWriteDirectory(tiff_file);
|
||||
TIFFClose(tiff_file);
|
||||
return 0;
|
||||
}
|
BIN
libs/spandsp/test-data/local/lenna-colour.tif
Normal file
BIN
libs/spandsp/test-data/local/lenna-colour.tif
Normal file
Binary file not shown.
189
libs/spandsp/tests/bitstream_tests.c
Normal file
189
libs/spandsp/tests/bitstream_tests.c
Normal file
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* bitstream_tests.c
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 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 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.
|
||||
*/
|
||||
|
||||
/*! \page bitstream_tests_page Bitstream tests
|
||||
\section bitstream_tests_page_sec_1 What does it do?
|
||||
|
||||
\section bitstream_tests_page_sec_2 How is it used?
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
//#if defined(WITH_SPANDSP_INTERNALS)
|
||||
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
|
||||
//#endif
|
||||
|
||||
#include "spandsp.h"
|
||||
|
||||
uint8_t buffer[256];
|
||||
|
||||
#define PATTERN 0x11111111
|
||||
#define SEQUENCE_LENGTH 17
|
||||
|
||||
uint8_t left[] =
|
||||
{
|
||||
0x28, /* 2 of 4, 3, 2, 1 */
|
||||
0xC8, /* 1 of 6, 5, 2 of 4 */
|
||||
0xAE, /* 3 of 7, 5 of 6 */
|
||||
0x67, /* 4 of 8, 4 of 7 */
|
||||
0x74, /* 4 of 9, 4 of 8 */
|
||||
0x43, /* 3 of 10, 5 of 9 */
|
||||
0x32, /* 1 of 11, 7 of 10 */
|
||||
0xAA, /* 8 of 11 */
|
||||
0xAE, /* 6 of 12, 2 of 11 */
|
||||
0xED, /* 2 of 13, 6 of 12 */
|
||||
0x99, /* 8 of 13 */
|
||||
0x8E, /* 5 of 14, 3 of 13 */
|
||||
0xEE, /* 8 of 14 */
|
||||
0xEE, /* 7 of 15, 1 of 14 */
|
||||
0xEE, /* 8 of 15 */
|
||||
0xFF, /* 8 of 16 */
|
||||
0xFF, /* 8 of 16 */
|
||||
0x88, /* 8 of 17 */
|
||||
0x88, /* 8 of 17 */
|
||||
0x00 /* 1 of 17 */
|
||||
};
|
||||
uint8_t right[] =
|
||||
{
|
||||
0xD2, /* 1, 2, 3, 2 of 4 */
|
||||
0x90, /* 2 of 4, 5, 1 of 6 */
|
||||
0xCA, /* 5 of 6, 3 of 7 */
|
||||
0x7C, /* 4 of 7, 4 of 8 */
|
||||
0x87, /* 4 of 8, 4 of 9 */
|
||||
0x28, /* 5 of 9, 3 of 10 */
|
||||
0x33, /* 7 of 10, 1 of 11 */
|
||||
0x55, /* 8 of 11 */
|
||||
0xED, /* 2 of 11, 6 of 12 */
|
||||
0x2E, /* 6 of 12, 2 of 13 */
|
||||
0x33, /* 8 of 13 */
|
||||
0xEB, /* 3 of 13, 5 of 14 */
|
||||
0xEE, /* 8 of 14 */
|
||||
0xDC, /* 1 of 14, 7 of 15 */
|
||||
0xDD, /* 8 of 15 */
|
||||
0xFF, /* 8 of 16 */
|
||||
0xFF, /* 8 of 16 */
|
||||
0x10, /* 8 of 17 */
|
||||
0x11, /* 8 of 17 */
|
||||
0x01 /* 1 of 17 */
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
bitstream_state_t state;
|
||||
bitstream_state_t *s;
|
||||
const uint8_t *r;
|
||||
uint8_t *w;
|
||||
uint8_t *cc;
|
||||
unsigned int x;
|
||||
int total_bits;
|
||||
|
||||
s = bitstream_init(&state, TRUE);
|
||||
w = buffer;
|
||||
total_bits = 0;
|
||||
for (i = 0; i < SEQUENCE_LENGTH; i++)
|
||||
{
|
||||
bitstream_put(s, &w, PATTERN*i, i + 1);
|
||||
total_bits += (i + 1);
|
||||
}
|
||||
bitstream_flush(s, &w);
|
||||
printf("%d bits written\n", total_bits);
|
||||
|
||||
for (cc = buffer; cc < w; cc++)
|
||||
printf("%02X ", *cc);
|
||||
printf("\n");
|
||||
for (cc = right; cc < right + sizeof(right); cc++)
|
||||
printf("%02X ", *cc);
|
||||
printf("\n");
|
||||
|
||||
if ((w - buffer) != sizeof(right) || memcmp(buffer, right, sizeof(right)))
|
||||
{
|
||||
printf("Test failed\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
s = bitstream_init(&state, TRUE);
|
||||
r = buffer;
|
||||
for (i = 0; i < SEQUENCE_LENGTH; i++)
|
||||
{
|
||||
x = bitstream_get(s, &r, i + 1);
|
||||
if (x != ((PATTERN*i) & ((1 << (i + 1)) - 1)))
|
||||
{
|
||||
printf("Error 0x%X 0x%X\n", x, ((PATTERN*i) & ((1 << (i + 1)) - 1)));
|
||||
printf("Test failed\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
s = bitstream_init(&state, FALSE);
|
||||
w = buffer;
|
||||
total_bits = 0;
|
||||
for (i = 0; i < SEQUENCE_LENGTH; i++)
|
||||
{
|
||||
bitstream_put(s, &w, PATTERN*i, i + 1);
|
||||
total_bits += (i + 1);
|
||||
}
|
||||
bitstream_flush(s, &w);
|
||||
printf("%d bits written\n", total_bits);
|
||||
|
||||
for (cc = buffer; cc < w; cc++)
|
||||
printf("%02X ", *cc);
|
||||
printf("\n");
|
||||
for (cc = left; cc < left + sizeof(left); cc++)
|
||||
printf("%02X ", *cc);
|
||||
printf("\n");
|
||||
|
||||
if ((w - buffer) != sizeof(left) || memcmp(buffer, left, sizeof(left)))
|
||||
{
|
||||
printf("Test failed\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
s = bitstream_init(&state, FALSE);
|
||||
r = buffer;
|
||||
for (i = 0; i < SEQUENCE_LENGTH; i++)
|
||||
{
|
||||
x = bitstream_get(s, &r, i + 1);
|
||||
if (x != ((PATTERN*i) & ((1 << (i + 1)) - 1)))
|
||||
{
|
||||
printf("Error 0x%X 0x%X\n", x, ((PATTERN*i) & ((1 << (i + 1)) - 1)));
|
||||
printf("Test failed\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Tests passed.\n");
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
452
libs/spandsp/tests/image_translate_tests.c
Normal file
452
libs/spandsp/tests/image_translate_tests.c
Normal file
@ -0,0 +1,452 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* image_translate_tests.c - Tests for the image translation routines.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 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 image_translate_tests_page Image translation tests
|
||||
\section image_translate_tests_page_sec_1 What does it do?
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
|
||||
//#if defined(WITH_SPANDSP_INTERNALS)
|
||||
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
|
||||
//#endif
|
||||
|
||||
#include "spandsp.h"
|
||||
|
||||
#define INPUT_TIFF_FILE_NAME "../test-data/local/lenna-colour.tif"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const uint8_t *image;
|
||||
int width;
|
||||
int length;
|
||||
int current_row;
|
||||
int bytes_per_pixel;
|
||||
} image_descriptor_t;
|
||||
|
||||
static void display_row(int row, int width, uint8_t buf[])
|
||||
{
|
||||
int i;
|
||||
int test_pixel;
|
||||
|
||||
printf("%3d: ", row);
|
||||
for (i = 0; i < width; i++)
|
||||
{
|
||||
test_pixel = (buf[i >> 3] >> (7 - (i & 7))) & 0x01;
|
||||
printf("%c", (test_pixel) ? ' ' : '@');
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int test_dithered_50_by_50(int row, int width, uint8_t buf[])
|
||||
{
|
||||
static const char *image[50] =
|
||||
{
|
||||
" 0: @ @ @ @ @ @ @ @@ @@@@@@@@@@@@@@",
|
||||
" 1: @ @ @ @ @ @ @ @ @ @@ @@ @ @ @ @ @@@@",
|
||||
" 2: @ @ @ @ @ @ @ @@ @ @ @@@ @@@@@@ @@",
|
||||
" 3: @ @ @ @ @ @ @ @ @ @ @@@ @@@@ @@@@@@",
|
||||
" 4: @ @ @ @ @ @ @ @ @ @@@ @ @@ @@@@ @@@@",
|
||||
" 5: @ @ @ @ @ @ @ @ @ @ @ @ @@ @@@ @@@@@@",
|
||||
" 6: @ @ @ @ @ @ @@ @@@@ @@@ @@@ @@ @",
|
||||
" 7: @ @ @ @ @ @ @ @ @ @@ @@ @ @@ @@@@@@",
|
||||
" 8: @ @ @ @ @ @ @ @ @@@ @@@@@@@@@ @@@",
|
||||
" 9: @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @ @ @ @@@@@",
|
||||
" 10: @ @ @ @ @ @@ @ @@ @@@@@@@@@@@@@",
|
||||
" 11: @ @ @ @ @ @ @ @ @ @@ @@ @ @ @@ @@ @@",
|
||||
" 12: @ @ @ @ @ @ @ @ @ @@ @@@@@@ @@@@@@@",
|
||||
" 13: @ @ @ @ @ @ @ @ @@ @ @ @ @ @@@@@ @@@",
|
||||
" 14: @ @ @ @ @ @ @ @@ @@@ @@@ @ @@@@@@",
|
||||
" 15: @ @ @ @ @ @ @ @ @ @ @ @ @@ @@@@@@@ @@",
|
||||
" 16: @ @ @ @ @ @ @ @ @@ @@ @@ @@ @@@@@",
|
||||
" 17: @ @ @ @ @ @ @ @ @ @@ @@ @@ @@ @@@@@@@",
|
||||
" 18: @ @ @ @ @ @ @ @ @ @ @ @@ @@@@@ @ @@@",
|
||||
" 19: @ @ @ @ @ @ @ @ @@@ @@@ @ @@@@@@@",
|
||||
" 20: @ @ @ @ @ @ @ @ @ @@ @ @@ @@@@@@ @@@ @",
|
||||
" 21: @ @ @ @ @ @ @ @@ @@ @ @ @@@@@@@",
|
||||
" 22: @ @ @ @ @ @@ @ @ @ @ @@ @@@@@@@ @@ @@",
|
||||
" 23: @ @ @ @ @ @ @ @@ @@ @@ @ @ @@@@@@@",
|
||||
" 24: @ @ @ @ @@ @ @ @@ @ @ @@@@@@ @@@@@",
|
||||
" 25: @ @ @ @ @ @ @ @ @ @ @@@@@ @ @@@@ @@",
|
||||
" 26: @ @ @ @ @ @ @ @ @ @@ @ @ @@@@ @@@@@",
|
||||
" 27: @ @ @ @ @ @ @ @ @ @@ @ @@ @@@ @@@@@@@",
|
||||
" 28: @ @ @ @ @ @ @ @ @@@ @@@ @@@ @@ @@",
|
||||
" 29: @ @ @ @ @ @ @ @ @@ @ @@ @ @@ @@@@@@@",
|
||||
" 30: @ @ @ @ @ @ @ @ @ @ @ @@@@@@@ @@@@@",
|
||||
" 31: @ @ @ @ @ @ @ @ @ @@@@ @ @ @@@@ @@",
|
||||
" 32: @ @ @ @ @ @ @ @ @ @@ @ @ @@@@@@@ @@@@@",
|
||||
" 33: @ @ @ @ @ @ @ @@@ @@ @ @ @@@@@@@",
|
||||
" 34: @ @ @ @ @ @ @ @ @ @ @ @ @@ @@@@@@ @ @@@",
|
||||
" 35: @ @ @ @ @ @ @ @ @ @@ @ @ @@@@@@@",
|
||||
" 36: @ @ @ @ @ @ @ @ @@ @@@ @@@@@@@ @@@ @",
|
||||
" 37: @ @ @ @ @ @ @ @ @ @ @@ @ @ @@@@@@@",
|
||||
" 38: @ @ @ @ @ @ @ @ @@ @@ @@@@@@@ @@ @@",
|
||||
" 39: @ @ @ @ @ @ @ @ @ @ @@ @@ @ @ @@@@@@@",
|
||||
" 40: @ @ @ @ @ @ @ @ @ @@ @@ @@@@ @@@@@",
|
||||
" 41: @ @ @ @ @ @ @ @ @ @@ @ @@ @@@ @@@@ @@",
|
||||
" 42: @ @ @ @ @ @ @@ @@ @@ @@ @@@ @@@@@",
|
||||
" 43: @ @ @ @ @ @ @ @ @ @ @@ @@@ @@@@@@@",
|
||||
" 44: @ @ @ @ @ @ @ @ @ @ @@@ @@@ @@@ @@ @@",
|
||||
" 45: @ @ @ @ @ @ @@ @ @ @ @@ @@@@@@@",
|
||||
" 46: @ @ @ @ @ @ @ @ @ @ @ @@ @@@@@@@@@ @@@@@",
|
||||
" 47: @ @ @ @ @ @ @ @ @ @@ @ @ @ @@@@ @@",
|
||||
" 48: @ @ @ @ @ @ @@ @ @@ @@@@@@ @@@@@",
|
||||
" 49: @ @ @ @ @ @ @ @ @ @ @ @@ @@ @ @ @@@@@@@"
|
||||
};
|
||||
int i;
|
||||
int match;
|
||||
int ref_pixel;
|
||||
int test_pixel;
|
||||
|
||||
match = 0;
|
||||
for (i = 0; i < width; i++)
|
||||
{
|
||||
ref_pixel = (image[row][i + 5] == ' ');
|
||||
test_pixel = (buf[i >> 3] >> (7 - (i & 7))) & 0x01;
|
||||
if (ref_pixel != test_pixel)
|
||||
match = -1;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int row_read(void *user_data, uint8_t buf[], size_t len)
|
||||
{
|
||||
image_descriptor_t *im;
|
||||
|
||||
im = (image_descriptor_t *) user_data;
|
||||
if (im->current_row >= im->length)
|
||||
return 0;
|
||||
memcpy(buf, &im->image[im->current_row*im->width*im->bytes_per_pixel], len);
|
||||
im->current_row++;
|
||||
return len;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void get_flattened_image(image_translate_state_t *s, int compare)
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
uint8_t row_buf[5000];
|
||||
|
||||
for (i = 0; i < s->output_length; i++)
|
||||
{
|
||||
if ((len = image_translate_row(s, row_buf, (s->output_width + 7)/8)) != (s->output_width + 7)/8)
|
||||
{
|
||||
printf("Image finished early - %d %d\n", len, (s->output_width + 7)/8);
|
||||
exit(2);
|
||||
}
|
||||
display_row(i, s->output_width, row_buf);
|
||||
if (compare)
|
||||
{
|
||||
if (test_dithered_50_by_50(i, s->output_width, row_buf))
|
||||
{
|
||||
printf("Dithered image mismatch at row %d\n", i);
|
||||
printf("Test failed\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((len = image_translate_row(s, row_buf, (s->output_width + 7)/8)) != 0)
|
||||
{
|
||||
printf("Image finished late - %d %d\n", len, (s->output_width + 7)/8);
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void dither_tests_gray16(void)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
image_translate_state_t bw;
|
||||
image_translate_state_t *s = &bw;
|
||||
uint16_t image[50*50];
|
||||
image_descriptor_t im;
|
||||
|
||||
printf("Dithering from a 16 bit per sample gray scale to bi-level\n");
|
||||
im.image = (const uint8_t *) image;
|
||||
im.width = 50;
|
||||
im.length = 50;
|
||||
im.bytes_per_pixel = 2;
|
||||
im.current_row = 0;
|
||||
|
||||
for (i = 0; i < im.length; i++)
|
||||
{
|
||||
for (j = 0; j < im.width; j++)
|
||||
image[i*im.width + j] = j*1200;
|
||||
}
|
||||
|
||||
s = image_translate_init(s, IMAGE_TRANSLATE_FROM_GRAY_16, im.width, im.length, -1, row_read, &im);
|
||||
get_flattened_image(s, TRUE);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void dither_tests_gray8(void)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
image_translate_state_t bw;
|
||||
image_translate_state_t *s = &bw;
|
||||
uint8_t image[50*50];
|
||||
image_descriptor_t im;
|
||||
|
||||
printf("Dithering from a 8 bit per sample gray scale to bi-level\n");
|
||||
im.image = image;
|
||||
im.width = 50;
|
||||
im.length = 50;
|
||||
im.bytes_per_pixel = 1;
|
||||
im.current_row = 0;
|
||||
|
||||
for (i = 0; i < im.length; i++)
|
||||
{
|
||||
for (j = 0; j < im.width; j++)
|
||||
image[i*im.width + j] = j*1200/256;
|
||||
}
|
||||
s = image_translate_init(s, IMAGE_TRANSLATE_FROM_GRAY_8, im.width, im.length, -1, row_read, &im);
|
||||
get_flattened_image(s, TRUE);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void dither_tests_colour16(void)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
image_translate_state_t bw;
|
||||
image_translate_state_t *s = &bw;
|
||||
uint16_t image[50*50*3];
|
||||
image_descriptor_t im;
|
||||
|
||||
printf("Dithering from a 3x16 bit per sample colour to bi-level\n");
|
||||
im.image = (const uint8_t *) image;
|
||||
im.width = 50;
|
||||
im.length = 50;
|
||||
im.bytes_per_pixel = 6;
|
||||
im.current_row = 0;
|
||||
|
||||
for (i = 0; i < im.length; i++)
|
||||
{
|
||||
for (j = 0; j < im.width; j++)
|
||||
{
|
||||
image[i*3*im.width + 3*j + 0] = j*1200;
|
||||
image[i*3*im.width + 3*j + 1] = j*1200;
|
||||
image[i*3*im.width + 3*j + 2] = j*1200;
|
||||
}
|
||||
}
|
||||
s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_16, im.width, im.length, -1, row_read, &im);
|
||||
get_flattened_image(s, TRUE);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void dither_tests_colour8(void)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
image_translate_state_t bw;
|
||||
image_translate_state_t *s = &bw;
|
||||
uint8_t image[50*50*3];
|
||||
image_descriptor_t im;
|
||||
|
||||
printf("Dithering from a 3x8 bit per sample colour to bi-level\n");
|
||||
im.image = image;
|
||||
im.width = 50;
|
||||
im.length = 50;
|
||||
im.bytes_per_pixel = 3;
|
||||
im.current_row = 0;
|
||||
|
||||
for (i = 0; i < im.length; i++)
|
||||
{
|
||||
for (j = 0; j < im.width; j++)
|
||||
{
|
||||
image[i*3*im.width + 3*j + 0] = j*1200/256;
|
||||
image[i*3*im.width + 3*j + 1] = j*1200/256;
|
||||
image[i*3*im.width + 3*j + 2] = j*1200/256;
|
||||
}
|
||||
}
|
||||
|
||||
s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_8, im.width, im.length, -1, row_read, &im);
|
||||
get_flattened_image(s, TRUE);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void grow_tests_colour8(void)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
image_translate_state_t resize;
|
||||
image_translate_state_t *s1 = &resize;
|
||||
uint8_t image[50*50*3];
|
||||
image_descriptor_t im;
|
||||
|
||||
printf("Image growth tests\n");
|
||||
im.image = image;
|
||||
im.width = 50;
|
||||
im.length = 50;
|
||||
im.bytes_per_pixel = 3;
|
||||
im.current_row = 0;
|
||||
|
||||
for (i = 0; i < im.length; i++)
|
||||
{
|
||||
for (j = 0; j < im.width; j++)
|
||||
{
|
||||
image[i*3*im.width + 3*j + 0] = j*1200/256;
|
||||
image[i*3*im.width + 3*j + 1] = j*1200/256;
|
||||
image[i*3*im.width + 3*j + 2] = j*1200/256;
|
||||
}
|
||||
}
|
||||
|
||||
s1 = image_translate_init(s1, IMAGE_TRANSLATE_FROM_COLOUR_8, im.width, im.length, 200, row_read, &im);
|
||||
|
||||
get_flattened_image(s1, FALSE);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void lenna_tests(int output_width, const char *file)
|
||||
{
|
||||
TIFF *in_file;
|
||||
TIFF *out_file;
|
||||
int image_width;
|
||||
int image_length;
|
||||
int output_length;
|
||||
uint8_t *image;
|
||||
uint8_t *image2;
|
||||
int len;
|
||||
int total;
|
||||
int16_t bits_per_sample;
|
||||
int16_t samples_per_pixel;
|
||||
int i;
|
||||
int n;
|
||||
image_translate_state_t bw;
|
||||
image_translate_state_t *s = &bw;
|
||||
image_descriptor_t im;
|
||||
|
||||
printf("Dithering Lenna from colour to bi-level test\n");
|
||||
if ((in_file = TIFFOpen(INPUT_TIFF_FILE_NAME, "r")) == NULL)
|
||||
return;
|
||||
image_width = 0;
|
||||
TIFFGetField(in_file, TIFFTAG_IMAGEWIDTH, &image_width);
|
||||
if (image_width <= 0)
|
||||
return;
|
||||
image_length = 0;
|
||||
TIFFGetField(in_file, TIFFTAG_IMAGELENGTH, &image_length);
|
||||
if (image_length <= 0)
|
||||
return;
|
||||
bits_per_sample = 0;
|
||||
TIFFGetField(in_file, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
|
||||
samples_per_pixel = 0;
|
||||
TIFFGetField(in_file, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel);
|
||||
printf("Original image is %d x %d, %d bits per sample, %d samples per pixel\n", image_width, image_length, bits_per_sample, samples_per_pixel);
|
||||
if ((image = malloc(image_width*image_length*samples_per_pixel)) == NULL)
|
||||
return;
|
||||
for (total = 0, i = 0; i < 1000; i++)
|
||||
{
|
||||
len = TIFFReadEncodedStrip(in_file, i, &image[total], image_width*image_length*samples_per_pixel - total);
|
||||
if (len <= 0)
|
||||
break;
|
||||
total += len;
|
||||
if (total == image_width*image_length*samples_per_pixel)
|
||||
{
|
||||
printf("Done\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("Image size %d %d\n", total, image_width*image_length*samples_per_pixel);
|
||||
TIFFClose(in_file);
|
||||
|
||||
im.image = image;
|
||||
im.width = image_width;
|
||||
im.length = image_length;
|
||||
im.current_row = 0;
|
||||
im.bytes_per_pixel = samples_per_pixel;
|
||||
|
||||
s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_8, image_width, image_length, output_width, row_read, &im);
|
||||
output_width = image_translate_get_output_width(s);
|
||||
output_length = image_translate_get_output_length(s);
|
||||
|
||||
if ((out_file = TIFFOpen(file, "w")) == NULL)
|
||||
return;
|
||||
TIFFSetField(out_file, TIFFTAG_IMAGEWIDTH, output_width);
|
||||
TIFFSetField(out_file, TIFFTAG_IMAGELENGTH, output_length);
|
||||
TIFFSetField(out_file, TIFFTAG_BITSPERSAMPLE, 1);
|
||||
TIFFSetField(out_file, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
|
||||
TIFFSetField(out_file, TIFFTAG_SAMPLESPERPIXEL, 1);
|
||||
TIFFSetField(out_file, TIFFTAG_ROWSPERSTRIP, -1);
|
||||
TIFFSetField(out_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
||||
TIFFSetField(out_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
|
||||
TIFFSetField(out_file, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB);
|
||||
TIFFSetField(out_file, TIFFTAG_PAGENUMBER, 0, 1);
|
||||
TIFFSetField(out_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
|
||||
TIFFSetField(out_file, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB);
|
||||
|
||||
printf("Input %d x %d, output %d x %d\n", image_width, image_length, output_width, output_length);
|
||||
|
||||
if ((image2 = malloc(output_width*output_length/8)) == NULL)
|
||||
return;
|
||||
memset(image2, 0, output_width*output_length/8);
|
||||
n = 0;
|
||||
for (i = 0; i < output_length; i++)
|
||||
n += image_translate_row(s, &image2[n], output_width/8);
|
||||
|
||||
TIFFWriteEncodedStrip(out_file, 0, image2, output_width*output_length/8);
|
||||
TIFFWriteDirectory(out_file);
|
||||
TIFFClose(out_file);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#if 1
|
||||
dither_tests_gray16();
|
||||
dither_tests_gray8();
|
||||
dither_tests_colour16();
|
||||
dither_tests_colour8();
|
||||
#endif
|
||||
#if 1
|
||||
grow_tests_colour8();
|
||||
#endif
|
||||
#if 1
|
||||
lenna_tests(0, "lenna-bw.tif");
|
||||
lenna_tests(1728, "lenna-bw-1728.tif");
|
||||
lenna_tests(200, "lenna-bw-200.tif");
|
||||
#endif
|
||||
printf("Tests passed.\n");
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
311
libs/spandsp/tests/saturated_tests.c
Normal file
311
libs/spandsp/tests/saturated_tests.c
Normal file
@ -0,0 +1,311 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* saturated_tests.c
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2004 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.
|
||||
*/
|
||||
|
||||
/*! \page saturated_tests_page Saturated arithmetic function tests
|
||||
\section saturated_tests_page_sec_1 What does it do?
|
||||
???.
|
||||
|
||||
\section saturated_tests_page_sec_2 How does it work?
|
||||
???.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
|
||||
#include "spandsp.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
printf("Testing 16 bit saturation\n");
|
||||
if (saturate16(10000) != 10000
|
||||
||
|
||||
saturate16(-10000) != -10000
|
||||
||
|
||||
saturate16(32767) != 32767
|
||||
||
|
||||
saturate16(-32768) != -32768
|
||||
||
|
||||
saturate16(32768) != 32767
|
||||
||
|
||||
saturate16(-32769) != -32768)
|
||||
{
|
||||
printf("Test failed.\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("Testing 15 bit saturation\n");
|
||||
if (saturate15(10000) != 10000
|
||||
||
|
||||
saturate15(-10000) != -10000
|
||||
||
|
||||
saturate15(16383) != 16383
|
||||
||
|
||||
saturate15(-16384) != -16384
|
||||
||
|
||||
saturate15(16384) != 16383
|
||||
||
|
||||
saturate15(-16385) != -16384)
|
||||
{
|
||||
printf("Test failed.\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("Testing 16 bit unsigned saturation\n");
|
||||
if (saturateu16(10000) != 10000
|
||||
||
|
||||
saturateu16(32767) != 32767
|
||||
||
|
||||
saturateu16(65535) != 65535
|
||||
||
|
||||
saturateu16(65536) != 65535)
|
||||
{
|
||||
printf("Test failed.\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("Testing 8 bit unsigned saturation\n");
|
||||
if (saturateu8(100) != 100
|
||||
||
|
||||
saturateu8(127) != 127
|
||||
||
|
||||
saturateu8(255) != 255
|
||||
||
|
||||
saturateu8(256) != 255)
|
||||
{
|
||||
printf("Test failed.\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("Testing 16 bit saturation from float\n");
|
||||
if (fsaturatef(10000.0f) != 10000
|
||||
||
|
||||
fsaturatef(-10000.0f) != -10000
|
||||
||
|
||||
fsaturatef(32767.0f) != 32767
|
||||
||
|
||||
fsaturatef(-32768.0f) != -32768
|
||||
||
|
||||
fsaturatef(32768.0f) != 32767
|
||||
||
|
||||
fsaturatef(-32769.0f) != -32768)
|
||||
{
|
||||
printf("Test failed.\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("Testing 16 bit saturation from double\n");
|
||||
if (fsaturate(10000.0) != 10000
|
||||
||
|
||||
fsaturate(-10000.0) != -10000
|
||||
||
|
||||
fsaturate(32767.0) != 32767
|
||||
||
|
||||
fsaturate(-32768.0) != -32768
|
||||
||
|
||||
fsaturate(32768.0) != 32767
|
||||
||
|
||||
fsaturate(-32769.0) != -32768)
|
||||
{
|
||||
printf("Test failed.\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("Testing 16 bit fast saturation from float\n");
|
||||
if (ffastsaturatef(10000.0f) != 10000
|
||||
||
|
||||
ffastsaturatef(-10000.0f) != -10000
|
||||
||
|
||||
ffastsaturatef(32767.0f) != 32767
|
||||
||
|
||||
ffastsaturatef(-32768.0f) != -32768
|
||||
||
|
||||
ffastsaturatef(32768.0f) != 32767
|
||||
||
|
||||
ffastsaturatef(-32769.0f) != -32768)
|
||||
{
|
||||
printf("Test failed.\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("Testing 16 bit fast saturation from double\n");
|
||||
if (ffastsaturate(10000.0) != 10000
|
||||
||
|
||||
ffastsaturate(-10000.0) != -10000
|
||||
||
|
||||
ffastsaturate(32767.0) != 32767
|
||||
||
|
||||
ffastsaturate(-32768.0) != -32768
|
||||
||
|
||||
ffastsaturate(32768.0) != 32767
|
||||
||
|
||||
ffastsaturate(-32769.0) != -32768)
|
||||
{
|
||||
printf("Test failed.\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("Testing 16 bit float saturation from float\n");
|
||||
if (ffsaturatef(10000.0f) != 10000.0f
|
||||
||
|
||||
ffsaturatef(-10000.0f) != -10000.0f
|
||||
||
|
||||
ffsaturatef(32767.0f) != 32767.0f
|
||||
||
|
||||
ffsaturatef(-32768.0f) != -32768.0f
|
||||
||
|
||||
ffsaturatef(32768.0f) != 32767.0f
|
||||
||
|
||||
ffsaturatef(-32769.0f) != -32768.0f)
|
||||
{
|
||||
printf("Test failed.\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("Testing 16 bit double saturation from double\n");
|
||||
if (ffsaturate(10000.0) != 10000.0
|
||||
||
|
||||
ffsaturate(-10000.0) != -10000.0
|
||||
||
|
||||
ffsaturate(32767.0) != 32767.0
|
||||
||
|
||||
ffsaturate(-32768.0) != -32768.0
|
||||
||
|
||||
ffsaturate(32768.0) != 32767.0
|
||||
||
|
||||
ffsaturate(-32769.0) != -32768.0)
|
||||
{
|
||||
printf("Test failed.\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("Testing 16 bit add\n");
|
||||
if (saturated_add16(10000, 10000) != 20000
|
||||
||
|
||||
saturated_add16(10000, -10000) != 0
|
||||
||
|
||||
saturated_add16(-10000, 10000) != 0
|
||||
||
|
||||
saturated_add16(-10000, -10000) != -20000
|
||||
||
|
||||
saturated_add16(-30000, -30000) != INT16_MIN
|
||||
||
|
||||
saturated_add16(30000, 30000) != INT16_MAX)
|
||||
{
|
||||
printf("Test failed.\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("Testing 32 bit add\n");
|
||||
if (saturated_add32(10000, 10000) != 20000
|
||||
||
|
||||
saturated_add32(10000, -10000) != 0
|
||||
||
|
||||
saturated_add32(-10000, 10000) != 0
|
||||
||
|
||||
saturated_add32(-10000, -10000) != -20000
|
||||
||
|
||||
saturated_add32(-2000000000, -2000000000) != INT32_MIN
|
||||
||
|
||||
saturated_add32(2000000000, 2000000000) != INT32_MAX)
|
||||
{
|
||||
printf("Test failed.\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("Testing 16 bit subtract\n");
|
||||
if (saturated_sub16(10000, 10000) != 0
|
||||
||
|
||||
saturated_sub16(10000, -10000) != 20000
|
||||
||
|
||||
saturated_sub16(-10000, 10000) != -20000
|
||||
||
|
||||
saturated_sub16(-10000, -10000) != 0
|
||||
||
|
||||
saturated_sub16(-30000, 30000) != INT16_MIN
|
||||
||
|
||||
saturated_sub16(30000, -30000) != INT16_MAX)
|
||||
{
|
||||
printf("Test failed.\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("Testing 32 bit subtract\n");
|
||||
if (saturated_sub32(10000, 10000) != 0
|
||||
||
|
||||
saturated_sub32(10000, -10000) != 20000
|
||||
||
|
||||
saturated_sub32(-10000, 10000) != -20000
|
||||
||
|
||||
saturated_sub32(-10000, -10000) != 0
|
||||
||
|
||||
saturated_sub32(-2000000000, 2000000000) != INT32_MIN
|
||||
||
|
||||
saturated_sub32(2000000000, -2000000000) != INT32_MAX)
|
||||
{
|
||||
printf("Test failed.\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("Testing 16 x 16 => 16 bit multiply\n");
|
||||
if (saturated_mul16(100, 100) != 0
|
||||
||
|
||||
saturated_mul16(255, 255) != 1
|
||||
||
|
||||
saturated_mul16(32767, -32768) != -32767
|
||||
||
|
||||
saturated_mul16(-32768, 32767) != -32767
|
||||
||
|
||||
saturated_mul16(32767, 32767) != 32766
|
||||
||
|
||||
saturated_mul16(-32768, -32768) != 32767)
|
||||
{
|
||||
printf("Test failed.\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("Testing 16 x 16 => 32 bit multiply\n");
|
||||
if (saturated_mul16_32(100, 100) != 20000
|
||||
||
|
||||
saturated_mul16_32(-100, 100) != -20000
|
||||
||
|
||||
saturated_mul16_32(32767, -32768) != -2147418112
|
||||
||
|
||||
saturated_mul16_32(-32768, 32767) != -2147418112
|
||||
||
|
||||
saturated_mul16_32(32767, 32767) != 2147352578
|
||||
||
|
||||
saturated_mul16_32(-32768, -32768) != -2147483648)
|
||||
{
|
||||
printf("Test failed.\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("Testing 16 bit absolute\n");
|
||||
if (saturated_abs16(10000) != 10000
|
||||
||
|
||||
saturated_abs16(-10000) != 10000
|
||||
||
|
||||
saturated_abs16(32767) != 32767
|
||||
||
|
||||
saturated_abs16(-32768) != 32767)
|
||||
{
|
||||
printf("Test failed.\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("Tests passed.\n");
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
86
libs/spandsp/tests/timezone_tests.c
Normal file
86
libs/spandsp/tests/timezone_tests.c
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* timezone_tests.c - Timezone handling for time interpretation
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
/*! \page timezone_tests_page Timezone handling tests
|
||||
\section timezone_tests_page_sec_1 What does it do?
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
//#if defined(WITH_SPANDSP_INTERNALS)
|
||||
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
|
||||
//#endif
|
||||
|
||||
#include "spandsp.h"
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE (!FALSE)
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct tm tms;
|
||||
struct tm *tmp = &tms;
|
||||
time_t ltime;
|
||||
tz_t *tz;
|
||||
|
||||
/* Get the current time */
|
||||
ltime = time(NULL);
|
||||
|
||||
/* Compute the local current time now for several localities, based on Posix tz strings */
|
||||
|
||||
tz = tz_init(NULL, "GMT0GMT0,M10.5.0,M3.5.0");
|
||||
tz_localtime(tz, tmp, ltime);
|
||||
printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
||||
printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst));
|
||||
|
||||
tz_init(tz, "CST-8CST-8,M10.5.0,M3.5.0");
|
||||
tz_localtime(tz, tmp, ltime);
|
||||
printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
||||
printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst));
|
||||
|
||||
tz_init(tz, "AEST-10AEDT-11,M10.5.0,M3.5.0");
|
||||
tz_localtime(tz, tmp, ltime);
|
||||
printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
||||
printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst));
|
||||
|
||||
tz_free(tz);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
33
libs/spandsp/tests/tsb85_extra_tests.sh
Executable file
33
libs/spandsp/tests/tsb85_extra_tests.sh
Executable file
@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# spandsp fax tests
|
||||
#
|
||||
# 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 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.
|
||||
|
||||
run_tsb85_test()
|
||||
{
|
||||
rm -f fax_tests_1.tif
|
||||
echo ./tsb85_tests ${TEST}
|
||||
./tsb85_tests -x ../spandsp/fax-tests.xml ${TEST} 2>xyzzy2
|
||||
RETVAL=$?
|
||||
if [ $RETVAL != 0 ]
|
||||
then
|
||||
echo tsb85_tests ${TEST} failed!
|
||||
exit $RETVAL
|
||||
fi
|
||||
}
|
||||
|
||||
for TEST in PPS-MPS-lost-PPS ; do
|
||||
run_tsb85_test
|
||||
done
|
Loading…
x
Reference in New Issue
Block a user