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