xref: /plan9-contrib/sys/src/cmd/gs/src/gshtx.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1998, 1999 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gshtx.c,v 1.6 2004/08/04 19:36:12 stefan Exp $ */
187dd7cddfSDavid du Colombier /* Stand-alone halftone/transfer function related code */
197dd7cddfSDavid du Colombier #include "memory_.h"
207dd7cddfSDavid du Colombier #include "gx.h"
217dd7cddfSDavid du Colombier #include "gserrors.h"
227dd7cddfSDavid du Colombier #include "gsstruct.h"
237dd7cddfSDavid du Colombier #include "gsutil.h"		/* for gs_next_ids */
247dd7cddfSDavid du Colombier #include "gxfmap.h"
257dd7cddfSDavid du Colombier #include "gzstate.h"
267dd7cddfSDavid du Colombier #include "gzht.h"
277dd7cddfSDavid du Colombier #include "gshtx.h"		/* must come after g*ht.h */
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier /*
307dd7cddfSDavid du Colombier  * Procedure to free the set of components when a halftone is released.
317dd7cddfSDavid du Colombier  */
327dd7cddfSDavid du Colombier private void
free_comps(gs_memory_t * pmem,void * pvht,client_name_t cname)337dd7cddfSDavid du Colombier free_comps(
347dd7cddfSDavid du Colombier 	      gs_memory_t * pmem,
357dd7cddfSDavid du Colombier 	      void *pvht,
367dd7cddfSDavid du Colombier 	      client_name_t cname
377dd7cddfSDavid du Colombier )
387dd7cddfSDavid du Colombier {
397dd7cddfSDavid du Colombier     gs_ht *pht = (gs_ht *) pvht;
407dd7cddfSDavid du Colombier 
417dd7cddfSDavid du Colombier     gs_free_object(pmem, pht->params.ht_multiple.components, cname);
427dd7cddfSDavid du Colombier     gs_free_object(pmem, pvht, cname);
437dd7cddfSDavid du Colombier }
447dd7cddfSDavid du Colombier 
457dd7cddfSDavid du Colombier /*
467dd7cddfSDavid du Colombier  * Stub transfer function, to be applied to components that are not provided
477dd7cddfSDavid du Colombier  * with a transfer function.
487dd7cddfSDavid du Colombier  */
497dd7cddfSDavid du Colombier private float
null_closure_transfer(floatp val,const gx_transfer_map * pmap_dummy,const void * dummy)507dd7cddfSDavid du Colombier null_closure_transfer(
517dd7cddfSDavid du Colombier 			 floatp val,
527dd7cddfSDavid du Colombier 			 const gx_transfer_map * pmap_dummy,	/* NOTUSED */
537dd7cddfSDavid du Colombier 			 const void *dummy	/* NOTUSED */
547dd7cddfSDavid du Colombier )
557dd7cddfSDavid du Colombier {
567dd7cddfSDavid du Colombier     return val;
577dd7cddfSDavid du Colombier }
587dd7cddfSDavid du Colombier 
597dd7cddfSDavid du Colombier 
607dd7cddfSDavid du Colombier /*
617dd7cddfSDavid du Colombier  * Build a gs_ht halftone structure.
627dd7cddfSDavid du Colombier  */
637dd7cddfSDavid du Colombier int
gs_ht_build(gs_ht ** ppht,uint num_comps,gs_memory_t * pmem)647dd7cddfSDavid du Colombier gs_ht_build(
657dd7cddfSDavid du Colombier 	       gs_ht ** ppht,
667dd7cddfSDavid du Colombier 	       uint num_comps,
677dd7cddfSDavid du Colombier 	       gs_memory_t * pmem
687dd7cddfSDavid du Colombier )
697dd7cddfSDavid du Colombier {
707dd7cddfSDavid du Colombier     gs_ht *pht;
717dd7cddfSDavid du Colombier     gs_ht_component *phtc;
727dd7cddfSDavid du Colombier     int i;
737dd7cddfSDavid du Colombier 
747dd7cddfSDavid du Colombier     /* must have at least one component */
757dd7cddfSDavid du Colombier     *ppht = 0;
767dd7cddfSDavid du Colombier     if (num_comps == 0)
777dd7cddfSDavid du Colombier 	return_error(gs_error_rangecheck);
787dd7cddfSDavid du Colombier 
797dd7cddfSDavid du Colombier     /* allocate the halftone and the array of components */
807dd7cddfSDavid du Colombier     rc_alloc_struct_1(pht,
817dd7cddfSDavid du Colombier 		      gs_ht,
827dd7cddfSDavid du Colombier 		      &st_gs_ht,
837dd7cddfSDavid du Colombier 		      pmem,
847dd7cddfSDavid du Colombier 		      return_error(gs_error_VMerror),
857dd7cddfSDavid du Colombier 		      "gs_ht_build"
867dd7cddfSDavid du Colombier 	);
877dd7cddfSDavid du Colombier     phtc = gs_alloc_struct_array(pmem,
887dd7cddfSDavid du Colombier 				 num_comps,
897dd7cddfSDavid du Colombier 				 gs_ht_component,
907dd7cddfSDavid du Colombier 				 &st_ht_comp_element,
917dd7cddfSDavid du Colombier 				 "gs_ht_build"
927dd7cddfSDavid du Colombier 	);
937dd7cddfSDavid du Colombier     if (phtc == 0) {
947dd7cddfSDavid du Colombier 	gs_free_object(pmem, pht, "gs_ht_build");
957dd7cddfSDavid du Colombier 	return_error(gs_error_VMerror);
967dd7cddfSDavid du Colombier     }
977dd7cddfSDavid du Colombier     /* initialize the halftone */
987dd7cddfSDavid du Colombier     pht->type = ht_type_multiple;
997dd7cddfSDavid du Colombier     pht->rc.free = free_comps;
1007dd7cddfSDavid du Colombier     pht->params.ht_multiple.components = phtc;
1017dd7cddfSDavid du Colombier     pht->params.ht_multiple.num_comp = num_comps;
1027dd7cddfSDavid du Colombier 
1037dd7cddfSDavid du Colombier     for (i = 0; i < num_comps; i++) {
104*593dc095SDavid du Colombier         phtc[i].comp_number = i;
105*593dc095SDavid du Colombier 	phtc[i].cname = 0;
1067dd7cddfSDavid du Colombier 	phtc[i].type = ht_type_none;
1077dd7cddfSDavid du Colombier     }
1087dd7cddfSDavid du Colombier 
1097dd7cddfSDavid du Colombier     *ppht = pht;
1107dd7cddfSDavid du Colombier 
1117dd7cddfSDavid du Colombier     return 0;
1127dd7cddfSDavid du Colombier }
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier /*
1157dd7cddfSDavid du Colombier  * Set a spot-function halftone component in a gs_ht halftone.
1167dd7cddfSDavid du Colombier  */
1177dd7cddfSDavid du Colombier int
gs_ht_set_spot_comp(gs_ht * pht,int comp,floatp freq,floatp angle,float (* spot_func)(floatp,floatp),bool accurate,gs_ht_transfer_proc transfer,const void * client_data)1187dd7cddfSDavid du Colombier gs_ht_set_spot_comp(
1197dd7cddfSDavid du Colombier 		       gs_ht * pht,
1207dd7cddfSDavid du Colombier 		       int comp,
1217dd7cddfSDavid du Colombier 		       floatp freq,
1227dd7cddfSDavid du Colombier 		       floatp angle,
1237dd7cddfSDavid du Colombier 		       float (*spot_func) (floatp, floatp),
1247dd7cddfSDavid du Colombier 		       bool accurate,
1257dd7cddfSDavid du Colombier 		       gs_ht_transfer_proc transfer,
1267dd7cddfSDavid du Colombier 		       const void *client_data
1277dd7cddfSDavid du Colombier )
1287dd7cddfSDavid du Colombier {
1297dd7cddfSDavid du Colombier     gs_ht_component *phtc = &(pht->params.ht_multiple.components[comp]);
1307dd7cddfSDavid du Colombier 
1317dd7cddfSDavid du Colombier     if (comp >= pht->params.ht_multiple.num_comp)
1327dd7cddfSDavid du Colombier 	return_error(gs_error_rangecheck);
1337dd7cddfSDavid du Colombier     if (phtc->type != ht_type_none)
1347dd7cddfSDavid du Colombier 	return_error(gs_error_invalidaccess);
1357dd7cddfSDavid du Colombier 
1367dd7cddfSDavid du Colombier     phtc->type = ht_type_spot;
1377dd7cddfSDavid du Colombier     phtc->params.ht_spot.screen.frequency = freq;
1387dd7cddfSDavid du Colombier     phtc->params.ht_spot.screen.angle = angle;
1397dd7cddfSDavid du Colombier     phtc->params.ht_spot.screen.spot_function = spot_func;
1407dd7cddfSDavid du Colombier     phtc->params.ht_spot.accurate_screens = accurate;
1417dd7cddfSDavid du Colombier     phtc->params.ht_spot.transfer = gs_mapped_transfer;
1427dd7cddfSDavid du Colombier 
1437dd7cddfSDavid du Colombier     phtc->params.ht_spot.transfer_closure.proc =
1447dd7cddfSDavid du Colombier 	(transfer == 0 ? null_closure_transfer : transfer);
1457dd7cddfSDavid du Colombier     phtc->params.ht_spot.transfer_closure.data = client_data;
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier     return 0;
1487dd7cddfSDavid du Colombier }
1497dd7cddfSDavid du Colombier 
1507dd7cddfSDavid du Colombier /*
1517dd7cddfSDavid du Colombier  * Set a threshold halftone component in a gs_ht halftone. Note that the
1527dd7cddfSDavid du Colombier  * caller is responsible for releasing the threshold data.
1537dd7cddfSDavid du Colombier  */
1547dd7cddfSDavid du Colombier int
gs_ht_set_threshold_comp(gs_ht * pht,int comp,int width,int height,const gs_const_string * thresholds,gs_ht_transfer_proc transfer,const void * client_data)1557dd7cddfSDavid du Colombier gs_ht_set_threshold_comp(
1567dd7cddfSDavid du Colombier 			    gs_ht * pht,
1577dd7cddfSDavid du Colombier 			    int comp,
1587dd7cddfSDavid du Colombier 			    int width,
1597dd7cddfSDavid du Colombier 			    int height,
1607dd7cddfSDavid du Colombier 			    const gs_const_string * thresholds,
1617dd7cddfSDavid du Colombier 			    gs_ht_transfer_proc transfer,
1627dd7cddfSDavid du Colombier 			    const void *client_data
1637dd7cddfSDavid du Colombier )
1647dd7cddfSDavid du Colombier {
1657dd7cddfSDavid du Colombier     gs_ht_component *phtc = &(pht->params.ht_multiple.components[comp]);
1667dd7cddfSDavid du Colombier 
1677dd7cddfSDavid du Colombier     if (comp >= pht->params.ht_multiple.num_comp)
1687dd7cddfSDavid du Colombier 	return_error(gs_error_rangecheck);
1697dd7cddfSDavid du Colombier     if (phtc->type != ht_type_none)
1707dd7cddfSDavid du Colombier 	return_error(gs_error_invalidaccess);
1717dd7cddfSDavid du Colombier 
1727dd7cddfSDavid du Colombier     phtc->type = ht_type_threshold;
1737dd7cddfSDavid du Colombier     phtc->params.ht_threshold.width = width;
1747dd7cddfSDavid du Colombier     phtc->params.ht_threshold.height = height;
1757dd7cddfSDavid du Colombier     phtc->params.ht_threshold.thresholds = *thresholds;
1767dd7cddfSDavid du Colombier     phtc->params.ht_threshold.transfer = gs_mapped_transfer;
1777dd7cddfSDavid du Colombier 
1787dd7cddfSDavid du Colombier     phtc->params.ht_threshold.transfer_closure.proc =
1797dd7cddfSDavid du Colombier 	(transfer == 0 ? null_closure_transfer : transfer);
1807dd7cddfSDavid du Colombier     phtc->params.ht_threshold.transfer_closure.data = client_data;
1817dd7cddfSDavid du Colombier 
1827dd7cddfSDavid du Colombier     return 0;
1837dd7cddfSDavid du Colombier }
1847dd7cddfSDavid du Colombier 
1857dd7cddfSDavid du Colombier /*
1867dd7cddfSDavid du Colombier  * Increase the reference count of a gs_ht structure by 1.
1877dd7cddfSDavid du Colombier  */
1887dd7cddfSDavid du Colombier void
gs_ht_reference(gs_ht * pht)1897dd7cddfSDavid du Colombier gs_ht_reference(
1907dd7cddfSDavid du Colombier 		   gs_ht * pht
1917dd7cddfSDavid du Colombier )
1927dd7cddfSDavid du Colombier {
1937dd7cddfSDavid du Colombier     rc_increment(pht);
1947dd7cddfSDavid du Colombier }
1957dd7cddfSDavid du Colombier 
1967dd7cddfSDavid du Colombier /*
1977dd7cddfSDavid du Colombier  * Decrement the reference count of a gs_ht structure by 1. Free the
1987dd7cddfSDavid du Colombier  * structure if the reference count reaches 0.
1997dd7cddfSDavid du Colombier  */
2007dd7cddfSDavid du Colombier void
gs_ht_release(gs_ht * pht)2017dd7cddfSDavid du Colombier gs_ht_release(
2027dd7cddfSDavid du Colombier 		 gs_ht * pht
2037dd7cddfSDavid du Colombier )
2047dd7cddfSDavid du Colombier {
2057dd7cddfSDavid du Colombier     rc_decrement_only(pht, "gs_ht_release");
2067dd7cddfSDavid du Colombier }
2077dd7cddfSDavid du Colombier 
2087dd7cddfSDavid du Colombier 
2097dd7cddfSDavid du Colombier /*
2107dd7cddfSDavid du Colombier  *  Verify that a gs_ht halftone is legitimate.
2117dd7cddfSDavid du Colombier  */
2127dd7cddfSDavid du Colombier private int
check_ht(gs_ht * pht)2137dd7cddfSDavid du Colombier check_ht(
2147dd7cddfSDavid du Colombier 	    gs_ht * pht
2157dd7cddfSDavid du Colombier )
2167dd7cddfSDavid du Colombier {
2177dd7cddfSDavid du Colombier     int i;
2187dd7cddfSDavid du Colombier     int num_comps = pht->params.ht_multiple.num_comp;
2197dd7cddfSDavid du Colombier 
2207dd7cddfSDavid du Colombier     if (pht->type != ht_type_multiple)
2217dd7cddfSDavid du Colombier 	return_error(gs_error_unregistered);
2227dd7cddfSDavid du Colombier     for (i = 0; i < num_comps; i++) {
2237dd7cddfSDavid du Colombier 	gs_ht_component *phtc = &(pht->params.ht_multiple.components[i]);
2247dd7cddfSDavid du Colombier 	if ((phtc->type != ht_type_spot) && (phtc->type != ht_type_threshold))
2257dd7cddfSDavid du Colombier 	    return_error(gs_error_unregistered);
2267dd7cddfSDavid du Colombier     }
227*593dc095SDavid du Colombier     return 0;
2287dd7cddfSDavid du Colombier }
2297dd7cddfSDavid du Colombier 
2307dd7cddfSDavid du Colombier /*
2317dd7cddfSDavid du Colombier  *  Load a transfer map from a gs_ht_transfer_proc function.
2327dd7cddfSDavid du Colombier  */
2337dd7cddfSDavid du Colombier private void
build_transfer_map(gs_ht_component * phtc,gx_transfer_map * pmap)2347dd7cddfSDavid du Colombier build_transfer_map(
2357dd7cddfSDavid du Colombier 		      gs_ht_component * phtc,
2367dd7cddfSDavid du Colombier 		      gx_transfer_map * pmap
2377dd7cddfSDavid du Colombier )
2387dd7cddfSDavid du Colombier {
2397dd7cddfSDavid du Colombier     gs_ht_transfer_proc proc;
2407dd7cddfSDavid du Colombier     const void *client_info;
2417dd7cddfSDavid du Colombier     int i;
2427dd7cddfSDavid du Colombier     frac *values = pmap->values;
2437dd7cddfSDavid du Colombier 
2447dd7cddfSDavid du Colombier     if (phtc->type == ht_type_spot) {
2457dd7cddfSDavid du Colombier 	proc = phtc->params.ht_spot.transfer_closure.proc;
2467dd7cddfSDavid du Colombier 	client_info = phtc->params.ht_spot.transfer_closure.data;
2477dd7cddfSDavid du Colombier     } else {
2487dd7cddfSDavid du Colombier 	proc = phtc->params.ht_threshold.transfer_closure.proc;
2497dd7cddfSDavid du Colombier 	client_info = phtc->params.ht_threshold.transfer_closure.data;
2507dd7cddfSDavid du Colombier     }
2517dd7cddfSDavid du Colombier 
2527dd7cddfSDavid du Colombier     for (i = 0; i < transfer_map_size; i++) {
2537dd7cddfSDavid du Colombier 	float fval =
2547dd7cddfSDavid du Colombier 	    proc(i * (1 / (double)(transfer_map_size - 1)), pmap, client_info);
2557dd7cddfSDavid du Colombier 
2567dd7cddfSDavid du Colombier 	values[i] =
2577dd7cddfSDavid du Colombier 	    (fval <= 0.0 ? frac_0 : fval >= 1.0 ? frac_1 :
2587dd7cddfSDavid du Colombier 	     float2frac(fval));
2597dd7cddfSDavid du Colombier     }
2607dd7cddfSDavid du Colombier }
2617dd7cddfSDavid du Colombier 
2627dd7cddfSDavid du Colombier /*
2637dd7cddfSDavid du Colombier  *  Allocate the order and transfer maps required by a halftone, and perform
2647dd7cddfSDavid du Colombier  *  some elementary initialization. This will also build the component index
2657dd7cddfSDavid du Colombier  *  to order index map.
2667dd7cddfSDavid du Colombier  */
2677dd7cddfSDavid du Colombier private gx_ht_order_component *
alloc_ht_order(const gs_ht * pht,gs_memory_t * pmem,byte * comp2order)2687dd7cddfSDavid du Colombier alloc_ht_order(
2697dd7cddfSDavid du Colombier 		  const gs_ht * pht,
2707dd7cddfSDavid du Colombier 		  gs_memory_t * pmem,
2717dd7cddfSDavid du Colombier 		  byte * comp2order
2727dd7cddfSDavid du Colombier )
2737dd7cddfSDavid du Colombier {
2747dd7cddfSDavid du Colombier     int num_comps = pht->params.ht_multiple.num_comp;
2757dd7cddfSDavid du Colombier     gx_ht_order_component *pocs = gs_alloc_struct_array(
2767dd7cddfSDavid du Colombier 							   pmem,
2777dd7cddfSDavid du Colombier 					   pht->params.ht_multiple.num_comp,
2787dd7cddfSDavid du Colombier 						      gx_ht_order_component,
2797dd7cddfSDavid du Colombier 					     &st_ht_order_component_element,
2807dd7cddfSDavid du Colombier 							   "alloc_ht_order"
2817dd7cddfSDavid du Colombier     );
282*593dc095SDavid du Colombier     int inext = 0;
2837dd7cddfSDavid du Colombier     int i;
2847dd7cddfSDavid du Colombier 
2857dd7cddfSDavid du Colombier     if (pocs == 0)
2867dd7cddfSDavid du Colombier 	return 0;
2877dd7cddfSDavid du Colombier     pocs->corder.transfer = 0;
2887dd7cddfSDavid du Colombier 
2897dd7cddfSDavid du Colombier     for (i = 0; i < num_comps; i++) {
2907dd7cddfSDavid du Colombier 	gs_ht_component *phtc = &(pht->params.ht_multiple.components[i]);
2917dd7cddfSDavid du Colombier 	gx_transfer_map *pmap = gs_alloc_struct(pmem,
2927dd7cddfSDavid du Colombier 						gx_transfer_map,
2937dd7cddfSDavid du Colombier 						&st_transfer_map,
2947dd7cddfSDavid du Colombier 						"alloc_ht_order"
2957dd7cddfSDavid du Colombier 	);
2967dd7cddfSDavid du Colombier 
2977dd7cddfSDavid du Colombier 	if (pmap == 0) {
2987dd7cddfSDavid du Colombier 	    int j;
2997dd7cddfSDavid du Colombier 
3007dd7cddfSDavid du Colombier 	    for (j = 0; j < inext; j++)
3017dd7cddfSDavid du Colombier 		gs_free_object(pmem, pocs[j].corder.transfer, "alloc_ht_order");
3027dd7cddfSDavid du Colombier 	    gs_free_object(pmem, pocs, "alloc_ht_order");
3037dd7cddfSDavid du Colombier 	    return 0;
3047dd7cddfSDavid du Colombier 	}
3057dd7cddfSDavid du Colombier 	pmap->proc = gs_mapped_transfer;
306*593dc095SDavid du Colombier 	pmap->id = gs_next_ids(pmem, 1);
3077dd7cddfSDavid du Colombier 	pocs[inext].corder.levels = 0;
3087dd7cddfSDavid du Colombier 	pocs[inext].corder.bit_data = 0;
3097dd7cddfSDavid du Colombier 	pocs[inext].corder.cache = 0;
3107dd7cddfSDavid du Colombier 	pocs[inext].corder.transfer = pmap;
3117dd7cddfSDavid du Colombier 	pocs[inext].cname = phtc->cname;
312*593dc095SDavid du Colombier         pocs[inext].comp_number = phtc->comp_number;
3137dd7cddfSDavid du Colombier 	comp2order[i] = inext++;
3147dd7cddfSDavid du Colombier     }
3157dd7cddfSDavid du Colombier 
3167dd7cddfSDavid du Colombier     return pocs;
3177dd7cddfSDavid du Colombier }
3187dd7cddfSDavid du Colombier 
3197dd7cddfSDavid du Colombier /*
3207dd7cddfSDavid du Colombier  *  Build the halftone order for one component.
3217dd7cddfSDavid du Colombier  */
3227dd7cddfSDavid du Colombier private int
build_component(gs_ht_component * phtc,gx_ht_order * porder,gs_state * pgs,gs_memory_t * pmem)3237dd7cddfSDavid du Colombier build_component(
3247dd7cddfSDavid du Colombier 		   gs_ht_component * phtc,
3257dd7cddfSDavid du Colombier 		   gx_ht_order * porder,
3267dd7cddfSDavid du Colombier 		   gs_state * pgs,
3277dd7cddfSDavid du Colombier 		   gs_memory_t * pmem
3287dd7cddfSDavid du Colombier )
3297dd7cddfSDavid du Colombier {
3307dd7cddfSDavid du Colombier     if (phtc->type == ht_type_spot) {
3317dd7cddfSDavid du Colombier 	gs_screen_enum senum;
3327dd7cddfSDavid du Colombier 	int code;
3337dd7cddfSDavid du Colombier 
3347dd7cddfSDavid du Colombier 	code = gx_ht_process_screen_memory(&senum,
3357dd7cddfSDavid du Colombier 					   pgs,
3367dd7cddfSDavid du Colombier 					   &phtc->params.ht_spot.screen,
3377dd7cddfSDavid du Colombier 				      phtc->params.ht_spot.accurate_screens,
3387dd7cddfSDavid du Colombier 					   pmem
3397dd7cddfSDavid du Colombier 	    );
3407dd7cddfSDavid du Colombier 	if (code < 0)
3417dd7cddfSDavid du Colombier 	    return code;
3427dd7cddfSDavid du Colombier 
3437dd7cddfSDavid du Colombier 	/* avoid wiping out the transfer structure pointer */
3447dd7cddfSDavid du Colombier 	senum.order.transfer = porder->transfer;
3457dd7cddfSDavid du Colombier 	*porder = senum.order;
3467dd7cddfSDavid du Colombier 
3477dd7cddfSDavid du Colombier     } else {			/* ht_type_threshold */
3487dd7cddfSDavid du Colombier 	int code;
3497dd7cddfSDavid du Colombier 	gx_transfer_map *transfer = porder->transfer;
3507dd7cddfSDavid du Colombier 
3517dd7cddfSDavid du Colombier 	porder->params.M = phtc->params.ht_threshold.width;
3527dd7cddfSDavid du Colombier 	porder->params.N = 0;
3537dd7cddfSDavid du Colombier 	porder->params.R = 1;
3547dd7cddfSDavid du Colombier 	porder->params.M1 = phtc->params.ht_threshold.height;
3557dd7cddfSDavid du Colombier 	porder->params.N1 = 0;
3567dd7cddfSDavid du Colombier 	porder->params.R1 = 1;
3577dd7cddfSDavid du Colombier 	code = gx_ht_alloc_threshold_order(porder,
3587dd7cddfSDavid du Colombier 					   phtc->params.ht_threshold.width,
3597dd7cddfSDavid du Colombier 					   phtc->params.ht_threshold.height,
3607dd7cddfSDavid du Colombier 					   256,
3617dd7cddfSDavid du Colombier 					   pmem
3627dd7cddfSDavid du Colombier 	    );
3637dd7cddfSDavid du Colombier 	if (code < 0)
3647dd7cddfSDavid du Colombier 	    return code;
3657dd7cddfSDavid du Colombier 	gx_ht_construct_threshold_order(
3667dd7cddfSDavid du Colombier 				porder,
3677dd7cddfSDavid du Colombier 				phtc->params.ht_threshold.thresholds.data
3687dd7cddfSDavid du Colombier 	    );
3697dd7cddfSDavid du Colombier 	/*
3707dd7cddfSDavid du Colombier 	 * gx_ht_construct_threshold_order wipes out transfer map pointer,
3717dd7cddfSDavid du Colombier 	 * restore it here.
3727dd7cddfSDavid du Colombier 	 */
3737dd7cddfSDavid du Colombier 	porder->transfer = transfer;
3747dd7cddfSDavid du Colombier     }
3757dd7cddfSDavid du Colombier 
3767dd7cddfSDavid du Colombier     build_transfer_map(phtc, porder->transfer);
3777dd7cddfSDavid du Colombier     return 0;
3787dd7cddfSDavid du Colombier }
3797dd7cddfSDavid du Colombier 
3807dd7cddfSDavid du Colombier /*
3817dd7cddfSDavid du Colombier  * Free an order array and all elements it points to.
3827dd7cddfSDavid du Colombier  */
3837dd7cddfSDavid du Colombier private void
free_order_array(gx_ht_order_component * pocs,int num_comps,gs_memory_t * pmem)3847dd7cddfSDavid du Colombier free_order_array(
3857dd7cddfSDavid du Colombier 		    gx_ht_order_component * pocs,
3867dd7cddfSDavid du Colombier 		    int num_comps,
3877dd7cddfSDavid du Colombier 		    gs_memory_t * pmem
3887dd7cddfSDavid du Colombier )
3897dd7cddfSDavid du Colombier {
3907dd7cddfSDavid du Colombier     int i;
3917dd7cddfSDavid du Colombier 
3927dd7cddfSDavid du Colombier     for (i = 0; i < num_comps; i++)
3937dd7cddfSDavid du Colombier 	gx_ht_order_release(&(pocs[i].corder), pmem, true);
3947dd7cddfSDavid du Colombier     gs_free_object(pmem, pocs, "gs_ht_install");
3957dd7cddfSDavid du Colombier }
3967dd7cddfSDavid du Colombier 
3977dd7cddfSDavid du Colombier 
3987dd7cddfSDavid du Colombier /*
3997dd7cddfSDavid du Colombier  *  Install a gs_ht halftone as the current halftone in the graphic state.
4007dd7cddfSDavid du Colombier  */
4017dd7cddfSDavid du Colombier int
gs_ht_install(gs_state * pgs,gs_ht * pht)4027dd7cddfSDavid du Colombier gs_ht_install(
4037dd7cddfSDavid du Colombier 		 gs_state * pgs,
4047dd7cddfSDavid du Colombier 		 gs_ht * pht
4057dd7cddfSDavid du Colombier )
4067dd7cddfSDavid du Colombier {
4077dd7cddfSDavid du Colombier     int code = 0;
4087dd7cddfSDavid du Colombier     gs_memory_t *pmem = pht->rc.memory;
4097dd7cddfSDavid du Colombier     gx_device_halftone dev_ht;
4107dd7cddfSDavid du Colombier     gx_ht_order_component *pocs;
4117dd7cddfSDavid du Colombier     byte comp2order[32];	/* ample component to order map */
4127dd7cddfSDavid du Colombier     int num_comps = pht->params.ht_multiple.num_comp;
4137dd7cddfSDavid du Colombier     int i;
4147dd7cddfSDavid du Colombier 
4157dd7cddfSDavid du Colombier     /* perform so sanity checks (must have one default component) */
4167dd7cddfSDavid du Colombier     if ((code = check_ht(pht)) != 0)
4177dd7cddfSDavid du Colombier 	return code;
4187dd7cddfSDavid du Colombier 
4197dd7cddfSDavid du Colombier     /* allocate the halftone order structure and transfer maps */
4207dd7cddfSDavid du Colombier     if ((pocs = alloc_ht_order(pht, pmem, comp2order)) == 0)
4217dd7cddfSDavid du Colombier 	return_error(gs_error_VMerror);
4227dd7cddfSDavid du Colombier 
4237dd7cddfSDavid du Colombier     /* build all of the order for each component */
4247dd7cddfSDavid du Colombier     for (i = 0; i < num_comps; i++) {
4257dd7cddfSDavid du Colombier 	int j = comp2order[i];
4267dd7cddfSDavid du Colombier 
4277dd7cddfSDavid du Colombier 	code = build_component(&(pht->params.ht_multiple.components[i]),
4287dd7cddfSDavid du Colombier 			       &(pocs[j].corder),
4297dd7cddfSDavid du Colombier 			       pgs,
4307dd7cddfSDavid du Colombier 			       pmem
4317dd7cddfSDavid du Colombier 	    );
4327dd7cddfSDavid du Colombier 
4337dd7cddfSDavid du Colombier 	if ((code >= 0) && (j != 0)) {
4347dd7cddfSDavid du Colombier 	    gx_ht_cache *pcache;
4357dd7cddfSDavid du Colombier 
4367dd7cddfSDavid du Colombier 	    pcache = gx_ht_alloc_cache(pmem,
4377dd7cddfSDavid du Colombier 				       4,
4387dd7cddfSDavid du Colombier 				       pocs[j].corder.raster *
4397dd7cddfSDavid du Colombier 				       (pocs[j].corder.num_bits /
4407dd7cddfSDavid du Colombier 					pocs[j].corder.width) * 4
4417dd7cddfSDavid du Colombier 		);
4427dd7cddfSDavid du Colombier 
4437dd7cddfSDavid du Colombier 	    if (pcache == 0)
4447dd7cddfSDavid du Colombier 		code = gs_note_error(gs_error_VMerror);
4457dd7cddfSDavid du Colombier 	    else {
4467dd7cddfSDavid du Colombier 		pocs[j].corder.cache = pcache;
447*593dc095SDavid du Colombier 		gx_ht_init_cache(pmem, pcache, &(pocs[j].corder));
4487dd7cddfSDavid du Colombier 	    }
4497dd7cddfSDavid du Colombier 	}
4507dd7cddfSDavid du Colombier 	if (code < 0)
4517dd7cddfSDavid du Colombier 	    break;
4527dd7cddfSDavid du Colombier     }
4537dd7cddfSDavid du Colombier 
4547dd7cddfSDavid du Colombier     if (code < 0) {
4557dd7cddfSDavid du Colombier 	free_order_array(pocs, num_comps, pmem);
4567dd7cddfSDavid du Colombier 	return code;
4577dd7cddfSDavid du Colombier     }
4587dd7cddfSDavid du Colombier     /* initialize the device halftone structure */
4597dd7cddfSDavid du Colombier     dev_ht.rc.memory = pmem;
4607dd7cddfSDavid du Colombier     dev_ht.order = pocs[0].corder;	/* Default */
4617dd7cddfSDavid du Colombier     if (num_comps == 1) {
4627dd7cddfSDavid du Colombier 	/* we have only a Default; we don't need components. */
4637dd7cddfSDavid du Colombier 	gs_free_object(pmem, pocs, "gs_ht_install");
4647dd7cddfSDavid du Colombier 	dev_ht.components = 0;
4657dd7cddfSDavid du Colombier     } else {
4667dd7cddfSDavid du Colombier 	dev_ht.components = pocs;
4677dd7cddfSDavid du Colombier 	dev_ht.num_comp = num_comps;
4687dd7cddfSDavid du Colombier     }
4697dd7cddfSDavid du Colombier 
4707dd7cddfSDavid du Colombier     /* at last, actually install the halftone in the graphic state */
471*593dc095SDavid du Colombier     if ((code = gx_ht_install(pgs, (gs_halftone *) pht, &dev_ht)) < 0)
472*593dc095SDavid du Colombier         gx_device_halftone_release(&dev_ht, pmem);
473*593dc095SDavid du Colombier     return code;
4747dd7cddfSDavid du Colombier }
4757dd7cddfSDavid du Colombier 
4767dd7cddfSDavid du Colombier /* ---------------- Mask-defined halftones ---------------- */
4777dd7cddfSDavid du Colombier 
4787dd7cddfSDavid du Colombier /*
4797dd7cddfSDavid du Colombier  * Create a halftone order from an array of explicit masks.  This is
4807dd7cddfSDavid du Colombier  * silly, because the rendering machinery actually wants masks, but doing
4817dd7cddfSDavid du Colombier  * it right seems to require too many changes in existing code.
4827dd7cddfSDavid du Colombier  */
4837dd7cddfSDavid du Colombier private int
create_mask_bits(const byte * mask1,const byte * mask2,int width,int height,gx_ht_bit * bits)4847dd7cddfSDavid du Colombier create_mask_bits(const byte * mask1, const byte * mask2,
4857dd7cddfSDavid du Colombier 		 int width, int height, gx_ht_bit * bits)
4867dd7cddfSDavid du Colombier {
4877dd7cddfSDavid du Colombier     /*
4887dd7cddfSDavid du Colombier      * We do this with the slowest, simplest possible algorithm....
4897dd7cddfSDavid du Colombier      */
4907dd7cddfSDavid du Colombier     int width_bytes = (width + 7) >> 3;
4917dd7cddfSDavid du Colombier     int x, y;
4927dd7cddfSDavid du Colombier     int count = 0;
4937dd7cddfSDavid du Colombier 
4947dd7cddfSDavid du Colombier     for (y = 0; y < height; ++y)
4957dd7cddfSDavid du Colombier 	for (x = 0; x < width; ++x) {
4967dd7cddfSDavid du Colombier 	    int offset = y * width_bytes + (x >> 3);
4977dd7cddfSDavid du Colombier 	    byte bit_mask = 0x80 >> (x & 7);
4987dd7cddfSDavid du Colombier 
4997dd7cddfSDavid du Colombier 	    if ((mask1[offset] ^ mask2[offset]) & bit_mask) {
5007dd7cddfSDavid du Colombier 		if (bits)
5017dd7cddfSDavid du Colombier 		    gx_ht_construct_bit(&bits[count], width, y * width + x);
5027dd7cddfSDavid du Colombier 		++count;
5037dd7cddfSDavid du Colombier 	    }
5047dd7cddfSDavid du Colombier 	}
5057dd7cddfSDavid du Colombier     return count;
5067dd7cddfSDavid du Colombier }
5077dd7cddfSDavid du Colombier private int
create_mask_order(gx_ht_order * porder,gs_state * pgs,const gs_client_order_halftone * phcop,gs_memory_t * mem)5087dd7cddfSDavid du Colombier create_mask_order(gx_ht_order * porder, gs_state * pgs,
5097dd7cddfSDavid du Colombier 		  const gs_client_order_halftone * phcop,
5107dd7cddfSDavid du Colombier 		  gs_memory_t * mem)
5117dd7cddfSDavid du Colombier {
5127dd7cddfSDavid du Colombier     int width_bytes = (phcop->width + 7) >> 3;
5137dd7cddfSDavid du Colombier     const byte *masks = (const byte *)phcop->client_data;
5147dd7cddfSDavid du Colombier     int bytes_per_mask = width_bytes * phcop->height;
5157dd7cddfSDavid du Colombier     const byte *prev_mask;
5167dd7cddfSDavid du Colombier     int num_levels = phcop->num_levels;
5177dd7cddfSDavid du Colombier     int num_bits = 0;
5187dd7cddfSDavid du Colombier     int i;
5197dd7cddfSDavid du Colombier     int code;
5207dd7cddfSDavid du Colombier 
5217dd7cddfSDavid du Colombier     /* Do a first pass to compute how many bits entries will be needed. */
5227dd7cddfSDavid du Colombier     for (prev_mask = masks, num_bits = 0, i = 0;
5237dd7cddfSDavid du Colombier 	 i < num_levels - 1;
5247dd7cddfSDavid du Colombier 	 ++i, prev_mask += bytes_per_mask
5257dd7cddfSDavid du Colombier 	)
5267dd7cddfSDavid du Colombier 	num_bits += create_mask_bits(prev_mask, prev_mask + bytes_per_mask,
5277dd7cddfSDavid du Colombier 				     phcop->width, phcop->height, NULL);
5287dd7cddfSDavid du Colombier     code = gx_ht_alloc_client_order(porder, phcop->width, phcop->height,
5297dd7cddfSDavid du Colombier 				    num_levels, num_bits, mem);
5307dd7cddfSDavid du Colombier     if (code < 0)
5317dd7cddfSDavid du Colombier 	return code;
5327dd7cddfSDavid du Colombier     /* Fill in the bits and levels entries. */
5337dd7cddfSDavid du Colombier     for (prev_mask = masks, num_bits = 0, i = 0;
5347dd7cddfSDavid du Colombier 	 i < num_levels - 1;
5357dd7cddfSDavid du Colombier 	 ++i, prev_mask += bytes_per_mask
5367dd7cddfSDavid du Colombier 	) {
5377dd7cddfSDavid du Colombier 	porder->levels[i] = num_bits;
5387dd7cddfSDavid du Colombier 	num_bits += create_mask_bits(prev_mask, prev_mask + bytes_per_mask,
5397dd7cddfSDavid du Colombier 				     phcop->width, phcop->height,
5407dd7cddfSDavid du Colombier 				     ((gx_ht_bit *)porder->bit_data) +
5417dd7cddfSDavid du Colombier 				      num_bits);
5427dd7cddfSDavid du Colombier     }
5437dd7cddfSDavid du Colombier     porder->levels[num_levels - 1] = num_bits;
5447dd7cddfSDavid du Colombier     return 0;
5457dd7cddfSDavid du Colombier }
5467dd7cddfSDavid du Colombier 
5477dd7cddfSDavid du Colombier /* Define the client-order halftone procedure structure. */
5487dd7cddfSDavid du Colombier private const gs_client_order_ht_procs_t mask_order_procs =
5497dd7cddfSDavid du Colombier {
5507dd7cddfSDavid du Colombier     create_mask_order
5517dd7cddfSDavid du Colombier };
5527dd7cddfSDavid du Colombier 
5537dd7cddfSDavid du Colombier /*
5547dd7cddfSDavid du Colombier  * Define a halftone by an explicit set of masks.  We translate these
5557dd7cddfSDavid du Colombier  * internally into a threshold array, since that's what the halftone
5567dd7cddfSDavid du Colombier  * rendering machinery knows how to deal with.
5577dd7cddfSDavid du Colombier  */
5587dd7cddfSDavid du Colombier int
gs_ht_set_mask_comp(gs_ht * pht,int component_index,int width,int height,int num_levels,const byte * masks,gs_ht_transfer_proc transfer,const void * client_data)5597dd7cddfSDavid du Colombier gs_ht_set_mask_comp(gs_ht * pht,
560*593dc095SDavid du Colombier 		    int component_index,
5617dd7cddfSDavid du Colombier 		    int width, int height, int num_levels,
5627dd7cddfSDavid du Colombier 		    const byte * masks,		/* width x height x num_levels bits */
5637dd7cddfSDavid du Colombier 		    gs_ht_transfer_proc transfer,
5647dd7cddfSDavid du Colombier 		    const void *client_data)
5657dd7cddfSDavid du Colombier {
5667dd7cddfSDavid du Colombier     gs_ht_component *phtc =
5677dd7cddfSDavid du Colombier     &(pht->params.ht_multiple.components[component_index]);
5687dd7cddfSDavid du Colombier 
5697dd7cddfSDavid du Colombier     if (component_index >= pht->params.ht_multiple.num_comp)
5707dd7cddfSDavid du Colombier 	return_error(gs_error_rangecheck);
5717dd7cddfSDavid du Colombier     if (phtc->type != ht_type_none)
5727dd7cddfSDavid du Colombier 	return_error(gs_error_invalidaccess);
5737dd7cddfSDavid du Colombier 
5747dd7cddfSDavid du Colombier     phtc->type = ht_type_client_order;
5757dd7cddfSDavid du Colombier     phtc->params.client_order.width = width;
5767dd7cddfSDavid du Colombier     phtc->params.client_order.height = height;
5777dd7cddfSDavid du Colombier     phtc->params.client_order.num_levels = num_levels;
5787dd7cddfSDavid du Colombier     phtc->params.client_order.procs = &mask_order_procs;
5797dd7cddfSDavid du Colombier     phtc->params.client_order.client_data = masks;
5807dd7cddfSDavid du Colombier     phtc->params.client_order.transfer_closure.proc =
5817dd7cddfSDavid du Colombier 	(transfer == 0 ? null_closure_transfer : transfer);
5827dd7cddfSDavid du Colombier     phtc->params.client_order.transfer_closure.data = client_data;
5837dd7cddfSDavid du Colombier 
5847dd7cddfSDavid du Colombier     return 0;
5857dd7cddfSDavid du Colombier 
5867dd7cddfSDavid du Colombier }
587