1/*
2 * "$Id: dither-impl.h,v 1.32 2008/02/18 14:20:17 rlk Exp $"
3 *
4 *   Internal implementation of dither algorithms
5 *
6 *   Copyright 1997-2003 Michael Sweet (mike@easysw.com) and
7 *	Robert Krawitz (rlk@alum.mit.edu)
8 *
9 *   This program is free software; you can redistribute it and/or modify it
10 *   under the terms of the GNU General Public License as published by the Free
11 *   Software Foundation; either version 2 of the License, or (at your option)
12 *   any later version.
13 *
14 *   This program is distributed in the hope that it will be useful, but
15 *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 *   for more details.
18 *
19 *   You should have received a copy of the GNU General Public License
20 *   along with this program; if not, write to the Free Software
21 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 *
23 * Revision History:
24 *
25 *   See ChangeLog
26 */
27
28/*
29 * This file must include only standard C header files.  The core code must
30 * compile on generic platforms that don't support glib, gimp, gtk, etc.
31 */
32
33#ifndef GUTENPRINT_INTERNAL_DITHER_IMPL_H
34#define GUTENPRINT_INTERNAL_DITHER_IMPL_H
35
36#ifdef __cplusplus
37extern "C" {
38#endif
39
40#include <limits.h>
41
42#ifdef __GNUC__
43#define inline __inline__
44#endif
45
46#define D_FLOYD_HYBRID 0
47#define D_ADAPTIVE_BASE 4
48#define D_ADAPTIVE_HYBRID (D_ADAPTIVE_BASE | D_FLOYD_HYBRID)
49#define D_ORDERED_BASE 8
50#define D_ORDERED (D_ORDERED_BASE)
51#define D_FAST_BASE 16
52#define D_FAST (D_FAST_BASE)
53#define D_VERY_FAST (D_FAST_BASE + 1)
54#define D_EVENTONE 32
55#define D_UNITONE 64
56#define D_EVENBETTER 128
57#define D_HYBRID_EVENTONE (D_ORDERED_BASE | D_EVENTONE)
58#define D_HYBRID_UNITONE (D_ORDERED_BASE | D_UNITONE)
59#define D_HYBRID_EVENBETTER (D_ORDERED_BASE | D_EVENBETTER)
60#define D_PREDITHERED 256
61#define D_ORDERED_NEW 512
62#define D_ORDERED_SEGMENTED 1024
63#define D_ORDERED_SEGMENTED_NEW (D_ORDERED_SEGMENTED | D_ORDERED_NEW)
64#define D_INVALID -2
65
66#define DITHER_FAST_STEPS (6)
67
68typedef struct
69{
70  const char *name;
71  const char *text;
72  int id;
73} stpi_dither_algorithm_t;
74
75#define ERROR_ROWS 2
76
77#define MAX_SPREAD 32
78
79typedef void stpi_ditherfunc_t(stp_vars_t *, int, const unsigned short *, int,
80			       int, const unsigned char *);
81
82/*
83 * An end of a dither segment, describing one ink
84 */
85
86typedef struct ink_defn
87{
88  unsigned range;
89  unsigned value;
90  unsigned bits;
91} stpi_ink_defn_t;
92
93/*
94 * A segment of the entire 0-65535 intensity range.
95 */
96
97typedef struct dither_segment
98{
99  stpi_ink_defn_t *lower;
100  stpi_ink_defn_t *upper;
101  unsigned range_span;
102  unsigned value_span;
103  int is_same_ink;
104  int is_equal;
105} stpi_dither_segment_t;
106
107typedef struct dither_channel
108{
109  unsigned randomizer;		/* With Floyd-Steinberg dithering, control */
110				/* how much randomness is applied to the */
111				/* threshold values (0-65535). */
112  unsigned bit_max;
113  unsigned signif_bits;
114  unsigned density;
115  double darkness;		/* Relative darkness of this ink */
116
117  int v;
118  int o;
119  int b;
120  int very_fast;
121
122  stpi_ink_defn_t *ink_list;
123
124  int nlevels;
125  stpi_dither_segment_t *ranges;
126
127  int error_rows;
128  int **errs;
129
130  stp_dither_matrix_impl_t pick;
131  stp_dither_matrix_impl_t dithermat;
132  int row_ends[2];
133  unsigned char *ptr;
134  void *aux_data;		/* aux_freefunc for dither should free this */
135} stpi_dither_channel_t;
136
137typedef struct dither
138{
139  int src_width;		/* Input width */
140  int dst_width;		/* Output width */
141
142  int spread;			/* With Floyd-Steinberg, how widely the */
143  int spread_mask;		/* error is distributed.  This should be */
144				/* between 12 (very broad distribution) and */
145				/* 19 (very narrow) */
146
147  int stpi_dither_type;
148
149  int adaptive_limit;
150
151  int x_aspect;			/* Aspect ratio numerator */
152  int y_aspect;			/* Aspect ratio denominator */
153
154
155  int *offset0_table;
156  int *offset1_table;
157
158  int d_cutoff;
159
160  int last_line_was_empty;
161  int ptr_offset;
162  int error_rows;
163
164  int finalized;		/* When dither is first called, calculate
165				 * some things */
166
167  stp_dither_matrix_impl_t dither_matrix;
168  stpi_dither_channel_t *channel;
169  unsigned channel_count;
170  unsigned total_channel_count;
171  unsigned *channel_index;
172  unsigned *subchannel_count;
173
174  stpi_ditherfunc_t *ditherfunc;
175  void *aux_data;
176  void (*aux_freefunc)(struct dither *);
177} stpi_dither_t;
178
179#define CHANNEL(d, c) ((d)->channel[(c)])
180#define CHANNEL_COUNT(d) ((d)->total_channel_count)
181
182#define USMIN(a, b) ((a) < (b) ? (a) : (b))
183
184
185extern stpi_ditherfunc_t stpi_dither_predithered;
186extern stpi_ditherfunc_t stpi_dither_very_fast;
187extern stpi_ditherfunc_t stpi_dither_ordered;
188extern stpi_ditherfunc_t stpi_dither_ed;
189extern stpi_ditherfunc_t stpi_dither_et;
190extern stpi_ditherfunc_t stpi_dither_ut;
191
192extern void stpi_dither_reverse_row_ends(stpi_dither_t *d);
193extern int stpi_dither_translate_channel(stp_vars_t *v, unsigned channel,
194					 unsigned subchannel);
195extern void stpi_dither_channel_destroy(stpi_dither_channel_t *channel);
196extern void stpi_dither_finalize(stp_vars_t *v);
197extern int *stpi_dither_get_errline(stpi_dither_t *d, int row, int color);
198
199
200#define ADVANCE_UNIDIRECTIONAL(d, bit, input, width, xerror, xstep, xmod) \
201do									  \
202{									  \
203  bit >>= 1;								  \
204  if (bit == 0)								  \
205    {									  \
206      d->ptr_offset++;							  \
207      bit = 128;							  \
208    }									  \
209  input += xstep;							  \
210  if (xmod)								  \
211    {									  \
212      xerror += xmod;							  \
213      if (xerror >= d->dst_width)					  \
214	{								  \
215	  xerror -= d->dst_width;					  \
216	  input += (width);						  \
217	}								  \
218    }									  \
219} while (0)
220
221#define ADVANCE_REVERSE(d, bit, input, width, xerror, xstep, xmod)	\
222do									\
223{									\
224  if (bit == 128)							\
225    {									\
226      d->ptr_offset--;							\
227      bit = 1;								\
228    }									\
229  else									\
230    bit <<= 1;								\
231  input -= xstep;							\
232  if (xmod)								\
233    {									\
234      xerror -= xmod;							\
235      if (xerror < 0)							\
236	{								\
237	  xerror += d->dst_width;					\
238	  input -= (width);						\
239	}								\
240    }									\
241} while (0)
242
243#define ADVANCE_BIDIRECTIONAL(d,bit,in,dir,width,xer,xstep,xmod,err,S)	\
244do									\
245{									\
246  int ii;								\
247  int jj;								\
248  for (ii = 0; ii < width; ii++)					\
249    for (jj = 0; jj < S; jj++)						\
250      err[ii][jj] += dir;						\
251  if (dir == 1)								\
252    ADVANCE_UNIDIRECTIONAL(d, bit, in, width, xer, xstep, xmod);	\
253  else									\
254    ADVANCE_REVERSE(d, bit, in, width, xer, xstep, xmod);		\
255} while (0)
256
257#ifdef __cplusplus
258  }
259#endif
260
261#endif /* GUTENPRINT_INTERNAL_DITHER_IMPL_H */
262/*
263 * End of "$Id: dither-impl.h,v 1.32 2008/02/18 14:20:17 rlk Exp $".
264 */
265