Esempio n. 1
0
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;
}
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;
}
Esempio n. 3
0
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;
    int x;
    double c1;
    double c2;
#if defined(SPANDSP_USE_FIXED_POINT)
    int frac_row;
    int frac_col;
#else
    double int_part;
    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;
        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);
    }
#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;
}