/src/ghostpdl/base/gdevdgbr.c
Line | Count | Source (jump to first uncovered line) |
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 | | /* Default implementation of device get_bits[_rectangle] */ |
17 | | #include "memory_.h" |
18 | | #include "gx.h" |
19 | | #include "gserrors.h" |
20 | | #include "gxdevice.h" |
21 | | #include "gxdevmem.h" |
22 | | #include "gxgetbit.h" |
23 | | #include "gxlum.h" |
24 | | #include "gdevmem.h" |
25 | | #include "gxdevsop.h" |
26 | | |
27 | | /* |
28 | | * Determine whether we can satisfy a request by simply using the stored |
29 | | * representation. dev is used only for color_info.{num_components, depth}. |
30 | | */ |
31 | | static bool |
32 | | requested_includes_stored(const gx_device *dev, |
33 | | const gs_get_bits_params_t *requested, |
34 | | const gs_get_bits_params_t *stored) |
35 | 160M | { |
36 | 160M | gs_get_bits_options_t both = requested->options & stored->options; |
37 | | |
38 | 160M | if (!(both & GB_PACKING_ALL)) |
39 | 474k | return false; |
40 | 160M | if (stored->options & GB_SELECT_PLANES) { |
41 | | /* |
42 | | * The device only provides a subset of the planes. |
43 | | * Make sure it provides all the requested ones. |
44 | | */ |
45 | 0 | int i; |
46 | 0 | int n = (stored->options & GB_PACKING_BIT_PLANAR ? |
47 | 0 | dev->color_info.depth : dev->color_info.num_components); |
48 | |
|
49 | 0 | if (!(requested->options & GB_SELECT_PLANES) || |
50 | 0 | !(both & (GB_PACKING_PLANAR | GB_PACKING_BIT_PLANAR)) |
51 | 0 | ) |
52 | 0 | return false; |
53 | 0 | for (i = 0; i < n; ++i) |
54 | 0 | if (requested->data[i] && !stored->data[i]) |
55 | 0 | return false; |
56 | 0 | } |
57 | 160M | if (both & GB_COLORS_NATIVE) |
58 | 160M | return true; |
59 | 0 | if (both & GB_COLORS_STANDARD_ALL) { |
60 | 0 | if ((both & GB_ALPHA_ALL) && (both & GB_DEPTH_ALL)) |
61 | 0 | return true; |
62 | 0 | } |
63 | 0 | return false; |
64 | 0 | } |
65 | | |
66 | | /* |
67 | | * Try to implement get_bits_rectangle by returning a pointer. |
68 | | * Note that dev is used only for computing the default raster |
69 | | * and for color_info.depth. |
70 | | * This routine does not check x or h for validity. |
71 | | */ |
72 | | int |
73 | | gx_get_bits_return_pointer(gx_device * dev, int x, int h, |
74 | | gs_get_bits_params_t *params, |
75 | | const gs_get_bits_params_t *stored, |
76 | | byte **stored_base) |
77 | 160M | { |
78 | 160M | gs_get_bits_options_t options = params->options; |
79 | 160M | gs_get_bits_options_t both = options & stored->options; |
80 | | |
81 | 160M | if (!(options & GB_RETURN_POINTER) || |
82 | 160M | !requested_includes_stored(dev, params, stored) |
83 | 160M | ) |
84 | 41.9M | return -1; |
85 | | /* |
86 | | * See whether we can return the bits in place. Note that even if |
87 | | * OFFSET_ANY isn't set, x_offset and x don't have to be equal: their |
88 | | * bit offsets only have to match modulo align_bitmap_mod * 8 (to |
89 | | * preserve alignment) if ALIGN_ANY isn't set, or mod 8 (since |
90 | | * byte alignment is always required) if ALIGN_ANY is set. |
91 | | */ |
92 | 118M | { |
93 | 118M | int depth = dev->color_info.depth; |
94 | | /* |
95 | | * For PLANAR devices, we assume that each plane consists of |
96 | | * depth/num_components bits. This is wrong in general, but if |
97 | | * the device wants something else, it should implement |
98 | | * get_bits_rectangle itself. |
99 | | */ |
100 | 118M | uint dev_raster = gx_device_raster(dev, true); |
101 | 118M | uint raster = |
102 | 118M | (options & (GB_RASTER_STANDARD | GB_RASTER_ANY) ? dev_raster : |
103 | 118M | params->raster); |
104 | 118M | byte *base; |
105 | | |
106 | 118M | if (h <= 1 || raster == dev_raster) { |
107 | 118M | int x_offset = |
108 | 118M | (options & GB_OFFSET_ANY ? x : |
109 | 118M | options & GB_OFFSET_0 ? 0 : params->x_offset); |
110 | | |
111 | 118M | if (x_offset == x) { |
112 | 118M | base = stored_base[0]; |
113 | 118M | params->x_offset = x; |
114 | 118M | } else { |
115 | 0 | uint align_mod = |
116 | 0 | (options & GB_ALIGN_ANY ? 8 : align_bitmap_mod * 8); |
117 | 0 | int bit_offset = x - x_offset; |
118 | 0 | int bytes; |
119 | |
|
120 | 0 | if (bit_offset & (align_mod - 1)) |
121 | 0 | return -1; /* can't align */ |
122 | 0 | if (depth & (depth - 1)) { |
123 | | /* step = lcm(depth, align_mod) */ |
124 | 0 | int step = depth / igcd(depth, align_mod) * align_mod; |
125 | |
|
126 | 0 | bytes = bit_offset / step * step; |
127 | 0 | } else { |
128 | | /* Use a faster algorithm if depth is a power of 2. */ |
129 | 0 | bytes = bit_offset & (-depth & -(int)align_mod); |
130 | 0 | } |
131 | 0 | base = stored_base[0] + arith_rshift(bytes, 3); |
132 | 0 | params->x_offset = (bit_offset - bytes) / depth; |
133 | 0 | } |
134 | 118M | params->options = |
135 | 118M | GB_ALIGN_STANDARD | GB_RETURN_POINTER | GB_RASTER_STANDARD | |
136 | 118M | (stored->options & ~GB_PACKING_ALL) /*see below for PACKING*/ | |
137 | 118M | (params->x_offset == 0 ? GB_OFFSET_0 : GB_OFFSET_SPECIFIED); |
138 | 118M | if (both & GB_PACKING_CHUNKY) { |
139 | 111M | params->options |= GB_PACKING_CHUNKY; |
140 | 111M | params->data[0] = base; |
141 | 111M | } else { |
142 | 7.38M | int n = |
143 | 7.38M | (stored->options & GB_PACKING_BIT_PLANAR ? |
144 | 0 | (params->options |= GB_PACKING_BIT_PLANAR, |
145 | 0 | dev->color_info.depth) : |
146 | 7.38M | (params->options |= GB_PACKING_PLANAR, |
147 | 7.38M | dev->num_planar_planes)); |
148 | 7.38M | int i; |
149 | | |
150 | 44.3M | for (i = 0; i < n; ++i) { |
151 | 36.9M | if (!(both & GB_SELECT_PLANES) || stored->data[i] != 0) { |
152 | 36.9M | params->data[i] = base; |
153 | 36.9M | } |
154 | 36.9M | if (i < n-1) { |
155 | 29.5M | base += stored_base[dev->height]-stored_base[0]; |
156 | 29.5M | stored_base += dev->height; |
157 | 29.5M | } |
158 | 36.9M | } |
159 | 7.38M | } |
160 | 118M | return 0; |
161 | 118M | } |
162 | 118M | } |
163 | 0 | return -1; |
164 | 118M | } |
165 | | |
166 | | /* |
167 | | * Implement gx_get_bits_copy (see below) for the case of converting |
168 | | * 4-bit CMYK to 24-bit RGB with standard mapping, used heavily by PCL. |
169 | | */ |
170 | | static void |
171 | | gx_get_bits_copy_cmyk_1bit(byte *dest_line, uint dest_raster, |
172 | | const byte *src_line, uint src_raster, |
173 | | int src_bit, int w, int h) |
174 | 0 | { |
175 | 0 | for (; h > 0; dest_line += dest_raster, src_line += src_raster, --h) { |
176 | 0 | const byte *src = src_line; |
177 | 0 | byte *dest = dest_line; |
178 | 0 | bool hi = (src_bit & 4) != 0; /* last nibble processed was hi */ |
179 | 0 | int i; |
180 | |
|
181 | 0 | for (i = w; i > 0; dest += 3, --i) { |
182 | 0 | uint pixel = |
183 | 0 | ((hi = !hi)? *src >> 4 : *src++ & 0xf); |
184 | |
|
185 | 0 | if (pixel & 1) |
186 | 0 | dest[0] = dest[1] = dest[2] = 0; |
187 | 0 | else { |
188 | 0 | dest[0] = (byte)((pixel >> 3) - 1); |
189 | 0 | dest[1] = (byte)(((pixel >> 2) & 1) - 1); |
190 | 0 | dest[2] = (byte)(((pixel >> 1) & 1) - 1); |
191 | 0 | } |
192 | 0 | } |
193 | 0 | } |
194 | 0 | } |
195 | | |
196 | | /* |
197 | | * Convert pixels between representations, primarily for get_bits_rectangle. |
198 | | * stored indicates how the data are actually stored, and includes: |
199 | | * - one option from the GB_PACKING group; |
200 | | * - if h > 1, one option from the GB_RASTER group; |
201 | | * - optionally (and normally), GB_COLORS_NATIVE; |
202 | | * - optionally, one option each from the GB_COLORS_STANDARD, GB_DEPTH, |
203 | | * and GB_ALPHA groups. |
204 | | * Note that dev is used only for color mapping. This routine assumes that |
205 | | * the stored data are aligned. |
206 | | * |
207 | | * Note: this routine does not check x, w, h for validity. |
208 | | * |
209 | | * The code for converting between standard and native colors has been |
210 | | * factored out into single-use procedures strictly for readability. |
211 | | * A good optimizing compiler would compile them in-line. |
212 | | */ |
213 | | static int |
214 | | gx_get_bits_native_to_std(gx_device * dev, int x, int w, int h, |
215 | | gs_get_bits_params_t * params, |
216 | | const gs_get_bits_params_t *stored, |
217 | | const byte * src_base, uint dev_raster, |
218 | | int x_offset, uint raster, uint std_raster); |
219 | | int |
220 | | gx_get_bits_copy(gx_device * dev, int x, int w, int h, |
221 | | gs_get_bits_params_t * params, |
222 | | const gs_get_bits_params_t *stored, |
223 | | const byte * src_base, uint dev_raster) |
224 | 41.4M | { |
225 | 41.4M | gs_get_bits_options_t options = params->options; |
226 | 41.4M | gs_get_bits_options_t stored_options = stored->options; |
227 | 41.4M | int x_offset = (options & GB_OFFSET_0 ? 0 : params->x_offset); |
228 | 41.4M | int depth = dev->color_info.depth; |
229 | 41.4M | int bit_x = x * depth; |
230 | 41.4M | const byte *src = src_base; |
231 | | /* |
232 | | * If the stored representation matches a requested representation, |
233 | | * we can copy the data without any transformations. |
234 | | */ |
235 | 41.4M | bool direct_copy = requested_includes_stored(dev, params, stored); |
236 | 41.4M | int code = 0; |
237 | | |
238 | | /* |
239 | | * The request must include either GB_PACKING_CHUNKY or |
240 | | * GB_PACKING_PLANAR + GB_SELECT_PLANES, GB_RETURN_COPY, |
241 | | * and an offset and raster specification. In the planar case, |
242 | | * the request must include GB_ALIGN_STANDARD, the stored |
243 | | * representation must include GB_PACKING_CHUNKY, and both must |
244 | | * include GB_COLORS_NATIVE. |
245 | | */ |
246 | 41.4M | if ((~options & GB_RETURN_COPY) || |
247 | 41.4M | !(options & (GB_OFFSET_0 | GB_OFFSET_SPECIFIED)) || |
248 | 41.4M | !(options & (GB_RASTER_STANDARD | GB_RASTER_SPECIFIED)) |
249 | 41.4M | ) |
250 | 0 | return_error(gs_error_rangecheck); |
251 | 41.4M | if (options & GB_PACKING_CHUNKY) { |
252 | 41.4M | byte *data = params->data[0]; |
253 | 41.4M | int end_bit = (x_offset + w) * depth; |
254 | 41.4M | uint std_raster = |
255 | 41.4M | (options & GB_ALIGN_STANDARD ? bitmap_raster(end_bit) : |
256 | 41.4M | (end_bit + 7) >> 3); |
257 | 41.4M | uint raster = |
258 | 41.4M | (options & GB_RASTER_STANDARD ? std_raster : params->raster); |
259 | 41.4M | int dest_bit_x = x_offset * depth; |
260 | 41.4M | int skew = bit_x - dest_bit_x; |
261 | | |
262 | | /* |
263 | | * If the bit positions line up, use bytes_copy_rectangle. |
264 | | * Since bytes_copy_rectangle doesn't require alignment, |
265 | | * the bit positions only have to match within a byte, |
266 | | * not within align_bitmap_mod bytes. |
267 | | */ |
268 | 41.4M | if (!(skew & 7) && direct_copy) { |
269 | 41.4M | int bit_w = w * depth; |
270 | | |
271 | 41.4M | bytes_copy_rectangle(data + (dest_bit_x >> 3), raster, |
272 | 41.4M | src + (bit_x >> 3), dev_raster, |
273 | 41.4M | ((bit_x + bit_w + 7) >> 3) - (bit_x >> 3), h); |
274 | 41.4M | } else if (direct_copy) { |
275 | | /* |
276 | | * Use the logic already in mem_mono_copy_mono to copy the |
277 | | * bits to the destination. We do this one line at a time, |
278 | | * to avoid having to allocate a line pointer table. |
279 | | */ |
280 | 0 | gx_device_memory tdev; |
281 | 0 | byte *line_ptr = data; |
282 | 0 | int bit_w = w * depth; |
283 | |
|
284 | 0 | tdev.line_ptrs = &tdev.base; |
285 | 0 | for (; h > 0; line_ptr += raster, src += dev_raster, --h) { |
286 | | /* Make sure the destination is aligned. */ |
287 | 0 | int align = ALIGNMENT_MOD(line_ptr, align_bitmap_mod); |
288 | |
|
289 | 0 | tdev.base = line_ptr - align; |
290 | | /* set up parameters required by copy_mono's fit_copy */ |
291 | 0 | tdev.width = dest_bit_x + (align << 3) + bit_w; |
292 | 0 | tdev.height = 1; |
293 | 0 | code = mem_mono_copy_mono((gx_device *) & tdev, src, bit_x, |
294 | 0 | dev_raster, gx_no_bitmap_id, |
295 | 0 | dest_bit_x + (align << 3), 0, bit_w, 1, |
296 | 0 | (gx_color_index) 0, (gx_color_index) 1); |
297 | 0 | if (code < 0) |
298 | 0 | break; |
299 | 0 | } |
300 | 0 | } else if (options & ~stored_options & GB_COLORS_NATIVE) { |
301 | | /* Convert standard colors to native. */ |
302 | 0 | return_error(gs_error_rangecheck); |
303 | 0 | } else { |
304 | | /* Convert native colors to standard. */ |
305 | 0 | code = gx_get_bits_native_to_std(dev, x, w, h, params, stored, |
306 | 0 | src_base, dev_raster, |
307 | 0 | x_offset, raster, std_raster); |
308 | 0 | options = params->options; |
309 | 0 | } |
310 | 41.4M | params->options = |
311 | 41.4M | (options & (GB_COLORS_ALL | GB_ALPHA_ALL)) | GB_PACKING_CHUNKY | |
312 | 41.4M | (options & GB_COLORS_NATIVE ? 0 : options & GB_DEPTH_ALL) | |
313 | 41.4M | (options & GB_ALIGN_STANDARD ? GB_ALIGN_STANDARD : GB_ALIGN_ANY) | |
314 | 41.4M | GB_RETURN_COPY | |
315 | 41.4M | (x_offset == 0 ? GB_OFFSET_0 : GB_OFFSET_SPECIFIED) | |
316 | 41.4M | (raster == std_raster ? GB_RASTER_STANDARD : GB_RASTER_SPECIFIED); |
317 | 41.4M | } else if (!(~options & |
318 | 0 | (GB_PACKING_PLANAR | GB_SELECT_PLANES | GB_ALIGN_STANDARD)) && |
319 | 0 | (stored_options & GB_PACKING_CHUNKY) && |
320 | 0 | ((options & stored_options) & GB_COLORS_NATIVE) |
321 | 0 | ) { |
322 | 0 | uchar num_planes = dev->color_info.num_components; |
323 | 0 | int dest_depth = depth / num_planes; |
324 | 0 | bits_plane_t source, dest; |
325 | 0 | int plane = -1; |
326 | 0 | uchar i; |
327 | | |
328 | | /* Make sure only one plane is being requested. */ |
329 | 0 | for (i = 0; i < num_planes; ++i) |
330 | 0 | if (params->data[i] != 0) { |
331 | 0 | if (plane >= 0) |
332 | 0 | return_error(gs_error_rangecheck); /* > 1 plane */ |
333 | 0 | plane = i; |
334 | 0 | } |
335 | | /* Ensure at least one plane is requested */ |
336 | 0 | if (plane < 0) |
337 | 0 | return_error(gs_error_rangecheck); /* No planes */ |
338 | 0 | source.data.read = src_base; |
339 | 0 | source.raster = dev_raster; |
340 | 0 | source.depth = depth; |
341 | 0 | source.x = x; |
342 | 0 | dest.data.write = params->data[plane]; |
343 | 0 | dest.raster = |
344 | 0 | (options & GB_RASTER_STANDARD ? |
345 | 0 | bitmap_raster((x_offset + w) * dest_depth) : params->raster); |
346 | 0 | if (dev->color_info.separable_and_linear == GX_CINFO_SEP_LIN) |
347 | 0 | dest.depth = dev->color_info.comp_bits[plane]; |
348 | 0 | else |
349 | 0 | dest.depth = dest_depth; |
350 | 0 | dest.x = x_offset; |
351 | 0 | return bits_extract_plane(&dest, &source, |
352 | 0 | (num_planes - 1 - plane) * dest_depth, |
353 | 0 | w, h); |
354 | 0 | } else |
355 | 0 | return_error(gs_error_rangecheck); |
356 | 41.4M | return code; |
357 | 41.4M | } |
358 | | |
359 | | /* |
360 | | * Convert native colors to standard. Only GB_DEPTH_8 is supported. |
361 | | */ |
362 | | static int |
363 | | gx_get_bits_native_to_std(gx_device * dev, int x, int w, int h, |
364 | | gs_get_bits_params_t * params, |
365 | | const gs_get_bits_params_t *stored, |
366 | | const byte * src_base, uint dev_raster, |
367 | | int x_offset, uint raster, uint std_raster) |
368 | 0 | { |
369 | 0 | int depth = dev->color_info.depth; |
370 | 0 | int src_bit_offset = x * depth; |
371 | 0 | const byte *src_line = src_base + (src_bit_offset >> 3); |
372 | 0 | gs_get_bits_options_t options = params->options; |
373 | 0 | int ncomp = |
374 | 0 | (options & (GB_ALPHA_FIRST | GB_ALPHA_LAST) ? 4 : 3); |
375 | 0 | byte *dest_line = params->data[0] + x_offset * ncomp; |
376 | 0 | byte *mapped[16]; |
377 | 0 | int dest_bytes; |
378 | 0 | int i; |
379 | |
|
380 | 0 | if (!(options & GB_DEPTH_8)) { |
381 | | /* |
382 | | * We don't support general depths yet, or conversion between |
383 | | * different formats. Punt. |
384 | | */ |
385 | 0 | return_error(gs_error_rangecheck); |
386 | 0 | } |
387 | | |
388 | | /* Pick the representation that's most likely to be useful. */ |
389 | 0 | if (options & GB_COLORS_RGB) |
390 | 0 | params->options = options &= ~GB_COLORS_STANDARD_ALL | GB_COLORS_RGB, |
391 | 0 | dest_bytes = 3; |
392 | 0 | else if (options & GB_COLORS_CMYK) |
393 | 0 | params->options = options &= ~GB_COLORS_STANDARD_ALL | GB_COLORS_CMYK, |
394 | 0 | dest_bytes = 4; |
395 | 0 | else if (options & GB_COLORS_GRAY) |
396 | 0 | params->options = options &= ~GB_COLORS_STANDARD_ALL | GB_COLORS_GRAY, |
397 | 0 | dest_bytes = 1; |
398 | 0 | else |
399 | 0 | return_error(gs_error_rangecheck); |
400 | | /* Recompute the destination raster based on the color space. */ |
401 | 0 | if (options & GB_RASTER_STANDARD) { |
402 | 0 | uint end_byte = (x_offset + w) * dest_bytes; |
403 | |
|
404 | 0 | raster = std_raster = |
405 | 0 | (options & GB_ALIGN_STANDARD ? |
406 | 0 | bitmap_raster(end_byte << 3) : end_byte); |
407 | 0 | } |
408 | | /* Check for the one special case we care about, namely that we have a |
409 | | * device that uses cmyk_1bit_map_cmyk_color, or equivalent. We do not |
410 | | * check function pointers directly, as this is defeated by forwarding |
411 | | * devices, but rather use a dev_spec_op. */ |
412 | 0 | if (((options & (GB_COLORS_RGB | GB_ALPHA_FIRST | GB_ALPHA_LAST)) |
413 | 0 | == GB_COLORS_RGB) && |
414 | 0 | (dev_proc(dev, dev_spec_op)(dev, gxdso_is_std_cmyk_1bit, NULL, 0) > 0)) { |
415 | 0 | gx_get_bits_copy_cmyk_1bit(dest_line, raster, |
416 | 0 | src_line, dev_raster, |
417 | 0 | src_bit_offset & 7, w, h); |
418 | 0 | return 0; |
419 | 0 | } |
420 | 0 | if (options & (GB_ALPHA_FIRST | GB_ALPHA_LAST)) |
421 | 0 | ++dest_bytes; |
422 | | /* Clear the color translation cache. */ |
423 | 0 | for (i = (depth > 4 ? 16 : 1 << depth); --i >= 0; ) |
424 | 0 | mapped[i] = 0; |
425 | 0 | for (; h > 0; dest_line += raster, src_line += dev_raster, --h) { |
426 | 0 | const byte *src = src_line; |
427 | 0 | int bit = src_bit_offset & 7; |
428 | 0 | byte *dest = dest_line; |
429 | |
|
430 | 0 | for (i = 0; i < w; ++i) { |
431 | 0 | gx_color_index pixel = 0; |
432 | 0 | gx_color_value rgba[4]; |
433 | |
|
434 | 0 | if (sizeof(pixel) > 4) { |
435 | 0 | if (sample_load_next64((uint64_t *)&pixel, &src, &bit, depth) < 0) |
436 | 0 | return_error(gs_error_rangecheck); |
437 | 0 | } |
438 | 0 | else { |
439 | 0 | if (sample_load_next32((uint32_t *)&pixel, &src, &bit, depth) < 0) |
440 | 0 | return_error(gs_error_rangecheck); |
441 | 0 | } |
442 | 0 | if (pixel < 16) { |
443 | 0 | if (mapped[pixel]) { |
444 | | /* Use the value from the cache. */ |
445 | 0 | memcpy(dest, mapped[pixel], dest_bytes); |
446 | 0 | dest += dest_bytes; |
447 | 0 | continue; |
448 | 0 | } |
449 | 0 | mapped[pixel] = dest; |
450 | 0 | } |
451 | 0 | (*dev_proc(dev, map_color_rgb)) (dev, pixel, rgba); |
452 | 0 | if (options & GB_ALPHA_FIRST) |
453 | 0 | *dest++ = 0xff; |
454 | | /* Convert to the requested color space. */ |
455 | 0 | if (options & GB_COLORS_RGB) { |
456 | 0 | dest[0] = gx_color_value_to_byte(rgba[0]); |
457 | 0 | dest[1] = gx_color_value_to_byte(rgba[1]); |
458 | 0 | dest[2] = gx_color_value_to_byte(rgba[2]); |
459 | 0 | dest += 3; |
460 | 0 | } else if (options & GB_COLORS_CMYK) { |
461 | | /* Use the standard RGB to CMYK algorithm, */ |
462 | | /* with maximum black generation and undercolor removal. */ |
463 | 0 | gx_color_value white = max(rgba[0], max(rgba[1], rgba[2])); |
464 | |
|
465 | 0 | dest[0] = gx_color_value_to_byte(white - rgba[0]); |
466 | 0 | dest[1] = gx_color_value_to_byte(white - rgba[1]); |
467 | 0 | dest[2] = gx_color_value_to_byte(white - rgba[2]); |
468 | 0 | dest[3] = gx_color_value_to_byte(gx_max_color_value - white); |
469 | 0 | dest += 4; |
470 | 0 | } else { /* GB_COLORS_GRAY */ |
471 | | /* Use the standard RGB to Gray algorithm. */ |
472 | 0 | *dest++ = gx_color_value_to_byte( |
473 | 0 | ((rgba[0] * (ulong) lum_red_weight) + |
474 | 0 | (rgba[1] * (ulong) lum_green_weight) + |
475 | 0 | (rgba[2] * (ulong) lum_blue_weight) + |
476 | 0 | (lum_all_weights / 2)) |
477 | 0 | / lum_all_weights); |
478 | 0 | } |
479 | 0 | if (options & GB_ALPHA_LAST) |
480 | 0 | *dest++ = 0xff; |
481 | 0 | } |
482 | 0 | } |
483 | 0 | return 0; |
484 | 0 | } |
485 | | |
486 | | /* ------ Default implementations of get_bits_rectangle ------ */ |
487 | | |
488 | | int |
489 | | gx_default_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect, |
490 | | gs_get_bits_params_t * params) |
491 | 0 | { |
492 | 0 | return_error(gs_error_unknownerror); |
493 | 0 | } |
494 | | |
495 | | int gx_blank_get_bits_rectangle(gx_device *dev, const gs_int_rect *prect, |
496 | | gs_get_bits_params_t *params) |
497 | 0 | { |
498 | 0 | int supported = GB_COLORS_NATIVE | |
499 | 0 | GB_ALPHA_NONE | |
500 | 0 | GB_DEPTH_8 | |
501 | 0 | GB_PACKING_CHUNKY | |
502 | 0 | GB_RETURN_COPY | |
503 | 0 | GB_ALIGN_STANDARD | |
504 | 0 | GB_OFFSET_0 | |
505 | 0 | GB_RASTER_STANDARD; |
506 | 0 | unsigned char *ptr = params->data[0]; |
507 | 0 | int bytes = (prect->q.x - prect->p.x) * dev->color_info.num_components; |
508 | 0 | int col = dev->color_info.num_components > 3 ? 0 : 0xff; |
509 | 0 | int raster = bitmap_raster(dev->width * dev->color_info.num_components); |
510 | 0 | int y; |
511 | |
|
512 | 0 | if ((params->options & supported) != supported) |
513 | 0 | return_error(gs_error_unknownerror); |
514 | | |
515 | 0 | params->options = supported; |
516 | |
|
517 | 0 | for (y = prect->p.y; y < prect->q.y; y++) { |
518 | 0 | memset(ptr, col, bytes); |
519 | 0 | ptr += raster; |
520 | 0 | } |
521 | |
|
522 | 0 | return 0; |
523 | 0 | } |