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 | |
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')
-rw-r--r-- | converter/other/fiasco/lib/Makefile | 33 | ||||
-rw-r--r-- | converter/other/fiasco/lib/arith.c | 708 | ||||
-rw-r--r-- | converter/other/fiasco/lib/arith.h | 122 | ||||
-rw-r--r-- | converter/other/fiasco/lib/bit-io.c | 327 | ||||
-rw-r--r-- | converter/other/fiasco/lib/bit-io.h | 58 | ||||
-rw-r--r-- | converter/other/fiasco/lib/dither.c | 1892 | ||||
-rw-r--r-- | converter/other/fiasco/lib/dither.h | 27 | ||||
-rw-r--r-- | converter/other/fiasco/lib/error.c | 326 | ||||
-rw-r--r-- | converter/other/fiasco/lib/error.h | 39 | ||||
-rw-r--r-- | converter/other/fiasco/lib/image.c | 512 | ||||
-rw-r--r-- | converter/other/fiasco/lib/image.h | 59 | ||||
-rw-r--r-- | converter/other/fiasco/lib/list.c | 258 | ||||
-rw-r--r-- | converter/other/fiasco/lib/list.h | 72 | ||||
-rw-r--r-- | converter/other/fiasco/lib/macros.h | 70 | ||||
-rw-r--r-- | converter/other/fiasco/lib/misc.c | 563 | ||||
-rw-r--r-- | converter/other/fiasco/lib/misc.h | 98 | ||||
-rw-r--r-- | converter/other/fiasco/lib/mvcode.c | 14 | ||||
-rw-r--r-- | converter/other/fiasco/lib/mvcode.h | 6 | ||||
-rw-r--r-- | converter/other/fiasco/lib/rpf.c | 223 | ||||
-rw-r--r-- | converter/other/fiasco/lib/rpf.h | 47 | ||||
-rw-r--r-- | converter/other/fiasco/lib/types.h | 38 |
21 files changed, 5492 insertions, 0 deletions
diff --git a/converter/other/fiasco/lib/Makefile b/converter/other/fiasco/lib/Makefile new file mode 100644 index 00000000..99d7c1d7 --- /dev/null +++ b/converter/other/fiasco/lib/Makefile @@ -0,0 +1,33 @@ +ifeq ($(SRCDIR)x,x) + SRCDIR = $(CURDIR)/../../../.. + BUILDDIR = $(SRCDIR) +endif +FIASCOSUBDIR = converter/other/fiasco +SUBDIR = $(FIASCOSUBDIR)/lib +VPATH=.:$(SRCDIR)/$(SUBDIR) + +include $(BUILDDIR)/Makefile.config + +OBJECTS = \ + arith.o \ + bit-io.o \ + dither.o \ + error.o \ + image.o \ + list.o \ + misc.o \ + rpf.o \ + mvcode.o \ + +MERGE_OBJECTS = $(OBJECTS) + +INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) + +all: libfiasco_lib.a + +include $(SRCDIR)/Makefile.common + +libfiasco_lib.a: $(OBJECTS) + $(AR) -rc $@ $(OBJECTS) + $(RANLIB) $@ + diff --git a/converter/other/fiasco/lib/arith.c b/converter/other/fiasco/lib/arith.c new file mode 100644 index 00000000..e3745bf7 --- /dev/null +++ b/converter/other/fiasco/lib/arith.c @@ -0,0 +1,708 @@ +/* + * arith.c: Adaptive arithmetic coding and decoding + * + * Written 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> + */ + +/* + * $Date: 2000/06/14 20:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "bit-io.h" +#include "misc.h" +#include "arith.h" + +/****************************************************************************** + + public code + +******************************************************************************/ + +arith_t * +alloc_encoder (bitfile_t *output) +/* + * Arithmetic coder constructor: + * Initialize the arithmetic coder. + * + * Return value: + * A pointer to the new coder structure + */ +{ + arith_t *arith = Calloc (1, sizeof (arith_t)); + + assert (output); + + arith->low = LOW; + arith->high = HIGH; + arith->underflow = 0; + arith->file = output; + + return arith; +} + +void +free_encoder (arith_t *arith) +/* + * Arithmetic encoder destructor. + * Flush the arithmetic coder. Append all remaining bits to the + * output stream. Append zero bits to get the output file byte aligned. + * + * No return value. + */ +{ + u_word_t low; /* start of the current code range */ + u_word_t high; /* end of the current code range */ + u_word_t underflow; /* number of underflow bits pending */ + bitfile_t *output; + + assert (arith); + + low = arith->low; + high = arith->high; + underflow = arith->underflow; + output = arith->file; + + low = high; + + RESCALE_OUTPUT_INTERVAL; + + OUTPUT_BYTE_ALIGN (output); + + Free (arith); +} + +real_t +encode_symbol (unsigned symbol, arith_t *arith, model_t *model) +/* + * Encode the given 'symbol' using the given probability 'model'. + * The current state of the arithmetic coder is given by 'arith'. + * Output bits are appended to the stream 'output'. + * + * The model is updated after encoding the symbol (if neccessary the + * symbol counts are rescaled). + * + * Return value: + * information content of the encoded symbol. + * + * Side effects: + * 'model' is updated (probability distribution) + * 'arith' is updated (coder state) + */ +{ + u_word_t low_count; /* lower bound of 'symbol' interval */ + u_word_t high_count; /* upper bound of 'symbol' interval */ + u_word_t scale; /* range of all 'm' symbol intervals */ + unsigned range; /* range of current interval */ + unsigned index; /* index of probability model */ + u_word_t low; /* start of the current code range */ + u_word_t high; /* end of the current code range */ + u_word_t underflow; /* number of underflow bits pending */ + bitfile_t *output; /* output file */ + + assert (model && arith); + + /* + * Get interval values + */ + low = arith->low; + high = arith->high; + underflow = arith->underflow; + output = arith->file; + + assert (high > low); + + if (model->order > 0) /* order-'n' model*/ + { + unsigned power; /* multiplicator */ + unsigned i; + + /* + * Compute index of the probability model to use. + * See init_model() for more details. + */ + power = 1; /* multiplicator */ + index = 0; /* address of prob. model */ + + for (i = 0; i < model->order; i++) /* genarate a M-nary number */ + { + index += model->context [i] * power; + power *= model->symbols; + } + + index *= model->symbols + 1; /* we need space for M + 1 elements */ + + for (i = 0; i < model->order - 1; i++) + model->context [i] = model->context [i + 1]; + model->context [i] = symbol; + } + else + index = 0; + + scale = model->totals [index + model->symbols]; + low_count = model->totals [index + symbol]; + high_count = model->totals [index + symbol + 1]; + + /* + * Compute the new interval depending on the input 'symbol'. + */ + range = (high - low) + 1; + high = low + (u_word_t) ((range * high_count) / scale - 1); + low = low + (u_word_t) ((range * low_count) / scale); + + RESCALE_OUTPUT_INTERVAL; + + if (model->scale > 0) /* adaptive model */ + { + unsigned i; + + /* + * Update probability model + */ + for (i = symbol + 1; i <= model->symbols; i++) + model->totals [index + i]++; + if (model->totals [index + model->symbols] > model->scale) /* scaling */ + { + for (i = 1; i <= model->symbols; i++) + { + model->totals [index + i] >>= 1; + if (model->totals [index + i] <= model->totals [index + i - 1]) + model->totals [index + i] = model->totals [index + i - 1] + 1; + } + } + } + + /* + * Store interval values + */ + arith->low = low; + arith->high = high; + arith->underflow = underflow; + + return - log2 ((high_count - low_count) / (real_t) scale); +} + +void +encode_array (bitfile_t *output, const unsigned *data, const unsigned *context, + const unsigned *c_symbols, unsigned n_context, unsigned n_data, + unsigned scaling) +/* + * Arithmetic coding of #'n_data' symbols given in the array 'data'. + * If 'n_context' > 1 then a number (context [n]) is assigned to every + * data element n, specifying which context (i.e. number of symbols given by + * c_symbols [context [n]] and adaptive probability model) must be used. + * Rescale probability models if range > 'scaling'. + * + * No return value. + */ +{ + u_word_t **totals; /* probability model */ + + if (!n_context) + n_context = 1; /* always use one context */ + + assert (output && c_symbols && data); + assert (n_context == 1 || context); + + /* + * Allocate probability models, start with uniform distribution + */ + totals = Calloc (n_context, sizeof (u_word_t *)); + { + unsigned c; + + for (c = 0; c < n_context; c++) + { + unsigned i; + + totals [c] = Calloc (c_symbols [c] + 1, sizeof (u_word_t)); + totals [c][0] = 0; + + for (i = 0; i < c_symbols [c]; i++) + totals [c][i + 1] = totals [c][i] + 1; + } + } + + /* + * Encode array elements + */ + { + u_word_t low = 0; /* Start of the current code range */ + u_word_t high = 0xffff; /* End of the current code range */ + u_word_t underflow = 0; /* Number of underflow bits pending */ + unsigned n; + + for (n = 0; n < n_data; n++) + { + u_word_t low_count; /* lower bound of 'symbol' interval */ + u_word_t high_count; /* upper bound of 'symbol' interval */ + u_word_t scale; /* range of all 'm' symbol intervals */ + unsigned range; /* current range */ + int d; /* current data symbol */ + int c; /* context of current data symbol */ + + d = data [n]; + c = n_context > 1 ? context [n] : 0; + + scale = totals [c][c_symbols [c]]; + low_count = totals [c][d]; + high_count = totals [c][d + 1]; + + /* + * Rescale high and low for the new symbol. + */ + range = (high - low) + 1; + high = low + (u_word_t) ((range * high_count) / scale - 1); + low = low + (u_word_t) ((range * low_count) / scale); + RESCALE_OUTPUT_INTERVAL; + + /* + * Update probability models + */ + { + unsigned i; + + for (i = d + 1; i < c_symbols [c] + 1; i++) + totals [c][i]++; + + if (totals [c][c_symbols [c]] > scaling) /* scaling */ + for (i = 1; i < c_symbols [c] + 1; i++) + { + totals [c][i] >>= 1; + if (totals [c][i] <= totals [c][i - 1]) + totals [c][i] = totals [c][i - 1] + 1; + } + } + } + /* + * Flush arithmetic encoder + */ + low = high; + RESCALE_OUTPUT_INTERVAL; + OUTPUT_BYTE_ALIGN (output); + } + + /* + * Cleanup ... + */ + { + unsigned c; + for (c = 0; c < n_context; c++) + Free (totals [c]); + Free (totals); + } +} + +arith_t * +alloc_decoder (bitfile_t *input) +/* + * Arithmetic decoder constructor: + * Initialize the arithmetic decoder with the first + * 16 input bits from the stream 'input'. + * + * Return value: + * A pointer to the new decoder structure + */ + +{ + arith_t *arith = Calloc (1, sizeof (arith_t)); + + assert (input); + + arith->low = LOW; + arith->high = HIGH; + arith->code = get_bits (input, 16); + arith->file = input; + + return arith; +} + +void +free_decoder (arith_t *arith) +/* + * Arithmetic decoder destructor: + * Flush the arithmetic decoder, i.e., read bits to get the input + * file byte aligned. + * + * No return value. + * + * Side effects: + * structure 'arith' is discarded. + */ +{ + assert (arith); + + INPUT_BYTE_ALIGN (arith->file); + + Free (arith); +} + +unsigned +decode_symbol (arith_t *arith, model_t *model) +/* + * Decode the next symbol - the state of the arithmetic decoder + * is given in 'arith'. Read refinement bits from the stream 'input' + * and use the given probability 'model'. Update the probability model after + * deconding the symbol (if neccessary also rescale the symbol counts). + * + * Return value: + * decoded symbol + * + * Side effects: + * 'model' is updated (probability distribution) + * 'arith' is updated (decoder state) + */ +{ + unsigned range; /* range of current interval */ + unsigned count; /* value in the current interval */ + unsigned index; /* index of probability model */ + unsigned symbol; /* decoded symbol */ + u_word_t scale; /* range of all 'm' symbol intervals */ + u_word_t low; /* start of the current code range */ + u_word_t high; /* end of the current code range */ + u_word_t code; /* the present input code value */ + bitfile_t *input; /* input file */ + + assert (arith && model); + + /* + * Get interval values + */ + low = arith->low; + high = arith->high; + code = arith->code; + input = arith->file; + + assert (high > low); + + if (model->order > 0) /* order-'n' model */ + { + unsigned power; /* multiplicator */ + unsigned i; + + /* + * Compute index of the probability model to use. + * See init_model() for more details. + */ + power = 1; /* multiplicator */ + index = 0; /* address of prob. model */ + + for (i = 0; i < model->order; i++) /* genarate a m-nary number */ + { + index += model->context[i] * power; + power *= model->symbols; + } + + index *= model->symbols + 1; /* we need space for m + 1 elements */ + } + else + index = 0; + + scale = model->totals [index + model->symbols]; + range = (high - low) + 1; + count = ((code - low + 1) * scale - 1) / range; + + for (symbol = model->symbols; count < model->totals [index + symbol]; + symbol--) + ; + + if (model->order > 0) /* order-'n' model */ + { + unsigned i; + + for (i = 0; i < model->order - 1; i++) + model->context [i] = model->context [i + 1]; + model->context [i] = symbol; + } + + /* + * Compute interval boundaries + */ + { + u_word_t low_count; /* lower bound of 'symbol' interval */ + u_word_t high_count; /* upper bound of 'symbol' interval */ + + low_count = model->totals [index + symbol]; + high_count = model->totals [index + symbol + 1]; + high = low + (u_word_t) ((range * high_count) / scale - 1 ); + low = low + (u_word_t) ((range * low_count) / scale ); + } + + RESCALE_INPUT_INTERVAL; + + if (model->scale > 0) /* adaptive model */ + { + unsigned i; + + /* + * Update probability model + */ + for (i = symbol + 1; i <= model->symbols; i++) + model->totals [index + i]++; + if (model->totals [index + model->symbols] > model->scale) /* scaling */ + { + for (i = 1; i <= model->symbols; i++) + { + model->totals [index + i] >>= 1; + if (model->totals [index + i] <= model->totals [index + i - 1]) + model->totals [index + i] = model->totals [index + i - 1] + 1; + } + } + } + + /* + * Store interval values + */ + arith->low = low; + arith->high = high; + arith->code = code; + + return symbol; +} + +unsigned * +decode_array (bitfile_t *input, const unsigned *context, + const unsigned *c_symbols, unsigned n_context, + unsigned n_data, unsigned scaling) +/* + * Arithmetic decoding of #'n_data' symbols. + * If 'n_context' > 1 then a number (context [n]) is assigned to every + * data element n, specifying which context (i.e. number of symbols given by + * c_symbols [context [n]] and adaptive probability model) must be used. + * Rescale probability models if range > 'scaling'. + * + * Return value: + * pointer to array containing the decoded symbols + */ +{ + unsigned *data; /* array to store decoded symbols */ + u_word_t **totals; /* probability model */ + + if (n_context < 1) + n_context = 1; /* always use one context */ + assert (input && c_symbols); + assert (n_context == 1 || context); + + data = Calloc (n_data, sizeof (unsigned)); + + /* + * Allocate probability models, start with uniform distribution + */ + totals = Calloc (n_context, sizeof (u_word_t *)); + { + unsigned c; + + for (c = 0; c < n_context; c++) + { + unsigned i; + + totals [c] = Calloc (c_symbols [c] + 1, sizeof (u_word_t)); + totals [c][0] = 0; + + for (i = 0; i < c_symbols [c]; i++) + totals [c][i + 1] = totals [c][i] + 1; + } + } + + /* + * Fill array 'data' with decoded values + */ + { + u_word_t code = get_bits (input, 16); /* The present input code value */ + u_word_t low = 0; /* Start of the current code range */ + u_word_t high = 0xffff; /* End of the current code range */ + unsigned n; + + for (n = 0; n < n_data; n++) + { + u_word_t scale; /* range of all 'm' symbol intervals */ + u_word_t low_count; /* lower bound of 'symbol' interval */ + u_word_t high_count; /* upper bound of 'symbol' interval */ + unsigned count; /* value in the current interval */ + unsigned range; /* current interval range */ + unsigned d; /* current data symbol */ + unsigned c; /* context of current data symbol */ + + c = n_context > 1 ? context [n] : 0; + + assert (high > low); + scale = totals [c][c_symbols [c]]; + range = (high - low) + 1; + count = (((code - low) + 1 ) * scale - 1) / range; + + for (d = c_symbols [c]; count < totals [c][d]; d--) /* next symbol */ + ; + low_count = totals [c][d]; + high_count = totals [c][d + 1]; + + high = low + (u_word_t) ((range * high_count) / scale - 1 ); + low = low + (u_word_t) ((range * low_count) / scale ); + RESCALE_INPUT_INTERVAL; + + /* + * Updata probability models + */ + { + unsigned i; + + for (i = d + 1; i < c_symbols [c] + 1; i++) + totals [c][i]++; + + if (totals [c][c_symbols [c]] > scaling) /* scaling */ + for (i = 1; i < c_symbols [c] + 1; i++) + { + totals [c][i] >>= 1; + if (totals [c][i] <= totals [c][i - 1]) + totals [c][i] = totals [c][i - 1] + 1; + } + } + data [n] = d; + } + INPUT_BYTE_ALIGN (input); + } + + /* + * Cleanup ... + */ + { + unsigned c; + + for (c = 0; c < n_context; c++) + Free (totals [c]); + Free (totals); + } + + return data; +} + +model_t * +alloc_model (unsigned m, unsigned scale, unsigned n, unsigned *totals) +/* + * Model constructor: + * allocate and initialize an order-'n' probability model. + * The size of the source alphabet is 'm'. Rescale the symbol counts after + * 'scale' symbols are encoded/decoded. The initial probability of every + * symbol is 1/m. + * If 'scale' = 0 then use static modeling (p = 1/n). + * If 'totals' is not NULL then use this array of 'm' values to set + * the initial counts. + * + * Return value: + * a pointer to the new probability model structure. + * + * Note: We recommend a small size of the alphabet because no escape codes + * are used to encode/decode previously unseen symbols. + * + */ +{ + model_t *model; /* new probability model */ + unsigned num; /* number of contexts to allocate */ + bool_t cont; /* continue flag */ + bool_t dec; /* next order flag */ + unsigned i; + + /* + * Allocate memory for the structure + */ + model = Calloc (1, sizeof (model_t)); + model->symbols = m; + model->scale = scale; + model->order = n; + model->context = n > 0 ? Calloc (n, sizeof (unsigned)) : NULL; + /* + * Allocate memory for the probabilty model. + * Each of the m^n different contexts requires its own probability model. + */ + for (num = 1, i = 0; i < model->order; i++) + num *= model->symbols; + + model->totals = Calloc (num * (model->symbols + 1), sizeof (unsigned)); + + for (i = 0; i < model->order; i++) + model->context[i] = 0; /* start with context 0,0, .. ,0 */ + cont = YES; + while (cont) /* repeat while context != M ... M */ + { + int power; /* multiplicator */ + int index; /* index of probability model */ + /* + * There are m^n different contexts: + * Let "context_1 context_2 ... context_n symbol" be the current input + * stream then the index of the probability model is given by: + * index = context_1 * M^0 + context_2 * M^1 + ... + context_n * M^(n-1) + */ + power = 1; /* multiplicator */ + index = 0; /* address of prob. model */ + + for (i = 0; i < model->order; i++) /* genarate a m-nary number */ + { + index += model->context[i] * power; + power *= model->symbols; + } + + index *= model->symbols + 1; /* size of each model is m + 1 */ + + model->totals [index + 0] = 0; /* always zero */ + + for (i = 1; i <= model->symbols; i++) /* prob of each symbol is 1/m or + as given in totals */ + model->totals[index + i] = model->totals [index + i - 1] + + (totals ? totals [i - 1] : 1); + + if (model->order == 0) /* order-0 model */ + cont = NO; + else /* try next context */ + for (i = model->order - 1, dec = YES; dec; i--) + { + dec = NO; + model->context[i]++; + if (model->context[i] >= model->symbols) + { + /* change previous context */ + model->context[i] = 0; + if (i > 0) /* there's still a context remaining */ + dec = YES; + else + cont = NO; /* all context models initilized */ + } + } + } + for (i = 0; i < model->order; i++) + model->context[i] = 0; /* start with context 0,0, .. ,0 */ + + return model; +} + +void +free_model (model_t *model) +/* + * Model destructor: + * Free memory allocated by the arithmetic 'model'. + * + * No return value. + * + * Side effects: + * struct 'model' is discarded + */ +{ + if (model != NULL) + { + if (model->context != NULL) + Free (model->context); + Free (model->totals); + Free (model); + } + else + warning ("Can't free model <NULL>."); +} diff --git a/converter/other/fiasco/lib/arith.h b/converter/other/fiasco/lib/arith.h new file mode 100644 index 00000000..744eb9d7 --- /dev/null +++ b/converter/other/fiasco/lib/arith.h @@ -0,0 +1,122 @@ +/* + * arith.h + * + * 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> + */ + +/* + * $Date: 2000/06/14 20:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _ARITH_H +#define _ARITH_H + +#include "types.h" +#include "bit-io.h" + +typedef struct model +{ + unsigned symbols; /* number of symbols in the alphabet */ + unsigned scale; /* if totals > scale rescale totals */ + unsigned order; /* order of the probability model */ + unsigned *context; /* context of the model */ + unsigned *totals; /* the totals */ +} model_t; + +typedef struct arith +{ + u_word_t low; /* start of the current code range */ + u_word_t high; /* end of the current code range */ + u_word_t underflow; /* number of underflow bits pending */ + u_word_t code; /* the present input code value */ + bitfile_t *file; /* I/O stream */ +} arith_t; + +enum interval {LOW = 0x0000, FIRST_QUARTER = 0x4000, HALF = 0x8000, + THIRD_QUARTER = 0xc000, HIGH = 0xffff}; + +arith_t * +alloc_encoder (bitfile_t *file); +void +free_encoder (arith_t *arith); +real_t +encode_symbol (unsigned symbol, arith_t *arith, model_t *model); +void +encode_array (bitfile_t *output, const unsigned *data, const unsigned *context, + const unsigned *c_symbols, unsigned n_context, unsigned n_data, + unsigned scaling); +arith_t * +alloc_decoder (bitfile_t *input); +void +free_decoder (arith_t *arith); +unsigned +decode_symbol (arith_t *arith, model_t *model); +unsigned * +decode_array (bitfile_t *input, const unsigned *context, + const unsigned *c_symbols, unsigned n_context, + unsigned n_data, unsigned scaling); +model_t * +alloc_model (unsigned m, unsigned scale, unsigned n, unsigned *totals); +void +free_model (model_t *model); + +#define RESCALE_INPUT_INTERVAL for (;;) \ + if ((high >= HALF) && (low < HALF) && \ + ((low & FIRST_QUARTER) != FIRST_QUARTER \ + || (high & FIRST_QUARTER) != 0)) \ + { \ + break; \ + } \ + else if ((high < HALF) || (low >= HALF)) \ + { \ + low <<= 1; \ + high <<= 1; \ + high |= 1; \ + code <<= 1; \ + code += get_bit (input); \ + } \ + else \ + { \ + code ^= FIRST_QUARTER; \ + low &= FIRST_QUARTER - 1; \ + low <<= 1; \ + high <<= 1; \ + high |= HALF + 1; \ + code <<= 1; \ + code += get_bit (input); \ + } + +#define RESCALE_OUTPUT_INTERVAL for (;;) \ + { \ + if (high < HALF) \ + { \ + put_bit (output, 0); \ + for (; underflow; underflow--) \ + put_bit (output, 1); \ + } \ + else if (low >= HALF) \ + { \ + put_bit (output, 1); \ + for (; underflow; underflow--) \ + put_bit (output, 0); \ + } \ + else if (high < THIRD_QUARTER && \ + low >= FIRST_QUARTER) \ + { \ + underflow++; \ + high |= FIRST_QUARTER; \ + low &= FIRST_QUARTER - 1; \ + } \ + else \ + break; \ + high <<= 1; \ + high |= 1; \ + low <<= 1; \ + } + +#endif /* not _ARITH_H */ + diff --git a/converter/other/fiasco/lib/bit-io.c b/converter/other/fiasco/lib/bit-io.c new file mode 100644 index 00000000..364a1c05 --- /dev/null +++ b/converter/other/fiasco/lib/bit-io.c @@ -0,0 +1,327 @@ +/* + * bit-io.c: Buffered and bit oriented file I/O + * + * Written 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> + */ + +/* + * $Date: 2000/06/14 20:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ + +#include "config.h" + +#include <string.h> +#if STDC_HEADERS +# include <stdlib.h> +#endif /* not STDC_HEADERS */ + +#include "macros.h" +#include "types.h" +#include "error.h" + +#include "misc.h" +#include "bit-io.h" + +/***************************************************************************** + + local constants + +*****************************************************************************/ + +static const unsigned BUFFER_SIZE = 16350; + +static const unsigned mask[] = {0x0001, 0x0002, 0x0004, 0x0008, + 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, + 0x1000, 0x2000, 0x4000, 0x8000}; + +/***************************************************************************** + + public code + +*****************************************************************************/ + +FILE * +open_file (const char *filename, const char *env_var, openmode_e mode) +/* + * Try to open file 'filename' with mode 'mode' (READ_ACCESS, WRITE_ACCESS). + * Scan the current directory first and then cycle through the + * path given in the environment variable 'env_var', if set. + * + * Return value: + * Pointer to open file on success, else NULL. + */ +{ + char *path; /* current path */ + FILE *fp; /* file pointer of I/O stream */ + char *ext_filename = NULL; /* full path of file */ + char *env_path = NULL; /* path given by 'env_var' */ + char const * const PATH_SEP = " ;:,"; /* path separation characters */ + char const * const DEFAULT_PATH = "."; /* default for output files */ + const char * const read_mode = "rb"; + const char * const write_mode = "wb"; + + + assert (mode == READ_ACCESS || mode == WRITE_ACCESS); + + /* + * First check for stdin or stdout + */ + if (filename == NULL || streq (filename, "-")) + { + if (mode == READ_ACCESS) + return stdin; + else + return stdout; + } + + /* + * Try to open 'readonly' file in the current directory + */ + if (mode == READ_ACCESS && (fp = fopen (filename, read_mode))) + return fp; + + if (mode == WRITE_ACCESS && strchr (filename, '/')) /* contains path */ + return fopen (filename, write_mode); + + /* + * Get value of environment variable 'env_var', if set + * else use DEFAULT_PATH ("./") + */ + if (env_var != NULL) + env_path = getenv (env_var); + if (env_path == NULL) + env_path = strdup (DEFAULT_PATH); + else + env_path = strdup (env_path); + + /* + * Try to open file in the directory given by the environment + * variable env_var - individual path components are separated by PATH_SEP + */ + path = strtok (env_path, PATH_SEP); + do + { + if (ext_filename) + Free (ext_filename); + ext_filename = Calloc (strlen (path) + strlen (filename) + 2, + sizeof (char)); + strcpy (ext_filename, path); + if (*(ext_filename + strlen (ext_filename) - 1) != '/') + strcat (ext_filename, "/"); + strcat (ext_filename, filename); + fp = fopen (ext_filename, mode == READ_ACCESS ? read_mode : write_mode); + } + while (fp == NULL && (path = strtok (NULL, PATH_SEP)) != NULL); + + Free (env_path); + + return fp; +} + +bitfile_t * +open_bitfile (const char *filename, const char *env_var, openmode_e mode) +/* + * Bitfile constructor: + * Try to open file 'filename' for buffered bit oriented access with mode + * 'mode'. Scan the current directory first and then cycle through the path + * given in the environment variable 'env_var', if set. + * + * Return value: + * Pointer to open bitfile on success, + * otherwise the program is terminated. + */ +{ + bitfile_t *bitfile = Calloc (1, sizeof (bitfile_t)); + + bitfile->file = open_file (filename, env_var, mode); + + if (bitfile->file == NULL) + file_error (filename); + + if (mode == READ_ACCESS) + { + bitfile->bytepos = 0; + bitfile->bitpos = 0; + bitfile->mode = mode; + bitfile->filename = filename ? strdup (filename) : strdup ("(stdin)"); + } + else if (mode == WRITE_ACCESS) + { + bitfile->bytepos = BUFFER_SIZE - 1; + bitfile->bitpos = 8; + bitfile->mode = mode; + bitfile->filename = filename ? strdup (filename) : strdup ("(stdout)"); + } + else + error ("Unknow file access mode '%d'.", mode); + + bitfile->bits_processed = 0; + bitfile->buffer = Calloc (BUFFER_SIZE, sizeof (byte_t)); + bitfile->ptr = bitfile->buffer; + + return bitfile; +} + +bool_t +get_bit (bitfile_t *bitfile) +/* + * Get one bit from the given stream 'bitfile'. + * + * Return value: + * 1 H bit + * 0 L bit + * + * Side effects: + * Buffer of 'bitfile' is modified accordingly. + */ +{ + assert (bitfile); + + if (!bitfile->bitpos--) /* use next byte ? */ + { + bitfile->ptr++; + if (!bitfile->bytepos--) /* no more bytes left in the buffer? */ + { + /* + * Fill buffer with new data + */ + int bytes = fread (bitfile->buffer, sizeof (byte_t), + BUFFER_SIZE, bitfile->file) - 1; + if (bytes < 0) /* Error or EOF */ + error ("Can't read next bit from bitfile %s.", bitfile->filename); + else + bitfile->bytepos = bytes; + + bitfile->ptr = bitfile->buffer; + } + bitfile->bitpos = 7; + } + + bitfile->bits_processed++; + + return *bitfile->ptr & mask [bitfile->bitpos] ? 1 : 0; +} + +unsigned int +get_bits (bitfile_t *bitfile, unsigned bits) +/* + * Get #'bits' bits from the given stream 'bitfile'. + * + * Return value: + * composed integer value + * + * Side effects: + * Buffer of 'bitfile' is modified. + */ +{ + unsigned value = 0; /* input value */ + + while (bits--) + value = (unsigned) (value << 1) | get_bit (bitfile); + + return value; +} + +void +put_bit (bitfile_t *bitfile, unsigned value) +/* + * Put the bit 'value' to the bitfile buffer. + * The buffer is written to the file 'bitfile->file' if the number of + * buffer bytes exceeds 'BUFFER_SIZE'. + * + * No return value. + * + * Side effects: + * Buffer of 'bitfile' is modified. + */ +{ + assert (bitfile); + + if (!bitfile->bitpos--) /* use next byte ? */ + { + bitfile->ptr++; + if (!bitfile->bytepos--) /* no more bytes left ? */ + { + /* + * Write buffer to disk and fill buffer with zeros + */ + if (fwrite (bitfile->buffer, sizeof (byte_t), + BUFFER_SIZE, bitfile->file) != BUFFER_SIZE) + error ("Can't write next bit of bitfile %s!", bitfile->filename); + memset (bitfile->buffer, 0, BUFFER_SIZE); + bitfile->bytepos = BUFFER_SIZE - 1; + bitfile->ptr = bitfile->buffer; + } + bitfile->bitpos = 7; + } + + if (value) + *bitfile->ptr |= mask [bitfile->bitpos]; + + bitfile->bits_processed++; +} + +void +put_bits (bitfile_t *bitfile, unsigned value, unsigned bits) +/* + * Put #'bits' bits of integer 'value' to the bitfile buffer 'bitfile'. + * + * No return value. + * + * Side effects: + * Buffer of 'bitfile' is modified. + */ +{ + while (bits--) + put_bit (bitfile, value & mask [bits]); +} + +void +close_bitfile (bitfile_t *bitfile) +/* + * Bitfile destructor: + * Close 'bitfile', if 'bitfile->mode' == WRITE_ACCESS write bit buffer + * to disk. + * + * No return value. + * + * Side effects: + * Structure 'bitfile' is discarded. + */ +{ + assert (bitfile); + + if (bitfile->mode == WRITE_ACCESS) + { + unsigned bytes = fwrite (bitfile->buffer, sizeof (byte_t), + BUFFER_SIZE - bitfile->bytepos, bitfile->file); + if (bytes != BUFFER_SIZE - bitfile->bytepos) + error ("Can't write remaining %d bytes of bitfile " + "(only %d bytes written)!", + BUFFER_SIZE - bitfile->bytepos, bytes); + } + fclose (bitfile->file); + Free (bitfile->buffer); + Free (bitfile->filename); + Free (bitfile); +} + +unsigned +bits_processed (const bitfile_t *bitfile) +/* + * Return value: + * Number of bits processed up to now + */ +{ + return bitfile->bits_processed; +} diff --git a/converter/other/fiasco/lib/bit-io.h b/converter/other/fiasco/lib/bit-io.h new file mode 100644 index 00000000..d37cc47c --- /dev/null +++ b/converter/other/fiasco/lib/bit-io.h @@ -0,0 +1,58 @@ +/* + * bit-io.h + * + * Written 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> + */ + +/* + * $Date: 2000/06/14 20:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _BIT_IO_H +#define _BIT_IO_H + +#include <stdio.h> +#include "types.h" + +#define OUTPUT_BYTE_ALIGN(bfile) while ((bfile)->bitpos) put_bit (bfile, 0); +#define INPUT_BYTE_ALIGN(bfile) while ((bfile)->bitpos) get_bit (bfile); + +typedef enum {READ_ACCESS, WRITE_ACCESS} openmode_e; + +typedef struct bitfile +{ + FILE *file; /* associated filepointer */ + char *filename; /* corresponding filename */ + byte_t *buffer; /* stream buffer */ + byte_t *ptr; /* pointer to current buffer pos */ + unsigned bytepos; /* current I/O byte */ + unsigned bitpos; /* current I/O bit */ + unsigned bits_processed; /* number of bits already processed */ + openmode_e mode; /* access mode */ +} bitfile_t; + +FILE * +open_file (const char *filename, const char *env_var, openmode_e mode); +bitfile_t * +open_bitfile (const char *filename, const char *env_var, openmode_e mode); +void +put_bit (bitfile_t *bitfile, unsigned value); +void +put_bits (bitfile_t *bitfile, unsigned value, unsigned bits); +bool_t +get_bit (bitfile_t *bitfile); +unsigned +get_bits (bitfile_t *bitfile, unsigned bits); +void +close_bitfile (bitfile_t *bitfile); +unsigned +bits_processed (const bitfile_t *bitfile); + +#endif /* not _BIT_IO_H */ + 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; +} + + + diff --git a/converter/other/fiasco/lib/dither.h b/converter/other/fiasco/lib/dither.h new file mode 100644 index 00000000..71f9d3c3 --- /dev/null +++ b/converter/other/fiasco/lib/dither.h @@ -0,0 +1,27 @@ +/* + * dither.h + * + * Written 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> + */ + +/* + * $Date: 2000/06/14 20:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _DITHER_H +#define _DITHER_H + +typedef struct renderer_private +{ + int *Cr_r_tab, *Cr_g_tab, *Cb_g_tab, *Cb_b_tab; + unsigned int *r_table, *g_table, *b_table, *y_table; + bool_t double_resolution; +} renderer_private_t; + +#endif /* _DITHER_H */ diff --git a/converter/other/fiasco/lib/error.c b/converter/other/fiasco/lib/error.c new file mode 100644 index 00000000..b858badf --- /dev/null +++ b/converter/other/fiasco/lib/error.c @@ -0,0 +1,326 @@ +/* + * error.c: Error handling + * + * Written by: Stefan Frank + * Ullrich Hafner + * + * Credits: Modelled after variable argument routines from Jef + * Poskanzer's pbmplus package. + * + * 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> + + "int dummy = " change to int dummy; dummy =" for Netpbm to avoid + unused variable warning. + + */ + +/* + * $Date: 2000/06/14 20:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#define _ERROR_C + +#include "config.h" + +#include <stdio.h> +#include <errno.h> + +#if STDC_HEADERS +# include <stdarg.h> +# define VA_START(args, lastarg) va_start(args, lastarg) +#else /* not STDC_HEADERS */ +# include <varargs.h> +# define VA_START(args, lastarg) va_start(args) +#endif /* not STDC_HEADERS */ +#if HAVE_STRING_H +# include <string.h> +#else /* not HAVE_STRING_H */ +# include <strings.h> +#endif /* not HAVE_STRING_H */ + +#if HAVE_SETJMP_H +# include <setjmp.h> +#endif /* HAVE_SETJMP_H */ + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "misc.h" +#include "fiasco.h" + +/***************************************************************************** + + local variables + +*****************************************************************************/ + +static fiasco_verbosity_e verboselevel = FIASCO_SOME_VERBOSITY; +static char *error_message = NULL; + +#if HAVE_SETJMP_H +jmp_buf env; +#endif /* HAVE_SETJMP_H */ + +/***************************************************************************** + + public code + +*****************************************************************************/ + +void +set_error (const char *format, ...) +/* + * Set error text to given string. + */ +{ + va_list args; + unsigned len = 0; + const char *str = format; + + VA_START (args, format); + + len = strlen (format); + while ((str = strchr (str, '%'))) + { + str++; + if (*str == 's') + { + char *vstring = va_arg (args, char *); + len += strlen (vstring); + } + else if (*str == 'd') + { + int dummy; + dummy = va_arg (args, int); + len += 10; + } + else if (*str == 'c') + { + int dummy; + dummy = va_arg (args, int); + len += 1; + } + else + return; + str++; + } + va_end(args); + + VA_START (args, format); + + if (error_message) + Free (error_message); + error_message = Calloc (len, sizeof (char)); + +#if HAVE_VPRINTF + vsprintf (error_message, format, args); +#elif HAVE_DOPRNT + _doprnt (format, args, stderr); +#endif /* HAVE_DOPRNT */ + + va_end (args); +} + +void +error (const char *format, ...) +/* + * Set error text to given string. + */ +{ + va_list args; + unsigned len = 0; + const char *str = format; + + VA_START (args, format); + + len = strlen (format); + while ((str = strchr (str, '%'))) + { + str++; + if (*str == 's') + { + char *vstring = va_arg (args, char *); + len += strlen (vstring); + } + else if (*str == 'd') + { + int dummy; + dummy = va_arg (args, int); + len += 10; + } + else if (*str == 'c') + { + int dummy; + dummy = va_arg (args, int); + len += 1; + } + else + { +#if HAVE_SETJMP_H + longjmp (env, 1); +#else /* not HAVE_SETJMP_H */ + exit (1); +#endif /* HAVE_SETJMP_H */ + }; + + str++; + } + va_end(args); + + VA_START (args, format); + + if (error_message) + Free (error_message); + error_message = Calloc (len, sizeof (char)); + +#if HAVE_VPRINTF + vsprintf (error_message, format, args); +#elif HAVE_DOPRNT + _doprnt (format, args, stderr); +#endif /* HAVE_DOPRNT */ + + va_end (args); + +#if HAVE_SETJMP_H + longjmp (env, 1); +#else /* not HAVE_SETJMP_H */ + exit (1); +#endif /* HAVE_SETJMP_H */ +} + +const char * +fiasco_get_error_message (void) +/* + * Return value: + * Last error message of FIASCO library. + */ +{ + return error_message ? error_message : ""; +} + +const char * +get_system_error (void) +{ + return strerror (errno); +} + +void +file_error (const char *filename) +/* + * Print file error message and exit. + * + * No return value. + */ +{ + error ("File `%s': I/O Error - %s.", filename, get_system_error ()); +} + +void +warning (const char *format, ...) +/* + * Issue a warning and continue execution. + * + * No return value. + */ +{ + va_list args; + + VA_START (args, format); + + if (verboselevel == FIASCO_NO_VERBOSITY) + return; + + fprintf (stderr, "Warning: "); +#if HAVE_VPRINTF + vfprintf (stderr, format, args); +#elif HAVE_DOPRNT + _doprnt (format, args, stderr); +#endif /* HAVE_DOPRNT */ + fputc ('\n', stderr); + + va_end (args); +} + +void +message (const char *format, ...) +/* + * Print a message to stderr. + */ +{ + va_list args; + + VA_START (args, format); + + if (verboselevel == FIASCO_NO_VERBOSITY) + return; + +#if HAVE_VPRINTF + vfprintf (stderr, format, args); +#elif HAVE_DOPRNT + _doprnt (format, args, stderr); +#endif /* HAVE_DOPRNT */ + fputc ('\n', stderr); + va_end (args); +} + +void +debug_message (const char *format, ...) +/* + * Print a message to stderr. + */ +{ + va_list args; + + VA_START (args, format); + + if (verboselevel < FIASCO_ULTIMATE_VERBOSITY) + return; + + fprintf (stderr, "*** "); +#if HAVE_VPRINTF + vfprintf (stderr, format, args); +#elif HAVE_DOPRNT + _doprnt (format, args, stderr); +#endif /* HAVE_DOPRNT */ + fputc ('\n', stderr); + va_end (args); +} + +void +info (const char *format, ...) +/* + * Print a message to stderr. Do not append a newline. + */ +{ + va_list args; + + VA_START (args, format); + + if (verboselevel == FIASCO_NO_VERBOSITY) + return; + +#if HAVE_VPRINTF + vfprintf (stderr, format, args); +#elif HAVE_DOPRNT + _doprnt (format, args, stderr); +#endif /* HAVE_DOPRNT */ + fflush (stderr); + va_end (args); +} + +void +fiasco_set_verbosity (fiasco_verbosity_e level) +{ + verboselevel = level; +} + +fiasco_verbosity_e +fiasco_get_verbosity (void) +{ + return verboselevel; +} diff --git a/converter/other/fiasco/lib/error.h b/converter/other/fiasco/lib/error.h new file mode 100644 index 00000000..288b25f4 --- /dev/null +++ b/converter/other/fiasco/lib/error.h @@ -0,0 +1,39 @@ +/* + * error.h + * + * Written by: Stefan Frank + * 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> + */ + +#ifndef ERROR_H_INCLUDED +#define ERROR_H_INCLUDED + +void +set_error (const char *format, ...); +void +error (const char *format, ...); +void +file_error (const char *filename); +void +message (const char *format, ...); +void +debug_message (const char *format, ...); +void +warning (const char *format, ...); +void +info (const char *format, ...); +const char * +get_system_error (void); + +#include <setjmp.h> +extern jmp_buf env; + +#define try if (setjmp (env) == 0) +#define catch else + +#include <assert.h> + +#endif diff --git a/converter/other/fiasco/lib/image.c b/converter/other/fiasco/lib/image.c new file mode 100644 index 00000000..019ba03c --- /dev/null +++ b/converter/other/fiasco/lib/image.c @@ -0,0 +1,512 @@ +/* + * image.c: Input and output of PNM images. + * + * Written 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> + */ + +/* + * $Date: 2000/06/15 17:21:30 $ + * $Author: hafner $ + * $Revision: 5.2 $ + * $State: Exp $ + */ + +#include "pnm.h" + +#include <string.h> + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "fiasco.h" +#include "misc.h" +#include "image.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +init_chroma_tables (void); + +/***************************************************************************** + + local variables + +*****************************************************************************/ +static int *Cr_r_tab = NULL; +static int *Cr_g_tab = NULL; +static int *Cb_g_tab = NULL; +static int *Cb_b_tab = NULL; + +/***************************************************************************** + + public code + +*****************************************************************************/ + +fiasco_image_t * +fiasco_image_new (const char *filename) +/* + * FIASCO image constructor. + * Allocate memory for the FIASCO image structure and + * load the specified image `filename'. The image has to be in + * raw pgm or ppm format. + * + * Return value: + * pointer to the new image structure + * or NULL in case of an error + */ +{ + try + { + fiasco_image_t *image = Calloc (1, sizeof (fiasco_image_t)); + + image->private = read_image (filename); + image->delete = fiasco_image_delete; + image->get_width = fiasco_image_get_width; + image->get_height = fiasco_image_get_height; + image->is_color = fiasco_image_is_color; + + return image; + } + catch + { + return NULL; + } +} + +void +fiasco_image_delete (fiasco_image_t *image) +/* + * FIASCO image destructor. + * Free memory of FIASCO image struct. + * + * No return value. + * + * Side effects: + * structure 'image' is discarded. + */ +{ + image_t *this = cast_image (image); + + if (!this) + return; + + try + { + free_image (this); + } + catch + { + return; + } +} + +unsigned +fiasco_image_get_width (fiasco_image_t *image) +{ + image_t *this = cast_image (image); + + if (!this) + return 0; + else + return this->width; +} + +unsigned +fiasco_image_get_height (fiasco_image_t *image) +{ + image_t *this = cast_image (image); + + if (!this) + return 0; + else + return this->width; +} + +int +fiasco_image_is_color (fiasco_image_t *image) +{ + image_t *this = cast_image (image); + + if (!this) + return 0; + else + return this->color; +} + +image_t * +cast_image (fiasco_image_t *image) +/* + * Cast pointer `image' to type image_t. + * Check whether `image' is a valid object of type image_t. + * + * Return value: + * pointer to dfiasco_t struct on success + * NULL otherwise + */ +{ + image_t *this = (image_t *) image->private; + if (this) + { + if (!streq (this->id, "IFIASCO")) + { + set_error (_("Parameter `image' doesn't match required type.")); + return NULL; + } + } + else + { + set_error (_("Parameter `%s' not defined (NULL)."), "image"); + } + + return this; +} + +image_t * +alloc_image (unsigned width, unsigned height, bool_t color, format_e format) +/* + * Image constructor: + * Allocate memory for the image_t structure. + * Image size is given by 'width' and 'height'. + * If 'color' == YES then allocate memory for three color bands (Y, Cb, Cr). + * otherwise just allocate memory for a grayscale image. + * 'format' specifies whether image pixels of color images + * are stored in 4:4:4 or 4:2:0 format. + * + * Return value: + * pointer to the new image structure. + */ +{ + image_t *image; + color_e band; + + if ((width & 1) || (height & 1)) + error ("Width and height of images must be even numbers."); + if (!color) + format = FORMAT_4_4_4; + + image = Calloc (1, sizeof (image_t)); + image->width = width; + image->height = height; + image->color = color; + image->format = format; + image->reference_count = 1; + + strcpy (image->id, "IFIASCO"); + + for (band = first_band (color); band <= last_band (color); band++) + if (format == FORMAT_4_2_0 && band != Y) + image->pixels [band] = Calloc ((width * height) >> 2, + sizeof (word_t)); + else + image->pixels [band] = Calloc (width * height, sizeof (word_t)); + + return image; +} + +image_t * +clone_image (image_t *image) +/* + * Copy constructor: + * Construct new image by copying the given `image'. + * + * Return value: + * pointer to the new image structure. + */ +{ + image_t *new = alloc_image (image->width, image->height, image->color, + image->format); + color_e band; + + for (band = first_band (new->color); band <= last_band (new->color); band++) + if (new->format == FORMAT_4_2_0 && band != Y) + { + memcpy (new->pixels [band], image->pixels [band], + ((new->width * new->height) >> 2) * sizeof (word_t)); + } + else + { + memcpy (new->pixels [band], image->pixels [band], + new->width * new->height * sizeof (word_t)); + } + + return new; +} + +void +free_image (image_t *image) +/* + * Image destructor: + * Free memory of 'image' struct and pixel data. + * + * No return value. + * + * Side effects: + * structure 'image' is discarded. + */ +{ + if (image != NULL) + { + if (--image->reference_count) + return; /* image is still referenced */ + else + { + color_e band; + + for (band = first_band (image->color); + band <= last_band (image->color); band++) + if (image->pixels [band]) + Free (image->pixels [band]); + Free (image); + } + } + else + warning ("Can't free image <NULL>."); +} + + +static void +read_image_data(image_t * const image, FILE *input, const bool_t color, + const int width, const int height, const xelval maxval, + const int format) { + int row; + int i; /* Cursor into image->pixels arrays */ + xel * xelrow; + /* The following are just the normal rgb -> YCbCr conversion matrix, + except normalization to maxval 4095 (12 bit color) is built in + */ + const double coeff_lu_r = +0.2989 / maxval * 4095; + const double coeff_lu_g = +0.5866 / maxval * 4095; + const double coeff_lu_b = +0.1145 / maxval * 4095; + const double coeff_cb_r = -0.1687 / maxval * 4095; + const double coeff_cb_g = -0.3312 / maxval * 4095; + const double coeff_cb_b = +0.5000 / maxval * 4095; + const double coeff_cr_r = +0.5000 / maxval * 4095; + const double coeff_cr_g = -0.4183 / maxval * 4095; + const double coeff_cr_b = -0.0816 / maxval * 4095; + + xelrow = pnm_allocrow(width); + + i = 0; + for (row = 0; row < height; row++) { + int col; + pnm_readpnmrow(input, xelrow, width, maxval, format); + for (col = 0; col < width; col++) { + if (color) { + image->pixels[Y][i] = + coeff_lu_r * PPM_GETR(xelrow[col]) + + coeff_lu_g * PPM_GETG(xelrow[col]) + + coeff_lu_b * PPM_GETB(xelrow[col]) - 2048; + image->pixels[Cb][i] = + coeff_cb_r * PPM_GETR(xelrow[col]) + + coeff_cb_g * PPM_GETG(xelrow[col]) + + coeff_cb_b * PPM_GETB(xelrow[col]); + image->pixels[Cr][i] = + coeff_cr_r * PPM_GETR(xelrow[col]) + + coeff_cr_g * PPM_GETG(xelrow[col]) + + coeff_cr_b * PPM_GETB(xelrow[col]); + + i++; + } else + image->pixels[GRAY][i++] = + PNM_GET1(xelrow[col]) * 4095 / maxval - 2048; + } + } + + free(xelrow); +} + + + +image_t * +read_image (const char *image_name) +/* + * Read image 'image_name'. + * + * Return value: + * pointer to the image structure. + */ +{ + FILE *input; /* input stream */ + image_t *image; /* pointer to new image structure */ + int width, height; /* image size */ + xelval maxval; /* Maxval of image */ + int format; /* Image's format code */ + bool_t color; /* color image ? (YES/NO) */ + + if (image_name == NULL) + input = stdin; + else + input = pm_openr((char*)image_name); + + pnm_readpnminit(input, &width, &height, &maxval, &format); + + if (PNM_FORMAT_TYPE(format) == PPM_FORMAT) + color = YES; + else + color = NO; + + if (width < 32) + pm_error("Image must have a width of at least 32 pixels."); + + if (height < 32) + pm_error("Image must have a height of at least 32 pixels."); + + image = alloc_image (width, height, color, FORMAT_4_4_4); + + read_image_data(image, input, color, width, height, maxval, format); + + pm_close(input); + + return image; +} + +void +write_image (const char *image_name, const image_t *image) +/* + * Write given 'image' data to the file 'image_name'. + * + * No return value. + */ +{ + FILE *output; /* output stream */ + int format; + int row; + int i; /* Cursor into image->pixel arrays */ + xel * xelrow; + unsigned *gray_clip; /* clipping table */ + + assert (image && image_name); + + if (image->format == FORMAT_4_2_0) + { + warning ("Writing of images in 4:2:0 format not supported."); + return; + } + + if (image_name == NULL) + output = stdout; + else if (strcmp(image_name, "-") == 0) + output = stdout; + else + output = pm_openw((char*)image_name); + + gray_clip = init_clipping (); /* mapping of int -> unsigned */ + if (!gray_clip) + error (fiasco_get_error_message ()); + init_chroma_tables (); + + format = image->color ? PPM_TYPE : PGM_TYPE; + + pnm_writepnminit(output, image->width, image->height, 255, format, 0); + + xelrow = pnm_allocrow(image->width); + i = 0; + for (row = 0; row < image->height; row++) { + int col; + for (col = 0; col < image->width; col++) { + if (image->color) { + word_t yval, cbval, crval; + + yval = image->pixels[Y][i] / 16 + 128; + cbval = image->pixels[Cb][i] / 16; + crval = image->pixels[Cr][i] / 16; + + PPM_ASSIGN(xelrow[col], + gray_clip[yval + Cr_r_tab[crval]], + gray_clip[yval + Cr_g_tab[crval] + Cb_g_tab [cbval]], + gray_clip[yval + Cb_b_tab[cbval]]); + + } else + /* The 16 below should be 4095/255 = 16.0588 */ + PNM_ASSIGN1(xelrow[col], + gray_clip[image->pixels[GRAY][i]/16+128]); + i++; + } + pnm_writepnmrow(output, xelrow, + image->width, 255, format, 0); + } + pnm_freerow(xelrow); + + pm_close(output); +} + +bool_t +same_image_type (const image_t *img1, const image_t *img2) +/* + * Check whether the given images 'img1' and `img2' are of the same type. + * + * Return value: + * YES if images 'img1' and `img2' are of the same type + * NO otherwise. + */ +{ + assert (img1 && img2); + + return ((img1->width == img2->width) + && (img1->height == img2->height) + && (img1->color == img2->color) + && (img1->format == img2->format)); +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static void +init_chroma_tables (void) +/* + * Chroma tables are used to perform fast YCbCr->RGB color space conversion. + */ +{ + int crval, cbval, i; + + if (Cr_r_tab != NULL || Cr_g_tab != NULL || + Cb_g_tab != NULL || Cb_b_tab != NULL) + return; + + Cr_r_tab = Calloc (768, sizeof (int)); + Cr_g_tab = Calloc (768, sizeof (int)); + Cb_g_tab = Calloc (768, sizeof (int)); + Cb_b_tab = Calloc (768, sizeof (int)); + + for (i = 256; i < 512; i++) + { + cbval = crval = i - 128 - 256; + + Cr_r_tab[i] = 1.4022 * crval + 0.5; + Cr_g_tab[i] = -0.7145 * crval + 0.5; + Cb_g_tab[i] = -0.3456 * cbval + 0.5; + Cb_b_tab[i] = 1.7710 * cbval + 0.5; + } + for (i = 0; i < 256; i++) + { + Cr_r_tab[i] = Cr_r_tab[256]; + Cr_g_tab[i] = Cr_g_tab[256]; + Cb_g_tab[i] = Cb_g_tab[256]; + Cb_b_tab[i] = Cb_b_tab[256]; + } + for (i = 512; i < 768; i++) + { + Cr_r_tab[i] = Cr_r_tab[511]; + Cr_g_tab[i] = Cr_g_tab[511]; + Cb_g_tab[i] = Cb_g_tab[511]; + Cb_b_tab[i] = Cb_b_tab[511]; + } + + Cr_r_tab += 256 + 128; + Cr_g_tab += 256 + 128; + Cb_g_tab += 256 + 128; + Cb_b_tab += 256 + 128; +} + diff --git a/converter/other/fiasco/lib/image.h b/converter/other/fiasco/lib/image.h new file mode 100644 index 00000000..958049f6 --- /dev/null +++ b/converter/other/fiasco/lib/image.h @@ -0,0 +1,59 @@ +/* + * image.h + * + * Written 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> + */ + +/* + * $Date: 2000/10/22 10:43:56 $ + * $Author: hafner $ + * $Revision: 5.3 $ + * $State: Exp $ + */ + +#ifndef _IMAGE_H +#define _IMAGE_H + +#include <stdio.h> +#include "types.h" +#include "fiasco.h" + +typedef enum {FORMAT_4_4_4, FORMAT_4_2_0} format_e; + +typedef struct image +/* + * Image data + */ +{ + char id [7]; + unsigned reference_count; + unsigned width; /* Width of the image */ + unsigned height; /* Height of the image */ + bool_t color; /* Color or grayscale image */ + format_e format; /* Pixel format 4:4:4 or 4:2:0 */ + word_t *pixels [3]; /* Pixels in short format */ +} image_t; + +image_t * +cast_image (fiasco_image_t *image); +image_t * +alloc_image (unsigned width, unsigned height, bool_t color, format_e format); +image_t * +clone_image (image_t *image); +void +free_image (image_t *image); +FILE * +read_pnmheader (const char *image_name, unsigned *width, unsigned *height, + bool_t *color); +image_t * +read_image (const char *image_name); +void +write_image (const char *image_name, const image_t *image); +bool_t +same_image_type (const image_t *img1, const image_t *img2); + +#endif /* not _IMAGE_H */ + diff --git a/converter/other/fiasco/lib/list.c b/converter/other/fiasco/lib/list.c new file mode 100644 index 00000000..9f516c2e --- /dev/null +++ b/converter/other/fiasco/lib/list.c @@ -0,0 +1,258 @@ +/* + * list.c: List operations + * + * Written 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> + */ + +/* + * $Date: 2000/06/14 20:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $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 */ + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "misc.h" +#include "list.h" + +/***************************************************************************** + + public code + +*****************************************************************************/ + +list_t * +alloc_list (size_t size_of_element) +/* + * List constructor: + * Allocate a new list. + * Size of list element values is given by 'size_of_element'. + * + * Return value: + * pointer to an empty list + */ +{ + list_t *new_list = Calloc (1, sizeof (list_t)); + + assert (size_of_element > 0); + + new_list->head = NULL; + new_list->tail = NULL; + new_list->size_of_element = size_of_element; + + return new_list; +} + +void +free_list (list_t *list) +/* + * List destructor: + * Discard list and its elements. + * + * No return value. + * + * Side effects: + * struct 'list' is discarded + */ +{ + assert (list); + + while (list_remove (list, HEAD, NULL)) + ; + Free (list); +} + +void +list_insert (list_t *list, pos_e pos, const void *data) +/* + * Insert a new 'list' element at head ('pos' = HEAD) or + * tail ('pos' = TAIL) of 'list'. + * 'data' is a pointer to a memory segment of size + * 'list'->size_of_element containing the value to store. + * The value is directly copied - no references are stored. + * + * No return value. + * + * Side effects: + * lists current tail or head is replaced by the new element + */ +{ + node_t *element; + + assert (list && data); + + element = Calloc (1, sizeof (node_t)); + element->value = Calloc (1, list->size_of_element); + memcpy (element->value, data, list->size_of_element); + + if (pos == TAIL) + { + element->next = NULL; + element->prev = list->tail; + if (list->tail) + list->tail->next = element; + list->tail = element; + if (!list->head) + list->head = element; + } + else /* pos == HEAD */ + { + element->prev = NULL; + element->next = list->head; + if (list->head) + list->head->prev = element; + list->head = element; + if (!list->tail) + list->tail = element; + } +} + +bool_t +list_remove (list_t *list, pos_e pos, void *data) +/* + * Remove 'list' element from head or tail of 'list'. + * + * Return value: + * TRUE on success, + * FALSE if list is empty or + * if list value data is NULL + * + * Side effects: + * lists current head or tail is removed + * value of the removed list element (if not NULL) is copied to + * 'data' (if 'data' is not NULL) + */ +{ + node_t *element; + void *valueptr; + + assert (list); + + if (pos == TAIL) + { + element = list->tail; + if (element) + { + list->tail = element->prev; + valueptr = element->value; + Free (element); + } + else + valueptr = NULL; + if (!list->tail) /* 'element' was last node */ + list->head = NULL; + } + else /* pos == HEAD */ + { + element = list->head; + if (element) + { + list->head = element->next; + valueptr = element->value; + Free (element); + } + else + valueptr = NULL; + if (!list->head) /* 'element' was last node */ + list->tail = NULL; + } + + if (valueptr) /* copy value of node */ + { + if (data) + memcpy (data, valueptr, list->size_of_element); + Free (valueptr); + } + + return valueptr ? TRUE : FALSE; +} + +bool_t +list_element_n (const list_t *list, pos_e pos, unsigned n, void *data) +/* + * Get value of 'list' element number 'n'. + * (First element is list head if 'pos' == HEAD + * or list tail if 'pos' == TAIL. + * Accordingly, traverse the list in ascending or descending order). + * + * Return value: + * TRUE on success, FALSE if there is no element 'n' + * + * Side effects: + * value of list element 'n' is copied to 'data' + */ +{ + node_t *element; + + assert (list && data); + + if (pos == HEAD) + for (element = list->head; element != NULL && n; + element = element->next, n--) + ; + else + for (element = list->tail; element != NULL && n; + element = element->prev, n--) + ; + + if (element) + { + memcpy (data, element->value, list->size_of_element); + return TRUE; + } + else + return FALSE; +} + +unsigned +list_sizeof (const list_t *list) +/* + * Count number of 'list' elements. + * + * Return value: + * number of 'list' elements. + */ +{ + node_t *element; + unsigned n = 0; + + assert (list); + + for (element = list->head; element != NULL; element = element->next) + n++; + + return n; +} + +void +list_foreach (const list_t *list, void (*function)(void *, void *), void *data) +/* + * Call 'function' for each element of the 'list'. + * Parameters given to 'function' are a pointer to the value of the + * current 'list' element and the user pointer 'data'. + * + * No return value. + */ +{ + node_t *element; + + assert (list && function && data); + + for (element = list->head; element; element = element->next) + function (element->value, data); +} + diff --git a/converter/other/fiasco/lib/list.h b/converter/other/fiasco/lib/list.h new file mode 100644 index 00000000..db7c08b2 --- /dev/null +++ b/converter/other/fiasco/lib/list.h @@ -0,0 +1,72 @@ +/* + * list.h + * + * Written 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> + */ + +/* + * $Date: 2000/06/14 20:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _LIST_H +#define _LIST_H + +#include <stdio.h> +#include <stddef.h> + +typedef struct node +{ + struct node *prev; /* pointer to prev list element */ + struct node *next; /* pointer to next list element */ + void *value; /* pointer to value of node */ +} node_t; + +typedef struct list +{ + node_t *head; + node_t *tail; + size_t size_of_element; /* number of bytes to store value */ +} list_t; + +typedef enum {TAIL, HEAD} pos_e; + +/* + * Alias definitions for queue and stack + */ + +typedef list_t lqueue_t ; +#define alloc_queue alloc_list +#define free_queue free_list +#define queue_append(q, d) (list_insert ((q), TAIL, (d))) +#define queue_remove(q, d) (list_remove ((q), HEAD, (d))) + +typedef list_t lstack_t ; +#define alloc_stack alloc_list +#define free_stack free_list +#define stack_push(q, d) (list_insert ((q), TAIL, (d))) +#define stack_pop(q, d) (list_remove ((q), TAIL, (d))) + +list_t * +alloc_list (size_t size_of_element); +void +free_list (list_t *list); +bool_t +list_element_n (const list_t *list, pos_e pos, unsigned n, void *data); +void +list_foreach (const list_t *list, void (*function)(void *, void *), + void *data); +void +list_insert (list_t *list, pos_e pos, const void *data); +bool_t +list_remove (list_t *list, pos_e pos, void *data); +unsigned +list_sizeof (const list_t *list); + +#endif /* not _LIST_H */ + diff --git a/converter/other/fiasco/lib/macros.h b/converter/other/fiasco/lib/macros.h new file mode 100644 index 00000000..877abeea --- /dev/null +++ b/converter/other/fiasco/lib/macros.h @@ -0,0 +1,70 @@ +/* + * macros.h + * + * Written 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> + */ + +/* + * $Date: 2000/06/14 20:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _MACROS_H +#define _MACROS_H + +#include <string.h> +/******************************************************************************* + + System configuration section + +*******************************************************************************/ + +#ifndef SEEK_CUR +# define SEEK_CUR 1 +#endif /* not SEEK_CUR */ + +#ifdef WIN32 +#undef max +#undef min +#endif /* not WIN32 */ + +/***************************************************************************** + + Various macros + +*****************************************************************************/ + +#define streq(str1, str2) (strcmp ((str1), (str2)) == 0) +#define strneq(str1, str2) (strcmp ((str1), (str2)) != 0) +#define square(x) ((x) * (x)) +#define first_band(color) ((unsigned) ((color) ? Y : GRAY)) +#define last_band(color) ((unsigned) ((color) ? Cr : GRAY)) +#define width_of_level(l) ((unsigned) (1 << ((l) >> 1))) +#define height_of_level(l) ((unsigned) (1 << (((l) + 1) >> 1))) +#define size_of_level(l) ((unsigned) (1 << (l))) +#define address_of_level(l) ((unsigned) (size_of_level (l) - 1)) +#define size_of_tree(l) ((unsigned) (address_of_level ((l) + 1))) +#define is_odd(n) (abs (n) % 2) +#ifndef max +#define max(a,b) ((a) < (b) ? (b) : (a)) +#endif +#ifndef min +#define min(a,b) ((a) > (b) ? (b) : (a)) +#endif +#define _(x) (x) + + +#define MAXSTRLEN 1024 +#define MAXSTRLEN_SCANF "%1024s" + +typedef enum color {GRAY = 0, Y = 0, Cb = 1, Cr = 2} color_e; + +#endif /* _MACROS_H */ + + + diff --git a/converter/other/fiasco/lib/misc.c b/converter/other/fiasco/lib/misc.c new file mode 100644 index 00000000..02a1314f --- /dev/null +++ b/converter/other/fiasco/lib/misc.c @@ -0,0 +1,563 @@ +/* + * misc.c: Some usefull functions, that don't fit in one of + * the other files and that are needed by at least + * two modules. + * + * Written by: Stefan Frank + * 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> + */ + +/* + * $Date: 2000/06/14 20:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include <math.h> +#include <ctype.h> + +#ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else /* not TIME_WITH_SYS_TIME */ +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else /* not HAVE_SYS_TIME_H */ +# include <time.h> +# endif /* not HAVE_SYS_TIME_H */ +#endif /* not TIME_WITH_SYS_TIME */ + +#if STDC_HEADERS +# include <stdlib.h> +#endif /* not STDC_HEADERS */ + +#if HAVE_STRING_H +# include <string.h> +#else /* not HAVE_STRING_H */ +# include <strings.h> +#endif /* not HAVE_STRING_H */ + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "bit-io.h" +#include "misc.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +remove_comments (FILE *file); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +void * +Calloc (size_t n, size_t size) +/* + * Allocate memory like calloc (). + * + * Return value: Pointer to the new block of memory on success, + * otherwise the program is terminated. + */ +{ + void *ptr; /* pointer to the new memory block */ + + if (n <= 0 || size <= 0) + error ("Can't allocate memory for %d items of size %d", + (int) n, (int) size); + + ptr = calloc (n, size); + if (!ptr) + error ("Out of memory!"); + + return ptr; +} + +void +Free (void *memory) +/* + * Free memory given by the pointer 'memory' + * + * No return value. + */ +{ + if (memory != NULL) + free (memory); + else + warning ("Can't free memory block <NULL>."); +} + +unsigned +prg_timer (clock_t *last_timer, enum action_e action) +/* + * If 'action' == START then store current value of system timer. + * If 'action' == STOP then compute number of elapsed micro seconds since + * the last time 'prg_timer' was called + * with 'action' == START. + * + * Return value: + * Number of elapsed micro seconds if 'action' == STOP + * 0 if 'action' == START + * + * Side effects: + * last_timer is set to current timer if action == START + */ +{ + assert (last_timer); + + if (action == START) + { + *last_timer = clock (); + return 0; + } + else + return (clock () - *last_timer) / (CLOCKS_PER_SEC / 1000.0); +} + +real_t +read_real (FILE *infile) +/* + * Read one real value from the given input stream 'infile'. + * + * Return value: + * real value on success + */ +{ + float input; + + assert (infile); + + remove_comments (infile); + if (fscanf(infile, "%f", &input) != 1) + error("Can't read float value!"); + + return (real_t) input; +} + +int +read_int (FILE *infile) +/* + * Read one integer value from the given input stream 'infile'. + * + * Return value: + * integer value on success + */ +{ + int input; /* integer */ + + assert (infile); + + remove_comments (infile); + if (fscanf(infile, "%d", &input) != 1) + error("Can't read integer value!"); + + return input; +} + +static void +remove_comments (FILE *file) +/* + * Remove shell/pgm style comments (#) from the input 'file' + * + * No return value. + */ +{ + int c; /* current character */ + + assert (file); + + do + { + while (isspace(c = getc (file))) + ; + if (c == EOF) + error ("EOF reached, input seems to be truncated!"); + if (c == '#') + { + int dummy; + + while (((dummy = getc (file)) != '\n') && dummy != EOF) + ; + if (dummy == EOF) + error ("EOF reached, input seems to be truncated!"); + } + else + ungetc (c, file); + } while (c == '#'); +} + +void +write_rice_code (unsigned value, unsigned rice_k, bitfile_t *output) +/* + * Write 'value' to the stream 'output' using Rice coding with base 'rice_k'. + * + * No return value. + */ +{ + unsigned unary; /* unary part of Rice Code */ + + assert (output); + + for (unary = value >> rice_k; unary; unary--) + put_bit (output, 1); + put_bit (output, 0); + put_bits (output, value & ((1 << rice_k) - 1), rice_k); +} + +unsigned +read_rice_code (unsigned rice_k, bitfile_t *input) +/* + * Read a Rice encoded integer (base 'rice_k') from the stream 'input'. + * + * Return value: + * decoded integer + */ +{ + unsigned unary; /* unary part of Rice code */ + + assert (input); + + for (unary = 0; get_bit (input); unary++) /* unary part */ + ; + + return (unary << rice_k) | get_bits (input, rice_k); +} + +void +write_bin_code (unsigned value, unsigned maxval, bitfile_t *output) +/* + * Write 'value' to the stream 'output' using an adjusted binary code + * based on given 'maxval'. + * + * No return value. + */ +{ + unsigned k; + unsigned r; + + assert (output && maxval && value <= maxval); + + k = log2 (maxval + 1); + r = (maxval + 1) % (1 << k); + + if (value < maxval + 1 - 2 * r) /* 0, ... , maxval - 2r */ + put_bits (output, value, k); + else /* maxval - 2r + 1, ..., maxval */ + put_bits (output, value + maxval + 1 - 2 * r, k + 1); +} + +unsigned +read_bin_code (unsigned maxval, bitfile_t *input) +/* + * Read a bincode encoded integer from the stream 'input'. + * + * Return value: + * decoded integer + */ +{ + unsigned k; + unsigned r; + unsigned value; + + assert (input); + + k = log2 (maxval + 1); + r = (maxval + 1) % (1 << k); + + value = get_bits (input, k); + if (value < maxval + 1 - 2 * r) + return value; + else + { + value <<= 1; + if (get_bit (input)) + value++; + return value - maxval - 1 + 2 * r; + } +} + +unsigned +bits_rice_code (unsigned value, unsigned rice_k) +/* + * Compute number of bits needed for coding integer 'value' + * with given Rice code 'rice_k'. + * + * Return value: + * number of bits + */ +{ + unsigned unary; + unsigned bits = 0; + + for (unary = value >> rice_k; unary; unary--) + bits++; + bits += rice_k + 1; + + return bits; +} + +unsigned +bits_bin_code (unsigned value, unsigned maxval) +/* + * Compute number of bits needed for coding integer 'value' + * with adjusted binary code of given maximum value 'maxval'. + * + * Return value: + * number of bits + */ +{ + unsigned k; + unsigned r; + + assert (maxval && value <= maxval); + + k = log2 (maxval + 1); + r = (maxval + 1) % (1 << k); + + return value < maxval + 1 - 2 * r ? k : k + 1; +} + +unsigned * +init_clipping (void) +/* + * Initialize the clipping tables + * + * Return value: + * pointer to clipping table + */ +{ + static unsigned *gray_clip = NULL; /* clipping array */ + + if (gray_clip == NULL) /* initialize clipping table */ + { + int i; /* counter */ + + gray_clip = calloc (256 * 3, sizeof (unsigned)); + if (!gray_clip) + { + set_error (_("Out of memory.")); + return NULL; + } + gray_clip += 256; + + for (i = -256; i < 512; i++) + if (i < 0) + gray_clip [i] = 0; + else if (i > 255) + gray_clip [i] = 255; + else + gray_clip [i] = i; + } + + return gray_clip; +} + +#ifndef HAVE_MEMMOVE +void * +memmove (void *v_dst, const void *v_src, size_t n) +/* + * Copy 'n' bytes from memory area 'src' to memory area 'dest'. + * The memory areas may overlap. + * + * Return value: + * pointer 'dest' + */ +{ + byte_t *to, *dst = (byte_t *) v_dst; + const byte_t *from, *src = (byte_t *) v_src; + + assert (v_dst && v_src); + + if (dst <= src) + { + from = src; + to = dst; + for (; n; n--) + *to++ = *from++; + } + else + { + from = src + (n - 1); + to = dst + (n - 1); + for (; n; n--) + *to-- = *from--; + } + + return v_dst; +} +#endif /* not HAVE_MEMMOVE */ + +#ifndef HAVE_STRDUP +char * +strdup (const char *s) +/* + * Duplicate given string 's'. + * + * Return value: + * pointer to new string value + */ +{ + assert (s); + + return strcpy (Calloc (strlen (s) + 1, sizeof (char)), s); +} +#endif /* not HAVE_STRDUP */ + +/* Note that some systems have a "log2()" in the math library and some + have a "log2" macro. So we name ours Log2. But to avoid lots of + differences from the original fiasco source code, we define a + macro log2 in config.h to expand to Log2. + */ +double +Log2 (double x) +/* + * Return value: + * base-2 logarithm of 'x' + */ +{ + return log (x) / 0.69314718; +} + +#ifndef HAVE_STRCASECMP +bool_t +strcaseeq (const char *s1, const char *s2) +/* + * Compare strings 's1' and 's2', ignoring the case of the characters. + * + * Return value: + * TRUE if strings match, else FALSE + */ +{ + bool_t matched; + char *ls1, *ls2, *ptr; + + assert (s1 && s2); + + ls1 = strdup (s1); + ls2 = strdup (s2); + + for (ptr = ls1; *ptr; ptr++) + *ptr = tolower (*ptr); + for (ptr = ls2; *ptr; ptr++) + *ptr = tolower (*ptr); + + matched = streq (ls1, ls2) ? YES : NO; + + Free (ls1); + Free (ls2); + + return matched; +} +#endif /* not HAVE_STRCASECMP */ + +real_t +variance (const word_t *pixels, unsigned x0, unsigned y0, + unsigned width, unsigned height, unsigned cols) +/* + * Compute variance of subimage ('x0', y0', 'width', 'height') of + * the image data given by 'pixels' ('cols' is the number of pixels + * in one row of the image). + * + * Return value: + * variance + */ +{ + real_t average; /* average of pixel values */ + real_t variance; /* variance of pixel values */ + unsigned x, y; /* pixel counter */ + unsigned n; /* number of pixels */ + + assert (pixels); + + for (average = 0, n = 0, y = y0; y < y0 + height; y++) + for (x = x0; x < min (x0 + width, cols); x++, n++) + average += pixels [y * cols + x] / 16; + + average /= n; + + for (variance = 0, y = y0; y < y0 + height; y++) + for (x = x0; x < min (x0 + width, cols); x++) + variance += square ((pixels [y * cols + x] / 16) - average); + + return variance; +} + +int +sort_asc_word (const void *value1, const void *value2) +/* + * Sorting function for quicksort. + * Smallest values come first. + */ +{ + if (* (word_t *) value1 < * (word_t *) value2) + return -1; + else if (* (word_t *) value1 > * (word_t *) value2) + return +1; + else + return 0; +} + +int +sort_desc_word (const void *value1, const void *value2) +/* + * Sorting function for quicksort. + * Largest values come first. + */ +{ + if (* (word_t *) value1 > * (word_t *) value2) + return -1; + else if (* (word_t *) value1 < * (word_t *) value2) + return +1; + else + return 0; +} + +int +sort_asc_pair (const void *value1, const void *value2) +/* + * Sorting function for quicksort. + * Smallest values come first. + */ +{ + word_t v1 = ((pair_t *) value1)->key; + word_t v2 = ((pair_t *) value2)->key; + + if (v1 < v2) + return -1; + else if (v1 > v2) + return +1; + else + return 0; +} + +int +sort_desc_pair (const void *value1, const void *value2) +/* + * Sorting function for quicksort. + * Largest values come first. + */ +{ + word_t v1 = ((pair_t *) value1)->key; + word_t v2 = ((pair_t *) value2)->key; + + if (v1 > v2) + return -1; + else if (v1 < v2) + return +1; + else + return 0; +} diff --git a/converter/other/fiasco/lib/misc.h b/converter/other/fiasco/lib/misc.h new file mode 100644 index 00000000..29456590 --- /dev/null +++ b/converter/other/fiasco/lib/misc.h @@ -0,0 +1,98 @@ +/* + * misc.h + * + * Written by: Stefan Frank + * 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> + */ + +/* + * $Date: 2000/06/14 20:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _MISC_H +#define _MISC_H + +#include "config.h" + +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else /* not TIME_WITH_SYS_TIME */ +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else /* not HAVE_SYS_TIME_H */ +# include <time.h> +# endif /* not HAVE_SYS_TIME_H */ +#endif /* not TIME_WITH_SYS_TIME */ + +#include <stdio.h> +#include "types.h" +#include "bit-io.h" + +enum action_e {START, STOP}; + +void * +Calloc (size_t n, size_t size); +void +Free (void *memory); +unsigned +prg_timer (clock_t *ptimer, enum action_e action); +int +read_int(FILE *infile); +real_t +read_real(FILE *infile); +unsigned +read_rice_code (unsigned rice_k, bitfile_t *input); +void +write_rice_code (unsigned value, unsigned rice_k, bitfile_t *output); +void +write_bin_code (unsigned value, unsigned maxval, bitfile_t *output); +unsigned +bits_bin_code (unsigned value, unsigned maxval); +unsigned +bits_rice_code (unsigned value, unsigned rice_k); +unsigned +read_bin_code (unsigned maxval, bitfile_t *input); +unsigned * +init_clipping (void); +real_t +variance (const word_t *pixels, unsigned x0, unsigned y0, + unsigned width, unsigned height, unsigned cols); + +#ifndef HAVE_MEMMOVE +void * +memmove(void *dest, const void *src, size_t n); +#endif /* not HAVE_MEMMOVE */ + +double +Log2 (double x); +#ifndef HAVE_STRDUP +char * +strdup (const char *s); +#endif +#ifndef HAVE_STRCASECMP +bool_t +strcaseeq (const char *s1, const char *s2); +#else /* HAVE_STRCASECMP */ +int +strcasecmp (const char *s1, const char *s2); +#define strcaseeq(s1, s2) (strcasecmp ((s1), (s2)) == 0) +#endif /* HAVE_STRCASECMP */ + +int +sort_asc_word (const void *value1, const void *value2); +int +sort_desc_word (const void *value1, const void *value2); +int +sort_asc_pair (const void *value1, const void *value2); +int +sort_desc_pair (const void *value1, const void *value2); + +#endif /* not _MISC_H */ + diff --git a/converter/other/fiasco/lib/mvcode.c b/converter/other/fiasco/lib/mvcode.c new file mode 100644 index 00000000..d9ce91e2 --- /dev/null +++ b/converter/other/fiasco/lib/mvcode.c @@ -0,0 +1,14 @@ +#include "mvcode.h" + +unsigned mv_code_table [33][2] = +/* + * MPEG's huffman code for vector components. Format: code_value, length + */ +{ + {0x19, 11}, {0x1b, 11}, {0x1d, 11}, {0x1f, 11}, {0x21, 11}, {0x23, 11}, + {0x13, 10}, {0x15, 10}, {0x17, 10}, {0x7, 8}, {0x9, 8}, {0xb, 8}, {0x7, 7}, + {0x3, 5}, {0x3, 4}, {0x3, 3}, {0x1, 1}, {0x2, 3}, {0x2, 4}, {0x2, 5}, + {0x6, 7}, {0xa, 8}, {0x8, 8}, {0x6, 8}, {0x16, 10}, {0x14, 10}, {0x12, 10}, + {0x22, 11}, {0x20, 11}, {0x1e, 11}, {0x1c, 11}, {0x1a, 11}, {0x18, 11} +}; + diff --git a/converter/other/fiasco/lib/mvcode.h b/converter/other/fiasco/lib/mvcode.h new file mode 100644 index 00000000..f43f2081 --- /dev/null +++ b/converter/other/fiasco/lib/mvcode.h @@ -0,0 +1,6 @@ +#ifndef MVCODE_H_INCLUDED +#define MVCODE_H_INCLUDED + +extern unsigned mv_code_table [33][2]; + +#endif diff --git a/converter/other/fiasco/lib/rpf.c b/converter/other/fiasco/lib/rpf.c new file mode 100644 index 00000000..ac7d48ca --- /dev/null +++ b/converter/other/fiasco/lib/rpf.c @@ -0,0 +1,223 @@ +/* + * rpf.c: Conversion of float to reduced precision format values + * + * Written by: Stefan Frank + * Richard Krampfl + * 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> + */ + +/* + * $Date: 2000/06/14 20:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "misc.h" +#include "rpf.h" + +/* + * CAUTION: The IEEE float format must be used by your compiler, + * or all following code is void! + */ + +#ifdef WORDS_BIGENDIAN +/* + * Big-Endian Architecture (e.g. SUN, Motorola) + * Memory representation of integer 0x00112233 is 00,11,22,33 + */ + +enum real_bytes {BYTE_0, BYTE_1, BYTE_2, BYTE_3}; + +#else /* not WORDS_BIGENDIAN */ +/* + * Little-Endian Architecture (e.g. Intel, VAX, Alpha) + * Memory representation of integer 0x00112233 is 33,22,11,00 + */ + +enum real_bytes {BYTE_3, BYTE_2, BYTE_1, BYTE_0}; + +#endif /* not WORDS_BIGENDIAN */ + +const int RPF_ZERO = -1; + +/***************************************************************************** + + private code + +*****************************************************************************/ + +int +rtob (real_t f, const rpf_t *rpf) +/* + * Convert real number 'f' into fixed point format. + * The real number in [-'range'; +'range'] is scaled to [-1 ; +1]. + * Sign and the first 'precision' - 1 bits of the mantissa are + * packed into one integer. + * + * Return value: + * real value in reduced precision format + */ +{ + unsigned int mantissa; + int exponent, sign; + union + { + float f; + unsigned char c[4]; + } v; /* conversion dummy */ + + f /= rpf->range; /* scale f to [-1,+1] */ + v.f = f; + + /* + * Extract mantissa (23 Bits), exponent (8 Bits) and sign (1 Bit) + */ + + mantissa = ((((v.c[BYTE_1] & 127) << 8 ) | v.c[BYTE_2]) << 8) | v.c[BYTE_3]; + exponent = (((v.c[BYTE_0] & 127) << 1) | (v.c[BYTE_1] & 128 ? 1 : 0)) - 126; + sign = v.c[BYTE_0] & 128 ? 1 : 0; + + /* + * Generate reduced precision mantissa. + */ + mantissa >>= 1; /* shift 1 into from left */ + mantissa |= (1 << 22); + if (exponent > 0) + mantissa <<= exponent; + else + mantissa >>= -exponent; + + mantissa >>= (23 - rpf->mantissa_bits - 1); + + mantissa += 1; /* Round last bit. */ + mantissa >>= 1; + + if (mantissa == 0) /* close to zero */ + return RPF_ZERO; + else if (mantissa >= (1U << rpf->mantissa_bits)) /* overflow */ + return sign; + else + return ((mantissa & ((1U << rpf->mantissa_bits) - 1)) << 1) | sign; +} + +float +btor (int binary, const rpf_t *rpf) +/* + * Convert value 'binary' in reduced precision format to a real value. + * For more information refer to function lin_rtob() above. + * + * Return value: + * converted value + */ +{ + unsigned int mantissa; + int sign, exponent; + union + { + float f; + unsigned char c[4]; + } value; + + if (binary == RPF_ZERO) + return 0; + + if (binary < 0 || binary >= 1 << (rpf->mantissa_bits + 1)) + error ("Reduced precision format: value %d out of range.", binary); + + /* + * Restore IEEE float format: + * mantissa (23 Bits), exponent (8 Bits) and sign (1 Bit) + */ + + sign = binary & 1; + mantissa = (binary & ((1 << (rpf->mantissa_bits + 1)) - 1)) >> 1; + mantissa <<= (23 - rpf->mantissa_bits); + exponent = 0; + + if (mantissa == 0) + { + value.f = (sign ? -1.0 : 1.0); + } + else + { + while (!(mantissa & (1 << 22))) /* normalize mantissa */ + { + exponent--; + mantissa <<= 1; + } + mantissa <<= 1; + + value.c[BYTE_0] = (sign << 7) | ((exponent + 126) >> 1); + value.c[BYTE_1] = (((exponent + 126) & 1) << 7) + | ((mantissa >> 16) & 127); + value.c[BYTE_2] = (mantissa >> 8) & 255; + value.c[BYTE_3] = mantissa & 255; + } + + return value.f * rpf->range; /* expand [ -1 ; +1 ] to + [ -range ; +range ] */ +} + +rpf_t * +alloc_rpf (unsigned mantissa, fiasco_rpf_range_e range) +/* + * Reduced precision format constructor. + * Allocate memory for the rpf_t structure. + * Number of mantissa bits is given by `mantissa'. + * The range of the real values is in the interval [-`range', +`range']. + * In case of invalid parameters, a structure with default values is + * returned. + * + * Return value + * pointer to the new rpf structure + */ +{ + rpf_t *rpf = Calloc (1, sizeof (rpf_t)); + + if (mantissa < 2) + { + warning (_("Size of RPF mantissa has to be in the interval [2,8]. " + "Using minimum value 2.\n")); + mantissa = 2; + } + else if (mantissa > 8) + { + warning (_("Size of RPF mantissa has to be in the interval [2,8]. " + "Using maximum value 8.\n")); + mantissa = 2; + } + + rpf->mantissa_bits = mantissa; + rpf->range_e = range; + switch (range) + { + case FIASCO_RPF_RANGE_0_75: + rpf->range = 0.75; + break; + case FIASCO_RPF_RANGE_1_50: + rpf->range = 1.50; + break; + case FIASCO_RPF_RANGE_2_00: + rpf->range = 2.00; + break; + case FIASCO_RPF_RANGE_1_00: + rpf->range = 1.00; + break; + default: + warning (_("Invalid RPF range specified. Using default value 1.0.")); + rpf->range = 1.00; + rpf->range_e = FIASCO_RPF_RANGE_1_00; + break; + } + return rpf; +} diff --git a/converter/other/fiasco/lib/rpf.h b/converter/other/fiasco/lib/rpf.h new file mode 100644 index 00000000..ba3ff6be --- /dev/null +++ b/converter/other/fiasco/lib/rpf.h @@ -0,0 +1,47 @@ +/* + * rpf.h + * + * Written by: Stefan Frank + * Richard Krampfl + * 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> + */ + +/* + * $Date: 2000/06/14 20:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _RPF_H +#define _RPF_H + +#include "types.h" +#include "fiasco.h" + +typedef struct rpf +{ + unsigned mantissa_bits; /* number of bits used for mantissa */ + real_t range; /* scale value to [-range, +range] */ + fiasco_rpf_range_e range_e; +} rpf_t; + +int +rtob (real_t real, const rpf_t *rpf); +real_t +btor (int b, const rpf_t *rpf); +rpf_t * +alloc_rpf (unsigned mantissa, fiasco_rpf_range_e range); + +extern const int RPF_ZERO; + +#endif /* not _RPF_H */ + + + + + + diff --git a/converter/other/fiasco/lib/types.h b/converter/other/fiasco/lib/types.h new file mode 100644 index 00000000..16d8028c --- /dev/null +++ b/converter/other/fiasco/lib/types.h @@ -0,0 +1,38 @@ +/* + * types.h + * + * Written 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> + */ + +/* + * $Date: 2000/06/14 20:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _FIASCO_TYPES_H +#define _FIASCO_TYPES_H + +#undef FALSE +#undef NO +#undef TRUE +#undef YES + +enum fiasco_boolean { NO = 0, FALSE = 0, YES = 1, TRUE = 1}; + +typedef float real_t; +typedef enum fiasco_boolean bool_t; +typedef unsigned char byte_t; +typedef short word_t; +typedef unsigned short u_word_t; +typedef struct pair +{ + word_t key; + word_t value; +} pair_t; + +#endif |