13ff48bf5SDavid du Colombier /*
2*593dc095SDavid du Colombier Copyright (C) 2001-2004 artofcode LLC.
33ff48bf5SDavid du Colombier
4*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
5*593dc095SDavid du Colombier implied.
63ff48bf5SDavid du Colombier
7*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
8*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
9*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
103ff48bf5SDavid du Colombier
11*593dc095SDavid du Colombier For more information about licensing, please refer to
12*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
13*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
14*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
15*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
163ff48bf5SDavid du Colombier
173ff48bf5SDavid du Colombier Author: Raph Levien <raph@artofcode.com>
183ff48bf5SDavid du Colombier */
19*593dc095SDavid du Colombier /* $Id: gdevp14.c,v 1.35 2005/10/10 18:58:18 leonardo Exp $ */
20*593dc095SDavid du Colombier /* Compositing devices for implementing PDF 1.4 imaging model */
213ff48bf5SDavid du Colombier
223ff48bf5SDavid du Colombier #include "math_.h"
233ff48bf5SDavid du Colombier #include "memory_.h"
243ff48bf5SDavid du Colombier #include "gx.h"
253ff48bf5SDavid du Colombier #include "gserrors.h"
263ff48bf5SDavid du Colombier #include "gscdefs.h"
273ff48bf5SDavid du Colombier #include "gxdevice.h"
283ff48bf5SDavid du Colombier #include "gsdevice.h"
293ff48bf5SDavid du Colombier #include "gsstruct.h"
303ff48bf5SDavid du Colombier #include "gxistate.h"
313ff48bf5SDavid du Colombier #include "gxdcolor.h"
323ff48bf5SDavid du Colombier #include "gxiparam.h"
333ff48bf5SDavid du Colombier #include "gstparam.h"
343ff48bf5SDavid du Colombier #include "gxblend.h"
353ff48bf5SDavid du Colombier #include "gxtext.h"
363ff48bf5SDavid du Colombier #include "gsdfilt.h"
373ff48bf5SDavid du Colombier #include "gsimage.h"
38*593dc095SDavid du Colombier #include "gsrect.h"
393ff48bf5SDavid du Colombier #include "gzstate.h"
403ff48bf5SDavid du Colombier #include "gdevp14.h"
41*593dc095SDavid du Colombier #include "gsovrc.h"
42*593dc095SDavid du Colombier #include "gxcmap.h"
43*593dc095SDavid du Colombier #include "gscolor1.h"
44*593dc095SDavid du Colombier #include "gstrans.h"
45*593dc095SDavid du Colombier #include "gsutil.h"
46*593dc095SDavid du Colombier #include "gxcldev.h"
47*593dc095SDavid du Colombier
48*593dc095SDavid du Colombier /* #define DUMP_TO_PNG */
49*593dc095SDavid du Colombier
50*593dc095SDavid du Colombier #ifdef DUMP_TO_PNG
51*593dc095SDavid du Colombier #include "png_.h"
52*593dc095SDavid du Colombier #endif
533ff48bf5SDavid du Colombier
543ff48bf5SDavid du Colombier # define INCR(v) DO_NOTHING
553ff48bf5SDavid du Colombier
563ff48bf5SDavid du Colombier /* Buffer stack data structure */
573ff48bf5SDavid du Colombier
583ff48bf5SDavid du Colombier #define PDF14_MAX_PLANES 16
593ff48bf5SDavid du Colombier
603ff48bf5SDavid du Colombier /* GC procedures for buffer stack */
613ff48bf5SDavid du Colombier
623ff48bf5SDavid du Colombier private
633ff48bf5SDavid du Colombier ENUM_PTRS_WITH(pdf14_buf_enum_ptrs, pdf14_buf *buf)
643ff48bf5SDavid du Colombier return 0;
653ff48bf5SDavid du Colombier case 0: return ENUM_OBJ(buf->saved);
663ff48bf5SDavid du Colombier case 1: return ENUM_OBJ(buf->data);
67*593dc095SDavid du Colombier case 2: return ENUM_OBJ(buf->transfer_fn);
683ff48bf5SDavid du Colombier ENUM_PTRS_END
693ff48bf5SDavid du Colombier
703ff48bf5SDavid du Colombier private
RELOC_PTRS_WITH(pdf14_buf_reloc_ptrs,pdf14_buf * buf)713ff48bf5SDavid du Colombier RELOC_PTRS_WITH(pdf14_buf_reloc_ptrs, pdf14_buf *buf)
723ff48bf5SDavid du Colombier {
733ff48bf5SDavid du Colombier RELOC_VAR(buf->saved);
743ff48bf5SDavid du Colombier RELOC_VAR(buf->data);
75*593dc095SDavid du Colombier RELOC_VAR(buf->transfer_fn);
763ff48bf5SDavid du Colombier }
773ff48bf5SDavid du Colombier RELOC_PTRS_END
783ff48bf5SDavid du Colombier
793ff48bf5SDavid du Colombier gs_private_st_composite(st_pdf14_buf, pdf14_buf, "pdf14_buf",
803ff48bf5SDavid du Colombier pdf14_buf_enum_ptrs, pdf14_buf_reloc_ptrs);
813ff48bf5SDavid du Colombier
82*593dc095SDavid du Colombier gs_private_st_ptrs2(st_pdf14_ctx, pdf14_ctx, "pdf14_ctx",
833ff48bf5SDavid du Colombier pdf14_ctx_enum_ptrs, pdf14_ctx_reloc_ptrs,
84*593dc095SDavid du Colombier stack, maskbuf);
853ff48bf5SDavid du Colombier
863ff48bf5SDavid du Colombier /* ------ The device descriptors ------ */
873ff48bf5SDavid du Colombier
883ff48bf5SDavid du Colombier /*
893ff48bf5SDavid du Colombier * Default X and Y resolution.
903ff48bf5SDavid du Colombier */
913ff48bf5SDavid du Colombier #define X_DPI 72
923ff48bf5SDavid du Colombier #define Y_DPI 72
933ff48bf5SDavid du Colombier
943ff48bf5SDavid du Colombier private int pdf14_open(gx_device * pdev);
953ff48bf5SDavid du Colombier private dev_proc_close_device(pdf14_close);
963ff48bf5SDavid du Colombier private int pdf14_output_page(gx_device * pdev, int num_copies, int flush);
97*593dc095SDavid du Colombier private dev_proc_put_params(pdf14_put_params);
98*593dc095SDavid du Colombier private dev_proc_encode_color(pdf14_encode_color);
99*593dc095SDavid du Colombier private dev_proc_decode_color(pdf14_decode_color);
1003ff48bf5SDavid du Colombier private dev_proc_fill_rectangle(pdf14_fill_rectangle);
101*593dc095SDavid du Colombier private dev_proc_fill_rectangle(pdf14_mark_fill_rectangle);
102*593dc095SDavid du Colombier private dev_proc_fill_rectangle(pdf14_mark_fill_rectangle_ko_simple);
1033ff48bf5SDavid du Colombier private dev_proc_fill_path(pdf14_fill_path);
1043ff48bf5SDavid du Colombier private dev_proc_stroke_path(pdf14_stroke_path);
1053ff48bf5SDavid du Colombier private dev_proc_begin_typed_image(pdf14_begin_typed_image);
1063ff48bf5SDavid du Colombier private dev_proc_text_begin(pdf14_text_begin);
107*593dc095SDavid du Colombier private dev_proc_create_compositor(pdf14_create_compositor);
108*593dc095SDavid du Colombier private dev_proc_create_compositor(pdf14_forward_create_compositor);
1093ff48bf5SDavid du Colombier private dev_proc_begin_transparency_group(pdf14_begin_transparency_group);
1103ff48bf5SDavid du Colombier private dev_proc_end_transparency_group(pdf14_end_transparency_group);
111*593dc095SDavid du Colombier private dev_proc_begin_transparency_mask(pdf14_begin_transparency_mask);
112*593dc095SDavid du Colombier private dev_proc_end_transparency_mask(pdf14_end_transparency_mask);
1133ff48bf5SDavid du Colombier
114*593dc095SDavid du Colombier private const gx_color_map_procs *
115*593dc095SDavid du Colombier pdf14_get_cmap_procs(const gs_imager_state *, const gx_device *);
116*593dc095SDavid du Colombier
117*593dc095SDavid du Colombier #define XSIZE (int)(8.5 * X_DPI) /* 8.5 x 11 inch page, by default */
118*593dc095SDavid du Colombier #define YSIZE (int)(11 * Y_DPI)
1193ff48bf5SDavid du Colombier
1203ff48bf5SDavid du Colombier /* 24-bit color. */
1213ff48bf5SDavid du Colombier
122*593dc095SDavid du Colombier #define pdf14_procs(get_color_mapping_procs, get_color_comp_index) \
123*593dc095SDavid du Colombier {\
124*593dc095SDavid du Colombier pdf14_open, /* open */\
125*593dc095SDavid du Colombier NULL, /* get_initial_matrix */\
126*593dc095SDavid du Colombier NULL, /* sync_output */\
127*593dc095SDavid du Colombier pdf14_output_page, /* output_page */\
128*593dc095SDavid du Colombier pdf14_close, /* close */\
129*593dc095SDavid du Colombier pdf14_encode_color, /* rgb_map_rgb_color */\
130*593dc095SDavid du Colombier pdf14_decode_color, /* gx_default_rgb_map_color_rgb */\
131*593dc095SDavid du Colombier pdf14_fill_rectangle, /* fill_rectangle */\
132*593dc095SDavid du Colombier NULL, /* tile_rectangle */\
133*593dc095SDavid du Colombier NULL, /* copy_mono */\
134*593dc095SDavid du Colombier NULL, /* copy_color */\
135*593dc095SDavid du Colombier NULL, /* draw_line */\
136*593dc095SDavid du Colombier NULL, /* get_bits */\
137*593dc095SDavid du Colombier NULL, /* get_params */\
138*593dc095SDavid du Colombier pdf14_put_params, /* put_params */\
139*593dc095SDavid du Colombier NULL, /* map_cmyk_color */\
140*593dc095SDavid du Colombier NULL, /* get_xfont_procs */\
141*593dc095SDavid du Colombier NULL, /* get_xfont_device */\
142*593dc095SDavid du Colombier NULL, /* map_rgb_alpha_color */\
143*593dc095SDavid du Colombier NULL, /* get_page_device */\
144*593dc095SDavid du Colombier NULL, /* get_alpha_bits */\
145*593dc095SDavid du Colombier NULL, /* copy_alpha */\
146*593dc095SDavid du Colombier NULL, /* get_band */\
147*593dc095SDavid du Colombier NULL, /* copy_rop */\
148*593dc095SDavid du Colombier pdf14_fill_path, /* fill_path */\
149*593dc095SDavid du Colombier pdf14_stroke_path, /* stroke_path */\
150*593dc095SDavid du Colombier NULL, /* fill_mask */\
151*593dc095SDavid du Colombier NULL, /* fill_trapezoid */\
152*593dc095SDavid du Colombier NULL, /* fill_parallelogram */\
153*593dc095SDavid du Colombier NULL, /* fill_triangle */\
154*593dc095SDavid du Colombier NULL, /* draw_thin_line */\
155*593dc095SDavid du Colombier NULL, /* begin_image */\
156*593dc095SDavid du Colombier NULL, /* image_data */\
157*593dc095SDavid du Colombier NULL, /* end_image */\
158*593dc095SDavid du Colombier NULL, /* strip_tile_rectangle */\
159*593dc095SDavid du Colombier NULL, /* strip_copy_rop, */\
160*593dc095SDavid du Colombier NULL, /* get_clipping_box */\
161*593dc095SDavid du Colombier pdf14_begin_typed_image, /* begin_typed_image */\
162*593dc095SDavid du Colombier NULL, /* get_bits_rectangle */\
163*593dc095SDavid du Colombier NULL, /* map_color_rgb_alpha */\
164*593dc095SDavid du Colombier pdf14_create_compositor, /* create_compositor */\
165*593dc095SDavid du Colombier NULL, /* get_hardware_params */\
166*593dc095SDavid du Colombier pdf14_text_begin, /* text_begin */\
167*593dc095SDavid du Colombier NULL, /* finish_copydevice */\
168*593dc095SDavid du Colombier pdf14_begin_transparency_group,\
169*593dc095SDavid du Colombier pdf14_end_transparency_group,\
170*593dc095SDavid du Colombier pdf14_begin_transparency_mask,\
171*593dc095SDavid du Colombier pdf14_end_transparency_mask,\
172*593dc095SDavid du Colombier NULL, /* discard_transparency_layer */\
173*593dc095SDavid du Colombier get_color_mapping_procs, /* get_color_mapping_procs */\
174*593dc095SDavid du Colombier get_color_comp_index, /* get_color_comp_index */\
175*593dc095SDavid du Colombier pdf14_encode_color, /* encode_color */\
176*593dc095SDavid du Colombier pdf14_decode_color /* decode_color */\
177*593dc095SDavid du Colombier }
1783ff48bf5SDavid du Colombier
179*593dc095SDavid du Colombier private const gx_device_procs pdf14_Gray_procs =
180*593dc095SDavid du Colombier pdf14_procs(gx_default_DevGray_get_color_mapping_procs,
181*593dc095SDavid du Colombier gx_default_DevGray_get_color_comp_index);
1823ff48bf5SDavid du Colombier
183*593dc095SDavid du Colombier private const gx_device_procs pdf14_RGB_procs =
184*593dc095SDavid du Colombier pdf14_procs(gx_default_DevRGB_get_color_mapping_procs,
185*593dc095SDavid du Colombier gx_default_DevRGB_get_color_comp_index);
1863ff48bf5SDavid du Colombier
187*593dc095SDavid du Colombier private const gx_device_procs pdf14_CMYK_procs =
188*593dc095SDavid du Colombier pdf14_procs(gx_default_DevCMYK_get_color_mapping_procs,
189*593dc095SDavid du Colombier gx_default_DevCMYK_get_color_comp_index);
1903ff48bf5SDavid du Colombier
1913ff48bf5SDavid du Colombier gs_private_st_composite_use_final(st_pdf14_device, pdf14_device, "pdf14_device",
1923ff48bf5SDavid du Colombier pdf14_device_enum_ptrs, pdf14_device_reloc_ptrs,
1933ff48bf5SDavid du Colombier gx_device_finalize);
1943ff48bf5SDavid du Colombier
195*593dc095SDavid du Colombier const pdf14_device gs_pdf14_Gray_device = {
196*593dc095SDavid du Colombier std_device_color_stype_body(pdf14_device, &pdf14_Gray_procs, "pdf14gray",
1973ff48bf5SDavid du Colombier &st_pdf14_device,
198*593dc095SDavid du Colombier XSIZE, YSIZE, X_DPI, Y_DPI, 8, 255, 256),
199*593dc095SDavid du Colombier { 0 }
200*593dc095SDavid du Colombier };
201*593dc095SDavid du Colombier
202*593dc095SDavid du Colombier const pdf14_device gs_pdf14_RGB_device = {
203*593dc095SDavid du Colombier std_device_color_stype_body(pdf14_device, &pdf14_RGB_procs, "pdf14RGB",
204*593dc095SDavid du Colombier &st_pdf14_device,
205*593dc095SDavid du Colombier XSIZE, YSIZE, X_DPI, Y_DPI, 24, 255, 256),
206*593dc095SDavid du Colombier { 0 }
207*593dc095SDavid du Colombier };
208*593dc095SDavid du Colombier
209*593dc095SDavid du Colombier const pdf14_device gs_pdf14_CMYK_device = {
210*593dc095SDavid du Colombier std_device_std_color_full_body_type(pdf14_device, &pdf14_CMYK_procs,
211*593dc095SDavid du Colombier "PDF14cmyk", &st_pdf14_device, XSIZE, YSIZE, X_DPI, Y_DPI, 32,
212*593dc095SDavid du Colombier 0, 0, 0, 0, 0, 0),
2133ff48bf5SDavid du Colombier { 0 }
2143ff48bf5SDavid du Colombier };
2153ff48bf5SDavid du Colombier
2163ff48bf5SDavid du Colombier /* GC procedures */
2173ff48bf5SDavid du Colombier private
2183ff48bf5SDavid du Colombier ENUM_PTRS_WITH(pdf14_device_enum_ptrs, pdf14_device *pdev) return 0;
2193ff48bf5SDavid du Colombier case 0: return ENUM_OBJ(pdev->ctx);
2203ff48bf5SDavid du Colombier case 1: ENUM_RETURN(gx_device_enum_ptr(pdev->target));
2213ff48bf5SDavid du Colombier ENUM_PTRS_END
RELOC_PTRS_WITH(pdf14_device_reloc_ptrs,pdf14_device * pdev)2223ff48bf5SDavid du Colombier private RELOC_PTRS_WITH(pdf14_device_reloc_ptrs, pdf14_device *pdev)
2233ff48bf5SDavid du Colombier {
2243ff48bf5SDavid du Colombier RELOC_VAR(pdev->ctx);
2253ff48bf5SDavid du Colombier pdev->target = gx_device_reloc_ptr(pdev->target, gcst);
2263ff48bf5SDavid du Colombier }
2273ff48bf5SDavid du Colombier RELOC_PTRS_END
2283ff48bf5SDavid du Colombier
2293ff48bf5SDavid du Colombier /* ------ Private definitions ------ */
2303ff48bf5SDavid du Colombier
2313ff48bf5SDavid du Colombier /**
2323ff48bf5SDavid du Colombier * pdf14_buf_new: Allocate a new PDF 1.4 buffer.
2333ff48bf5SDavid du Colombier * @n_chan: Number of pixel channels including alpha.
2343ff48bf5SDavid du Colombier *
2353ff48bf5SDavid du Colombier * Return value: Newly allocated buffer, or NULL on failure.
2363ff48bf5SDavid du Colombier **/
2373ff48bf5SDavid du Colombier private pdf14_buf *
pdf14_buf_new(gs_int_rect * rect,bool has_alpha_g,bool has_shape,int n_chan,gs_memory_t * memory)2383ff48bf5SDavid du Colombier pdf14_buf_new(gs_int_rect *rect, bool has_alpha_g, bool has_shape,
2393ff48bf5SDavid du Colombier int n_chan,
2403ff48bf5SDavid du Colombier gs_memory_t *memory)
2413ff48bf5SDavid du Colombier {
2423ff48bf5SDavid du Colombier pdf14_buf *result;
2433ff48bf5SDavid du Colombier int rowstride = (rect->q.x - rect->p.x + 3) & -4;
244*593dc095SDavid du Colombier int height = (rect->q.y - rect->p.y);
2453ff48bf5SDavid du Colombier int n_planes = n_chan + (has_shape ? 1 : 0) + (has_alpha_g ? 1 : 0);
246*593dc095SDavid du Colombier int planestride;
247*593dc095SDavid du Colombier double dsize = (((double) rowstride) * height) * n_planes;
248*593dc095SDavid du Colombier
249*593dc095SDavid du Colombier if (dsize > (double)max_uint)
250*593dc095SDavid du Colombier return NULL;
2513ff48bf5SDavid du Colombier
2523ff48bf5SDavid du Colombier result = gs_alloc_struct(memory, pdf14_buf, &st_pdf14_buf,
2533ff48bf5SDavid du Colombier "pdf14_buf_new");
2543ff48bf5SDavid du Colombier if (result == NULL)
2553ff48bf5SDavid du Colombier return result;
2563ff48bf5SDavid du Colombier
2573ff48bf5SDavid du Colombier result->isolated = false;
2583ff48bf5SDavid du Colombier result->knockout = false;
2593ff48bf5SDavid du Colombier result->has_alpha_g = has_alpha_g;
2603ff48bf5SDavid du Colombier result->has_shape = has_shape;
2613ff48bf5SDavid du Colombier result->rect = *rect;
2623ff48bf5SDavid du Colombier result->n_chan = n_chan;
2633ff48bf5SDavid du Colombier result->n_planes = n_planes;
2643ff48bf5SDavid du Colombier result->rowstride = rowstride;
265*593dc095SDavid du Colombier result->transfer_fn = NULL;
266*593dc095SDavid du Colombier
267*593dc095SDavid du Colombier if (height < 0) {
268*593dc095SDavid du Colombier /* Empty clipping - will skip all drawings. */
269*593dc095SDavid du Colombier result->planestride = 0;
270*593dc095SDavid du Colombier result->data = 0;
271*593dc095SDavid du Colombier } else {
272*593dc095SDavid du Colombier planestride = rowstride * height;
2733ff48bf5SDavid du Colombier result->planestride = planestride;
2743ff48bf5SDavid du Colombier result->data = gs_alloc_bytes(memory, planestride * n_planes,
2753ff48bf5SDavid du Colombier "pdf14_buf_new");
2763ff48bf5SDavid du Colombier if (result->data == NULL) {
2773ff48bf5SDavid du Colombier gs_free_object(memory, result, "pdf_buf_new");
2783ff48bf5SDavid du Colombier return NULL;
2793ff48bf5SDavid du Colombier }
2803ff48bf5SDavid du Colombier if (has_alpha_g) {
2813ff48bf5SDavid du Colombier int alpha_g_plane = n_chan + (has_shape ? 1 : 0);
2823ff48bf5SDavid du Colombier memset (result->data + alpha_g_plane * planestride, 0, planestride);
2833ff48bf5SDavid du Colombier }
284*593dc095SDavid du Colombier }
285*593dc095SDavid du Colombier result->bbox.p.x = max_int;
286*593dc095SDavid du Colombier result->bbox.p.y = max_int;
287*593dc095SDavid du Colombier result->bbox.q.x = min_int;
288*593dc095SDavid du Colombier result->bbox.q.y = min_int;
2893ff48bf5SDavid du Colombier return result;
2903ff48bf5SDavid du Colombier }
2913ff48bf5SDavid du Colombier
2923ff48bf5SDavid du Colombier private void
pdf14_buf_free(pdf14_buf * buf,gs_memory_t * memory)2933ff48bf5SDavid du Colombier pdf14_buf_free(pdf14_buf *buf, gs_memory_t *memory)
2943ff48bf5SDavid du Colombier {
295*593dc095SDavid du Colombier gs_free_object(memory, buf->transfer_fn, "pdf14_buf_free");
2963ff48bf5SDavid du Colombier gs_free_object(memory, buf->data, "pdf14_buf_free");
2973ff48bf5SDavid du Colombier gs_free_object(memory, buf, "pdf14_buf_free");
2983ff48bf5SDavid du Colombier }
2993ff48bf5SDavid du Colombier
3003ff48bf5SDavid du Colombier private pdf14_ctx *
pdf14_ctx_new(gs_int_rect * rect,int n_chan,bool additive,gs_memory_t * memory)301*593dc095SDavid du Colombier pdf14_ctx_new(gs_int_rect *rect, int n_chan, bool additive, gs_memory_t *memory)
3023ff48bf5SDavid du Colombier {
3033ff48bf5SDavid du Colombier pdf14_ctx *result;
3043ff48bf5SDavid du Colombier pdf14_buf *buf;
3053ff48bf5SDavid du Colombier
3063ff48bf5SDavid du Colombier result = gs_alloc_struct(memory, pdf14_ctx, &st_pdf14_ctx,
3073ff48bf5SDavid du Colombier "pdf14_ctx_new");
308*593dc095SDavid du Colombier if (result == NULL)
309*593dc095SDavid du Colombier return result;
3103ff48bf5SDavid du Colombier
3113ff48bf5SDavid du Colombier buf = pdf14_buf_new(rect, false, false, n_chan, memory);
3123ff48bf5SDavid du Colombier if (buf == NULL) {
3133ff48bf5SDavid du Colombier gs_free_object(memory, result, "pdf14_ctx_new");
3143ff48bf5SDavid du Colombier return NULL;
3153ff48bf5SDavid du Colombier }
316*593dc095SDavid du Colombier if_debug3('v', "[v]base buf: %d x %d, %d channels\n",
317*593dc095SDavid du Colombier buf->rect.q.x, buf->rect.q.y, buf->n_chan);
318*593dc095SDavid du Colombier memset(buf->data, 0, buf->planestride * buf->n_planes);
3193ff48bf5SDavid du Colombier buf->saved = NULL;
3203ff48bf5SDavid du Colombier result->stack = buf;
321*593dc095SDavid du Colombier result->maskbuf = NULL;
3223ff48bf5SDavid du Colombier result->n_chan = n_chan;
3233ff48bf5SDavid du Colombier result->memory = memory;
3243ff48bf5SDavid du Colombier result->rect = *rect;
325*593dc095SDavid du Colombier result->additive = additive;
3263ff48bf5SDavid du Colombier return result;
3273ff48bf5SDavid du Colombier }
3283ff48bf5SDavid du Colombier
3293ff48bf5SDavid du Colombier private void
pdf14_ctx_free(pdf14_ctx * ctx)3303ff48bf5SDavid du Colombier pdf14_ctx_free(pdf14_ctx *ctx)
3313ff48bf5SDavid du Colombier {
3323ff48bf5SDavid du Colombier pdf14_buf *buf, *next;
3333ff48bf5SDavid du Colombier
3343ff48bf5SDavid du Colombier for (buf = ctx->stack; buf != NULL; buf = next) {
3353ff48bf5SDavid du Colombier next = buf->saved;
3363ff48bf5SDavid du Colombier pdf14_buf_free(buf, ctx->memory);
3373ff48bf5SDavid du Colombier }
3383ff48bf5SDavid du Colombier gs_free_object (ctx->memory, ctx, "pdf14_ctx_free");
3393ff48bf5SDavid du Colombier }
3403ff48bf5SDavid du Colombier
3413ff48bf5SDavid du Colombier /**
3423ff48bf5SDavid du Colombier * pdf14_find_backdrop_buf: Find backdrop buffer.
3433ff48bf5SDavid du Colombier *
3443ff48bf5SDavid du Colombier * Return value: Backdrop buffer for current group operation, or NULL
3453ff48bf5SDavid du Colombier * if backdrop is fully transparent.
3463ff48bf5SDavid du Colombier **/
3473ff48bf5SDavid du Colombier private pdf14_buf *
pdf14_find_backdrop_buf(pdf14_ctx * ctx)3483ff48bf5SDavid du Colombier pdf14_find_backdrop_buf(pdf14_ctx *ctx)
3493ff48bf5SDavid du Colombier {
3503ff48bf5SDavid du Colombier pdf14_buf *buf = ctx->stack;
3513ff48bf5SDavid du Colombier
3523ff48bf5SDavid du Colombier while (buf != NULL) {
3533ff48bf5SDavid du Colombier if (buf->isolated) return NULL;
3543ff48bf5SDavid du Colombier if (!buf->knockout) return buf->saved;
3553ff48bf5SDavid du Colombier buf = buf->saved;
3563ff48bf5SDavid du Colombier }
3573ff48bf5SDavid du Colombier /* this really shouldn't happen, as bottom-most buf should be
3583ff48bf5SDavid du Colombier non-knockout */
3593ff48bf5SDavid du Colombier return NULL;
3603ff48bf5SDavid du Colombier }
3613ff48bf5SDavid du Colombier
3623ff48bf5SDavid du Colombier private int
pdf14_push_transparency_group(pdf14_ctx * ctx,gs_int_rect * rect,bool isolated,bool knockout,byte alpha,byte shape,gs_blend_mode_t blend_mode)3633ff48bf5SDavid du Colombier pdf14_push_transparency_group(pdf14_ctx *ctx, gs_int_rect *rect,
3643ff48bf5SDavid du Colombier bool isolated, bool knockout,
3653ff48bf5SDavid du Colombier byte alpha, byte shape,
3663ff48bf5SDavid du Colombier gs_blend_mode_t blend_mode)
3673ff48bf5SDavid du Colombier {
3683ff48bf5SDavid du Colombier pdf14_buf *tos = ctx->stack;
3693ff48bf5SDavid du Colombier pdf14_buf *buf, *backdrop;
3703ff48bf5SDavid du Colombier bool has_shape;
3713ff48bf5SDavid du Colombier
3723ff48bf5SDavid du Colombier /* todo: fix this hack, which makes all knockout groups isolated.
3733ff48bf5SDavid du Colombier For the vast majority of files, there won't be any visible
3743ff48bf5SDavid du Colombier effects, but it still isn't correct. The pixel compositing code
3753ff48bf5SDavid du Colombier for non-isolated knockout groups gets pretty hairy, which is
3763ff48bf5SDavid du Colombier why this is here. */
377*593dc095SDavid du Colombier if (knockout)
378*593dc095SDavid du Colombier isolated = true;
3793ff48bf5SDavid du Colombier
3803ff48bf5SDavid du Colombier has_shape = tos->has_shape || tos->knockout;
3813ff48bf5SDavid du Colombier
3823ff48bf5SDavid du Colombier buf = pdf14_buf_new(rect, !isolated, has_shape, ctx->n_chan, ctx->memory);
383*593dc095SDavid du Colombier if_debug3('v', "[v]push buf: %d x %d, %d channels\n", buf->rect.p.x, buf->rect.p.y, buf->n_chan);
3843ff48bf5SDavid du Colombier if (buf == NULL)
3853ff48bf5SDavid du Colombier return_error(gs_error_VMerror);
3863ff48bf5SDavid du Colombier buf->isolated = isolated;
3873ff48bf5SDavid du Colombier buf->knockout = knockout;
3883ff48bf5SDavid du Colombier buf->alpha = alpha;
3893ff48bf5SDavid du Colombier buf->shape = shape;
3903ff48bf5SDavid du Colombier buf->blend_mode = blend_mode;
3913ff48bf5SDavid du Colombier
3923ff48bf5SDavid du Colombier buf->saved = tos;
3933ff48bf5SDavid du Colombier ctx->stack = buf;
3943ff48bf5SDavid du Colombier
3953ff48bf5SDavid du Colombier backdrop = pdf14_find_backdrop_buf(ctx);
3963ff48bf5SDavid du Colombier if (backdrop == NULL) {
3973ff48bf5SDavid du Colombier memset(buf->data, 0, buf->planestride * (buf->n_chan +
3983ff48bf5SDavid du Colombier (buf->has_shape ? 1 : 0)));
3993ff48bf5SDavid du Colombier } else {
4003ff48bf5SDavid du Colombier /* make copy of backdrop for compositing */
4013ff48bf5SDavid du Colombier byte *buf_plane = buf->data;
4023ff48bf5SDavid du Colombier byte *tos_plane = tos->data + buf->rect.p.x - tos->rect.p.x +
4033ff48bf5SDavid du Colombier (buf->rect.p.y - tos->rect.p.y) * tos->rowstride;
4043ff48bf5SDavid du Colombier int width = buf->rect.q.x - buf->rect.p.x;
4053ff48bf5SDavid du Colombier int y0 = buf->rect.p.y;
4063ff48bf5SDavid du Colombier int y1 = buf->rect.q.y;
4073ff48bf5SDavid du Colombier int i;
4083ff48bf5SDavid du Colombier int n_chan_copy = buf->n_chan + (tos->has_shape ? 1 : 0);
4093ff48bf5SDavid du Colombier
4103ff48bf5SDavid du Colombier for (i = 0; i < n_chan_copy; i++) {
4113ff48bf5SDavid du Colombier byte *buf_ptr = buf_plane;
4123ff48bf5SDavid du Colombier byte *tos_ptr = tos_plane;
4133ff48bf5SDavid du Colombier int y;
4143ff48bf5SDavid du Colombier
4153ff48bf5SDavid du Colombier for (y = y0; y < y1; ++y) {
4163ff48bf5SDavid du Colombier memcpy (buf_ptr, tos_ptr, width);
4173ff48bf5SDavid du Colombier buf_ptr += buf->rowstride;
4183ff48bf5SDavid du Colombier tos_ptr += tos->rowstride;
4193ff48bf5SDavid du Colombier }
4203ff48bf5SDavid du Colombier buf_plane += buf->planestride;
4213ff48bf5SDavid du Colombier tos_plane += tos->planestride;
4223ff48bf5SDavid du Colombier }
4233ff48bf5SDavid du Colombier if (has_shape && !tos->has_shape)
4243ff48bf5SDavid du Colombier memset (buf_plane, 0, buf->planestride);
4253ff48bf5SDavid du Colombier }
4263ff48bf5SDavid du Colombier
4273ff48bf5SDavid du Colombier return 0;
4283ff48bf5SDavid du Colombier }
4293ff48bf5SDavid du Colombier
4303ff48bf5SDavid du Colombier private int
pdf14_pop_transparency_group(pdf14_ctx * ctx)4313ff48bf5SDavid du Colombier pdf14_pop_transparency_group(pdf14_ctx *ctx)
4323ff48bf5SDavid du Colombier {
4333ff48bf5SDavid du Colombier pdf14_buf *tos = ctx->stack;
4343ff48bf5SDavid du Colombier pdf14_buf *nos = tos->saved;
435*593dc095SDavid du Colombier pdf14_buf *maskbuf = ctx->maskbuf;
436*593dc095SDavid du Colombier int y0 = tos->rect.p.y;
437*593dc095SDavid du Colombier int y1 = tos->rect.q.y;
438*593dc095SDavid du Colombier if (y0 < y1) {
439*593dc095SDavid du Colombier int x0 = tos->rect.p.x;
440*593dc095SDavid du Colombier int x1 = tos->rect.q.x;
4413ff48bf5SDavid du Colombier int n_chan = ctx->n_chan;
442*593dc095SDavid du Colombier int num_comp = n_chan - 1;
4433ff48bf5SDavid du Colombier byte alpha = tos->alpha;
4443ff48bf5SDavid du Colombier byte shape = tos->shape;
4453ff48bf5SDavid du Colombier byte blend_mode = tos->blend_mode;
4463ff48bf5SDavid du Colombier byte *tos_ptr = tos->data;
4473ff48bf5SDavid du Colombier byte *nos_ptr = nos->data + x0 - nos->rect.p.x +
4483ff48bf5SDavid du Colombier (y0 - nos->rect.p.y) * nos->rowstride;
449*593dc095SDavid du Colombier byte *mask_ptr = NULL;
4503ff48bf5SDavid du Colombier int tos_planestride = tos->planestride;
4513ff48bf5SDavid du Colombier int nos_planestride = nos->planestride;
452*593dc095SDavid du Colombier int mask_planestride = 0x0badf00d; /* Quiet compiler. */
453*593dc095SDavid du Colombier byte mask_bg_alpha = 0; /* Quiet compiler. */
4543ff48bf5SDavid du Colombier int width = x1 - x0;
4553ff48bf5SDavid du Colombier int x, y;
4563ff48bf5SDavid du Colombier int i;
4573ff48bf5SDavid du Colombier byte tos_pixel[PDF14_MAX_PLANES];
4583ff48bf5SDavid du Colombier byte nos_pixel[PDF14_MAX_PLANES];
4593ff48bf5SDavid du Colombier bool tos_isolated = tos->isolated;
4603ff48bf5SDavid du Colombier bool nos_knockout = nos->knockout;
4613ff48bf5SDavid du Colombier byte *nos_alpha_g_ptr;
4623ff48bf5SDavid du Colombier int tos_shape_offset = n_chan * tos_planestride;
4633ff48bf5SDavid du Colombier int tos_alpha_g_offset = tos_shape_offset +
4643ff48bf5SDavid du Colombier (tos->has_shape ? tos_planestride : 0);
4653ff48bf5SDavid du Colombier int nos_shape_offset = n_chan * nos_planestride;
4663ff48bf5SDavid du Colombier bool nos_has_shape = nos->has_shape;
467*593dc095SDavid du Colombier byte *mask_tr_fn = NULL; /* Quiet compiler. */
468*593dc095SDavid du Colombier bool additive = ctx->additive;
4693ff48bf5SDavid du Colombier
4703ff48bf5SDavid du Colombier if (nos == NULL)
4713ff48bf5SDavid du Colombier return_error(gs_error_rangecheck);
4723ff48bf5SDavid du Colombier
473*593dc095SDavid du Colombier rect_merge(nos->bbox, tos->bbox);
4743ff48bf5SDavid du Colombier
475*593dc095SDavid du Colombier if_debug6('v', "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, bm = %d\n",
476*593dc095SDavid du Colombier y0, y1, width, alpha, shape, blend_mode);
4773ff48bf5SDavid du Colombier if (nos->has_alpha_g)
4783ff48bf5SDavid du Colombier nos_alpha_g_ptr = nos_ptr + n_chan * nos_planestride;
4793ff48bf5SDavid du Colombier else
4803ff48bf5SDavid du Colombier nos_alpha_g_ptr = NULL;
4813ff48bf5SDavid du Colombier
482*593dc095SDavid du Colombier if (maskbuf != NULL) {
483*593dc095SDavid du Colombier mask_ptr = maskbuf->data + x0 - maskbuf->rect.p.x +
484*593dc095SDavid du Colombier (y0 - maskbuf->rect.p.y) * maskbuf->rowstride;
485*593dc095SDavid du Colombier mask_planestride = maskbuf->planestride;
486*593dc095SDavid du Colombier mask_bg_alpha = maskbuf->alpha;
487*593dc095SDavid du Colombier mask_tr_fn = maskbuf->transfer_fn;
488*593dc095SDavid du Colombier }
489*593dc095SDavid du Colombier
4903ff48bf5SDavid du Colombier for (y = y0; y < y1; ++y) {
4913ff48bf5SDavid du Colombier for (x = 0; x < width; ++x) {
492*593dc095SDavid du Colombier byte pix_alpha = alpha;
493*593dc095SDavid du Colombier
494*593dc095SDavid du Colombier /* Complement the components for subtractive color spaces */
495*593dc095SDavid du Colombier if (additive) {
4963ff48bf5SDavid du Colombier for (i = 0; i < n_chan; ++i) {
4973ff48bf5SDavid du Colombier tos_pixel[i] = tos_ptr[x + i * tos_planestride];
4983ff48bf5SDavid du Colombier nos_pixel[i] = nos_ptr[x + i * nos_planestride];
4993ff48bf5SDavid du Colombier }
500*593dc095SDavid du Colombier } else {
501*593dc095SDavid du Colombier for (i = 0; i < num_comp; ++i) {
502*593dc095SDavid du Colombier tos_pixel[i] = 255 - tos_ptr[x + i * tos_planestride];
503*593dc095SDavid du Colombier nos_pixel[i] = 255 - nos_ptr[x + i * nos_planestride];
504*593dc095SDavid du Colombier }
505*593dc095SDavid du Colombier tos_pixel[num_comp] = tos_ptr[x + num_comp * tos_planestride];
506*593dc095SDavid du Colombier nos_pixel[num_comp] = nos_ptr[x + num_comp * nos_planestride];
507*593dc095SDavid du Colombier }
508*593dc095SDavid du Colombier
509*593dc095SDavid du Colombier if (mask_ptr != NULL) {
510*593dc095SDavid du Colombier int mask_alpha = mask_ptr[x + num_comp * mask_planestride];
511*593dc095SDavid du Colombier int tmp;
512*593dc095SDavid du Colombier byte mask;
513*593dc095SDavid du Colombier
514*593dc095SDavid du Colombier /*
515*593dc095SDavid du Colombier * The mask data is really monochrome. Thus for additive (RGB)
516*593dc095SDavid du Colombier * we use the R channel for alpha since R = G = B. For
517*593dc095SDavid du Colombier * subtractive (CMYK) we use the K channel.
518*593dc095SDavid du Colombier */
519*593dc095SDavid du Colombier if (mask_alpha == 255) {
520*593dc095SDavid du Colombier /* todo: rgba->mask */
521*593dc095SDavid du Colombier mask = additive ? mask_ptr[x]
522*593dc095SDavid du Colombier : 255 - mask_ptr[x + 3 * mask_planestride];
523*593dc095SDavid du Colombier } else if (mask_alpha == 0)
524*593dc095SDavid du Colombier mask = mask_bg_alpha;
525*593dc095SDavid du Colombier else {
526*593dc095SDavid du Colombier int t2 = additive ? mask_ptr[x]
527*593dc095SDavid du Colombier : 255 - mask_ptr[x + 3 * mask_planestride];
528*593dc095SDavid du Colombier
529*593dc095SDavid du Colombier t2 = (t2 - mask_bg_alpha) * mask_alpha + 0x80;
530*593dc095SDavid du Colombier mask = mask_bg_alpha + ((t2 + (t2 >> 8)) >> 8);
531*593dc095SDavid du Colombier }
532*593dc095SDavid du Colombier mask = mask_tr_fn[mask];
533*593dc095SDavid du Colombier tmp = pix_alpha * mask + 0x80;
534*593dc095SDavid du Colombier pix_alpha = (tmp + (tmp >> 8)) >> 8;
535*593dc095SDavid du Colombier }
5363ff48bf5SDavid du Colombier
5373ff48bf5SDavid du Colombier if (nos_knockout) {
5383ff48bf5SDavid du Colombier byte *nos_shape_ptr = nos_has_shape ?
5393ff48bf5SDavid du Colombier &nos_ptr[x + nos_shape_offset] : NULL;
5403ff48bf5SDavid du Colombier byte tos_shape = tos_ptr[x + tos_shape_offset];
5413ff48bf5SDavid du Colombier
5423ff48bf5SDavid du Colombier art_pdf_composite_knockout_isolated_8(nos_pixel,
5433ff48bf5SDavid du Colombier nos_shape_ptr,
5443ff48bf5SDavid du Colombier tos_pixel,
5453ff48bf5SDavid du Colombier n_chan - 1,
5463ff48bf5SDavid du Colombier tos_shape,
547*593dc095SDavid du Colombier pix_alpha, shape);
5483ff48bf5SDavid du Colombier } else if (tos_isolated) {
5493ff48bf5SDavid du Colombier art_pdf_composite_group_8(nos_pixel, nos_alpha_g_ptr,
5503ff48bf5SDavid du Colombier tos_pixel,
5513ff48bf5SDavid du Colombier n_chan - 1,
552*593dc095SDavid du Colombier pix_alpha, blend_mode);
5533ff48bf5SDavid du Colombier } else {
5543ff48bf5SDavid du Colombier byte tos_alpha_g = tos_ptr[x + tos_alpha_g_offset];
5553ff48bf5SDavid du Colombier art_pdf_recomposite_group_8(nos_pixel, nos_alpha_g_ptr,
5563ff48bf5SDavid du Colombier tos_pixel, tos_alpha_g,
5573ff48bf5SDavid du Colombier n_chan - 1,
558*593dc095SDavid du Colombier pix_alpha, blend_mode);
5593ff48bf5SDavid du Colombier }
5603ff48bf5SDavid du Colombier if (nos_has_shape) {
5613ff48bf5SDavid du Colombier nos_ptr[x + nos_shape_offset] =
5623ff48bf5SDavid du Colombier art_pdf_union_mul_8 (nos_ptr[x + nos_shape_offset],
5633ff48bf5SDavid du Colombier tos_ptr[x + tos_shape_offset],
5643ff48bf5SDavid du Colombier shape);
5653ff48bf5SDavid du Colombier }
5663ff48bf5SDavid du Colombier
567*593dc095SDavid du Colombier /* Complement the results for subtractive color spaces */
568*593dc095SDavid du Colombier if (additive) {
5693ff48bf5SDavid du Colombier for (i = 0; i < n_chan; ++i) {
5703ff48bf5SDavid du Colombier nos_ptr[x + i * nos_planestride] = nos_pixel[i];
5713ff48bf5SDavid du Colombier }
572*593dc095SDavid du Colombier } else {
573*593dc095SDavid du Colombier for (i = 0; i < num_comp; ++i)
574*593dc095SDavid du Colombier nos_ptr[x + i * nos_planestride] = 255 - nos_pixel[i];
575*593dc095SDavid du Colombier nos_ptr[x + num_comp * nos_planestride] = nos_pixel[num_comp];
576*593dc095SDavid du Colombier }
5773ff48bf5SDavid du Colombier if (nos_alpha_g_ptr != NULL)
5783ff48bf5SDavid du Colombier ++nos_alpha_g_ptr;
5793ff48bf5SDavid du Colombier }
5803ff48bf5SDavid du Colombier tos_ptr += tos->rowstride;
5813ff48bf5SDavid du Colombier nos_ptr += nos->rowstride;
5823ff48bf5SDavid du Colombier if (nos_alpha_g_ptr != NULL)
5833ff48bf5SDavid du Colombier nos_alpha_g_ptr += nos->rowstride - width;
584*593dc095SDavid du Colombier if (mask_ptr != NULL)
585*593dc095SDavid du Colombier mask_ptr += maskbuf->rowstride;
586*593dc095SDavid du Colombier }
5873ff48bf5SDavid du Colombier }
5883ff48bf5SDavid du Colombier
5893ff48bf5SDavid du Colombier ctx->stack = nos;
590*593dc095SDavid du Colombier if_debug0('v', "[v]pop buf\n");
5913ff48bf5SDavid du Colombier pdf14_buf_free(tos, ctx->memory);
592*593dc095SDavid du Colombier if (maskbuf != NULL) {
593*593dc095SDavid du Colombier pdf14_buf_free(maskbuf, ctx->memory);
594*593dc095SDavid du Colombier ctx->maskbuf = NULL;
595*593dc095SDavid du Colombier }
596*593dc095SDavid du Colombier return 0;
597*593dc095SDavid du Colombier }
598*593dc095SDavid du Colombier
599*593dc095SDavid du Colombier private int
pdf14_push_transparency_mask(pdf14_ctx * ctx,gs_int_rect * rect,byte bg_alpha,byte * transfer_fn)600*593dc095SDavid du Colombier pdf14_push_transparency_mask(pdf14_ctx *ctx, gs_int_rect *rect, byte bg_alpha,
601*593dc095SDavid du Colombier byte *transfer_fn)
602*593dc095SDavid du Colombier {
603*593dc095SDavid du Colombier pdf14_buf *buf;
604*593dc095SDavid du Colombier
605*593dc095SDavid du Colombier if_debug0('v', "[v]pdf_push_transparency_mask\n");
606*593dc095SDavid du Colombier buf = pdf14_buf_new(rect, false, false, ctx->n_chan, ctx->memory);
607*593dc095SDavid du Colombier if (buf == NULL)
608*593dc095SDavid du Colombier return_error(gs_error_VMerror);
609*593dc095SDavid du Colombier
610*593dc095SDavid du Colombier /* fill in, but these values aren't really used */
611*593dc095SDavid du Colombier buf->isolated = true;
612*593dc095SDavid du Colombier buf->knockout = false;
613*593dc095SDavid du Colombier buf->alpha = bg_alpha;
614*593dc095SDavid du Colombier buf->shape = 0xff;
615*593dc095SDavid du Colombier buf->blend_mode = BLEND_MODE_Normal;
616*593dc095SDavid du Colombier buf->transfer_fn = transfer_fn;
617*593dc095SDavid du Colombier
618*593dc095SDavid du Colombier buf->saved = ctx->stack;
619*593dc095SDavid du Colombier ctx->stack = buf;
620*593dc095SDavid du Colombier memset(buf->data, 0, buf->planestride * buf->n_chan);
621*593dc095SDavid du Colombier return 0;
622*593dc095SDavid du Colombier }
623*593dc095SDavid du Colombier
624*593dc095SDavid du Colombier private int
pdf14_pop_transparency_mask(pdf14_ctx * ctx)625*593dc095SDavid du Colombier pdf14_pop_transparency_mask(pdf14_ctx *ctx)
626*593dc095SDavid du Colombier {
627*593dc095SDavid du Colombier pdf14_buf *tos = ctx->stack;
628*593dc095SDavid du Colombier
629*593dc095SDavid du Colombier ctx->stack = tos->saved;
630*593dc095SDavid du Colombier ctx->maskbuf = tos;
6313ff48bf5SDavid du Colombier return 0;
6323ff48bf5SDavid du Colombier }
6333ff48bf5SDavid du Colombier
6343ff48bf5SDavid du Colombier private int
pdf14_open(gx_device * dev)6353ff48bf5SDavid du Colombier pdf14_open(gx_device *dev)
6363ff48bf5SDavid du Colombier {
6373ff48bf5SDavid du Colombier pdf14_device *pdev = (pdf14_device *)dev;
6383ff48bf5SDavid du Colombier gs_int_rect rect;
6393ff48bf5SDavid du Colombier
6403ff48bf5SDavid du Colombier if_debug2('v', "[v]pdf14_open: width = %d, height = %d\n",
6413ff48bf5SDavid du Colombier dev->width, dev->height);
6423ff48bf5SDavid du Colombier
6433ff48bf5SDavid du Colombier rect.p.x = 0;
6443ff48bf5SDavid du Colombier rect.p.y = 0;
6453ff48bf5SDavid du Colombier rect.q.x = dev->width;
6463ff48bf5SDavid du Colombier rect.q.y = dev->height;
647*593dc095SDavid du Colombier pdev->ctx = pdf14_ctx_new(&rect, dev->color_info.num_components + 1,
648*593dc095SDavid du Colombier pdev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE, dev->memory);
6493ff48bf5SDavid du Colombier if (pdev->ctx == NULL)
6503ff48bf5SDavid du Colombier return_error(gs_error_VMerror);
6513ff48bf5SDavid du Colombier return 0;
6523ff48bf5SDavid du Colombier }
6533ff48bf5SDavid du Colombier
654*593dc095SDavid du Colombier /*
655*593dc095SDavid du Colombier * Encode a list of colorant values into a gx_color_index_value.
656*593dc095SDavid du Colombier */
657*593dc095SDavid du Colombier private gx_color_index
pdf14_encode_color(gx_device * dev,const gx_color_value colors[])658*593dc095SDavid du Colombier pdf14_encode_color(gx_device *dev, const gx_color_value colors[])
659*593dc095SDavid du Colombier {
660*593dc095SDavid du Colombier int drop = sizeof(gx_color_value) * 8 - 8;
661*593dc095SDavid du Colombier gx_color_index color = 0;
662*593dc095SDavid du Colombier int i;
663*593dc095SDavid du Colombier int ncomp = dev->color_info.num_components;
664*593dc095SDavid du Colombier
665*593dc095SDavid du Colombier for (i = 0; i < ncomp; i++) {
666*593dc095SDavid du Colombier color <<= 8;
667*593dc095SDavid du Colombier color |= (colors[i] >> drop);
668*593dc095SDavid du Colombier }
669*593dc095SDavid du Colombier return (color == gx_no_color_index ? color ^ 1 : color);
670*593dc095SDavid du Colombier }
671*593dc095SDavid du Colombier
672*593dc095SDavid du Colombier /*
673*593dc095SDavid du Colombier * Decode a gx_color_index value back to a list of colorant values.
674*593dc095SDavid du Colombier */
675*593dc095SDavid du Colombier private int
pdf14_decode_color(gx_device * dev,gx_color_index color,gx_color_value * out)676*593dc095SDavid du Colombier pdf14_decode_color(gx_device * dev, gx_color_index color, gx_color_value * out)
677*593dc095SDavid du Colombier {
678*593dc095SDavid du Colombier int i;
679*593dc095SDavid du Colombier int ncomp = dev->color_info.num_components;
680*593dc095SDavid du Colombier
681*593dc095SDavid du Colombier for (i = 0; i < ncomp; i++) {
682*593dc095SDavid du Colombier out[ncomp - i - 1] = (gx_color_value) ((color & 0xff) * 0x101);
683*593dc095SDavid du Colombier color >>= 8;
684*593dc095SDavid du Colombier }
685*593dc095SDavid du Colombier return 0;
686*593dc095SDavid du Colombier }
687*593dc095SDavid du Colombier
688*593dc095SDavid du Colombier #ifdef DUMP_TO_PNG
689*593dc095SDavid du Colombier /* Dumps a planar RGBA image to a PNG file. */
690*593dc095SDavid du Colombier private int
dump_planar_rgba(gs_memory_t * mem,const byte * buf,int width,int height,int rowstride,int planestride)691*593dc095SDavid du Colombier dump_planar_rgba(gs_memory_t *mem,
692*593dc095SDavid du Colombier const byte *buf, int width, int height, int rowstride, int planestride)
693*593dc095SDavid du Colombier {
694*593dc095SDavid du Colombier int rowbytes = width << 2;
695*593dc095SDavid du Colombier byte *row = gs_malloc(mem, rowbytes, 1, "png raster buffer");
696*593dc095SDavid du Colombier png_struct *png_ptr =
697*593dc095SDavid du Colombier png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
698*593dc095SDavid du Colombier png_info *info_ptr =
699*593dc095SDavid du Colombier png_create_info_struct(png_ptr);
700*593dc095SDavid du Colombier const char *software_key = "Software";
701*593dc095SDavid du Colombier char software_text[256];
702*593dc095SDavid du Colombier png_text text_png;
703*593dc095SDavid du Colombier const byte *buf_ptr = buf;
704*593dc095SDavid du Colombier FILE *file;
705*593dc095SDavid du Colombier int code;
706*593dc095SDavid du Colombier int y;
707*593dc095SDavid du Colombier
708*593dc095SDavid du Colombier file = fopen ("c:\\temp\\tmp.png", "wb");
709*593dc095SDavid du Colombier
710*593dc095SDavid du Colombier if_debug0('v', "[v]pnga_output_page\n");
711*593dc095SDavid du Colombier
712*593dc095SDavid du Colombier if (row == 0 || png_ptr == 0 || info_ptr == 0) {
713*593dc095SDavid du Colombier code = gs_note_error(gs_error_VMerror);
714*593dc095SDavid du Colombier goto done;
715*593dc095SDavid du Colombier }
716*593dc095SDavid du Colombier /* set error handling */
717*593dc095SDavid du Colombier if (setjmp(png_ptr->jmpbuf)) {
718*593dc095SDavid du Colombier /* If we get here, we had a problem reading the file */
719*593dc095SDavid du Colombier code = gs_note_error(gs_error_VMerror);
720*593dc095SDavid du Colombier goto done;
721*593dc095SDavid du Colombier }
722*593dc095SDavid du Colombier
723*593dc095SDavid du Colombier code = 0; /* for normal path */
724*593dc095SDavid du Colombier /* set up the output control */
725*593dc095SDavid du Colombier png_init_io(png_ptr, file);
726*593dc095SDavid du Colombier
727*593dc095SDavid du Colombier /* set the file information here */
728*593dc095SDavid du Colombier info_ptr->width = width;
729*593dc095SDavid du Colombier info_ptr->height = height;
730*593dc095SDavid du Colombier /* resolution is in pixels per meter vs. dpi */
731*593dc095SDavid du Colombier info_ptr->x_pixels_per_unit =
732*593dc095SDavid du Colombier (png_uint_32) (96.0 * (100.0 / 2.54));
733*593dc095SDavid du Colombier info_ptr->y_pixels_per_unit =
734*593dc095SDavid du Colombier (png_uint_32) (96.0 * (100.0 / 2.54));
735*593dc095SDavid du Colombier info_ptr->phys_unit_type = PNG_RESOLUTION_METER;
736*593dc095SDavid du Colombier info_ptr->valid |= PNG_INFO_pHYs;
737*593dc095SDavid du Colombier
738*593dc095SDavid du Colombier /* At present, only supporting 32-bit rgba */
739*593dc095SDavid du Colombier info_ptr->bit_depth = 8;
740*593dc095SDavid du Colombier info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
741*593dc095SDavid du Colombier
742*593dc095SDavid du Colombier /* add comment */
743*593dc095SDavid du Colombier sprintf(software_text, "%s %d.%02d", gs_product,
744*593dc095SDavid du Colombier (int)(gs_revision / 100), (int)(gs_revision % 100));
745*593dc095SDavid du Colombier text_png.compression = -1; /* uncompressed */
746*593dc095SDavid du Colombier text_png.key = (char *)software_key; /* not const, unfortunately */
747*593dc095SDavid du Colombier text_png.text = software_text;
748*593dc095SDavid du Colombier text_png.text_length = strlen(software_text);
749*593dc095SDavid du Colombier info_ptr->text = &text_png;
750*593dc095SDavid du Colombier info_ptr->num_text = 1;
751*593dc095SDavid du Colombier
752*593dc095SDavid du Colombier /* write the file information */
753*593dc095SDavid du Colombier png_write_info(png_ptr, info_ptr);
754*593dc095SDavid du Colombier
755*593dc095SDavid du Colombier /* don't write the comments twice */
756*593dc095SDavid du Colombier info_ptr->num_text = 0;
757*593dc095SDavid du Colombier info_ptr->text = NULL;
758*593dc095SDavid du Colombier
759*593dc095SDavid du Colombier /* Write the contents of the image. */
760*593dc095SDavid du Colombier for (y = 0; y < height; ++y) {
761*593dc095SDavid du Colombier int x;
762*593dc095SDavid du Colombier
763*593dc095SDavid du Colombier for (x = 0; x < width; ++x) {
764*593dc095SDavid du Colombier row[(x << 2)] = buf_ptr[x];
765*593dc095SDavid du Colombier row[(x << 2) + 1] = buf_ptr[x + planestride];
766*593dc095SDavid du Colombier row[(x << 2) + 2] = buf_ptr[x + planestride * 2];
767*593dc095SDavid du Colombier row[(x << 2) + 3] = buf_ptr[x + planestride * 3];
768*593dc095SDavid du Colombier }
769*593dc095SDavid du Colombier png_write_row(png_ptr, row);
770*593dc095SDavid du Colombier buf_ptr += rowstride;
771*593dc095SDavid du Colombier }
772*593dc095SDavid du Colombier
773*593dc095SDavid du Colombier /* write the rest of the file */
774*593dc095SDavid du Colombier png_write_end(png_ptr, info_ptr);
775*593dc095SDavid du Colombier
776*593dc095SDavid du Colombier done:
777*593dc095SDavid du Colombier /* free the structures */
778*593dc095SDavid du Colombier png_destroy_write_struct(&png_ptr, &info_ptr);
779*593dc095SDavid du Colombier gs_free(mem, row, rowbytes, 1, "png raster buffer");
780*593dc095SDavid du Colombier
781*593dc095SDavid du Colombier fclose (file);
782*593dc095SDavid du Colombier return code;
783*593dc095SDavid du Colombier }
784*593dc095SDavid du Colombier #endif
785*593dc095SDavid du Colombier
786*593dc095SDavid du Colombier
7873ff48bf5SDavid du Colombier /**
7883ff48bf5SDavid du Colombier * pdf14_put_image: Put rendered image to target device.
7893ff48bf5SDavid du Colombier * @pdev: The PDF 1.4 rendering device.
7903ff48bf5SDavid du Colombier * @pgs: State for image draw operation.
7913ff48bf5SDavid du Colombier * @target: The target device.
7923ff48bf5SDavid du Colombier *
7933ff48bf5SDavid du Colombier * Puts the rendered image in @pdev's buffer to @target. This is called
7943ff48bf5SDavid du Colombier * as part of the sequence of popping the PDF 1.4 device filter.
7953ff48bf5SDavid du Colombier *
7963ff48bf5SDavid du Colombier * Return code: negative on error.
7973ff48bf5SDavid du Colombier **/
7983ff48bf5SDavid du Colombier private int
pdf14_put_image(pdf14_device * pdev,gs_imager_state * pis,gx_device * target)799*593dc095SDavid du Colombier pdf14_put_image(pdf14_device *pdev, gs_imager_state *pis, gx_device *target)
8003ff48bf5SDavid du Colombier {
8013ff48bf5SDavid du Colombier int code;
8023ff48bf5SDavid du Colombier gs_image1_t image;
8033ff48bf5SDavid du Colombier gs_matrix pmat;
8043ff48bf5SDavid du Colombier gx_image_enum_common_t *info;
8053ff48bf5SDavid du Colombier int width = pdev->width;
8063ff48bf5SDavid du Colombier int height = pdev->height;
8073ff48bf5SDavid du Colombier int y;
8083ff48bf5SDavid du Colombier pdf14_buf *buf = pdev->ctx->stack;
8093ff48bf5SDavid du Colombier int planestride = buf->planestride;
810*593dc095SDavid du Colombier int num_comp = buf->n_chan - 1;
8113ff48bf5SDavid du Colombier byte *buf_ptr = buf->data;
8123ff48bf5SDavid du Colombier byte *linebuf;
813*593dc095SDavid du Colombier gs_color_space cs;
814*593dc095SDavid du Colombier const byte bg = pdev->ctx->additive ? 255 : 0;
8153ff48bf5SDavid du Colombier
816*593dc095SDavid du Colombier #ifdef DUMP_TO_PNG
817*593dc095SDavid du Colombier dump_planar_rgba(pdev->memory, buf_ptr, width, height,
818*593dc095SDavid du Colombier buf->rowstride, buf->planestride);
8193ff48bf5SDavid du Colombier #endif
8203ff48bf5SDavid du Colombier
821*593dc095SDavid du Colombier #if 0
822*593dc095SDavid du Colombier /* Set graphics state device to target, so that image can set up
823*593dc095SDavid du Colombier the color mapping properly. */
824*593dc095SDavid du Colombier rc_increment(pdev);
825*593dc095SDavid du Colombier gs_setdevice_no_init(pgs, target);
826*593dc095SDavid du Colombier #endif
827*593dc095SDavid du Colombier
828*593dc095SDavid du Colombier if_debug0('v', "[v]pdf14_put_image\n");
829*593dc095SDavid du Colombier /*
830*593dc095SDavid du Colombier * Set color space to either Gray, RGB, or CMYK in preparation for sending
831*593dc095SDavid du Colombier * an image.
832*593dc095SDavid du Colombier */
833*593dc095SDavid du Colombier switch (num_comp) {
834*593dc095SDavid du Colombier case 1: /* DeviceGray */
835*593dc095SDavid du Colombier gs_cspace_init_DeviceGray(pis->memory, &cs);
836*593dc095SDavid du Colombier break;
837*593dc095SDavid du Colombier case 3: /* DeviceRGB */
838*593dc095SDavid du Colombier gs_cspace_init_DeviceRGB(pis->memory, &cs);
839*593dc095SDavid du Colombier break;
840*593dc095SDavid du Colombier case 4: /* DeviceCMYK */
841*593dc095SDavid du Colombier gs_cspace_init_DeviceCMYK(pis->memory, &cs);
842*593dc095SDavid du Colombier break;
843*593dc095SDavid du Colombier default: /* Should never occur */
844*593dc095SDavid du Colombier return_error(gs_error_rangecheck);
845*593dc095SDavid du Colombier break;
846*593dc095SDavid du Colombier }
847*593dc095SDavid du Colombier gs_image_t_init_adjust(&image, &cs, false);
848*593dc095SDavid du Colombier image.ImageMatrix.xx = (float)width;
849*593dc095SDavid du Colombier image.ImageMatrix.yy = (float)height;
8503ff48bf5SDavid du Colombier image.Width = width;
8513ff48bf5SDavid du Colombier image.Height = height;
8523ff48bf5SDavid du Colombier image.BitsPerComponent = 8;
853*593dc095SDavid du Colombier pmat.xx = (float)width;
8543ff48bf5SDavid du Colombier pmat.xy = 0;
8553ff48bf5SDavid du Colombier pmat.yx = 0;
856*593dc095SDavid du Colombier pmat.yy = (float)height;
8573ff48bf5SDavid du Colombier pmat.tx = 0;
8583ff48bf5SDavid du Colombier pmat.ty = 0;
8593ff48bf5SDavid du Colombier code = dev_proc(target, begin_typed_image) (target,
8603ff48bf5SDavid du Colombier pis, &pmat,
8613ff48bf5SDavid du Colombier (gs_image_common_t *)&image,
8623ff48bf5SDavid du Colombier NULL, NULL, NULL,
863*593dc095SDavid du Colombier pis->memory, &info);
8643ff48bf5SDavid du Colombier if (code < 0)
8653ff48bf5SDavid du Colombier return code;
8663ff48bf5SDavid du Colombier
867*593dc095SDavid du Colombier linebuf = gs_alloc_bytes(pdev->memory, width * num_comp, "pdf14_put_image");
8683ff48bf5SDavid du Colombier for (y = 0; y < height; y++) {
8693ff48bf5SDavid du Colombier gx_image_plane_t planes;
8703ff48bf5SDavid du Colombier int x;
8713ff48bf5SDavid du Colombier int rows_used;
8723ff48bf5SDavid du Colombier
8733ff48bf5SDavid du Colombier for (x = 0; x < width; x++) {
874*593dc095SDavid du Colombier byte comp, a;
875*593dc095SDavid du Colombier int tmp, comp_num;
8763ff48bf5SDavid du Colombier
877*593dc095SDavid du Colombier /* composite RGBA (or CMYKA, etc.) pixel with over solid background */
878*593dc095SDavid du Colombier a = buf_ptr[x + planestride * num_comp];
8793ff48bf5SDavid du Colombier
8803ff48bf5SDavid du Colombier if ((a + 1) & 0xfe) {
8813ff48bf5SDavid du Colombier a ^= 0xff;
882*593dc095SDavid du Colombier for (comp_num = 0; comp_num < num_comp; comp_num++) {
883*593dc095SDavid du Colombier comp = buf_ptr[x + planestride * comp_num];
884*593dc095SDavid du Colombier tmp = ((bg - comp) * a) + 0x80;
885*593dc095SDavid du Colombier comp += (tmp + (tmp >> 8)) >> 8;
886*593dc095SDavid du Colombier linebuf[x * num_comp + comp_num] = comp;
887*593dc095SDavid du Colombier }
8883ff48bf5SDavid du Colombier } else if (a == 0) {
889*593dc095SDavid du Colombier for (comp_num = 0; comp_num < num_comp; comp_num++) {
890*593dc095SDavid du Colombier linebuf[x * num_comp + comp_num] = bg;
891*593dc095SDavid du Colombier }
8923ff48bf5SDavid du Colombier } else {
893*593dc095SDavid du Colombier for (comp_num = 0; comp_num < num_comp; comp_num++) {
894*593dc095SDavid du Colombier comp = buf_ptr[x + planestride * comp_num];
895*593dc095SDavid du Colombier linebuf[x * num_comp + comp_num] = comp;
896*593dc095SDavid du Colombier }
8973ff48bf5SDavid du Colombier }
8983ff48bf5SDavid du Colombier }
8993ff48bf5SDavid du Colombier
9003ff48bf5SDavid du Colombier planes.data = linebuf;
9013ff48bf5SDavid du Colombier planes.data_x = 0;
902*593dc095SDavid du Colombier planes.raster = width * num_comp;
9033ff48bf5SDavid du Colombier info->procs->plane_data(info, &planes, 1, &rows_used);
9043ff48bf5SDavid du Colombier /* todo: check return value */
9053ff48bf5SDavid du Colombier
9063ff48bf5SDavid du Colombier buf_ptr += buf->rowstride;
9073ff48bf5SDavid du Colombier }
9083ff48bf5SDavid du Colombier gs_free_object(pdev->memory, linebuf, "pdf14_put_image");
9093ff48bf5SDavid du Colombier
9103ff48bf5SDavid du Colombier info->procs->end_image(info, true);
911*593dc095SDavid du Colombier
912*593dc095SDavid du Colombier #if 0
913*593dc095SDavid du Colombier /* Restore device in graphics state.*/
914*593dc095SDavid du Colombier gs_setdevice_no_init(pgs, (gx_device*) pdev);
915*593dc095SDavid du Colombier rc_decrement_only(pdev, "pdf_14_put_image");
916*593dc095SDavid du Colombier #endif
917*593dc095SDavid du Colombier
9183ff48bf5SDavid du Colombier return code;
9193ff48bf5SDavid du Colombier }
9203ff48bf5SDavid du Colombier
9213ff48bf5SDavid du Colombier private int
pdf14_close(gx_device * dev)9223ff48bf5SDavid du Colombier pdf14_close(gx_device *dev)
9233ff48bf5SDavid du Colombier {
9243ff48bf5SDavid du Colombier pdf14_device *pdev = (pdf14_device *)dev;
9253ff48bf5SDavid du Colombier
926*593dc095SDavid du Colombier if (pdev->ctx) {
9273ff48bf5SDavid du Colombier pdf14_ctx_free(pdev->ctx);
928*593dc095SDavid du Colombier pdev->ctx = NULL;
929*593dc095SDavid du Colombier }
9303ff48bf5SDavid du Colombier return 0;
9313ff48bf5SDavid du Colombier }
9323ff48bf5SDavid du Colombier
9333ff48bf5SDavid du Colombier private int
pdf14_output_page(gx_device * dev,int num_copies,int flush)9343ff48bf5SDavid du Colombier pdf14_output_page(gx_device * dev, int num_copies, int flush)
9353ff48bf5SDavid du Colombier {
936*593dc095SDavid du Colombier pdf14_device * pdev = (pdf14_device *)dev;
9373ff48bf5SDavid du Colombier
938*593dc095SDavid du Colombier if (pdev->target != NULL)
939*593dc095SDavid du Colombier return (*dev_proc(pdev->target, output_page)) (pdev->target, num_copies, flush);
9403ff48bf5SDavid du Colombier return 0;
9413ff48bf5SDavid du Colombier }
9423ff48bf5SDavid du Colombier
9433ff48bf5SDavid du Colombier #define COPY_PARAM(p) dev->p = target->p
9443ff48bf5SDavid du Colombier #define COPY_ARRAY_PARAM(p) memcpy(dev->p, target->p, sizeof(dev->p))
9453ff48bf5SDavid du Colombier
9463ff48bf5SDavid du Colombier /*
9473ff48bf5SDavid du Colombier * Copy device parameters back from a target. This copies all standard
9483ff48bf5SDavid du Colombier * parameters related to page size and resolution, but not any of the
9493ff48bf5SDavid du Colombier * color-related parameters, as the pdf14 device retains its own color
9503ff48bf5SDavid du Colombier * handling. This routine is parallel to gx_device_copy_params().
9513ff48bf5SDavid du Colombier */
9523ff48bf5SDavid du Colombier private void
gs_pdf14_device_copy_params(gx_device * dev,const gx_device * target)9533ff48bf5SDavid du Colombier gs_pdf14_device_copy_params(gx_device *dev, const gx_device *target)
9543ff48bf5SDavid du Colombier {
9553ff48bf5SDavid du Colombier COPY_PARAM(width);
9563ff48bf5SDavid du Colombier COPY_PARAM(height);
9573ff48bf5SDavid du Colombier COPY_ARRAY_PARAM(MediaSize);
9583ff48bf5SDavid du Colombier COPY_ARRAY_PARAM(ImagingBBox);
9593ff48bf5SDavid du Colombier COPY_PARAM(ImagingBBox_set);
9603ff48bf5SDavid du Colombier COPY_ARRAY_PARAM(HWResolution);
9613ff48bf5SDavid du Colombier COPY_ARRAY_PARAM(MarginsHWResolution);
9623ff48bf5SDavid du Colombier COPY_ARRAY_PARAM(Margins);
9633ff48bf5SDavid du Colombier COPY_ARRAY_PARAM(HWMargins);
9643ff48bf5SDavid du Colombier COPY_PARAM(PageCount);
9653ff48bf5SDavid du Colombier #undef COPY_ARRAY_PARAM
9663ff48bf5SDavid du Colombier #undef COPY_PARAM
9673ff48bf5SDavid du Colombier }
9683ff48bf5SDavid du Colombier
969*593dc095SDavid du Colombier /*
970*593dc095SDavid du Colombier * This is a forwarding version of the put_params device proc. It is only
971*593dc095SDavid du Colombier * used when the PDF 1.4 compositor devices are closed. The routine will
972*593dc095SDavid du Colombier * check if the target device has closed and, if so, close itself. The routine
973*593dc095SDavid du Colombier * also sync the device parameters.
974*593dc095SDavid du Colombier */
975*593dc095SDavid du Colombier private int
pdf14_forward_put_params(gx_device * dev,gs_param_list * plist)976*593dc095SDavid du Colombier pdf14_forward_put_params(gx_device * dev, gs_param_list * plist)
9773ff48bf5SDavid du Colombier {
9783ff48bf5SDavid du Colombier pdf14_device * pdev = (pdf14_device *)dev;
979*593dc095SDavid du Colombier gx_device * tdev = pdev->target;
980*593dc095SDavid du Colombier int code = 0;
9813ff48bf5SDavid du Colombier
982*593dc095SDavid du Colombier if (tdev != 0 && (code = dev_proc(tdev, put_params)(tdev, plist)) >= 0) {
983*593dc095SDavid du Colombier gx_device_decache_colors(dev);
984*593dc095SDavid du Colombier if (!tdev->is_open)
985*593dc095SDavid du Colombier code = gs_closedevice(dev);
986*593dc095SDavid du Colombier gx_device_copy_params(dev, tdev);
987*593dc095SDavid du Colombier }
988*593dc095SDavid du Colombier return code;
9893ff48bf5SDavid du Colombier }
9903ff48bf5SDavid du Colombier
991*593dc095SDavid du Colombier /*
992*593dc095SDavid du Colombier * The put_params method for the PDF 1.4 device will check if the
993*593dc095SDavid du Colombier * target device has closed and, if so, close itself. Note: This routine is
994*593dc095SDavid du Colombier * currently being used by both the pdf14_clist_device and the pdf_device.
995*593dc095SDavid du Colombier * Please make sure that any changes are either applicable to both devices
996*593dc095SDavid du Colombier * or clone the routine for each device.
997*593dc095SDavid du Colombier */
998*593dc095SDavid du Colombier private int
pdf14_put_params(gx_device * dev,gs_param_list * plist)999*593dc095SDavid du Colombier pdf14_put_params(gx_device * dev, gs_param_list * plist)
10003ff48bf5SDavid du Colombier {
1001*593dc095SDavid du Colombier pdf14_device * pdev = (pdf14_device *)dev;
1002*593dc095SDavid du Colombier gx_device * tdev = pdev->target;
1003*593dc095SDavid du Colombier int code = 0;
1004*593dc095SDavid du Colombier
1005*593dc095SDavid du Colombier if (tdev != 0 && (code = dev_proc(tdev, put_params)(tdev, plist)) >= 0) {
1006*593dc095SDavid du Colombier gx_device_decache_colors(dev);
1007*593dc095SDavid du Colombier if (!tdev->is_open)
1008*593dc095SDavid du Colombier code = gs_closedevice(dev);
1009*593dc095SDavid du Colombier gs_pdf14_device_copy_params(dev, tdev);
1010*593dc095SDavid du Colombier }
1011*593dc095SDavid du Colombier return code;
1012*593dc095SDavid du Colombier }
1013*593dc095SDavid du Colombier
1014*593dc095SDavid du Colombier /*
1015*593dc095SDavid du Colombier * Copy marking related parameters into the PDF 1.4 device structure for use
1016*593dc095SDavid du Colombier * by pdf14_fill_rrectangle.
1017*593dc095SDavid du Colombier */
1018*593dc095SDavid du Colombier private void
pdf14_set_marking_params(gx_device * dev,const gs_imager_state * pis)1019*593dc095SDavid du Colombier pdf14_set_marking_params(gx_device *dev, const gs_imager_state *pis)
1020*593dc095SDavid du Colombier {
1021*593dc095SDavid du Colombier pdf14_device * pdev = (pdf14_device *)dev;
1022*593dc095SDavid du Colombier
1023*593dc095SDavid du Colombier pdev->opacity = pis->opacity.alpha;
1024*593dc095SDavid du Colombier pdev->shape = pis->shape.alpha;
1025*593dc095SDavid du Colombier pdev->alpha = pis->opacity.alpha * pis->shape.alpha;
1026*593dc095SDavid du Colombier pdev->blend_mode = pis->blend_mode;
1027*593dc095SDavid du Colombier if_debug3('v', "[v]set_marking_params, opacity = %g, shape = %g, bm = %d\n",
1028*593dc095SDavid du Colombier pdev->opacity, pdev->shape, pis->blend_mode);
10293ff48bf5SDavid du Colombier }
10303ff48bf5SDavid du Colombier
10313ff48bf5SDavid du Colombier private int
pdf14_fill_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)10323ff48bf5SDavid du Colombier pdf14_fill_path(gx_device *dev, const gs_imager_state *pis,
10333ff48bf5SDavid du Colombier gx_path *ppath, const gx_fill_params *params,
10343ff48bf5SDavid du Colombier const gx_drawing_color *pdcolor,
10353ff48bf5SDavid du Colombier const gx_clip_path *pcpath)
10363ff48bf5SDavid du Colombier {
10373ff48bf5SDavid du Colombier gs_imager_state new_is = *pis;
10383ff48bf5SDavid du Colombier
1039*593dc095SDavid du Colombier /*
1040*593dc095SDavid du Colombier * The blend operations are not idempotent. Force non-idempotent
1041*593dc095SDavid du Colombier * filling and stroking operations.
1042*593dc095SDavid du Colombier */
10433ff48bf5SDavid du Colombier new_is.log_op |= lop_pdf14;
1044*593dc095SDavid du Colombier pdf14_set_marking_params(dev, pis);
1045*593dc095SDavid du Colombier return gx_default_fill_path(dev, &new_is, ppath, params, pdcolor, pcpath);
10463ff48bf5SDavid du Colombier }
10473ff48bf5SDavid du Colombier
10483ff48bf5SDavid du Colombier private int
pdf14_stroke_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_stroke_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)10493ff48bf5SDavid du Colombier pdf14_stroke_path(gx_device *dev, const gs_imager_state *pis,
10503ff48bf5SDavid du Colombier gx_path *ppath, const gx_stroke_params *params,
10513ff48bf5SDavid du Colombier const gx_drawing_color *pdcolor,
10523ff48bf5SDavid du Colombier const gx_clip_path *pcpath)
10533ff48bf5SDavid du Colombier {
10543ff48bf5SDavid du Colombier gs_imager_state new_is = *pis;
10553ff48bf5SDavid du Colombier
1056*593dc095SDavid du Colombier /*
1057*593dc095SDavid du Colombier * The blend operations are not idempotent. Force non-idempotent
1058*593dc095SDavid du Colombier * filling and stroking operations.
1059*593dc095SDavid du Colombier */
10603ff48bf5SDavid du Colombier new_is.log_op |= lop_pdf14;
1061*593dc095SDavid du Colombier pdf14_set_marking_params(dev, pis);
1062*593dc095SDavid du Colombier return gx_default_stroke_path(dev, &new_is, ppath, params, pdcolor,
10633ff48bf5SDavid du Colombier pcpath);
10643ff48bf5SDavid du Colombier }
10653ff48bf5SDavid du Colombier
10663ff48bf5SDavid du Colombier private int
pdf14_begin_typed_image(gx_device * dev,const gs_imager_state * pis,const gs_matrix * pmat,const gs_image_common_t * pic,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * mem,gx_image_enum_common_t ** pinfo)10673ff48bf5SDavid du Colombier pdf14_begin_typed_image(gx_device * dev, const gs_imager_state * pis,
10683ff48bf5SDavid du Colombier const gs_matrix *pmat, const gs_image_common_t *pic,
10693ff48bf5SDavid du Colombier const gs_int_rect * prect,
10703ff48bf5SDavid du Colombier const gx_drawing_color * pdcolor,
10713ff48bf5SDavid du Colombier const gx_clip_path * pcpath, gs_memory_t * mem,
10723ff48bf5SDavid du Colombier gx_image_enum_common_t ** pinfo)
10733ff48bf5SDavid du Colombier {
1074*593dc095SDavid du Colombier pdf14_set_marking_params(dev, pis);
1075*593dc095SDavid du Colombier return gx_default_begin_typed_image(dev, pis, pmat, pic, prect, pdcolor,
10763ff48bf5SDavid du Colombier pcpath, mem, pinfo);
10773ff48bf5SDavid du Colombier }
10783ff48bf5SDavid du Colombier
10793ff48bf5SDavid du Colombier private void
pdf14_set_params(gs_imager_state * pis,gx_device * dev,const gs_pdf14trans_params_t * pparams)1080*593dc095SDavid du Colombier pdf14_set_params(gs_imager_state * pis, gx_device * dev,
1081*593dc095SDavid du Colombier const gs_pdf14trans_params_t * pparams)
10823ff48bf5SDavid du Colombier {
1083*593dc095SDavid du Colombier if (pparams->changed & PDF14_SET_BLEND_MODE)
1084*593dc095SDavid du Colombier pis->blend_mode = pparams->blend_mode;
1085*593dc095SDavid du Colombier if (pparams->changed & PDF14_SET_TEXT_KNOCKOUT)
1086*593dc095SDavid du Colombier pis->text_knockout = pparams->text_knockout;
1087*593dc095SDavid du Colombier if (pparams->changed & PDF14_SET_SHAPE_ALPHA)
1088*593dc095SDavid du Colombier pis->shape.alpha = pparams->shape.alpha;
1089*593dc095SDavid du Colombier if (pparams->changed & PDF14_SET_OPACITY_ALPHA)
1090*593dc095SDavid du Colombier pis->opacity.alpha = pparams->opacity.alpha;
1091*593dc095SDavid du Colombier pdf14_set_marking_params(dev, pis);
10923ff48bf5SDavid du Colombier }
10933ff48bf5SDavid du Colombier
1094*593dc095SDavid du Colombier /*
1095*593dc095SDavid du Colombier * This open_device method for the PDF 1.4 compositor devices is only used
1096*593dc095SDavid du Colombier * when these devices are disabled. This routine is about as close to
1097*593dc095SDavid du Colombier * a pure "forwarding" open_device operation as is possible. Its only
1098*593dc095SDavid du Colombier * significant function is to ensure that the is_open field of the
1099*593dc095SDavid du Colombier * PDF 1.4 compositor devices matches that of the target device.
1100*593dc095SDavid du Colombier *
1101*593dc095SDavid du Colombier * We assume this procedure is called only if the device is not already
1102*593dc095SDavid du Colombier * open, and that gs_opendevice will take care of the is_open flag.
1103*593dc095SDavid du Colombier */
1104*593dc095SDavid du Colombier private int
pdf14_forward_open_device(gx_device * dev)1105*593dc095SDavid du Colombier pdf14_forward_open_device(gx_device * dev)
1106*593dc095SDavid du Colombier {
1107*593dc095SDavid du Colombier gx_device_forward * pdev = (gx_device_forward *)dev;
1108*593dc095SDavid du Colombier gx_device * tdev = pdev->target;
1109*593dc095SDavid du Colombier int code = 0;
1110*593dc095SDavid du Colombier
1111*593dc095SDavid du Colombier /* The PDF 1.4 compositing devices must have a target */
1112*593dc095SDavid du Colombier if (tdev == 0)
1113*593dc095SDavid du Colombier return_error(gs_error_unknownerror);
1114*593dc095SDavid du Colombier if ((code = gs_opendevice(tdev)) >= 0)
1115*593dc095SDavid du Colombier gx_device_copy_params(dev, tdev);
1116*593dc095SDavid du Colombier return code;
1117*593dc095SDavid du Colombier }
1118*593dc095SDavid du Colombier
1119*593dc095SDavid du Colombier /*
1120*593dc095SDavid du Colombier * Convert all device procs to be 'forwarding'. The caller is responsible
1121*593dc095SDavid du Colombier * for setting any device procs that should not be forwarded.
1122*593dc095SDavid du Colombier */
1123*593dc095SDavid du Colombier private void
pdf14_forward_device_procs(gx_device * dev)1124*593dc095SDavid du Colombier pdf14_forward_device_procs(gx_device * dev)
1125*593dc095SDavid du Colombier {
1126*593dc095SDavid du Colombier gx_device_forward * pdev = (gx_device_forward *)dev;
1127*593dc095SDavid du Colombier
1128*593dc095SDavid du Colombier /*
1129*593dc095SDavid du Colombier * We are using gx_device_forward_fill_in_procs to set the various procs.
1130*593dc095SDavid du Colombier * This will ensure that any new device procs are also set. However that
1131*593dc095SDavid du Colombier * routine only changes procs which are NULL. Thus we start by setting all
1132*593dc095SDavid du Colombier * procs to NULL.
1133*593dc095SDavid du Colombier */
1134*593dc095SDavid du Colombier memset(&(pdev->procs), 0, size_of(pdev->procs));
1135*593dc095SDavid du Colombier gx_device_forward_fill_in_procs(pdev);
1136*593dc095SDavid du Colombier /*
1137*593dc095SDavid du Colombier * gx_device_forward_fill_in_procs does not forward all procs.
1138*593dc095SDavid du Colombier * Set the remainding procs to also forward.
1139*593dc095SDavid du Colombier */
1140*593dc095SDavid du Colombier set_dev_proc(dev, close_device, gx_forward_close_device);
1141*593dc095SDavid du Colombier set_dev_proc(dev, fill_rectangle, gx_forward_fill_rectangle);
1142*593dc095SDavid du Colombier set_dev_proc(dev, tile_rectangle, gx_forward_tile_rectangle);
1143*593dc095SDavid du Colombier set_dev_proc(dev, copy_mono, gx_forward_copy_mono);
1144*593dc095SDavid du Colombier set_dev_proc(dev, copy_color, gx_forward_copy_color);
1145*593dc095SDavid du Colombier set_dev_proc(dev, get_page_device, gx_forward_get_page_device);
1146*593dc095SDavid du Colombier set_dev_proc(dev, strip_tile_rectangle, gx_forward_strip_tile_rectangle);
1147*593dc095SDavid du Colombier set_dev_proc(dev, copy_alpha, gx_forward_copy_alpha);
1148*593dc095SDavid du Colombier /* These are forwarding devices with minor tweaks. */
1149*593dc095SDavid du Colombier set_dev_proc(dev, open_device, pdf14_forward_open_device);
1150*593dc095SDavid du Colombier set_dev_proc(dev, put_params, pdf14_forward_put_params);
1151*593dc095SDavid du Colombier }
1152*593dc095SDavid du Colombier
1153*593dc095SDavid du Colombier /*
1154*593dc095SDavid du Colombier * Disable the PDF 1.4 compositor device. Once created, the PDF 1.4
1155*593dc095SDavid du Colombier * compositor device is never removed. (We do not have a remove compositor
1156*593dc095SDavid du Colombier * method.) However it is no-op'ed when the PDF 1.4 device is popped. This
1157*593dc095SDavid du Colombier * routine implements that action.
1158*593dc095SDavid du Colombier */
1159*593dc095SDavid du Colombier private int
pdf14_disable_device(gx_device * dev)1160*593dc095SDavid du Colombier pdf14_disable_device(gx_device * dev)
1161*593dc095SDavid du Colombier {
1162*593dc095SDavid du Colombier gx_device_forward * pdev = (gx_device_forward *)dev;
1163*593dc095SDavid du Colombier
1164*593dc095SDavid du Colombier if_debug0('v', "[v]pdf14_disable_device\n");
1165*593dc095SDavid du Colombier dev->color_info = pdev->target->color_info;
1166*593dc095SDavid du Colombier pdf14_forward_device_procs(dev);
1167*593dc095SDavid du Colombier set_dev_proc(dev, create_compositor, pdf14_forward_create_compositor);
1168*593dc095SDavid du Colombier return 0;
1169*593dc095SDavid du Colombier }
1170*593dc095SDavid du Colombier
1171*593dc095SDavid du Colombier /*
1172*593dc095SDavid du Colombier * The default color space for PDF 1.4 blend modes is based upon the process
1173*593dc095SDavid du Colombier * color model of the output device.
1174*593dc095SDavid du Colombier */
1175*593dc095SDavid du Colombier private pdf14_default_colorspace_t
pdf14_determine_default_blend_cs(gx_device * pdev)1176*593dc095SDavid du Colombier pdf14_determine_default_blend_cs(gx_device * pdev)
1177*593dc095SDavid du Colombier {
1178*593dc095SDavid du Colombier if (pdev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE)
1179*593dc095SDavid du Colombier /* Use DeviceCMYK for all subrtactive process color models. */
1180*593dc095SDavid du Colombier return DeviceCMYK;
1181*593dc095SDavid du Colombier else {
1182*593dc095SDavid du Colombier /*
1183*593dc095SDavid du Colombier * Note: We do not allow the SeparationOrder device parameter for
1184*593dc095SDavid du Colombier * additive devices. Thus we always have 1 colorant for DeviceGray
1185*593dc095SDavid du Colombier * and 3 colorants for DeviceRGB. We do not currently support
1186*593dc095SDavid du Colombier * blending in a DeviceGray color space. Thus we oniy use DeviceRGB.
1187*593dc095SDavid du Colombier */
1188*593dc095SDavid du Colombier return DeviceRGB;
1189*593dc095SDavid du Colombier }
1190*593dc095SDavid du Colombier }
1191*593dc095SDavid du Colombier
1192*593dc095SDavid du Colombier /*
1193*593dc095SDavid du Colombier * the PDF 1.4 transparency spec says that color space for blending
1194*593dc095SDavid du Colombier * operations can be based upon either a color space specified in the
1195*593dc095SDavid du Colombier * group or a default value based upon the output device. We are
1196*593dc095SDavid du Colombier * currently only using a color space based upon the device.
1197*593dc095SDavid du Colombier */
1198*593dc095SDavid du Colombier private int
get_pdf14_device_proto(gx_device * dev,const pdf14_device ** pdevproto)1199*593dc095SDavid du Colombier get_pdf14_device_proto(gx_device * dev,
1200*593dc095SDavid du Colombier const pdf14_device ** pdevproto)
1201*593dc095SDavid du Colombier {
1202*593dc095SDavid du Colombier pdf14_default_colorspace_t dev_cs =
1203*593dc095SDavid du Colombier pdf14_determine_default_blend_cs(dev);
1204*593dc095SDavid du Colombier
1205*593dc095SDavid du Colombier switch (dev_cs) {
1206*593dc095SDavid du Colombier case DeviceGray:
1207*593dc095SDavid du Colombier *pdevproto = &gs_pdf14_Gray_device;
1208*593dc095SDavid du Colombier break;
1209*593dc095SDavid du Colombier case DeviceRGB:
1210*593dc095SDavid du Colombier *pdevproto = &gs_pdf14_RGB_device;
1211*593dc095SDavid du Colombier break;
1212*593dc095SDavid du Colombier case DeviceCMYK:
1213*593dc095SDavid du Colombier *pdevproto = &gs_pdf14_CMYK_device;
1214*593dc095SDavid du Colombier break;
1215*593dc095SDavid du Colombier default: /* Should not occur */
1216*593dc095SDavid du Colombier return_error(gs_error_rangecheck);
1217*593dc095SDavid du Colombier }
1218*593dc095SDavid du Colombier return 0;
1219*593dc095SDavid du Colombier }
1220*593dc095SDavid du Colombier
1221*593dc095SDavid du Colombier /*
1222*593dc095SDavid du Colombier * Recreate the PDF 1.4 compositor device. Once created, the PDF 1.4
1223*593dc095SDavid du Colombier * compositor device is never removed. (We do not have a remove compositor
1224*593dc095SDavid du Colombier * method.) However it is no-op'ed when the PDF 1.4 device is popped. This
1225*593dc095SDavid du Colombier * routine will re-enable the compositor if the PDF 1.4 device is pushed
1226*593dc095SDavid du Colombier * again.
1227*593dc095SDavid du Colombier */
1228*593dc095SDavid du Colombier private int
pdf14_recreate_device(gs_memory_t * mem,gs_imager_state * pis,gx_device * dev)1229*593dc095SDavid du Colombier pdf14_recreate_device(gs_memory_t *mem, gs_imager_state * pis,
1230*593dc095SDavid du Colombier gx_device * dev)
1231*593dc095SDavid du Colombier {
1232*593dc095SDavid du Colombier pdf14_device * pdev = (pdf14_device *)dev;
1233*593dc095SDavid du Colombier gx_device * target = pdev->target;
1234*593dc095SDavid du Colombier const pdf14_device * dev_proto;
1235*593dc095SDavid du Colombier int code;
1236*593dc095SDavid du Colombier
1237*593dc095SDavid du Colombier if_debug0('v', "[v]pdf14_recreate_device\n");
1238*593dc095SDavid du Colombier
1239*593dc095SDavid du Colombier /*
1240*593dc095SDavid du Colombier * We will not use the entire prototype device but we will set the
1241*593dc095SDavid du Colombier * color related info and the device procs to match the prototype.
1242*593dc095SDavid du Colombier */
1243*593dc095SDavid du Colombier code = get_pdf14_device_proto(target, &dev_proto);
1244*593dc095SDavid du Colombier if (code < 0)
1245*593dc095SDavid du Colombier return code;
1246*593dc095SDavid du Colombier pdev->color_info = dev_proto->color_info;
1247*593dc095SDavid du Colombier pdev->procs = dev_proto->procs;
1248*593dc095SDavid du Colombier gx_device_fill_in_procs(dev);
1249*593dc095SDavid du Colombier check_device_separable((gx_device *)pdev);
1250*593dc095SDavid du Colombier
1251*593dc095SDavid du Colombier return code;
1252*593dc095SDavid du Colombier }
1253*593dc095SDavid du Colombier
1254*593dc095SDavid du Colombier /*
1255*593dc095SDavid du Colombier * Implement the various operations that can be specified via the PDF 1.4
1256*593dc095SDavid du Colombier * create compositor request.
1257*593dc095SDavid du Colombier */
1258*593dc095SDavid du Colombier private int
gx_update_pdf14_compositor(gx_device * pdev,gs_imager_state * pis,const gs_pdf14trans_t * pdf14pct,gs_memory_t * mem)1259*593dc095SDavid du Colombier gx_update_pdf14_compositor(gx_device * pdev, gs_imager_state * pis,
1260*593dc095SDavid du Colombier const gs_pdf14trans_t * pdf14pct, gs_memory_t * mem )
1261*593dc095SDavid du Colombier {
1262*593dc095SDavid du Colombier pdf14_device *p14dev = (pdf14_device *)pdev;
1263*593dc095SDavid du Colombier int code = 0;
1264*593dc095SDavid du Colombier
1265*593dc095SDavid du Colombier switch (pdf14pct->params.pdf14_op) {
1266*593dc095SDavid du Colombier default: /* Should not occur. */
1267*593dc095SDavid du Colombier break;
1268*593dc095SDavid du Colombier case PDF14_PUSH_DEVICE:
1269*593dc095SDavid du Colombier p14dev->blend_mode = 0;
1270*593dc095SDavid du Colombier p14dev->opacity = p14dev->shape = 0.0;
1271*593dc095SDavid du Colombier pdf14_recreate_device(mem, pis, pdev);
1272*593dc095SDavid du Colombier break;
1273*593dc095SDavid du Colombier case PDF14_POP_DEVICE:
1274*593dc095SDavid du Colombier pis->get_cmap_procs = p14dev->save_get_cmap_procs;
1275*593dc095SDavid du Colombier gx_set_cmap_procs(pis, p14dev->target);
1276*593dc095SDavid du Colombier code = pdf14_put_image(p14dev, pis, p14dev->target);
1277*593dc095SDavid du Colombier pdf14_disable_device(pdev);
1278*593dc095SDavid du Colombier pdf14_close(pdev);
1279*593dc095SDavid du Colombier break;
1280*593dc095SDavid du Colombier case PDF14_BEGIN_TRANS_GROUP:
1281*593dc095SDavid du Colombier code = gx_begin_transparency_group(pis, pdev, &pdf14pct->params);
1282*593dc095SDavid du Colombier break;
1283*593dc095SDavid du Colombier case PDF14_END_TRANS_GROUP:
1284*593dc095SDavid du Colombier code = gx_end_transparency_group(pis, pdev);
1285*593dc095SDavid du Colombier break;
1286*593dc095SDavid du Colombier case PDF14_INIT_TRANS_MASK:
1287*593dc095SDavid du Colombier code = gx_init_transparency_mask(pis, &pdf14pct->params);
1288*593dc095SDavid du Colombier break;
1289*593dc095SDavid du Colombier case PDF14_BEGIN_TRANS_MASK:
1290*593dc095SDavid du Colombier code = gx_begin_transparency_mask(pis, pdev, &pdf14pct->params);
1291*593dc095SDavid du Colombier break;
1292*593dc095SDavid du Colombier case PDF14_END_TRANS_MASK:
1293*593dc095SDavid du Colombier code = gx_end_transparency_mask(pis, pdev, &pdf14pct->params);
1294*593dc095SDavid du Colombier break;
1295*593dc095SDavid du Colombier case PDF14_SET_BLEND_PARAMS:
1296*593dc095SDavid du Colombier pdf14_set_params(pis, pdev, &pdf14pct->params);
1297*593dc095SDavid du Colombier break;
1298*593dc095SDavid du Colombier }
1299*593dc095SDavid du Colombier return code;
1300*593dc095SDavid du Colombier }
1301*593dc095SDavid du Colombier
1302*593dc095SDavid du Colombier /*
1303*593dc095SDavid du Colombier * The PDF 1.4 compositor is never removed. (We do not have a 'remove
1304*593dc095SDavid du Colombier * compositor' method. However the compositor is disabled when we are not
1305*593dc095SDavid du Colombier * doing a page which uses PDF 1.4 transparency. This routine is only active
1306*593dc095SDavid du Colombier * when the PDF 1.4 compositor is 'disabled'. It checks for reenabling the
1307*593dc095SDavid du Colombier * PDF 1.4 compositor. Otherwise it simply passes create compositor requests
1308*593dc095SDavid du Colombier * to the targer.
1309*593dc095SDavid du Colombier */
1310*593dc095SDavid du Colombier private int
pdf14_forward_create_compositor(gx_device * dev,gx_device ** pcdev,const gs_composite_t * pct,gs_imager_state * pis,gs_memory_t * mem)1311*593dc095SDavid du Colombier pdf14_forward_create_compositor(gx_device * dev, gx_device * * pcdev,
1312*593dc095SDavid du Colombier const gs_composite_t * pct, gs_imager_state * pis,
1313*593dc095SDavid du Colombier gs_memory_t * mem)
1314*593dc095SDavid du Colombier {
1315*593dc095SDavid du Colombier pdf14_device *pdev = (pdf14_device *)dev;
1316*593dc095SDavid du Colombier gx_device * tdev = pdev->target;
1317*593dc095SDavid du Colombier gx_device * ndev;
1318*593dc095SDavid du Colombier int code = 0;
1319*593dc095SDavid du Colombier
1320*593dc095SDavid du Colombier *pcdev = dev;
1321*593dc095SDavid du Colombier if (gs_is_pdf14trans_compositor(pct)) {
1322*593dc095SDavid du Colombier const gs_pdf14trans_t * pdf14pct = (const gs_pdf14trans_t *) pct;
1323*593dc095SDavid du Colombier
1324*593dc095SDavid du Colombier if (pdf14pct->params.pdf14_op == PDF14_PUSH_DEVICE)
1325*593dc095SDavid du Colombier return gx_update_pdf14_compositor(dev, pis, pdf14pct, mem);
1326*593dc095SDavid du Colombier return 0;
1327*593dc095SDavid du Colombier }
1328*593dc095SDavid du Colombier code = dev_proc(tdev, create_compositor)(tdev, &ndev, pct, pis, mem);
1329*593dc095SDavid du Colombier if (code < 0)
1330*593dc095SDavid du Colombier return code;
1331*593dc095SDavid du Colombier pdev->target = ndev;
1332*593dc095SDavid du Colombier return 0;
1333*593dc095SDavid du Colombier }
1334*593dc095SDavid du Colombier
1335*593dc095SDavid du Colombier /*
1336*593dc095SDavid du Colombier * The PDF 1.4 compositor can be handled directly, so just set *pcdev = dev
1337*593dc095SDavid du Colombier * and return. Since the gs_pdf14_device only supports the high-level routines
1338*593dc095SDavid du Colombier * of the interface, don't bother trying to handle any other compositor.
1339*593dc095SDavid du Colombier */
1340*593dc095SDavid du Colombier private int
pdf14_create_compositor(gx_device * dev,gx_device ** pcdev,const gs_composite_t * pct,gs_imager_state * pis,gs_memory_t * mem)1341*593dc095SDavid du Colombier pdf14_create_compositor(gx_device * dev, gx_device * * pcdev,
1342*593dc095SDavid du Colombier const gs_composite_t * pct, gs_imager_state * pis,
1343*593dc095SDavid du Colombier gs_memory_t * mem)
1344*593dc095SDavid du Colombier {
1345*593dc095SDavid du Colombier if (gs_is_pdf14trans_compositor(pct)) {
1346*593dc095SDavid du Colombier const gs_pdf14trans_t * pdf14pct = (const gs_pdf14trans_t *) pct;
1347*593dc095SDavid du Colombier
1348*593dc095SDavid du Colombier *pcdev = dev;
1349*593dc095SDavid du Colombier return gx_update_pdf14_compositor(dev, pis, pdf14pct, mem);
1350*593dc095SDavid du Colombier } else if (gs_is_overprint_compositor(pct)) {
1351*593dc095SDavid du Colombier *pcdev = dev;
1352*593dc095SDavid du Colombier return 0;
1353*593dc095SDavid du Colombier } else
1354*593dc095SDavid du Colombier return gx_no_create_compositor(dev, pcdev, pct, pis, mem);
1355*593dc095SDavid du Colombier }
13563ff48bf5SDavid du Colombier
13573ff48bf5SDavid du Colombier private int
pdf14_text_begin(gx_device * dev,gs_imager_state * pis,const gs_text_params_t * text,gs_font * font,gx_path * path,const gx_device_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * memory,gs_text_enum_t ** ppenum)13583ff48bf5SDavid du Colombier pdf14_text_begin(gx_device * dev, gs_imager_state * pis,
13593ff48bf5SDavid du Colombier const gs_text_params_t * text, gs_font * font,
13603ff48bf5SDavid du Colombier gx_path * path, const gx_device_color * pdcolor,
13613ff48bf5SDavid du Colombier const gx_clip_path * pcpath, gs_memory_t * memory,
13623ff48bf5SDavid du Colombier gs_text_enum_t ** ppenum)
13633ff48bf5SDavid du Colombier {
13643ff48bf5SDavid du Colombier int code;
1365*593dc095SDavid du Colombier gs_text_enum_t *penum;
13663ff48bf5SDavid du Colombier
13673ff48bf5SDavid du Colombier if_debug0('v', "[v]pdf14_text_begin\n");
1368*593dc095SDavid du Colombier pdf14_set_marking_params(dev, pis);
1369*593dc095SDavid du Colombier code = gx_default_text_begin(dev, pis, text, font, path, pdcolor, pcpath,
1370*593dc095SDavid du Colombier memory, &penum);
1371*593dc095SDavid du Colombier if (code < 0)
13723ff48bf5SDavid du Colombier return code;
13733ff48bf5SDavid du Colombier *ppenum = (gs_text_enum_t *)penum;
13743ff48bf5SDavid du Colombier return code;
13753ff48bf5SDavid du Colombier }
13763ff48bf5SDavid du Colombier
13773ff48bf5SDavid du Colombier private int
pdf14_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)13783ff48bf5SDavid du Colombier pdf14_fill_rectangle(gx_device * dev,
13793ff48bf5SDavid du Colombier int x, int y, int w, int h, gx_color_index color)
13803ff48bf5SDavid du Colombier {
1381*593dc095SDavid du Colombier pdf14_device *pdev = (pdf14_device *)dev;
1382*593dc095SDavid du Colombier pdf14_buf *buf = pdev->ctx->stack;
13833ff48bf5SDavid du Colombier
1384*593dc095SDavid du Colombier fit_fill_xywh(dev, x, y, w, h);
1385*593dc095SDavid du Colombier if (w <= 0 || h <= 0)
1386*593dc095SDavid du Colombier return 0;
1387*593dc095SDavid du Colombier if (buf->knockout)
1388*593dc095SDavid du Colombier return pdf14_mark_fill_rectangle_ko_simple(dev, x, y, w, h, color);
1389*593dc095SDavid du Colombier else
1390*593dc095SDavid du Colombier return pdf14_mark_fill_rectangle(dev, x, y, w, h, color);
1391*593dc095SDavid du Colombier }
13923ff48bf5SDavid du Colombier
13933ff48bf5SDavid du Colombier private int
pdf14_begin_transparency_group(gx_device * dev,const gs_transparency_group_params_t * ptgp,const gs_rect * pbbox,gs_imager_state * pis,gs_transparency_state_t ** ppts,gs_memory_t * mem)13943ff48bf5SDavid du Colombier pdf14_begin_transparency_group(gx_device *dev,
13953ff48bf5SDavid du Colombier const gs_transparency_group_params_t *ptgp,
13963ff48bf5SDavid du Colombier const gs_rect *pbbox,
13973ff48bf5SDavid du Colombier gs_imager_state *pis,
13983ff48bf5SDavid du Colombier gs_transparency_state_t **ppts,
13993ff48bf5SDavid du Colombier gs_memory_t *mem)
14003ff48bf5SDavid du Colombier {
14013ff48bf5SDavid du Colombier pdf14_device *pdev = (pdf14_device *)dev;
14023ff48bf5SDavid du Colombier double alpha = pis->opacity.alpha * pis->shape.alpha;
1403*593dc095SDavid du Colombier gs_rect dev_bbox;
1404*593dc095SDavid du Colombier gs_int_rect rect;
14053ff48bf5SDavid du Colombier int code;
14063ff48bf5SDavid du Colombier
1407*593dc095SDavid du Colombier code = gs_bbox_transform(pbbox, &ctm_only(pis), &dev_bbox);
1408*593dc095SDavid du Colombier if (code < 0)
1409*593dc095SDavid du Colombier return code;
1410*593dc095SDavid du Colombier rect.p.x = (int)floor(dev_bbox.p.x);
1411*593dc095SDavid du Colombier rect.p.y = (int)floor(dev_bbox.p.y);
1412*593dc095SDavid du Colombier rect.q.x = (int)ceil(dev_bbox.q.x);
1413*593dc095SDavid du Colombier rect.q.y = (int)ceil(dev_bbox.q.y);
1414*593dc095SDavid du Colombier rect_intersect(rect, pdev->ctx->rect);
14153ff48bf5SDavid du Colombier if_debug4('v', "[v]begin_transparency_group, I = %d, K = %d, alpha = %g, bm = %d\n",
14163ff48bf5SDavid du Colombier ptgp->Isolated, ptgp->Knockout, alpha, pis->blend_mode);
1417*593dc095SDavid du Colombier code = pdf14_push_transparency_group(pdev->ctx, &rect,
14183ff48bf5SDavid du Colombier ptgp->Isolated, ptgp->Knockout,
1419*593dc095SDavid du Colombier (byte)floor (255 * alpha + 0.5),
1420*593dc095SDavid du Colombier (byte)floor (255 * pis->shape.alpha + 0.5),
14213ff48bf5SDavid du Colombier pis->blend_mode);
14223ff48bf5SDavid du Colombier return code;
14233ff48bf5SDavid du Colombier }
14243ff48bf5SDavid du Colombier
14253ff48bf5SDavid du Colombier private int
pdf14_end_transparency_group(gx_device * dev,gs_imager_state * pis,gs_transparency_state_t ** ppts)14263ff48bf5SDavid du Colombier pdf14_end_transparency_group(gx_device *dev,
14273ff48bf5SDavid du Colombier gs_imager_state *pis,
14283ff48bf5SDavid du Colombier gs_transparency_state_t **ppts)
14293ff48bf5SDavid du Colombier {
14303ff48bf5SDavid du Colombier pdf14_device *pdev = (pdf14_device *)dev;
14313ff48bf5SDavid du Colombier int code;
14323ff48bf5SDavid du Colombier
14333ff48bf5SDavid du Colombier if_debug0('v', "[v]end_transparency_group\n");
14343ff48bf5SDavid du Colombier code = pdf14_pop_transparency_group(pdev->ctx);
14353ff48bf5SDavid du Colombier return code;
14363ff48bf5SDavid du Colombier }
14373ff48bf5SDavid du Colombier
14383ff48bf5SDavid du Colombier private int
pdf14_begin_transparency_mask(gx_device * dev,const gx_transparency_mask_params_t * ptmp,const gs_rect * pbbox,gs_imager_state * pis,gs_transparency_state_t ** ppts,gs_memory_t * mem)1439*593dc095SDavid du Colombier pdf14_begin_transparency_mask(gx_device *dev,
1440*593dc095SDavid du Colombier const gx_transparency_mask_params_t *ptmp,
1441*593dc095SDavid du Colombier const gs_rect *pbbox,
1442*593dc095SDavid du Colombier gs_imager_state *pis,
1443*593dc095SDavid du Colombier gs_transparency_state_t **ppts,
1444*593dc095SDavid du Colombier gs_memory_t *mem)
1445*593dc095SDavid du Colombier {
1446*593dc095SDavid du Colombier pdf14_device *pdev = (pdf14_device *)dev;
1447*593dc095SDavid du Colombier byte bg_alpha = 0;
1448*593dc095SDavid du Colombier byte *transfer_fn = (byte *)gs_alloc_bytes(pdev->ctx->memory, 256,
1449*593dc095SDavid du Colombier "pdf14_push_transparency_mask");
1450*593dc095SDavid du Colombier
1451*593dc095SDavid du Colombier if (ptmp->Background_components)
1452*593dc095SDavid du Colombier bg_alpha = (int)(255 * ptmp->Background[0] + 0.5);
1453*593dc095SDavid du Colombier if_debug1('v', "begin transparency mask, bg_alpha = %d\n", bg_alpha);
1454*593dc095SDavid du Colombier memcpy(transfer_fn, ptmp->transfer_fn, size_of(ptmp->transfer_fn));
1455*593dc095SDavid du Colombier return pdf14_push_transparency_mask(pdev->ctx, &pdev->ctx->rect, bg_alpha,
1456*593dc095SDavid du Colombier transfer_fn);
1457*593dc095SDavid du Colombier }
1458*593dc095SDavid du Colombier
1459*593dc095SDavid du Colombier private int
pdf14_end_transparency_mask(gx_device * dev,gs_transparency_mask_t ** pptm)1460*593dc095SDavid du Colombier pdf14_end_transparency_mask(gx_device *dev,
1461*593dc095SDavid du Colombier gs_transparency_mask_t **pptm)
1462*593dc095SDavid du Colombier {
1463*593dc095SDavid du Colombier pdf14_device *pdev = (pdf14_device *)dev;
1464*593dc095SDavid du Colombier
1465*593dc095SDavid du Colombier if_debug0('v', "end transparency mask!\n");
1466*593dc095SDavid du Colombier return pdf14_pop_transparency_mask(pdev->ctx);
1467*593dc095SDavid du Colombier }
1468*593dc095SDavid du Colombier
1469*593dc095SDavid du Colombier private int
pdf14_mark_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)14703ff48bf5SDavid du Colombier pdf14_mark_fill_rectangle(gx_device * dev,
14713ff48bf5SDavid du Colombier int x, int y, int w, int h, gx_color_index color)
14723ff48bf5SDavid du Colombier {
1473*593dc095SDavid du Colombier pdf14_device *pdev = (pdf14_device *)dev;
14743ff48bf5SDavid du Colombier pdf14_buf *buf = pdev->ctx->stack;
14753ff48bf5SDavid du Colombier int i, j, k;
14763ff48bf5SDavid du Colombier byte *line, *dst_ptr;
14773ff48bf5SDavid du Colombier byte src[PDF14_MAX_PLANES];
14783ff48bf5SDavid du Colombier byte dst[PDF14_MAX_PLANES];
1479*593dc095SDavid du Colombier gs_blend_mode_t blend_mode = pdev->blend_mode;
1480*593dc095SDavid du Colombier bool additive = pdev->ctx->additive;
14813ff48bf5SDavid du Colombier int rowstride = buf->rowstride;
14823ff48bf5SDavid du Colombier int planestride = buf->planestride;
14833ff48bf5SDavid du Colombier bool has_alpha_g = buf->has_alpha_g;
14843ff48bf5SDavid du Colombier bool has_shape = buf->has_shape;
1485*593dc095SDavid du Colombier int num_chan = buf->n_chan;
1486*593dc095SDavid du Colombier int num_comp = num_chan - 1;
1487*593dc095SDavid du Colombier int shape_off = num_chan * planestride;
14883ff48bf5SDavid du Colombier int alpha_g_off = shape_off + (has_shape ? planestride : 0);
1489*593dc095SDavid du Colombier byte shape = 0; /* Quiet compiler. */
1490*593dc095SDavid du Colombier byte src_alpha;
14913ff48bf5SDavid du Colombier
1492*593dc095SDavid du Colombier if_debug7('v', "[v]pdf14_mark_fill_rectangle, (%d, %d), %d x %d color = %lx bm %d, nc %d,\n", x, y, w, h, color, blend_mode, num_chan);
1493*593dc095SDavid du Colombier
1494*593dc095SDavid du Colombier /* Complement the components for subtractive color spaces */
1495*593dc095SDavid du Colombier if (additive) {
1496*593dc095SDavid du Colombier for (i = num_comp - 1; i >= 0; i--) {
1497*593dc095SDavid du Colombier src[i] = (byte)(color & 0xff);
1498*593dc095SDavid du Colombier color >>= 8;
1499*593dc095SDavid du Colombier }
1500*593dc095SDavid du Colombier }
1501*593dc095SDavid du Colombier else {
1502*593dc095SDavid du Colombier for (i = num_comp - 1; i >= 0; i--) {
1503*593dc095SDavid du Colombier src[i] = (byte)(0xff - (color & 0xff));
1504*593dc095SDavid du Colombier color >>= 8;
1505*593dc095SDavid du Colombier }
1506*593dc095SDavid du Colombier }
1507*593dc095SDavid du Colombier src_alpha = src[num_comp] = (byte)floor (255 * pdev->alpha + 0.5);
15083ff48bf5SDavid du Colombier if (has_shape)
1509*593dc095SDavid du Colombier shape = (byte)floor (255 * pdev->shape + 0.5);
15103ff48bf5SDavid du Colombier
15113ff48bf5SDavid du Colombier if (x < buf->rect.p.x) x = buf->rect.p.x;
1512*593dc095SDavid du Colombier if (y < buf->rect.p.y) y = buf->rect.p.y;
15133ff48bf5SDavid du Colombier if (x + w > buf->rect.q.x) w = buf->rect.q.x - x;
15143ff48bf5SDavid du Colombier if (y + h > buf->rect.q.y) h = buf->rect.q.y - y;
15153ff48bf5SDavid du Colombier
1516*593dc095SDavid du Colombier if (x < buf->bbox.p.x) buf->bbox.p.x = x;
1517*593dc095SDavid du Colombier if (y < buf->bbox.p.y) buf->bbox.p.y = y;
1518*593dc095SDavid du Colombier if (x + w > buf->bbox.q.x) buf->bbox.q.x = x + w;
1519*593dc095SDavid du Colombier if (y + h > buf->bbox.q.y) buf->bbox.q.y = y + h;
1520*593dc095SDavid du Colombier
15213ff48bf5SDavid du Colombier line = buf->data + (x - buf->rect.p.x) + (y - buf->rect.p.y) * rowstride;
15223ff48bf5SDavid du Colombier
15233ff48bf5SDavid du Colombier for (j = 0; j < h; ++j) {
15243ff48bf5SDavid du Colombier dst_ptr = line;
15253ff48bf5SDavid du Colombier for (i = 0; i < w; ++i) {
1526*593dc095SDavid du Colombier /* Complement the components for subtractive color spaces */
1527*593dc095SDavid du Colombier if (additive) {
1528*593dc095SDavid du Colombier for (k = 0; k < num_chan; ++k)
15293ff48bf5SDavid du Colombier dst[k] = dst_ptr[k * planestride];
1530*593dc095SDavid du Colombier }
1531*593dc095SDavid du Colombier else { /* Complement the components for subtractive color spaces */
1532*593dc095SDavid du Colombier for (k = 0; k < num_comp; ++k)
1533*593dc095SDavid du Colombier dst[k] = 255 - dst_ptr[k * planestride];
1534*593dc095SDavid du Colombier dst[num_comp] = dst_ptr[num_comp * planestride];
1535*593dc095SDavid du Colombier }
1536*593dc095SDavid du Colombier art_pdf_composite_pixel_alpha_8(dst, src, num_comp, blend_mode);
1537*593dc095SDavid du Colombier /* Complement the results for subtractive color spaces */
1538*593dc095SDavid du Colombier if (additive) {
1539*593dc095SDavid du Colombier for (k = 0; k < num_chan; ++k)
15403ff48bf5SDavid du Colombier dst_ptr[k * planestride] = dst[k];
1541*593dc095SDavid du Colombier }
1542*593dc095SDavid du Colombier else {
1543*593dc095SDavid du Colombier for (k = 0; k < num_comp; ++k)
1544*593dc095SDavid du Colombier dst_ptr[k * planestride] = 255 - dst[k];
1545*593dc095SDavid du Colombier dst_ptr[num_comp * planestride] = dst[num_comp];
1546*593dc095SDavid du Colombier }
15473ff48bf5SDavid du Colombier if (has_alpha_g) {
1548*593dc095SDavid du Colombier int tmp = (255 - dst_ptr[alpha_g_off]) * (255 - src_alpha) + 0x80;
15493ff48bf5SDavid du Colombier dst_ptr[alpha_g_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
15503ff48bf5SDavid du Colombier }
15513ff48bf5SDavid du Colombier if (has_shape) {
15523ff48bf5SDavid du Colombier int tmp = (255 - dst_ptr[shape_off]) * (255 - shape) + 0x80;
15533ff48bf5SDavid du Colombier dst_ptr[shape_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
15543ff48bf5SDavid du Colombier }
15553ff48bf5SDavid du Colombier ++dst_ptr;
15563ff48bf5SDavid du Colombier }
15573ff48bf5SDavid du Colombier line += rowstride;
15583ff48bf5SDavid du Colombier }
15593ff48bf5SDavid du Colombier return 0;
15603ff48bf5SDavid du Colombier }
15613ff48bf5SDavid du Colombier
15623ff48bf5SDavid du Colombier private int
pdf14_mark_fill_rectangle_ko_simple(gx_device * dev,int x,int y,int w,int h,gx_color_index color)15633ff48bf5SDavid du Colombier pdf14_mark_fill_rectangle_ko_simple(gx_device * dev,
15643ff48bf5SDavid du Colombier int x, int y, int w, int h, gx_color_index color)
15653ff48bf5SDavid du Colombier {
1566*593dc095SDavid du Colombier pdf14_device *pdev = (pdf14_device *)dev;
15673ff48bf5SDavid du Colombier pdf14_buf *buf = pdev->ctx->stack;
15683ff48bf5SDavid du Colombier int i, j, k;
15693ff48bf5SDavid du Colombier byte *line, *dst_ptr;
15703ff48bf5SDavid du Colombier byte src[PDF14_MAX_PLANES];
15713ff48bf5SDavid du Colombier byte dst[PDF14_MAX_PLANES];
15723ff48bf5SDavid du Colombier int rowstride = buf->rowstride;
15733ff48bf5SDavid du Colombier int planestride = buf->planestride;
1574*593dc095SDavid du Colombier int num_chan = buf->n_chan;
1575*593dc095SDavid du Colombier int num_comp = num_chan - 1;
1576*593dc095SDavid du Colombier int shape_off = num_chan * planestride;
15773ff48bf5SDavid du Colombier bool has_shape = buf->has_shape;
15783ff48bf5SDavid du Colombier byte opacity;
1579*593dc095SDavid du Colombier bool additive = pdev->ctx->additive;
15803ff48bf5SDavid du Colombier
1581*593dc095SDavid du Colombier if_debug6('v', "[v]pdf14_mark_fill_rectangle_ko_simple, (%d, %d), %d x %d color = %lx bm %d, nc %d,\n", x, y, w, h, color, num_chan);
1582*593dc095SDavid du Colombier
1583*593dc095SDavid du Colombier /* Complement the components for subtractive color spaces */
1584*593dc095SDavid du Colombier if (additive) {
1585*593dc095SDavid du Colombier for (i = num_comp - 1; i >= 0; i--) {
1586*593dc095SDavid du Colombier src[i] = (byte)(color & 0xff);
1587*593dc095SDavid du Colombier color >>= 8;
1588*593dc095SDavid du Colombier }
1589*593dc095SDavid du Colombier }
1590*593dc095SDavid du Colombier else {
1591*593dc095SDavid du Colombier for (i = num_comp - 1; i >= 0; i--) {
1592*593dc095SDavid du Colombier src[i] = (byte)(0xff - (color & 0xff));
1593*593dc095SDavid du Colombier color >>= 8;
1594*593dc095SDavid du Colombier }
1595*593dc095SDavid du Colombier }
1596*593dc095SDavid du Colombier src[num_comp] = (byte)floor (255 * pdev->alpha + 0.5);
1597*593dc095SDavid du Colombier opacity = (byte)floor (255 * pdev->opacity + 0.5);
15983ff48bf5SDavid du Colombier
15993ff48bf5SDavid du Colombier if (x < buf->rect.p.x) x = buf->rect.p.x;
1600*593dc095SDavid du Colombier if (y < buf->rect.p.y) y = buf->rect.p.y;
16013ff48bf5SDavid du Colombier if (x + w > buf->rect.q.x) w = buf->rect.q.x - x;
16023ff48bf5SDavid du Colombier if (y + h > buf->rect.q.y) h = buf->rect.q.y - y;
16033ff48bf5SDavid du Colombier
1604*593dc095SDavid du Colombier if (x < buf->bbox.p.x) buf->bbox.p.x = x;
1605*593dc095SDavid du Colombier if (y < buf->bbox.p.y) buf->bbox.p.y = y;
1606*593dc095SDavid du Colombier if (x + w > buf->bbox.q.x) buf->bbox.q.x = x + w;
1607*593dc095SDavid du Colombier if (y + h > buf->bbox.q.y) buf->bbox.q.y = y + h;
1608*593dc095SDavid du Colombier
16093ff48bf5SDavid du Colombier line = buf->data + (x - buf->rect.p.x) + (y - buf->rect.p.y) * rowstride;
16103ff48bf5SDavid du Colombier
16113ff48bf5SDavid du Colombier for (j = 0; j < h; ++j) {
16123ff48bf5SDavid du Colombier dst_ptr = line;
16133ff48bf5SDavid du Colombier for (i = 0; i < w; ++i) {
1614*593dc095SDavid du Colombier /* Complement the components for subtractive color spaces */
1615*593dc095SDavid du Colombier if (additive) {
1616*593dc095SDavid du Colombier for (k = 0; k < num_chan; ++k)
16173ff48bf5SDavid du Colombier dst[k] = dst_ptr[k * planestride];
1618*593dc095SDavid du Colombier }
1619*593dc095SDavid du Colombier else {
1620*593dc095SDavid du Colombier for (k = 0; k < num_comp; ++k)
1621*593dc095SDavid du Colombier dst[k] = 255 - dst_ptr[k * planestride];
1622*593dc095SDavid du Colombier dst[num_comp] = dst_ptr[num_comp * planestride];
1623*593dc095SDavid du Colombier }
1624*593dc095SDavid du Colombier art_pdf_composite_knockout_simple_8(dst,
1625*593dc095SDavid du Colombier has_shape ? dst_ptr + shape_off : NULL, src, num_comp, opacity);
1626*593dc095SDavid du Colombier /* Complement the results for subtractive color spaces */
1627*593dc095SDavid du Colombier if (additive) {
1628*593dc095SDavid du Colombier for (k = 0; k < num_chan; ++k)
16293ff48bf5SDavid du Colombier dst_ptr[k * planestride] = dst[k];
1630*593dc095SDavid du Colombier }
1631*593dc095SDavid du Colombier else {
1632*593dc095SDavid du Colombier for (k = 0; k < num_comp; ++k)
1633*593dc095SDavid du Colombier dst_ptr[k * planestride] = 255 - dst[k];
1634*593dc095SDavid du Colombier dst_ptr[num_comp * planestride] = dst[num_comp];
1635*593dc095SDavid du Colombier }
16363ff48bf5SDavid du Colombier ++dst_ptr;
16373ff48bf5SDavid du Colombier }
16383ff48bf5SDavid du Colombier line += rowstride;
16393ff48bf5SDavid du Colombier }
16403ff48bf5SDavid du Colombier return 0;
16413ff48bf5SDavid du Colombier }
16423ff48bf5SDavid du Colombier
1643*593dc095SDavid du Colombier /**
1644*593dc095SDavid du Colombier * Here we have logic to override the cmap_procs with versions that
1645*593dc095SDavid du Colombier * do not apply the transfer function. These copies should track the
1646*593dc095SDavid du Colombier * versions in gxcmap.c.
1647*593dc095SDavid du Colombier **/
1648*593dc095SDavid du Colombier
1649*593dc095SDavid du Colombier private cmap_proc_gray(pdf14_cmap_gray_direct);
1650*593dc095SDavid du Colombier private cmap_proc_rgb(pdf14_cmap_rgb_direct);
1651*593dc095SDavid du Colombier private cmap_proc_cmyk(pdf14_cmap_cmyk_direct);
1652*593dc095SDavid du Colombier private cmap_proc_rgb_alpha(pdf14_cmap_rgb_alpha_direct);
1653*593dc095SDavid du Colombier private cmap_proc_separation(pdf14_cmap_separation_direct);
1654*593dc095SDavid du Colombier private cmap_proc_devicen(pdf14_cmap_devicen_direct);
1655*593dc095SDavid du Colombier private cmap_proc_is_halftoned(pdf14_cmap_is_halftoned);
1656*593dc095SDavid du Colombier
1657*593dc095SDavid du Colombier private const gx_color_map_procs pdf14_cmap_many = {
1658*593dc095SDavid du Colombier pdf14_cmap_gray_direct,
1659*593dc095SDavid du Colombier pdf14_cmap_rgb_direct,
1660*593dc095SDavid du Colombier pdf14_cmap_cmyk_direct,
1661*593dc095SDavid du Colombier pdf14_cmap_rgb_alpha_direct,
1662*593dc095SDavid du Colombier pdf14_cmap_separation_direct,
1663*593dc095SDavid du Colombier pdf14_cmap_devicen_direct,
1664*593dc095SDavid du Colombier pdf14_cmap_is_halftoned
1665*593dc095SDavid du Colombier };
1666*593dc095SDavid du Colombier
1667*593dc095SDavid du Colombier /**
1668*593dc095SDavid du Colombier * Note: copied from gxcmap.c because it's inlined.
1669*593dc095SDavid du Colombier **/
1670*593dc095SDavid du Colombier private inline void
map_components_to_colorants(const frac * pcc,const gs_devicen_color_map * pcolor_component_map,frac * plist)1671*593dc095SDavid du Colombier map_components_to_colorants(const frac * pcc,
1672*593dc095SDavid du Colombier const gs_devicen_color_map * pcolor_component_map, frac * plist)
1673*593dc095SDavid du Colombier {
1674*593dc095SDavid du Colombier int i = pcolor_component_map->num_colorants - 1;
1675*593dc095SDavid du Colombier int pos;
1676*593dc095SDavid du Colombier
1677*593dc095SDavid du Colombier /* Clear all output colorants first */
1678*593dc095SDavid du Colombier for (; i >= 0; i--) {
1679*593dc095SDavid du Colombier plist[i] = frac_0;
1680*593dc095SDavid du Colombier }
1681*593dc095SDavid du Colombier
1682*593dc095SDavid du Colombier /* Map color components into output list */
1683*593dc095SDavid du Colombier for (i = pcolor_component_map->num_components - 1; i >= 0; i--) {
1684*593dc095SDavid du Colombier pos = pcolor_component_map->color_map[i];
1685*593dc095SDavid du Colombier if (pos >= 0)
1686*593dc095SDavid du Colombier plist[pos] = pcc[i];
1687*593dc095SDavid du Colombier }
1688*593dc095SDavid du Colombier }
1689*593dc095SDavid du Colombier
1690*593dc095SDavid du Colombier private void
pdf14_cmap_gray_direct(frac gray,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)1691*593dc095SDavid du Colombier pdf14_cmap_gray_direct(frac gray, gx_device_color * pdc, const gs_imager_state * pis,
1692*593dc095SDavid du Colombier gx_device * dev, gs_color_select_t select)
1693*593dc095SDavid du Colombier {
1694*593dc095SDavid du Colombier int i, ncomps = dev->color_info.num_components;
1695*593dc095SDavid du Colombier frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
1696*593dc095SDavid du Colombier gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
1697*593dc095SDavid du Colombier gx_color_index color;
1698*593dc095SDavid du Colombier
1699*593dc095SDavid du Colombier /* map to the color model */
1700*593dc095SDavid du Colombier dev_proc(dev, get_color_mapping_procs)(dev)->map_gray(dev, gray, cm_comps);
1701*593dc095SDavid du Colombier
1702*593dc095SDavid du Colombier for (i = 0; i < ncomps; i++)
1703*593dc095SDavid du Colombier cv[i] = frac2cv(cm_comps[i]);
1704*593dc095SDavid du Colombier
1705*593dc095SDavid du Colombier /* encode as a color index */
1706*593dc095SDavid du Colombier color = dev_proc(dev, encode_color)(dev, cv);
1707*593dc095SDavid du Colombier
1708*593dc095SDavid du Colombier /* check if the encoding was successful; we presume failure is rare */
1709*593dc095SDavid du Colombier if (color != gx_no_color_index)
1710*593dc095SDavid du Colombier color_set_pure(pdc, color);
1711*593dc095SDavid du Colombier }
1712*593dc095SDavid du Colombier
1713*593dc095SDavid du Colombier
1714*593dc095SDavid du Colombier private void
pdf14_cmap_rgb_direct(frac r,frac g,frac b,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)1715*593dc095SDavid du Colombier pdf14_cmap_rgb_direct(frac r, frac g, frac b, gx_device_color * pdc,
1716*593dc095SDavid du Colombier const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
1717*593dc095SDavid du Colombier {
1718*593dc095SDavid du Colombier int i, ncomps = dev->color_info.num_components;
1719*593dc095SDavid du Colombier frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
1720*593dc095SDavid du Colombier gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
1721*593dc095SDavid du Colombier gx_color_index color;
1722*593dc095SDavid du Colombier
1723*593dc095SDavid du Colombier /* map to the color model */
1724*593dc095SDavid du Colombier dev_proc(dev, get_color_mapping_procs)(dev)->map_rgb(dev, pis, r, g, b, cm_comps);
1725*593dc095SDavid du Colombier
1726*593dc095SDavid du Colombier for (i = 0; i < ncomps; i++)
1727*593dc095SDavid du Colombier cv[i] = frac2cv(cm_comps[i]);
1728*593dc095SDavid du Colombier
1729*593dc095SDavid du Colombier /* encode as a color index */
1730*593dc095SDavid du Colombier color = dev_proc(dev, encode_color)(dev, cv);
1731*593dc095SDavid du Colombier
1732*593dc095SDavid du Colombier /* check if the encoding was successful; we presume failure is rare */
1733*593dc095SDavid du Colombier if (color != gx_no_color_index)
1734*593dc095SDavid du Colombier color_set_pure(pdc, color);
1735*593dc095SDavid du Colombier }
1736*593dc095SDavid du Colombier
1737*593dc095SDavid du Colombier private void
pdf14_cmap_cmyk_direct(frac c,frac m,frac y,frac k,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)1738*593dc095SDavid du Colombier pdf14_cmap_cmyk_direct(frac c, frac m, frac y, frac k, gx_device_color * pdc,
1739*593dc095SDavid du Colombier const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
1740*593dc095SDavid du Colombier {
1741*593dc095SDavid du Colombier int i, ncomps = dev->color_info.num_components;
1742*593dc095SDavid du Colombier frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
1743*593dc095SDavid du Colombier gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
1744*593dc095SDavid du Colombier gx_color_index color;
1745*593dc095SDavid du Colombier
1746*593dc095SDavid du Colombier /* map to the color model */
1747*593dc095SDavid du Colombier dev_proc(dev, get_color_mapping_procs)(dev)->map_cmyk(dev, c, m, y, k, cm_comps);
1748*593dc095SDavid du Colombier
1749*593dc095SDavid du Colombier for (i = 0; i < ncomps; i++)
1750*593dc095SDavid du Colombier cv[i] = frac2cv(cm_comps[i]);
1751*593dc095SDavid du Colombier
1752*593dc095SDavid du Colombier color = dev_proc(dev, encode_color)(dev, cv);
1753*593dc095SDavid du Colombier if (color != gx_no_color_index)
1754*593dc095SDavid du Colombier color_set_pure(pdc, color);
1755*593dc095SDavid du Colombier }
1756*593dc095SDavid du Colombier
1757*593dc095SDavid du Colombier private void
pdf14_cmap_rgb_alpha_direct(frac r,frac g,frac b,frac alpha,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)1758*593dc095SDavid du Colombier pdf14_cmap_rgb_alpha_direct(frac r, frac g, frac b, frac alpha, gx_device_color * pdc,
1759*593dc095SDavid du Colombier const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
1760*593dc095SDavid du Colombier {
1761*593dc095SDavid du Colombier int i, ncomps = dev->color_info.num_components;
1762*593dc095SDavid du Colombier frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
1763*593dc095SDavid du Colombier gx_color_value cv_alpha, cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
1764*593dc095SDavid du Colombier gx_color_index color;
1765*593dc095SDavid du Colombier
1766*593dc095SDavid du Colombier /* map to the color model */
1767*593dc095SDavid du Colombier dev_proc(dev, get_color_mapping_procs)(dev)->map_rgb(dev, pis, r, g, b, cm_comps);
1768*593dc095SDavid du Colombier
1769*593dc095SDavid du Colombier /* pre-multiply to account for the alpha weighting */
1770*593dc095SDavid du Colombier if (alpha != frac_1) {
1771*593dc095SDavid du Colombier #ifdef PREMULTIPLY_TOWARDS_WHITE
1772*593dc095SDavid du Colombier frac alpha_bias = frac_1 - alpha;
1773*593dc095SDavid du Colombier #else
1774*593dc095SDavid du Colombier frac alpha_bias = 0;
1775*593dc095SDavid du Colombier #endif
1776*593dc095SDavid du Colombier
1777*593dc095SDavid du Colombier for (i = 0; i < ncomps; i++)
1778*593dc095SDavid du Colombier cm_comps[i] = (frac)((long)cm_comps[i] * alpha) / frac_1 + alpha_bias;
1779*593dc095SDavid du Colombier }
1780*593dc095SDavid du Colombier
1781*593dc095SDavid du Colombier for (i = 0; i < ncomps; i++)
1782*593dc095SDavid du Colombier cv[i] = frac2cv(cm_comps[i]);
1783*593dc095SDavid du Colombier
1784*593dc095SDavid du Colombier /* encode as a color index */
1785*593dc095SDavid du Colombier if (dev_proc(dev, map_rgb_alpha_color) != gx_default_map_rgb_alpha_color &&
1786*593dc095SDavid du Colombier (cv_alpha = frac2cv(alpha)) != gx_max_color_value)
1787*593dc095SDavid du Colombier color = dev_proc(dev, map_rgb_alpha_color)(dev, cv[0], cv[1], cv[2], cv_alpha);
1788*593dc095SDavid du Colombier else
1789*593dc095SDavid du Colombier color = dev_proc(dev, encode_color)(dev, cv);
1790*593dc095SDavid du Colombier
1791*593dc095SDavid du Colombier /* check if the encoding was successful; we presume failure is rare */
1792*593dc095SDavid du Colombier if (color != gx_no_color_index)
1793*593dc095SDavid du Colombier color_set_pure(pdc, color);
1794*593dc095SDavid du Colombier }
1795*593dc095SDavid du Colombier
1796*593dc095SDavid du Colombier
1797*593dc095SDavid du Colombier private void
pdf14_cmap_separation_direct(frac all,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)1798*593dc095SDavid du Colombier pdf14_cmap_separation_direct(frac all, gx_device_color * pdc, const gs_imager_state * pis,
1799*593dc095SDavid du Colombier gx_device * dev, gs_color_select_t select)
1800*593dc095SDavid du Colombier {
1801*593dc095SDavid du Colombier int i, ncomps = dev->color_info.num_components;
1802*593dc095SDavid du Colombier bool additive = dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE;
1803*593dc095SDavid du Colombier frac comp_value = all;
1804*593dc095SDavid du Colombier frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
1805*593dc095SDavid du Colombier gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
1806*593dc095SDavid du Colombier gx_color_index color;
1807*593dc095SDavid du Colombier
1808*593dc095SDavid du Colombier if (pis->color_component_map.sep_type == SEP_ALL) {
1809*593dc095SDavid du Colombier /*
1810*593dc095SDavid du Colombier * Invert the photometric interpretation for additive
1811*593dc095SDavid du Colombier * color spaces because separations are always subtractive.
1812*593dc095SDavid du Colombier */
1813*593dc095SDavid du Colombier if (additive)
1814*593dc095SDavid du Colombier comp_value = frac_1 - comp_value;
1815*593dc095SDavid du Colombier
1816*593dc095SDavid du Colombier /* Use the "all" value for all components */
1817*593dc095SDavid du Colombier i = pis->color_component_map.num_colorants - 1;
1818*593dc095SDavid du Colombier for (; i >= 0; i--)
1819*593dc095SDavid du Colombier cm_comps[i] = comp_value;
1820*593dc095SDavid du Colombier }
1821*593dc095SDavid du Colombier else {
1822*593dc095SDavid du Colombier /* map to the color model */
1823*593dc095SDavid du Colombier map_components_to_colorants(&comp_value, &(pis->color_component_map), cm_comps);
1824*593dc095SDavid du Colombier }
1825*593dc095SDavid du Colombier
1826*593dc095SDavid du Colombier /* apply the transfer function(s); convert to color values */
1827*593dc095SDavid du Colombier if (additive)
1828*593dc095SDavid du Colombier for (i = 0; i < ncomps; i++)
1829*593dc095SDavid du Colombier cv[i] = frac2cv(gx_map_color_frac(pis,
1830*593dc095SDavid du Colombier cm_comps[i], effective_transfer[i]));
1831*593dc095SDavid du Colombier else
1832*593dc095SDavid du Colombier for (i = 0; i < ncomps; i++)
1833*593dc095SDavid du Colombier cv[i] = frac2cv(frac_1 - gx_map_color_frac(pis,
1834*593dc095SDavid du Colombier (frac)(frac_1 - cm_comps[i]), effective_transfer[i]));
1835*593dc095SDavid du Colombier
1836*593dc095SDavid du Colombier /* encode as a color index */
1837*593dc095SDavid du Colombier color = dev_proc(dev, encode_color)(dev, cv);
1838*593dc095SDavid du Colombier
1839*593dc095SDavid du Colombier /* check if the encoding was successful; we presume failure is rare */
1840*593dc095SDavid du Colombier if (color != gx_no_color_index)
1841*593dc095SDavid du Colombier color_set_pure(pdc, color);
1842*593dc095SDavid du Colombier }
1843*593dc095SDavid du Colombier
1844*593dc095SDavid du Colombier
1845*593dc095SDavid du Colombier private void
pdf14_cmap_devicen_direct(const frac * pcc,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)1846*593dc095SDavid du Colombier pdf14_cmap_devicen_direct(const frac * pcc,
1847*593dc095SDavid du Colombier gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
1848*593dc095SDavid du Colombier gs_color_select_t select)
1849*593dc095SDavid du Colombier {
1850*593dc095SDavid du Colombier int i, ncomps = dev->color_info.num_components;
1851*593dc095SDavid du Colombier frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
1852*593dc095SDavid du Colombier gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
1853*593dc095SDavid du Colombier gx_color_index color;
1854*593dc095SDavid du Colombier
1855*593dc095SDavid du Colombier /* map to the color model */
1856*593dc095SDavid du Colombier map_components_to_colorants(pcc, &(pis->color_component_map), cm_comps);;
1857*593dc095SDavid du Colombier
1858*593dc095SDavid du Colombier /* apply the transfer function(s); convert to color values */
1859*593dc095SDavid du Colombier if (dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE)
1860*593dc095SDavid du Colombier for (i = 0; i < ncomps; i++)
1861*593dc095SDavid du Colombier cv[i] = frac2cv(gx_map_color_frac(pis,
1862*593dc095SDavid du Colombier cm_comps[i], effective_transfer[i]));
1863*593dc095SDavid du Colombier else
1864*593dc095SDavid du Colombier for (i = 0; i < ncomps; i++)
1865*593dc095SDavid du Colombier cv[i] = frac2cv(frac_1 - gx_map_color_frac(pis,
1866*593dc095SDavid du Colombier (frac)(frac_1 - cm_comps[i]), effective_transfer[i]));
1867*593dc095SDavid du Colombier
1868*593dc095SDavid du Colombier /* encode as a color index */
1869*593dc095SDavid du Colombier color = dev_proc(dev, encode_color)(dev, cv);
1870*593dc095SDavid du Colombier
1871*593dc095SDavid du Colombier /* check if the encoding was successful; we presume failure is rare */
1872*593dc095SDavid du Colombier if (color != gx_no_color_index)
1873*593dc095SDavid du Colombier color_set_pure(pdc, color);
1874*593dc095SDavid du Colombier }
1875*593dc095SDavid du Colombier
1876*593dc095SDavid du Colombier private bool
pdf14_cmap_is_halftoned(const gs_imager_state * pis,gx_device * dev)1877*593dc095SDavid du Colombier pdf14_cmap_is_halftoned(const gs_imager_state * pis, gx_device * dev)
1878*593dc095SDavid du Colombier {
1879*593dc095SDavid du Colombier return false;
1880*593dc095SDavid du Colombier }
1881*593dc095SDavid du Colombier
1882*593dc095SDavid du Colombier private const gx_color_map_procs *
pdf14_get_cmap_procs(const gs_imager_state * pis,const gx_device * dev)1883*593dc095SDavid du Colombier pdf14_get_cmap_procs(const gs_imager_state *pis, const gx_device * dev)
1884*593dc095SDavid du Colombier {
1885*593dc095SDavid du Colombier /* The pdf14 marking device itself is always continuous tone. */
1886*593dc095SDavid du Colombier return &pdf14_cmap_many;
1887*593dc095SDavid du Colombier }
1888*593dc095SDavid du Colombier
1889*593dc095SDavid du Colombier
1890*593dc095SDavid du Colombier int
gs_pdf14_device_push(gs_memory_t * mem,gs_imager_state * pis,gx_device ** pdev,gx_device * target)1891*593dc095SDavid du Colombier gs_pdf14_device_push(gs_memory_t *mem, gs_imager_state * pis,
18923ff48bf5SDavid du Colombier gx_device ** pdev, gx_device * target)
18933ff48bf5SDavid du Colombier {
1894*593dc095SDavid du Colombier const pdf14_device * dev_proto;
18953ff48bf5SDavid du Colombier pdf14_device *p14dev;
18963ff48bf5SDavid du Colombier int code;
18973ff48bf5SDavid du Colombier
1898*593dc095SDavid du Colombier if_debug0('v', "[v]gs_pdf14_device_push\n");
1899*593dc095SDavid du Colombier
1900*593dc095SDavid du Colombier code = get_pdf14_device_proto(target, &dev_proto);
1901*593dc095SDavid du Colombier if (code < 0)
1902*593dc095SDavid du Colombier return code;
19033ff48bf5SDavid du Colombier code = gs_copydevice((gx_device **) &p14dev,
1904*593dc095SDavid du Colombier (const gx_device *) dev_proto, mem);
19053ff48bf5SDavid du Colombier if (code < 0)
19063ff48bf5SDavid du Colombier return code;
19073ff48bf5SDavid du Colombier
1908*593dc095SDavid du Colombier check_device_separable((gx_device *)p14dev);
19093ff48bf5SDavid du Colombier gx_device_fill_in_procs((gx_device *)p14dev);
19103ff48bf5SDavid du Colombier
19113ff48bf5SDavid du Colombier gs_pdf14_device_copy_params((gx_device *)p14dev, target);
19123ff48bf5SDavid du Colombier
1913*593dc095SDavid du Colombier rc_assign(p14dev->target, target, "gs_pdf14_device_push");
19143ff48bf5SDavid du Colombier
1915*593dc095SDavid du Colombier p14dev->save_get_cmap_procs = pis->get_cmap_procs;
1916*593dc095SDavid du Colombier pis->get_cmap_procs = pdf14_get_cmap_procs;
1917*593dc095SDavid du Colombier gx_set_cmap_procs(pis, (gx_device *)p14dev);
1918*593dc095SDavid du Colombier
1919*593dc095SDavid du Colombier code = dev_proc((gx_device *) p14dev, open_device) ((gx_device *) p14dev);
19203ff48bf5SDavid du Colombier *pdev = (gx_device *) p14dev;
1921*593dc095SDavid du Colombier pdf14_set_marking_params((gx_device *)p14dev, pis);
1922*593dc095SDavid du Colombier return code;
1923*593dc095SDavid du Colombier }
1924*593dc095SDavid du Colombier
1925*593dc095SDavid du Colombier /*
1926*593dc095SDavid du Colombier * In a modest violation of good coding practice, the gs_composite_common
1927*593dc095SDavid du Colombier * fields are "known" to be simple (contain no pointers to garbage
1928*593dc095SDavid du Colombier * collected memory), and we also know the gs_pdf14trans_params_t structure
1929*593dc095SDavid du Colombier * to be simple, so we just create a trivial structure descriptor for the
1930*593dc095SDavid du Colombier * entire gs_pdf14trans_s structure.
1931*593dc095SDavid du Colombier */
1932*593dc095SDavid du Colombier #define private_st_gs_pdf14trans_t()\
1933*593dc095SDavid du Colombier gs_private_st_ptrs1(st_pdf14trans, gs_pdf14trans_t, "gs_pdf14trans_t",\
1934*593dc095SDavid du Colombier st_pdf14trans_enum_ptrs, st_pdf14trans_reloc_ptrs, params.transfer_function)
1935*593dc095SDavid du Colombier
1936*593dc095SDavid du Colombier /* GC descriptor for gs_pdf14trans_t */
1937*593dc095SDavid du Colombier private_st_gs_pdf14trans_t();
1938*593dc095SDavid du Colombier
1939*593dc095SDavid du Colombier /*
1940*593dc095SDavid du Colombier * Check for equality of two PDF 1.4 transparency compositor objects.
1941*593dc095SDavid du Colombier *
1942*593dc095SDavid du Colombier * We are currently always indicating that PDF 1.4 transparency compositors are
1943*593dc095SDavid du Colombier * equal. Two transparency compositors may have teh same data but still
1944*593dc095SDavid du Colombier * represent separate actions. (E.g. two PDF14_BEGIN_TRANS_GROUP compositor
1945*593dc095SDavid du Colombier * operations in a row mean that we are creating a group inside of a group.
1946*593dc095SDavid du Colombier */
1947*593dc095SDavid du Colombier private bool
c_pdf14trans_equal(const gs_composite_t * pct0,const gs_composite_t * pct1)1948*593dc095SDavid du Colombier c_pdf14trans_equal(const gs_composite_t * pct0, const gs_composite_t * pct1)
1949*593dc095SDavid du Colombier {
1950*593dc095SDavid du Colombier return false;
1951*593dc095SDavid du Colombier }
1952*593dc095SDavid du Colombier
1953*593dc095SDavid du Colombier #ifdef DEBUG
1954*593dc095SDavid du Colombier static char * pdf14_opcode_names[] = PDF14_OPCODE_NAMES;
1955*593dc095SDavid du Colombier #endif
1956*593dc095SDavid du Colombier
1957*593dc095SDavid du Colombier #define put_value(dp, value)\
1958*593dc095SDavid du Colombier memcpy(dp, &value, sizeof(value));\
1959*593dc095SDavid du Colombier dp += sizeof(value)
1960*593dc095SDavid du Colombier
1961*593dc095SDavid du Colombier /*
1962*593dc095SDavid du Colombier * Convert a PDF 1.4 transparency compositor to string form for use by the command
1963*593dc095SDavid du Colombier * list device.
1964*593dc095SDavid du Colombier */
1965*593dc095SDavid du Colombier private int
c_pdf14trans_write(const gs_composite_t * pct,byte * data,uint * psize)1966*593dc095SDavid du Colombier c_pdf14trans_write(const gs_composite_t * pct, byte * data, uint * psize)
1967*593dc095SDavid du Colombier {
1968*593dc095SDavid du Colombier const gs_pdf14trans_params_t * pparams = &((const gs_pdf14trans_t *)pct)->params;
1969*593dc095SDavid du Colombier int need, avail = *psize;
1970*593dc095SDavid du Colombier /* Must be large enough for largest data struct */
1971*593dc095SDavid du Colombier byte buf[21 + sizeof(pparams->Background)
1972*593dc095SDavid du Colombier + sizeof(pparams->GrayBackground) + sizeof(pparams->bbox)];
1973*593dc095SDavid du Colombier byte * pbuf = buf;
1974*593dc095SDavid du Colombier int opcode = pparams->pdf14_op;
1975*593dc095SDavid du Colombier int mask_size = 0;
1976*593dc095SDavid du Colombier
1977*593dc095SDavid du Colombier /* Write PDF 1.4 compositor data into the clist */
1978*593dc095SDavid du Colombier
1979*593dc095SDavid du Colombier *pbuf++ = opcode; /* 1 byte */
1980*593dc095SDavid du Colombier switch (opcode) {
1981*593dc095SDavid du Colombier default: /* Should not occur. */
1982*593dc095SDavid du Colombier break;
1983*593dc095SDavid du Colombier case PDF14_PUSH_DEVICE:
1984*593dc095SDavid du Colombier case PDF14_POP_DEVICE:
1985*593dc095SDavid du Colombier case PDF14_END_TRANS_GROUP:
1986*593dc095SDavid du Colombier case PDF14_END_TRANS_MASK:
1987*593dc095SDavid du Colombier break; /* No data */
1988*593dc095SDavid du Colombier case PDF14_BEGIN_TRANS_GROUP:
1989*593dc095SDavid du Colombier /*
1990*593dc095SDavid du Colombier * The bbox data is floating point. We are not currently using it.
1991*593dc095SDavid du Colombier * So we are not currently putting it into the clist. We are also
1992*593dc095SDavid du Colombier * not using the color space.
1993*593dc095SDavid du Colombier */
1994*593dc095SDavid du Colombier *pbuf++ = (pparams->Isolated & 1) + ((pparams->Knockout & 1) << 1);
1995*593dc095SDavid du Colombier *pbuf++ = pparams->blend_mode;
1996*593dc095SDavid du Colombier put_value(pbuf, pparams->opacity.alpha);
1997*593dc095SDavid du Colombier put_value(pbuf, pparams->shape.alpha);
1998*593dc095SDavid du Colombier put_value(pbuf, pparams->bbox);
1999*593dc095SDavid du Colombier break;
2000*593dc095SDavid du Colombier case PDF14_INIT_TRANS_MASK:
2001*593dc095SDavid du Colombier *pbuf++ = pparams->csel;
2002*593dc095SDavid du Colombier break;
2003*593dc095SDavid du Colombier case PDF14_BEGIN_TRANS_MASK:
2004*593dc095SDavid du Colombier put_value(pbuf, pparams->subtype);
2005*593dc095SDavid du Colombier *pbuf++ = pparams->function_is_identity;
2006*593dc095SDavid du Colombier *pbuf++ = pparams->Background_components;
2007*593dc095SDavid du Colombier if (pparams->Background_components) {
2008*593dc095SDavid du Colombier const int l = sizeof(pparams->Background[0]) * pparams->Background_components;
2009*593dc095SDavid du Colombier
2010*593dc095SDavid du Colombier memcpy(pbuf, pparams->Background, l);
2011*593dc095SDavid du Colombier pbuf += l;
2012*593dc095SDavid du Colombier memcpy(pbuf, &pparams->GrayBackground, sizeof(pparams->GrayBackground));
2013*593dc095SDavid du Colombier pbuf += sizeof(pparams->GrayBackground);
2014*593dc095SDavid du Colombier }
2015*593dc095SDavid du Colombier if (!pparams->function_is_identity)
2016*593dc095SDavid du Colombier mask_size = sizeof(pparams->transfer_fn);
2017*593dc095SDavid du Colombier break;
2018*593dc095SDavid du Colombier case PDF14_SET_BLEND_PARAMS:
2019*593dc095SDavid du Colombier *pbuf++ = pparams->changed;
2020*593dc095SDavid du Colombier if (pparams->changed & PDF14_SET_BLEND_MODE)
2021*593dc095SDavid du Colombier *pbuf++ = pparams->blend_mode;
2022*593dc095SDavid du Colombier if (pparams->changed & PDF14_SET_TEXT_KNOCKOUT)
2023*593dc095SDavid du Colombier *pbuf++ = pparams->text_knockout;
2024*593dc095SDavid du Colombier if (pparams->changed & PDF14_SET_OPACITY_ALPHA)
2025*593dc095SDavid du Colombier put_value(pbuf, pparams->opacity.alpha);
2026*593dc095SDavid du Colombier if (pparams->changed & PDF14_SET_SHAPE_ALPHA)
2027*593dc095SDavid du Colombier put_value(pbuf, pparams->shape.alpha);
2028*593dc095SDavid du Colombier break;
2029*593dc095SDavid du Colombier }
2030*593dc095SDavid du Colombier #undef put_value
2031*593dc095SDavid du Colombier
2032*593dc095SDavid du Colombier /* check for fit */
2033*593dc095SDavid du Colombier need = (pbuf - buf) + mask_size;
2034*593dc095SDavid du Colombier *psize = need;
2035*593dc095SDavid du Colombier if (need > avail)
2036*593dc095SDavid du Colombier return_error(gs_error_rangecheck);
2037*593dc095SDavid du Colombier /* Copy our serialzed data into the output buffer */
2038*593dc095SDavid du Colombier memcpy(data, buf, need - mask_size);
2039*593dc095SDavid du Colombier if (mask_size) /* Include the transfer mask data if present */
2040*593dc095SDavid du Colombier memcpy(data + need - mask_size, pparams->transfer_fn, mask_size);
2041*593dc095SDavid du Colombier if_debug2('v', "[v] c_pdf14trans_write: opcode = %s need = %d\n",
2042*593dc095SDavid du Colombier pdf14_opcode_names[opcode], need);
2043*593dc095SDavid du Colombier return 0;
2044*593dc095SDavid du Colombier }
2045*593dc095SDavid du Colombier
2046*593dc095SDavid du Colombier /* Function prototypes */
2047*593dc095SDavid du Colombier int gs_create_pdf14trans( gs_composite_t ** ppct,
2048*593dc095SDavid du Colombier const gs_pdf14trans_params_t * pparams,
2049*593dc095SDavid du Colombier gs_memory_t * mem );
2050*593dc095SDavid du Colombier
2051*593dc095SDavid du Colombier #define read_value(dp, value)\
2052*593dc095SDavid du Colombier memcpy(&value, dp, sizeof(value));\
2053*593dc095SDavid du Colombier dp += sizeof(value)
2054*593dc095SDavid du Colombier
2055*593dc095SDavid du Colombier /*
2056*593dc095SDavid du Colombier * Convert the string representation of the PDF 1.4 tranparency parameter
2057*593dc095SDavid du Colombier * into the full compositor.
2058*593dc095SDavid du Colombier */
2059*593dc095SDavid du Colombier private int
c_pdf14trans_read(gs_composite_t ** ppct,const byte * data,uint size,gs_memory_t * mem)2060*593dc095SDavid du Colombier c_pdf14trans_read(gs_composite_t * * ppct, const byte * data,
2061*593dc095SDavid du Colombier uint size, gs_memory_t * mem )
2062*593dc095SDavid du Colombier {
2063*593dc095SDavid du Colombier gs_pdf14trans_params_t params = {0};
2064*593dc095SDavid du Colombier const byte * start = data;
2065*593dc095SDavid du Colombier int used, code = 0;
2066*593dc095SDavid du Colombier
2067*593dc095SDavid du Colombier if (size < 1)
2068*593dc095SDavid du Colombier return_error(gs_error_rangecheck);
2069*593dc095SDavid du Colombier
2070*593dc095SDavid du Colombier /* Read PDF 1.4 compositor data from the clist */
2071*593dc095SDavid du Colombier params.pdf14_op = *data++;
2072*593dc095SDavid du Colombier if_debug2('v', "[v] c_pdf14trans_read: opcode = %s avail = %d",
2073*593dc095SDavid du Colombier pdf14_opcode_names[params.pdf14_op], size);
2074*593dc095SDavid du Colombier switch (params.pdf14_op) {
2075*593dc095SDavid du Colombier default: /* Should not occur. */
2076*593dc095SDavid du Colombier break;
2077*593dc095SDavid du Colombier case PDF14_PUSH_DEVICE:
2078*593dc095SDavid du Colombier case PDF14_POP_DEVICE:
2079*593dc095SDavid du Colombier case PDF14_END_TRANS_GROUP:
2080*593dc095SDavid du Colombier break; /* No data */
2081*593dc095SDavid du Colombier case PDF14_BEGIN_TRANS_GROUP:
2082*593dc095SDavid du Colombier /*
2083*593dc095SDavid du Colombier * We are currently not using the bbox or the colorspace so they were
2084*593dc095SDavid du Colombier * not placed in the clist
2085*593dc095SDavid du Colombier */
2086*593dc095SDavid du Colombier params.Isolated = (*data) & 1;
2087*593dc095SDavid du Colombier params.Knockout = (*data++ >> 1) & 1;
2088*593dc095SDavid du Colombier params.blend_mode = *data++;
2089*593dc095SDavid du Colombier read_value(data, params.opacity.alpha);
2090*593dc095SDavid du Colombier read_value(data, params.shape.alpha);
2091*593dc095SDavid du Colombier read_value(data, params.bbox);
2092*593dc095SDavid du Colombier break;
2093*593dc095SDavid du Colombier case PDF14_INIT_TRANS_MASK:
2094*593dc095SDavid du Colombier params.csel = *data++;
2095*593dc095SDavid du Colombier break;
2096*593dc095SDavid du Colombier case PDF14_BEGIN_TRANS_MASK:
2097*593dc095SDavid du Colombier read_value(data, params.subtype);
2098*593dc095SDavid du Colombier params.function_is_identity = *data++;
2099*593dc095SDavid du Colombier params.Background_components = *data++;
2100*593dc095SDavid du Colombier if (params.Background_components) {
2101*593dc095SDavid du Colombier const int l = sizeof(params.Background[0]) * params.Background_components;
2102*593dc095SDavid du Colombier
2103*593dc095SDavid du Colombier memcpy(params.Background, data, l);
2104*593dc095SDavid du Colombier data += l;
2105*593dc095SDavid du Colombier memcpy(¶ms.GrayBackground, data, sizeof(params.GrayBackground));
2106*593dc095SDavid du Colombier data += sizeof(params.GrayBackground);
2107*593dc095SDavid du Colombier }
2108*593dc095SDavid du Colombier if (params.function_is_identity) {
2109*593dc095SDavid du Colombier int i;
2110*593dc095SDavid du Colombier
2111*593dc095SDavid du Colombier for (i = 0; i < MASK_TRANSFER_FUNCTION_SIZE; i++) {
2112*593dc095SDavid du Colombier params.transfer_fn[i] = (byte)floor(i *
2113*593dc095SDavid du Colombier (255.0 / (MASK_TRANSFER_FUNCTION_SIZE - 1)) + 0.5);
2114*593dc095SDavid du Colombier }
2115*593dc095SDavid du Colombier } else {
2116*593dc095SDavid du Colombier read_value(data, params.transfer_fn);
2117*593dc095SDavid du Colombier }
2118*593dc095SDavid du Colombier break;
2119*593dc095SDavid du Colombier case PDF14_END_TRANS_MASK:
2120*593dc095SDavid du Colombier break; /* No data */
2121*593dc095SDavid du Colombier case PDF14_SET_BLEND_PARAMS:
2122*593dc095SDavid du Colombier params.changed = *data++;
2123*593dc095SDavid du Colombier if (params.changed & PDF14_SET_BLEND_MODE)
2124*593dc095SDavid du Colombier params.blend_mode = *data++;
2125*593dc095SDavid du Colombier if (params.changed & PDF14_SET_TEXT_KNOCKOUT)
2126*593dc095SDavid du Colombier params.text_knockout = *data++;
2127*593dc095SDavid du Colombier if (params.changed & PDF14_SET_OPACITY_ALPHA)
2128*593dc095SDavid du Colombier read_value(data, params.opacity.alpha);
2129*593dc095SDavid du Colombier if (params.changed & PDF14_SET_SHAPE_ALPHA)
2130*593dc095SDavid du Colombier read_value(data, params.shape.alpha);
2131*593dc095SDavid du Colombier break;
2132*593dc095SDavid du Colombier }
2133*593dc095SDavid du Colombier code = gs_create_pdf14trans(ppct, ¶ms, mem);
2134*593dc095SDavid du Colombier if (code < 0)
2135*593dc095SDavid du Colombier return code;
2136*593dc095SDavid du Colombier used = data - start;
2137*593dc095SDavid du Colombier if_debug1('v', " used = %d\n", used);
2138*593dc095SDavid du Colombier return used;
2139*593dc095SDavid du Colombier }
2140*593dc095SDavid du Colombier
2141*593dc095SDavid du Colombier /*
2142*593dc095SDavid du Colombier * Create a PDF 1.4 transparency compositor.
2143*593dc095SDavid du Colombier *
2144*593dc095SDavid du Colombier * Note that this routine will be called only if the device is not already
2145*593dc095SDavid du Colombier * a PDF 1.4 transparency compositor.
2146*593dc095SDavid du Colombier */
2147*593dc095SDavid du Colombier private int
c_pdf14trans_create_default_compositor(const gs_composite_t * pct,gx_device ** pp14dev,gx_device * tdev,gs_imager_state * pis,gs_memory_t * mem)2148*593dc095SDavid du Colombier c_pdf14trans_create_default_compositor(const gs_composite_t * pct,
2149*593dc095SDavid du Colombier gx_device ** pp14dev, gx_device * tdev, gs_imager_state * pis,
2150*593dc095SDavid du Colombier gs_memory_t * mem)
2151*593dc095SDavid du Colombier {
2152*593dc095SDavid du Colombier const gs_pdf14trans_t * pdf14pct = (const gs_pdf14trans_t *) pct;
2153*593dc095SDavid du Colombier gx_device * p14dev = NULL;
2154*593dc095SDavid du Colombier int code = 0;
2155*593dc095SDavid du Colombier
2156*593dc095SDavid du Colombier /*
2157*593dc095SDavid du Colombier * We only handle the push operation. All other operations are ignored.
2158*593dc095SDavid du Colombier */
2159*593dc095SDavid du Colombier switch (pdf14pct->params.pdf14_op) {
2160*593dc095SDavid du Colombier case PDF14_PUSH_DEVICE:
2161*593dc095SDavid du Colombier code = gs_pdf14_device_push(mem, pis, &p14dev, tdev);
2162*593dc095SDavid du Colombier *pp14dev = p14dev;
2163*593dc095SDavid du Colombier break;
2164*593dc095SDavid du Colombier default:
2165*593dc095SDavid du Colombier *pp14dev = tdev;
2166*593dc095SDavid du Colombier break;
2167*593dc095SDavid du Colombier }
2168*593dc095SDavid du Colombier return code;
2169*593dc095SDavid du Colombier }
2170*593dc095SDavid du Colombier
2171*593dc095SDavid du Colombier private composite_clist_write_update(c_pdf14trans_clist_write_update);
2172*593dc095SDavid du Colombier private composite_clist_read_update(c_pdf14trans_clist_read_update);
2173*593dc095SDavid du Colombier
2174*593dc095SDavid du Colombier /*
2175*593dc095SDavid du Colombier * Methods for the PDF 1.4 transparency compositor
2176*593dc095SDavid du Colombier *
2177*593dc095SDavid du Colombier * Note: We have two set of methods. They are the same except for the
2178*593dc095SDavid du Colombier * composite_clist_write_update method. Once the clist write device is created,
2179*593dc095SDavid du Colombier * we use the second set of procedures. This prevents the creation of multiple
2180*593dc095SDavid du Colombier * PDF 1.4 clist write compositor devices being chained together.
2181*593dc095SDavid du Colombier */
2182*593dc095SDavid du Colombier const gs_composite_type_t gs_composite_pdf14trans_type = {
2183*593dc095SDavid du Colombier GX_COMPOSITOR_PDF14_TRANS,
2184*593dc095SDavid du Colombier {
2185*593dc095SDavid du Colombier c_pdf14trans_create_default_compositor, /* procs.create_default_compositor */
2186*593dc095SDavid du Colombier c_pdf14trans_equal, /* procs.equal */
2187*593dc095SDavid du Colombier c_pdf14trans_write, /* procs.write */
2188*593dc095SDavid du Colombier c_pdf14trans_read, /* procs.read */
2189*593dc095SDavid du Colombier /* Create a PDF 1.4 clist write device */
2190*593dc095SDavid du Colombier c_pdf14trans_clist_write_update, /* procs.composite_clist_write_update */
2191*593dc095SDavid du Colombier c_pdf14trans_clist_read_update /* procs.composite_clist_reade_update */
2192*593dc095SDavid du Colombier } /* procs */
2193*593dc095SDavid du Colombier };
2194*593dc095SDavid du Colombier
2195*593dc095SDavid du Colombier const gs_composite_type_t gs_composite_pdf14trans_no_clist_writer_type = {
2196*593dc095SDavid du Colombier GX_COMPOSITOR_PDF14_TRANS,
2197*593dc095SDavid du Colombier {
2198*593dc095SDavid du Colombier c_pdf14trans_create_default_compositor, /* procs.create_default_compositor */
2199*593dc095SDavid du Colombier c_pdf14trans_equal, /* procs.equal */
2200*593dc095SDavid du Colombier c_pdf14trans_write, /* procs.write */
2201*593dc095SDavid du Colombier c_pdf14trans_read, /* procs.read */
2202*593dc095SDavid du Colombier /* The PDF 1.4 clist writer already exists, Do not create it. */
2203*593dc095SDavid du Colombier gx_default_composite_clist_write_update, /* procs.composite_clist_write_update */
2204*593dc095SDavid du Colombier c_pdf14trans_clist_read_update /* procs.composite_clist_reade_update */
2205*593dc095SDavid du Colombier } /* procs */
2206*593dc095SDavid du Colombier };
2207*593dc095SDavid du Colombier
2208*593dc095SDavid du Colombier /*
2209*593dc095SDavid du Colombier * Verify that a compositor data structure is for the PDF 1.4 compositor.
2210*593dc095SDavid du Colombier */
2211*593dc095SDavid du Colombier int
gs_is_pdf14trans_compositor(const gs_composite_t * pct)2212*593dc095SDavid du Colombier gs_is_pdf14trans_compositor(const gs_composite_t * pct)
2213*593dc095SDavid du Colombier {
2214*593dc095SDavid du Colombier return (pct->type == &gs_composite_pdf14trans_type
2215*593dc095SDavid du Colombier || pct->type == &gs_composite_pdf14trans_no_clist_writer_type);
2216*593dc095SDavid du Colombier }
2217*593dc095SDavid du Colombier
2218*593dc095SDavid du Colombier /*
2219*593dc095SDavid du Colombier * Create a PDF 1.4 transparency compositor data structure.
2220*593dc095SDavid du Colombier */
2221*593dc095SDavid du Colombier int
gs_create_pdf14trans(gs_composite_t ** ppct,const gs_pdf14trans_params_t * pparams,gs_memory_t * mem)2222*593dc095SDavid du Colombier gs_create_pdf14trans(
2223*593dc095SDavid du Colombier gs_composite_t ** ppct,
2224*593dc095SDavid du Colombier const gs_pdf14trans_params_t * pparams,
2225*593dc095SDavid du Colombier gs_memory_t * mem )
2226*593dc095SDavid du Colombier {
2227*593dc095SDavid du Colombier gs_pdf14trans_t * pct;
2228*593dc095SDavid du Colombier
2229*593dc095SDavid du Colombier rc_alloc_struct_0( pct,
2230*593dc095SDavid du Colombier gs_pdf14trans_t,
2231*593dc095SDavid du Colombier &st_pdf14trans,
2232*593dc095SDavid du Colombier mem,
2233*593dc095SDavid du Colombier return_error(gs_error_VMerror),
2234*593dc095SDavid du Colombier "gs_create_pdf14trans" );
2235*593dc095SDavid du Colombier pct->type = &gs_composite_pdf14trans_type;
2236*593dc095SDavid du Colombier pct->id = gs_next_ids(mem, 1);
2237*593dc095SDavid du Colombier pct->params = *pparams;
2238*593dc095SDavid du Colombier *ppct = (gs_composite_t *)pct;
2239*593dc095SDavid du Colombier return 0;
2240*593dc095SDavid du Colombier }
2241*593dc095SDavid du Colombier
2242*593dc095SDavid du Colombier /*
2243*593dc095SDavid du Colombier * Send a PDF 1.4 transparency compositor action to the specified device.
2244*593dc095SDavid du Colombier */
2245*593dc095SDavid du Colombier int
send_pdf14trans(gs_imager_state * pis,gx_device * dev,gx_device ** pcdev,gs_pdf14trans_params_t * pparams,gs_memory_t * mem)2246*593dc095SDavid du Colombier send_pdf14trans(gs_imager_state * pis, gx_device * dev,
2247*593dc095SDavid du Colombier gx_device * * pcdev, gs_pdf14trans_params_t * pparams, gs_memory_t * mem)
2248*593dc095SDavid du Colombier {
2249*593dc095SDavid du Colombier gs_composite_t * pct = NULL;
2250*593dc095SDavid du Colombier int code;
2251*593dc095SDavid du Colombier
2252*593dc095SDavid du Colombier code = gs_create_pdf14trans(&pct, pparams, mem);
2253*593dc095SDavid du Colombier if (code < 0)
2254*593dc095SDavid du Colombier return code;
2255*593dc095SDavid du Colombier code = dev_proc(dev, create_compositor) (dev, pcdev, pct, pis, mem);
2256*593dc095SDavid du Colombier
2257*593dc095SDavid du Colombier gs_free_object(pis->memory, pct, "send_pdf14trans");
2258*593dc095SDavid du Colombier
2259*593dc095SDavid du Colombier return code;
2260*593dc095SDavid du Colombier }
2261*593dc095SDavid du Colombier
2262*593dc095SDavid du Colombier /* ------------- PDF 1.4 transparency device for clist writing ------------- */
2263*593dc095SDavid du Colombier
2264*593dc095SDavid du Colombier /*
2265*593dc095SDavid du Colombier * The PDF 1.4 transparency compositor device may have a different process
2266*593dc095SDavid du Colombier * color model than the output device. If we are banding then we need to
2267*593dc095SDavid du Colombier * create two compositor devices. The output side (clist reader) needs a
2268*593dc095SDavid du Colombier * compositor to actually composite the output. We also need a compositor
2269*593dc095SDavid du Colombier * device before the clist writer. This is needed to provide a process color
2270*593dc095SDavid du Colombier * model which matches the PDF 1.4 blending space.
2271*593dc095SDavid du Colombier *
2272*593dc095SDavid du Colombier * This section provides support for this device.
2273*593dc095SDavid du Colombier */
2274*593dc095SDavid du Colombier
2275*593dc095SDavid du Colombier /* Define the default alpha-compositing device. */
2276*593dc095SDavid du Colombier typedef struct pdf14_clist_device_s {
2277*593dc095SDavid du Colombier gx_device_forward_common;
2278*593dc095SDavid du Colombier const gx_color_map_procs *(*save_get_cmap_procs)(const gs_imager_state *,
2279*593dc095SDavid du Colombier const gx_device *);
2280*593dc095SDavid du Colombier gx_device_color_info saved_target_color_info;
2281*593dc095SDavid du Colombier float opacity;
2282*593dc095SDavid du Colombier float shape;
2283*593dc095SDavid du Colombier gs_blend_mode_t blend_mode;
2284*593dc095SDavid du Colombier bool text_knockout;
2285*593dc095SDavid du Colombier } pdf14_clist_device;
2286*593dc095SDavid du Colombier
2287*593dc095SDavid du Colombier gs_private_st_suffix_add0_final(st_pdf14_clist_device,
2288*593dc095SDavid du Colombier pdf14_clist_device, "pdf14_clist_device",
2289*593dc095SDavid du Colombier device_c_pdf14_clist_enum_ptrs, device_c_pdf14_clist_reloc_ptrs,
2290*593dc095SDavid du Colombier gx_device_finalize, st_device_forward);
2291*593dc095SDavid du Colombier
2292*593dc095SDavid du Colombier #define pdf14_clist_procs(get_color_mapping_procs, get_color_comp_index,\
2293*593dc095SDavid du Colombier encode_color, decode_color) \
2294*593dc095SDavid du Colombier {\
2295*593dc095SDavid du Colombier NULL, /* open */\
2296*593dc095SDavid du Colombier gx_forward_get_initial_matrix, /* get_initial_matrix */\
2297*593dc095SDavid du Colombier gx_forward_sync_output, /* sync_output */\
2298*593dc095SDavid du Colombier gx_forward_output_page, /* output_page */\
2299*593dc095SDavid du Colombier gx_forward_close_device, /* close_device */\
2300*593dc095SDavid du Colombier encode_color, /* rgb_map_rgb_color */\
2301*593dc095SDavid du Colombier decode_color, /* map_color_rgb */\
2302*593dc095SDavid du Colombier gx_forward_fill_rectangle, /* fill_rectangle */\
2303*593dc095SDavid du Colombier gx_forward_tile_rectangle, /* tile_rectangle */\
2304*593dc095SDavid du Colombier gx_forward_copy_mono, /* copy_mono */\
2305*593dc095SDavid du Colombier gx_forward_copy_color, /* copy_color */\
2306*593dc095SDavid du Colombier NULL , /* draw_line - obsolete */\
2307*593dc095SDavid du Colombier gx_forward_get_bits, /* get_bits */\
2308*593dc095SDavid du Colombier gx_forward_get_params, /* get_params */\
2309*593dc095SDavid du Colombier pdf14_put_params, /* put_params */\
2310*593dc095SDavid du Colombier encode_color, /* map_cmyk_color */\
2311*593dc095SDavid du Colombier gx_forward_get_xfont_procs, /* get_xfont_procs */\
2312*593dc095SDavid du Colombier gx_forward_get_xfont_device, /* get_xfont_device */\
2313*593dc095SDavid du Colombier NULL, /* map_rgb_alpha_color */\
2314*593dc095SDavid du Colombier gx_forward_get_page_device, /* get_page_device */\
2315*593dc095SDavid du Colombier gx_forward_get_alpha_bits, /* get_alpha_bits */\
2316*593dc095SDavid du Colombier NULL, /* copy_alpha */\
2317*593dc095SDavid du Colombier gx_forward_get_band, /* get_band */\
2318*593dc095SDavid du Colombier gx_forward_copy_rop, /* copy_rop */\
2319*593dc095SDavid du Colombier pdf14_clist_fill_path, /* fill_path */\
2320*593dc095SDavid du Colombier pdf14_clist_stroke_path, /* stroke_path */\
2321*593dc095SDavid du Colombier gx_forward_fill_mask, /* fill_mask */\
2322*593dc095SDavid du Colombier gx_forward_fill_trapezoid, /* fill_trapezoid */\
2323*593dc095SDavid du Colombier gx_forward_fill_parallelogram, /* fill_parallelogram */\
2324*593dc095SDavid du Colombier gx_forward_fill_triangle, /* fill_triangle */\
2325*593dc095SDavid du Colombier gx_forward_draw_thin_line, /* draw_thin_line */\
2326*593dc095SDavid du Colombier pdf14_clist_begin_image, /* begin_image */\
2327*593dc095SDavid du Colombier gx_forward_image_data, /* image_data */\
2328*593dc095SDavid du Colombier gx_forward_end_image, /* end_image */\
2329*593dc095SDavid du Colombier gx_forward_strip_tile_rectangle, /* strip_tile_rectangle */\
2330*593dc095SDavid du Colombier gx_forward_strip_copy_rop, /* strip_copy_rop, */\
2331*593dc095SDavid du Colombier gx_forward_get_clipping_box, /* get_clipping_box */\
2332*593dc095SDavid du Colombier pdf14_clist_begin_typed_image, /* begin_typed_image */\
2333*593dc095SDavid du Colombier gx_forward_get_bits_rectangle, /* get_bits_rectangle */\
2334*593dc095SDavid du Colombier NULL, /* map_color_rgb_alpha */\
2335*593dc095SDavid du Colombier pdf14_clist_create_compositor, /* create_compositor */\
2336*593dc095SDavid du Colombier gx_forward_get_hardware_params, /* get_hardware_params */\
2337*593dc095SDavid du Colombier pdf14_clist_text_begin, /* text_begin */\
2338*593dc095SDavid du Colombier NULL, /* finish_copydevice */\
2339*593dc095SDavid du Colombier pdf14_begin_transparency_group,\
2340*593dc095SDavid du Colombier pdf14_end_transparency_group,\
2341*593dc095SDavid du Colombier pdf14_begin_transparency_mask,\
2342*593dc095SDavid du Colombier pdf14_end_transparency_mask,\
2343*593dc095SDavid du Colombier NULL, /* discard_transparency_layer */\
2344*593dc095SDavid du Colombier get_color_mapping_procs, /* get_color_mapping_procs */\
2345*593dc095SDavid du Colombier get_color_comp_index, /* get_color_comp_index */\
2346*593dc095SDavid du Colombier encode_color, /* encode_color */\
2347*593dc095SDavid du Colombier decode_color /* decode_color */\
2348*593dc095SDavid du Colombier }
2349*593dc095SDavid du Colombier
2350*593dc095SDavid du Colombier private dev_proc_create_compositor(pdf14_clist_create_compositor);
2351*593dc095SDavid du Colombier private dev_proc_create_compositor(pdf14_clist_forward_create_compositor);
2352*593dc095SDavid du Colombier private dev_proc_fill_path(pdf14_clist_fill_path);
2353*593dc095SDavid du Colombier private dev_proc_stroke_path(pdf14_clist_stroke_path);
2354*593dc095SDavid du Colombier private dev_proc_text_begin(pdf14_clist_text_begin);
2355*593dc095SDavid du Colombier private dev_proc_begin_image(pdf14_clist_begin_image);
2356*593dc095SDavid du Colombier private dev_proc_begin_typed_image(pdf14_clist_begin_typed_image);
2357*593dc095SDavid du Colombier
2358*593dc095SDavid du Colombier private const gx_device_procs pdf14_clist_Gray_procs =
2359*593dc095SDavid du Colombier pdf14_clist_procs(gx_default_DevGray_get_color_mapping_procs,
2360*593dc095SDavid du Colombier gx_default_DevGray_get_color_comp_index,
2361*593dc095SDavid du Colombier gx_default_8bit_map_gray_color,
2362*593dc095SDavid du Colombier gx_default_8bit_map_color_gray);
2363*593dc095SDavid du Colombier
2364*593dc095SDavid du Colombier private const gx_device_procs pdf14_clist_RGB_procs =
2365*593dc095SDavid du Colombier pdf14_clist_procs(gx_default_DevRGB_get_color_mapping_procs,
2366*593dc095SDavid du Colombier gx_default_DevRGB_get_color_comp_index,
2367*593dc095SDavid du Colombier gx_default_rgb_map_rgb_color,
2368*593dc095SDavid du Colombier gx_default_rgb_map_color_rgb);
2369*593dc095SDavid du Colombier
2370*593dc095SDavid du Colombier private const gx_device_procs pdf14_clist_CMYK_procs =
2371*593dc095SDavid du Colombier pdf14_clist_procs(gx_default_DevCMYK_get_color_mapping_procs,
2372*593dc095SDavid du Colombier gx_default_DevCMYK_get_color_comp_index,
2373*593dc095SDavid du Colombier cmyk_8bit_map_cmyk_color, cmyk_8bit_map_color_cmyk);
2374*593dc095SDavid du Colombier
2375*593dc095SDavid du Colombier const pdf14_clist_device pdf14_clist_Gray_device = {
2376*593dc095SDavid du Colombier std_device_color_stype_body(pdf14_clist_device, &pdf14_clist_Gray_procs,
2377*593dc095SDavid du Colombier "pdf14clistgray", &st_pdf14_clist_device,
2378*593dc095SDavid du Colombier XSIZE, YSIZE, X_DPI, Y_DPI, 8, 255, 256),
2379*593dc095SDavid du Colombier { 0 }
2380*593dc095SDavid du Colombier };
2381*593dc095SDavid du Colombier
2382*593dc095SDavid du Colombier const pdf14_clist_device pdf14_clist_RGB_device = {
2383*593dc095SDavid du Colombier std_device_color_stype_body(pdf14_clist_device, &pdf14_clist_RGB_procs,
2384*593dc095SDavid du Colombier "pdf14clistRGB", &st_pdf14_clist_device,
2385*593dc095SDavid du Colombier XSIZE, YSIZE, X_DPI, Y_DPI, 24, 255, 256),
2386*593dc095SDavid du Colombier { 0 }
2387*593dc095SDavid du Colombier };
2388*593dc095SDavid du Colombier
2389*593dc095SDavid du Colombier const pdf14_clist_device pdf14_clist_CMYK_device = {
2390*593dc095SDavid du Colombier std_device_std_color_full_body_type(pdf14_clist_device,
2391*593dc095SDavid du Colombier &pdf14_clist_CMYK_procs, "PDF14clistcmyk",
2392*593dc095SDavid du Colombier &st_pdf14_clist_device, XSIZE, YSIZE, X_DPI, Y_DPI, 32,
2393*593dc095SDavid du Colombier 0, 0, 0, 0, 0, 0),
2394*593dc095SDavid du Colombier { 0 }
2395*593dc095SDavid du Colombier };
2396*593dc095SDavid du Colombier
2397*593dc095SDavid du Colombier /*
2398*593dc095SDavid du Colombier * the PDF 1.4 transparency spec says that color space for blending
2399*593dc095SDavid du Colombier * operations can be based upon either a color space specified in the
2400*593dc095SDavid du Colombier * group or a default value based upon the output device. We are
2401*593dc095SDavid du Colombier * currently only using a color space based upon the device.
2402*593dc095SDavid du Colombier */
2403*593dc095SDavid du Colombier private int
get_pdf14_clist_device_proto(gx_device * dev,const pdf14_clist_device ** pdevproto)2404*593dc095SDavid du Colombier get_pdf14_clist_device_proto(gx_device * dev,
2405*593dc095SDavid du Colombier const pdf14_clist_device ** pdevproto)
2406*593dc095SDavid du Colombier {
2407*593dc095SDavid du Colombier pdf14_default_colorspace_t dev_cs =
2408*593dc095SDavid du Colombier pdf14_determine_default_blend_cs(dev);
2409*593dc095SDavid du Colombier
2410*593dc095SDavid du Colombier switch (dev_cs) {
2411*593dc095SDavid du Colombier case DeviceGray:
2412*593dc095SDavid du Colombier *pdevproto = &pdf14_clist_Gray_device;
2413*593dc095SDavid du Colombier break;
2414*593dc095SDavid du Colombier case DeviceRGB:
2415*593dc095SDavid du Colombier *pdevproto = &pdf14_clist_RGB_device;
2416*593dc095SDavid du Colombier break;
2417*593dc095SDavid du Colombier case DeviceCMYK:
2418*593dc095SDavid du Colombier *pdevproto = &pdf14_clist_CMYK_device;
2419*593dc095SDavid du Colombier break;
2420*593dc095SDavid du Colombier default: /* Should not occur */
2421*593dc095SDavid du Colombier return_error(gs_error_rangecheck);
2422*593dc095SDavid du Colombier }
24233ff48bf5SDavid du Colombier return 0;
24243ff48bf5SDavid du Colombier }
24253ff48bf5SDavid du Colombier
24263ff48bf5SDavid du Colombier private int
pdf14_create_clist_device(gs_memory_t * mem,gs_imager_state * pis,gx_device ** ppdev,gx_device * target)2427*593dc095SDavid du Colombier pdf14_create_clist_device(gs_memory_t *mem, gs_imager_state * pis,
2428*593dc095SDavid du Colombier gx_device ** ppdev, gx_device * target)
24293ff48bf5SDavid du Colombier {
2430*593dc095SDavid du Colombier const pdf14_clist_device * dev_proto;
2431*593dc095SDavid du Colombier pdf14_clist_device *pdev;
24323ff48bf5SDavid du Colombier int code;
24333ff48bf5SDavid du Colombier
2434*593dc095SDavid du Colombier if_debug0('v', "[v]pdf14_create_clist_device\n");
2435*593dc095SDavid du Colombier
2436*593dc095SDavid du Colombier code = get_pdf14_clist_device_proto(target, &dev_proto);
24373ff48bf5SDavid du Colombier if (code < 0)
24383ff48bf5SDavid du Colombier return code;
24393ff48bf5SDavid du Colombier
2440*593dc095SDavid du Colombier code = gs_copydevice((gx_device **) &pdev,
2441*593dc095SDavid du Colombier (const gx_device *) dev_proto, mem);
24423ff48bf5SDavid du Colombier if (code < 0)
24433ff48bf5SDavid du Colombier return code;
24443ff48bf5SDavid du Colombier
2445*593dc095SDavid du Colombier check_device_separable((gx_device *)pdev);
2446*593dc095SDavid du Colombier gx_device_fill_in_procs((gx_device *)pdev);
24473ff48bf5SDavid du Colombier
2448*593dc095SDavid du Colombier gs_pdf14_device_copy_params((gx_device *)pdev, target);
2449*593dc095SDavid du Colombier
2450*593dc095SDavid du Colombier rc_assign(pdev->target, target, "pdf14_create_clist_device");
2451*593dc095SDavid du Colombier
2452*593dc095SDavid du Colombier code = dev_proc((gx_device *) pdev, open_device) ((gx_device *) pdev);
2453*593dc095SDavid du Colombier *ppdev = (gx_device *) pdev;
2454*593dc095SDavid du Colombier return code;
2455*593dc095SDavid du Colombier }
2456*593dc095SDavid du Colombier
2457*593dc095SDavid du Colombier /*
2458*593dc095SDavid du Colombier * Disable the PDF 1.4 clist compositor device. Once created, the PDF 1.4
2459*593dc095SDavid du Colombier * compositor device is never removed. (We do not have a remove compositor
2460*593dc095SDavid du Colombier * method.) However it is no-op'ed when the PDF 1.4 device is popped. This
2461*593dc095SDavid du Colombier * routine implements that action.
2462*593dc095SDavid du Colombier */
2463*593dc095SDavid du Colombier private int
pdf14_disable_clist_device(gs_memory_t * mem,gs_imager_state * pis,gx_device * dev)2464*593dc095SDavid du Colombier pdf14_disable_clist_device(gs_memory_t *mem, gs_imager_state * pis,
2465*593dc095SDavid du Colombier gx_device * dev)
2466*593dc095SDavid du Colombier {
2467*593dc095SDavid du Colombier gx_device_forward * pdev = (gx_device_forward *)dev;
2468*593dc095SDavid du Colombier gx_device * target = pdev->target;
2469*593dc095SDavid du Colombier
2470*593dc095SDavid du Colombier if_debug0('v', "[v]pdf14_disable_clist_device\n");
2471*593dc095SDavid du Colombier
2472*593dc095SDavid du Colombier /*
2473*593dc095SDavid du Colombier * To disable the action of this device, we forward all device
2474*593dc095SDavid du Colombier * procedures to the target except the create_compositor and copy
2475*593dc095SDavid du Colombier * the target's color_info.
2476*593dc095SDavid du Colombier */
2477*593dc095SDavid du Colombier dev->color_info = target->color_info;
2478*593dc095SDavid du Colombier pdf14_forward_device_procs(dev);
2479*593dc095SDavid du Colombier set_dev_proc(dev, create_compositor, pdf14_clist_forward_create_compositor);
24803ff48bf5SDavid du Colombier return 0;
24813ff48bf5SDavid du Colombier }
24823ff48bf5SDavid du Colombier
2483*593dc095SDavid du Colombier /*
2484*593dc095SDavid du Colombier * Recreate the PDF 1.4 clist compositor device. Once created, the PDF 1.4
2485*593dc095SDavid du Colombier * compositor device is never removed. (We do not have a remove compositor
2486*593dc095SDavid du Colombier * method.) However it is no-op'ed when the PDF 1.4 device is popped. This
2487*593dc095SDavid du Colombier * routine will re-enable the compositor if the PDF 1.4 device is pushed
2488*593dc095SDavid du Colombier * again.
2489*593dc095SDavid du Colombier */
2490*593dc095SDavid du Colombier private int
pdf14_recreate_clist_device(gs_memory_t * mem,gs_imager_state * pis,gx_device * dev)2491*593dc095SDavid du Colombier pdf14_recreate_clist_device(gs_memory_t *mem, gs_imager_state * pis,
2492*593dc095SDavid du Colombier gx_device * dev)
24933ff48bf5SDavid du Colombier {
2494*593dc095SDavid du Colombier pdf14_clist_device * pdev = (pdf14_clist_device *)dev;
2495*593dc095SDavid du Colombier gx_device * target = pdev->target;
2496*593dc095SDavid du Colombier const pdf14_clist_device * dev_proto;
2497*593dc095SDavid du Colombier int code;
24983ff48bf5SDavid du Colombier
2499*593dc095SDavid du Colombier if_debug0('v', "[v]pdf14_recreate_clist_device\n");
2500*593dc095SDavid du Colombier
2501*593dc095SDavid du Colombier /*
2502*593dc095SDavid du Colombier * We will not use the entire prototype device but we will set the
2503*593dc095SDavid du Colombier * color related info to match the prototype.
2504*593dc095SDavid du Colombier */
2505*593dc095SDavid du Colombier code = get_pdf14_clist_device_proto(target, &dev_proto);
2506*593dc095SDavid du Colombier if (code < 0)
2507*593dc095SDavid du Colombier return code;
2508*593dc095SDavid du Colombier pdev->color_info = dev_proto->color_info;
2509*593dc095SDavid du Colombier pdev->procs = dev_proto->procs;
2510*593dc095SDavid du Colombier gx_device_fill_in_procs(dev);
2511*593dc095SDavid du Colombier check_device_separable((gx_device *)pdev);
2512*593dc095SDavid du Colombier
2513*593dc095SDavid du Colombier return code;
2514*593dc095SDavid du Colombier }
2515*593dc095SDavid du Colombier
2516*593dc095SDavid du Colombier /*
2517*593dc095SDavid du Colombier * When we are banding, we have two PDF 1.4 compositor devices. One for
2518*593dc095SDavid du Colombier * when we are creating the clist. The second is for imaging the data from
2519*593dc095SDavid du Colombier * the clist. This routine is part of the clist writing PDF 1.4 device.
2520*593dc095SDavid du Colombier * This routine is only called once the PDF 1.4 clist write compositor already
2521*593dc095SDavid du Colombier * exists.
2522*593dc095SDavid du Colombier */
2523*593dc095SDavid du Colombier private int
pdf14_clist_create_compositor(gx_device * dev,gx_device ** pcdev,const gs_composite_t * pct,gs_imager_state * pis,gs_memory_t * mem)2524*593dc095SDavid du Colombier pdf14_clist_create_compositor(gx_device * dev, gx_device ** pcdev,
2525*593dc095SDavid du Colombier const gs_composite_t * pct, gs_imager_state * pis, gs_memory_t * mem)
2526*593dc095SDavid du Colombier {
2527*593dc095SDavid du Colombier pdf14_clist_device * pdev = (pdf14_clist_device *)dev;
2528*593dc095SDavid du Colombier int code;
2529*593dc095SDavid du Colombier
2530*593dc095SDavid du Colombier /* We only handle a few PDF 1.4 transparency operations 4 */
2531*593dc095SDavid du Colombier if (gs_is_pdf14trans_compositor(pct)) {
2532*593dc095SDavid du Colombier const gs_pdf14trans_t * pdf14pct = (const gs_pdf14trans_t *) pct;
2533*593dc095SDavid du Colombier
2534*593dc095SDavid du Colombier switch (pdf14pct->params.pdf14_op) {
2535*593dc095SDavid du Colombier case PDF14_PUSH_DEVICE:
2536*593dc095SDavid du Colombier /* Re-activate the PDF 1.4 compositor */
2537*593dc095SDavid du Colombier pdev->saved_target_color_info = pdev->target->color_info;
2538*593dc095SDavid du Colombier pdev->target->color_info = pdev->color_info;
2539*593dc095SDavid du Colombier pdev->save_get_cmap_procs = pis->get_cmap_procs;
2540*593dc095SDavid du Colombier pis->get_cmap_procs = pdf14_get_cmap_procs;
2541*593dc095SDavid du Colombier gx_set_cmap_procs(pis, dev);
2542*593dc095SDavid du Colombier code = pdf14_recreate_clist_device(mem, pis, dev);
2543*593dc095SDavid du Colombier pdev->blend_mode = pdev->text_knockout = 0;
2544*593dc095SDavid du Colombier pdev->opacity = pdev->shape = 0.0;
2545*593dc095SDavid du Colombier if (code < 0)
2546*593dc095SDavid du Colombier return code;
2547*593dc095SDavid du Colombier /*
2548*593dc095SDavid du Colombier * This routine is part of the PDF 1.4 clist write device.
2549*593dc095SDavid du Colombier * Change the compositor procs to not create another since we
2550*593dc095SDavid du Colombier * do not need to create a chain of identical devices.
2551*593dc095SDavid du Colombier */
2552*593dc095SDavid du Colombier {
2553*593dc095SDavid du Colombier gs_composite_t pctemp = *pct;
2554*593dc095SDavid du Colombier
2555*593dc095SDavid du Colombier pctemp.type = &gs_composite_pdf14trans_no_clist_writer_type;
2556*593dc095SDavid du Colombier code = dev_proc(pdev->target, create_compositor)
2557*593dc095SDavid du Colombier (pdev->target, pcdev, &pctemp, pis, mem);
2558*593dc095SDavid du Colombier *pcdev = dev;
2559*593dc095SDavid du Colombier return code;
2560*593dc095SDavid du Colombier }
2561*593dc095SDavid du Colombier case PDF14_POP_DEVICE:
2562*593dc095SDavid du Colombier /* Restore the color_info for the clist device */
2563*593dc095SDavid du Colombier pdev->target->color_info = pdev->saved_target_color_info;
2564*593dc095SDavid du Colombier pis->get_cmap_procs = pdev->save_get_cmap_procs;
2565*593dc095SDavid du Colombier gx_set_cmap_procs(pis, pdev->target);
2566*593dc095SDavid du Colombier /* Disable the PDF 1.4 compositor */
2567*593dc095SDavid du Colombier pdf14_disable_clist_device(mem, pis, dev);
2568*593dc095SDavid du Colombier /*
2569*593dc095SDavid du Colombier * Make sure that the transfer funtions, etc. are current.
2570*593dc095SDavid du Colombier */
2571*593dc095SDavid du Colombier code = cmd_put_color_mapping(
2572*593dc095SDavid du Colombier (gx_device_clist_writer *)(pdev->target), pis);
2573*593dc095SDavid du Colombier if (code < 0)
2574*593dc095SDavid du Colombier return code;
2575*593dc095SDavid du Colombier break;
2576*593dc095SDavid du Colombier case PDF14_BEGIN_TRANS_GROUP:
2577*593dc095SDavid du Colombier /*
2578*593dc095SDavid du Colombier * Keep track of any changes made in the blending parameters.
2579*593dc095SDavid du Colombier */
2580*593dc095SDavid du Colombier pdev->text_knockout = pdf14pct->params.Knockout;
2581*593dc095SDavid du Colombier pdev->blend_mode = pdf14pct->params.blend_mode;
2582*593dc095SDavid du Colombier pdev->opacity = pdf14pct->params.opacity.alpha;
2583*593dc095SDavid du Colombier pdev->shape = pdf14pct->params.shape.alpha;
2584*593dc095SDavid du Colombier {
2585*593dc095SDavid du Colombier const gs_pdf14trans_params_t * pparams = &((const gs_pdf14trans_t *)pct)->params;
2586*593dc095SDavid du Colombier
2587*593dc095SDavid du Colombier if (pparams->Background_components != 0 &&
2588*593dc095SDavid du Colombier pparams->Background_components != pdev->color_info.num_components)
2589*593dc095SDavid du Colombier return_error(gs_error_rangecheck);
2590*593dc095SDavid du Colombier }
2591*593dc095SDavid du Colombier break;
2592*593dc095SDavid du Colombier default:
2593*593dc095SDavid du Colombier break; /* Pass remaining ops to target */
2594*593dc095SDavid du Colombier }
2595*593dc095SDavid du Colombier }
2596*593dc095SDavid du Colombier code = dev_proc(pdev->target, create_compositor)
2597*593dc095SDavid du Colombier (pdev->target, pcdev, pct, pis, mem);
2598*593dc095SDavid du Colombier if (*pcdev != pdev->target)
2599*593dc095SDavid du Colombier rc_assign(pdev->target, *pcdev, "pdf14_clist_create_compositor");
2600*593dc095SDavid du Colombier *pcdev = dev;
2601*593dc095SDavid du Colombier return code;
2602*593dc095SDavid du Colombier }
2603*593dc095SDavid du Colombier
2604*593dc095SDavid du Colombier /*
2605*593dc095SDavid du Colombier * The PDF 1.4 clist compositor is never removed. (We do not have a 'remove
2606*593dc095SDavid du Colombier * compositor' method. However the compositor is disabled when we are not
2607*593dc095SDavid du Colombier * doing a page which uses PDF 1.4 transparency. This routine is only active
2608*593dc095SDavid du Colombier * when the PDF 1.4 compositor is 'disabled'. It checks for reenabling the
2609*593dc095SDavid du Colombier * PDF 1.4 compositor. Otherwise it simply passes create compositor requests
2610*593dc095SDavid du Colombier * to the targer.
2611*593dc095SDavid du Colombier */
2612*593dc095SDavid du Colombier private int
pdf14_clist_forward_create_compositor(gx_device * dev,gx_device ** pcdev,const gs_composite_t * pct,gs_imager_state * pis,gs_memory_t * mem)2613*593dc095SDavid du Colombier pdf14_clist_forward_create_compositor(gx_device * dev, gx_device * * pcdev,
2614*593dc095SDavid du Colombier const gs_composite_t * pct, gs_imager_state * pis,
2615*593dc095SDavid du Colombier gs_memory_t * mem)
2616*593dc095SDavid du Colombier {
2617*593dc095SDavid du Colombier pdf14_device *pdev = (pdf14_device *)dev;
2618*593dc095SDavid du Colombier gx_device * tdev = pdev->target;
2619*593dc095SDavid du Colombier gx_device * ndev;
2620*593dc095SDavid du Colombier int code = 0;
2621*593dc095SDavid du Colombier
2622*593dc095SDavid du Colombier *pcdev = dev;
2623*593dc095SDavid du Colombier if (gs_is_pdf14trans_compositor(pct)) {
2624*593dc095SDavid du Colombier const gs_pdf14trans_t * pdf14pct = (const gs_pdf14trans_t *) pct;
2625*593dc095SDavid du Colombier
2626*593dc095SDavid du Colombier if (pdf14pct->params.pdf14_op == PDF14_PUSH_DEVICE)
2627*593dc095SDavid du Colombier return pdf14_clist_create_compositor(dev, &ndev, pct, pis, mem);
2628*593dc095SDavid du Colombier return 0;
2629*593dc095SDavid du Colombier }
2630*593dc095SDavid du Colombier code = dev_proc(tdev, create_compositor)(tdev, &ndev, pct, pis, mem);
2631*593dc095SDavid du Colombier if (code < 0)
2632*593dc095SDavid du Colombier return code;
2633*593dc095SDavid du Colombier pdev->target = ndev;
2634*593dc095SDavid du Colombier return 0;
2635*593dc095SDavid du Colombier }
2636*593dc095SDavid du Colombier
2637*593dc095SDavid du Colombier /*
2638*593dc095SDavid du Colombier * If any of the PDF 1.4 transparency blending parameters have changed, we
2639*593dc095SDavid du Colombier * need to send them to the PDF 1.4 compositor on the output side of the clist.
2640*593dc095SDavid du Colombier */
2641*593dc095SDavid du Colombier private int
pdf14_clist_update_params(pdf14_clist_device * pdev,const gs_imager_state * pis)2642*593dc095SDavid du Colombier pdf14_clist_update_params(pdf14_clist_device * pdev, const gs_imager_state * pis)
2643*593dc095SDavid du Colombier {
2644*593dc095SDavid du Colombier gs_pdf14trans_params_t params = { 0 };
2645*593dc095SDavid du Colombier gx_device * pcdev;
2646*593dc095SDavid du Colombier int changed = 0;
2647*593dc095SDavid du Colombier int code = 0;
2648*593dc095SDavid du Colombier
2649*593dc095SDavid du Colombier params.pdf14_op = PDF14_SET_BLEND_PARAMS;
2650*593dc095SDavid du Colombier if (pis->blend_mode != pdev->blend_mode) {
2651*593dc095SDavid du Colombier changed |= PDF14_SET_BLEND_MODE;
2652*593dc095SDavid du Colombier params.blend_mode = pdev->blend_mode = pis->blend_mode;
2653*593dc095SDavid du Colombier }
2654*593dc095SDavid du Colombier if (pis->text_knockout != pdev->text_knockout) {
2655*593dc095SDavid du Colombier changed |= PDF14_SET_TEXT_KNOCKOUT;
2656*593dc095SDavid du Colombier params.text_knockout = pdev->text_knockout = pis->text_knockout;
2657*593dc095SDavid du Colombier }
2658*593dc095SDavid du Colombier if (pis->shape.alpha != pdev->shape) {
2659*593dc095SDavid du Colombier changed |= PDF14_SET_SHAPE_ALPHA;
2660*593dc095SDavid du Colombier params.shape.alpha = pdev->shape = pis->shape.alpha;
2661*593dc095SDavid du Colombier }
2662*593dc095SDavid du Colombier if (pis->opacity.alpha != pdev->opacity) {
2663*593dc095SDavid du Colombier changed |= PDF14_SET_OPACITY_ALPHA;
2664*593dc095SDavid du Colombier params.opacity.alpha = pdev->opacity = pis->opacity.alpha;
2665*593dc095SDavid du Colombier }
2666*593dc095SDavid du Colombier /*
2667*593dc095SDavid du Colombier * Put parameters into a compositor parameter and then call the
2668*593dc095SDavid du Colombier * create_compositor. This will pass the data through the clist
2669*593dc095SDavid du Colombier * to the PDF 1.4 transparency output device. Note: This action
2670*593dc095SDavid du Colombier * never creates a new PDF 1.4 compositor and it does not change
2671*593dc095SDavid du Colombier * the imager state.
2672*593dc095SDavid du Colombier */
2673*593dc095SDavid du Colombier if (changed != 0) {
2674*593dc095SDavid du Colombier params.changed = changed;
2675*593dc095SDavid du Colombier code = send_pdf14trans((gs_imager_state *)pis, (gx_device *)pdev,
2676*593dc095SDavid du Colombier &pcdev, ¶ms, pis->memory);
2677*593dc095SDavid du Colombier }
2678*593dc095SDavid du Colombier return code;
2679*593dc095SDavid du Colombier }
2680*593dc095SDavid du Colombier
2681*593dc095SDavid du Colombier /*
2682*593dc095SDavid du Colombier * fill_path routine for the PDF 1.4 transaprency compositor device for
2683*593dc095SDavid du Colombier * writing the clist.
2684*593dc095SDavid du Colombier */
2685*593dc095SDavid du Colombier private int
pdf14_clist_fill_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)2686*593dc095SDavid du Colombier pdf14_clist_fill_path(gx_device *dev, const gs_imager_state *pis,
2687*593dc095SDavid du Colombier gx_path *ppath, const gx_fill_params *params,
2688*593dc095SDavid du Colombier const gx_drawing_color *pdcolor,
2689*593dc095SDavid du Colombier const gx_clip_path *pcpath)
2690*593dc095SDavid du Colombier {
2691*593dc095SDavid du Colombier pdf14_clist_device * pdev = (pdf14_clist_device *)dev;
2692*593dc095SDavid du Colombier gs_imager_state new_is = *pis;
2693*593dc095SDavid du Colombier int code;
2694*593dc095SDavid du Colombier
2695*593dc095SDavid du Colombier /*
2696*593dc095SDavid du Colombier * Ensure that that the PDF 1.4 reading compositor will have the current
2697*593dc095SDavid du Colombier * blending parameters. This is needed since the fill_rectangle routines
2698*593dc095SDavid du Colombier * do not have access to the imager state. Thus we have to pass any
2699*593dc095SDavid du Colombier * changes explictly.
2700*593dc095SDavid du Colombier */
2701*593dc095SDavid du Colombier code = pdf14_clist_update_params(pdev, pis);
2702*593dc095SDavid du Colombier if (code < 0)
2703*593dc095SDavid du Colombier return code;
2704*593dc095SDavid du Colombier /*
2705*593dc095SDavid du Colombier * The blend operations are not idempotent. Force non-idempotent
2706*593dc095SDavid du Colombier * filling and stroking operations.
2707*593dc095SDavid du Colombier */
2708*593dc095SDavid du Colombier new_is.log_op |= lop_pdf14;
2709*593dc095SDavid du Colombier return gx_default_fill_path(dev, &new_is, ppath, params, pdcolor, pcpath);
2710*593dc095SDavid du Colombier }
2711*593dc095SDavid du Colombier
2712*593dc095SDavid du Colombier /*
2713*593dc095SDavid du Colombier * stroke_path routine for the PDF 1.4 transaprency compositor device for
2714*593dc095SDavid du Colombier * writing the clist.
2715*593dc095SDavid du Colombier */
2716*593dc095SDavid du Colombier private int
pdf14_clist_stroke_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_stroke_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)2717*593dc095SDavid du Colombier pdf14_clist_stroke_path(gx_device *dev, const gs_imager_state *pis,
2718*593dc095SDavid du Colombier gx_path *ppath, const gx_stroke_params *params,
2719*593dc095SDavid du Colombier const gx_drawing_color *pdcolor,
2720*593dc095SDavid du Colombier const gx_clip_path *pcpath)
2721*593dc095SDavid du Colombier {
2722*593dc095SDavid du Colombier pdf14_clist_device * pdev = (pdf14_clist_device *)dev;
2723*593dc095SDavid du Colombier gs_imager_state new_is = *pis;
2724*593dc095SDavid du Colombier int code;
2725*593dc095SDavid du Colombier
2726*593dc095SDavid du Colombier /*
2727*593dc095SDavid du Colombier * Ensure that that the PDF 1.4 reading compositor will have the current
2728*593dc095SDavid du Colombier * blending parameters. This is needed since the fill_rectangle routines
2729*593dc095SDavid du Colombier * do not have access to the imager state. Thus we have to pass any
2730*593dc095SDavid du Colombier * changes explictly.
2731*593dc095SDavid du Colombier */
2732*593dc095SDavid du Colombier code = pdf14_clist_update_params(pdev, pis);
2733*593dc095SDavid du Colombier if (code < 0)
2734*593dc095SDavid du Colombier return code;
2735*593dc095SDavid du Colombier /*
2736*593dc095SDavid du Colombier * The blend operations are not idempotent. Force non-idempotent
2737*593dc095SDavid du Colombier * filling and stroking operations.
2738*593dc095SDavid du Colombier */
2739*593dc095SDavid du Colombier new_is.log_op |= lop_pdf14;
2740*593dc095SDavid du Colombier return gx_default_stroke_path(dev, &new_is, ppath, params, pdcolor, pcpath);
2741*593dc095SDavid du Colombier }
2742*593dc095SDavid du Colombier
2743*593dc095SDavid du Colombier /*
2744*593dc095SDavid du Colombier * text_begin routine for the PDF 1.4 transaprency compositor device for
2745*593dc095SDavid du Colombier * writing the clist.
2746*593dc095SDavid du Colombier */
2747*593dc095SDavid du Colombier private int
pdf14_clist_text_begin(gx_device * dev,gs_imager_state * pis,const gs_text_params_t * text,gs_font * font,gx_path * path,const gx_device_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * memory,gs_text_enum_t ** ppenum)2748*593dc095SDavid du Colombier pdf14_clist_text_begin(gx_device * dev, gs_imager_state * pis,
2749*593dc095SDavid du Colombier const gs_text_params_t * text, gs_font * font,
2750*593dc095SDavid du Colombier gx_path * path, const gx_device_color * pdcolor,
2751*593dc095SDavid du Colombier const gx_clip_path * pcpath, gs_memory_t * memory,
2752*593dc095SDavid du Colombier gs_text_enum_t ** ppenum)
2753*593dc095SDavid du Colombier {
2754*593dc095SDavid du Colombier pdf14_clist_device * pdev = (pdf14_clist_device *)dev;
2755*593dc095SDavid du Colombier gs_text_enum_t *penum;
2756*593dc095SDavid du Colombier int code;
2757*593dc095SDavid du Colombier
2758*593dc095SDavid du Colombier /*
2759*593dc095SDavid du Colombier * Ensure that that the PDF 1.4 reading compositor will have the current
2760*593dc095SDavid du Colombier * blending parameters. This is needed since the fill_rectangle routines
2761*593dc095SDavid du Colombier * do not have access to the imager state. Thus we have to pass any
2762*593dc095SDavid du Colombier * changes explictly.
2763*593dc095SDavid du Colombier */
2764*593dc095SDavid du Colombier code = pdf14_clist_update_params(pdev, pis);
2765*593dc095SDavid du Colombier if (code < 0)
2766*593dc095SDavid du Colombier return code;
2767*593dc095SDavid du Colombier /* Pass text_begin to the target */
2768*593dc095SDavid du Colombier code = gx_default_text_begin(dev, pis, text, font, path,
2769*593dc095SDavid du Colombier pdcolor, pcpath, memory, &penum);
2770*593dc095SDavid du Colombier if (code < 0)
2771*593dc095SDavid du Colombier return code;
2772*593dc095SDavid du Colombier *ppenum = (gs_text_enum_t *)penum;
2773*593dc095SDavid du Colombier return code;
2774*593dc095SDavid du Colombier }
2775*593dc095SDavid du Colombier
2776*593dc095SDavid du Colombier private int
pdf14_clist_begin_image(gx_device * dev,const gs_imager_state * pis,const gs_image_t * pim,gs_image_format_t format,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * memory,gx_image_enum_common_t ** pinfo)2777*593dc095SDavid du Colombier pdf14_clist_begin_image(gx_device * dev,
2778*593dc095SDavid du Colombier const gs_imager_state * pis, const gs_image_t * pim,
2779*593dc095SDavid du Colombier gs_image_format_t format, const gs_int_rect * prect,
2780*593dc095SDavid du Colombier const gx_drawing_color * pdcolor,
2781*593dc095SDavid du Colombier const gx_clip_path * pcpath,
2782*593dc095SDavid du Colombier gs_memory_t * memory, gx_image_enum_common_t ** pinfo)
2783*593dc095SDavid du Colombier {
2784*593dc095SDavid du Colombier pdf14_clist_device * pdev = (pdf14_clist_device *)dev;
2785*593dc095SDavid du Colombier int code;
2786*593dc095SDavid du Colombier
2787*593dc095SDavid du Colombier /*
2788*593dc095SDavid du Colombier * Ensure that that the PDF 1.4 reading compositor will have the current
2789*593dc095SDavid du Colombier * blending parameters. This is needed since the fill_rectangle routines
2790*593dc095SDavid du Colombier * do not have access to the imager state. Thus we have to pass any
2791*593dc095SDavid du Colombier * changes explictly.
2792*593dc095SDavid du Colombier */
2793*593dc095SDavid du Colombier code = pdf14_clist_update_params(pdev, pis);
2794*593dc095SDavid du Colombier if (code < 0)
2795*593dc095SDavid du Colombier return code;
2796*593dc095SDavid du Colombier /* Pass image to the target */
2797*593dc095SDavid du Colombier return gx_default_begin_image(dev, pis, pim, format, prect,
2798*593dc095SDavid du Colombier pdcolor, pcpath, memory, pinfo);
2799*593dc095SDavid du Colombier }
2800*593dc095SDavid du Colombier
2801*593dc095SDavid du Colombier private int
pdf14_clist_begin_typed_image(gx_device * dev,const gs_imager_state * pis,const gs_matrix * pmat,const gs_image_common_t * pic,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * mem,gx_image_enum_common_t ** pinfo)2802*593dc095SDavid du Colombier pdf14_clist_begin_typed_image(gx_device * dev, const gs_imager_state * pis,
2803*593dc095SDavid du Colombier const gs_matrix *pmat, const gs_image_common_t *pic,
2804*593dc095SDavid du Colombier const gs_int_rect * prect,
2805*593dc095SDavid du Colombier const gx_drawing_color * pdcolor,
2806*593dc095SDavid du Colombier const gx_clip_path * pcpath, gs_memory_t * mem,
2807*593dc095SDavid du Colombier gx_image_enum_common_t ** pinfo)
2808*593dc095SDavid du Colombier {
2809*593dc095SDavid du Colombier pdf14_clist_device * pdev = (pdf14_clist_device *)dev;
2810*593dc095SDavid du Colombier int code;
2811*593dc095SDavid du Colombier
2812*593dc095SDavid du Colombier /*
2813*593dc095SDavid du Colombier * Ensure that that the PDF 1.4 reading compositor will have the current
2814*593dc095SDavid du Colombier * blending parameters. This is needed since the fill_rectangle routines
2815*593dc095SDavid du Colombier * do not have access to the imager state. Thus we have to pass any
2816*593dc095SDavid du Colombier * changes explictly.
2817*593dc095SDavid du Colombier */
2818*593dc095SDavid du Colombier code = pdf14_clist_update_params(pdev, pis);
2819*593dc095SDavid du Colombier if (code < 0)
2820*593dc095SDavid du Colombier return code;
2821*593dc095SDavid du Colombier /* Pass image to the target */
2822*593dc095SDavid du Colombier return gx_default_begin_typed_image(dev, pis, pmat,
2823*593dc095SDavid du Colombier pic, prect, pdcolor, pcpath, mem, pinfo);
2824*593dc095SDavid du Colombier }
2825*593dc095SDavid du Colombier
2826*593dc095SDavid du Colombier /*
2827*593dc095SDavid du Colombier * When we push a PDF 1.4 transparency compositor onto the clist, we also need
2828*593dc095SDavid du Colombier * to create a compositing device for clist writing. The primary purpose of
2829*593dc095SDavid du Colombier * this device is to provide support for the process color model in which
2830*593dc095SDavid du Colombier * the PDF 1.4 transparency is done. (This may differ from the process color
2831*593dc095SDavid du Colombier * model of the output device.) The actual work of compositing the image is
2832*593dc095SDavid du Colombier * done on the output (reader) side of the clist.
2833*593dc095SDavid du Colombier */
2834*593dc095SDavid du Colombier private int
c_pdf14trans_clist_write_update(const gs_composite_t * pcte,gx_device * dev,gx_device ** pcdev,gs_imager_state * pis,gs_memory_t * mem)2835*593dc095SDavid du Colombier c_pdf14trans_clist_write_update(const gs_composite_t * pcte, gx_device * dev,
2836*593dc095SDavid du Colombier gx_device ** pcdev, gs_imager_state * pis, gs_memory_t * mem)
2837*593dc095SDavid du Colombier {
2838*593dc095SDavid du Colombier const gs_pdf14trans_t * pdf14pct = (const gs_pdf14trans_t *) pcte;
2839*593dc095SDavid du Colombier pdf14_clist_device * p14dev;
2840*593dc095SDavid du Colombier int code = 0;
2841*593dc095SDavid du Colombier
2842*593dc095SDavid du Colombier /* We only handle the push/pop operations */
2843*593dc095SDavid du Colombier switch (pdf14pct->params.pdf14_op) {
2844*593dc095SDavid du Colombier case PDF14_PUSH_DEVICE:
2845*593dc095SDavid du Colombier code = pdf14_create_clist_device(mem, pis, pcdev, dev);
2846*593dc095SDavid du Colombier /*
2847*593dc095SDavid du Colombier * Set the color_info of the clist device to match the compositing
2848*593dc095SDavid du Colombier * device. We will restore it when the compositor is popped.
2849*593dc095SDavid du Colombier * See pdf14_clist_create_compositor for the restore. Do the same
2850*593dc095SDavid du Colombier * with the imager state's get_cmap_procs. We do not want the
2851*593dc095SDavid du Colombier * imager state to use transfer functions on our color values. The
2852*593dc095SDavid du Colombier * transfer functions will be applied at the end after we have done
2853*593dc095SDavid du Colombier * our PDF 1.4 blend operations.
2854*593dc095SDavid du Colombier */
2855*593dc095SDavid du Colombier p14dev = (pdf14_clist_device *)(*pcdev);
2856*593dc095SDavid du Colombier p14dev->saved_target_color_info = dev->color_info;
2857*593dc095SDavid du Colombier dev->color_info = (*pcdev)->color_info;
2858*593dc095SDavid du Colombier p14dev->save_get_cmap_procs = pis->get_cmap_procs;
2859*593dc095SDavid du Colombier pis->get_cmap_procs = pdf14_get_cmap_procs;
2860*593dc095SDavid du Colombier gx_set_cmap_procs(pis, dev);
2861*593dc095SDavid du Colombier return code;
2862*593dc095SDavid du Colombier case PDF14_POP_DEVICE:
2863*593dc095SDavid du Colombier /*
2864*593dc095SDavid du Colombier * Ensure that the tranfer functions, etc. are current before we
2865*593dc095SDavid du Colombier * dump our transparency image to the output device.
2866*593dc095SDavid du Colombier */
2867*593dc095SDavid du Colombier code = cmd_put_halftone((gx_device_clist_writer *)
2868*593dc095SDavid du Colombier (((pdf14_clist_device *)dev)->target), pis->dev_ht);
2869*593dc095SDavid du Colombier break;
2870*593dc095SDavid du Colombier default:
2871*593dc095SDavid du Colombier break; /* do nothing for remaining ops */
2872*593dc095SDavid du Colombier }
2873*593dc095SDavid du Colombier *pcdev = dev;
2874*593dc095SDavid du Colombier return code;
2875*593dc095SDavid du Colombier }
2876*593dc095SDavid du Colombier
2877*593dc095SDavid du Colombier /*
2878*593dc095SDavid du Colombier * When we push a PDF 1.4 transparency compositor, we need to make the clist
2879*593dc095SDavid du Colombier * device color_info data match the compositing device. We need to do this
2880*593dc095SDavid du Colombier * since the PDF 1.4 transparency compositing device may use a different
2881*593dc095SDavid du Colombier * process color model than the output device. We do not need to modify the
2882*593dc095SDavid du Colombier * color related device procs since the compositing device has its own. We
2883*593dc095SDavid du Colombier * restore the color_info data when the transparency device is popped.
2884*593dc095SDavid du Colombier */
2885*593dc095SDavid du Colombier private int
c_pdf14trans_clist_read_update(gs_composite_t * pcte,gx_device * cdev,gx_device * tdev,gs_imager_state * pis,gs_memory_t * mem)2886*593dc095SDavid du Colombier c_pdf14trans_clist_read_update(gs_composite_t * pcte, gx_device * cdev,
2887*593dc095SDavid du Colombier gx_device * tdev, gs_imager_state * pis, gs_memory_t * mem)
2888*593dc095SDavid du Colombier {
2889*593dc095SDavid du Colombier pdf14_device * p14dev = (pdf14_device *)tdev;
2890*593dc095SDavid du Colombier gs_pdf14trans_t * pdf14pct = (gs_pdf14trans_t *) pcte;
2891*593dc095SDavid du Colombier
2892*593dc095SDavid du Colombier /*
2893*593dc095SDavid du Colombier * We only handle the push/pop operations. Save and restore the color_info
2894*593dc095SDavid du Colombier * field for the clist device. (This is needed since the process color
2895*593dc095SDavid du Colombier * model of the clist device needs to match the PDF 1.4 compositing
2896*593dc095SDavid du Colombier * device.
2897*593dc095SDavid du Colombier */
2898*593dc095SDavid du Colombier switch (pdf14pct->params.pdf14_op) {
2899*593dc095SDavid du Colombier case PDF14_PUSH_DEVICE:
2900*593dc095SDavid du Colombier p14dev->saved_clist_color_info = cdev->color_info;
2901*593dc095SDavid du Colombier cdev->color_info = p14dev->color_info;
2902*593dc095SDavid du Colombier break;
2903*593dc095SDavid du Colombier case PDF14_POP_DEVICE:
2904*593dc095SDavid du Colombier cdev->color_info = p14dev->saved_clist_color_info;
2905*593dc095SDavid du Colombier break;
2906*593dc095SDavid du Colombier default:
2907*593dc095SDavid du Colombier break; /* do nothing for remaining ops */
2908*593dc095SDavid du Colombier }
29093ff48bf5SDavid du Colombier return 0;
29103ff48bf5SDavid du Colombier }
2911