xref: /plan9/sys/src/cmd/gs/src/gsht1.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /*$Id: gsht1.c,v 1.15 2004/08/04 19:36:12 stefan Exp $ */
18 /* Extended halftone operators for Ghostscript library */
19 #include "memory_.h"
20 #include "string_.h"
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsstruct.h"
24 #include "gsutil.h"		/* for gs_next_ids */
25 #include "gzstate.h"
26 #include "gxdevice.h"		/* for gzht.h */
27 #include "gzht.h"
28 
29 #include "gxwts.h"
30 #include "gswts.h"
31 
32 /* Imports from gscolor.c */
33 void load_transfer_map(gs_state *, gx_transfer_map *, floatp);
34 
35 /* Forward declarations */
36 private int process_spot(gx_ht_order *, gs_state *,
37 			 gs_spot_halftone *, gs_memory_t *);
38 private int process_threshold(gx_ht_order *, gs_state *,
39 			      gs_threshold_halftone *, gs_memory_t *);
40 private int process_threshold2(gx_ht_order *, gs_state *,
41 			       gs_threshold2_halftone *, gs_memory_t *);
42 private int process_client_order(gx_ht_order *, gs_state *,
43 				 gs_client_order_halftone *, gs_memory_t *);
44 private int
45 gs_sethalftone_try_wts(gs_halftone *pht, gs_state *pgs,
46 		       gx_device_halftone *pdht);
47 
48 /* Structure types */
49 public_st_halftone_component();
50 public_st_ht_component_element();
51 
52 /* GC procedures */
53 
54 private
55 ENUM_PTRS_WITH(halftone_component_enum_ptrs, gs_halftone_component *hptr) return 0;
56 case 0:
57 switch (hptr->type)
58 {
59     case ht_type_spot:
60 ENUM_RETURN((hptr->params.spot.transfer == 0 ?
61 	     hptr->params.spot.transfer_closure.data :
62 	     0));
63     case ht_type_threshold:
64 ENUM_RETURN_CONST_STRING_PTR(gs_halftone_component,
65 			     params.threshold.thresholds);
66     case ht_type_threshold2:
67 return ENUM_CONST_BYTESTRING(&hptr->params.threshold2.thresholds);
68     case ht_type_client_order:
69 ENUM_RETURN(hptr->params.client_order.client_data);
70     default:			/* not possible */
71 return 0;
72 }
73 case 1:
74 switch (hptr->type) {
75     case ht_type_threshold:
76 	ENUM_RETURN((hptr->params.threshold.transfer == 0 ?
77 		     hptr->params.threshold.transfer_closure.data :
78 		     0));
79     case ht_type_threshold2:
80 	ENUM_RETURN(hptr->params.threshold2.transfer_closure.data);
81     case ht_type_client_order:
82 	ENUM_RETURN(hptr->params.client_order.transfer_closure.data);
83     default:
84 	return 0;
85 }
86 ENUM_PTRS_END
RELOC_PTRS_WITH(halftone_component_reloc_ptrs,gs_halftone_component * hptr)87 private RELOC_PTRS_WITH(halftone_component_reloc_ptrs, gs_halftone_component *hptr)
88 {
89     switch (hptr->type) {
90 	case ht_type_spot:
91 	    if (hptr->params.spot.transfer == 0)
92 		RELOC_VAR(hptr->params.spot.transfer_closure.data);
93 	    break;
94 	case ht_type_threshold:
95 	    RELOC_CONST_STRING_VAR(hptr->params.threshold.thresholds);
96 	    if (hptr->params.threshold.transfer == 0)
97 		RELOC_VAR(hptr->params.threshold.transfer_closure.data);
98 	    break;
99 	case ht_type_threshold2:
100 	    RELOC_CONST_BYTESTRING_VAR(hptr->params.threshold2.thresholds);
101 	    RELOC_OBJ_VAR(hptr->params.threshold2.transfer_closure.data);
102 	    break;
103 	case ht_type_client_order:
104 	    RELOC_VAR(hptr->params.client_order.client_data);
105 	    RELOC_VAR(hptr->params.client_order.transfer_closure.data);
106 	    break;
107 	default:
108 	    break;
109     }
110 }
111 RELOC_PTRS_END
112 
113 /* setcolorscreen */
114 int
gs_setcolorscreen(gs_state * pgs,gs_colorscreen_halftone * pht)115 gs_setcolorscreen(gs_state * pgs, gs_colorscreen_halftone * pht)
116 {
117     gs_halftone ht;
118 
119     ht.type = ht_type_colorscreen;
120     ht.params.colorscreen = *pht;
121     return gs_sethalftone(pgs, &ht);
122 }
123 
124 /* currentcolorscreen */
125 int
gs_currentcolorscreen(gs_state * pgs,gs_colorscreen_halftone * pht)126 gs_currentcolorscreen(gs_state * pgs, gs_colorscreen_halftone * pht)
127 {
128     int code;
129 
130     switch (pgs->halftone->type) {
131 	case ht_type_colorscreen:
132 	    *pht = pgs->halftone->params.colorscreen;
133 	    return 0;
134 	default:
135 	    code = gs_currentscreen(pgs, &pht->screens.colored.gray);
136 	    if (code < 0)
137 		return code;
138 	    pht->screens.colored.red = pht->screens.colored.gray;
139 	    pht->screens.colored.green = pht->screens.colored.gray;
140 	    pht->screens.colored.blue = pht->screens.colored.gray;
141 	    return 0;
142     }
143 }
144 
145 /* Set the halftone in the graphics state. */
146 int
gs_sethalftone(gs_state * pgs,gs_halftone * pht)147 gs_sethalftone(gs_state * pgs, gs_halftone * pht)
148 {
149     gs_halftone ht;
150 
151     ht = *pht;
152     ht.rc.memory = pgs->memory;
153     return gs_sethalftone_allocated(pgs, &ht);
154 }
155 int
gs_sethalftone_allocated(gs_state * pgs,gs_halftone * pht)156 gs_sethalftone_allocated(gs_state * pgs, gs_halftone * pht)
157 {
158     gx_device_halftone dev_ht;
159     int code = gs_sethalftone_prepare(pgs, pht, &dev_ht);
160 
161     if (code < 0)
162 	return code;
163     dev_ht.rc.memory = pht->rc.memory;
164     if ((code = gx_ht_install(pgs, pht, &dev_ht)) < 0)
165         gx_device_halftone_release(&dev_ht, pht->rc.memory);
166     return code;
167 }
168 
169 /* Prepare the halftone, but don't install it. */
170 int
gs_sethalftone_prepare(gs_state * pgs,gs_halftone * pht,gx_device_halftone * pdht)171 gs_sethalftone_prepare(gs_state * pgs, gs_halftone * pht,
172 		       gx_device_halftone * pdht)
173 {
174     gs_memory_t *mem = pht->rc.memory;
175     gx_ht_order_component *pocs = 0;
176     int code = 0;
177 
178     if (gs_currentusewts() && gs_sethalftone_try_wts(pht, pgs, pdht) == 0)
179 	return 0;
180 
181     switch (pht->type) {
182 	case ht_type_colorscreen:
183 	    {
184 		gs_screen_halftone *phc =
185 		    pht->params.colorscreen.screens.indexed;
186 		static const int cindex[4] = {3, 0, 1, 2};
187 		static const char * color_names[4] = {"Gray", "Red", "Green", "Blue"};
188 		int i;
189 
190 		pocs = gs_alloc_struct_array(mem, 4,
191 					     gx_ht_order_component,
192 					     &st_ht_order_component_element,
193 					     "gs_sethalftone");
194 		if (pocs == 0)
195 		    return_error(gs_error_VMerror);
196 		for (i = 0; i < 4; i++) {
197 		    gs_screen_enum senum;
198 		    int ci = cindex[i];
199 		    gx_ht_order_component *poc = &pocs[i];
200 
201 		    code = gx_ht_process_screen_memory(&senum, pgs,
202 				&phc[ci], gs_currentaccuratescreens(), mem);
203 		    if (code < 0)
204 			break;
205 		    poc->corder = senum.order;
206 		    poc->comp_number = gs_color_name_component_number(pgs->device,
207 				color_names[i], strlen(color_names[i]), pht->type);
208 		    poc->cname = 0;  /* name index values are not known (or needed) */
209 		    if (i == 0)	/* Gray = Default */
210 			pdht->order = poc->corder;	/* Save default value */
211 		}
212 		if (code < 0)
213 		    break;
214 		pdht->components = pocs;
215 		pdht->num_comp = 4;
216 	    }
217 	    break;
218 	case ht_type_spot:
219 	    code = process_spot(&pdht->order, pgs, &pht->params.spot, mem);
220 	    if (code < 0)
221 		return code;
222 	    pdht->components = 0;
223 	    break;
224 	case ht_type_threshold:
225 	    code = process_threshold(&pdht->order, pgs,
226 				     &pht->params.threshold, mem);
227 	    if (code < 0)
228 		return code;
229 	    pdht->components = 0;
230 	    break;
231 	case ht_type_threshold2:
232 	    code = process_threshold2(&pdht->order, pgs,
233 				      &pht->params.threshold2, mem);
234 	    if (code < 0)
235 		return code;
236 	    pdht->components = 0;
237 	    break;
238 	case ht_type_client_order:
239 	    code = process_client_order(&pdht->order, pgs,
240 					&pht->params.client_order, mem);
241 	    if (code < 0)
242 		return code;
243 	    pdht->components = 0;
244 	    break;
245 	case ht_type_multiple:
246 	case ht_type_multiple_colorscreen:
247 	    {
248 		uint count = pht->params.multiple.num_comp;
249 		bool have_Default = false;
250 		uint i;
251 		gs_halftone_component *phc = pht->params.multiple.components;
252 		gx_ht_order_component *poc_next;
253 
254 		pocs = gs_alloc_struct_array(mem, count,
255 					     gx_ht_order_component,
256 					     &st_ht_order_component_element,
257 					     "gs_sethalftone");
258 		if (pocs == 0)
259 		    return_error(gs_error_VMerror);
260 		poc_next = pocs + 1;
261 		for (i = 0; i < count; i++, phc++) {
262 		    gx_ht_order_component *poc = poc_next;
263 
264 		    if (phc->comp_number == GX_DEVICE_COLOR_MAX_COMPONENTS) {
265 			if (have_Default) {
266 			    /* Duplicate Default */
267 			    code = gs_note_error(gs_error_rangecheck);
268 			    break;
269 			}
270 			poc = pocs;
271 			have_Default = true;
272 		    } else if (i == count - 1 && !have_Default) {
273 			/* No Default */
274 			code = gs_note_error(gs_error_rangecheck);
275 			break;
276 		    } else
277 			poc = poc_next++;
278 
279 		    poc->comp_number = phc->comp_number;
280 		    poc->cname = phc->cname;
281 		    switch (phc->type) {
282 			case ht_type_spot:
283 			    code = process_spot(&poc->corder, pgs,
284 						&phc->params.spot, mem);
285 			    break;
286 			case ht_type_threshold:
287 			    code = process_threshold(&poc->corder, pgs,
288 						&phc->params.threshold, mem);
289 			    break;
290 			case ht_type_threshold2:
291 			    code = process_threshold2(&poc->corder, pgs,
292 						&phc->params.threshold2, mem);
293 			    break;
294 			case ht_type_client_order:
295 			    code = process_client_order(&poc->corder, pgs,
296 					    &phc->params.client_order, mem);
297 			    break;
298 			default:
299 			    code = gs_note_error(gs_error_rangecheck);
300 			    break;
301 		    }
302 		    if (code < 0)
303 			break;
304 		}
305 		if (code < 0)
306 		    break;
307 		pdht->order = pocs[0].corder;	/* Default */
308 		if (count == 1) {
309 		    /* We have only a Default; */
310 		    /* we don't need components. */
311 		    gs_free_object(mem, pocs, "gs_sethalftone");
312 		    pdht->components = 0;
313 		    pdht->num_comp = 0;
314 		} else {
315 		    pdht->components = pocs;
316 		    pdht->num_comp = count;
317 		}
318 	    }
319 	    break;
320 	default:
321 	    return_error(gs_error_rangecheck);
322     }
323     if (code < 0)
324 	gs_free_object(mem, pocs, "gs_sethalftone");
325     return code;
326 }
327 
328 /* ------ Internal routines ------ */
329 
330 /* Process a transfer function override, if any. */
331 private int
process_transfer(gx_ht_order * porder,gs_state * pgs,gs_mapping_proc proc,gs_mapping_closure_t * pmc,gs_memory_t * mem)332 process_transfer(gx_ht_order * porder, gs_state * pgs,
333 		 gs_mapping_proc proc, gs_mapping_closure_t * pmc,
334 		 gs_memory_t * mem)
335 {
336     gx_transfer_map *pmap;
337 
338     if (proc == 0 && pmc->proc == 0)
339 	return 0;
340     /*
341      * The transfer funtion is referenced by the order, so start the
342      * reference count at 1.
343      */
344     rc_alloc_struct_1(pmap, gx_transfer_map, &st_transfer_map, mem,
345 		      return_error(gs_error_VMerror),
346 		      "process_transfer");
347     pmap->proc = proc;		/* 0 => use closure */
348     pmap->closure = *pmc;
349     pmap->id = gs_next_ids(mem, 1);
350     load_transfer_map(pgs, pmap, 0.0);
351     porder->transfer = pmap;
352     return 0;
353 }
354 
355 /* Process a spot plane. */
356 private int
process_spot(gx_ht_order * porder,gs_state * pgs,gs_spot_halftone * phsp,gs_memory_t * mem)357 process_spot(gx_ht_order * porder, gs_state * pgs,
358 	     gs_spot_halftone * phsp, gs_memory_t * mem)
359 {
360     gs_screen_enum senum;
361 
362     int code = gx_ht_process_screen_memory(&senum, pgs, &phsp->screen,
363 					   phsp->accurate_screens, mem);
364 
365     if (code < 0)
366 	return code;
367     *porder = senum.order;
368     return process_transfer(porder, pgs, phsp->transfer,
369 			    &phsp->transfer_closure, mem);
370 }
371 
372 /* Construct the halftone order from a threshold array. */
373 void
gx_ht_complete_threshold_order(gx_ht_order * porder)374 gx_ht_complete_threshold_order(gx_ht_order * porder)
375 {
376     int num_levels = porder->num_levels;
377     uint *levels = porder->levels;
378     uint size = porder->num_bits;
379     gx_ht_bit *bits = porder->bit_data;
380     uint i, j;
381 
382     /* The caller has set bits[i] = max(1, thresholds[i]). */
383     gx_sort_ht_order(bits, size);
384     /* We want to set levels[j] to the lowest value of i */
385     /* such that bits[i].mask > j. */
386     for (i = 0, j = 0; i < size; i++) {
387 	if (bits[i].mask != j) {
388 	    if_debug3('h', "[h]levels[%u..%u] = %u\n",
389 		      j, (uint) bits[i].mask, i);
390 	    while (j < bits[i].mask)
391 		levels[j++] = i;
392 	}
393     }
394     while (j < num_levels)
395 	levels[j++] = size;
396     gx_ht_construct_bits(porder);
397 }
398 int
gx_ht_construct_threshold_order(gx_ht_order * porder,const byte * thresholds)399 gx_ht_construct_threshold_order(gx_ht_order * porder, const byte * thresholds)
400 {
401     return porder->procs->construct_order(porder, thresholds);
402 }
403 
404 /* Process a threshold plane. */
405 private int
process_threshold(gx_ht_order * porder,gs_state * pgs,gs_threshold_halftone * phtp,gs_memory_t * mem)406 process_threshold(gx_ht_order * porder, gs_state * pgs,
407 		  gs_threshold_halftone * phtp, gs_memory_t * mem)
408 {
409     int code;
410 
411     porder->params.M = phtp->width, porder->params.N = 0;
412     porder->params.R = 1;
413     porder->params.M1 = phtp->height, porder->params.N1 = 0;
414     porder->params.R1 = 1;
415     code = gx_ht_alloc_threshold_order(porder, phtp->width, phtp->height,
416 				       256, mem);
417     if (code < 0)
418 	return code;
419     gx_ht_construct_threshold_order(porder, phtp->thresholds.data);
420     return process_transfer(porder, pgs, phtp->transfer,
421 			    &phtp->transfer_closure, mem);
422 }
423 
424 /* Process an extended threshold plane. */
425 private int
process_threshold2(gx_ht_order * porder,gs_state * pgs,gs_threshold2_halftone * phtp,gs_memory_t * mem)426 process_threshold2(gx_ht_order * porder, gs_state * pgs,
427 		   gs_threshold2_halftone * phtp, gs_memory_t * mem)
428 {
429     int code;
430     /*
431      * There are potentially 64K different levels for this plane, but this
432      * is more than we're willing to handle.  Try to reduce the number of
433      * levels by dropping leading or trailing zero bits from the thresholds;
434      * as a last resort, drop (possibly significant) trailing bits.
435      */
436 #define LOG2_MAX_HT_LEVELS 14
437 #define MAX_HT_LEVELS (1 << LOG2_MAX_HT_LEVELS)
438     int bps = phtp->bytes_per_sample;
439     const byte *data = phtp->thresholds.data;
440     const int w1 = phtp->width, h1 = phtp->height, size1 = w1 * h1;
441     const int w2 = phtp->width2, h2 = phtp->height2, size2 = w2 * h2;
442     const uint size = size1 + size2;
443     const int d = (h2 == 0 ? h1 : igcd(h1, h2));
444     const int sod = size / d;
445     uint num_levels;
446     uint i;
447     int rshift = 0;
448     int shift;
449 
450     {
451 	uint mask = 0, max_thr = 0;
452 
453 	for (i = 0; i < size; ++i) {
454 	    uint thr =
455 		(bps == 1 ? data[i] : (data[i * 2] << 8) + data[i * 2 + 1]);
456 
457 	    mask |= thr;
458 	    max_thr = max(max_thr, thr);
459 	}
460 	if (mask == 0)
461 	    mask = 1, max_thr = 1;
462 	while (!(mask & 1) || max_thr > MAX_HT_LEVELS)
463 	    mask >>= 1, max_thr >>= 1, rshift++;
464 	num_levels = max_thr + 1;
465     }
466     /*
467      * Set nominal values for the params, and don't bother to call
468      * gx_compute_cell_values -- the values are only needed for spot
469      * halftones.
470      */
471     porder->params.M = sod, porder->params.N = d;
472     porder->params.R = 1;
473     porder->params.M1 = d, porder->params.N1 = sod;
474     porder->params.R1 = 1;
475     /*
476      * Determine the shift between strips.  We don't know a closed formula
477      * for this, so we do it by enumeration.
478      */
479     shift = 0;
480     {
481 	int x = 0, y = 0;
482 
483 	do {
484 	    if (y < h1)
485 		x += w1, y += h2;
486 	    else
487 		x += w2, y -= h1;
488 	} while (y > d);
489 	if (y)
490 	    shift = x;
491     }
492     code = gx_ht_alloc_ht_order(porder, sod, d, num_levels, size, shift,
493 				&ht_order_procs_default, mem);
494     if (code < 0)
495 	return code;
496     {
497 	gx_ht_bit *bits = (gx_ht_bit *)porder->bit_data;
498 	int row, di;
499 
500 	if_debug7('h', "[h]rect1=(%d,%d), rect2=(%d,%d), strip=(%d,%d), shift=%d\n",
501 		  w1, h1, w2, h2, sod, d, shift);
502 	for (row = 0, di = 0; row < d; ++row) {
503 	    /* Iterate over destination rows. */
504 	    int dx, sy = row;	/* sy = row mod d */
505 	    int w;
506 
507 	    for (dx = 0; dx < sod; dx += w) {
508 		/* Iterate within a destination row, over source rows. */
509 		int si, j;
510 
511 		if (sy < h1) {
512 		    /* Copy a row from rect1. */
513 		    si = sy * w1;
514 		    w = w1;
515 		    sy += h2;
516 		} else {
517 		    /* Copy a row from rect2. */
518 		    si = size1 + (sy - h1) * w2;
519 		    w = w2;
520 		    sy -= h1;
521 		}
522 		for (j = 0; j < w; ++j, ++si, ++di) {
523 		    uint thr =
524 			(bps == 1 ? data[si] :
525 			 (data[si * 2] << 8) + data[si * 2 + 1])
526 				       >> rshift;
527 
528 		    if_debug3('H', "[H]sy=%d, si=%d, di=%d\n", sy, si, di);
529 		    bits[di].mask = max(thr, 1);
530 		}
531 	    }
532 	}
533     }
534     gx_ht_complete_threshold_order(porder);
535     return process_transfer(porder, pgs, NULL, &phtp->transfer_closure, mem);
536 #undef LOG2_MAX_HT_LEVELS
537 #undef MAX_HT_LEVELS
538 }
539 
540 /* Process a client-order plane. */
541 private int
process_client_order(gx_ht_order * porder,gs_state * pgs,gs_client_order_halftone * phcop,gs_memory_t * mem)542 process_client_order(gx_ht_order * porder, gs_state * pgs,
543 		     gs_client_order_halftone * phcop, gs_memory_t * mem)
544 {
545     int code = (*phcop->procs->create_order) (porder, pgs, phcop, mem);
546 
547     if (code < 0)
548 	return code;
549     return process_transfer(porder, pgs, NULL,
550 			    &phcop->transfer_closure, mem);
551 }
552 
553 private const gx_ht_order_procs_t wts_order_procs = { 0
554 };
555 
556 /**
557  * gs_sethalftone_try_wts: Try creating a wts-based device halftone.
558  * @pht: Client halftone.
559  * @pdht: Device halftone to initialize.
560  *
561  * Tries initializing @pdht based on data from @pht, using WTS.
562  *
563  * Return value: 0 on success, 1 to indicate that the initialization
564  * was not done, and that the legacy initialization code path should
565  * be used.
566  **/
567 private int
gs_sethalftone_try_wts(gs_halftone * pht,gs_state * pgs,gx_device_halftone * pdht)568 gs_sethalftone_try_wts(gs_halftone *pht, gs_state *pgs,
569 		       gx_device_halftone *pdht)
570 {
571     gx_device *dev = pgs->device;
572     int num_comps = dev->color_info.num_components;
573     int depth = dev->color_info.depth;
574 
575     if (pht->type != ht_type_multiple)
576 	/* Only work with Type 5 halftones. todo: we probably want
577 	   to relax this. */
578 	return 1;
579 
580     if_debug2('h', "[h]%s, num_comp = %d\n",
581 	      dev->color_info.separable_and_linear == GX_CINFO_SEP_LIN ? "Separable and linear" : "Not separable and linear!",
582 	      pht->params.multiple.num_comp);
583 
584     if (dev->color_info.separable_and_linear != GX_CINFO_SEP_LIN &&
585 	pht->params.multiple.num_comp > 1)
586 	/* WTS is only enabled for separable or monochrome devices. */
587 	return 1;
588 
589     /* only work with bilevel (not multilevel) devices */
590     if (depth > num_comps) {
591         if (depth >= 2 * num_comps)
592 	    return 1;
593         if (dev->color_info.gray_index != GX_CINFO_COMP_NO_INDEX &&
594             (dev->color_info.max_gray > 1 ||
595 	    (num_comps > 1 && dev->color_info.max_color > 1)))
596             return 1;
597     }
598 
599     if (pht->type == ht_type_multiple) {
600 	gs_halftone_component *components = pht->params.multiple.components;
601 	uint num_comp = pht->params.multiple.num_comp;
602 	int i;
603 	gx_ht_order_component *pocs;
604 	gx_ht_order_component *poc_next;
605 	int code = 0;
606 	bool have_Default = false;
607 
608 	for (i = 0; i < num_comp; i++) {
609 	    if (components[i].type != ht_type_spot)
610 		return 1;
611 	    else {
612 		gs_spot_halftone *spot = &components[i].params.spot;
613 		if (!spot->accurate_screens)
614 		    return 1;
615 	    }
616 	}
617 
618 	pocs = gs_alloc_struct_array( pgs->memory,
619                                       num_comp,
620                                       gx_ht_order_component,
621                                       &st_ht_order_component_element,
622                                       "gs_sethalftone_try_wts" );
623 	/* pocs = malloc(num_comp * sizeof(gx_ht_order_component)); */
624 	poc_next = &pocs[1];
625 	for (i = 0; i < num_comp; i++) {
626 	    gs_halftone_component *component = &components[i];
627 	    gs_spot_halftone *spot = &component->params.spot;
628 	    gs_screen_halftone *h = &spot->screen;
629 	    gx_wts_cell_params_t *wcp;
630 	    gs_wts_screen_enum_t *wse;
631 	    gs_matrix imat;
632 	    gx_ht_order_component *poc;
633 
634 	    if (component->comp_number == GX_DEVICE_COLOR_MAX_COMPONENTS) {
635 		if (have_Default) {
636 		    /* Duplicate Default */
637 		    code = gs_note_error(gs_error_rangecheck);
638 		    break;
639 		}
640 		poc = pocs;
641 		have_Default = true;
642 	    } else if (i == num_comp - 1 && !have_Default) {
643 		/* No Default */
644 		code = gs_note_error(gs_error_rangecheck);
645 		break;
646 	    } else
647 		poc = poc_next++;
648 
649 	    gs_deviceinitialmatrix(gs_currentdevice(pgs), &imat);
650 
651 	    wcp = wts_pick_cell_size(h, &imat);
652 	    wse = gs_wts_screen_enum_new(wcp);
653 
654 	    poc->corder.wse = wse;
655 	    poc->corder.wts = NULL;
656 	    poc->corder.procs = &wts_order_procs;
657 	    poc->corder.data_memory = NULL;
658 	    poc->corder.num_levels = 0;
659 	    poc->corder.num_bits = 0;
660 	    poc->corder.levels = NULL;
661 	    poc->corder.bit_data = NULL;
662 	    poc->corder.cache = NULL;
663 	    poc->corder.transfer = NULL;
664 	    poc->comp_number = component->comp_number;
665 	    poc->cname = component->cname;
666 	    code = process_transfer( &poc->corder,
667                                      pgs,
668                                      spot->transfer,
669                                      &spot->transfer_closure,
670                                      pgs->memory );
671 	    if (code < 0)
672 		break;
673 	}
674 	/* todo: cleanup on error */
675 	pdht->components = pocs;
676 	pdht->num_comp = num_comp;
677 	return code;
678     }
679     return 1;
680 }
681