/src/ghostpdl/base/gdevmplt.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2023 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | /* Device to set monochrome mode in PCL */ |
17 | | /* This device is one of the 'subclassing' devices, part of a chain or pipeline |
18 | | * of devices, each of which can process some aspect of the graphics methods |
19 | | * before passing them on to the next device in the chain. |
20 | | * In this case, the device simply returns monochrome color_mapping procs |
21 | | * instead of color ones. When we want to go back to color, we just |
22 | | * remove this device. |
23 | | */ |
24 | | #include "math_.h" |
25 | | #include "memory_.h" |
26 | | #include "gx.h" |
27 | | #include "gserrors.h" |
28 | | #include "gsparam.h" |
29 | | #include "gxdevice.h" |
30 | | #include "gsdevice.h" /* requires gsmatrix.h */ |
31 | | #include "gxdcolor.h" /* for gx_device_black/white */ |
32 | | #include "gxiparam.h" /* for image source size */ |
33 | | #include "gxgstate.h" |
34 | | #include "gxpaint.h" |
35 | | #include "gxpath.h" |
36 | | #include "gxcpath.h" |
37 | | #include "gxcmap.h" /* color mapping procs */ |
38 | | #include "gsstype.h" |
39 | | #include "gdevprn.h" |
40 | | #include "gdevp14.h" /* Needed to patch up the procs after compositor creation */ |
41 | | #include "gdevsclass.h" |
42 | | #include "gdevmplt.h" |
43 | | #include "gxdcconv.h" /* for color_rgb_to_gray and color_cmyk_to_gray */ |
44 | | #include "gxdevsop.h" |
45 | | |
46 | | /* Device procedures, we only need one */ |
47 | | static dev_proc_get_color_mapping_procs(pcl_mono_palette_get_color_mapping_procs); |
48 | | |
49 | | /* The device prototype */ |
50 | | #define MAX_COORD (max_int_in_fixed - 1000) |
51 | | #define MAX_RESOLUTION 4000 |
52 | | |
53 | | /* GC descriptor */ |
54 | | #define public_st_pcl_mono_palette_device() /* in gsdevice.c */\ |
55 | | gs_public_st_complex_only(st_pcl_mono_palette_device, gx_device, "PCL_Mono_Palette",\ |
56 | | 0, pcl_mono_palette_enum_ptrs, pcl_mono_palette_reloc_ptrs, default_subclass_finalize) |
57 | | |
58 | | static |
59 | 0 | ENUM_PTRS_WITH(pcl_mono_palette_enum_ptrs, gx_device *dev); |
60 | 0 | return 0; /* default case */ |
61 | 0 | case 0:ENUM_RETURN(gx_device_enum_ptr(dev->parent)); |
62 | 0 | case 1:ENUM_RETURN(gx_device_enum_ptr(dev->child)); |
63 | 0 | ENUM_PTRS_END |
64 | 0 | static RELOC_PTRS_WITH(pcl_mono_palette_reloc_ptrs, gx_device *dev) |
65 | 0 | { |
66 | 0 | dev->parent = gx_device_reloc_ptr(dev->parent, gcst); |
67 | 0 | dev->child = gx_device_reloc_ptr(dev->child, gcst); |
68 | 0 | } |
69 | 0 | RELOC_PTRS_END |
70 | | |
71 | | public_st_pcl_mono_palette_device(); |
72 | | |
73 | | static int |
74 | | pcl_mono_dev_spec_op(gx_device *dev, int dev_spec_op, void *data, int size) |
75 | 0 | { |
76 | 0 | if (dev_spec_op == gxdso_supports_hlcolor) |
77 | 0 | return 0; |
78 | 0 | if (dev->child) |
79 | 0 | return dev_proc(dev->child, dev_spec_op)(dev->child, dev_spec_op, data, size); |
80 | 0 | return_error(gs_error_rangecheck); |
81 | 0 | } |
82 | | |
83 | | static int |
84 | | pcl_mono_text_begin(gx_device *dev, gs_gstate *pgs, const gs_text_params_t *text, |
85 | | gs_font *font, const gx_clip_path *pcpath, gs_text_enum_t **ppte) |
86 | 0 | { |
87 | | /* The 'high level' version of the color has not been 'monochromized' by this |
88 | | * device, so ensure that routines that we call (notably pdfwrite) don't |
89 | | * think it's valid and use it. */ |
90 | 0 | pgs->color[0].dev_color->ccolor_valid = 0; |
91 | |
|
92 | 0 | if (dev->child) |
93 | 0 | return dev_proc(dev->child, text_begin)(dev->child, pgs, text, font, pcpath, ppte); |
94 | 0 | else |
95 | 0 | return gx_default_text_begin(dev, pgs, text, font, pcpath, ppte); |
96 | 0 | } |
97 | | |
98 | | static void |
99 | | pcl_mono_palette_initialize(gx_device *dev) |
100 | 0 | { |
101 | 0 | default_subclass_initialize_device_procs(dev); |
102 | |
|
103 | 0 | set_dev_proc(dev, get_color_mapping_procs, pcl_mono_palette_get_color_mapping_procs); |
104 | | /* We must override begin_typed_image here with the default. If |
105 | | * we don't, then we forward down to the underlying devices own |
106 | | * begin_typed_image, and the color calls done during that bypass |
107 | | * the monochroming behaviour. See: page 32 of 75dpi png rendering of |
108 | | * tests_private/pcl/pcl5ccet/15-01.BIN for an example. */ |
109 | 0 | set_dev_proc(dev, begin_typed_image, gx_default_begin_typed_image); |
110 | 0 | set_dev_proc(dev, dev_spec_op, pcl_mono_dev_spec_op); |
111 | 0 | set_dev_proc(dev, text_begin, pcl_mono_text_begin); |
112 | 0 | } |
113 | | |
114 | | const |
115 | | gx_device_mplt gs_pcl_mono_palette_device = |
116 | | { |
117 | | /* |
118 | | * Define the device as 8-bit gray scale to avoid computing halftones. |
119 | | */ |
120 | | std_device_dci_type_body_sc(gx_device_mplt, pcl_mono_palette_initialize, |
121 | | "PCL_Mono_Palette", &st_pcl_mono_palette_device, |
122 | | MAX_COORD, MAX_COORD, |
123 | | MAX_RESOLUTION, MAX_RESOLUTION, |
124 | | 1, 8, 255, 0, 256, 1, NULL, NULL, NULL) |
125 | | }; |
126 | | |
127 | | #undef MAX_COORD |
128 | | #undef MAX_RESOLUTION |
129 | | |
130 | | /* The justification for this device, these 3 procedures map colour values |
131 | | * to gray values |
132 | | */ |
133 | | static void |
134 | | pcl_gray_cs_to_cm(const gx_device * dev, frac gray, frac out[]) |
135 | 0 | { |
136 | 0 | pcl_mono_palette_subclass_data *psubclass_data = dev->subclass_data; |
137 | | |
138 | | /* assert(strncmp(dev->dname, "PCL_Mono_Palette", 16) == 0) - otherwise we are being |
139 | | * called with the wrong dev! */ |
140 | |
|
141 | 0 | if (psubclass_data->device_cm) { |
142 | | /* just pass it along */ |
143 | 0 | psubclass_data->device_cm_procs->map_gray(psubclass_data->device_cm, gray, out); |
144 | 0 | } |
145 | 0 | } |
146 | | |
147 | | static void |
148 | | pcl_rgb_cs_to_cm(const gx_device * dev, const gs_gstate * pgs, frac r, frac g, |
149 | | frac b, frac out[]) |
150 | 0 | { |
151 | 0 | pcl_mono_palette_subclass_data *psubclass_data = dev->subclass_data; |
152 | 0 | frac gray; |
153 | | |
154 | | /* assert(strncmp(dev->dname, "PCL_Mono_Palette", 16) == 0) - otherwise we are being |
155 | | * called with the wrong dev! */ |
156 | |
|
157 | 0 | if (psubclass_data->device_cm) { |
158 | 0 | gray = color_rgb_to_gray(r, g, b, NULL); |
159 | |
|
160 | 0 | psubclass_data->device_cm_procs->map_rgb(psubclass_data->device_cm, pgs, gray, gray, gray, out); |
161 | 0 | } |
162 | 0 | } |
163 | | |
164 | | static void |
165 | | pcl_cmyk_cs_to_cm(const gx_device * dev, frac c, frac m, frac y, frac k, frac out[]) |
166 | 0 | { |
167 | 0 | pcl_mono_palette_subclass_data *psubclass_data = dev->subclass_data; |
168 | 0 | frac gray; |
169 | | |
170 | | /* assert(strncmp(dev->dname, "PCL_Mono_Palette", 16) == 0) - otherwise we are being |
171 | | * called with the wrong dev! */ |
172 | |
|
173 | 0 | if (psubclass_data->device_cm) { |
174 | 0 | gray = color_cmyk_to_gray(c, m, y, k, NULL); |
175 | |
|
176 | 0 | psubclass_data->device_cm_procs->map_cmyk(psubclass_data->device_cm, gray, gray, gray, gray, out); |
177 | 0 | } |
178 | 0 | } |
179 | | |
180 | | static gx_cm_color_map_procs pcl_mono_procs = |
181 | | { |
182 | | pcl_gray_cs_to_cm, |
183 | | pcl_rgb_cs_to_cm, |
184 | | pcl_cmyk_cs_to_cm |
185 | | }; |
186 | | |
187 | | const gx_cm_color_map_procs *pcl_mono_palette_get_color_mapping_procs(const gx_device *dev, |
188 | | const gx_device **tdev) |
189 | 0 | { |
190 | 0 | pcl_mono_palette_subclass_data *psubclass_data = dev->subclass_data; |
191 | | |
192 | | /* assert(strncmp(dev->dname, "PCL_Mono_Palette", 16) == 0) - otherwise we are being |
193 | | * called with the wrong dev! */ |
194 | |
|
195 | 0 | *tdev = dev; |
196 | 0 | if (psubclass_data->device_cm_procs == NULL) { |
197 | 0 | psubclass_data->device_cm_procs = (gx_cm_color_map_procs *)dev_proc(dev->child, get_color_mapping_procs)(dev->child, &psubclass_data->device_cm); |
198 | 0 | } |
199 | 0 | return &pcl_mono_procs; |
200 | 0 | } |