📄 dither.c
字号:
/* * dither.c: Various dithering routines * * Adapted by: Ullrich Hafner * * This file is part of FIASCO (獸籸actal 獻籱age 獳籲d 玈籩quence 獵O籨ec) * 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 intfree_bits_at_bottom (unsigned long a);static intfree_bits_at_top (unsigned long a);static intnumber_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; } }voidfiasco_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); }}intfiasco_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 intnumber_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 intfree_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 intfree_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];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -