diff options
Diffstat (limited to 'devices/gdevgprf.c')
-rw-r--r-- | devices/gdevgprf.c | 1332 |
1 files changed, 0 insertions, 1332 deletions
diff --git a/devices/gdevgprf.c b/devices/gdevgprf.c deleted file mode 100644 index 492b1c24f..000000000 --- a/devices/gdevgprf.c +++ /dev/null @@ -1,1332 +0,0 @@ -/* Copyright (C) 2001-2019 Artifex Software, Inc. - All Rights Reserved. - - This software is provided AS-IS with no warranty, either express or - implied. - - This software is distributed under license and may not be copied, - modified or distributed except as expressly authorized under the terms - of the license contained in the file LICENSE in this distribution. - - Refer to licensing information at http://www.artifex.com or contact - Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, - CA 94945, U.S.A., +1(415)492-9861, for further information. -*/ - - -/* gprf device, based upon the gdevpsd.c code. */ - -#include "math_.h" -#include "zlib.h" -#include "gdevprn.h" -#include "gsparam.h" -#include "gscrd.h" -#include "gscrdp.h" -#include "gxlum.h" -#include "gdevdcrd.h" -#include "gstypes.h" -#include "gxdcconv.h" -#include "gdevdevn.h" -#include "gsequivc.h" -#include "gscms.h" -#include "gsicc_cache.h" -#include "gsicc_manage.h" -#include "gxgetbit.h" -#include "gdevppla.h" -#include "gxdownscale.h" -#include "gdevdevnprn.h" -#include "gxdevsop.h" - -#ifndef MAX_CHAN -# define MAX_CHAN 15 -#endif - -/* Define the device parameters. */ -#ifndef X_DPI -# define X_DPI 72 -#endif -#ifndef Y_DPI -# define Y_DPI 72 -#endif - -#define MAX_COLOR_VALUE 255 /* We are using 8 bits per colorant */ - - -/* The device descriptor */ -static dev_proc_open_device(gprf_prn_open); -static dev_proc_close_device(gprf_prn_close); -static dev_proc_get_params(gprf_get_params); -static dev_proc_put_params(gprf_put_params); -static dev_proc_print_page(gprf_print_page); -static dev_proc_get_color_mapping_procs(get_gprf_color_mapping_procs); -static dev_proc_get_color_comp_index(gprf_get_color_comp_index); - -/* - * A structure definition for a DeviceN type device - */ -typedef struct gprf_device_s { - gx_devn_prn_device_common; - gx_downscaler_params downscale; - int max_spots; - bool lock_colorants; - gsicc_link_t *icclink; - bool warning_given; /* Used to notify the user that max colorants reached */ -} gprf_device; - -/* GC procedures */ -static -ENUM_PTRS_WITH(gprf_device_enum_ptrs, gprf_device *pdev) -{ - ENUM_PREFIX(st_gx_devn_prn_device, 0); - (void)pdev; /* Stop unused var warning */ - return 0; -} -ENUM_PTRS_END - -static RELOC_PTRS_WITH(gprf_device_reloc_ptrs, gprf_device *pdev) -{ - RELOC_PREFIX(st_gx_devn_prn_device); - (void)pdev; /* Stop unused var warning */ -} -RELOC_PTRS_END - -static int -gprf_spec_op(gx_device *dev_, int op, void *data, int datasize) -{ - if (op == gxdso_supports_devn) { - return true; - } - if (op == gxdso_supports_iccpostrender) { - return true; - } - return gx_default_dev_spec_op(dev_, op, data, datasize); -} - -/* Even though gprf_device_finalize is the same as gx_devn_prn_device_finalize, - * we need to implement it separately because st_composite_final - * declares all 3 procedures as private. */ -static void -gprf_device_finalize(const gs_memory_t *cmem, void *vpdev) -{ - gx_devn_prn_device_finalize(cmem, vpdev); -} - -gs_private_st_composite_final(st_gprf_device, gprf_device, - "gprf_device", gprf_device_enum_ptrs, gprf_device_reloc_ptrs, - gprf_device_finalize); - -/* - * Macro definition for gprf device procedures - */ -#define device_procs(get_color_mapping_procs)\ -{ gprf_prn_open,\ - gx_default_get_initial_matrix,\ - NULL, /* sync_output */\ - /* Since the print_page doesn't alter the device, this device can print in the background */\ - gdev_prn_bg_output_page, /* output_page */\ - gprf_prn_close, /* close */\ - NULL, /* map_rgb_color - not used */\ - NULL, /* map_color_rgb */\ - NULL, /* fill_rectangle */\ - NULL, /* tile_rectangle */\ - NULL, /* copy_mono */\ - NULL, /* copy_color */\ - NULL, /* draw_line */\ - NULL, /* get_bits */\ - gprf_get_params, /* get_params */\ - gprf_put_params, /* put_params */\ - NULL, /* map_cmyk_color - not used */\ - NULL, /* get_xfont_procs */\ - NULL, /* get_xfont_device */\ - NULL, /* map_rgb_alpha_color */\ - gx_page_device_get_page_device, /* get_page_device */\ - NULL, /* get_alpha_bits */\ - NULL, /* copy_alpha */\ - NULL, /* get_band */\ - NULL, /* copy_rop */\ - NULL, /* fill_path */\ - NULL, /* stroke_path */\ - NULL, /* fill_mask */\ - NULL, /* fill_trapezoid */\ - NULL, /* fill_parallelogram */\ - NULL, /* fill_triangle */\ - NULL, /* draw_thin_line */\ - NULL, /* begin_image */\ - NULL, /* image_data */\ - NULL, /* end_image */\ - NULL, /* strip_tile_rectangle */\ - NULL, /* strip_copy_rop */\ - NULL, /* get_clipping_box */\ - NULL, /* begin_typed_image */\ - NULL, /* get_bits_rectangle */\ - NULL, /* map_color_rgb_alpha */\ - NULL, /* create_compositor */\ - NULL, /* get_hardware_params */\ - NULL, /* text_begin */\ - NULL, /* finish_copydevice */\ - NULL, /* begin_transparency_group */\ - NULL, /* end_transparency_group */\ - NULL, /* begin_transparency_mask */\ - NULL, /* end_transparency_mask */\ - NULL, /* discard_transparency_layer */\ - get_color_mapping_procs, /* get_color_mapping_procs */\ - gprf_get_color_comp_index, /* get_color_comp_index */\ - gx_devn_prn_encode_color, /* encode_color */\ - gx_devn_prn_decode_color, /* decode_color */\ - NULL, /* pattern_manage */\ - NULL, /* fill_rectangle_hl_color */\ - NULL, /* include_color_space */\ - NULL, /* fill_linear_color_scanline */\ - NULL, /* fill_linear_color_trapezoid */\ - NULL, /* fill_linear_color_triangle */\ - gx_devn_prn_update_spot_equivalent_colors, /* update_spot_equivalent_colors */\ - gx_devn_prn_ret_devn_params, /* ret_devn_params */\ - NULL, /* fillpage */\ - NULL, /* push_transparency_state */\ - NULL, /* pop_transparency_state */\ - NULL, /* put_image */\ - gprf_spec_op /* dev_spec_op */\ -} - -#define gprf_device_body(procs, dname, ncomp, pol, depth, mg, mc, sl, cn)\ - std_device_full_body_type_extended(gprf_device, &procs, dname,\ - &st_gprf_device,\ - (int)((long)(DEFAULT_WIDTH_10THS) * (X_DPI) / 10),\ - (int)((long)(DEFAULT_HEIGHT_10THS) * (Y_DPI) / 10),\ - X_DPI, Y_DPI,\ - GX_DEVICE_COLOR_MAX_COMPONENTS, /* MaxComponents */\ - ncomp, /* NumComp */\ - pol, /* Polarity */\ - depth, 0, /* Depth, GrayIndex */\ - mg, mc, /* MaxGray, MaxColor */\ - mg + 1, mc + 1, /* DitherGray, DitherColor */\ - sl, /* Linear & Separable? */\ - cn, /* Process color model name */\ - 0, 0, /* offsets */\ - 0, 0, 0, 0 /* margins */\ - ),\ - prn_device_body_rest_(gprf_print_page) - -/* - * CMYK process color model and spot color support. - */ -static const gx_device_procs spot_cmyk_procs - = device_procs(get_gprf_color_mapping_procs); - -const gprf_device gs_gprf_device = -{ - gprf_device_body(spot_cmyk_procs, "gprf", - ARCH_SIZEOF_GX_COLOR_INDEX, /* Number of components - need a nominal 1 bit for each */ - GX_CINFO_POLARITY_SUBTRACTIVE, - ARCH_SIZEOF_GX_COLOR_INDEX * 8, /* 8 bits per component (albeit in planes) */ - 255, 255, GX_CINFO_SEP_LIN, "DeviceCMYK"), - /* devn_params specific parameters */ - { 8, /* Bits per color - must match ncomp, depth, etc. above */ - DeviceCMYKComponents, /* Names of color model colorants */ - 4, /* Number colorants for CMYK */ - 0, /* MaxSeparations has not been specified */ - -1, /* PageSpotColors has not been specified */ - {0}, /* SeparationNames */ - 0, /* SeparationOrder names */ - {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */ - }, - { true }, /* equivalent CMYK colors for spot colors */ - /* gprf device specific parameters */ - GX_DOWNSCALER_PARAMS_DEFAULTS, - GS_SOFT_MAX_SPOTS, /* max_spots */ - false, /* colorants not locked */ - 0, /* ICC link */ -}; - -/* Open the gprf device */ -int -gprf_prn_open(gx_device * pdev) -{ - gprf_device *pdev_gprf = (gprf_device *) pdev; - int code; - int k; - bool force_pdf, force_ps; - cmm_dev_profile_t *profile_struct; - gsicc_rendering_param_t rendering_params; - -#ifdef TEST_PAD_AND_ALIGN - pdev->pad = 5; - pdev->log2_align_mod = 6; -#endif - - /* 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 (code < 0) - return code; - - 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 - } - pdev_gprf->warning_given = false; - /* With planar the depth can be more than 64. Update the color - info to reflect the proper depth and number of planes. Also note - that the number of spot colors can change from page to page. - Update things so that we only output separations for the - inks on that page. */ - - if ((pdev_gprf->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_gprf->devn_params.separations.num_separations - + pdev_gprf->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 { - /* Use the information that is in the page spot color. We should - be here if we are processing a PDF and we do not have a DeviceN - ICC profile specified for output */ - if (!(pdev_gprf->lock_colorants)) { - pdev->color_info.num_components = - (pdev_gprf->devn_params.page_spot_colors - + pdev_gprf->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_gprf->lock_colorants)) { - int num_comp = pdev_gprf->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_gprf->devn_params.num_separation_order_names == 0) - for (k = 0; k < GS_CLIENT_COLOR_MAX_COMPONENTS; k++) { - pdev_gprf->devn_params.separation_order_map[k] = k; - } - pdev->color_info.depth = pdev->color_info.num_components * - pdev_gprf->devn_params.bitspercomponent; - pdev->color_info.separable_and_linear = GX_CINFO_SEP_LIN; - profile_struct->supports_devn = true; - code = gdev_prn_open_planar(pdev, true); - - /* Take care of the ICC transform now. There are several possible ways - * that this could go. One is that the CMYK colors are color managed - * but the non-standard colorants are not. That is, we have specified - * a CMYK profile for our device but we have other spot colorants in - * the source file. In this case, we will do managed proofing for the - * CMYK colorants and use the equivalent CMYK values for the spot colorants. - * DeviceN colorants will be problematic in this case and we will do the - * the best we can with the tools given to us. The other possibility is - * that someone has given an NColor ICC profile for the device and we can - * actually deal with the mapping directly. This is a much cleaner case - * but as we know NColor profiles are not too common. Also we need to - * deal with transparent colorants (e.g. varnish) in an intelligent manner. - * Note that we require the post rendering profile to be RGB based for - * this particular device. */ - - if (pdev_gprf->icclink == NULL && profile_struct->device_profile[0] != NULL - && profile_struct->postren_profile != NULL && - profile_struct->postren_profile->data_cs == gsRGB) { - 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; - pdev_gprf->icclink = gsicc_alloc_link_dev(pdev_gprf->memory, - profile_struct->device_profile[0], profile_struct->postren_profile, - &rendering_params); - if (pdev_gprf->icclink == NULL) - code = gs_error_VMerror; - } - return code; -} - -/* Color mapping routines */ - -/* -* The following procedures are used to map the standard color spaces into -* the color components. This is not where the color management occurs. These -* may do a reordering of the colors following some ICC base color management -* or they may be used in the case of -dUseFastColor as that relies upon the -* device color mapping procedures -*/ -static void -gray_cs_to_gprf_cm(gx_device * dev, frac gray, frac out[]) -{ - int * map = ((gprf_device *)dev)->devn_params.separation_order_map; - gray_cs_to_devn_cm(dev, map, gray, out); -} - -static void -rgb_cs_to_gprf_cm(gx_device * dev, const gs_gstate *pgs, frac r, frac g, - frac b, frac out[]) -{ - int * map = ((gprf_device *)dev)->devn_params.separation_order_map; - rgb_cs_to_devn_cm(dev, map, pgs, r, g, b, out); -} - -static void -cmyk_cs_to_gprf_cm(gx_device * dev, frac c, frac m, frac y, frac k, frac out[]) -{ - const gs_devn_params *devn = &(((gprf_device *) dev)->devn_params); - const int *map = devn->separation_order_map; - int j; - - if (devn->num_separation_order_names > 0) { - /* This is to set only those that we are using */ - for (j = 0; j < devn->num_separation_order_names; j++) { - switch (map[j]) { - case 0: - out[0] = c; - break; - case 1: - out[1] = m; - break; - case 2: - out[2] = y; - break; - case 3: - out[3] = k; - break; - default: - break; - } - } - } - else { - cmyk_cs_to_devn_cm(dev, map, c, m, y, k, out); - } -} - -static const gx_cm_color_map_procs gprf_cm_procs = { - gray_cs_to_gprf_cm, rgb_cs_to_gprf_cm, cmyk_cs_to_gprf_cm -}; - -/* - * These are the handlers for returning the list of color space - * to color model conversion routines. - */ -static const gx_cm_color_map_procs * -get_gprf_color_mapping_procs(const gx_device * dev) -{ - return &gprf_cm_procs; -} - -/* Get parameters. We provide a default CRD. */ -static int -gprf_get_params(gx_device * pdev, gs_param_list * plist) -{ - gprf_device *xdev = (gprf_device *)pdev; - int code; - - code = gx_devn_prn_get_params(pdev, plist); - if (code < 0) - return code; - - code = gx_downscaler_write_params(plist, &xdev->downscale, 0); - if (code < 0) - return code; - code = param_write_int(plist, "MaxSpots", &xdev->max_spots); - if (code < 0) - return code; - code = param_write_bool(plist, "LockColorants", &xdev->lock_colorants); - return code; -} - -/* Set parameters. We allow setting the number of bits per component. */ -static int -gprf_put_params(gx_device * pdev, gs_param_list * plist) -{ - gprf_device * const pdevn = (gprf_device *) pdev; - int code = 0; - - gx_device_color_info save_info = pdevn->color_info; - - code = gx_downscaler_read_params(plist, &pdevn->downscale, 0); - if (code < 0) - return code; - - switch (code = param_read_bool(plist, "LockColorants", &(pdevn->lock_colorants))) { - case 0: - break; - case 1: - break; - default: - param_signal_error(plist, "LockColorants", code); - return code; - } - - switch (code = param_read_int(plist, - "MaxSpots", - &pdevn->max_spots)) { - case 0: - if (pdevn->max_spots >= 0 && pdevn->max_spots <= GS_CLIENT_COLOR_MAX_COMPONENTS-4) - break; - emprintf1(pdevn->memory, "MaxSpots must be between 0 and %d\n", - GS_CLIENT_COLOR_MAX_COMPONENTS-4); - code = gs_error_rangecheck; - /* fall through */ - default: - param_signal_error(plist, "MaxSpots", code); - return code; - case 1: - break; - } - code = 0; - - /* handle the standard DeviceN related parameters */ - if (code == 0) - code = gx_devn_prn_put_params(pdev, plist); - - if (code < 0) { - pdev->color_info = save_info; - return code; - } - return code; -} - -/* - * This routine will check to see if the color component name match those - * that are available amoung the current device's color components. - * - * Parameters: - * dev - pointer to device data structure. - * pname - pointer to name (zero termination not required) - * nlength - length of the name - * - * This routine returns a positive value (0 to n) which is the device colorant - * number if the name is found. It returns a negative value if not found. - */ -static int -gprf_get_color_comp_index(gx_device * dev, const char * pname, - int name_size, int component_type) -{ - int index; - gprf_device *pdev = (gprf_device *)dev; - - if (strncmp(pname, "None", name_size) == 0) return -1; - index = gx_devn_prn_get_color_comp_index(dev, pname, name_size, - component_type); - /* This is a one shot deal. That is it will simply post a notice once that - some colorants will be converted due to a limit being reached. It will - not list names of colorants since then I would need to keep track of - which ones I have already mentioned. Also, if someone is fooling with - num_order, then this warning is not given since they should know what - is going on already */ - if (index < 0 && component_type == SEPARATION_NAME && - pdev->warning_given == false && - pdev->devn_params.num_separation_order_names == 0) { - dmlprintf(dev->memory, "**** Max spot colorants reached.\n"); - dmlprintf(dev->memory, "**** Some colorants will be converted to equivalent CMYK values.\n"); - dmlprintf(dev->memory, "**** If this is a Postscript file, try using the -dMaxSpots= option.\n"); - pdev->warning_given = true; - } - return index; -} - -/* ------ Private definitions ------ */ - -typedef struct { - gp_file *f; - - int width; - int height; - int n_extra_channels; - int num_channels; /* base_bytes_pp + any spot colors that are imaged */ - /* Map output channel number to original separation number. */ - int chnl_to_orig_sep[GX_DEVICE_COLOR_MAX_COMPONENTS]; - /* Map output channel number to gx_color_index position. */ - int chnl_to_position[GX_DEVICE_COLOR_MAX_COMPONENTS]; - - gsicc_link_t *icclink; - - unsigned long table_offset; - gx_device_printer *dev; - int deflate_bound; - byte *deflate_block; -} gprf_write_ctx; - -static int -gprf_setup(gprf_write_ctx *xc, gx_device_printer *pdev, gp_file *file, int w, int h, - gsicc_link_t *icclink) -{ - int i; - int spot_count; - z_stream zstm; - gx_devn_prn_device *dev = (gx_devn_prn_device *)pdev; - - xc->f = file; - xc->dev = pdev; - xc->icclink = icclink; - -#define NUM_CMYK_COMPONENTS 4 - for (i = 0; i < GX_DEVICE_COLOR_MAX_COMPONENTS; i++) { - if (dev->devn_params.std_colorant_names[i] == NULL) - break; - } - xc->num_channels = i; - if (dev->devn_params.num_separation_order_names == 0) { - xc->n_extra_channels = dev->devn_params.separations.num_separations; - } else { - /* Have to figure out how many in the order list were not std - colorants */ - spot_count = 0; - for (i = 0; i < dev->devn_params.num_separation_order_names; i++) { - if (dev->devn_params.separation_order_map[i] >= NUM_CMYK_COMPONENTS) { - spot_count++; - } - } - xc->n_extra_channels = spot_count; - } - xc->width = w; - xc->height = h; - /* - * Determine the order of the output components. This is based upon - * the SeparationOrder parameter. This parameter can be used to select - * which planes are actually imaged. For the process color model channels - * we image the channels which are requested. Non requested process color - * model channels are simply filled with white. For spot colors we only - * image the requested channels. - */ - for (i = 0; i < xc->num_channels + xc->n_extra_channels; i++) { - xc->chnl_to_position[i] = i; - xc->chnl_to_orig_sep[i] = i; - } - /* If we had a specify order name, then we may need to adjust things */ - if (dev->devn_params.num_separation_order_names > 0) { - for (i = 0; i < dev->devn_params.num_separation_order_names; i++) { - int sep_order_num = dev->devn_params.separation_order_map[i]; - if (sep_order_num >= NUM_CMYK_COMPONENTS) { - xc->chnl_to_position[xc->num_channels] = sep_order_num; - xc->chnl_to_orig_sep[xc->num_channels++] = sep_order_num; - } - } - } else { - xc->num_channels += dev->devn_params.separations.num_separations; - } - - zstm.zalloc = NULL; - zstm.zfree = NULL; - zstm.opaque = NULL; - deflateInit(&zstm, Z_BEST_SPEED); - xc->deflate_bound = deflateBound(&zstm, 256*256); - deflateEnd(&zstm); - xc->deflate_block = gs_alloc_bytes(dev->memory, xc->deflate_bound, "gprf_setup"); - - return (xc->deflate_block != NULL); -} - -/* All multi-byte quantities are stored LSB-first! */ -#if ARCH_IS_BIG_ENDIAN -# define assign_u16(a,v) a = ((v) >> 8) + ((v) << 8) -# define assign_u32(a,v) a = (((v) >> 24) & 0xff) + (((v) >> 8) & 0xff00) + (((v) & 0xff00) << 8) + (((v) & 0xff) << 24) -#else -# define assign_u16(a,v) a = (v) -# define assign_u32(a,v) a = (v) -#endif - -static int -gprf_write(gprf_write_ctx *xc, const byte *buf, int size) { - int code; - - code = gp_fwrite(buf, 1, size, xc->f); - if (code < size) - return_error(gs_error_ioerror); - return 0; -} - -static int -gprf_write_8(gprf_write_ctx *xc, byte v) -{ - return gprf_write(xc, (byte *)&v, 1); -} - -static int -gprf_write_16(gprf_write_ctx *xc, bits16 v) -{ - bits16 buf; - - assign_u16(buf, v); - return gprf_write(xc, (byte *)&buf, 2); -} - -static int -gprf_write_32(gprf_write_ctx *xc, bits32 v) -{ - bits32 buf; - - assign_u32(buf, v); - return gprf_write(xc, (byte *)&buf, 4); -} - -static int -gprf_write_header(gprf_write_ctx *xc) -{ - int i, code; - int index; - unsigned int offset; - gx_devn_prn_device *dev = (gx_devn_prn_device *)xc->dev; - - code = (unsigned int)gp_ftell(xc->f); - if (code < 0) - return_error(gs_error_ioerror); - - offset = (unsigned int)code; - - code = gprf_write(xc, (const byte *)"GSPF", 4); /* Signature */ - if (code < 0) - return code; - code = gprf_write_16(xc, 1); /* Version - Always equal to 1*/ - if (code < 0) - return code; - code = gprf_write_16(xc, 0); /* Compression method - 0 (deflated deltas) */ - if (code < 0) - return code; - code = gprf_write_32(xc, xc->width); - if (code < 0) - return code; - code = gprf_write_32(xc, xc->height); - if (code < 0) - return code; - code = gprf_write_16(xc, 8); /* Bits per channel */ - if (code < 0) - return code; - code = gprf_write_16(xc, xc->num_channels); /* Number of separations */ - if (code < 0) - return code; - code = gprf_write_32(xc, 0); /* ICC offset */ - if (code < 0) - return code; - code = gprf_write_32(xc, 0); /* ICC offset */ - if (code < 0) - return code; - code = gprf_write_32(xc, 0); /* Table offset */ - if (code < 0) - return code; - code = gprf_write_32(xc, 0); /* Table offset */ - if (code < 0) - return code; - code = gprf_write_32(xc, 0); /* Reserved */ - if (code < 0) - return code; - code = gprf_write_32(xc, 0); /* Reserved */ - if (code < 0) - return code; - code = gprf_write_32(xc, 0); /* Reserved */ - if (code < 0) - return code; - code = gprf_write_32(xc, 0); /* Reserved */ - if (code < 0) - return code; - code = gprf_write_32(xc, 0); /* Reserved */ - if (code < 0) - return code; - code = gprf_write_32(xc, 0); /* Reserved */ - if (code < 0) - return code; - code = gprf_write_32(xc, 0); /* Reserved */ - if (code < 0) - return code; - - /* Color Mode Data */ - for (i = 0; i < xc->num_channels; i++) - { - int j = xc->chnl_to_orig_sep[i]; - const char *name; - int namelen; - int c, m, y, k; - byte cmyk[4], rgba[4]; - - if (j < NUM_CMYK_COMPONENTS) { - name = dev->devn_params.std_colorant_names[j]; - cmyk[0] = 0; - cmyk[1] = 0; - cmyk[2] = 0; - cmyk[3] = 0; - cmyk[j] = 255; - if (name == NULL) - namelen = 0; - else - namelen = strlen(name); - } else { - index = j - NUM_CMYK_COMPONENTS; - name = (const char *)dev->devn_params.separations.names[index].data; - namelen = dev->devn_params.separations.names[index].size; - c = (2 * 255 * dev->equiv_cmyk_colors.color[index].c + frac_1) / (2 * frac_1); - cmyk[0] = (c < 0 ? 0 : (c > 255 ? 255 : c)); - m = (2 * 255 * dev->equiv_cmyk_colors.color[index].m + frac_1) / (2 * frac_1); - cmyk[1] = (m < 0 ? 0 : (m > 255 ? 255 : m)); - y = (2 * 255 * dev->equiv_cmyk_colors.color[index].y + frac_1) / (2 * frac_1); - cmyk[2] = (y < 0 ? 0 : (y > 255 ? 255 : y)); - k = (2 * 255 * dev->equiv_cmyk_colors.color[index].k + frac_1) / (2 * frac_1); - cmyk[3] = (k < 0 ? 0 : (k > 255 ? 255 : k)); - } - - /* Convert color to RGBA. To get the A value, we are going to need to - deal with the mixing hints information in the PDF content. A ToDo - project. At this point, everything has an alpha of 1.0 */ - rgba[3] = 255; - if (xc->icclink != NULL) { - xc->icclink->procs.map_color((gx_device *)dev, xc->icclink, - &(cmyk[0]), &(rgba[0]), 1); - } else { - /* Something was wrong with the icclink. Use the canned routines. */ - frac rgb_frac[3], cmyk_frac[4]; - int index; - int temp; - - if (j >= NUM_CMYK_COMPONENTS) { - /* Non std. colorant */ - color_cmyk_to_rgb(dev->equiv_cmyk_colors.color[j].c, - dev->equiv_cmyk_colors.color[j].m, - dev->equiv_cmyk_colors.color[j].y, - dev->equiv_cmyk_colors.color[j].k, NULL, rgb_frac, dev->memory); - } else { - /* Std. colorant */ - cmyk_frac[0] = frac_0; - cmyk_frac[1] = frac_0; - cmyk_frac[2] = frac_0; - cmyk_frac[3] = frac_0; - cmyk_frac[j] = frac_1; - color_cmyk_to_rgb(cmyk_frac[0], cmyk_frac[1], cmyk_frac[2], - cmyk_frac[3], NULL, rgb_frac, dev->memory); - } - /* Out of frac and to byte */ - for (index = 0; index < 3; index++) { - temp = (2 * 255 * rgb_frac[index] + frac_1) / (2 * frac_1); - rgba[index] = (temp < 0 ? 0 : (temp > 255 ? 255 : temp)); - } - } - - code = gprf_write_8(xc, rgba[0]); - if (code < 0) - return code; - code = gprf_write_8(xc, rgba[1]); - if (code < 0) - return code; - code = gprf_write_8(xc, rgba[2]); - if (code < 0) - return code; - code = gprf_write_8(xc, rgba[3]); - if (code < 0) - return code; - code = gprf_write_8(xc, cmyk[0]); - if (code < 0) - return code; - code = gprf_write_8(xc, cmyk[1]); - if (code < 0) - return code; - code = gprf_write_8(xc, cmyk[2]); - if (code < 0) - return code; - code = gprf_write_8(xc, cmyk[3]); - if (code < 0) - return code; - - if (namelen > 0) { - code = gprf_write(xc, (const byte *)name, namelen); - if (code < 0) - return code; - } - code = gprf_write_8(xc, 0); - if (code < 0) - return code; - } - - /* FIXME: ICC Profile would go here */ - /* Since MuPDF can't really use the profile and it's optional, at this point - * we will not spend time writing out the profile. */ - /* Update header pointer to table */ - code = (unsigned long)gp_ftell(xc->f); - if (code < 0) - return_error(gs_error_ioerror); - xc->table_offset = (unsigned int) code; - if (gp_fseek(xc->f, offset+28, SEEK_SET) != 0) - return_error (gs_error_ioerror); - code = gprf_write_32(xc, xc->table_offset); - if (code < 0) - return code; - if (gp_fseek(xc->f, xc->table_offset, SEEK_SET) != 0) - return_error(gs_error_ioerror); - return 0; -} - -/* - * Close device and clean up ICC structures. - */ -static int -gprf_prn_close(gx_device *dev) -{ - gprf_device * const xdev = (gprf_device *) dev; - - if (xdev->icclink != NULL) { - xdev->icclink->procs.free_link(xdev->icclink); - gsicc_free_link_dev(xdev->memory, xdev->icclink); - xdev->icclink = NULL; - } - return gdev_prn_close(dev); -} - -static void *my_zalloc(void *opaque, unsigned int items, unsigned int size) -{ - gs_memory_t *mem = (gs_memory_t *)opaque; - return gs_alloc_bytes(mem, items * size, "gprf_zalloc"); -} - -static void my_zfree(void *opaque, void *addr) -{ - gs_memory_t *mem = (gs_memory_t *)opaque; - gs_free_object(mem, addr, "gprf_zalloc"); -} - -static int -updateTable(gprf_write_ctx *xc) -{ - int offset, code; - - /* Read the current position of the file */ - offset = gp_ftell(xc->f); - if (offset < 0) - return_error(gs_error_ioerror); - - /* Put that value into the table */ - if (gp_fseek(xc->f, xc->table_offset, SEEK_SET) != 0) - return_error(gs_error_ioerror); - - code = gprf_write_32(xc, offset); - if (code < 0) - return code; - - code = gprf_write_32(xc, 0); - if (code < 0) - return code; - - xc->table_offset += 8; - - /* Seek back to where we were before */ - if (gp_fseek(xc->f, offset, SEEK_SET) != 0) - return_error(gs_error_ioerror); - return 0; -} - -static int -compressAndWrite(gprf_write_ctx *xc, byte *data, int tile_w, int tile_h, int raster) -{ - int x, y, code; - int delta = 0; - byte *row_d; - int orr = 0; - z_stream zstm; - - code = updateTable(xc); - if (code < 0) - return code; - - /* Delta the data (and check for non-zero) */ - row_d = data; - for (y = 0; y < tile_h; y++) - { - byte *d = row_d; - for (x = 0; x < tile_w; x++) - { - int del = *d; - orr |= *d; - *d++ -= delta; - delta = del; - } - row_d += raster; - } - - /* If the separation is blank, no need to write anything more */ - if (orr == 0) - return 0; - - /* Now we need to compress the data and write it. */ - zstm.zalloc = my_zalloc; - zstm.zfree = my_zfree; - zstm.opaque = xc->dev->memory; - deflateInit(&zstm, Z_BEST_SPEED); - zstm.avail_out = xc->deflate_bound; - zstm.next_out = xc->deflate_block; - - row_d = data; - for (y = 0; y < tile_h; y++) - { - zstm.avail_in = tile_w; - zstm.next_in = row_d; - deflate(&zstm, Z_NO_FLUSH); - row_d += raster; - } - deflate(&zstm, Z_FINISH); - deflateEnd(&zstm); - - code = gprf_write(xc, xc->deflate_block, xc->deflate_bound - zstm.avail_out); - if (code < 0) - return_error(gs_error_ioerror); - return 0; -} - -/* If the profile is NULL or if the profile does not support the spot - colors then we have to calculate the equivalent CMYK values and then color - manage. */ -static void -build_cmyk_planar_raster(gprf_write_ctx *xc, byte *planes[], byte *cmyk_in, - int raster, int ypos, cmyk_composite_map * cmyk_map) -{ - int pixel, comp_num; - uint temp, cyan, magenta, yellow, black; - cmyk_composite_map * cmyk_map_entry; - int num_comp = xc->num_channels; - byte *cmyk = cmyk_in; - - for (pixel = 0; pixel < raster; pixel++) { - cmyk_map_entry = cmyk_map; - /* Get the first one */ - temp = *(planes[xc->chnl_to_position[0]] + ypos * raster + pixel); - cyan = cmyk_map_entry->c * temp; - magenta = cmyk_map_entry->m * temp; - yellow = cmyk_map_entry->y * temp; - black = cmyk_map_entry->k * temp; - cmyk_map_entry++; - /* Add in the contributions from the rest */ - for (comp_num = 1; comp_num < num_comp; comp_num++) { - temp = *(planes[xc->chnl_to_position[comp_num]] + ypos * raster + pixel); - cyan += cmyk_map_entry->c * temp; - magenta += cmyk_map_entry->m * temp; - yellow += cmyk_map_entry->y * temp; - black += cmyk_map_entry->k * temp; - cmyk_map_entry++; - } - cyan /= frac_1; - magenta /= frac_1; - yellow /= frac_1; - black /= frac_1; - if (cyan > MAX_COLOR_VALUE) - cyan = MAX_COLOR_VALUE; - if (magenta > MAX_COLOR_VALUE) - magenta = MAX_COLOR_VALUE; - if (yellow > MAX_COLOR_VALUE) - yellow = MAX_COLOR_VALUE; - if (black > MAX_COLOR_VALUE) - black = MAX_COLOR_VALUE; - /* Now store the CMYK value in the planar buffer */ - cmyk[0] = cyan; - cmyk[raster] = magenta; - cmyk[2 * raster] = yellow; - cmyk[3 * raster] = black; - cmyk++; - } -} - -/* Create RGB from CMYK the horribly slow way */ -static void -get_rgb_planar_line(gprf_write_ctx *xc, byte *c, byte *m, byte *y, byte *k, - byte *red_in, byte *green_in, byte *blue_in, int width) -{ - int x_pos; - int c_val, m_val, y_val, k_val; - gprf_device *gprf_dev = (gprf_device *)xc->dev; - frac rgb_frac[3]; - int temp; - byte *rp = red_in; - byte *gp = green_in; - byte *bp = blue_in; - - for (x_pos = 0; x_pos < width; x_pos++) { - - c_val = (int)((long)(*c++)* frac_1 / 255.0); - c_val = (c_val < 0 ? 0 : (c_val > frac_1 ? frac_1 : c_val)); - - m_val = (int)((long)(*m++)* frac_1 / 255.0); - m_val = (m_val < 0 ? 0 : (m_val > frac_1 ? frac_1 : m_val)); - - y_val = (int)((long)(*y++)* frac_1 / 255.0); - y_val = (y_val < 0 ? 0 : (y_val > frac_1 ? frac_1 : y_val)); - - k_val = (int)((long)(*k++)* frac_1 / 255.0); - k_val = (k_val < 0 ? 0 : (k_val > frac_1 ? frac_1 : k_val)); - - color_cmyk_to_rgb(c_val, m_val, y_val, k_val, NULL, rgb_frac, - gprf_dev->memory); - - temp = (2 * 255 * rgb_frac[0] + frac_1) / (2 * frac_1); - temp = (temp < 0 ? 0 : (temp > 255 ? 255 : temp)); - *rp++ = temp; - - temp = (2 * 255 * rgb_frac[1] + frac_1) / (2 * frac_1); - temp = (temp < 0 ? 0 : (temp > 255 ? 255 : temp)); - *gp++ = temp; - - temp = (2 * 255 * rgb_frac[2] + frac_1) / (2 * frac_1); - temp = (temp < 0 ? 0 : (temp > 255 ? 255 : temp)); - *bp++ = temp; - } -} - -/* - * Output the image data for the GPRF device. - */ -static int -gprf_write_image_data(gprf_write_ctx *xc) -{ - gx_device_printer *pdev = xc->dev; - int raster_row = bitmap_raster(pdev->width * 8); - int raster_plane; - byte *planes[GS_CLIENT_COLOR_MAX_COMPONENTS]; - byte *rgb[3]; - byte *cmyk = NULL; - int code = 0; - int i, y; - int chan_idx; - int tiled_w, tiled_h, tile_x, tile_y; - int num_comp = xc->num_channels; - gs_get_bits_params_t params; - gx_downscaler_t ds = { NULL }; - gprf_device *gprf_dev = (gprf_device *)pdev; - bool slowcolor = false; - bool equiv_needed = false; - cmyk_composite_map cmyk_map[GX_DEVICE_COLOR_MAX_COMPONENTS]; - gsicc_bufferdesc_t input_buffer_desc; - gsicc_bufferdesc_t output_buffer_desc; - - /* Get set up for color management */ - /* We are going to deal with four cases for creating the RGB content. - * Case 1: We have a CMYK ICC profile and only CMYK colors. - * Case 2: We have a DeviceN ICC profile, which defines all our colorants - * Case 3: We have a CMYK ICC profile and non-standard spot colorants - * Case 4: There was an issue creating the ICC link - * For Case 1 and Case 2, we will do a direct ICC mapping from the - * planar components to the RGB proofing color. This is the best work - * flow for accurate color proofing. - * For Case 3, we will need to compute the equivalent CMYK color similar - * to what the tiffsep device does and then apply the ICC mapping - * For Case 4, we need to compute the equivalent CMYK color mapping AND - * do the slow conversion to RGB */ - - if (gprf_dev->icclink == NULL) { - /* Case 4 */ - slowcolor = true; - equiv_needed = true; - } else { - if (num_comp > 4 && - gprf_dev->icc_struct->device_profile[0]->data_cs == gsCMYK) { - /* Case 3 */ - equiv_needed = true; - } - } - - /* Return planar data */ - params.options = (GB_RETURN_POINTER | GB_RETURN_COPY | - GB_ALIGN_STANDARD | GB_OFFSET_0 | GB_RASTER_STANDARD | - GB_PACKING_PLANAR | GB_COLORS_NATIVE | GB_ALPHA_NONE); - params.x_offset = 0; - params.raster = raster_row; - - /* For every plane, we need a buffer large enough to let us pull out - * 256 raster lines from that plane. Make contiguous so that we can apply - * color management */ - raster_plane = raster_row * 256; - planes[0] = gs_alloc_bytes(pdev->memory, raster_plane * num_comp, "gprf_write_image_data"); - if (planes[0] == NULL) - return_error(gs_error_VMerror); - - for (chan_idx = 1; chan_idx < num_comp; chan_idx++) - { - planes[chan_idx] = planes[0] + raster_plane * chan_idx; - params.data[chan_idx] = planes[chan_idx]; - } - - /* We also need space for our RGB planes. */ - rgb[0] = gs_alloc_bytes(pdev->memory, raster_plane * 3, - "gprf_write_image_data"); - if (rgb[0] == NULL) - return_error(gs_error_VMerror); - rgb[1] = rgb[0] + raster_plane; - rgb[2] = rgb[0] + raster_plane * 2; - - /* Finally, we may need a temporary CMYK composite if we have no profile - * to handle the spot colorants. Case 3 and Case 4. Also build the mapping - * at this point. Note that this does not need to be the whole tile, just - * a row across as it can be reused */ - if (equiv_needed) { - build_cmyk_map((gx_device*)gprf_dev, num_comp, &gprf_dev->equiv_cmyk_colors, - cmyk_map); - cmyk = gs_alloc_bytes(pdev->memory, raster_row * 4, - "gprf_write_image_data"); - if (cmyk == NULL) - return_error(gs_error_VMerror); - } - - code = gx_downscaler_init_planar(&ds, (gx_device *)pdev, ¶ms, num_comp, - gprf_dev->downscale.downscale_factor, 0, 8, 8); - if (code < 0) - goto cleanup; - - tiled_w = (xc->width + 255) / 256; - tiled_h = (xc->height + 255) / 256; - - /* Reserve space in the table for all the offsets */ - for (i = 8 * tiled_w * tiled_h * (3 + xc->num_channels); i >= 0; i -= 8) { - code = gprf_write_32(xc, 0); - if (code < 0) - return code; - code = gprf_write_32(xc, 0); - if (code < 0) - return code; - } - - /* Print the output planes */ - /* For each row of tiles... */ - for (tile_y = 0; tile_y < tiled_h; tile_y++) { - /* Pull out the data for the tiles in that row. */ - int tile_h = (xc->height - tile_y * 256); - - if (tile_h > 256) - tile_h = 256; - for (y = 0; y < tile_h; y++) { - for (chan_idx = 0; chan_idx < num_comp; chan_idx++) { - params.data[chan_idx] = planes[chan_idx] + y * raster_row; - } - code = gx_downscaler_get_bits_rectangle(&ds, ¶ms, y + tile_y * 256); - if (code < 0) - goto cleanup; - for (chan_idx = 0; chan_idx < num_comp; chan_idx++) { - if (params.data[chan_idx] != planes[chan_idx] + y * raster_row) - memcpy(planes[chan_idx] + y * raster_row, params.data[chan_idx], raster_row); - } - /* Take care of any color management */ - if (equiv_needed) { - build_cmyk_planar_raster(xc, planes, cmyk, raster_row, y, cmyk_map); - /* At this point we have equiv. CMYK data */ - if (slowcolor) { - /* Slowest case, no profile and spots present */ - get_rgb_planar_line(xc, cmyk, cmyk + raster_row, - cmyk + 2 * raster_row, cmyk + 3 * raster_row, - rgb[0] + y * raster_row, rgb[1] + y * raster_row, - rgb[2] + y * raster_row, pdev->width); - } else { - /* ICC approach. Likely a case with spots but CMYK profile */ - /* set up for planar buffer transform */ - gsicc_init_buffer(&input_buffer_desc, 4, 1, false, false, true, - raster_row, raster_row, 1, pdev->width); - gsicc_init_buffer(&output_buffer_desc, 3, 1, false, false, true, - raster_plane, raster_row, 1, pdev->width); - xc->icclink->procs.map_buffer((gx_device *)gprf_dev, - xc->icclink, &input_buffer_desc, &output_buffer_desc, - cmyk, rgb[0] + y * raster_row); - } - } else { - if (slowcolor) { - /* CMYK input but profile likely missing here */ - get_rgb_planar_line(xc, planes[xc->chnl_to_position[0]] + y * raster_row, - planes[xc->chnl_to_position[xc->chnl_to_position[1]]] + y * raster_row, - planes[xc->chnl_to_position[xc->chnl_to_position[2]]] + y * raster_row, - planes[xc->chnl_to_position[xc->chnl_to_position[3]]] + y * raster_row, - rgb[0] + y * raster_row, rgb[1] + y * raster_row, - rgb[2] + y * raster_row, pdev->width); - } else { - /* Fastest case all ICC. Note this could have an issue - if someone reorders the cmyk values. */ - gsicc_init_buffer(&input_buffer_desc, num_comp, 1, false, - false, true, raster_plane, raster_row, 1, pdev->width); - gsicc_init_buffer(&output_buffer_desc, 3, 1, false, false, true, - raster_plane, raster_row, 1, pdev->width); - xc->icclink->procs.map_buffer((gx_device *)gprf_dev, - xc->icclink, &input_buffer_desc, &output_buffer_desc, - planes[0] + y * raster_row, rgb[0] + y * raster_row); - } - } - } - - /* Now, for each tile... */ - for (tile_x = 0; tile_x < tiled_w; tile_x++) { - int tile_w = (xc->width - tile_x * 256); - - if (tile_w > 256) - tile_w = 256; - - /* Now we have to compress and write each separation in turn */ - code = compressAndWrite(xc, rgb[0] + tile_x * 256, tile_w, tile_h, raster_row); - if (code >= 0) - code = compressAndWrite(xc, rgb[1] + tile_x * 256, tile_w, tile_h, raster_row); - if (code >= 0) - code = compressAndWrite(xc, rgb[2] + tile_x * 256, tile_w, tile_h, raster_row); - for (chan_idx = 0; chan_idx < num_comp; chan_idx++) { - int j = xc->chnl_to_position[chan_idx]; - if (code >= 0) - code = compressAndWrite(xc, planes[j] + tile_x * 256, tile_w, tile_h, raster_row); - } - } - } - - /* And put the last entry in the table */ - updateTable(xc); - -cleanup: - gx_downscaler_fin(&ds); - gs_free_object(pdev->memory, planes[0], "gprf_write_image_data"); - gs_free_object(pdev->memory, rgb[0], "gprf_write_image_data"); - gs_free_object(pdev->memory, xc->deflate_block, "gprf_write_image_data"); - if (equiv_needed) { - gs_free_object(pdev->memory, cmyk, "gprf_write_image_data"); - } - return code; -} - -static int -gprf_print_page(gx_device_printer *pdev, gp_file *file) -{ - int code; - - gprf_write_ctx xc; - gprf_device *gprf_dev = (gprf_device *)pdev; - - gprf_setup(&xc, pdev, file, - gx_downscaler_scale(pdev->width, gprf_dev->downscale.downscale_factor), - gx_downscaler_scale(pdev->height, gprf_dev->downscale.downscale_factor), - gprf_dev->icclink); - code = gprf_write_header(&xc); - if (code < 0) - return code; - code = gprf_write_image_data(&xc); - if (code < 0) - return code; - return 0; -} |