Beispiel #1
0
/* Call for cases where the equivalent icc color space needs to be set */
int
gs_colorspace_set_icc_equivalent(gs_color_space *pcs, bool *islab,
                                 gs_memory_t *memory)
{
     gs_color_space_index color_space_index = gs_color_space_get_index(pcs);
     gs_color_space *picc_cs;

     *islab = false;  /* For non CIEABC cases */
     if (pcs->icc_equivalent != NULL || !gs_color_space_is_PSCIE(pcs)) {
         return(0);
}
     switch( color_space_index ) {
       case gs_color_space_index_CIEDEFG:
            gx_ciedefg_to_icc(&picc_cs, pcs, memory->stable_memory);
            break;
        case gs_color_space_index_CIEDEF:
            gx_ciedef_to_icc(&picc_cs, pcs, memory->stable_memory);
            break;
        case gs_color_space_index_CIEABC:
            gx_cieabc_to_icc(&picc_cs, pcs, islab, memory->stable_memory);
            break;
        case gs_color_space_index_CIEA:
            gx_ciea_to_icc(&picc_cs, pcs, memory->stable_memory);
            break;
        default:
             /* do nothing.  Sould never happen */
             break;
     }
    return(0);
}
Beispiel #2
0
RELOC_PTRS_END

/* Get the concrete space for a Separation space. */
static const gs_color_space *
gx_concrete_space_Separation(const gs_color_space * pcs,
                             const gs_imager_state * pis)
{
    bool is_lab = false;
#ifdef DEBUG
    /*
     * Verify that the color space and imager state info match.
     */
    if (pcs->id != pis->color_component_map.cspace_id)
        dprintf("gx_concretze_space_Separation: color space id mismatch");
#endif

    /*
     * Check if we are using the alternate color space.
     */
    if (pis->color_component_map.use_alt_cspace) {
        /* Need to handle PS CIE space */
        if (gs_color_space_is_PSCIE(pcs->base_space)) {
            if (pcs->base_space->icc_equivalent == NULL) {
                gs_colorspace_set_icc_equivalent(pcs->base_space,
                                                    &is_lab, pis->memory);
            }
            return (pcs->base_space->icc_equivalent);
        }
        return cs_concrete_space(pcs->base_space, pis);
    }
    /*
     * Separation color spaces are concrete (when not using alt. color space).
     */
    return pcs;
}
Beispiel #3
0
static int
gx_concretize_Separation(const gs_client_color *pc, const gs_color_space *pcs,
                         frac *pconc, const gs_imager_state *pis, gx_device *dev)
{
    int code;
    gs_client_color cc;
    gs_color_space *pacs = pcs->base_space;
    bool is_lab;
    int k;
    int num_des_comps = dev->color_info.num_components;

    if (pcs->params.separation.sep_type == SEP_OTHER &&
        pcs->params.separation.use_alt_cspace) {
        gs_device_n_map *map = pcs->params.separation.map;
        /* First see if we have a named color object that we can use to try
           to map from the spot color into device values.  */
        if (pis->icc_manager->device_named != NULL) {
            /* There is a table present.  If we have the colorant name
               then get the device values */
            gx_color_value device_values[GX_DEVICE_COLOR_MAX_COMPONENTS];
            const gs_separation_name name = pcs->params.separation.sep_name;
            byte *pname;
            uint name_size;
            gsicc_rendering_param_t rendering_params;

            /* Define the rendering intents. */
            rendering_params.black_point_comp = BP_ON;
            rendering_params.graphics_type_tag = GS_PATH_TAG;
            rendering_params.rendering_intent = pis->renderingintent;

            pcs->params.separation.get_colorname_string(pis->memory, name,
                                                &pname, &name_size);
            code = gsicc_transform_named_color(pc->paint.values[0], pname,
                            name_size, device_values, pis, dev, NULL,
                            &rendering_params);
            if (code == 0) {
                for (k = 0; k < num_des_comps; k++){
                    pconc[k] = float2frac(((float) device_values[k])/65535.0);
                }
                return(0);
            }
        }
        /* Check the 1-element cache first. */
        if (map->cache_valid && map->tint[0] == pc->paint.values[0]) {
            int i, num_out = gs_color_space_num_components(pacs);

            for (i = 0; i < num_out; ++i)
                pconc[i] = map->conc[i];
            return 0;
        }
        code = (*pcs->params.separation.map->tint_transform)
            (pc->paint.values, &cc.paint.values[0],
             pis, pcs->params.separation.map->tint_transform_data);
        if (code < 0)
            return code;
        /* First check if this was PS based. */
        if (gs_color_space_is_PSCIE(pacs)) {
            /* If we have not yet create the profile do that now */
            if (pacs->icc_equivalent == NULL) {
                gs_colorspace_set_icc_equivalent(pacs, &(is_lab), pis->memory);
            }
            /* Use the ICC equivalent color space */
            pacs = pacs->icc_equivalent;
        }
        if (pacs->cmm_icc_profile_data->data_cs == gsCIELAB) {
            /* Get the data in a form that is concrete for the CMM */
            cc.paint.values[0] /= 100.0;
            cc.paint.values[1] = (cc.paint.values[1]+128)/255.0;
            cc.paint.values[2] = (cc.paint.values[2]+128)/255.0;
        }
        return cs_concretize_color(&cc, pacs, pconc, pis, dev);
    }
    else {
        pconc[0] = gx_unit_frac(pc->paint.values[0]);
    }
    return 0;
}
Beispiel #4
0
static int
gx_concretize_DeviceN(const gs_client_color * pc, const gs_color_space * pcs,
                      frac * pconc, const gs_imager_state * pis, gx_device *dev)
{
    int code, tcode = 0;
    gs_client_color cc;
    gs_color_space *pacs = (gs_color_space*) (pcs->base_space);
    gs_device_n_map *map = pcs->params.device_n.map;
    bool is_lab;
    int num_src_comps = pcs->params.device_n.num_components;

#ifdef DEBUG
    /*
     * Verify that the color space and imager state info match.
     */
    if (pcs->id != pis->color_component_map.cspace_id)
        dmprintf(dev->memory, "gx_concretize_DeviceN: color space id mismatch");
#endif

    /*
     * Check if we need to map into the alternate color space.
     * We must preserve tcode for implementing a semi-hack in the interpreter.
     */

    if (pis->color_component_map.use_alt_cspace) {
        /* Check the 1-element cache first. */
        if (map->cache_valid) {
            int i;

            for (i = pcs->params.device_n.num_components; --i >= 0;) {
                if (map->tint[i] != pc->paint.values[i])
                    break;
            }
            if (i < 0) {
                int num_out = gs_color_space_num_components(pacs);

                for (i = 0; i < num_out; ++i)
                    pconc[i] = map->conc[i];
                return 0;
            }
        }
        tcode = (*pcs->params.device_n.map->tint_transform)
             (pc->paint.values, &cc.paint.values[0],
             pis, pcs->params.device_n.map->tint_transform_data);
        (*pacs->type->restrict_color)(&cc, pacs);
        if (tcode < 0)
            return tcode;
        /* First check if this was PS based. */
        if (gs_color_space_is_PSCIE(pacs)) {
            /* We may have to rescale data to 0 to 1 range */
            rescale_cie_colors(pacs, &cc);
            /* If we have not yet created the profile do that now */
            if (pacs->icc_equivalent == NULL) {
                gs_colorspace_set_icc_equivalent(pacs, &(is_lab), pis->memory);
            }
            /* Use the ICC equivalent color space */
            pacs = pacs->icc_equivalent;
        }
        if (pacs->cmm_icc_profile_data->data_cs == gsCIELAB ||
            pacs->cmm_icc_profile_data->islab) {
            /* Get the data in a form that is concrete for the CMM */
            cc.paint.values[0] /= 100.0;
            cc.paint.values[1] = (cc.paint.values[1]+128)/255.0;
            cc.paint.values[2] = (cc.paint.values[2]+128)/255.0;
        }
        code = cs_concretize_color(&cc, pacs, pconc, pis, dev);
    }
    else {
        int i;

        for (i = num_src_comps; --i >= 0;)
            pconc[i] = gx_unit_frac(pc->paint.values[i]);
        return 0;
    }
    return (code < 0 || tcode == 0 ? code : tcode);
}
Beispiel #5
0
static int
gx_concretize_DeviceN(const gs_client_color * pc, const gs_color_space * pcs,
                      frac * pconc, const gs_imager_state * pis, gx_device *dev)
{
    int code, tcode = 0;
    gs_client_color cc;
    gs_color_space *pacs = (gs_color_space*) (pcs->base_space);
    gs_device_n_map *map = pcs->params.device_n.map;
    bool is_lab;
    int k;
    int num_des_comps = dev->color_info.num_components;
    gsicc_namedcolor_t *named_color;
    const gs_separation_name *names = pcs->params.device_n.names;
    int num_src_comps = pcs->params.device_n.num_components;

#ifdef DEBUG
    /*
     * Verify that the color space and imager state info match.
     */
    if (pcs->id != pis->color_component_map.cspace_id)
        dmprintf(dev->memory, "gx_concretize_DeviceN: color space id mismatch");
#endif

    /*
     * Check if we need to map into the alternate color space.
     * We must preserve tcode for implementing a semi-hack in the interpreter.
     */

    if (pis->color_component_map.use_alt_cspace) {
        /* First see if we have a named color object that we can use to try
           to map from the spot color into device values.  */
        if (pis->icc_manager->device_named != NULL) {
            /* There is a table present.  If we have the colorant name
               then get the device values */
            gx_color_value device_values[GX_DEVICE_COLOR_MAX_COMPONENTS];
            byte *pname;
            uint name_size;
            gsicc_rendering_param_t rendering_params;

            /* Define the rendering intents. */
            rendering_params.black_point_comp = pis->blackptcomp;
            rendering_params.graphics_type_tag = dev->graphics_type_tag;
            rendering_params.override_icc = false;
            rendering_params.preserve_black = gsBKPRESNOTSPECIFIED;
            rendering_params.rendering_intent = pis->renderingintent;
            rendering_params.cmm = gsCMM_DEFAULT;

            /* Allocate and initialize name structure */
            named_color = 
                (gsicc_namedcolor_t*) gs_alloc_bytes(dev->memory,
                    num_src_comps * sizeof(gsicc_namedcolor_t),
                    "gx_remap_concrete_DeviceN");

            for (k = 0; k < num_src_comps; k++) {
                pcs->params.device_n.get_colorname_string(dev->memory, names[k], 
                                                          &pname, &name_size);
                named_color[k].colorant_name = (char*) pname;
                named_color[k].name_size = name_size;
            }
            code = gsicc_transform_named_color(pc->paint.values, named_color,
                                               num_src_comps, device_values, 
                                               pis, dev, NULL, 
                                               &rendering_params);
            gs_free_object(dev->memory, named_color, 
                           "gx_remap_concrete_DeviceN");
            if (code == 0) {
                for (k = 0; k < num_des_comps; k++){
                    pconc[k] = float2frac(((float) device_values[k])/65535.0);
                }
                return(0);
            }
        }
        /* Check the 1-element cache first. */
        if (map->cache_valid) {
            int i;

            for (i = pcs->params.device_n.num_components; --i >= 0;) {
                if (map->tint[i] != pc->paint.values[i])
                    break;
            }
            if (i < 0) {
                int num_out = gs_color_space_num_components(pacs);

                for (i = 0; i < num_out; ++i)
                    pconc[i] = map->conc[i];
                return 0;
            }
        }
        tcode = (*pcs->params.device_n.map->tint_transform)
             (pc->paint.values, &cc.paint.values[0],
             pis, pcs->params.device_n.map->tint_transform_data);
        (*pacs->type->restrict_color)(&cc, pacs);
        if (tcode < 0)
            return tcode;
        /* First check if this was PS based. */
        if (gs_color_space_is_PSCIE(pacs)) {
            /* We may have to rescale data to 0 to 1 range */
            rescale_cie_colors(pacs, &cc);
            /* If we have not yet created the profile do that now */
            if (pacs->icc_equivalent == NULL) {
                gs_colorspace_set_icc_equivalent(pacs, &(is_lab), pis->memory);
            }
            /* Use the ICC equivalent color space */
            pacs = pacs->icc_equivalent;
        }
        if (pacs->cmm_icc_profile_data->data_cs == gsCIELAB ||
            pacs->cmm_icc_profile_data->islab) {
            /* Get the data in a form that is concrete for the CMM */
            cc.paint.values[0] /= 100.0;
            cc.paint.values[1] = (cc.paint.values[1]+128)/255.0;
            cc.paint.values[2] = (cc.paint.values[2]+128)/255.0;
        }
        code = cs_concretize_color(&cc, pacs, pconc, pis, dev);
    }
    else {
        int i;

        for (i = num_src_comps; --i >= 0;)
            pconc[i] = gx_unit_frac(pc->paint.values[i]);
        return 0;
    }
    return (code < 0 || tcode == 0 ? code : tcode);
}
Beispiel #6
0
/*
 * Create a PDF color space corresponding to a PostScript color space.
 * For parameterless color spaces, set *pvalue to a (literal) string with
 * the color space name; for other color spaces, create a cos_array_t if
 * necessary and set *pvalue to refer to it.  In the latter case, if
 * by_name is true, return a string /Rxxxx rather than a reference to
 * the actual object.
 *
 * If ppranges is not NULL, then if  the domain of the color space had
 * to be scaled (to convert a CIEBased space to ICCBased), store a pointer
 * to the ranges in *ppranges, otherwise set *ppranges to 0.
 */
int
pdf_color_space_named(gx_device_pdf *pdev, cos_value_t *pvalue,
                      const gs_range_t **ppranges,
                      const gs_color_space *pcs_in,
                      const pdf_color_space_names_t *pcsn,
                      bool by_name, const byte *res_name, int name_length)
{
    const gs_color_space *pcs;
    gs_color_space_index csi;
    cos_array_t *pca;
    cos_dict_t *pcd;
    cos_value_t v;
    const gs_cie_common *pciec;
    gs_function_t *pfn;
    const gs_range_t *ranges = 0;
    uint serialized_size;
    byte *serialized = NULL, serialized0[100];
    pdf_resource_t *pres = NULL;
    int code;
#if 0
    bool islab = false;
#endif

    /* If color space is CIE based and we have compatibility then go ahead and use the ICC alternative */
    if ((pdev->CompatibilityLevel < 1.3) || !gs_color_space_is_PSCIE(pcs_in) ) {
        pcs = pcs_in;
    } else {
        pcs = pcs_in;
        /* The snippet below creates an ICC equivalent profile for the PS
           color space.  This is disabled until I add the capability to
           specify the profile version to ensure compatability with
           the PDF versions */
#if 0
        if (pcs_in->icc_equivalent != NULL) {
            pcs = pcs_in->icc_equivalent;
        } else {
            /* Need to create the equivalent object */
            gs_colorspace_set_icc_equivalent((gs_color_space *)pcs_in, &islab, pdev->memory);
            pcs = pcs_in->icc_equivalent;
        }
#endif
    }
    csi = gs_color_space_get_index(pcs);
    /* Note that if csi is ICC, check to see if this was one of
       the default substitutes that we introduced for DeviceGray,
       DeviceRGB or DeviceCMYK.  If it is, then just write
       the default color.  Depending upon the flavor of PDF,
       or other options, we may want to actually have all
       the colors defined by ICC profiles and not do the following
       substituion of the Device space. */
    if (csi == gs_color_space_index_ICC) {
        csi = gsicc_get_default_type(pcs->cmm_icc_profile_data);
    }
    if (ppranges)
        *ppranges = 0;		/* default */
    switch (csi) {
    case gs_color_space_index_DeviceGray:
        cos_c_string_value(pvalue, pcsn->DeviceGray);
        return 0;
    case gs_color_space_index_DeviceRGB:
        cos_c_string_value(pvalue, pcsn->DeviceRGB);
        return 0;
    case gs_color_space_index_DeviceCMYK:
        cos_c_string_value(pvalue, pcsn->DeviceCMYK);
        return 0;
    case gs_color_space_index_Pattern:
        if (!pcs->params.pattern.has_base_space) {
            cos_c_string_value(pvalue, "/Pattern");
            return 0;
        }
        break;
    case gs_color_space_index_ICC:
        /*
         * Take a special early exit for unrecognized ICCBased color spaces,
         * or for PDF 1.2 output (ICCBased color spaces date from PDF 1.3).
         */

        if (pcs->cmm_icc_profile_data == NULL ||
                pdev->CompatibilityLevel < 1.3
           ) {
            if (res_name != NULL)
                return 0; /* Ignore .includecolorspace */
            if (pcs->base_space != NULL) {
                return pdf_color_space_named( pdev, pvalue, ppranges,
                                              pcs->base_space,
                                              pcsn, by_name, NULL, 0);
            } else {
                /* Base space is NULL, use appropriate device space */
                switch( cs_num_components(pcs) )  {
                case 1:
                    cos_c_string_value(pvalue, pcsn->DeviceGray);
                    return 0;
                case 3:
                    cos_c_string_value(pvalue, pcsn->DeviceRGB);
                    return 0;
                case 4:
                    cos_c_string_value(pvalue, pcsn->DeviceCMYK);
                    return 0;
                default:
                    break;
                }
            }
        }

        break;
    default:
        break;
    }
    if (pdev->params.ColorConversionStrategy == ccs_CMYK &&
            csi != gs_color_space_index_DeviceCMYK &&
            csi != gs_color_space_index_DeviceGray &&
            csi != gs_color_space_index_Pattern)
        return_error(gs_error_rangecheck);
    if (pdev->params.ColorConversionStrategy == ccs_sRGB &&
            csi != gs_color_space_index_DeviceRGB &&
            csi != gs_color_space_index_DeviceGray &&
            csi != gs_color_space_index_Pattern)
        return_error(gs_error_rangecheck);
    if (pdev->params.ColorConversionStrategy == ccs_Gray &&
            csi != gs_color_space_index_DeviceGray &&
            csi != gs_color_space_index_Pattern)
        return_error(gs_error_rangecheck);
    /* Check whether we already have a PDF object for this color space. */
    if (pcs->id != gs_no_id)
        pres = pdf_find_resource_by_gs_id(pdev, resourceColorSpace, pcs->id);
    if (pres == NULL) {
        stream s;

        s_init(&s, pdev->memory);
        swrite_position_only(&s);
        code = cs_serialize(pcs, &s);
        if (code < 0)
            return_error(gs_error_unregistered); /* Must not happen. */
        serialized_size = stell(&s);
        sclose(&s);
        if (serialized_size <= sizeof(serialized0))
            serialized = serialized0;
        else {
            serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space");
            if (serialized == NULL)
                return_error(gs_error_VMerror);
        }
        swrite_string(&s, serialized, serialized_size);
        code = cs_serialize(pcs, &s);
        if (code < 0)
            return_error(gs_error_unregistered); /* Must not happen. */
        if (stell(&s) != serialized_size)
            return_error(gs_error_unregistered); /* Must not happen. */
        sclose(&s);
        pres = pdf_find_cspace_resource(pdev, serialized, serialized_size);
        if (pres != NULL) {
            if (serialized != serialized0)
                gs_free_object(pdev->pdf_memory, serialized, "pdf_color_space");
            serialized = NULL;
        }
    }
    if (pres) {
        const pdf_color_space_t *const ppcs =
            (const pdf_color_space_t *)pres;

        if (ppranges != 0 && ppcs->ranges != 0)
            *ppranges = ppcs->ranges;
        pca = (cos_array_t *)pres->object;
        goto ret;
    }

    /* Space has parameters -- create an array. */
    pca = cos_array_alloc(pdev, "pdf_color_space");
    if (pca == 0)
        return_error(gs_error_VMerror);

    switch (csi) {

    case gs_color_space_index_ICC:
        code = pdf_iccbased_color_space(pdev, pvalue, pcs, pca);
        break;

    case gs_color_space_index_CIEA: {
        /* Check that we can represent this as a CalGray space. */
        const gs_cie_a *pcie = pcs->params.a;
        bool unitary = cie_ranges_are_0_1(&pcie->RangeA, 1);
        bool identityA = (pcie->MatrixA.u == 1 && pcie->MatrixA.v == 1 &&
                          pcie->MatrixA.w == 1);
        gs_vector3 expts;

        pciec = (const gs_cie_common *)pcie;
        if (!pcie->common.MatrixLMN.is_identity) {
            code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec,
                                         &pcie->RangeA, ONE_STEP_NOT, NULL,
                                         &ranges);
            break;
        }
        if (unitary && identityA &&
                CIE_CACHE_IS_IDENTITY(&pcie->caches.DecodeA) &&
                CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts) &&
                expts.v == expts.u && expts.w == expts.u
           ) {
            DO_NOTHING;
        } else if (unitary && identityA &&
                   CIE_CACHE3_IS_IDENTITY(pcie->common.caches.DecodeLMN) &&
                   cie_vector_cache_is_exponential(&pcie->caches.DecodeA, &expts.u)
                  ) {
            DO_NOTHING;
        } else {
            code = pdf_convert_cie_space(pdev, pca, pcs, "GRAY", pciec,
                                         &pcie->RangeA, ONE_STEP_NOT, NULL,
                                         &ranges);
            break;
        }
        code = cos_array_add(pca, cos_c_string_value(&v, "/CalGray"));
        if (code < 0)
            return code;
        pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
        if (pcd == 0)
            return_error(gs_error_VMerror);
        if (expts.u != 1) {
            code = cos_dict_put_c_key_real(pcd, "/Gamma", expts.u);
            if (code < 0)
                return code;
        }
    }
cal:
        /* Finish handling a CIE-based color space (Calxxx or Lab). */
    if (code < 0)
        return code;
    code = pdf_finish_cie_space(pca, pcd, pciec);
    break;

    case gs_color_space_index_CIEABC: {
        /* Check that we can represent this as a CalRGB space. */
        const gs_cie_abc *pcie = pcs->params.abc;
        bool unitary = cie_ranges_are_0_1(pcie->RangeABC.ranges, 3);
        gs_vector3 expts;
        const gs_matrix3 *pmat = NULL;
        cie_cache_one_step_t one_step =
            cie_cached_abc_is_one_step(pcie, &pmat);

        pciec = (const gs_cie_common *)pcie;
        if (unitary) {
            switch (one_step) {
            case ONE_STEP_ABC:
                if (CIE_VECTOR3_CACHE_IS_EXPONENTIAL(pcie->caches.DecodeABC.caches, expts))
                    goto calrgb;
                break;
            case ONE_STEP_LMN:
                if (CIE_SCALAR3_CACHE_IS_EXPONENTIAL(pcie->common.caches.DecodeLMN, expts))
                    goto calrgb;
            default:
                break;
            }
        }
        if (cie_is_lab(pcie)) {
            /* Represent this as a Lab space. */
            pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
            if (pcd == 0)
                return_error(gs_error_VMerror);
            code = pdf_put_lab_color_space(pca, pcd, pcie->RangeABC.ranges);
            goto cal;
        } else {
            code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ", pciec,
                                         pcie->RangeABC.ranges,
                                         one_step, pmat, &ranges);
            break;
        }
calrgb:
        code = cos_array_add(pca, cos_c_string_value(&v, "/CalRGB"));
        if (code < 0)
            return code;
        pcd = cos_dict_alloc(pdev, "pdf_color_space(dict)");
        if (pcd == 0)
            return_error(gs_error_VMerror);
        if (expts.u != 1 || expts.v != 1 || expts.w != 1) {
            code = cos_dict_put_c_key_vector3(pcd, "/Gamma", &expts);
            if (code < 0)
                return code;
        }
        if (!pmat->is_identity) {
            cos_array_t *pcma =
                cos_array_alloc(pdev, "pdf_color_space(Matrix)");

            if (pcma == 0)
                return_error(gs_error_VMerror);
            if ((code = cos_array_add_vector3(pcma, &pmat->cu)) < 0 ||
                    (code = cos_array_add_vector3(pcma, &pmat->cv)) < 0 ||
                    (code = cos_array_add_vector3(pcma, &pmat->cw)) < 0 ||
                    (code = cos_dict_put(pcd, (const byte *)"/Matrix", 7,
                                         COS_OBJECT_VALUE(&v, pcma))) < 0
               )
                return code;
        }
    }
    goto cal;

    case gs_color_space_index_CIEDEF:
        code = pdf_convert_cie_space(pdev, pca, pcs, "RGB ",
                                     (const gs_cie_common *)pcs->params.def,
                                     pcs->params.def->RangeDEF.ranges,
                                     ONE_STEP_NOT, NULL, &ranges);
        break;

    case gs_color_space_index_CIEDEFG:
        code = pdf_convert_cie_space(pdev, pca, pcs, "CMYK",
                                     (const gs_cie_common *)pcs->params.defg,
                                     pcs->params.defg->RangeDEFG.ranges,
                                     ONE_STEP_NOT, NULL, &ranges);
        break;

    case gs_color_space_index_Indexed:
        code = pdf_indexed_color_space(pdev, pvalue, pcs, pca);
        break;

    case gs_color_space_index_DeviceN:
        if (!pdev->PreserveDeviceN)
            return_error(gs_error_rangecheck);
        if (pdev->CompatibilityLevel < 1.3)
            return_error(gs_error_rangecheck);
        pfn = gs_cspace_get_devn_function(pcs);
        /****** CURRENTLY WE ONLY HANDLE Functions ******/
        if (pfn == 0)
            return_error(gs_error_rangecheck);
        {
            cos_array_t *psna =
                cos_array_alloc(pdev, "pdf_color_space(DeviceN)");
            int i;
            byte *name_string;
            uint name_string_length;
            cos_value_t v_attriburtes, *va = NULL;

            if (psna == 0)
                return_error(gs_error_VMerror);
            for (i = 0; i < pcs->params.device_n.num_components; ++i) {
                if ((code = pcs->params.device_n.get_colorname_string(
                                pdev->memory,
                                pcs->params.device_n.names[i], &name_string,
                                &name_string_length)) < 0 ||
                        (code = pdf_string_to_cos_name(pdev, name_string,
                                                       name_string_length, &v)) < 0 ||
                        (code = cos_array_add_no_copy(psna, &v)) < 0)
                    return code;
            }
            COS_OBJECT_VALUE(&v, psna);
            if (pcs->params.device_n.colorants != NULL) {
                cos_dict_t *colorants  = cos_dict_alloc(pdev, "pdf_color_space(DeviceN)");
                cos_value_t v_colorants, v_separation, v_colorant_name;
                const gs_device_n_attributes *csa;
                pdf_resource_t *pres_attributes;

                if (colorants == NULL)
                    return_error(gs_error_VMerror);
                code = pdf_alloc_resource(pdev, resourceOther, 0, &pres_attributes, -1);
                if (code < 0)
                    return code;
                cos_become(pres_attributes->object, cos_type_dict);
                COS_OBJECT_VALUE(&v_colorants, colorants);
                code = cos_dict_put((cos_dict_t *)pres_attributes->object,
                                    (const byte *)"/Colorants", 10, &v_colorants);
                if (code < 0)
                    return code;
                for (csa = pcs->params.device_n.colorants; csa != NULL; csa = csa->next) {
                    code = pcs->params.device_n.get_colorname_string(pdev->memory,
                            csa->colorant_name, &name_string, &name_string_length);
                    if (code < 0)
                        return code;
                    code = pdf_color_space_named(pdev, &v_separation, NULL, csa->cspace, pcsn, false, NULL, 0);
                    if (code < 0)
                        return code;
                    code = pdf_string_to_cos_name(pdev, name_string, name_string_length, &v_colorant_name);
                    if (code < 0)
                        return code;
                    code = cos_dict_put(colorants, v_colorant_name.contents.chars.data,
                                        v_colorant_name.contents.chars.size, &v_separation);
                    if (code < 0)
                        return code;
                }
                code = pdf_substitute_resource(pdev, &pres_attributes, resourceOther, NULL, true);
                if (code < 0)
                    return code;
                pres_attributes->where_used |= pdev->used_mask;
                va = &v_attriburtes;
                COS_OBJECT_VALUE(va, pres_attributes->object);
            }
            if ((code = pdf_separation_color_space(pdev, pca, "/DeviceN", &v,
                                                   pcs->base_space,
                                                   pfn, &pdf_color_space_names, va)) < 0)
                return code;
        }
        break;

    case gs_color_space_index_Separation:
        if (!pdev->PreserveSeparation)
            return_error(gs_error_rangecheck);
        pfn = gs_cspace_get_sepr_function(pcs);
        /****** CURRENTLY WE ONLY HANDLE Functions ******/
        if (pfn == 0)
            return_error(gs_error_rangecheck);
        {
            byte *name_string;
            uint name_string_length;
            if ((code = pcs->params.separation.get_colorname_string(
                            pdev->memory,
                            pcs->params.separation.sep_name, &name_string,
                            &name_string_length)) < 0 ||
                    (code = pdf_string_to_cos_name(pdev, name_string,
                                                   name_string_length, &v)) < 0 ||
                    (code = pdf_separation_color_space(pdev, pca, "/Separation", &v,
                            pcs->base_space,
                            pfn, &pdf_color_space_names, NULL)) < 0)
                return code;
        }
        break;

    case gs_color_space_index_Pattern:
        if ((code = pdf_color_space_named(pdev, pvalue, ppranges,
                                          pcs->base_space,
                                          &pdf_color_space_names, false, NULL, 0)) < 0 ||
                (code = cos_array_add(pca,
                                      cos_c_string_value(&v, "/Pattern"))) < 0 ||
                (code = cos_array_add(pca, pvalue)) < 0
           )
            return code;
        break;

    default:
        return_error(gs_error_rangecheck);
    }

    /*
     * Register the color space as a resource, since it must be referenced
     * by name rather than directly.
     */
    {
        pdf_color_space_t *ppcs;

        if (code < 0 ||
                (code = pdf_alloc_resource(pdev, resourceColorSpace, pcs->id,
                                           &pres, -1)) < 0
           ) {
            COS_FREE(pca, "pdf_color_space");
            return code;
        }
        pdf_reserve_object_id(pdev, pres, 0);
        if (res_name != NULL) {
            int l = min(name_length, sizeof(pres->rname) - 1);

            memcpy(pres->rname, res_name, l);
            pres->rname[l] = 0;
        }
        ppcs = (pdf_color_space_t *)pres;
        if (serialized == serialized0) {
            serialized = gs_alloc_bytes(pdev->pdf_memory, serialized_size, "pdf_color_space");
            if (serialized == NULL)
                return_error(gs_error_VMerror);
            memcpy(serialized, serialized0, serialized_size);
        }
        ppcs->serialized = serialized;
        ppcs->serialized_size = serialized_size;
        if (ranges) {
            int num_comp = gs_color_space_num_components(pcs);
            gs_range_t *copy_ranges = (gs_range_t *)
                                      gs_alloc_byte_array(pdev->pdf_memory, num_comp,
                                              sizeof(gs_range_t), "pdf_color_space");

            if (copy_ranges == 0) {
                COS_FREE(pca, "pdf_color_space");
                return_error(gs_error_VMerror);
            }
            memcpy(copy_ranges, ranges, num_comp * sizeof(gs_range_t));
            ppcs->ranges = copy_ranges;
            if (ppranges)
                *ppranges = copy_ranges;
        } else
            ppcs->ranges = 0;
        pca->id = pres->object->id;
        COS_FREE(pres->object, "pdf_color_space");
        pres->object = (cos_object_t *)pca;
        cos_write_object(COS_OBJECT(pca), pdev, resourceColorSpace);
    }
ret:
    if (by_name) {
        /* Return a resource name rather than an object reference. */
        discard(COS_RESOURCE_VALUE(pvalue, pca));
    } else
        discard(COS_OBJECT_VALUE(pvalue, pca));
    if (pres != NULL) {
        pres->where_used |= pdev->used_mask;
        code = pdf_add_resource(pdev, pdev->substream_Resources, "/ColorSpace", pres);
        if (code < 0)
            return code;
    }
    return 0;
}