/*
* Internal implementation of dither algorithms
*
* Copyright 1997-2003 Michael Sweet (mike@easysw.com) and
* Robert Krawitz (rlk@alum.mit.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Revision History:
*
* See ChangeLog
*/
/*
* This file must include only standard C header files. The core code must
* compile on generic platforms that don't support glib, gimp, gtk, etc.
*/
#ifndef GUTENPRINT_INTERNAL_DITHER_IMPL_H
#define GUTENPRINT_INTERNAL_DITHER_IMPL_H
#ifdef __cplusplus
extern "C" {
#endif
#include
#ifdef __GNUC__
#ifndef inline
#define inline __inline__
#endif
#endif
#define D_FLOYD_HYBRID 0
#define D_ADAPTIVE_BASE 4
#define D_ADAPTIVE_HYBRID (D_ADAPTIVE_BASE | D_FLOYD_HYBRID)
#define D_ORDERED_BASE 8
#define D_ORDERED (D_ORDERED_BASE)
#define D_FAST_BASE 16
#define D_FAST (D_FAST_BASE)
#define D_VERY_FAST (D_FAST_BASE + 1)
#define D_EVENTONE 32
#define D_UNITONE 64
#define D_EVENBETTER 128
#define D_HYBRID_EVENTONE (D_ORDERED_BASE | D_EVENTONE)
#define D_HYBRID_UNITONE (D_ORDERED_BASE | D_UNITONE)
#define D_HYBRID_EVENBETTER (D_ORDERED_BASE | D_EVENBETTER)
#define D_PREDITHERED 256
#define D_ORDERED_NEW 512
#define D_ORDERED_SEGMENTED 1024
#define D_ORDERED_SEGMENTED_NEW (D_ORDERED_SEGMENTED | D_ORDERED_NEW)
#define D_INVALID -2
#define DITHER_FAST_STEPS (6)
typedef struct
{
const char *name;
const char *text;
int id;
} stpi_dither_algorithm_t;
#define ERROR_ROWS 2
#define MAX_SPREAD 32
typedef void stpi_ditherfunc_t(stp_vars_t *, int, const unsigned short *, int,
int, const unsigned char *);
/*
* An end of a dither segment, describing one ink
*/
typedef struct ink_defn
{
unsigned range;
unsigned value;
unsigned bits;
} stpi_ink_defn_t;
/*
* A segment of the entire 0-65535 intensity range.
*/
typedef struct dither_segment
{
stpi_ink_defn_t *lower;
stpi_ink_defn_t *upper;
unsigned range_span;
unsigned value_span;
int is_same_ink;
int is_equal;
} stpi_dither_segment_t;
typedef struct dither_channel
{
unsigned randomizer; /* With Floyd-Steinberg dithering, control */
/* how much randomness is applied to the */
/* threshold values (0-65535). */
unsigned bit_max;
unsigned signif_bits;
unsigned density;
double darkness; /* Relative darkness of this ink */
int v;
int o;
int b;
int very_fast;
stpi_ink_defn_t *ink_list;
int nlevels;
stpi_dither_segment_t *ranges;
int error_rows;
int **errs;
stp_dither_matrix_impl_t pick;
stp_dither_matrix_impl_t dithermat;
int row_ends[2];
unsigned char *ptr;
void *aux_data; /* aux_freefunc for dither should free this */
} stpi_dither_channel_t;
typedef struct dither
{
int src_width; /* Input width */
int dst_width; /* Output width */
int spread; /* With Floyd-Steinberg, how widely the */
int spread_mask; /* error is distributed. This should be */
/* between 12 (very broad distribution) and */
/* 19 (very narrow) */
int stpi_dither_type;
int adaptive_limit;
int x_aspect; /* Aspect ratio numerator */
int y_aspect; /* Aspect ratio denominator */
int *offset0_table;
int *offset1_table;
int d_cutoff;
int last_line_was_empty;
int ptr_offset;
int error_rows;
int finalized; /* When dither is first called, calculate
* some things */
stp_dither_matrix_impl_t dither_matrix;
stpi_dither_channel_t *channel;
unsigned channel_count;
unsigned total_channel_count;
unsigned *channel_index;
unsigned *subchannel_count;
stpi_ditherfunc_t *ditherfunc;
void *aux_data;
void (*aux_freefunc)(struct dither *);
} stpi_dither_t;
#define CHANNEL(d, c) ((d)->channel[(c)])
#define CHANNEL_COUNT(d) ((d)->total_channel_count)
#define USMIN(a, b) ((a) < (b) ? (a) : (b))
extern stpi_ditherfunc_t stpi_dither_predithered;
extern stpi_ditherfunc_t stpi_dither_very_fast;
extern stpi_ditherfunc_t stpi_dither_ordered;
extern stpi_ditherfunc_t stpi_dither_ed;
extern stpi_ditherfunc_t stpi_dither_et;
extern stpi_ditherfunc_t stpi_dither_ut;
extern void stpi_dither_reverse_row_ends(stpi_dither_t *d);
extern int stpi_dither_translate_channel(stp_vars_t *v, unsigned channel,
unsigned subchannel);
extern void stpi_dither_channel_destroy(stpi_dither_channel_t *channel);
extern void stpi_dither_finalize(stp_vars_t *v);
extern int *stpi_dither_get_errline(stpi_dither_t *d, int row, int color);
#define ADVANCE_UNIDIRECTIONAL(d, bit, input, width, xerror, xstep, xmod) \
do \
{ \
bit >>= 1; \
if (bit == 0) \
{ \
d->ptr_offset++; \
bit = 128; \
} \
input += xstep; \
if (xmod) \
{ \
xerror += xmod; \
if (xerror >= d->dst_width) \
{ \
xerror -= d->dst_width; \
input += (width); \
} \
} \
} while (0)
#define ADVANCE_REVERSE(d, bit, input, width, xerror, xstep, xmod) \
do \
{ \
if (bit == 128) \
{ \
d->ptr_offset--; \
bit = 1; \
} \
else \
bit <<= 1; \
input -= xstep; \
if (xmod) \
{ \
xerror -= xmod; \
if (xerror < 0) \
{ \
xerror += d->dst_width; \
input -= (width); \
} \
} \
} while (0)
#define ADVANCE_BIDIRECTIONAL(d,bit,in,dir,width,xer,xstep,xmod,err,S) \
do \
{ \
int ii; \
int jj; \
for (ii = 0; ii < width; ii++) \
for (jj = 0; jj < S; jj++) \
err[ii][jj] += dir; \
if (dir == 1) \
ADVANCE_UNIDIRECTIONAL(d, bit, in, width, xer, xstep, xmod); \
else \
ADVANCE_REVERSE(d, bit, in, width, xer, xstep, xmod); \
} while (0)
#ifdef __cplusplus
}
#endif
#endif /* GUTENPRINT_INTERNAL_DITHER_IMPL_H */