Beispiel #1
0
int
gs_push_device_filter(gs_memory_t *mem, gs_state *pgs, gs_device_filter_t *df)
{
    gs_device_filter_stack_t *dfs;
    gx_device *new_dev = NULL;
    int code;

    dfs = gs_alloc_struct(mem, gs_device_filter_stack_t,
			  &st_gs_device_filter_stack, "gs_push_device_filter");
    if (dfs == NULL)
	return_error(gs_error_VMerror);
    rc_increment(pgs->device);
    dfs->next_device = pgs->device;
    code = df->push(df, mem, pgs, &new_dev, pgs->device);
    if (code < 0) {
	gs_free_object(mem, dfs, "gs_push_device_filter");
	return code;
    }
    dfs->next = pgs->dfilter_stack;
    pgs->dfilter_stack = dfs;
    dfs->df = df;
    rc_init(dfs, mem, 1);
    gs_setdevice_no_init(pgs, new_dev);
    rc_decrement_only(new_dev, "gs_push_device_filter");
    return code;
}
Beispiel #2
0
/*
 * DeviceN and NChannel color spaces can have an attributes dict.  In the
 * attribute dict can be a Colorants dict which contains Separation color
 * spaces.  If the Colorant dict is present, the PS logic will build each of
 * the Separation color spaces in a temp gstate and then call this procedure
 * to attach the Separation color space to the DeviceN color space.
 * The parameter to this procedure is a colorant name.  The Separation
 * color space is in the current (temp) gstate.  The DeviceN color space is
 * in the next gstate down in the gstate list (pgs->saved).
 */
int
gs_attachattributecolorspace(gs_separation_name sep_name, gs_state * pgs)
{
    gs_color_space * pdevncs;
    gs_device_n_attributes * patt;

    /* Verify that we have a DeviceN color space */
    if (!pgs->saved)
	return_error(gs_error_rangecheck);
    pdevncs = pgs->saved->color_space;
    if (pdevncs->type != &gs_color_space_type_DeviceN)
	return_error(gs_error_rangecheck);

    /* Allocate an attribute list element for our linked list of attributes */
    rc_alloc_struct_1(patt, gs_device_n_attributes, &st_device_n_attributes,
    			pgs->memory, return_error(gs_error_VMerror),
			"gs_attachattributrescolorspace");

    /* Point our attribute list entry to the attribute color space */
    patt->colorant_name = sep_name;
    patt->cspace = pgs->color_space;
    rc_increment(pgs->color_space);

    /* Link our new attribute color space to the DeviceN color space */
    patt->next = pdevncs->params.device_n.colorants;
    pdevncs->params.device_n.colorants = patt;

    return 0;
}
Beispiel #3
0
/*
 * Allocate a path on the heap, and initialize it.  If shared is NULL,
 * allocate a segments object; if shared is an existing path, share its
 * segments.
 */
gx_path *
gx_path_alloc_shared(const gx_path * shared, gs_memory_t * mem,
                     client_name_t cname)
{
    gx_path *ppath = gs_alloc_struct(mem, gx_path, &st_path, cname);

    if (ppath == 0)
        return 0;
    ppath->procs = &default_path_procs;
    if (shared) {
        if (shared->segments == &shared->local_segments) {
            lprintf1("Attempt to share (local) segments of path 0x%lx!\n",
                     (ulong) shared);
            gs_free_object(mem, ppath, cname);
            return 0;
        }
        *ppath = *shared;
        rc_increment(ppath->segments);
    } else {
        int code = path_alloc_segments(&ppath->segments, mem, cname);

        if (code < 0) {
            gs_free_object(mem, ppath, cname);
            return 0;
        }
        gx_path_init_contents(ppath);
    }
    ppath->memory = mem;
    ppath->allocation = path_allocated_on_heap;
    return ppath;
}
Beispiel #4
0
/* Install a DeviceN color space. */
static int
gx_install_DeviceN(gs_color_space * pcs, gs_state * pgs)
{
    int code;
    code = check_DeviceN_component_names(pcs, pgs);
    if (code < 0)
       return code;
    /* See if we have an ICC profile that we can associate with
       this DeviceN color space */
    if (pgs->icc_manager->device_n != NULL) {
        /* An nclr profile is in the manager.  Grab one that matches. */
        cmm_profile_t *profdata = gsicc_finddevicen(pcs, pgs->icc_manager);
        if (profdata != NULL)
            rc_increment(profdata);
        if (pcs->cmm_icc_profile_data != NULL)
            rc_decrement(pcs->cmm_icc_profile_data, "gx_install_DeviceN");
        pcs->cmm_icc_profile_data = profdata;
    }
    /* {csrc} was pgs->color_space->params.device_n.use_alt_cspace */
    ((gs_color_space *)pcs)->params.device_n.use_alt_cspace =
        using_alt_color_space(pgs);
    if (pcs->params.device_n.use_alt_cspace && pcs->cmm_icc_profile_data == NULL ) {
        /* No nclr ICC profile */
        code = (pcs->base_space->type->install_cspace)
            (pcs->base_space, pgs);
    } else if (pcs->params.device_n.use_alt_cspace) {
        gs_color_space *nclr_pcs;
        /* Need to install the nclr cspace */
        code = gs_cspace_build_ICC(&nclr_pcs, NULL, pgs->memory);
        nclr_pcs->cmm_icc_profile_data = pcs->cmm_icc_profile_data;
        rc_increment(pcs->cmm_icc_profile_data);
        rc_increment_cs(nclr_pcs); /* Suspicious - RJW */
        rc_decrement_cs(pcs->base_space, "gx_install_DeviceN");
        pcs->base_space = nclr_pcs;
    }
    /*
     * Give the device an opportunity to capture equivalent colors for any
     * spot colors which might be present in the color space.
     */
    if (code >= 0) {
        if (dev_proc(pgs->device, update_spot_equivalent_colors))
            code = dev_proc(pgs->device, update_spot_equivalent_colors)
                                                        (pgs->device, pgs);
    }
    return code;
}
Beispiel #5
0
RELOC_PTRS_END

/* ------ Public procedures ------ */

/*
 * Create a new DeviceN colorspace.
 */
int
gs_cspace_new_DeviceN(
    gs_color_space **ppcs,
    uint num_components,
    gs_color_space *palt_cspace,
    gs_memory_t *pmem
    )
{
    gs_color_space *pcs;
    gs_device_n_params *pcsdevn;
    gs_separation_name *pnames;
    int code;

    if (palt_cspace == 0 || !palt_cspace->type->can_be_alt_space)
	return_error(gs_error_rangecheck);

    pcs = gs_cspace_alloc(pmem, &gs_color_space_type_DeviceN);
    if (pcs == NULL)
	return_error(gs_error_VMerror);
    pcsdevn = &pcs->params.device_n;
    pcsdevn->names = NULL;
    pcsdevn->map = NULL;
    pcsdevn->colorants = NULL;

    /* Allocate space for color names list. */
    code = alloc_device_n_map(&pcsdevn->map, pmem, "gs_cspace_build_DeviceN");
    if (code < 0) {
	gs_free_object(pmem, pcs, "gs_cspace_new_DeviceN");
	return code;
    }
    /* Allocate space for color names list. */
    pnames = (gs_separation_name *)
	gs_alloc_byte_array(pmem, num_components, sizeof(gs_separation_name),
			  ".gs_cspace_build_DeviceN(names)");
    if (pnames == 0) {
	gs_free_object(pmem, pcsdevn->map, ".gs_cspace_build_DeviceN(map)");
	gs_free_object(pmem, pcs, "gs_cspace_new_DeviceN");
	return_error(gs_error_VMerror);
    }
    pcs->base_space = palt_cspace;
    rc_increment(palt_cspace);
    pcsdevn->names = pnames;
    pcsdevn->num_components = num_components;
    *ppcs = pcs;
    return 0;
}
Beispiel #6
0
/* Install a ICC type color space and use the ICC LABLUT profile. */
int
seticc_lab(i_ctx_t * i_ctx_p, float *white, float *black, float *range_buff)
{
    int                     code;
    gs_color_space *        pcs;
    gs_color_space *        palt_cs;
    gs_imager_state *       pis = (gs_imager_state *)igs;
    int                     i;
    static const char *const rfs = LAB_ICC;
    gs_param_string val, *pval;

    val.data = (const byte *)rfs;
    val.size = strlen(rfs);
    val.persistent = true;
    pval = &val;

    palt_cs = gs_currentcolorspace(igs);
    /* build the color space object */
    code = gs_cspace_build_ICC(&pcs, NULL, gs_state_memory(igs));
    if (code < 0)
        return gs_rethrow(code, "building color space object");
    /* record the current space as the alternative color space */
    /* pcs->base_space = palt_cs;
    rc_increment_cs(palt_cs); */
    /* Get the lab profile.  It may already be set in the icc manager.
       If not then lets populate it.  */
    if (pis->icc_manager->lab_profile == NULL ) {
        /* This can't happen as the profile
           should be initialized during the
           setting of the user params */
        return gs_rethrow(code, "cannot find lab icc profile");
    }
    /* Assign the LAB to LAB profile to this color space */
    code = gsicc_set_gscs_profile(pcs, pis->icc_manager->lab_profile, gs_state_memory(igs));
    rc_increment(pis->icc_manager->lab_profile);
    if (code < 0)
        return gs_rethrow(code, "installing the lab profile");
    pcs->cmm_icc_profile_data->Range.ranges[0].rmin = 0.0;
    pcs->cmm_icc_profile_data->Range.ranges[0].rmax = 100.0;
    for (i = 1; i < 3; i++) {
        pcs->cmm_icc_profile_data->Range.ranges[i].rmin =
            range_buff[2 * (i-1)];
        pcs->cmm_icc_profile_data->Range.ranges[i].rmax =
            range_buff[2 * (i-1) + 1];
    }
    /* Set the color space.  We are done.  */
    code = gs_setcolorspace(igs, pcs);
    return code;
}
Beispiel #7
0
/*
 * Assign one path to another, adjusting reference counts appropriately.
 * Note that this requires that segments of the two paths (but not the path
 * objects themselves) were allocated with the same allocator.  Note also
 * that since it does the equivalent of a gx_path_new(ppto), it may allocate
 * a new segments object for ppto.
 */
int
gx_path_assign_preserve(gx_path * ppto, gx_path * ppfrom)
{
    gx_path_segments *fromsegs = ppfrom->segments;
    gx_path_segments *tosegs = ppto->segments;
    gs_memory_t *mem = ppto->memory;
    gx_path_allocation_t allocation = ppto->allocation;

    if (fromsegs == &ppfrom->local_segments) {
        /* We can't use ppfrom's segments object. */
        if (tosegs == &ppto->local_segments || gx_path_is_shared(ppto)) {
            /* We can't use ppto's segments either.  Allocate a new one. */
            int code = path_alloc_segments(&tosegs, ppto->memory,
                                           "gx_path_assign");

            if (code < 0)
                return code;
            rc_decrement(ppto->segments, "gx_path_assign");
        } else {
            /* Use ppto's segments object. */
            rc_free_path_segments_local(tosegs->rc.memory, tosegs,
                                        "gx_path_assign");
        }
        tosegs->contents = fromsegs->contents;
        ppfrom->segments = tosegs;
        rc_increment(tosegs);	/* for reference from ppfrom */
    } else {
        /* We can use ppfrom's segments object. */
        rc_increment(fromsegs);
        rc_decrement(tosegs, "gx_path_assign");
    }
    *ppto = *ppfrom;
    ppto->memory = mem;
    ppto->allocation = allocation;
    return 0;
}
Beispiel #8
0
int
gs_pop_device_filter(gs_memory_t *mem, gs_state *pgs)
{
    gs_device_filter_stack_t *dfs_tos = pgs->dfilter_stack;
    gx_device *tos_device = pgs->device;
    gs_device_filter_t *df;
    int code;

    if (dfs_tos == NULL)
	return_error(gs_error_rangecheck);
    df = dfs_tos->df;
    pgs->dfilter_stack = dfs_tos->next;
    code = df->prepop(df, mem, pgs, tos_device);
    rc_increment(tos_device);
    gs_setdevice_no_init(pgs, dfs_tos->next_device);
    rc_decrement_only(dfs_tos->next_device, "gs_pop_device_filter");
    dfs_tos->df = NULL;
    rc_decrement_only(dfs_tos, "gs_pop_device_filter");
    code = df->postpop(df, mem, pgs, tos_device);
    rc_decrement_only(tos_device, "gs_pop_device_filter");
    return code;
}
Beispiel #9
0
/*
 * Initialize a stack-allocated path.  This doesn't allocate anything,
 * but may still share the segments.
 */
int
gx_path_init_local_shared(gx_path * ppath, const gx_path * shared,
                          gs_memory_t * mem)
{
    if (shared) {
        if (shared->segments == &shared->local_segments) {
            lprintf1("Attempt to share (local) segments of path 0x%lx!\n",
                     (ulong) shared);
            return_error(gs_error_Fatal);
        }
        *ppath = *shared;
        rc_increment(ppath->segments);
    } else {
        rc_init_free(&ppath->local_segments, mem, 1,
                     rc_free_path_segments_local);
        ppath->segments = &ppath->local_segments;
        gx_path_init_contents(ppath);
    }
    ppath->memory = mem;
    ppath->allocation = path_allocated_on_stack;
    ppath->procs = &default_path_procs;
    return 0;
}
Beispiel #10
0
/*
 * Assign one path to another and free the first path at the same time.
 * (This may do less work than assign_preserve + free.)
 */
int
gx_path_assign_free(gx_path * ppto, gx_path * ppfrom)
{
    /*
     * Detect the special case where both paths have non-shared local
     * segments, since we can avoid allocating new segments in this case.
     */
    if (ppto->segments == &ppto->local_segments &&
        ppfrom->segments == &ppfrom->local_segments &&
        !gx_path_is_shared(ppto)
        ) {
#define fromsegs (&ppfrom->local_segments)
#define tosegs (&ppto->local_segments)
        gs_memory_t *mem = ppto->memory;
        gx_path_allocation_t allocation = ppto->allocation;

        rc_free_path_segments_local(tosegs->rc.memory, tosegs,
                                    "gx_path_assign_free");
        /* We record a bogus reference to fromsegs, which */
        /* gx_path_free will undo. */
        *ppto = *ppfrom;
        rc_increment(fromsegs);
        ppto->segments = tosegs;
        ppto->memory = mem;
        ppto->allocation = allocation;
#undef fromsegs
#undef tosegs
    } else {
        /* In all other cases, just do assign + free. */
        int code = gx_path_assign_preserve(ppto, ppfrom);

        if (code < 0)
            return code;
    }
    gx_path_free(ppfrom, "gx_path_assign_free");
    return 0;
}
Beispiel #11
0
int
gx_path_init_contained_shared(gx_path * ppath, const gx_path * shared,
                              gs_memory_t * mem, client_name_t cname)
{
    if (shared) {
        if (shared->segments == &shared->local_segments) {
            lprintf1("Attempt to share (local) segments of path 0x%lx!\n",
                     (ulong) shared);
            return_error(gs_error_Fatal);
        }
        *ppath = *shared;
        rc_increment(ppath->segments);
    } else {
        int code = path_alloc_segments(&ppath->segments, mem, cname);

        if (code < 0)
            return code;
        gx_path_init_contents(ppath);
    }
    ppath->memory = mem;
    ppath->allocation = path_allocated_contained;
    ppath->procs = &default_path_procs;
    return 0;
}
Beispiel #12
0
/* Set up the color space information for a bitmap image or pattern. */
int
px_image_color_space(gs_image_t *pim,
  const px_bitmap_params_t *params, const gs_string *palette,
  const gs_state *pgs)
{	

    int depth = params->depth;
    gs_color_space *pbase_pcs = NULL;
    gs_color_space *pcs = NULL;
    bool cie_space = false;
    int code = 0;
    switch ( params->color_space ) {
    case eGray:
	pbase_pcs = gs_cspace_new_DeviceGray(pgs->memory);
        pbase_pcs->cmm_icc_profile_data = pgs->icc_manager->default_gray;
        pbase_pcs->type = &gs_color_space_type_ICC;
        rc_increment(pbase_pcs->cmm_icc_profile_data);
	break;
    case eRGB:
        pbase_pcs = gs_cspace_new_DeviceRGB(pgs->memory);
        pbase_pcs->cmm_icc_profile_data = pgs->icc_manager->default_rgb;
        pbase_pcs->type = &gs_color_space_type_ICC;
        rc_increment(pbase_pcs->cmm_icc_profile_data);
        break;
    case eSRGB:
    case eCRGB:
        if ( pl_cspace_init_SRGB(&pbase_pcs, pgs) < 0 )
            /* should not happen */
            return_error(errorInsufficientMemory);
        cie_space = true;
        pbase_pcs->cmm_icc_profile_data = pgs->icc_manager->default_rgb;
        pbase_pcs->type = &gs_color_space_type_ICC;
        rc_increment(pbase_pcs->cmm_icc_profile_data);
	break;
    default:
	return_error(errorIllegalAttributeValue);
    }
    if (pbase_pcs == NULL)
        return_error(errorInsufficientMemory);

    if ( params->indexed ) { 
        pcs = gs_cspace_alloc(pgs->memory, &gs_color_space_type_Indexed);
        if ( pcs == NULL ) {
            /* free the base space also */
            rc_decrement(pbase_pcs, "px_image_color_space");
            return_error(errorInsufficientMemory);
        }
	pcs->base_space = pbase_pcs;
	pcs->params.indexed.hival = (1 << depth) - 1;
	pcs->params.indexed.lookup.table.size = palette->size;
        {
            uint  n = palette->size;
            byte *p = gs_alloc_string(pgs->memory, n,
                           "px_image_color_space(palette)");
            if ( p == 0 ) {
                rc_decrement(pbase_pcs, "px_image_color_space");
                return_error(errorInsufficientMemory);

            }
            memcpy(p, palette->data, n);
            pcs->params.indexed.lookup.table.data = p;
        }
	pcs->params.indexed.use_proc = 0;
    } else {
        pcs = pbase_pcs;
    }
    gs_image_t_init(pim, pcs);
    pim->ColorSpace = pcs;
    pim->BitsPerComponent = depth;
    if ( params->indexed )
	pim->Decode[1] = (1 << depth) - 1;
    /* NB - this needs investigation */
    if (cie_space && !px_is_currentcolor_pattern(pgs)) {
        code = pl_setSRGBcolor((gs_state *)pgs, 0.0, 0.0, 0.0);
    }
    return code;
}
Beispiel #13
0
int seticc(i_ctx_t * i_ctx_p, int ncomps, ref *ICCdict, float *range_buff)
{
    int                     code, k;
    gs_color_space *        pcs;
    gs_color_space *  palt_cs;
    ref *                   pstrmval;
    stream *                s = 0L;
    cmm_profile_t           *picc_profile;
    gs_imager_state *       pis = (gs_imager_state *)igs;
    int                     i, expected = 0;
    ref *                   pnameval;
    static const char *const icc_std_profile_names[] = {
            GSICC_STANDARD_PROFILES
        };
    static const char *const icc_std_profile_keys[] = {
            GSICC_STANDARD_PROFILES_KEYS
        };

    palt_cs = gs_currentcolorspace(igs);

    /* verify the DataSource entry */
    if (dict_find_string(ICCdict, "DataSource", &pstrmval) <= 0)
        return_error(e_undefined);
    check_read_file(i_ctx_p, s, pstrmval);

    /* build the color space object */
    code = gs_cspace_build_ICC(&pcs, NULL, gs_state_memory(igs));
    if (code < 0)
        return gs_rethrow(code, "building color space object");
    /*  For now, dump the profile into a buffer
        and obtain handle from the buffer when we need it.
        We may want to change this later.
        This depends to some degree on what the CMS is capable of doing.
        I don't want to get bogged down on stream I/O at this point.
        Note also, if we are going to be putting these into the clist we will
        want to have this buffer. */
    /* Check if we have the /Name entry.  This is used to associate with
       specs that have enumerated types to indicate sRGB sGray etc */
    if (dict_find_string(ICCdict, "Name", &pnameval) > 0){
        uint size = r_size(pnameval);
        char *str = (char *)gs_alloc_bytes(gs_state_memory(igs), size+1, "seticc");
        memcpy(str, (const char *)pnameval->value.bytes, size);
        str[size] = 0;

        /* Compare this to the standard profile names */
        picc_profile = NULL;
        for (k = 0; k < GSICC_NUMBER_STANDARD_PROFILES; k++) {
            if ( strcmp( str, icc_std_profile_keys[k] ) == 0 ) {
                picc_profile = gsicc_get_profile_handle_file(icc_std_profile_names[k],
                    strlen(icc_std_profile_names[k]), gs_state_memory(igs));
                break;
            }
        }
    } else {
        picc_profile = gsicc_profile_new(s, gs_state_memory(igs), NULL, 0);
    }
    if (picc_profile == NULL) {
        rc_decrement(picc_profile,"seticc");
        rc_decrement(pcs,"seticc");
        return -1;
    }
    code = gsicc_set_gscs_profile(pcs, picc_profile, gs_state_memory(igs));
    if (code < 0) {
        rc_decrement(picc_profile,"seticc");
        rc_decrement(pcs,"seticc");
        return code;
    }
    picc_profile->num_comps = ncomps;

    /* We have to get the profile handle due to the fact that we need to know
       if it has a data space that is CIELAB */
    picc_profile->profile_handle =
        gsicc_get_profile_handle_buffer(picc_profile->buffer,
                                        picc_profile->buffer_size,
                                        gs_state_memory(igs));
    if (picc_profile->profile_handle == NULL) {
        /* Free up everything, the profile is not valid. We will end up going
           ahead and using a default based upon the number of components */
        rc_decrement(picc_profile,"seticc");
        rc_decrement(pcs,"seticc");
        return -1;
    }
    picc_profile->data_cs = gscms_get_profile_data_space(picc_profile->profile_handle);
    switch( picc_profile->data_cs ) {
        case gsCIEXYZ:
        case gsCIELAB:
        case gsRGB:
            expected = 3;
            break;
        case gsGRAY:
            expected = 1;
            break;
        case gsCMYK:
            expected = 4;
            break;
        case gsNCHANNEL:
        case gsNAMED:            /* Silence warnings */
        case gsUNDEFINED:        /* Silence warnings */
            break;
    }
    if (!expected || ncomps != expected) {
        rc_decrement(picc_profile,"seticc");
        rc_decrement(pcs,"seticc");
        return_error(e_rangecheck);
    }

    /* Lets go ahead and get the hash code and check if we match one of the default spaces */
    /* Later we may want to delay this, but for now lets go ahead and do it */
    gsicc_init_hash_cs(picc_profile, pis);

    /* Set the range according to the data type that is associated with the
       ICC input color type.  Occasionally, we will run into CIELAB to CIELAB
       profiles for spot colors in PDF documents. These spot colors are typically described
       as separation colors with tint transforms that go from a tint value
       to a linear mapping between the CIELAB white point and the CIELAB tint
       color.  This results in a CIELAB value that we need to use to fill.  We
       need to detect this to make sure we do the proper scaling of the data.  For
       CIELAB images in PDF, the source is always normal 8 or 16 bit encoded data
       in the range from 0 to 255 or 0 to 65535.  In that case, there should not
       be any encoding and decoding to CIELAB.  The PDF content will not include
       an ICC profile but will set the color space to \Lab.  In this case, we use
       our seticc_lab operation to install the LAB to LAB profile, but we detect
       that we did that through the use of the is_lab flag in the profile descriptor.
       When then avoid the CIELAB encode and decode */
    if (picc_profile->data_cs == gsCIELAB) {
    /* If the input space to this profile is CIELAB, then we need to adjust the limits */
        /* See ICC spec ICC.1:2004-10 Section 6.3.4.2 and 6.4.  I don't believe we need to
           worry about CIEXYZ profiles or any of the other odds ones.  Need to check that though
           at some point. */
        picc_profile->Range.ranges[0].rmin = 0.0;
        picc_profile->Range.ranges[0].rmax = 100.0;
        picc_profile->Range.ranges[1].rmin = -128.0;
        picc_profile->Range.ranges[1].rmax = 127.0;
        picc_profile->Range.ranges[2].rmin = -128.0;
        picc_profile->Range.ranges[2].rmax = 127.0;
        picc_profile->islab = true;
    } else {
        for (i = 0; i < ncomps; i++) {
            picc_profile->Range.ranges[i].rmin = range_buff[2 * i];
            picc_profile->Range.ranges[i].rmax = range_buff[2 * i + 1];
        }
    }
    /* Now see if we are in an overide situation.  We have to wait until now
       in case this is an LAB profile which we will not overide */
    if (gs_currentoverrideicc(pis) && picc_profile->data_cs != gsCIELAB) {
        /* Free up the profile structure */
        switch( picc_profile->data_cs ) {
            case gsRGB:
                pcs->cmm_icc_profile_data = pis->icc_manager->default_rgb;
                break;
            case gsGRAY:
                pcs->cmm_icc_profile_data = pis->icc_manager->default_gray;
                break;
            case gsCMYK:
                pcs->cmm_icc_profile_data = pis->icc_manager->default_cmyk;
                break;
            default:
                break;
        }
        /* Have one increment from the color space.  Having these tied 
           together is not really correct.  Need to fix that.  ToDo.  MJV */
        rc_adjust(picc_profile, -2, "seticc");
        rc_increment(pcs->cmm_icc_profile_data);
    } 
    /* Set the color space.  We are done.  No joint cache here... */
    code = gs_setcolorspace(igs, pcs);
    /* The context has taken a reference to the colorspace. We no longer need
     * ours, so drop it. */
    rc_decrement_only(pcs, "seticc");
    /* In this case, we already have a ref count of 2 on the icc profile
       one for when it was created and one for when it was set.  We really
       only want one here so adjust */
    rc_decrement(picc_profile,"seticc");
    /* Remove the ICC dict from the stack */
    pop(1);
    return code;
}
Beispiel #14
0
/*
 *   <dict>  .set_outputintent  -
 *
 * Set and use the specified output intent.  
 *
 */
static int
zset_outputintent(i_ctx_t * i_ctx_p)
{
    os_ptr                  op = osp;
    int                     code = 0;
    gx_device *dev = gs_currentdevice(igs);
    gs_imager_state *pis = (gs_imager_state *)igs;
    cmm_dev_profile_t       *dev_profile;
    stream *                s = 0L;
    ref *                   pnval;
    ref *                   pstrmval;
    int                     ncomps, dev_comps;
    cmm_profile_t           *picc_profile;
    int                     expected = 0;
    gs_color_space_index    index;
    gsicc_manager_t         *icc_manager = pis->icc_manager;
    cmm_profile_t           *source_profile = NULL;

    check_type(*op, t_dictionary);
    check_dict_read(*op);
    if_debug0m(gs_debug_flag_icc, imemory, "[icc] Using OutputIntent\n");

    /* Get the device structure */
    code = dev_proc(dev, get_profile)(dev,  &dev_profile);
    if (dev_profile == NULL) { 
        code = gsicc_init_device_profile_struct(dev, NULL, 0);
        code = dev_proc(dev, get_profile)(dev,  &dev_profile);
    }
    if (dev_profile->oi_profile != NULL) {
        return 0;  /* Allow only one setting of this object */
    }
    code = dict_find_string(op, "N", &pnval);
    if (code < 0)
        return code;
    ncomps = pnval->value.intval;

    /* verify the DataSource entry. Creat profile from stream */
    if (dict_find_string(op, "DataSource", &pstrmval) <= 0)
        return_error(e_undefined);
    check_read_file(i_ctx_p, s, pstrmval);

    picc_profile = gsicc_profile_new(s, gs_state_memory(igs), NULL, 0);
    picc_profile->num_comps = ncomps;
    picc_profile->profile_handle =
        gsicc_get_profile_handle_buffer(picc_profile->buffer,
                                        picc_profile->buffer_size,
                                        gs_state_memory(igs));
    if (picc_profile->profile_handle == NULL) {
        rc_decrement(picc_profile,"zset_outputintent");
        return -1;
    }
    picc_profile->data_cs = gscms_get_profile_data_space(picc_profile->profile_handle);
    switch (picc_profile->data_cs) {
        case gsCIEXYZ:
        case gsCIELAB:
        case gsRGB:
            expected = 3;
            source_profile = icc_manager->default_rgb;
            break;
        case gsGRAY:
            expected = 1;
            source_profile = icc_manager->default_gray;
            break;
        case gsCMYK:
            expected = 4;
            source_profile = icc_manager->default_cmyk;
            break;
        case gsNCHANNEL:
            expected = 0;
            break;
        case gsNAMED:            
        case gsUNDEFINED:        
            break;
    }
    if (expected && ncomps != expected) {
        rc_decrement(picc_profile,"zset_outputintent");
        return_error(e_rangecheck);
    }
    gsicc_init_hash_cs(picc_profile, pis);

    /* All is well with the profile.  Lets set the stuff that needs to be set */
    dev_profile->oi_profile = picc_profile;
    picc_profile->name = (char *) gs_alloc_bytes(picc_profile->memory, 
                                                 MAX_DEFAULT_ICC_LENGTH,
                                                 "zset_outputintent");
    strncpy(picc_profile->name, OI_PROFILE, strlen(OI_PROFILE));
    picc_profile->name[strlen(OI_PROFILE)] = 0;
    picc_profile->name_length = strlen(OI_PROFILE);
    /* Set the range of the profile */
    gscms_set_icc_range(&picc_profile);

    /* If the output device has a different number of componenets, then we are 
       going to set the output intent as the proofing profile, unless the 
       proofing profile has already been set. 

       If the device has the same number of components (and color model) then as 
       the profile we will use this as the output profile, unless someone has 
       explicitly set the output profile.

       Finally, we will use the output intent profile for the default profile
       of the proper Device profile in the icc manager, again, unless someone
       has explicitly set this default profile. */

    dev_comps = dev_profile->device_profile[0]->num_comps;
    index = gsicc_get_default_type(dev_profile->device_profile[0]);
    if (ncomps == dev_comps && index < gs_color_space_index_DevicePixel) {
        /* The OI profile is the same type as the profile for the device and a 
           "default" profile for the device was not externally set. So we go 
           ahead and use the OI profile as the device profile.  Care needs to be 
           taken here to keep from screwing up any device parameters.   We will 
           use a keyword of OIProfile for the user/device parameter to indicate 
           its usage.  Also, note conflicts if one is setting object dependent 
           color management */
        rc_assign(dev_profile->device_profile[0], picc_profile, 
                  "zset_outputintent");
        if_debug0m(gs_debug_flag_icc, imemory, "[icc] OutputIntent used for device profile\n");
    } else {
        if (dev_profile->proof_profile == NULL) {
            /* This means that we should use the OI profile as the proofing 
               profile.  Note that if someone already has specified a 
               proofing profile it is unclear what they are trying to do
               with the output intent.  In this case, we will use it 
               just for the source data below */
            dev_profile->proof_profile = picc_profile;
            rc_increment(picc_profile);
            if_debug0m(gs_debug_flag_icc, imemory, "[icc] OutputIntent used for proof profile\n");
        }
    }
    /* Now the source colors.  See which source color space needs to use the
       output intent ICC profile */
    index = gsicc_get_default_type(source_profile);
    if (index < gs_color_space_index_DevicePixel) {
        /* source_profile is currently the default.  Set it to the OI profile */
        switch (picc_profile->data_cs) {
            case gsGRAY:
                if_debug0m(gs_debug_flag_icc, imemory, "[icc] OutputIntent used source Gray\n");
                rc_assign(icc_manager->default_gray, picc_profile, 
                          "zset_outputintent");
                break;
            case gsRGB:
                if_debug0m(gs_debug_flag_icc, imemory, "[icc] OutputIntent used source RGB\n");
                rc_assign(icc_manager->default_rgb, picc_profile, 
                          "zset_outputintent");
                break;
            case gsCMYK:
                if_debug0m(gs_debug_flag_icc, imemory, "[icc] OutputIntent used source CMYK\n");
                rc_assign(icc_manager->default_cmyk, picc_profile, 
                          "zset_outputintent");
                break;
            default:
                break;
        }
    }
    /* Remove the output intent dict from the stack */
    pop(1);
    return code;
}
Beispiel #15
0
int
gs_begin_transparency_mask(gs_state * pgs,
                           const gs_transparency_mask_params_t * ptmp,
                           const gs_rect * pbbox, bool mask_is_image)
{
    gs_pdf14trans_params_t params = { 0 };
    gs_pdf14trans_params_t params_color = { 0 };
    const int l = sizeof(params.Background[0]) * ptmp->Background_components;
    int i, code;
    gs_color_space *blend_color_space;
    gsicc_manager_t *icc_manager = pgs->icc_manager;

    if (check_for_nontrans_pattern(pgs,
                  (unsigned char *)"gs_pop_transparency_state")) {
        return(0);
    }
    params.pdf14_op = PDF14_BEGIN_TRANS_MASK;
    params.bbox = *pbbox;
    params.subtype = ptmp->subtype;
    params.Background_components = ptmp->Background_components;
    memcpy(params.Background, ptmp->Background, l);
    params.GrayBackground = ptmp->GrayBackground;
    params.transfer_function = ptmp->TransferFunction_data;
    params.function_is_identity =
            (ptmp->TransferFunction == mask_transfer_identity);
    params.mask_is_image = mask_is_image;
    params.replacing = ptmp->replacing;

    /* The eventual state that we want this smask to be moved to
       is always gray.  This should provide us with a significant
       speed improvement over the old code.  This does not keep us
       from having groups within the softmask getting blended in different
       color spaces, it just makes the final space be gray, which is what
       we will need to get to eventually anyway. In this way we avoid a
       final color conversion on a potentially large buffer. */
    /* Also check if we have loaded in the transparency icc profiles.  If not
       go ahead and take care of that now */
    if (icc_manager->smask_profiles == NULL) {
        code = gsicc_initialize_iccsmask(icc_manager);
        if (code < 0)
            return(code);
    }
    /* A new soft mask group,  make sure the profiles are set */
    if_debug0m('v', pgs->memory, "[v]pushing soft mask color sending\n");
    if (params.subtype != TRANSPARENCY_MASK_None) {
        params_color.pdf14_op = PDF14_PUSH_SMASK_COLOR;
        code = gs_state_update_pdf14trans(pgs, &params_color);
        if (code < 0)
            return(code);
        blend_color_space = gs_cspace_new_DeviceGray(pgs->memory);
        blend_color_space->cmm_icc_profile_data = pgs->icc_manager->default_gray;
        rc_increment(blend_color_space->cmm_icc_profile_data);
        if_debug8m('v', pgs->memory, "[v](0x%lx)gs_begin_transparency_mask [%g %g %g %g]\n\
          subtype = %d  Background_components = %d %s\n",
                  (ulong)pgs, pbbox->p.x, pbbox->p.y, pbbox->q.x, pbbox->q.y,
                  (int)ptmp->subtype, ptmp->Background_components,
                  (ptmp->TransferFunction == mask_transfer_identity ? "no TR" :
                   "has TR"));
        /* Sample the transfer function */
        for (i = 0; i < MASK_TRANSFER_FUNCTION_SIZE; i++) {
            float in = (float)(i * (1.0 / (MASK_TRANSFER_FUNCTION_SIZE - 1)));
            float out;

            ptmp->TransferFunction(in, &out, ptmp->TransferFunction_data);
            params.transfer_fn[i] = (byte)floor((double)(out * 255 + 0.5));
        }
        /* Note:  This function is called during the c-list writer side. */
        if ( blend_color_space->cmm_icc_profile_data != NULL ) {
        /* Blending space is ICC based.  If we are doing c-list rendering we will
           need to write this color space into the clist. */
            params.group_color = ICC;
            params.group_color_numcomps =
                    blend_color_space->cmm_icc_profile_data->num_comps;
            /* Get the ICC profile */
            /* We don't reference count this - see comment in
             * pdf14_update_device_color_procs_pop_c()
             */
            params.iccprofile = blend_color_space->cmm_icc_profile_data;
            params.icc_hash = blend_color_space->cmm_icc_profile_data->hashcode;
        } else {
            params.group_color = GRAY_SCALE;
            params.group_color_numcomps = 1;  /* Need to check */
        }
        /* Explicitly decrement the profile data since blend_color_space may not
         * be an ICC color space object.
         */
        rc_decrement(blend_color_space->cmm_icc_profile_data, "gs_begin_transparency_mask");
        rc_decrement_only_cs(blend_color_space, "gs_begin_transparency_mask");
    }
Beispiel #16
0
int
main(int argc, const char *argv[])
{
    char achar = '0';
    gs_memory_t *mem;

    gs_state *pgs;
    const gx_device *const *list;
    gx_device *dev;
    gx_device_bbox *bbdev;
    int code;

    gp_init();
    mem = gs_malloc_init();
    gs_lib_init1(mem);
    if (argc < 2 || (achar = argv[1][0]) < '1' ||
        achar > '0' + countof(tests) - 1
        ) {
        lprintf1("Usage: gslib 1..%c\n", '0' + (char)countof(tests) - 1);
        gs_abort(mem);
    }
    gs_debug['@'] = 1;
    gs_debug['?'] = 1;
/*gs_debug['B'] = 1; *//****** PATCH ******/
/*gs_debug['L'] = 1; *//****** PATCH ******/
    /*
     * gs_iodev_init must be called after the rest of the inits, for
     * obscure reasons that really should be documented!
     */
    gs_iodev_init(mem);
/****** WRONG ******/
    gs_lib_device_list(&list, NULL);
    gs_copydevice(&dev, list[0], mem);
    check_device_separable(dev);
    gx_device_fill_in_procs(dev);
    bbdev =
        gs_alloc_struct_immovable(mem, gx_device_bbox, &st_device_bbox,
                                  "bbox");
    gx_device_bbox_init(bbdev, dev, mem);

    code = dev_proc(dev, get_profile)(dev, &bbdev->icc_struct);
    rc_increment(bbdev->icc_struct);

    /* Print out the device name just to test the gsparam.c API. */
    {
        gs_c_param_list list;
        gs_param_string nstr;

        gs_c_param_list_write(&list, mem);
        code = gs_getdeviceparams(dev, (gs_param_list *) & list);
        if (code < 0) {
            lprintf1("getdeviceparams failed! code = %d\n", code);
            gs_abort(mem);
        }
        gs_c_param_list_read(&list);
        code = param_read_string((gs_param_list *) & list, "Name", &nstr);
        if (code < 0) {
            lprintf1("reading Name failed! code = %d\n", code);
            gs_abort(mem);
        }
        dputs("Device name = ");
        debug_print_string(nstr.data, nstr.size);
        dputs("\n");
        gs_c_param_list_release(&list);
    }
    /*
     * If this is a device that takes an OutputFile, set the OutputFile
     * to "-" in the copy.
     */
    {
        gs_c_param_list list;
        gs_param_string nstr;

        gs_c_param_list_write(&list, mem);
        param_string_from_string(nstr, "-");
        code = param_write_string((gs_param_list *)&list, "OutputFile", &nstr);
        if (code < 0) {
            lprintf1("writing OutputFile failed! code = %d\n", code);
            gs_abort(mem);
        }
        gs_c_param_list_read(&list);
        code = gs_putdeviceparams(dev, (gs_param_list *)&list);
        gs_c_param_list_release(&list);
        if (code < 0 && code != gs_error_undefined) {
            lprintf1("putdeviceparams failed! code = %d\n", code);
            gs_abort(mem);
        }
    }
    dev = (gx_device *) bbdev;
    pgs = gs_state_alloc(mem);
    gs_setdevice_no_erase(pgs, dev);	/* can't erase yet */
    {
        gs_point dpi;
        gs_screen_halftone ht;

        gs_dtransform(pgs, 72.0, 72.0, &dpi);
        ht.frequency = min(fabs(dpi.x), fabs(dpi.y)) / 16.001;
        ht.angle = 0;
        ht.spot_function = odsf;
        gs_setscreen(pgs, &ht);
    }
    /* gsave and grestore (among other places) assume that */
    /* there are at least 2 gstates on the graphics stack. */
    /* Ensure that now. */
    gs_gsave(pgs);
    gs_erasepage(pgs);

    code = (*tests[achar - '1']) (pgs, mem);
    gs_output_page(pgs, 1, 1);
    {
        gs_rect bbox;

        gx_device_bbox_bbox(bbdev, &bbox);
        dprintf4("Bounding box: [%g %g %g %g]\n",
                 bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
    }
    if (code)
        dprintf1("**** Test returned code = %d.\n", code);
    dputs("Done.  Press <enter> to exit.");
    fgetc(mem->gs_lib_ctx->fstdin);
    gs_lib_finit(0, 0, mem);
    return 0;
#undef mem
}
Beispiel #17
0
/* Exported for use by background printing.                             */
gx_device *
setup_device_and_mem_for_thread(gs_memory_t *chunk_base_mem, gx_device *dev, bool bg_print, gsicc_link_cache_t **cachep)
{
    int i, code;
    char fmode[4];
    gs_memory_t *thread_mem;
    gx_device_clist *cldev = (gx_device_clist *)dev;
    gx_device_printer *pdev = (gx_device_printer *)dev;
    gx_device_clist_common *cdev = (gx_device_clist_common *)cldev;
    gx_device *ndev;
    gx_device_clist *ncldev;
    gx_device_clist_common *ncdev;
    gx_device_printer *npdev;
    gx_device *protodev;
    gs_c_param_list paramlist;
    gs_devn_params *pclist_devn_params;

    /* Every thread will have a 'chunk allocator' to reduce the interaction
     * with the 'base' allocator which has 'mutex' (locking) protection.
     * This improves performance of the threads.
     */
    if ((code = gs_memory_chunk_wrap(&(thread_mem), chunk_base_mem )) < 0) {
        emprintf1(dev->memory, "chunk_wrap returned error code: %d\n", code);
        return NULL;
    }
    /* Find the prototype for this device (needed so we can copy from it) */
    for (i=0; (protodev = (gx_device *)gs_getdevice(i)) != NULL; i++)
        if (strcmp(protodev->dname, dev->dname) == 0)
            break;

    /* Clone the device from the prototype device */
    if (protodev == NULL ||
        (code = gs_copydevice((gx_device **) &ndev, protodev, thread_mem)) < 0) {
        gs_memory_chunk_release(thread_mem);
        return NULL;
    }
    ncldev = (gx_device_clist *)ndev;
    ncdev = (gx_device_clist_common *)ndev;
    npdev = (gx_device_printer *)ndev;
    gx_device_fill_in_procs(ndev);
    ((gx_device_printer *)ncdev)->buffer_memory =
        ncdev->memory =
            ncdev->bandlist_memory =
               thread_mem;
    ndev->PageCount = dev->PageCount;       /* copy to prevent mismatch error */
    npdev->file = pdev->file;               /* For background printing when doing N copies with %d */
    strcpy((npdev->fname), (pdev->fname));
    ndev->color_info = dev->color_info;     /* copy before putdeviceparams */
    ndev->pad = dev->pad;
    ndev->log2_align_mod = dev->log2_align_mod;
    ndev->is_planar = dev->is_planar;
#if CMM_THREAD_SAFE
        ndev->icc_struct = dev->icc_struct;  /* Set before put params */
        rc_increment(ndev->icc_struct);
#endif
    /* get the current device parameters to put into the cloned device */
    gs_c_param_list_write(&paramlist, dev->memory);
    if ((code = gs_getdeviceparams(dev, (gs_param_list *)&paramlist)) < 0) {
        emprintf1(dev->memory,
                  "Error getting device params, code=%d. Rendering threads not started.\n",
                  code);
        goto out_cleanup;
    }
    gs_c_param_list_read(&paramlist);
    if ((code = gs_putdeviceparams(ndev, (gs_param_list *)&paramlist)) < 0)
        goto out_cleanup;
    gs_c_param_list_release(&paramlist);

    /* In the case of a separation device, we need to make sure we get the
       devn params copied over */
    pclist_devn_params = dev_proc(dev, ret_devn_params)(dev);
    if (pclist_devn_params != NULL) {
        code = devn_copy_params(dev, ndev);
        if (code < 0) {
#ifdef DEBUG /* suppress a warning on a release build */
            gs_note_error(gs_error_VMerror);
#endif
            goto out_cleanup;
        }
    }
    /* Also make sure supports_devn is set correctly */
    ndev->icc_struct->supports_devn = cdev->icc_struct->supports_devn;
    ncdev->page_uses_transparency = cdev->page_uses_transparency;
    if_debug3m(gs_debug_flag_icc, cdev->memory,
               "[icc] MT clist device = 0x%p profile = 0x%p handle = 0x%p\n",
               ncdev,
               ncdev->icc_struct->device_profile[0],
               ncdev->icc_struct->device_profile[0]->profile_handle);
    /* If the device is_planar, then set the flag in the new_device and the procs */
    if ((ncdev->is_planar = cdev->is_planar))
        gdev_prn_set_procs_planar(ndev);

    /* gdev_prn_allocate_memory sets the clist for writing, creating new files.
     * We need  to unlink those files and open the main thread's files, then
     * reset the clist state for reading/rendering
     */
    if ((code = gdev_prn_allocate_memory(ndev, NULL, ndev->width, ndev->height)) < 0)
        goto out_cleanup;

    /* close and unlink the temp files just created */
    ncdev->page_info.io_procs->fclose(ncdev->page_info.cfile, ncdev->page_info.cfname, true);
    ncdev->page_info.io_procs->fclose(ncdev->page_info.bfile, ncdev->page_info.bfname, true);
    ncdev->page_info.cfile = ncdev->page_info.bfile = NULL;

    /* open the main thread's files for this thread */
    strcpy(fmode, "r");                 /* read access for threads */
    strncat(fmode, gp_fmode_binary_suffix, 1);
    if ((code=cdev->page_info.io_procs->fopen(cdev->page_info.cfname, fmode, &ncdev->page_info.cfile,
                        thread_mem, thread_mem, true)) < 0 ||
         (code=cdev->page_info.io_procs->fopen(cdev->page_info.bfname, fmode, &ncdev->page_info.bfile,
                        thread_mem, thread_mem, false)) < 0)
        goto out_cleanup;

    strcpy((ncdev->page_info.cfname), (cdev->page_info.cfname));
    strcpy((ncdev->page_info.bfname), (cdev->page_info.bfname));
    clist_render_init(ncldev);      /* Initialize clist device for reading */
    ncdev->page_info.bfile_end_pos = cdev->page_info.bfile_end_pos;

    /* The threads are maintained until clist_finish_page.  At which
       point, the threads are torn down, the master clist reader device
       is changed to writer, and the icc_table and the icc_cache_cl freed */
#if CMM_THREAD_SAFE
    /* safe to share the link cache */
    ncdev->icc_cache_cl = cdev->icc_cache_cl;
    rc_increment(cdev->icc_cache_cl, "setup_render_thread");
#else
    /* each thread needs its own link cache */
    if (cachep != NULL) {
        if (*cachep == NULL) {
            /* We don't have one cached that we can reuse, so make one. */
            if ((*cachep = gsicc_cache_new(thread_mem->thread_safe_memory)) == NULL)
                goto out_cleanup;
        }
        rc_increment(*cachep);
        ncdev->icc_cache_cl = *cachep;
    } else if ((ncdev->icc_cache_cl = gsicc_cache_new(thread_mem)) == NULL)
        goto out_cleanup;
#endif
    if (bg_print) {
        gx_device_clist_reader *ncrdev = (gx_device_clist_reader *)ncdev;

        if (cdev->icc_table != NULL) {
            /* This is a background printing thread, so it cannot share the icc_table  */
            /* since this probably was created with a GC'ed allocator and the bg_print */
            /* thread can't deal with the relocation. Free the cdev->icc_table and get */
            /* a new one from the clist.                                               */
            clist_free_icc_table(cdev->icc_table, cdev->memory);
            cdev->icc_table = NULL;
            if ((code = clist_read_icctable((gx_device_clist_reader *)ncdev)) < 0)
                goto out_cleanup;
        }
        /* Similarly for the color_usage_array, when the foreground device switches to */
        /* writer mode, the foreground's array will be freed.                          */
        if ((code = clist_read_color_usage_array(ncrdev)) < 0)
            goto out_cleanup;
    } else {
    /* Use the same profile table and color usage array in each thread */
        ncdev->icc_table = cdev->icc_table;		/* OK for multiple rendering threads */
        ((gx_device_clist_reader *)ncdev)->color_usage_array =
                ((gx_device_clist_reader *)cdev)->color_usage_array;
    }
    /* Needed for case when the target has cielab profile and pdf14 device
       has a RGB profile stored in the profile list of the clist */
    ncdev->trans_dev_icc_hash = cdev->trans_dev_icc_hash;

    /* success */
    return ndev;

out_cleanup:
    /* Close the file handles, but don't delete (unlink) the files */
    if (ncdev->page_info.bfile != NULL)
        ncdev->page_info.io_procs->fclose(ncdev->page_info.bfile, ncdev->page_info.bfname, false);
    if (ncdev->page_info.cfile != NULL)
        ncdev->page_info.io_procs->fclose(ncdev->page_info.cfile, ncdev->page_info.cfname, false);
    ncdev->do_not_open_or_close_bandfiles = true; /* we already closed the files */

    if (ndev != NULL) {
        gdev_prn_free_memory(ndev);
        gs_free_object(thread_mem, ndev, "setup_device_and_mem_for_thread");
    }
    gs_memory_chunk_release(thread_mem);
    return NULL;
}
Beispiel #18
0
/* Open the output file and stream. */
int
gdev_vector_open_file_options(gx_device_vector * vdev, uint strmbuf_size,
                              int open_options)
{
    bool binary = !(open_options & VECTOR_OPEN_FILE_ASCII);
    int code = -1;		/* (only for testing, never returned) */
    cmm_dev_profile_t *icc_struct;

    /* Open the file as seekable or sequential, as requested. */
    if (!(open_options & VECTOR_OPEN_FILE_SEQUENTIAL)) {
        /* Try to open as seekable. */
        code =
            gx_device_open_output_file((gx_device *)vdev, vdev->fname,
                                       binary, true, &vdev->file);
    }
    if (code < 0 && (open_options & (VECTOR_OPEN_FILE_SEQUENTIAL |
                                     VECTOR_OPEN_FILE_SEQUENTIAL_OK))) {
        /* Try to open as sequential. */
        code = gx_device_open_output_file((gx_device *)vdev, vdev->fname,
                                          binary, false, &vdev->file);
    }
    if ((code >= 0) && (dev_proc(vdev, get_profile) != NULL)) {
        code = dev_proc(vdev, get_profile)((gx_device *)vdev, &icc_struct);
    }

    if (code < 0)
        return code;
    if ((vdev->strmbuf = gs_alloc_bytes(vdev->v_memory, strmbuf_size,
                                        "vector_open(strmbuf)")) == 0 ||
        (vdev->strm = s_alloc(vdev->v_memory,
                              "vector_open(strm)")) == 0 ||
        ((open_options & VECTOR_OPEN_FILE_BBOX) &&
         (vdev->bbox_device =
          gs_alloc_struct_immovable(vdev->v_memory,
                                    gx_device_bbox, &st_device_bbox,
                                    "vector_open(bbox_device)")) == 0)
        ) {
        if (vdev->bbox_device)
            gs_free_object(vdev->v_memory, vdev->bbox_device,
                           "vector_open(bbox_device)");
        vdev->bbox_device = 0;
        if (vdev->strm)
            gs_free_object(vdev->v_memory, vdev->strm,
                           "vector_open(strm)");
        vdev->strm = 0;
        if (vdev->strmbuf)
            gs_free_object(vdev->v_memory, vdev->strmbuf,
                           "vector_open(strmbuf)");
        vdev->strmbuf = 0;
        gx_device_close_output_file((gx_device *)vdev, vdev->fname, vdev->file);
        vdev->file = 0;
        return_error(gs_error_VMerror);
    }
    vdev->strmbuf_size = strmbuf_size;
    swrite_file(vdev->strm, vdev->file, vdev->strmbuf, strmbuf_size);
    vdev->open_options = open_options;
    /*
     * We don't want finalization to close the file, but we do want it
     * to flush the stream buffer.
     */
    vdev->strm->procs.close = vdev->strm->procs.flush;
    if (vdev->bbox_device) {
        gx_device_bbox_init(vdev->bbox_device, NULL, vdev->v_memory);
        rc_increment(vdev->bbox_device);

        vdev->bbox_device->icc_struct = icc_struct;
        rc_increment(vdev->bbox_device->icc_struct);

        gx_device_set_resolution((gx_device *) vdev->bbox_device,
                                 vdev->HWResolution[0],
                                 vdev->HWResolution[1]);
        /* Do the right thing about upright vs. inverted. */
        /* (This is dangerous in general, since the procedure */
        /* might reference non-standard elements.) */
        set_dev_proc(vdev->bbox_device, get_initial_matrix,
                     dev_proc(vdev, get_initial_matrix));
        (*dev_proc(vdev->bbox_device, open_device))
            ((gx_device *) vdev->bbox_device);
    }
    return 0;
}
Beispiel #19
0
/* Common framework for building shadings. */
static int
build_shading(i_ctx_t *i_ctx_p, build_shading_proc_t proc)
{
    os_ptr op = osp;
    int code;
    float box[4];
    gs_shading_params_t params;
    gs_shading_t *psh;
    ref *pvalue;

    check_type(*op, t_dictionary);
    params.ColorSpace = 0;
    params.cie_joint_caches = 0;
    params.Background = 0;
    /* Collect parameters common to all shading types. */
    {
        gs_color_space *pcs = gs_currentcolorspace(igs);
        int num_comp = gs_color_space_num_components(pcs);

        if (num_comp < 0) {	/* Pattern color space */
            gs_errorinfo_put_pair_from_dict(i_ctx_p, op, "ColorSpace");
            return_error(gs_error_typecheck);
        }
        params.ColorSpace = pcs;
        rc_increment_cs(pcs);
        if (dict_find_string(op, "Background", &pvalue) > 0) {
            gs_client_color *pcc =
                ialloc_struct(gs_client_color, &st_client_color,
                              "build_shading");

            if (pcc == 0) {
                code = gs_note_error(gs_error_VMerror);
                goto fail;
            }
            pcc->pattern = 0;
            params.Background = pcc;
            code = dict_floats_param(imemory, op, "Background",
                                     gs_color_space_num_components(pcs),
                                     pcc->paint.values, NULL);
            if (code < 0) {
                gs_errorinfo_put_pair_from_dict(i_ctx_p, op, "Background");
                goto fail;
            }
        }
    }
    if (dict_find_string(op, "BBox", &pvalue) <= 0)
        params.have_BBox = false;
    else if ((code = dict_floats_param(imemory, op, "BBox",
                                       4, box, NULL)) == 4) {
        /* Adobe Interpreters accept denormalised BBox - bug 688937 */
        if (box[0] <= box[2]) {
            params.BBox.p.x = box[0];
            params.BBox.q.x = box[2];
        } else {
            params.BBox.p.x = box[2];
            params.BBox.q.x = box[0];
        }
        if (box[1] <= box[3]) {
            params.BBox.p.y = box[1];
            params.BBox.q.y = box[3];
        } else {
            params.BBox.p.y = box[3];
            params.BBox.q.y = box[1];
        }
        params.have_BBox = true;
    } else {
        gs_errorinfo_put_pair_from_dict(i_ctx_p, op, "BBox");
        goto fail;
    }
    code = dict_bool_param(op, "AntiAlias", false, &params.AntiAlias);
    if (code < 0) {
        gs_errorinfo_put_pair_from_dict(i_ctx_p, op, "AntiAlias");
        goto fail;
    }
    /* Finish building the shading. */
    code = (*proc)(i_ctx_p, op, &params, &psh, imemory);
    if (code < 0)
        goto fail;
    if (gx_color_space_needs_cie_caches(psh->params.ColorSpace)) {
        rc_decrement(psh->params.cie_joint_caches, "build_shading");
        psh->params.cie_joint_caches = gx_currentciecaches(igs);
        rc_increment(psh->params.cie_joint_caches);
    }
    make_istruct_new(op, 0, psh);
    return code;
fail:
    gs_free_object(imemory, params.Background, "Background");
    if (params.ColorSpace) {
        rc_decrement_only_cs(params.ColorSpace, "build_shading");
    }
    return (code < 0 ? code : gs_note_error(gs_error_rangecheck));
}
Beispiel #20
0
/* shfill */
int
gs_shfill(gs_gstate * pgs, const gs_shading_t * psh)
{
    /*
     * shfill is equivalent to filling the current clipping path (or, if
     * clipping, its bounding box) with the shading, disregarding the
     * Background if any.  In order to produce reasonable high-level output,
     * we must implement this by calling gs_fill_path.
     */
    gs_pattern2_template_t pat;
    gs_matrix imat;
    gs_client_color cc;
    gs_color_space *pcs;
    gx_device_color devc;
    int code;

    /* Must install the shading color space
       to allow check_DeviceN_component_names initialize
       the color component map.
     */
    /* Don't bother with saving the old color space, color,
       and cie_joint_caches,
       because .shfill is always called within gsave-grestore -
       see gs/lib . */
    code = gs_setcolorspace(pgs, psh->params.ColorSpace);
    if (code < 0)
        return 0;
    if (psh->params.cie_joint_caches != NULL) {
        pgs->cie_joint_caches = psh->params.cie_joint_caches;
        rc_increment(pgs->cie_joint_caches);
    }
    gs_pattern2_init(&pat);
    pat.Shading = psh;
    gs_make_identity(&imat);
    code = gs_make_pattern(&cc, (gs_pattern_template_t *)&pat, &imat, pgs,
                           pgs->memory);
    if (code < 0)
        return code;
    code = gs_pattern2_set_shfill(&cc);
    if (code < 0)
        return code;
    pcs = gs_cspace_alloc(pgs->memory, &gs_color_space_type_Pattern);
    if (pcs == NULL)
        return_error(gs_error_VMerror);

    pcs->params.pattern.has_base_space = false;
    code = pcs->type->remap_color(&cc, pcs, &devc, pgs,
                                  pgs->device, gs_color_select_texture);
    if (code >= 0) {
        gx_device *dev = pgs->device;
        bool need_path = !dev_proc(dev, dev_spec_op)(dev,
                             gxdso_pattern_shfill_doesnt_need_path, NULL, 0);

        if (need_path) {
            gx_path cpath;

            gx_path_init_local(&cpath, pgs->memory);
            code = gx_cpath_to_path(pgs->clip_path, &cpath);
            if (code >= 0)
                code = gx_fill_path(&cpath, &devc, pgs, gx_rule_winding_number,
                                    pgs->fill_adjust.x, pgs->fill_adjust.y);
            gx_path_free(&cpath, "gs_shfill");
        } else
            code = gx_fill_path(NULL, &devc, pgs, gx_rule_winding_number,
                                pgs->fill_adjust.x, pgs->fill_adjust.y);
    }
    rc_decrement_cs(pcs, "gs_shfill");
    gs_pattern_reference(&cc, -1);
    return code;
}
Beispiel #21
0
int seticc(i_ctx_t * i_ctx_p, int ncomps, ref *ICCdict, float *range_buff)
{
    os_ptr                  op = osp;
    int edepth = ref_stack_count(&e_stack);
    int                     code, reuse_op = 0;
    gs_color_space *        pcs;
    gs_color_space *  palt_cs;
    int                     i;
    gs_cie_icc *            picc_info;
    ref *                   pstrmval;
    stream *                s = 0L;

    palt_cs = gs_currentcolorspace(igs);
    /* verify the DataSource entry */
    if (dict_find_string(ICCdict, "DataSource", &pstrmval) <= 0)
        return_error(e_undefined);
    check_read_file(s, pstrmval);

    /* build the color space object */
    code = gs_cspace_build_CIEICC(&pcs, NULL, gs_state_memory(igs));
    if (code < 0)
        return code;
    picc_info = pcs->params.icc.picc_info;
    picc_info->num_components = ncomps;
    picc_info->instrp = s;
    picc_info->file_id = (s->read_id | s->write_id);
    for (i = 0; i < ncomps; i++) {
        picc_info->Range.ranges[i].rmin = range_buff[2 * i];
        picc_info->Range.ranges[i].rmax = range_buff[2 * i + 1];

    }

    /* record the current space as the alternative color space */
    pcs->base_space = palt_cs;
    rc_increment(palt_cs);

    code = gx_load_icc_profile(picc_info);
    if (code < 0)
	return code;

    /* If the input space to this profile is CIELAB, then we need to adjust the limits */
    /* See ICC spec ICC.1:2004-10 Section 6.3.4.2 and 6.4 */
    if(picc_info->plu->e_inSpace == icSigLabData)
    {
        picc_info->Range.ranges[0].rmin = 0.0;
        picc_info->Range.ranges[0].rmax = 100.0;

        picc_info->Range.ranges[1].rmin = -128.0;
        picc_info->Range.ranges[1].rmax = 127.0;

        picc_info->Range.ranges[2].rmin = -128.0;
        picc_info->Range.ranges[2].rmax = 127.0;

    } 
    /* If the input space is icSigXYZData, then we should do the limits based upon the white point of the profile.  */
    if(picc_info->plu->e_inSpace == icSigXYZData)
    {
	for (i = 0; i < 3; i++) 
	{
	    picc_info->Range.ranges[i].rmin = 0;
	}

	picc_info->Range.ranges[0].rmax = picc_info->common.points.WhitePoint.u;
	picc_info->Range.ranges[1].rmax = picc_info->common.points.WhitePoint.v;
    	picc_info->Range.ranges[2].rmax = picc_info->common.points.WhitePoint.w;
    }

    code = cie_cache_joint(i_ctx_p, &istate->colorrendering.procs,
			   (gs_cie_common *)picc_info, igs);
    if (code < 0)
	return code;

    return cie_set_finish( i_ctx_p,
                           pcs,
                           &istate->colorspace.procs.cie,
                           edepth,
                           code );
}
Beispiel #22
0
/* Set up and start the render threads */
static int
clist_setup_render_threads(gx_device *dev, int y)
{
    gx_device_printer *pdev = (gx_device_printer *)dev;
    gx_device_clist *cldev = (gx_device_clist *)dev;
    gx_device_clist_common *cdev = (gx_device_clist_common *)cldev;
    gx_device_clist_reader *crdev = &cldev->reader;
    gs_memory_t *mem = cdev->bandlist_memory;
    gs_memory_t *chunk_base_mem = mem->thread_safe_memory;
    gs_memory_status_t mem_status;
    gx_device *protodev;
    gs_c_param_list paramlist;
    int i, code, band;
    int band_count = cdev->nbands;
    char fmode[4];
    gs_devn_params *pclist_devn_params;
    crdev->num_render_threads = pdev->num_render_threads_requested;

    if(gs_debug[':'] != 0)
        dprintf1("%% %d rendering threads requested.\n", pdev->num_render_threads_requested);

    if (crdev->num_render_threads > band_count)
        crdev->num_render_threads = band_count; /* don't bother starting more threads than bands */

    /* Allocate and initialize an array of thread control structures */
    crdev->render_threads = (clist_render_thread_control_t *)
              gs_alloc_byte_array(mem, crdev->num_render_threads,
              sizeof(clist_render_thread_control_t), "clist_setup_render_threads" );
    /* fallback to non-threaded if allocation fails */
    if (crdev->render_threads == NULL) {
        emprintf(mem, " VMerror prevented threads from starting.\n");
        return_error(gs_error_VMerror);
    }

    memset(crdev->render_threads, 0, crdev->num_render_threads *
            sizeof(clist_render_thread_control_t));
    crdev->main_thread_data = cdev->data;               /* save data area */
    /* Based on the line number requested, decide the order of band rendering */
    /* Almost all devices go in increasing line order (except the bmp* devices ) */
    crdev->thread_lookahead_direction = (y < (cdev->height - 1)) ? 1 : -1;
    band = y / crdev->page_info.band_params.BandHeight;

    /* Close the files so we can open them in multiple threads */
    if ((code = cdev->page_info.io_procs->fclose(cdev->page_cfile, cdev->page_cfname, false)) < 0 ||
        (code = cdev->page_info.io_procs->fclose(cdev->page_bfile, cdev->page_bfname, false)) < 0) {
        gs_free_object(mem, crdev->render_threads, "clist_setup_render_threads");
        crdev->render_threads = NULL;
        emprintf(mem, "Closing clist files prevented threads from starting.\n");
        return_error(gs_error_unknownerror); /* shouldn't happen */
    }
    cdev->page_cfile = cdev->page_bfile = NULL;
    strcpy(fmode, "r");                 /* read access for threads */
    strncat(fmode, gp_fmode_binary_suffix, 1);
    /* Find the prototype for this device (needed so we can copy from it) */
    for (i=0; (protodev = (gx_device *)gs_getdevice(i)) != NULL; i++)
        if (strcmp(protodev->dname, dev->dname) == 0)
            break;
    if (protodev == NULL) {
        emprintf(mem,
                 "Could not find prototype device. Rendering threads not started.\n");
        return gs_error_rangecheck;
    }

    gs_c_param_list_write(&paramlist, mem);
    if ((code = gs_getdeviceparams(dev, (gs_param_list *)&paramlist)) < 0) {
        emprintf1(mem,
                  "Error getting device params, code=%d. Rendering threads not started.\n",
                  code);
        return code;
    }

    /* If the 'mem' is not thread safe, we need to wrap it in a locking memory */
    gs_memory_status(chunk_base_mem, &mem_status);
    if (mem_status.is_thread_safe == false) {
            return_error(gs_error_VMerror);
    }

    /* Loop creating the devices and semaphores for each thread, then start them */
    for (i=0; (i < crdev->num_render_threads) && (band >= 0) && (band < band_count);
            i++, band += crdev->thread_lookahead_direction) {
        gx_device *ndev;
        gx_device_clist *ncldev;
        gx_device_clist_common *ncdev;
        clist_render_thread_control_t *thread = &(crdev->render_threads[i]);

        /* Every thread will have a 'chunk allocator' to reduce the interaction
         * with the 'base' allocator which has 'mutex' (locking) protection.
         * This improves performance of the threads.
         */
        if ((code = gs_memory_chunk_wrap(&(thread->memory), chunk_base_mem )) < 0) {
            emprintf1(mem, "chunk_wrap returned error code: %d\n", code);
            break;
        }

        thread->band = -1;              /* a value that won't match any valid band */
        if ((code = gs_copydevice((gx_device **) &ndev, protodev, thread->memory)) < 0) {
            code = 0;           /* even though we failed, no cleanup needed */
            break;
        }
        ncldev = (gx_device_clist *)ndev;
        ncdev = (gx_device_clist_common *)ndev;
        gx_device_fill_in_procs(ndev);
        ((gx_device_printer *)ncdev)->buffer_memory = ncdev->memory =
                ncdev->bandlist_memory = thread->memory;
        gs_c_param_list_read(&paramlist);
        ndev->PageCount = dev->PageCount;       /* copy to prevent mismatch error */
#if CMM_THREAD_SAFE
        ndev->icc_struct = dev->icc_struct;  /* Set before put params */
        rc_increment(ndev->icc_struct);
#endif
        if ((code = gs_putdeviceparams(ndev, (gs_param_list *)&paramlist)) < 0)
            break;
        /* In the case of a separation device, we need to make sure we get the
           devn params copied over */
        pclist_devn_params = dev_proc(dev, ret_devn_params)(dev);
        if (pclist_devn_params != NULL) {
            code = devn_copy_params(dev, (gx_device*) ncdev);
            if (code < 0) return_error(gs_error_VMerror);
        }
        ncdev->page_uses_transparency = cdev->page_uses_transparency;
        if_debug3('{',"[{]MT clist device = 0x%x profile = 0x%x handle = 0x%x\n", 
                  ncdev,
                  ncdev->icc_struct->device_profile[0],
                  ncdev->icc_struct->device_profile[0]->profile_handle);
        /* gdev_prn_allocate_memory sets the clist for writing, creating new files.
         * We need  to unlink those files and open the main thread's files, then
         * reset the clist state for reading/rendering
         */
        if ((code = gdev_prn_allocate_memory(ndev, NULL, ndev->width, ndev->height)) < 0)
            break;
        /* Needed for case when the target has cielab profile and pdf14 device
           has a RGB profile stored in the profile list of the clist */
        ncdev->trans_dev_icc_hash = cdev->trans_dev_icc_hash;
        thread->cdev = ndev;
        /* close and unlink the temp files just created */
        cdev->page_info.io_procs->fclose(ncdev->page_cfile, ncdev->page_cfname, true);
        cdev->page_info.io_procs->fclose(ncdev->page_bfile, ncdev->page_bfname, true);
        /* open the main thread's files for this thread */
        if ((code=cdev->page_info.io_procs->fopen(cdev->page_cfname, fmode, &ncdev->page_cfile,
                            thread->memory, thread->memory, true)) < 0 ||
             (code=cdev->page_info.io_procs->fopen(cdev->page_bfname, fmode, &ncdev->page_bfile,
                            thread->memory, thread->memory, false)) < 0)
            break;
        clist_render_init(ncldev);      /* Initialize clist device for reading */
        ncdev->page_bfile_end_pos = cdev->page_bfile_end_pos;
        /* Use the same link cache in each thread and the same profile table.
           The threads are maintained until clist_finish_page.  At which
           point, the threads are torn down and the master clist reader device
           is destroyed along with the icc_table and the icc_cache_cl */
#if CMM_THREAD_SAFE
        ncdev->icc_cache_cl = cdev->icc_cache_cl;
#else
        ncdev->icc_cache_cl = gsicc_cache_new(crdev->memory);
#endif
        ncdev->icc_table = cdev->icc_table;
        /* create the buf device for this thread, and allocate the semaphores */
        if ((code = gdev_create_buf_device(cdev->buf_procs.create_buf_device,
                                &(thread->bdev), cdev->target,
                                band*crdev->page_band_height, NULL,
                                thread->memory, clist_get_band_complexity(dev,y)) < 0))
            break;
        if ((thread->sema_this = gx_semaphore_alloc(thread->memory)) == NULL ||
            (thread->sema_group = gx_semaphore_alloc(thread->memory)) == NULL) {
            code = gs_error_VMerror;
            break;
        }
        /* Start thread 'i' to do band */
        if ((code = clist_start_render_thread(dev, i, band)) < 0)
            break;
    }
    gs_c_param_list_release(&paramlist);
    /* If the code < 0, the last thread creation failed -- clean it up */
    if (code < 0) {
        /* the following relies on 'free' ignoring NULL pointers */
        gx_semaphore_free(crdev->render_threads[i].sema_group);
        gx_semaphore_free(crdev->render_threads[i].sema_this);
        if (crdev->render_threads[i].bdev != NULL)
            cdev->buf_procs.destroy_buf_device(crdev->render_threads[i].bdev);
        if (crdev->render_threads[i].cdev != NULL) {
            gx_device_clist_common *thread_cdev = (gx_device_clist_common *)crdev->render_threads[i].cdev;

            /* Close the file handles, but don't delete (unlink) the files */
            thread_cdev->page_info.io_procs->fclose(thread_cdev->page_bfile, thread_cdev->page_bfname, false);
            thread_cdev->page_info.io_procs->fclose(thread_cdev->page_cfile, thread_cdev->page_cfname, false);
            thread_cdev->do_not_open_or_close_bandfiles = true; /* we already closed the files */

            gdev_prn_free_memory((gx_device *)thread_cdev);
            gs_free_object(crdev->render_threads[i].memory, thread_cdev,
            "clist_setup_render_threads");
        }
        if (crdev->render_threads[i].memory != NULL)
            gs_memory_chunk_release(crdev->render_threads[i].memory);
    }
    /* If we weren't able to create at least one thread, punt   */
    /* Although a single thread isn't any more efficient, the   */
    /* machinery still works, so that's OK.                     */
    if (i == 0) {
        if (crdev->render_threads[0].memory != NULL) {
            gs_memory_chunk_release(crdev->render_threads[0].memory);
            /* free up the locking wrapper if we allocated one */
            if (chunk_base_mem != mem) {
                gs_memory_locked_release((gs_memory_locked_t *)chunk_base_mem);
                gs_free_object(mem, chunk_base_mem, "clist_setup_render_threads(locked allocator)");
            }
        }
        gs_free_object(mem, crdev->render_threads, "clist_setup_render_threads");
        crdev->render_threads = NULL;
        /* restore the file pointers */
        if (cdev->page_cfile == NULL) {
            char fmode[4];

            strcpy(fmode, "a+");        /* file already exists and we want to re-use it */
            strncat(fmode, gp_fmode_binary_suffix, 1);
            cdev->page_info.io_procs->fopen(cdev->page_cfname, fmode, &cdev->page_cfile,
                                mem, cdev->bandlist_memory, true);
            cdev->page_info.io_procs->fseek(cdev->page_cfile, 0, SEEK_SET, cdev->page_cfname);
            cdev->page_info.io_procs->fopen(cdev->page_bfname, fmode, &cdev->page_bfile,
                                mem, cdev->bandlist_memory, false);
            cdev->page_info.io_procs->fseek(cdev->page_bfile, 0, SEEK_SET, cdev->page_bfname);
        }
        emprintf1(mem, "Rendering threads not started, code=%d.\n", code);
        return_error(code);
    }
    crdev->num_render_threads = i;
    crdev->curr_render_thread = 0;

    if(gs_debug[':'] != 0)
        dprintf1("%% Using %d rendering threads\n", i);

    return 0;
}