diff options
-rw-r--r-- | base/gen_ordered.c | 59 | ||||
-rw-r--r-- | doc/Language.htm | 13 | ||||
-rw-r--r-- | psi/int.mak | 2 | ||||
-rw-r--r-- | psi/zht2.c | 167 | ||||
-rw-r--r-- | toolbin/halftone/gen_ordered/gen_ordered_example.ps | 11 |
5 files changed, 160 insertions, 92 deletions
diff --git a/base/gen_ordered.c b/base/gen_ordered.c index d2667c263..f2544a1b8 100644 --- a/base/gen_ordered.c +++ b/base/gen_ordered.c @@ -28,9 +28,12 @@ # define FREE(mem, ptr) gs_free_object((gs_memory_t *)mem, ptr, "gen_ordered") # define PRINTF(mem, str) outprintf((gs_memory_t *)mem, str) +# define PRINTF2(mem, str, v1, v2) outprintf((gs_memory_t *)mem, str, v1, v2) +# define PRINTF4(mem, str, v1, v2, v3, v4) outprintf((gs_memory_t *)mem, str, v1, v2, v3, v4) # define PRINTF7(mem, str, v1, v2, v3, v4, v5, v6, v7) outprintf((gs_memory_t *)mem, str, v1, v2, v3, v4, v5, v6, v7) # define EPRINTF(mem, str) errprintf((gs_memory_t *)mem, str) # define EPRINTF1(mem, str, v1) errprintf((gs_memory_t *)mem, str, v1) +# define EPRINTF3(mem, str, v1, v2, v3) errprintf((gs_memory_t *)mem, str, v1, v2, v3) #endif /* defined GS_LIB_BUILD */ @@ -55,9 +58,12 @@ typedef unsigned char byte; # define FREE(mem, ptr) (free(ptr)) # define PRINTF(mem, str) printf(str) +# define PRINTF2(mem, str, v1, v2) printf(str, v1, v2) +# define PRINTF4(mem, str, v1, v2, v3, v4) printf(str, v1, v2, v3, v4) # define PRINTF7(mem, str, v1, v2, v3, v4, v5, v6, v7) printf(str, v1, v2, v3, v4, v5, v6, v7) # define EPRINTF(mem, str) fprintf(stderr, str) # define EPRINTF1(mem, str, v1) fprintf(stderr, str, v1) +# define EPRINTF3(mem, str, v1, v2, v3) fprintf(stderr, str, v1, v2, v3) #endif /* ndef LIB_BUILD */ @@ -123,7 +129,7 @@ void create_2d_gauss_filter(float *filter, int x_size, int y_size, static int htsc_create_holladay_mask(htsc_dig_grid_t super_cell, int H, int L, double gamma, htsc_dig_grid_t *final_mask); static int htsc_create_dither_mask(htsc_dig_grid_t super_cell, - htsc_dig_grid_t *final_mask, + htsc_dig_grid_t *final_mask, int verbose, int num_levels, int y, int x, double vert_dpi, double horiz_dpi, int N, double gamma, htsc_dig_grid_t dot_grid, htsc_point_t one_index); @@ -285,14 +291,18 @@ htsc_gen_ordered(htsc_param_t params, int *S, htsc_dig_grid_t *final_mask) } else { /* Dont allow nonsense settings */ if (num_levels * N > super_cell.height * super_cell.width) { - printf("Notice, %3.0lf quantization levels not possible with super cell of %d by %d\n", num_levels, super_cell.height, super_cell.width); + EPRINTF3(final_mask->memory, + "Notice, %3.0lf quantization levels not possible with super cell of %d by %d\n", + num_levels, super_cell.height, super_cell.width); num_levels = ROUND((super_cell.height * super_cell.width) / N); - printf("Reducing dithering quantization to %3.0lf\n", num_levels); - printf("For an effective quantization of %d\n", super_cell.height * super_cell.width); + EPRINTF1(final_mask->memory, "Reducing dithering quantization to %3.0lf\n", + num_levels); + EPRINTF1(final_mask->memory, "For an effective quantization of %d\n", + super_cell.height * super_cell.width); } - code = htsc_create_dither_mask(super_cell, final_mask, num_levels, y, x, - params.vert_dpi, params.horiz_dpi, N, params.gamma, - dot_grid, one_index); + code = htsc_create_dither_mask(super_cell, final_mask, params.verbose, num_levels, + y, x, params.vert_dpi, params.horiz_dpi, N, + params.gamma, dot_grid, one_index); } } final_mask->bin_center = bin_center; @@ -341,13 +351,13 @@ htsc_mask_to_tos(htsc_dig_grid_t *final_mask) values = (htsc_threshpoint_t *) ALLOC(final_mask->memory, sizeof(htsc_threshpoint_t) * width * height); if (values == NULL) { - printf("ERROR! malloc failure in htsc_mask_to_tos!\n"); + EPRINTF(final_mask->memory, "ERROR! malloc failure in htsc_mask_to_tos!\n"); return -1; } tos = (int *) ALLOC(final_mask->memory, sizeof(int) * 2 * height * width); if (tos == NULL) { FREE(final_mask->memory, values); - printf("ERROR! malloc failure in htsc_mask_to_tos!\n"); + EPRINTF(final_mask->memory, "ERROR! malloc failure in htsc_mask_to_tos!\n"); return -1; } /* Do a sort on the values and then output the coordinates */ @@ -365,18 +375,18 @@ htsc_mask_to_tos(htsc_dig_grid_t *final_mask) } } #if RAW_SCREEN_DUMP - printf("Unsorted\n"); + EPRINTF(final_mask->memory, "Unsorted\n"); for (k = 0; k < count; k++) { - printf("Index %d : x = %d y = %d dist = %4.2lf value = %d \n", + EPRINTF(final_mask->memory, "Index %d : x = %d y = %d dist = %4.2lf value = %d \n", values[k].index, values[k].x, values[k].y, values[k].dist_to_center, values[k].value); } #endif /* Sort */ qsort(values, height * width, sizeof(htsc_threshpoint_t), compare); #if RAW_SCREEN_DUMP - printf("Sorted\n"); + EPRINTF(final_mask->memory, "Sorted\n"); for (k = 0; k < count; k++) { - printf("Index %d : x = %d y = %d dist = %4.2lf value = %d \n", + EPRINTF(final_mask->memory, "Index %d : x = %d y = %d dist = %4.2lf value = %d \n", values[k].index, values[k].x, values[k].y, values[k].dist_to_center, values[k].value); } #endif @@ -1403,7 +1413,7 @@ htsc_init_dot_position(byte *screen_matrix, int num_cols, int num_rows, static int htsc_create_dither_mask(htsc_dig_grid_t super_cell, htsc_dig_grid_t *final_mask, - int num_levels, int y, int x, double vert_dpi, + int verbose, int num_levels, int y, int x, double vert_dpi, double horiz_dpi, int N, double gamma, htsc_dig_grid_t dot_grid, htsc_point_t dot_grid_one_index) { @@ -1455,8 +1465,16 @@ htsc_create_dither_mask(htsc_dig_grid_t super_cell, htsc_dig_grid_t *final_mask, locate[num_dots] = j; num_dots++; if (num_dots == (curr_size - 1)) { + int *tmp = locate; + curr_size = curr_size * 2; - locate = (int*) realloc(locate, sizeof(int) * curr_size); + locate = (int*) ALLOC(dot_grid.memory, sizeof(int) * curr_size); + if (locate == NULL) { + code = -1; + goto out; + } + memcpy(locate, tmp, sizeof(int) * (num_dots+1)); + FREE(dot_grid.memory, tmp); } } } @@ -1567,11 +1585,16 @@ htsc_create_dither_mask(htsc_dig_grid_t super_cell, htsc_dig_grid_t *final_mask, #endif } - printf("\n--Dot Positions--\n"); + if (verbose > 0) + PRINTF(final_mask->memory, "\n--Dot Positions--\n"); for (k = 0; k < num_levels; k++) { - printf("dot_level_pos %d: number_points = %d\n", k, dot_level_pos[k].number_points); + if (verbose > 0) + PRINTF2(final_mask->memory, "dot_level_pos %d: number_points = %d\n", + k, dot_level_pos[k].number_points); for (j = 0; j < dot_level_pos[k].number_points; j++) { - printf("\tpoint: %d: locations = %d x = %3.2lf y = %3.2lf\n", j, dot_level_pos[k].locations[j], dot_level_pos[k].point[j].x, dot_level_pos[k].point[j].y); + if (verbose > 0) + PRINTF4(final_mask->memory, "\tpoint: %d: locations = %d x = %3.2lf y = %3.2lf\n", + j, dot_level_pos[k].locations[j], dot_level_pos[k].point[j].x, dot_level_pos[k].point[j].y); } } diff --git a/doc/Language.htm b/doc/Language.htm index f94e73304..2212f696b 100644 --- a/doc/Language.htm +++ b/doc/Language.htm @@ -824,8 +824,10 @@ collection as a performance improvement. Additional settings may be added in the <dl> <dt><a name=".genordered"></a> -<code><dict> .genordered <dict></code></dt> -<dd>This operator creates an ordered dither screening pattern with the parameters from the dictionary, returning a PostScript HalftoneType 3 (threshold array based) dictionary suitable for use with <code>sethalftone</code> or as a component Halftone of a <code>HalftoneType 5</code> Halftone dictionary. +<code><dict> .genordered <dict></code> (default: /OutputType /Type3).</dt> +<dt><code><dict> .genordered <string></code> (/OutputType /ThreshString).</dt> +<dt><code><dict> .genordered <array></code> (/OutputType /TOSArray).</dt> +<dd>This operator creates an ordered dither screening pattern with the parameters from the dictionary, returning (by default) a PostScript HalftoneType 3 (threshold array based) dictionary suitable for use with <code>sethalftone</code> or as a component Halftone of a <code>HalftoneType 5</code> Halftone dictionary. The /OutputType parameter can also select other than Halftone Type 3 as the return paramter, <p> <code><dict></code> has the following keys (all are optional): <dl> @@ -846,6 +848,13 @@ collection as a performance improvement. Additional settings may be added in the <dt><code>/Levels</code> <dd>Integer; default value = 1 -- actual number of gray levels is determined by Frequency and H/V Resolution. <dd>SuperCellSize may need to be specified large enough to achieve the requested number of gray levels. +<dt><code>/OutputType</code> +<dd>Name; default value = /Type3 (HalftoneType 3 dictionary). Other shapes available are: +<dl> +<dt>/ThreshString: first two bytes are width (high byte first), next two bytes are height, followed by the +threshold array bytes (same as /Thresholds of the Type3 dictionary). +<dt>/TOSArray: first element is the width, next is the height, followed by pairs X, then Y, of the turn-on-sequence of the threshold array. This information can be used to construct a threshold array with a transfer function "pickled into" the threshold array, which is useful if the turn-on-sequence has more than 256 pairs. Refer to toolbin/halftone/thresh_remap for more information. +</dl> </dl> </dl> diff --git a/psi/int.mak b/psi/int.mak index 617f868a4..8680320ba 100644 --- a/psi/int.mak +++ b/psi/int.mak @@ -1074,7 +1074,7 @@ $(PSOBJ)zcsindex.$(OBJ) : $(PSSRC)zcsindex.c $(OP) $(memory__h)\ $(PSCC) $(PSO_)zcsindex.$(OBJ) $(C_) $(PSSRC)zcsindex.c $(PSOBJ)zht2.$(OBJ) : $(PSSRC)zht2.c $(OP)\ - $(gsstruct_h) $(gxdevice_h) $(gzht_h) $(gen_ordered_h)\ + $(memory__h) $(gsstruct_h) $(gxdevice_h) $(gzht_h) $(gen_ordered_h)\ $(estack_h) $(ialloc_h) $(icolor_h) $(iddict_h) $(idparam_h) $(igstate_h)\ $(iht_h) $(store_h) $(iname_h) $(zht2_h) $(gxgstate_h) $(INT_MAK) $(MAKEDIRS) $(PSCC) $(PSO_)zht2.$(OBJ) $(II)$(GENORDERED_SRCDIR) $(C_) $(PSSRC)zht2.c diff --git a/psi/zht2.c b/psi/zht2.c index f77f8aab4..739ed2704 100644 --- a/psi/zht2.c +++ b/psi/zht2.c @@ -15,6 +15,7 @@ /* Level 2 sethalftone operator */ +#include "memory_.h" #include "ghost.h" #include "oper.h" #include "gsstruct.h" @@ -373,10 +374,10 @@ zsethalftone5(i_ctx_t *i_ctx_p) /* array will have: width height turn_on_sequence.x turn_on_sequence.y ... */ /* total array length is 2 + (2 * width * height) */ static int -zgen_ordered(i_ctx_t *i_ctx_p) +zgenordered(i_ctx_t *i_ctx_p) { os_ptr op = osp; - int code = 0; + int i, code = 0; gs_memory_t *mem; int space_index; htsc_param_t params; @@ -385,6 +386,8 @@ zgen_ordered(i_ctx_t *i_ctx_p) float tmp_float; gs_gstate *pgs = igs; gx_device *currdevice = pgs->device; + output_format_type output_type = OUTPUT_PS; + ref *out_type_name; if (ref_stack_count(&o_stack) < 1) return_error(gs_error_stackunderflow); @@ -403,6 +406,21 @@ zgen_ordered(i_ctx_t *i_ctx_p) final_mask.memory = mem->non_gc_memory; final_mask.data = NULL; + if ((code = dict_find_string(op, "OutputType", &out_type_name)) > 0) { + ref namestr; + + if (!r_has_type(out_type_name, t_name)) + return gs_error_typecheck; + name_string_ref(imemory, out_type_name, &namestr); + if (r_size(&namestr) == 8 && !memcmp(namestr.value.bytes, "TOSArray", 8)) + output_type = OUTPUT_TOS; + else if (r_size(&namestr) == 5 && !memcmp(namestr.value.bytes, "Type3", 5)) + output_type = OUTPUT_PS; + else if (r_size(&namestr) == 12 && !memcmp(namestr.value.bytes, "ThreshString", 12)) + output_type = OUTPUT_RAW; + else + return gs_error_undefined; + } if ((code = dict_int_param(op, "Angle", 0, 360, 0, ¶ms.targ_scr_ang)) < 0) return gs_error_undefined; if ((code = dict_int_param(op, "Frequency", 1, 0x7fff, 75, ¶ms.targ_lpi)) < 0) @@ -434,83 +452,92 @@ zgen_ordered(i_ctx_t *i_ctx_p) if (code < 0) goto done; -#ifdef RETURN_TOS_ARRAY - /* Now return the mask info in an array [ width height turn_on.x turn_on.y ... ] */ - code = ialloc_ref_array((ref *)op, a_all, 2 + (2 * final_mask.width * final_mask.height), "gen_ordered"); - if (code < 0) - goto done; - make_int(&(op->value.refs[0]), final_mask.width); - make_int(&(op->value.refs[1]), final_mask.height); - for (i=0; i < 2 * final_mask.width * final_mask.height; i++) - make_int(&(op->value.refs[i+2]), final_mask.data[i]); -#else + switch (output_type) { + case OUTPUT_TOS: + /* Now return the mask info in an array [ width height turn_on.x turn_on.y ... ] */ + code = ialloc_ref_array((ref *)op, a_all, 2 + (2 * final_mask.width * final_mask.height), "gen_ordered"); + if (code < 0) + goto done; + make_int(&(op->value.refs[0]), final_mask.width); + make_int(&(op->value.refs[1]), final_mask.height); + for (i=0; i < 2 * final_mask.width * final_mask.height; i++) + make_int(&(op->value.refs[i+2]), final_mask.data[i]); + break; + case OUTPUT_RAW: + case OUTPUT_PS: /* Return a threshold array string first two bytes are width (high byte first), * next two bytes are height, followed by the threshold array (one byte per cell) * PostScript can easily form a Type 3 Halftone Thresholds string from this * using "getinterval". */ - { - /* Make a threshold array from the turn_on_sequence */ - int level; - int cur_pix = 0; - double end_value, cur_value = 0.0; - int width = final_mask.width; - int num_pix = width * final_mask.height; - double delta_value = 1.0 / (double)(num_pix); - byte *thresh = ialloc_string(4 + num_pix, "gen_ordered"); - ref rval, thresh_ref; - - if (thresh == 0) { - code = gs_error_VMerror; - goto done; - } - - *thresh++ = width >> 8; - *thresh++ = width & 0xff; - *thresh++ = final_mask.height >> 8; - *thresh++ = final_mask.height & 0xff; - - /* The following is adapted from thresh_remap with the default linear map */ - for (level=0; level<256; level++) { - end_value = (float)(1+level) / 256.; - if (end_value > 256.0) - end_value = 256.0; /* clamp in case of rounding errors */ - while (end_value - cur_value > 0.00001) { - thresh[final_mask.data[2*cur_pix] + (width*final_mask.data[2*cur_pix+1])] = 255 - level; - cur_pix++; + { + /* Make a threshold array from the turn_on_sequence */ + int level; + int cur_pix = 0; + double end_value, cur_value = 0.0; + int width = final_mask.width; + int num_pix = width * final_mask.height; + double delta_value = 1.0 / (double)(num_pix); + byte *thresh; + ref rval, thresh_ref; + + code = gs_error_VMerror; /* in case allocation of thresh fails */ + if (output_type == OUTPUT_RAW) { + if ((thresh = ialloc_string(4 + num_pix, "gen_ordered")) == 0) + goto done; + *thresh++ = width >> 8; + *thresh++ = width & 0xff; + *thresh++ = final_mask.height >> 8; + *thresh++ = final_mask.height & 0xff; + } else if ((thresh = ialloc_string(num_pix, "gen_ordered")) == 0) + goto done; + /* The following is adapted from thresh_remap with the default linear map */ + for (level=0; level<256; level++) { + end_value = (float)(1+level) / 256.; + if (end_value > 256.0) + end_value = 256.0; /* clamp in case of rounding errors */ + while (end_value - cur_value > 0.00001) { + thresh[final_mask.data[2*cur_pix] + (width*final_mask.data[2*cur_pix+1])] = 255 - level; + cur_pix++; + if (cur_pix >= num_pix) + break; + cur_value += delta_value; + } if (cur_pix >= num_pix) break; - cur_value += delta_value; } - if (cur_pix >= num_pix) - break; - } - /* now fill any remaining cells */ - for (; cur_pix < num_pix; cur_pix++) { - thresh[final_mask.data[2 * cur_pix] + (width*final_mask.data[2 * cur_pix + 1])] = 0; + /* now fill any remaining cells */ + for (; cur_pix < num_pix; cur_pix++) { + thresh[final_mask.data[2 * cur_pix] + (width*final_mask.data[2 * cur_pix + 1])] = 0; + } + if (output_type == OUTPUT_RAW) { + make_string(&thresh_ref, a_all | icurrent_space, 4 + num_pix, thresh-4); + *op = thresh_ref; + code = 0; + } else { + /* output_type == OUTPUT_PS */ + /* Return a HalftoneType 3 dictionary */ + code = dict_create(4, op); + if (code < 0) + goto done; + make_string(&thresh_ref, a_all | icurrent_space, num_pix, thresh); + if ((code = idict_put_string(op, "Thresholds", &thresh_ref)) < 0) + goto done; + make_int(&rval, final_mask.width); + if ((code = idict_put_string(op, "Width", &rval)) < 0) + goto done; + make_int(&rval, final_mask.height); + if ((code = idict_put_string(op, "Height", &rval)) < 0) + goto done; + make_int(&rval, 3); + if ((code = idict_put_string(op, "HalftoneType", &rval)) < 0) + goto done; + } } - make_string(&thresh_ref, a_all | icurrent_space, 4 + num_pix, thresh); -# ifdef RETURN_THRESH_STRING - op = thresh_ref; -# else /* The current default, and probably the most useful for PS users */ - /* Return a HalftoneType 3 dictionary */ - code = dict_create(4, op); - if (code < 0) - goto done; - if ((code = idict_put_string(op, "Thresholds", &thresh_ref)) < 0) - goto done; - make_int(&rval, final_mask.width); - if ((code = idict_put_string(op, "Width", &rval)) < 0) - goto done; - make_int(&rval, final_mask.height); - if ((code = idict_put_string(op, "Height", &rval)) < 0) - goto done; - make_int(&rval, 3); - if ((code = idict_put_string(op, "HalftoneType", &rval)) < 0) - goto done; -# endif /* RETURN_THRESH_STRING */ + break; + default: + return gs_error_undefined; } -#endif /* RETURN_TOS_ARRAY */ done: if (final_mask.data != NULL) @@ -556,7 +583,7 @@ const op_def zht2_l2_op_defs[] = { op_def_begin_level2(), {"2.sethalftone5", zsethalftone5}, - {"1.genordered", zgen_ordered}, + {"1.genordered", zgenordered}, /* Internal operators */ {"0%sethalftone_finish", sethalftone_finish}, op_def_end(0) diff --git a/toolbin/halftone/gen_ordered/gen_ordered_example.ps b/toolbin/halftone/gen_ordered/gen_ordered_example.ps index 13f3cb949..b17130bbd 100644 --- a/toolbin/halftone/gen_ordered/gen_ordered_example.ps +++ b/toolbin/halftone/gen_ordered/gen_ordered_example.ps @@ -20,12 +20,21 @@ mark % for .dicttomark { pop DITHERANGLE } { currentscreen pop exch pop } ifelse + /SuperCellSize /DITHERSC where + { pop DITHERSC } + { pop } + ifelse + /Levels /DITHERLEVELS where + { pop DITHERLEVELS } + { pop } + ifelse /DotShape 8 .dicttomark .genordered % Now set it as the default -/Default exch /Halftone defineresource sethalftone +/Default exch /Halftone defineresource +sethalftone % The following are used to make sure that 0.5 yeilds 50% black and that % a shaded (gradient) ramp has 255 steps (even if the halftone doesn't |