1/*
2 * "$Id: dither-very-fast.c,v 1.15 2004/09/17 18:38:20 rleigh Exp $"
3 *
4 *   Very fast dither algorithm
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#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <gutenprint/gutenprint.h>
32#include "gutenprint-internal.h"
33#include <gutenprint/gutenprint-intl-internal.h>
34#include "dither-impl.h"
35#include "dither-inlined-functions.h"
36
37static inline void
38print_color_very_fast(const stpi_dither_t *d, stpi_dither_channel_t *dc,
39		      int val, int x, int y, unsigned char bit,
40		      unsigned bits, int length)
41{
42  int j;
43  if (bits && val >= ditherpoint(d, &(dc->dithermat), x))
44    {
45      unsigned char *tptr = dc->ptr + d->ptr_offset;
46
47      /*
48       * Lay down all of the bits in the pixel.
49       */
50      set_row_ends(dc, x);
51      for (j = 1; j <= bits; j += j, tptr += length)
52	{
53	  if (j & bits)
54	    tptr[0] |= bit;
55	}
56    }
57}
58
59void
60stpi_dither_very_fast(stp_vars_t *v,
61		      int row,
62		      const unsigned short *raw,
63		      int duplicate_line,
64		      int zero_mask,
65		      const unsigned char *mask)
66{
67  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
68  int		x,
69		length;
70  unsigned char *bit_patterns;
71  unsigned char	bit;
72  int i;
73  int one_bit_only = 1;
74
75  int xerror, xstep, xmod;
76
77  if ((zero_mask & ((1 << CHANNEL_COUNT(d)) - 1)) ==
78      ((1 << CHANNEL_COUNT(d)) - 1))
79    return;
80
81  length = (d->dst_width + 7) / 8;
82
83  bit = 128;
84  xstep  = CHANNEL_COUNT(d) * (d->src_width / d->dst_width);
85  xmod   = d->src_width % d->dst_width;
86  xerror = 0;
87
88  bit_patterns = stp_zalloc(sizeof(unsigned char) * CHANNEL_COUNT(d));
89  for (i = 0; i < CHANNEL_COUNT(d); i++)
90    {
91      stpi_dither_channel_t *dc = &(CHANNEL(d, i));
92      if (dc->nlevels > 0)
93	bit_patterns[i] = dc->ranges[dc->nlevels - 1].upper->bits;
94      if (bit_patterns[i] != 1)
95	one_bit_only = 0;
96    }
97  if (one_bit_only)
98    {
99      for (x = 0; x < d->dst_width; x ++)
100	{
101	  if (!mask || (*(mask + d->ptr_offset) & bit))
102	    {
103	      for (i = 0; i < CHANNEL_COUNT(d); i++)
104		{
105		  if (raw[i] &&
106		      raw[i] >= ditherpoint(d, &(CHANNEL(d, i).dithermat), x))
107		    {
108		      set_row_ends(&(CHANNEL(d, i)), x);
109		      CHANNEL(d, i).ptr[d->ptr_offset] |= bit;
110		    }
111		}
112	    }
113	  ADVANCE_UNIDIRECTIONAL(d, bit, raw, CHANNEL_COUNT(d),
114				 xerror, xstep, xmod);
115	}
116    }
117  else
118    {
119      for (x = 0; x < d->dst_width; x ++)
120	{
121	  if (!mask || (*(mask + d->ptr_offset) & bit))
122	    {
123	      for (i = 0; i < CHANNEL_COUNT(d); i++)
124		{
125		  if (CHANNEL(d, i).ptr && raw[i])
126		    print_color_very_fast(d, &(CHANNEL(d, i)), raw[i], x, row,
127					  bit, bit_patterns[i], length);
128		}
129	    }
130	  ADVANCE_UNIDIRECTIONAL(d, bit, raw, CHANNEL_COUNT(d),
131				 xerror, xstep, xmod);
132	}
133    }
134  stp_free(bit_patterns);
135}
136