/* * dither.c: Various dithering routines * * Adapted by: Ullrich Hafner * * This file is part of FIASCO (Fractal Image And Sequence COdec) * Copyright (C) 1994-2000 Ullrich Hafner */ /* * 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 "pm_config.h" #include "config.h" #include #include #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 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_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 # if BYTE_ORDER == LITTLE_ENDIAN *dst++ = (y_table [src [1] >> 4] << 16) | y_table [src [0] >> 4]; # else *dst++ = (y_table [src [0] >> 4] << 16) | y_table [src [1] >> 4]; # endif #else /* not HAVE_SIGNED_SHIFT */ # if BYTE_ORDER == LITTLE_ENDIAN *dst++ = (y_table [src [1] / 16] << 16) | y_table [src [0] / 16]; # else *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; 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; 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 */ 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; 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; 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 */ 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; }