tiffsep_prn_open(gx_device * pdev)
{
    gx_device_printer *ppdev = (gx_device_printer *)pdev;
    tiffsep_device *pdev_sep = (tiffsep_device *) pdev;
    int code, k;
    bool force_pdf, force_ps;
    cmm_dev_profile_t *profile_struct;
    gsicc_rendering_param_t rendering_params;

    /* Use our own warning and error message handlers in libtiff */
    tiff_set_handlers();

    /* There are 2 approaches to the use of a DeviceN ICC output profile.
       One is to simply limit our device to only output the colorants
       defined in the output ICC profile.   The other is to use the
       DeviceN ICC profile to color manage those N colorants and
       to let any other separations pass through unmolested.   The define
       LIMIT_TO_ICC sets the option to limit our device to only the ICC
       colorants defined by -sICCOutputColors (or to the ones that are used
       as default names if ICCOutputColors is not used).  The pass through option
       (LIMIT_TO_ICC set to 0) makes life a bit more difficult since we don't
       know if the page_spot_colors overlap with any spot colorants that exist
       in the DeviceN ICC output profile. Hence we don't know how many planes
       to use for our device.  This is similar to the issue when processing
       a PostScript file.  So that I remember, the cases are
       DeviceN Profile?     limit_icc       Result
       0                    0               force_pdf 0 force_ps 0  (no effect)
       0                    0               force_pdf 0 force_ps 0  (no effect)
       1                    0               force_pdf 0 force_ps 1  (colorants not known)
       1                    1               force_pdf 1 force_ps 0  (colorants known)
       */
    code = dev_proc(pdev, get_profile)((gx_device *)pdev, &profile_struct);
    if (profile_struct->spotnames == NULL) {
        force_pdf = false;
        force_ps = false;
    } else {
#if LIMIT_TO_ICC
            force_pdf = true;
            force_ps = false;
#else
            force_pdf = false;
            force_ps = true;
#endif
    }

    /* For the planar device we need to set up the bit depth of each plane.
       For other devices this is handled in check_device_separable where
       we compute the bit shift for the components etc. */
    for (k = 0; k < GS_CLIENT_COLOR_MAX_COMPONENTS; k++) {
        pdev->color_info.comp_bits[k] = 8;
    }

    /* With planar the depth can be more than 64.  Update the color
       info to reflect the proper depth and number of planes */
    pdev_sep->warning_given = false;
    if ((pdev_sep->devn_params.page_spot_colors >= 0 || force_pdf) && !force_ps) {
        if (force_pdf) {
            /* Use the information that is in the ICC profle.  We will be here
               anytime that we have limited ourselves to a fixed number
               of colorants specified by the DeviceN ICC profile */
            pdev->color_info.num_components =
                (pdev_sep->devn_params.separations.num_separations
                 + pdev_sep->devn_params.num_std_colorant_names);
            if (pdev->color_info.num_components > pdev->color_info.max_components)
                pdev->color_info.num_components = pdev->color_info.max_components;
            /* Limit us only to the ICC colorants */
            pdev->color_info.max_components = pdev->color_info.num_components;
        } else {
            /* Do not allow the spot count to update if we have specified the
               colorants already */
            if (!(pdev_sep->lock_colorants)) {
                pdev->color_info.num_components =
                    (pdev_sep->devn_params.page_spot_colors
                    + pdev_sep->devn_params.num_std_colorant_names);
                if (pdev->color_info.num_components > pdev->color_info.max_components)
                    pdev->color_info.num_components = pdev->color_info.max_components;
            }
        }
    } else {
        /* We do not know how many spots may occur on the page.
           For this reason we go ahead and allocate the maximum that we
           have available.  Note, lack of knowledge only occurs in the case
           of PS files.  With PDF we know a priori the number of spot
           colorants.  */
        if (!(pdev_sep->lock_colorants)) {
            int num_comp = pdev_sep->max_spots + 4; /* Spots + CMYK */
            if (num_comp > GS_CLIENT_COLOR_MAX_COMPONENTS)
                num_comp = GS_CLIENT_COLOR_MAX_COMPONENTS;
            pdev->color_info.num_components = num_comp;
            pdev->color_info.max_components = num_comp;
        }
    }
    /* Push this to the max amount as a default if someone has not set it */
    if (pdev_sep->devn_params.num_separation_order_names == 0)
        for (k = 0; k < GS_CLIENT_COLOR_MAX_COMPONENTS; k++) {
            pdev_sep->devn_params.separation_order_map[k] = k;
        }
    pdev->color_info.depth = pdev->color_info.num_components *
                             pdev_sep->devn_params.bitspercomponent;
    pdev->color_info.separable_and_linear = GX_CINFO_SEP_LIN;
    code = gdev_prn_open_planar(pdev, true);
    while (pdev->child)
        pdev = pdev->child;
    ppdev = (gx_device_printer *)pdev;

    ppdev->file = NULL;
    pdev->icc_struct->supports_devn = true;

    /* Set up the icc link settings at this time.  Only CMYK post render profiles
       are allowed */
    code = dev_proc(pdev, get_profile)((gx_device *)pdev, &profile_struct);
    if (code < 0)
        return_error(gs_error_undefined);

    if (profile_struct->postren_profile != NULL &&
        profile_struct->postren_profile->data_cs == gsCMYK) {
        rendering_params.black_point_comp = gsBLACKPTCOMP_ON;
        rendering_params.graphics_type_tag = GS_UNKNOWN_TAG;
        rendering_params.override_icc = false;
        rendering_params.preserve_black = gsBLACKPRESERVE_OFF;
        rendering_params.rendering_intent = gsRELATIVECOLORIMETRIC;
        rendering_params.cmm = gsCMM_DEFAULT;
        if (profile_struct->oi_profile != NULL) {
            pdev_sep->icclink = gsicc_alloc_link_dev(pdev->memory,
                profile_struct->oi_profile, profile_struct->postren_profile,
                &rendering_params);
        } else if (profile_struct->link_profile != NULL) {
            pdev_sep->icclink = gsicc_alloc_link_dev(pdev->memory,
                profile_struct->link_profile, profile_struct->postren_profile,
                &rendering_params);
        } else {
            pdev_sep->icclink = gsicc_alloc_link_dev(pdev->memory,
                profile_struct->device_profile[0], profile_struct->postren_profile,
                &rendering_params);
        }
        /* If it is identity, release it now and set link to NULL */
        if (pdev_sep->icclink->is_identity) {
            pdev_sep->icclink->procs.free_link(pdev_sep->icclink);
            gsicc_free_link_dev(pdev->memory, pdev_sep->icclink);
            pdev_sep->icclink = NULL;
        }
    }
    return code;
}