Example #1
0
static int
output_has_gloss(const stp_vars_t *v)
{
  const stpi_channel_group_t *cg =
    ((const stpi_channel_group_t *) stp_get_component_data(v, "Channel"));
  return (cg->gloss_channel >= 0);
}
Example #2
0
void
stp_dither_set_transition(stp_vars_t *v, double exponent)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  unsigned rc = 1 + (unsigned) ceil(sqrt(CHANNEL_COUNT(d)));
  int i, j;
  int color = 0;
  unsigned x_n = d->dither_matrix.x_size / rc;
  unsigned y_n = d->dither_matrix.y_size / rc;
  for (i = 0; i < CHANNEL_COUNT(d); i++)
    stp_dither_matrix_destroy(&(CHANNEL(d, i).pick));
  stp_dither_matrix_destroy(&(d->transition_matrix));
  stp_dither_matrix_copy(&(d->dither_matrix), &(d->transition_matrix));
  d->transition = exponent;
  if (exponent < .999 || exponent > 1.001)
    stp_dither_matrix_scale_exponentially(&(d->transition_matrix), exponent);
  for (i = 0; i < rc; i++)
    for (j = 0; j < rc; j++)
      if (color < CHANNEL_COUNT(d))
	{
	  stp_dither_matrix_clone(&(d->dither_matrix),
				  &(CHANNEL(d, color).pick),
				  x_n * i, y_n * j);
	  color++;
	}
}
Example #3
0
static int
output_needs_gcr(const stp_vars_t *v)
{
  const stpi_channel_group_t *cg =
    ((const stpi_channel_group_t *) stp_get_component_data(v, "Channel"));
  return (cg->gcr_curve && cg->black_channel == 0);
}
Example #4
0
static stpi_channel_group_t *
get_channel_group(const stp_vars_t *v)
{
  stpi_channel_group_t *cg =
    ((stpi_channel_group_t *) stp_get_component_data(v, "Channel"));
  return cg;
}
Example #5
0
void
stp_dither_set_inks_full(stp_vars_t *v, int color, int nshades,
			 const stp_shade_t *shades, double density,
			 double darkness)
{
  int i;
  int idx;
  stpi_dither_channel_t *dc;

  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");

  stp_channel_reset_channel(v, color);

  for (i = nshades - 1; i >= 0; i--)
    {
      int subchannel = nshades - i - 1;
      idx = stpi_dither_translate_channel(v, color, subchannel);
      assert(idx >= 0);
      dc = &(CHANNEL(d, idx));

      stp_channel_add(v, color, subchannel, shades[i].value);
      if (idx >= 0)
	stpi_dither_set_ranges(v, idx, &shades[i], density,
			       shades[i].value * darkness);
      stp_dprintf(STP_DBG_INK, v,
		  "  shade %d value %f\n",
		  i, shades[i].value);
    }
}
Example #6
0
static int
input_has_special_channels(const stp_vars_t *v)
{
  const stpi_channel_group_t *cg =
    ((const stpi_channel_group_t *) stp_get_component_data(v, "Channel"));
  return (cg->curve_count > 0);
}
Example #7
0
static void
stpi_dither_finalize_ranges(stp_vars_t *v, stpi_dither_channel_t *dc)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  int i;
  unsigned lbit = dc->bit_max;
  dc->signif_bits = 0;
  while (lbit > 0)
    {
      dc->signif_bits++;
      lbit >>= 1;
    }

  for (i = 0; i < dc->nlevels; i++)
    {
      if (dc->ranges[i].lower->bits == dc->ranges[i].upper->bits)
	dc->ranges[i].is_same_ink = 1;
      else
	dc->ranges[i].is_same_ink = 0;
      if (dc->ranges[i].range_span > 0 && dc->ranges[i].value_span > 0)
	dc->ranges[i].is_equal = 0;
      else
	dc->ranges[i].is_equal = 1;

      stp_dprintf(STP_DBG_INK, v,
		  "    level %d value[0] %d value[1] %d range[0] %d range[1] %d\n",
		  i, dc->ranges[i].lower->value, dc->ranges[i].upper->value,
		  dc->ranges[i].lower->range, dc->ranges[i].upper->range);
      stp_dprintf(STP_DBG_INK, v,
		  "       bits[0] %d bits[1] %d\n",
		  dc->ranges[i].lower->bits, dc->ranges[i].upper->bits);
      stp_dprintf(STP_DBG_INK, v,
		  "       rangespan %d valuespan %d same_ink %d equal %d\n",
		  dc->ranges[i].range_span, dc->ranges[i].value_span,
		  dc->ranges[i].is_same_ink, dc->ranges[i].is_equal);
      if (i > 0 && dc->ranges[i].lower->range >= d->adaptive_limit)
	{
	  d->adaptive_limit = dc->ranges[i].lower->range + 1;
	  if (d->adaptive_limit > 65535)
	    d->adaptive_limit = 65535;
	  stp_dprintf(STP_DBG_INK, v, "Setting adaptive limit to %d\n",
		      d->adaptive_limit);
	}
    }
  for (i = 0; i <= dc->nlevels; i++)
    stp_dprintf(STP_DBG_INK, v,
		"    ink_list[%d] range %d value %d bits %d\n",
		i, dc->ink_list[i].range,
		dc->ink_list[i].value, dc->ink_list[i].bits);
  if (dc->nlevels == 1 && dc->ranges[0].upper->bits == 1)
    dc->very_fast = 1;
  else
    dc->very_fast = 0;

  stp_dprintf(STP_DBG_INK, v,
	      "  bit_max %d signif_bits %d\n", dc->bit_max, dc->signif_bits);
}
Example #8
0
static void
preinit_matrix(stp_vars_t *v)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  int i;
  for (i = 0; i < CHANNEL_COUNT(d); i++)
    stp_dither_matrix_destroy(&(CHANNEL(d, i).dithermat));
  stp_dither_matrix_destroy(&(d->dither_matrix));
}
Example #9
0
void
stp_dither_set_iterated_matrix(stp_vars_t *v, size_t edge, size_t iterations,
			       const unsigned *data, int prescaled,
			       int x_shear, int y_shear)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  preinit_matrix(v);
  stp_dither_matrix_iterated_init(&(d->dither_matrix), edge, iterations, data);
  postinit_matrix(v, x_shear, y_shear);
}
Example #10
0
unsigned char *
stp_dither_get_channel(stp_vars_t *v, unsigned channel, unsigned subchannel)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  int place = stpi_dither_translate_channel(v, channel, subchannel);
  if (place >= 0)
    return d->channel[place].ptr;
  else
    return NULL;
}
Example #11
0
void
stp_dither_set_matrix_from_dither_array(stp_vars_t *v,
					const stp_array_t *array,
					int transpose)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  preinit_matrix(v);
  stp_dither_matrix_init_from_dither_array(&(d->dither_matrix), array, transpose);
  postinit_matrix(v, 0, 0);
}
Example #12
0
void
stp_dither_add_channel(stp_vars_t *v, unsigned char *data,
		       unsigned channel, unsigned subchannel)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  int idx;
  if (channel >= d->channel_count)
    insert_channel(v, d, channel);
  if (subchannel >= d->subchannel_count[channel])
    insert_subchannel(v, d, channel, subchannel);
  idx = stpi_dither_translate_channel(v, channel, subchannel);
  assert(idx >= 0);
  d->channel[idx].ptr = data;
}
Example #13
0
int
stpi_dither_translate_channel(stp_vars_t *v, unsigned channel,
			      unsigned subchannel)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  unsigned chan_idx;
  if (!d)
    return -1;
  if (channel >= d->channel_count)
    return -1;
  if (subchannel >= d->subchannel_count[channel])
    return -1;
  chan_idx = d->channel_index[channel];
  return chan_idx + subchannel;
}
Example #14
0
void
stp_dither_set_matrix(stp_vars_t *v, const stp_dither_matrix_generic_t *matrix,
		      int transposed, int x_shear, int y_shear)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  int x = transposed ? matrix->y : matrix->x;
  int y = transposed ? matrix->x : matrix->y;
  preinit_matrix(v);
  if (matrix->bytes == 2)
    stp_dither_matrix_init_short(&(d->dither_matrix), x, y,
				 (const unsigned short *) matrix->data,
				 transposed, matrix->prescaled);
  else if (matrix->bytes == 4)
    stp_dither_matrix_init(&(d->dither_matrix), x, y,
			   (const unsigned *)matrix->data,
			   transposed, matrix->prescaled);
  postinit_matrix(v, x_shear, y_shear);
}
Example #15
0
static void
initialize_channel(stp_vars_t *v, int channel, int subchannel)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  int idx = stpi_dither_translate_channel(v, channel, subchannel);
  stpi_dither_channel_t *dc = &(CHANNEL(d, idx));
  stp_shade_t shade;
  stp_dotsize_t dot;
  assert(idx >= 0);
  memset(dc, 0, sizeof(stpi_dither_channel_t));
  stp_dither_matrix_clone(&(d->dither_matrix), &(dc->dithermat), 0, 0);
  stp_dither_matrix_clone(&(d->transition_matrix), &(dc->pick), 0, 0);
  shade.dot_sizes = &dot;
  shade.value = 1.0;
  shade.numsizes = 1;
  dot.bit_pattern = 1;
  dot.value = 1.0;
  stp_dither_set_inks_full(v, channel, 1, &shade, 1.0, 1.0);
}
Example #16
0
static int
input_needs_splitting(const stp_vars_t *v)
{
  const stpi_channel_group_t *cg =
    ((const stpi_channel_group_t *) stp_get_component_data(v, "Channel"));
#if 0
  return cg->total_channels != cg->aux_output_channels;
#else
  int i;
  if (!cg || cg->channel_count <= 0)
    return 0;
  for (i = 0; i < cg->channel_count; i++)
    {
      if (cg->c[i].subchannel_count > 1)
	return 1;
    }
  return 0;
#endif
}
Example #17
0
void
stpi_dither_finalize(stp_vars_t *v)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  if (!d->finalized)
    {
      int i;
      unsigned rc = 1 + (unsigned) ceil(sqrt(CHANNEL_COUNT(d)));
      unsigned x_n = d->dither_matrix.x_size / rc;
      unsigned y_n = d->dither_matrix.y_size / rc;
      for (i = 0; i < CHANNEL_COUNT(d); i++)
	{
	  stpi_dither_channel_t *dc = &(CHANNEL(d, i));
	  stp_dither_matrix_clone(&(d->dither_matrix), &(dc->dithermat),
				   x_n * (i % rc), y_n * (i / rc));
	  stp_dither_matrix_clone(&(d->dither_matrix), &(dc->pick),
				   x_n * (i % rc), y_n * (i / rc));
	}
      d->finalized = 1;
    }
}
Example #18
0
static void
postinit_matrix(stp_vars_t *v, int x_shear, int y_shear)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  unsigned rc = 1 + (unsigned) ceil(sqrt(CHANNEL_COUNT(d)));
  int i, j;
  int color = 0;
  unsigned x_n = d->dither_matrix.x_size / rc;
  unsigned y_n = d->dither_matrix.y_size / rc;
  if (x_shear || y_shear)
    stp_dither_matrix_shear(&(d->dither_matrix), x_shear, y_shear);
  for (i = 0; i < rc; i++)
    for (j = 0; j < rc; j++)
      if (color < CHANNEL_COUNT(d))
	{
	  stp_dither_matrix_clone(&(d->dither_matrix),
				  &(CHANNEL(d, color).dithermat),
				  x_n * i, y_n * j);
	  color++;
	}
  stp_dither_set_transition(v, d->transition);
}
Example #19
0
static void
stpi_dither_set_ranges(stp_vars_t *v, int color, const stp_shade_t *shade,
		       double density, double darkness)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  stpi_dither_channel_t *dc = &(CHANNEL(d, color));
  const stp_dotsize_t *ranges = shade->dot_sizes;
  int nlevels = shade->numsizes;
  int i;

  STP_SAFE_FREE(dc->ranges);
  STP_SAFE_FREE(dc->ink_list);

  dc->nlevels = nlevels > 1 ? nlevels + 1 : nlevels;
  dc->ranges = (stpi_dither_segment_t *)
    stp_zalloc(dc->nlevels * sizeof(stpi_dither_segment_t));
  dc->ink_list = (stpi_ink_defn_t *)
    stp_zalloc((dc->nlevels + 1) * sizeof(stpi_ink_defn_t));
  dc->bit_max = 0;
  dc->density = density * 65535;
  dc->darkness = darkness;
  stp_init_debug_messages(v);
  stp_dprintf(STP_DBG_INK, v,
	      "stpi_dither_set_ranges channel %d nlevels %d density %f darkness %f\n",
	      color, nlevels, density, darkness);
  for (i = 0; i < nlevels; i++)
    stp_dprintf(STP_DBG_INK, v,
		"  level %d value %f pattern %x\n", i,
		ranges[i].value, ranges[i].bit_pattern);
  dc->ranges[0].lower = &dc->ink_list[0];
  dc->ranges[0].upper = &dc->ink_list[1];
  dc->ink_list[0].range = 0;
  dc->ink_list[0].value = 0;
  dc->ink_list[0].bits = 0;
  if (nlevels == 1)
    dc->ink_list[1].range = 65535;
  else
    dc->ink_list[1].range = ranges[0].value * 65535.0 * density;
  if (dc->ink_list[1].range > 65535)
    dc->ink_list[1].range = 65535;
  dc->ink_list[1].value = ranges[0].value * 65535.0;
  if (dc->ink_list[1].value > 65535)
    dc->ink_list[1].value = 65535;
  dc->ink_list[1].bits = ranges[0].bit_pattern;
  if (ranges[0].bit_pattern > dc->bit_max)
    dc->bit_max = ranges[0].bit_pattern;
  dc->ranges[0].range_span = dc->ranges[0].upper->range;
  dc->ranges[0].value_span = dc->ranges[0].upper->value;
  if (dc->nlevels > 1)
    {
      for (i = 1; i < nlevels; i++)
	{
	  int l = i + 1;
	  dc->ranges[i].lower = &dc->ink_list[i];
	  dc->ranges[i].upper = &dc->ink_list[l];

	  dc->ink_list[l].range =
	    (ranges[i].value + ranges[i].value) * 32768.0 * density;
	  if (dc->ink_list[l].range > 65535)
	    dc->ink_list[l].range = 65535;
	  dc->ink_list[l].value = ranges[i].value * 65535.0;
	  if (dc->ink_list[l].value > 65535)
	    dc->ink_list[l].value = 65535;
	  dc->ink_list[l].bits = ranges[i].bit_pattern;
	  if (ranges[i].bit_pattern > dc->bit_max)
	    dc->bit_max = ranges[i].bit_pattern;
	  dc->ranges[i].range_span =
	    dc->ink_list[l].range - dc->ink_list[i].range;
	  dc->ranges[i].value_span =
	    dc->ink_list[l].value - dc->ink_list[i].value;
	}
      dc->ranges[i].lower = &dc->ink_list[i];
      dc->ranges[i].upper = &dc->ink_list[i+1];
      dc->ink_list[i+1] = dc->ink_list[i];
      dc->ink_list[i+1].range = 65535;
      dc->ranges[i].range_span =
	dc->ink_list[i+1].range - dc->ink_list[i].range;
      dc->ranges[i].value_span =
	dc->ink_list[i+1].value - dc->ink_list[i].value;
    }
  stpi_dither_finalize_ranges(v, dc);
  stp_flush_debug_messages(v);
}
Example #20
0
void
stpi_dither_et(stp_vars_t *v,
	       int row,
	       const unsigned short *raw,
	       int duplicate_line,
	       int zero_mask,
	       const unsigned char *mask)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  eventone_t *et;

  int		x,
	        length;
  unsigned char	bit;
  int		i;

  int		terminate;
  int		direction;
  int		xerror, xstep, xmod;
  int		channel_count = CHANNEL_COUNT(d);

  if (!et_initializer(d, duplicate_line, zero_mask))
    return;

  et = (eventone_t *) d->aux_data;

  length = (d->dst_width + 7) / 8;

  if (row & 1) {
    direction = 1;
    x = 0;
    terminate = d->dst_width;
    d->ptr_offset = 0;
  } else {
    direction = -1;
    x = d->dst_width - 1;
    terminate = -1;
    d->ptr_offset = length - 1;
    raw += channel_count * (d->src_width - 1);
  }
  bit = 1 << (7 - (x & 7));
  xstep  = channel_count * (d->src_width / d->dst_width);
  xmod   = d->src_width % d->dst_width;
  xerror = (xmod * x) % d->dst_width;

  for (; x != terminate; x += direction) {

    int point_error = 0;
    int comparison = 32768;

    if (d->stpi_dither_type & D_ORDERED_BASE)
      comparison += (ditherpoint(d, &(d->dither_matrix), x) / 16) - 2048;

    for (i=0; i < channel_count; i++) {
      if (CHANNEL(d, i).ptr)
	{
	  int inkspot;
	  int range_point;
	  stpi_dither_channel_t *dc = &CHANNEL(d, i);
	  shade_distance_t *sp = (shade_distance_t *) dc->aux_data;
	  stpi_ink_defn_t *inkp;
	  stpi_ink_defn_t lower, upper;

	  advance_eventone_pre(sp, et, x);

	  /*
	   * Find which are the two candidate dot sizes.
	   * Rather than use the absolute value of the point to compute
	   * the error, we will use the relative value of the point within
	   * the range to find the two candidate dot sizes.
	   */
	  range_point =
	    find_segment_and_ditherpoint(dc, raw[i], &lower, &upper);

	  /* Incorporate error data from previous line */
	  dc->v += 2 * range_point + (dc->errs[0][x + MAX_SPREAD] + 8) / 16;
	  inkspot = dc->v - range_point;

	  point_error += eventone_adjust(dc, et, inkspot, range_point);

	  /* Determine whether to print the larger or smaller dot */
	  inkp = &lower;
	  if (point_error >= comparison) {
	    point_error -= 65535;
	    inkp = &upper;
	    dc->v -= 131070;
	    sp->dis = et->d_sq;
	  }

	  /* Adjust the error to reflect the dot choice */
	  if (inkp->bits) {
	    if (!mask || (*(mask + d->ptr_offset) & bit)) {
	      set_row_ends(dc, x);

	      /* Do the printing */
	      print_ink(d, dc->ptr, inkp, bit, length);
	    }
	  }

	  /* Spread the error around to the adjacent dots */
	  eventone_update(dc, et, x, direction);
	  diffuse_error(dc, et, x, direction);
	}
    }
    if (direction == 1)
      ADVANCE_UNIDIRECTIONAL(d, bit, raw, channel_count, xerror, xstep, xmod);
    else
      ADVANCE_REVERSE(d, bit, raw, channel_count, xerror, xstep, xmod);
  }
  if (direction == -1)
    stpi_dither_reverse_row_ends(d);
}
Example #21
0
void
stpi_dither_ut(stp_vars_t *v,
	       int row,
	       const unsigned short *raw,
	       int duplicate_line,
	       int zero_mask,
	       const unsigned char *mask)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  eventone_t *et;

  int		x,
	        length;
  unsigned char	bit;
  int		i;

  int		terminate;
  int		direction;
  int		xerror, xstep, xmod;
  int		channel_count = CHANNEL_COUNT(d);
  stpi_dither_channel_t *ddc;

  if (channel_count == 1) {
    stpi_dither_et(v, row, raw, duplicate_line, zero_mask, mask);
    return;
  }

  if (!et_initializer(d, duplicate_line, zero_mask))
    return;

  et = (eventone_t *) d->aux_data;
  ddc = et->dummy_channel;

  length = (d->dst_width + 7) / 8;

  if (row & 1) {
    direction = 1;
    x = 0;
    terminate = d->dst_width;
    d->ptr_offset = 0;
  } else {
    direction = -1;
    x = d->dst_width - 1;
    terminate = -1;
    d->ptr_offset = length - 1;
    raw += channel_count * (d->src_width - 1);
  }
  bit = 1 << (7 - (x & 7));
  xstep  = channel_count * (d->src_width / d->dst_width);
  xmod   = d->src_width % d->dst_width;
  xerror = (xmod * x) % d->dst_width;

  for (; x != terminate; x += direction) {

    shade_distance_t *ssp = (shade_distance_t *) ddc->aux_data;
    int point_error = 0;
    int total_error = 0;
    int channels_to_print = 0;
    int print_all_channels = 0;
    int maximum_value = 0;
    int comparison = 32768;
    stpi_dither_channel_t *best_channel = NULL;
    stpi_dither_channel_t *second_best_channel = NULL;
    int best_channel_value = INT_MIN;
    int second_best_channel_value = INT_MIN;
    int random_value = ditherpoint(d, &(d->dither_matrix), x);

    if (d->stpi_dither_type & D_ORDERED_BASE)
      comparison += (random_value / 16) - 2048;


    ddc->b = 0;
    advance_eventone_pre(ssp, et, x);

    for (i=0; i < channel_count; i++) {
      stpi_dither_channel_t *dc = &CHANNEL(d, i);
      if (dc->ptr) {
	shade_distance_t *sp = (shade_distance_t *) dc->aux_data;

	advance_eventone_pre(sp, et, x);

	/*
	 * Find which are the two candidate dot sizes.
	 * Rather than use the absolute value of the point to compute
	 * the error, we will use the relative value of the point within
	 * the range to find the two candidate dot sizes.
	 */
	dc->b = find_segment_and_ditherpoint(dc, raw[i],
					     &(sp->lower), &(sp->upper));
	if (sp->share_this_channel) {
	  if (dc->b > maximum_value)
	    maximum_value = dc->b;
	  ddc->b += dc->b;
	}
	/* Incorporate error data from previous line */
	dc->v += 2 * dc->b + (dc->errs[0][x + MAX_SPREAD] + 8) / 16;
	dc->o = unitone_adjust(dc, et, dc->v - dc->b, dc->b);
      }
    }

#if 0
    if ((2 * (ddc->b - maximum_value)) < (3 * maximum_value))
      print_all_channels = 1;
#endif

    if (ddc->b > 131070)
      print_all_channels = 1;
    else if (ddc->b > 65535) {
      ddc->b -= 65535;
      channels_to_print = 1;
    }

    if (ddc->b > 65535) {
      ddc->b = 65535;
    }
    
    ddc->v += 2 * ddc->b + (ddc->errs[0][x + MAX_SPREAD] + 8) / 16;
    total_error += eventone_adjust(ddc, et, ddc->v - ddc->b, ddc->b);
    if (total_error >= comparison) {
      channels_to_print += 1;
    }

    if (!print_all_channels) {
      for (i=0; i < channel_count; i++) {
	stpi_dither_channel_t *dc = &CHANNEL(d, i);
	shade_distance_t *sp = (shade_distance_t *) dc->aux_data;
      
	if (dc->ptr) {

	  if (sp->share_this_channel) {
	    if (dc->o > best_channel_value) {
	      second_best_channel = best_channel;
	      best_channel = dc;
	      second_best_channel_value = best_channel_value;
	      if (dc->o >= 32768)
		best_channel_value = INT_MAX;
	      else
		best_channel_value = dc->o;
	    } else if (dc->o > second_best_channel_value) {
	      second_best_channel = dc;
	      if (dc->o >= 32768)
		second_best_channel_value = INT_MAX;
	      else
		second_best_channel_value = dc->o;
	    }
	  }
	}
      }
    }
    
    for (i=0; i < channel_count; i++) {
      stpi_dither_channel_t *dc = &CHANNEL(d, i);
      if (dc->ptr) {

	/* Determine whether to print the larger or smaller dot */
	shade_distance_t *sp = (shade_distance_t *) dc->aux_data;
	stpi_ink_defn_t *inkp = &(sp->lower);

	if (dc->o < 0)
	  dc->o = 0;
	else if (dc->o > 65535)
	  dc->o = 65535;
	if (print_all_channels || !sp->share_this_channel) {
	  point_error += dc->o;
	  if (point_error >= comparison) {
	    point_error -= 65535;
	    inkp = &(sp->upper);
	    dc->v -= 131070;
	    sp->dis = et->d_sq;
	  }
	} else if ((channels_to_print >= 1 && best_channel == dc) ||
		   (channels_to_print >= 2 && second_best_channel == dc)) {
	  inkp = &(sp->upper);
	  dc->v -= 131070;
	  sp->dis = et->d_sq;
	}	  
	if (inkp->bits) {
	  if (!mask || (*(mask + d->ptr_offset) & bit)) {
	    set_row_ends(dc, x);

	    /* Do the printing */
	    print_ink(d, dc->ptr, inkp, bit, length);
	  }
	}
      }
    }
    if (total_error >= comparison) {
      ddc->v -= 131070;
      total_error -= 65535;
      ssp->dis = et->d_sq;
    }

    eventone_update(ddc, et, x, direction);
    diffuse_error(ddc, et, x, direction);
    for (i=0; i < channel_count; i++) {
      stpi_dither_channel_t *dc = &CHANNEL(d, i);
      if (dc->ptr) {

	/* Spread the error around to the adjacent dots */
	eventone_update(dc, et, x, direction);
	diffuse_error(dc, et, x, direction);
      }
    }


    if (direction == 1)
      ADVANCE_UNIDIRECTIONAL(d, bit, raw, channel_count, xerror, xstep, xmod);
    else
      ADVANCE_REVERSE(d, bit, raw, channel_count, xerror, xstep, xmod);
  }
  if (direction == -1)
    stpi_dither_reverse_row_ends(d);
}