diff options
Diffstat (limited to 'pcl/pcuptrn.c')
-rw-r--r-- | pcl/pcuptrn.c | 589 |
1 files changed, 589 insertions, 0 deletions
diff --git a/pcl/pcuptrn.c b/pcl/pcuptrn.c new file mode 100644 index 000000000..644e79e0d --- /dev/null +++ b/pcl/pcuptrn.c @@ -0,0 +1,589 @@ +/* Portions Copyright (C) 2001, 2005 artofcode LLC. + Portions Copyright (C) 1996, 2001 Artifex Software Inc. + Portions Copyright (C) 1988, 2000 Aladdin Enterprises. + This software is based in part on the work of the Independent JPEG Group. + All Rights Reserved. + + This software is distributed under license and may not be copied, modified + or distributed except as expressly authorized under the terms of that + license. Refer to licensing information at http://www.artifex.com/ or + contact Artifex Software, Inc., 101 Lucas Valley Road #110, + San Rafael, CA 94903, (415)492-9861, for further information. */ +/*$Id$ */ + +/* pcuptrn.c - code for PCL and GL/2 user defined patterns */ + +#include "string_.h" +#include "gx.h" +#include "gsuid.h" +#include "gscsel.h" +#include "gsdevice.h" +#include "gxdevice.h" +#include "gscspace.h" +#include "gxdcolor.h" +#include "gxcolor2.h" +#include "gxpcolor.h" +#include "pldict.h" +#include "pcindxed.h" +#include "pcpatrn.h" +#include "pcbiptrn.h" +#include "pcuptrn.h" + +/* + * GC routines. + */ +private_st_pattern_data_t(); +private_st_pattern_t(); + +/* + * Free routine for pattern data structure. + */ + static void +free_pattern_data( + gs_memory_t * pmem, + void * pvpat_data, + client_name_t cname +) +{ + pcl_pattern_data_t * ppat_data = (pcl_pattern_data_t *)pvpat_data; + + if ((ppat_data->storage != pcds_internal) && (ppat_data->pixinfo.data != 0)) + gs_free_object(pmem, ppat_data->pixinfo.data, cname); + gs_free_object(pmem, pvpat_data, cname); +} + +/* + * Build a pattern data structure. This routine is static as pattern + * data structures may only be built as part of a pattern. + * + * All pattern data structure are built as "temporary". Routines that build + * internal patterns should modify this as soon as the pattern is built. + * + * Returns 0 on success, < 0 in the event of an error. In the latter case, + * *pppat_data will be set to NULL. + */ + static int +build_pattern_data( + pcl_pattern_data_t ** pppat_data, + const gs_depth_bitmap * ppixinfo, + pcl_pattern_type_t type, + int xres, + int yres, + gs_memory_t * pmem +) +{ + pcl_pattern_data_t * ppat_data = 0; + + *pppat_data = 0; + rc_alloc_struct_1( ppat_data, + pcl_pattern_data_t, + &st_pattern_data_t, + pmem, + return e_Memory, + "allocate PCL pattern data" + ); + ppat_data->rc.free = free_pattern_data; + + ppat_data->pixinfo = *ppixinfo; + ppat_data->storage = pcds_temporary; + ppat_data->type = type; + ppat_data->xres = xres; + ppat_data->yres = yres; + + *pppat_data = ppat_data; + return 0; +} + +/* + * Free the rendered portion of a pattern. + */ +static void +free_pattern_rendering(const gs_memory_t *mem, + pcl_pattern_t * pptrn +) +{ + if (pptrn->pcol_ccolor != 0) { + pcl_ccolor_release(pptrn->pcol_ccolor); + pptrn->pcol_ccolor = 0; + } + if (pptrn->pmask_ccolor != 0) { + pcl_ccolor_release(pptrn->pmask_ccolor); + pptrn->pmask_ccolor = 0; + } +} + +/* + * Free routine for patterns. This is exported for the benefit of the code + * that handles PCL built-in patterns. + */ + void +pcl_pattern_free_pattern( + gs_memory_t * pmem, + void * pvptrn, + client_name_t cname +) +{ + pcl_pattern_t * pptrn = (pcl_pattern_t *)pvptrn; + + free_pattern_rendering(pmem, pptrn); + if (pptrn->ppat_data != 0) + pcl_pattern_data_release(pptrn->ppat_data); + gs_free_object(pmem, pvptrn, cname); +} + +/* + * Build a PCL pattern. + * + * This is expoorted for use by the routines that create the "built in" + * patterns. + * + * Returns 0 if successful, < 0 in the event of an error. In the latter case, + * *ppptrn will be set to null. + */ + int +pcl_pattern_build_pattern( + pcl_pattern_t ** ppptrn, + const gs_depth_bitmap * ppixinfo, + pcl_pattern_type_t type, + int xres, + int yres, + gs_memory_t * pmem +) +{ + pcl_pattern_t * pptrn = 0; + int code = 0; + + *ppptrn = 0; + pptrn = gs_alloc_struct( pmem, + pcl_pattern_t, + &st_pattern_t, + "create PCL pattern" + ); + if (pptrn == 0) + return e_Memory; + + pptrn->pcol_ccolor = 0; + pptrn->pmask_ccolor = 0; + pptrn->orient = 0; + /* provide a sentinel to guarantee the initial pattern is + rendered */ + pptrn->ref_pt.x = pptrn->ref_pt.y = -1.0; + code = build_pattern_data( &(pptrn->ppat_data), + ppixinfo, + type, + xres, + yres, + pmem + ); + if (code < 0) { + pcl_pattern_free_pattern(pmem, pptrn, "create PCL pattern"); + return code; + } + + *ppptrn = pptrn; + return 0; +} + +/* + * Get a PCL user-defined pattern. A null return indicates the pattern is + * not defined. + */ + pcl_pattern_t * +pcl_pattern_get_pcl_uptrn( pcl_state_t *pcs, int id ) +{ + if (pcs->last_pcl_uptrn_id != id) { + pcl_id_t key; + + pcs->last_pcl_uptrn_id = id; + id_set_value(key, id); + if ( !pl_dict_lookup( &pcs->pcl_patterns, + id_key(key), + 2, + (void **)&pcs->plast_pcl_uptrn, + false, + NULL + ) ) + pcs->plast_pcl_uptrn = 0; + } + + return pcs->plast_pcl_uptrn; +} + +/* + * Define a PCL user-defined pattern. This procedure updates the cached + * information, hence it should be used for all definitions. To undefine + * an entry, set the second operard to null. + * + * Returns 0 on success, < 0 in the event of an error. + */ + static int +define_pcl_ptrn( + pcl_state_t * pcs, + int id, + pcl_pattern_t * pptrn +) +{ + pcl_id_t key; + + id_set_value(key, id); + if (pptrn == 0) + pl_dict_undef(&pcs->pcl_patterns, id_key(key), 2); + else if (pl_dict_put(&pcs->pcl_patterns, id_key(key), 2, pptrn) < 0) + return e_Memory; + + if (pcs->last_pcl_uptrn_id == id) + pcs->plast_pcl_uptrn = pptrn; + + return 0; +} + +/* + * Delete all temporary patterns or all patterns, based on the value of + * the operand. + */ + static void +delete_all_pcl_ptrns( + bool renderings, + bool tmp_only, + pcl_state_t * pcs +) +{ + pcl_pattern_t * pptrn; + pl_dict_enum_t denum; + gs_const_string plkey; + + pl_dict_enum_begin(&pcs->pcl_patterns, &denum); + while (pl_dict_enum_next(&denum, &plkey, (void **)&pptrn)) { + if (!tmp_only || (pptrn->ppat_data->storage == pcds_temporary)) { + pcl_id_t key; + + id_set_key(key, plkey.data); + define_pcl_ptrn(pcs, id_value(key), NULL); + } else if (renderings) + free_pattern_rendering(pcs->memory, pptrn); + } +} + +/* + * Get a GL/2 user defined pattern. A null return indicates there is no pattern + * defined for the index. + */ + pcl_pattern_t * +pcl_pattern_get_gl_uptrn(pcl_state_t *pcs, int indx) +{ + if (pcs->last_gl2_RF_indx != indx) { + pcl_id_t key; + + pcs->last_gl2_RF_indx = indx; + id_set_value(key, indx); + if ( !pl_dict_lookup( &pcs->gl_patterns, + id_key(key), + 2, + (void **)(&pcs->plast_gl2_uptrn), + false, + NULL + ) ) + pcs->plast_gl2_uptrn = 0; + } + + return pcs->plast_gl2_uptrn; +} + +/* + * Create and define a GL/2 user-define pattern. This is the only pattern- + * control like facility provided for GL/2. To undefine patterns, use null + * as the second operand. See pcpatrn.h for further information. + * + * Note that RF patterns may be either colored or uncolored. At the GL/2 level + * the determination is made based on whether or not they contain pen indices + * other than 0 or 1. At this level the determination is based on the depth + * of the data pixmap: 1 for uncolored, 8 for colored. + * + * Returns 0 on success, < 0 in the event of an error. + */ + int +pcl_pattern_RF( + int indx, + const gs_depth_bitmap * ppixmap, + pcl_state_t * pcs +) +{ + pcl_id_t key; + pcl_pattern_t * pptrn = 0; + + id_set_value(key, indx); + + if (ppixmap != 0) { + pcl_pattern_type_t type = ( ppixmap->pix_depth == 1 + ? pcl_pattern_uncolored + : pcl_pattern_colored ); + /* RF appears to use the resolution of the device contrary to + what the pcl documentation implies */ + gx_device *pdev = gs_currentdevice(pcs->pgs); + int code = pcl_pattern_build_pattern( &pptrn, + ppixmap, + type, + pdev->HWResolution[0], + pdev->HWResolution[1], + pcs->memory + ); + + if (code < 0) + return code; + + if (pl_dict_put(&pcs->gl_patterns, id_key(key), 2, pptrn) < 0) { + pcl_pattern_free_pattern( pcs->memory, + pptrn, + "create GL/2 RF pattern" + ); + return e_Memory; + } + + } else + pl_dict_undef(&pcs->gl_patterns, id_key(key), 2); + + if (pcs->last_gl2_RF_indx == indx) + pcs->plast_gl2_uptrn = pptrn; + + return 0; +} + + +/* + * The PCL user-define pattern type. For memory management reasons, this has + * a transitory existence. + * + * This object comes in two forms, with and without resolution. Which form + * applies is determined based on the size of the received data array as + * compared to that indicated by the height, width, and depth fields + * + * Note: These structures are defined by HP. + */ +typedef struct pcl_upattern0_s { + byte format; /* actually pcl_pattern_type_t */ + byte cont; /* continuation; currently unused */ + byte depth; /* bits per pixel; 1 or 8 */ + byte dummy; /* reserved - currently unused */ + byte height[2]; /* height in pixels */ + byte width[2]; /* width in pixels */ + byte data[1]; /* actual size derived from hgiht, width, and bits */ +} pcl_upattern0_t; + +typedef struct pcl_upattern1_s { + byte format; /* actually pcl_pattern_type_t */ + byte cont; /* continuation; currently unused */ + byte depth; /* bits per pixel; 1 or 8 */ + byte dummy; /* reserved - currently unused */ + byte height[2]; /* height in pixels */ + byte width[2]; /* width in pixels */ + byte xres[2]; /* width resolution */ + byte yres[2]; /* height resolution */ + byte data[1]; /* actual size derived from hgiht, width, and bits */ +} pcl_upattern1_t; + +/* + * ESC * c # W + * + * Download Pattern + */ + static int +download_pcl_pattern( + pcl_args_t * pargs, + pcl_state_t * pcs +) +{ + uint count = arg_data_size(pargs); + const pcl_upattern0_t * puptrn0 = (pcl_upattern0_t *)arg_data(pargs); + uint format, depth, rsize, patsize, ndsize, dsize; + gs_depth_bitmap pixinfo; + int xres = 300, yres = 300; + pcl_pattern_t * pptrn = 0; + int code = 0; + int i; + + if (count < 8) + return e_Range; + + format = puptrn0->format; + /* non data size - the size of the parameters that describe the data */ + ndsize = (format == 20 ? sizeof(pcl_upattern1_t) : sizeof(pcl_upattern0_t)) - 1; + pixinfo.num_comps = 1; + pixinfo.size.x = (((uint)puptrn0->width[0]) << 8) + puptrn0->width[1]; + pixinfo.size.y = (((uint)puptrn0->height[0]) << 8) + puptrn0->height[1]; + depth = puptrn0->depth & 0xf; + pixinfo.pix_depth = depth; + pixinfo.raster = (pixinfo.size.x * depth + 7) / 8; + rsize = pixinfo.raster * pixinfo.size.y; + dsize = min(count - ndsize, rsize); + patsize = (((pixinfo.size.y) * (pixinfo.size.x) * depth) + 7) / 8; + + /* check for legitimate format */ + if ((format == 0) || (format == 20)) { + if (depth != 1) + return e_Range; + } else if ( (format != 1) || + ((depth != 1) && (depth != 8)) || + (pixinfo.size.x == 0) || + (pixinfo.size.y == 0) ) + return e_Range; + + if (rsize == 0) + return e_Range; + + /* allocate space for the array */ + pixinfo.data = gs_alloc_bytes(pcs->memory, rsize, "download PCL pattern"); + + if (pixinfo.data == 0) + return e_Memory; + + + if (format == 20) { + pcl_upattern1_t * puptrn1 = (pcl_upattern1_t *)puptrn0; + + xres = (((uint)puptrn1->xres[0]) << 8) + puptrn1->xres[1]; + yres = (((uint)puptrn1->yres[0]) << 8) + puptrn1->yres[1]; + memcpy(pixinfo.data, puptrn1->data, dsize); + } else { + memcpy(pixinfo.data, puptrn0->data, dsize); + } + if (dsize < rsize) + memset(pixinfo.data + dsize, 0, rsize - dsize); + + /* build the pattern */ + code = pcl_pattern_build_pattern( &(pptrn), + &pixinfo, + (format == 1 ? pcl_pattern_colored + : pcl_pattern_uncolored), + xres, + yres, + pcs->memory + ); + + /* place the pattern into the pattern dictionary */ + if ( (code < 0) || + ((code = define_pcl_ptrn(pcs, pcs->pattern_id, pptrn)) < 0) ) { + if (pptrn != 0) + pcl_pattern_free_pattern(pcs->memory, pptrn, "download PCL pattern"); + else + gs_free_object( pcs->memory, + (void *)pixinfo.data, + "download PCL pattern" + ); + } + + return code; +} + +/* + * ESC * c # Q + * + * Pattern contorl. + */ + static int +pattern_control( + pcl_args_t * pargs, + pcl_state_t * pcs +) +{ + pcl_pattern_t * pptrn = 0; + + switch (int_arg(pargs)) { + + /* delete all patterns */ + case 0: + delete_all_pcl_ptrns(false, false, pcs); + break; + + /* delete all temporary patterns */ + case 1: + delete_all_pcl_ptrns(false, true, pcs); + break; + + /* delete last specified pattern */ + case 2: + define_pcl_ptrn(pcs, pcs->pattern_id, NULL); + + /* make last specified pattern temporary */ + case 4: + pptrn = pcl_pattern_get_pcl_uptrn(pcs, pcs->pattern_id); + if (pptrn != 0) + pptrn->ppat_data->storage = pcds_temporary; + break; + + /* make last specified pattern permanent */ + case 5: + pptrn = pcl_pattern_get_pcl_uptrn(pcs, pcs->pattern_id); + if (pptrn != 0) + pptrn->ppat_data->storage = pcds_permanent; + break; + + default: + break; + } + + return 0; +} + +static int +upattern_do_copy(pcl_state_t *psaved, const pcl_state_t *pcs, + pcl_copy_operation_t operation) +{ + int i; + /* copy back any patterns created during macro invocation. NB + this should be incorporated in a built in pattern reset and + copy function in pcbiptrn.c along with + pcl_pattern_clear_bi_patterns() below */ + for(i = 0; i < countof(pcs->bi_pattern_array); i++) + psaved->bi_pattern_array[i] = pcs->bi_pattern_array[i]; + psaved->gl_patterns = pcs->gl_patterns; + psaved->pcl_patterns = pcs->pcl_patterns; + return 0; +} + +/* + * Initialization and reset routines. + */ + static int +upattern_do_registration( + pcl_parser_state_t *pcl_parser_state, + gs_memory_t * pmem +) +{ + DEFINE_CLASS('*') + { + 'c', 'W', + PCL_COMMAND("Download Pattern", download_pcl_pattern, pca_bytes) + }, + { + 'c', 'Q', + PCL_COMMAND( "Pattern Control", + pattern_control, + pca_neg_ignore | pca_big_ignore + ) + }, + END_CLASS + return 0; +} + + static void +upattern_do_reset( + pcl_state_t * pcs, + pcl_reset_type_t type +) +{ + if ((type & pcl_reset_initial) != 0) { + pl_dict_init(&pcs->pcl_patterns, pcs->memory, pcl_pattern_free_pattern); + pl_dict_init(&pcs->gl_patterns, pcs->memory, pcl_pattern_free_pattern); + pcs->last_pcl_uptrn_id = -1; + pcs->plast_pcl_uptrn = 0; + pcs->last_gl2_RF_indx = -1; + pcs->plast_gl2_uptrn = 0; + + } else if ((type & (pcl_reset_cold | pcl_reset_printer | pcl_reset_permanent)) != 0) { + delete_all_pcl_ptrns(true, !(type & pcl_reset_permanent) , pcs); + pcl_pattern_clear_bi_patterns(pcs); + /* GL's IN command takes care of the GL patterns */ + } +} + +const pcl_init_t pcl_upattern_init = { upattern_do_registration, upattern_do_reset, upattern_do_copy }; |