summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--base/gen_ordered.c59
-rw-r--r--doc/Language.htm13
-rw-r--r--psi/int.mak2
-rw-r--r--psi/zht2.c167
-rw-r--r--toolbin/halftone/gen_ordered/gen_ordered_example.ps11
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>&lt;dict&gt; .genordered &lt;dict&gt;</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>&lt;dict&gt; .genordered &lt;dict&gt;</code> (default: /OutputType /Type3).</dt>
+<dt><code>&lt;dict&gt; .genordered &lt;string&gt;</code> (/OutputType /ThreshString).</dt>
+<dt><code>&lt;dict&gt; .genordered &lt;array&gt;</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>&lt;dict&gt;</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, &params.targ_scr_ang)) < 0)
return gs_error_undefined;
if ((code = dict_int_param(op, "Frequency", 1, 0x7fff, 75, &params.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