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); }
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++; } }
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); }
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; }
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); } }
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); }
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); }
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)); }
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); }
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; }
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); }
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; }
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; }
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); }
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 = ˙ 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); }
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 }
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; } }
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); }
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); }
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); }
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); }