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