diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2006-08-19 03:12:28 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2006-08-19 03:12:28 +0000 |
commit | 1fd361a1ea06e44286c213ca1f814f49306fdc43 (patch) | |
tree | 64c8c96cf54d8718847339a403e5e67b922e8c3f /converter/other/fiasco/lib/dither.c | |
download | netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.gz netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.xz netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.zip |
Create Subversion repository
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'converter/other/fiasco/lib/dither.c')
-rw-r--r-- | converter/other/fiasco/lib/dither.c | 1892 |
1 files changed, 1892 insertions, 0 deletions
diff --git a/converter/other/fiasco/lib/dither.c b/converter/other/fiasco/lib/dither.c new file mode 100644 index 00000000..c7f9ebab --- /dev/null +++ b/converter/other/fiasco/lib/dither.c @@ -0,0 +1,1892 @@ +/* + * dither.c: Various dithering routines + * + * Adapted by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * Copyright (c) 1995 Erik Corry + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL ERIK CORRY BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, + * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF + * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF ERIK CORRY HAS BEEN ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ERIK CORRY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND ERIK CORRY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +/* + * $Date: 2000/11/27 20:22:51 $ + * $Author: hafner $ + * $Revision: 5.3 $ + * $State: Exp $ + */ + +#include "config.h" + +#if HAVE_STRING_H +# include <string.h> +#else /* not HAVE_STRING_H */ +# include <strings.h> +#endif /* not HAVE_STRING_H */ +#if STDC_HEADERS +# include <stdlib.h> +#endif /* not STDC_HEADERS */ + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "fiasco.h" +#include "image.h" +#include "misc.h" +#include "dither.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static int +display_16_bit (const struct fiasco_renderer *this, unsigned char *ximage, + const fiasco_image_t *fiasco_image); +static int +display_24_bit_bgr (const struct fiasco_renderer *this, unsigned char *ximage, + const fiasco_image_t *fiasco_image); +static int +display_24_bit_rgb (const struct fiasco_renderer *this, unsigned char *ximage, + const fiasco_image_t *fiasco_image); +static int +display_32_bit (const struct fiasco_renderer *this, unsigned char *ximage, + const fiasco_image_t *fiasco_image); +static int +free_bits_at_bottom (unsigned long a); +static int +free_bits_at_top (unsigned long a); +static int +number_of_bits_set (unsigned long a); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +fiasco_renderer_t * +fiasco_renderer_new (unsigned long red_mask, unsigned long green_mask, + unsigned long blue_mask, unsigned bpp, + int double_resolution) +/* + * FIASCO renderer constructor. + * Allocate memory for the FIASCO renderer structure and + * initialize values. + * `red_mask', `green_mask', and `blue_mask' are the corresponding masks + * of the X11R6 XImage structure. + * `bpp' gives the depth of the image in bits per pixel (16, 24, or 32). + * If `double_resolution' is not 0 the the image width and height is doubled. + * (fast pixel doubling, no interpolation!) + * + * Return value: + * pointer to the new structure or NULL on error + */ +{ + if (bpp != 16 && bpp != 24 && bpp !=32) + { + set_error (_("Rendering depth of XImage must be 16, 24, or 32 bpp.")); + return NULL; + } + else + { + fiasco_renderer_t *render = calloc (1, sizeof (fiasco_renderer_t)); + renderer_private_t *private = calloc (1, sizeof (renderer_private_t)); + bool_t twopixels = (bpp == 16 && double_resolution); + int crval, cbval, i; /* counter */ + + if (!render || !private) + { + set_error (_("Out of memory.")); + return NULL; + } + switch (bpp) + { + case 16: + render->render = display_16_bit; + break; + case 24: + if (red_mask > green_mask) + render->render = display_24_bit_rgb; + else + render->render = display_24_bit_bgr; + break; + case 32: + render->render = display_32_bit; + break; + default: + break; /* does not happen */ + } + render->private = private; + render->delete = fiasco_renderer_delete; + + private->double_resolution = double_resolution; + private->Cr_r_tab = calloc (256 + 2 * 1024, sizeof (int)); + private->Cr_g_tab = calloc (256 + 2 * 1024, sizeof (int)); + private->Cb_g_tab = calloc (256 + 2 * 1024, sizeof (int)); + private->Cb_b_tab = calloc (256 + 2 * 1024, sizeof (int)); + + if (!private->Cr_r_tab || !private->Cr_g_tab + || !private->Cb_b_tab || !private->Cb_g_tab) + { + set_error (_("Out of memory.")); + return NULL; + } + + for (i = 1024; i < 1024 + 256; i++) + { + cbval = crval = i - 128 - 1024; + + private->Cr_r_tab [i] = 1.4022 * crval + 0.5; + private->Cr_g_tab [i] = -0.7145 * crval + 0.5; + private->Cb_g_tab [i] = -0.3456 * cbval + 0.5; + private->Cb_b_tab [i] = 1.7710 * cbval + 0.5; + } + for (i = 0; i < 1024; i++) + { + private->Cr_r_tab [i] = private->Cr_r_tab [1024]; + private->Cr_g_tab [i] = private->Cr_g_tab [1024]; + private->Cb_g_tab [i] = private->Cb_g_tab [1024]; + private->Cb_b_tab [i] = private->Cb_b_tab [1024]; + } + for (i = 1024 + 256; i < 2048 + 256; i++) + { + private->Cr_r_tab [i] = private->Cr_r_tab [1024 + 255]; + private->Cr_g_tab [i] = private->Cr_g_tab [1024 + 255]; + private->Cb_g_tab [i] = private->Cb_g_tab [1024 + 255]; + private->Cb_b_tab [i] = private->Cb_b_tab [1024 + 255]; + } + + private->Cr_r_tab += 1024 + 128; + private->Cr_g_tab += 1024 + 128; + private->Cb_g_tab += 1024 + 128; + private->Cb_b_tab += 1024 + 128; + + /* + * Set up entries 0-255 in rgb-to-pixel value tables. + */ + private->r_table = calloc (256 + 2 * 1024, sizeof (unsigned int)); + private->g_table = calloc (256 + 2 * 1024, sizeof (unsigned int)); + private->b_table = calloc (256 + 2 * 1024, sizeof (unsigned int)); + private->y_table = calloc (256 + 2 * 1024, sizeof (unsigned int)); + + if (!private->r_table || !private->g_table + || !private->b_table || !private->y_table) + { + set_error (_("Out of memory.")); + return NULL; + } + + for (i = 0; i < 256; i++) + { + private->r_table [i + 1024] + = i >> (8 - number_of_bits_set(red_mask)); + private->r_table [i + 1024] + <<= free_bits_at_bottom (red_mask); + private->g_table [i + 1024] + = i >> (8 - number_of_bits_set (green_mask)); + private->g_table [i + 1024] + <<= free_bits_at_bottom (green_mask); + private->b_table [i + 1024] + <<= free_bits_at_bottom (blue_mask); + private->b_table [i + 1024] + = i >> (8 - number_of_bits_set (blue_mask)); + if (twopixels) + { + private->r_table [i + 1024] = ((private->r_table [i + 1024] << 16) + | private->r_table [i + 1024]); + private->g_table [i + 1024] = ((private->g_table [i + 1024] << 16) + | private->g_table [i + 1024]); + private->b_table [i + 1024] = ((private->b_table [i + 1024] << 16) + | private->b_table [i + 1024]); + } + private->y_table [i + 1024] = (private->r_table [i + 1024] + | private->g_table [i + 1024] + | private->b_table [i + 1024]); + } + + /* + * Spread out the values we have to the rest of the array so that + * we do not need to check for overflow. + */ + for (i = 0; i < 1024; i++) + { + private->r_table [i] = private->r_table [1024]; + private->r_table [i + 1024 + 256] = private->r_table [1024 + 255]; + private->g_table [i] = private->g_table [1024]; + private->g_table [i + 1024 + 256] = private->g_table [1024 + 255]; + private->b_table [i] = private->b_table [1024]; + private->b_table [i + 1024 + 256] = private->b_table [1024 + 255]; + private->y_table [i] = private->y_table [1024]; + private->y_table [i + 1024 + 256] = private->y_table [1024 + 255]; + } + + private->r_table += 1024; + private->g_table += 1024; + private->b_table += 1024; + private->y_table += 1024 + 128; + + return render; + } + +} + +void +fiasco_renderer_delete (fiasco_renderer_t *renderer) +/* + * FIASCO renderer destructor: + * Free memory of 'renderer' structure. + * + * No return value. + * + * Side effects: + * structure 'renderer' is discarded. + */ +{ + if (!renderer) + return; + else + { + renderer_private_t *private = (renderer_private_t *) renderer->private; + + Free (private->Cr_g_tab - (1024 + 128)); + Free (private->Cr_r_tab - (1024 + 128)); + Free (private->Cb_g_tab - (1024 + 128)); + Free (private->Cb_b_tab - (1024 + 128)); + Free (private->r_table - 1024); + Free (private->g_table - 1024); + Free (private->b_table - 1024); + Free (private->y_table - (1024 + 128)); + + Free (private); + Free (renderer); + } +} + +int +fiasco_renderer_render (const fiasco_renderer_t *renderer, + unsigned char *ximage, + const fiasco_image_t *fiasco_image) +{ + if (!renderer) + { + set_error (_("Parameter `%s' not defined (NULL)."), "renderer"); + return 0; + } + else + return renderer->render (renderer, ximage, fiasco_image); +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +/* + * Erik Corry's multi-byte dither routines. + * + * The basic idea is that the Init generates all the necessary + * tables. The tables incorporate the information about the layout + * of pixels in the XImage, so that it should be able to cope with + * 16-bit 24-bit (non-packed) and 32-bit (10-11 bits per + * color!) screens. At present it cannot cope with 24-bit packed + * mode, since this involves getting down to byte level again. It is + * assumed that the bits for each color are contiguous in the + * longword. + * + * Writing to memory is done in shorts or ints. (Unfortunately, short + * is not very fast on Alpha, so there is room for improvement + * here). There is no dither time check for overflow - instead the + * tables have slack at each end. This is likely to be faster than an + * 'if' test as many modern architectures are really bad at + * ifs. Potentially, each '&&' causes a pipeline flush! + * + * There is no shifting and fixed point arithmetic, as I really doubt + * you can see the difference, and it costs. This may be just my + * bias, since I heard that Intel is really bad at shifting. + */ + +static int +number_of_bits_set (unsigned long a) +/* + * How many 1 bits are there in the longword. + * Low performance, do not call often. + */ +{ + if (!a) + return 0; + if (a & 1) + return 1 + number_of_bits_set (a >> 1); + else + return (number_of_bits_set (a >> 1)); +} + +static int +free_bits_at_top (unsigned long a) +/* + * How many 0 bits are there at most significant end of longword. + * Low performance, do not call often. + */ +{ + if(!a) /* assume char is 8 bits */ + return sizeof (unsigned long) * 8; + else if (((long) a) < 0l) /* assume twos complement */ + return 0; + else + return 1 + free_bits_at_top ( a << 1); +} + +static int +free_bits_at_bottom (unsigned long a) +/* + * How many 0 bits are there at least significant end of longword. + * Low performance, do not call often. + */ +{ + /* assume char is 8 bits */ + if (!a) + return sizeof (unsigned long) * 8; + else if(((long) a) & 1l) + return 0; + else + return 1 + free_bits_at_bottom ( a >> 1); +} + +static int +display_16_bit (const struct fiasco_renderer *this, unsigned char *ximage, + const fiasco_image_t *fiasco_image) +/* + * Convert 'image' to 16 bit color bitmap. + * If 'double_resolution' is true then double image size in both directions. + * + * No return value. + * + * Side effects: + * 'out[]' is filled with dithered image + */ +{ + const image_t *image; + renderer_private_t *private; + byte_t *out; + + if (!this) + { + set_error (_("Parameter `%s' not defined (NULL)."), "this"); + return 0; + } + if (!ximage) + { + set_error (_("Parameter `%s' not defined (NULL)."), "ximage"); + return 0; + } + if (!fiasco_image) + { + set_error (_("Parameter `%s' not defined (NULL)."), "fiasco_image"); + return 0; + } + + out = (byte_t *) ximage; + image = cast_image ((fiasco_image_t *) fiasco_image); + if (!image) + return 0; + private = (renderer_private_t *) this->private; + + if (image->color) + { + word_t *cbptr, *crptr; /* pointer to chroma bands */ + word_t *yptr; /* pointers to lumincance band */ + int yval, crval, cbval; /* pixel value in YCbCr color space */ + int R, G, B; /* pixel value in RGB color space */ + int n; /* pixel counter */ + int x, y; /* pixel coordinates */ + int *Cr_r_tab, *Cr_g_tab, *Cb_g_tab, *Cb_b_tab; + unsigned int *r_table, *g_table, *b_table; + + Cr_g_tab = private->Cr_g_tab; + Cr_r_tab = private->Cr_r_tab; + Cb_b_tab = private->Cb_b_tab; + Cb_g_tab = private->Cb_g_tab; + r_table = private->r_table; + g_table = private->g_table; + b_table = private->b_table; + yptr = image->pixels [Y]; + cbptr = image->pixels [Cb]; + crptr = image->pixels [Cr]; + + if (image->format == FORMAT_4_2_0) + { + u_word_t *dst, *dst2; /* pointers to dithered pixels */ + word_t *yptr2; /* pointers to lumincance band */ + + if (private->double_resolution) + { + yptr2 = yptr + image->width; + dst = (u_word_t *) out; + dst2 = dst + 4 * image->width; + for (y = image->height / 2; y; y--) + { + for (x = image->width / 2; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + crval = *crptr++ >> 4; + cbval = *cbptr++ >> 4; + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + crval = *crptr++ / 16; + cbval = *cbptr++ / 16; + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + } + memcpy (dst, dst - 2 * image->width, + 2 * image->width * sizeof (u_word_t)); + memcpy (dst2, dst2 - 2 * image->width, + 2 * image->width * sizeof (u_word_t)); + yptr += image->width; + yptr2 += image->width; + dst += 3 * image->width * 2; + dst2 += 3 * image->width * 2; + } + } + else + { + yptr2 = yptr + image->width; + dst = (u_word_t *) out; + dst2 = dst + image->width; + + for (y = image->height / 2; y; y--) + { + for (x = image->width / 2; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + crval = *crptr++ >> 4; + cbval = *cbptr++ >> 4; + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + crval = *crptr++ / 16; + cbval = *cbptr++ / 16; + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + } + yptr += image->width; + yptr2 += image->width; + dst += image->width; + dst2 += image->width; + } + } + } + else /* 4:4:4 format */ + { + if (private->double_resolution) + { + unsigned int *dst; /* pointer to dithered pixels */ + + dst = (unsigned int *) out; + + for (y = image->height; y; y--) + { + for (x = image->width; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + crval = *crptr++ >> 4; + cbval = *cbptr++ >> 4; + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + crval = *crptr++ / 16; + cbval = *cbptr++ / 16; + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + + *dst++ = r_table [R] | g_table [G] | b_table [B]; + } + memcpy (dst, dst - image->width, + image->width * sizeof (unsigned int)); + dst += image->width; + } + } + else + { + u_word_t *dst; /* pointer to dithered pixels */ + + dst = (u_word_t *) out; + + for (n = image->width * image->height; n; n--) + { +#ifdef HAVE_SIGNED_SHIFT + crval = *crptr++ >> 4; + cbval = *cbptr++ >> 4; + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + crval = *crptr++ / 16; + cbval = *cbptr++ / 16; + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + + *dst++ = r_table [R] | g_table [G] | b_table [B]; + } + } + } + } + else + { + unsigned int *dst; /* pointer to dithered pixels */ + word_t *src; /* current pixel of frame */ + unsigned int *y_table; + + y_table = private->y_table; + dst = (unsigned int *) out; + src = image->pixels [GRAY]; + + if (private->double_resolution) + { + int x, y; /* pixel coordinates */ + + for (y = image->height; y; y--) + { + for (x = image->width; x; x--) + { + int value; + +#ifdef HAVE_SIGNED_SHIFT + value = y_table [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + value = y_table [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + *dst++ = (value << 16) | value; + } + + memcpy (dst, dst - image->width, + image->width * sizeof (unsigned int)); + dst += image->width; + } + } + else + { + int n; /* pixel counter */ + + for (n = image->width * image->height / 2; n; n--, src += 2) +#ifdef HAVE_SIGNED_SHIFT +# ifndef WORDS_BIGENDIAN + *dst++ = (y_table [src [1] >> 4] << 16) | y_table [src [0] >> 4]; +# else /* not WORDS_BIGENDIAN */ + *dst++ = (y_table [src [0] >> 4] << 16) | y_table [src [1] >> 4]; +# endif +#else /* not HAVE_SIGNED_SHIFT */ +# ifndef WORDS_BIGENDIAN + *dst++ = (y_table [src [1] / 16] << 16) | y_table [src [0] / 16]; +# else /* not WORDS_BIGENDIAN */ + *dst++ = (y_table [src [0] / 16] << 16) | y_table [src [1] / 16]; +# endif +#endif /* not HAVE_SIGNED_SHIFT */ + } + } + + return 1; +} + +static int +display_24_bit_bgr (const struct fiasco_renderer *this, unsigned char *ximage, + const fiasco_image_t *fiasco_image) +/* + * Convert 'image' to 16 bit color bitmap. + * If 'double_resolution' is true then double image size in both directions. + * + * No return value. + * + * Side effects: + * 'out[]' is filled with dithered image + */ +{ + unsigned *gray_clip = init_clipping (); + const image_t *image; + renderer_private_t *private; + byte_t *out; + + if (!gray_clip) + return 0; + if (!this) + { + set_error (_("Parameter `%s' not defined (NULL)."), "this"); + return 0; + } + if (!ximage) + { + set_error (_("Parameter `%s' not defined (NULL)."), "ximage"); + return 0; + } + if (!fiasco_image) + { + set_error (_("Parameter `%s' not defined (NULL)."), "fiasco_image"); + return 0; + } + + out = (byte_t *) ximage; + image = cast_image ((fiasco_image_t *) fiasco_image); + if (!image) + return 0; + private = (renderer_private_t *) this->private; + + if (image->color) + { + word_t *cbptr, *crptr; /* pointer to chroma bands */ + word_t *yptr; /* pointers to lumincance band */ + int *Cr_r_tab, *Cr_g_tab, *Cb_g_tab, *Cb_b_tab; + unsigned int *r_table, *g_table, *b_table; + + Cr_g_tab = private->Cr_g_tab; + Cr_r_tab = private->Cr_r_tab; + Cb_b_tab = private->Cb_b_tab; + Cb_g_tab = private->Cb_g_tab; + r_table = private->r_table; + g_table = private->g_table; + b_table = private->b_table; + yptr = image->pixels [Y]; + cbptr = image->pixels [Cb]; + crptr = image->pixels [Cr]; + + if (image->format == FORMAT_4_2_0) + { + if (private->double_resolution) + { + int yval1; /* lumincance pixel */ + int crval1, cbval1; /* chroma pixels */ + int yval2; /* pixel in YCbCr color space */ + unsigned int R1, G1, B1; /* pixel in RGB color space */ + unsigned int R2, G2, B2; /* pixel in RGB color space */ + int x, y; /* pixel counter */ + unsigned int *dst; /* pointer to dithered pixels */ + unsigned int *dst2; /* pointers to dithered pixels */ + word_t *yptr2; /* pointers to lumincance band */ + + dst = (unsigned int *) out; + dst2 = dst + (image->width >> 1) * 3 * 2; + yptr2 = yptr + image->width; + + for (y = image->height >> 1; y; y--) + { + for (x = image->width >> 1; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst++ = B1 | (G1 << 8) | (R1 << 16) | (B1 << 24); + *dst++ = G1 | (R1 << 8) | (B2 << 16) | (G2 << 24); + *dst++ = R2 | (B2 << 8) | (G2 << 16) | (R2 << 24); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr2++ >> 4) + 128; + yval2 = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr2++ / 16 + 128; + yval2 = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst2++ = B1 | (G1 << 8) | (R1 << 16) | (B1 << 24); + *dst2++ = G1 | (R1 << 8) | (B2 << 16) | (G2 << 24); + *dst2++ = R2 | (B2 << 8) | (G2 << 16) | (R2 << 24); + } + memcpy (dst, dst - (image->width >> 1) * 3, + (image->width >> 1) * 3 * sizeof (unsigned int)); + memcpy (dst2, dst2 - (image->width >> 1) * 3, + (image->width >> 1) * 3 * sizeof (unsigned int)); + dst += (image->width >> 1) * 3 * 3; + dst2 += (image->width >> 1) * 3 * 3; + yptr += image->width; + yptr2 += image->width; + } + } + else + { + int yval1; /* lumincance pixel */ + int crval1, cbval1; /* chroma pixels */ + int yval2; /* pixel in YCbCr color space */ + unsigned int R1, G1, B1; /* pixel in RGB color space */ + unsigned int R2, G2, B2; /* pixel in RGB color space */ + int x, y; /* pixel counter */ + unsigned int *dst; /* pointer to dithered pixels */ + unsigned int *dst2; /* pointers to dithered pixels */ + word_t *yptr2; /* pointers to lumincance band */ + + dst = (unsigned int *) out; + dst2 = dst + (image->width >> 2) * 3; + yptr2 = yptr + image->width; + + for (y = image->height >> 1; y; y--) + { + for (x = image->width >> 2; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst++ = B1 | (G1 << 8) | (R1 << 16) | (B2 << 24); + *dst = G2 | (R2 << 8); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr2++ >> 4) + 128; + yval2 = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr2++ / 16 + 128; + yval2 = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst2++ = B1 | (G1 << 8) | (R1 << 16) | (B2 << 24); + *dst2 = G2 | (R2 << 8); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + crval2 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; + cbval2 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst++ |= (B1 << 16) | (G1 << 24); + *dst++ = R1 | (B2 << 8) | (G2 << 16) | (R2 << 24); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr2++ >> 4) + 128; + yval2 = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr2++ / 16 + 128; + yval2 = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst2++ |= (B1 << 16) | (G1 << 24); + *dst2++ = R1 | (B2 << 8) | (G2 << 16) | (R2 << 24); + } + dst += (image->width >> 2) * 3; + dst2 += (image->width >> 2) * 3; + yptr += image->width; + yptr2 += image->width; + } + } + } + else /* 4:4:4 format */ + { + if (private->double_resolution) + { + unsigned int R1, G1, B1; /* pixel1 in RGB color space */ + unsigned int R2, G2, B2; /* pixel2 in RGB color space */ + int yval1, crval1, cbval1; /* pixel1 in YCbCr space */ + int yval2, crval2, cbval2; /* pixel2 in YCbCr space */ + int x, y; /* pixel counter */ + unsigned int *dst; /* dithered pixel pointer */ + + dst = (unsigned int *) out; + + for (y = image->height; y; y--) + { + for (x = image->width >> 1; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + crval2 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; + cbval2 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + crval2 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; + cbval2 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval2]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval2] + + Cb_g_tab [cbval2]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval2]]; + + *dst++ = B1 | (G1 << 8) | (R1 << 16) | (B1 << 24); + *dst++ = G1 | (R1 << 8) | (B2 << 16) | (G2 << 24); + *dst++ = R2 | (B2 << 8) | (G2 << 16) | (R2 << 24); + } + memcpy (dst, dst - 3 * (image->width >> 1), + 3 * (image->width >> 1) * sizeof (unsigned int)); + dst += 3 * (image->width >> 1); + } + } + else + { + unsigned int R1, G1, B1; /* pixel in RGB color space */ + unsigned int R2, G2, B2; /* pixel in RGB color space */ + int yval1, crval1, cbval1; /* pixel1 in YCbCr space */ + int yval2, crval2, cbval2; /* pixel2 in YCbCr space */ + int n; /* pixel counter */ + unsigned int *dst; /* dithered pixel pointer */ + + dst = (unsigned int *) out; + + for (n = (image->width * image->height) >> 2; n; n--) + { +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + crval2 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; + cbval2 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + crval2 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; + cbval2 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval2]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval2] + Cb_g_tab [cbval2]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval2]]; + + *dst++ = B1 | (G1 << 8) | (R1 << 16) | (B2 << 24); + *dst = G2 | (R2 << 8); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + crval2 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; + cbval2 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + crval2 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; + cbval2 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval2]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval2] + Cb_g_tab [cbval2]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval2]]; + + *dst++ |= (B1 << 16) | (G1 << 24); + *dst++ = R1 | (B2 << 8) | (G2 << 16) | (R2 << 24); + } + } + } + } + else + { + unsigned int *dst; /* pointer to dithered pixels */ + word_t *src; /* current pixel of frame */ + unsigned int *y_table; + + y_table = private->y_table; + dst = (unsigned int *) out; + src = image->pixels [GRAY]; + + if (private->double_resolution) + { + int x, y; /* pixel counter */ + unsigned *shift_clipping = gray_clip + 128; + + for (y = image->height; y; y--) + { + for (x = image->width >> 1; x; x--) + { + unsigned int val1, val2; +#ifdef HAVE_SIGNED_SHIFT + val1 = shift_clipping [*src++ >> 4]; + val2 = shift_clipping [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + val1 = shift_clipping [*src++ / 16]; + val2 = shift_clipping [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + + *dst++ = val1 | (val1 << 8) | (val1 << 16) | (val1 << 24); + *dst++ = val1 | (val1 << 8) | (val2 << 16) | (val2 << 24); + *dst++ = val2 | (val2 << 8) | (val2 << 16) | (val2 << 24); + } + + memcpy (dst, dst - 3 * (image->width >> 1), + 3 * (image->width >> 1) * sizeof (unsigned int)); + dst += 3 * (image->width >> 1); + } + } + else + { + int n; /* pixel counter */ + unsigned *shift_clipping = gray_clip + 128; + + for (n = (image->width * image->height) >> 2; n; n--) + { + unsigned int val1, val2; + +#ifdef HAVE_SIGNED_SHIFT + val1 = shift_clipping [*src++ >> 4]; + val2 = shift_clipping [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + val1 = shift_clipping [*src++ / 16]; + val2 = shift_clipping [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + + *dst++ = val1 | (val1 << 8) + | (val1 << 16) | (val2 << 24); /* RGBR */ + *dst = val2 | (val2 << 8); /* GB-- */ + +#ifdef HAVE_SIGNED_SHIFT + val1 = shift_clipping [*src++ >> 4]; + val2 = shift_clipping [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + val1 = shift_clipping [*src++ / 16]; + val2 = shift_clipping [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + + *dst++ |= (val1 << 16) | (val1 << 24); /* --RG */ + *dst++ = val1 | (val2 << 8) + | (val2 << 16) | (val2 << 24); /* BRGB */ + } + } + } + + return 1; +} + +static int +display_24_bit_rgb (const struct fiasco_renderer *this, unsigned char *ximage, + const fiasco_image_t *fiasco_image) +/* + * Convert 'image' to 16 bit color bitmap. + * If 'double_resolution' is true then double image size in both directions. + * + * No return value. + * + * Side effects: + * 'out[]' is filled with dithered image + */ +{ + unsigned *gray_clip = init_clipping (); + const image_t *image; + renderer_private_t *private; + byte_t *out; + + if (!gray_clip) + return 0; + if (!this) + { + set_error (_("Parameter `%s' not defined (NULL)."), "this"); + return 0; + } + if (!ximage) + { + set_error (_("Parameter `%s' not defined (NULL)."), "ximage"); + return 0; + } + if (!fiasco_image) + { + set_error (_("Parameter `%s' not defined (NULL)."), "fiasco_image"); + return 0; + } + + out = (byte_t *) ximage; + image = cast_image ((fiasco_image_t *) fiasco_image); + if (!image) + return 0; + private = (renderer_private_t *) this->private; + + if (image->color) + { + word_t *cbptr, *crptr; /* pointer to chroma bands */ + word_t *yptr; /* pointers to lumincance band */ + int *Cr_r_tab, *Cr_g_tab, *Cb_g_tab, *Cb_b_tab; + unsigned int *r_table, *g_table, *b_table; + + Cr_g_tab = private->Cr_g_tab; + Cr_r_tab = private->Cr_r_tab; + Cb_b_tab = private->Cb_b_tab; + Cb_g_tab = private->Cb_g_tab; + r_table = private->r_table; + g_table = private->g_table; + b_table = private->b_table; + yptr = image->pixels [Y]; + cbptr = image->pixels [Cb]; + crptr = image->pixels [Cr]; + + if (image->format == FORMAT_4_2_0) + { + if (private->double_resolution) + { + int yval1; /* lumincance pixel */ + int crval1, cbval1; /* chroma pixels */ + int yval2; /* pixel in YCbCr color space */ + unsigned int R1, G1, B1; /* pixel in RGB color space */ + unsigned int R2, G2, B2; /* pixel in RGB color space */ + int x, y; /* pixel counter */ + unsigned int *dst; /* pointer to dithered pixels */ + unsigned int *dst2; /* pointers to dithered pixels */ + word_t *yptr2; /* pointers to lumincance band */ + + dst = (unsigned int *) out; + dst2 = dst + (image->width >> 1) * 3 * 2; + yptr2 = yptr + image->width; + + for (y = image->height >> 1; y; y--) + { + for (x = image->width >> 1; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst++ = R1 | (G1 << 8) | (B1 << 16) | (R1 << 24); + *dst++ = G1 | (B1 << 8) | (R2 << 16) | (G2 << 24); + *dst++ = B2 | (R2 << 8) | (G2 << 16) | (B2 << 24); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr2++ >> 4) + 128; + yval2 = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr2++ / 16 + 128; + yval2 = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst2++ = R1 | (G1 << 8) | (B1 << 16) | (R1 << 24); + *dst2++ = G1 | (B1 << 8) | (R2 << 16) | (G2 << 24); + *dst2++ = B2 | (R2 << 8) | (G2 << 16) | (B2 << 24); + } + memcpy (dst, dst - (image->width >> 1) * 3, + (image->width >> 1) * 3 * sizeof (unsigned int)); + memcpy (dst2, dst2 - (image->width >> 1) * 3, + (image->width >> 1) * 3 * sizeof (unsigned int)); + dst += (image->width >> 1) * 3 * 3; + dst2 += (image->width >> 1) * 3 * 3; + yptr += image->width; + yptr2 += image->width; + } + } + else + { + int yval1; /* lumincance pixel */ + int crval1, cbval1; /* chroma pixels */ + int yval2; /* pixel in YCbCr color space */ + unsigned int R1, G1, B1; /* pixel in RGB color space */ + unsigned int R2, G2, B2; /* pixel in RGB color space */ + int x, y; /* pixel counter */ + unsigned int *dst; /* pointer to dithered pixels */ + unsigned int *dst2; /* pointers to dithered pixels */ + word_t *yptr2; /* pointers to lumincance band */ + + dst = (unsigned int *) out; + dst2 = dst + (image->width >> 2) * 3; + yptr2 = yptr + image->width; + + for (y = image->height >> 1; y; y--) + { + for (x = image->width >> 2; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst++ = R1 | (G1 << 8) | (B1 << 16) | (R2 << 24); + *dst = G2 | (B2 << 8); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr2++ >> 4) + 128; + yval2 = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr2++ / 16 + 128; + yval2 = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst2++ = R1 | (G1 << 8) | (B1 << 16) | (R2 << 24); + *dst2 = G2 | (B2 << 8); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + crval2 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; + cbval2 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst++ |= (R1 << 16) | (G1 << 24); + *dst++ = B1 | (R2 << 8) | (G2 << 16) | (B2 << 24); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr2++ >> 4) + 128; + yval2 = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr2++ / 16 + 128; + yval2 = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst2++ |= (R1 << 16) | (G1 << 24); + *dst2++ = B1 | (R2 << 8) | (G2 << 16) | (B2 << 24); + } + dst += (image->width >> 2) * 3; + dst2 += (image->width >> 2) * 3; + yptr += image->width; + yptr2 += image->width; + } + } + } + else /* 4:4:4 format */ + { + if (private->double_resolution) + { + unsigned int R1, G1, B1; /* pixel1 in RGB color space */ + unsigned int R2, G2, B2; /* pixel2 in RGB color space */ + int yval1, crval1, cbval1; /* pixel1 in YCbCr space */ + int yval2, crval2, cbval2; /* pixel2 in YCbCr space */ + int x, y; /* pixel counter */ + unsigned int *dst; /* dithered pixel pointer */ + + dst = (unsigned int *) out; + + for (y = image->height; y; y--) + { + for (x = image->width >> 1; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + crval2 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; + cbval2 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + crval2 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; + cbval2 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval2]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval2] + + Cb_g_tab [cbval2]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval2]]; + + *dst++ = R1 | (G1 << 8) | (B1 << 16) | (R1 << 24); + *dst++ = G1 | (B1 << 8) | (R2 << 16) | (G2 << 24); + *dst++ = B2 | (R2 << 8) | (G2 << 16) | (B2 << 24); + } + memcpy (dst, dst - 3 * (image->width >> 1), + 3 * (image->width >> 1) * sizeof (unsigned int)); + dst += 3 * (image->width >> 1); + } + } + else + { + unsigned int R1, G1, B1; /* pixel in RGB color space */ + unsigned int R2, G2, B2; /* pixel in RGB color space */ + int yval1, crval1, cbval1; /* pixel1 in YCbCr space */ + int yval2, crval2, cbval2; /* pixel2 in YCbCr space */ + int n; /* pixel counter */ + unsigned int *dst; /* dithered pixel pointer */ + + dst = (unsigned int *) out; + + for (n = (image->width * image->height) >> 2; n; n--) + { +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + crval2 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; + cbval2 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + crval2 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; + cbval2 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval2]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval2] + Cb_g_tab [cbval2]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval2]]; + + *dst++ = R1 | (G1 << 8) | (B1 << 16) | (R2 << 24); + *dst = G2 | (B2 << 8); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + crval2 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; + cbval2 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + crval2 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; + cbval2 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval2]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval2] + Cb_g_tab [cbval2]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval2]]; + + *dst++ |= (R1 << 16) | (G1 << 24); + *dst++ = B1 | (R2 << 8) | (G2 << 16) | (B2 << 24); + } + } + } + } + else + { + unsigned int *dst; /* pointer to dithered pixels */ + word_t *src; /* current pixel of frame */ + unsigned int *y_table; + + y_table = private->y_table; + dst = (unsigned int *) out; + src = image->pixels [GRAY]; + + if (private->double_resolution) + { + int x, y; /* pixel counter */ + unsigned *shift_clipping = gray_clip + 128; + + for (y = image->height; y; y--) + { + for (x = image->width >> 1; x; x--) + { + unsigned int val1, val2; +#ifdef HAVE_SIGNED_SHIFT + val1 = shift_clipping [*src++ >> 4]; + val2 = shift_clipping [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + val1 = shift_clipping [*src++ / 16]; + val2 = shift_clipping [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + + *dst++ = val1 | (val1 << 8) | (val1 << 16) | (val1 << 24); + *dst++ = val1 | (val1 << 8) | (val2 << 16) | (val2 << 24); + *dst++ = val2 | (val2 << 8) | (val2 << 16) | (val2 << 24); + } + + memcpy (dst, dst - 3 * (image->width >> 1), + 3 * (image->width >> 1) * sizeof (unsigned int)); + dst += 3 * (image->width >> 1); + } + } + else + { + int n; /* pixel counter */ + unsigned *shift_clipping = gray_clip + 128; + + for (n = (image->width * image->height) >> 2; n; n--) + { + unsigned int val1, val2; + +#ifdef HAVE_SIGNED_SHIFT + val1 = shift_clipping [*src++ >> 4]; + val2 = shift_clipping [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + val1 = shift_clipping [*src++ / 16]; + val2 = shift_clipping [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + + *dst++ = val1 | (val1 << 8) + | (val1 << 16) | (val2 << 24); /* RGBR */ + *dst = val2 | (val2 << 8); /* GB-- */ + +#ifdef HAVE_SIGNED_SHIFT + val1 = shift_clipping [*src++ >> 4]; + val2 = shift_clipping [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + val1 = shift_clipping [*src++ / 16]; + val2 = shift_clipping [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + + *dst++ |= (val1 << 16) | (val1 << 24); /* --RG */ + *dst++ = val1 | (val2 << 8) + | (val2 << 16) | (val2 << 24); /* BRGB */ + } + } + } + + return 1; +} + +static int +display_32_bit (const struct fiasco_renderer *this, unsigned char *ximage, + const fiasco_image_t *fiasco_image) +/* + * Convert 'image' to 16 bit color bitmap. + * If 'double_resolution' is true then double image size in both directions. + * + * No return value. + * + * Side effects: + * 'out[]' is filled with dithered image + */ +{ + const image_t *image; + renderer_private_t *private; + byte_t *out; + + if (!this) + { + set_error (_("Parameter `%s' not defined (NULL)."), "this"); + return 0; + } + if (!ximage) + { + set_error (_("Parameter `%s' not defined (NULL)."), "ximage"); + return 0; + } + if (!fiasco_image) + { + set_error (_("Parameter `%s' not defined (NULL)."), "fiasco_image"); + return 0; + } + + out = (byte_t *) ximage; + private = (renderer_private_t *) this->private; + image = cast_image ((fiasco_image_t *) fiasco_image); + if (!image) + return 0; + + if (image->color) + { + word_t *cbptr, *crptr; /* pointer to chroma bands */ + word_t *yptr; /* pointers to lumincance band */ + int yval, crval, cbval; /* pixel value in YCbCr color space */ + int R, G, B; /* pixel value in RGB color space */ + int n; /* pixel counter */ + int x, y; /* pixel coordinates */ + int *Cr_r_tab, *Cr_g_tab, *Cb_g_tab, *Cb_b_tab; + unsigned int *r_table, *g_table, *b_table; + + Cr_g_tab = private->Cr_g_tab; + Cr_r_tab = private->Cr_r_tab; + Cb_b_tab = private->Cb_b_tab; + Cb_g_tab = private->Cb_g_tab; + r_table = private->r_table; + g_table = private->g_table; + b_table = private->b_table; + yptr = image->pixels [Y]; + cbptr = image->pixels [Cb]; + crptr = image->pixels [Cr]; + + if (image->format == FORMAT_4_2_0) + { + unsigned int *dst, *dst2; /* pointers to dithered pixels */ + word_t *yptr2; /* pointers to lumincance band */ + + if (private->double_resolution) + { + yptr2 = yptr + image->width; + dst = (unsigned int *) out; + dst2 = dst + 4 * image->width; + for (y = image->height / 2; y; y--) + { + for (x = image->width / 2; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + crval = *crptr++ >> 4; + cbval = *cbptr++ >> 4; + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + crval = *crptr++ / 16; + cbval = *cbptr++ / 16; + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + } + memcpy (dst, dst - 2 * image->width, + 2 * image->width * sizeof (unsigned int)); + memcpy (dst2, dst2 - 2 * image->width, + 2 * image->width * sizeof (unsigned int)); + yptr += image->width; + yptr2 += image->width; + dst += 3 * image->width * 2; + dst2 += 3 * image->width * 2; + } + } + else + { + yptr2 = yptr + image->width; + dst = (unsigned int *) out; + dst2 = dst + image->width; + + for (y = image->height / 2; y; y--) + { + for (x = image->width / 2; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + crval = *crptr++ >> 4; + cbval = *cbptr++ >> 4; + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + crval = *crptr++ / 16; + cbval = *cbptr++ / 16; + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + } + yptr += image->width; + yptr2 += image->width; + dst += image->width; + dst2 += image->width; + } + } + } + else /* 4:4:4 format */ + { + if (private->double_resolution) + { + unsigned int *dst; /* pointer to dithered pixels */ + + dst = (unsigned int *) out; + + for (y = image->height; y; y--) + { + for (x = image->width; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + crval = *crptr++ >> 4; + cbval = *cbptr++ >> 4; + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + crval = *crptr++ / 16; + cbval = *cbptr++ / 16; + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + + *dst++ = r_table [R] | g_table [G] | b_table [B]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + } + memcpy (dst, dst - 2 * image->width, + 2 * image->width * sizeof (unsigned int)); + dst += image->width * 2; + } + } + else + { + unsigned int *dst; /* pointer to dithered pixels */ + + dst = (unsigned int *) out; + + for (n = image->width * image->height; n; n--) + { +#ifdef HAVE_SIGNED_SHIFT + crval = *crptr++ >> 4; + cbval = *cbptr++ >> 4; + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + crval = *crptr++ / 16; + cbval = *cbptr++ / 16; + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + + *dst++ = r_table [R] | g_table [G] | b_table [B]; + } + } + } + } + else + { + unsigned int *dst; /* pointer to dithered pixels */ + word_t *src; /* current pixel of frame */ + unsigned int *y_table; + + y_table = private->y_table; + dst = (unsigned int *) out; + src = image->pixels [GRAY]; + + if (private->double_resolution) + { + int x, y; /* pixel coordinates */ + + for (y = image->height; y; y--) + { + for (x = image->width; x; x--) + { + int value; + +#ifdef HAVE_SIGNED_SHIFT + value = y_table [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + value = y_table [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + *dst++ = value; + *dst++ = value; + } + + memcpy (dst, dst - 2 * image->width, + 2 * image->width * sizeof (unsigned int)); + dst += 2 * image->width; + } + } + else + { + int n; /* pixel counter */ + + for (n = image->width * image->height; n; n--) +#ifdef HAVE_SIGNED_SHIFT + *dst++ = y_table [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + *dst++ = y_table [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + } + } + + return 1; +} + + + |