/src/ghostpdl/contrib/pcl3/eprn/eprnrend.c
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | File: $Id: eprnrend.c,v 1.15 2001/08/01 05:12:56 Martin Rel $ |
3 | | Contents: Colour rendering functionality for the ghostscript device 'eprn' |
4 | | Author: Martin Lottermoser, Greifswaldstrasse 28, 38124 Braunschweig, |
5 | | Germany. E-mail: Martin.Lottermoser@t-online.de. |
6 | | |
7 | | ******************************************************************************* |
8 | | * * |
9 | | * Copyright (C) 2000, 2001 by Martin Lottermoser * |
10 | | * All rights reserved * |
11 | | * * |
12 | | ******************************************************************************* |
13 | | |
14 | | Preprocessor variables: |
15 | | |
16 | | EPRN_TRACE |
17 | | Define this to enable tracing. Only useful for development. |
18 | | |
19 | | EPRN_TRAILING_BIT_BUG_FIXED |
20 | | Define this to deactivate compensation for a bug in ghostscript which |
21 | | leads to the last pixel in an RGB line being black instead of white. |
22 | | This occurs at least in gs 6.01 and 6.50. The correction covers only |
23 | | the one-bit-per-colorant case and is equivalent to clipping the pixel. |
24 | | |
25 | | ******************************************************************************* |
26 | | |
27 | | The eprn device uses 'gx_color_index' values with varying interpretations, |
28 | | depending on the colour model and the rendering method, and stores them at |
29 | | different pixmaps depths, normally using the smallest depth which can |
30 | | accommodate all colorants at the same number of bits per colorant. |
31 | | |
32 | | To simplify matters, a field for the black component is always included, even |
33 | | for RGB and CMY, i.e., there are either 1 or 4 bit fields in a |
34 | | 'gx_color_index' value. If there are 4, the interpretation is either YMCK or |
35 | | BGRK, looking from left to right (most to least significant). The width of |
36 | | the fields can be found in the 'bits_per_colorant' variable in the eprn part |
37 | | of the device instance. |
38 | | |
39 | | Within each colorant field, not all bits need be used. Except when using the |
40 | | *_max() colour mapping functions, the values returned by |
41 | | eprn_bits_for_levels() for the parameters 'black_levels' and |
42 | | 'non_black_levels' determine the number of bits which are actually |
43 | | meaningful. Only the last (least significant) bits are used. |
44 | | |
45 | | ******************************************************************************/ |
46 | | |
47 | | /*****************************************************************************/ |
48 | | |
49 | | #ifndef _XOPEN_SOURCE |
50 | | #define _XOPEN_SOURCE 500 |
51 | | #endif |
52 | | |
53 | | /* Special Aladdin header, must be included before <sys/types.h> on some |
54 | | platforms (e.g., FreeBSD). */ |
55 | | #include "std.h" |
56 | | |
57 | | /* Standard headers */ |
58 | | #include "assert_.h" |
59 | | #include <stdlib.h> |
60 | | |
61 | | /* Ghostscript headers */ |
62 | | #ifdef EPRN_TRACE |
63 | | #include "gdebug.h" |
64 | | #endif /* EPRN_TRACE */ |
65 | | |
66 | | /* Special headers */ |
67 | | #include "gdeveprn.h" |
68 | | |
69 | | /*****************************************************************************/ |
70 | | |
71 | | /* Macros for 'gx_color_index' values used mainly for non-monochrome modes and |
72 | | a pixmap depth of 4 */ |
73 | | |
74 | | /* Colorants bits, numbered from 0 on the right to 3 on the left */ |
75 | 0 | #define COLORANT_0_BIT 1U |
76 | 0 | #define COLORANT_1_BIT 2U |
77 | 0 | #define COLORANT_2_BIT 4U |
78 | 0 | #define COLORANT_3_BIT 8U |
79 | | |
80 | | /* Alias names for the bits in particular colour models */ |
81 | 0 | #define BLACK_BIT COLORANT_0_BIT |
82 | 0 | #define CYAN_BIT COLORANT_1_BIT |
83 | 0 | #define MAGENTA_BIT COLORANT_2_BIT |
84 | 0 | #define YELLOW_BIT COLORANT_3_BIT |
85 | 0 | #define RED_BIT COLORANT_1_BIT |
86 | 0 | #define GREEN_BIT COLORANT_2_BIT |
87 | 0 | #define BLUE_BIT COLORANT_3_BIT |
88 | | |
89 | | /* Bit plane indices for splitting */ |
90 | 0 | #define COLORANT_0_INDEX 0 |
91 | 0 | #define COLORANT_1_INDEX 1 |
92 | 0 | #define COLORANT_2_INDEX 2 |
93 | 0 | #define COLORANT_3_INDEX 3 |
94 | | |
95 | | /* Macro to extract the dominant 8 bits from a 'gx_color_value'. This |
96 | | definition assumes that 'gx_color_value' uses the least significant 16 bits |
97 | | of the underlying type (unsigned short). Splitting this part off looks |
98 | | inefficient because left shifts will usually follow, but I'm relying on the |
99 | | compiler to be sufficiently intelligent to eliminate this inefficiency. |
100 | | This way the code is easier to check. |
101 | | The type cast is needed to prevent problems with negative values on |
102 | | platforms where 'gx_color_index' has more bits than 'int'. |
103 | | */ |
104 | 0 | #define dominant_8bits(value) ((unsigned int)((value) >> 8)) |
105 | | |
106 | | /****************************************************************************** |
107 | | |
108 | | Function: eprn_number_of_bitplanes |
109 | | |
110 | | Total number of bit planes returned by eprn_get_planes(). |
111 | | This value is constant while the device is open. |
112 | | |
113 | | ******************************************************************************/ |
114 | | |
115 | | unsigned int eprn_number_of_bitplanes(eprn_Device *dev) |
116 | 0 | { |
117 | 0 | return dev->eprn.output_planes; |
118 | 0 | } |
119 | | |
120 | | /****************************************************************************** |
121 | | |
122 | | Function: eprn_number_of_octets |
123 | | |
124 | | Maximal lengths, in terms of the number of 'eprn_Octet' instances, for each |
125 | | bit plane returned by eprn_get_planes() for this device. These values |
126 | | are constant while the device is open. |
127 | | |
128 | | ******************************************************************************/ |
129 | | |
130 | | void eprn_number_of_octets(eprn_Device *dev, unsigned int lenghts[]) |
131 | 0 | { |
132 | 0 | unsigned int j, length; |
133 | |
|
134 | 0 | length = (dev->eprn.octets_per_line + dev->color_info.depth - 1)/ |
135 | 0 | dev->color_info.depth; |
136 | | /* This results in length >= ceiling((number of pixels per line)/8) |
137 | | because: |
138 | | 8 * octets_per_line >= pixels_per_line * depth |
139 | | <==> octets_per_line/depth >= pixels_per_line/8 |
140 | | where division is to be understood as exact. |
141 | | */ |
142 | |
|
143 | 0 | for (j = 0; j < dev->eprn.output_planes; j++) lenghts[j] = length; |
144 | |
|
145 | 0 | return; |
146 | 0 | } |
147 | | |
148 | | /****************************************************************************** |
149 | | |
150 | | Function: eprn_map_rgb_color_for_RGB |
151 | | |
152 | | Colour mapping function for the process colour model 'DeviceRGB' and |
153 | | 2 intensity levels per colorant. |
154 | | |
155 | | ******************************************************************************/ |
156 | | |
157 | | gx_color_index eprn_map_rgb_color_for_RGB(gx_device *device, |
158 | | const gx_color_value cv[]) |
159 | 0 | { |
160 | 0 | gx_color_value red = cv[0], green = cv[1], blue = cv[2]; |
161 | 0 | static const gx_color_value half = gx_max_color_value/2; |
162 | 0 | gx_color_index value = 0; |
163 | |
|
164 | | #ifdef EPRN_TRACE |
165 | | if_debug3(EPRN_TRACE_CHAR, |
166 | | "! eprn_map_rgb_color_for_RGB() called for RGB = (%hu, %hu, %hu),\n", |
167 | | red, green, blue); |
168 | | #endif |
169 | |
|
170 | 0 | assert(((eprn_Device *)device)->eprn.colour_model == eprn_DeviceRGB); |
171 | |
|
172 | 0 | if (red > half) value |= RED_BIT; |
173 | 0 | if (green > half) value |= GREEN_BIT; |
174 | 0 | if (blue > half) value |= BLUE_BIT; |
175 | |
|
176 | | #ifdef EPRN_TRACE |
177 | | if_debug1(EPRN_TRACE_CHAR, " returning 0x%lX.\n", (unsigned long)value); |
178 | | #endif |
179 | 0 | return value; |
180 | 0 | } |
181 | | |
182 | | /****************************************************************************** |
183 | | |
184 | | Function: eprn_map_rgb_color_for_CMY_or_K |
185 | | |
186 | | Colour mapping function for the native colour spaces DeviceGray and DeviceRGB |
187 | | and a process colour model using a selection of CMYK colorants with at most |
188 | | 2 intensity levels per colorant. This function must not be called for the |
189 | | process colour models 'DeviceRGB' and 'DeviceCMYK'. |
190 | | |
191 | | ******************************************************************************/ |
192 | | |
193 | | gx_color_index eprn_map_rgb_color_for_CMY_or_K(gx_device *device, |
194 | | const gx_color_value cv[]) |
195 | 0 | { |
196 | 0 | gx_color_value red = cv[0], green = cv[1], blue = cv[2]; |
197 | 0 | static const gx_color_value half = gx_max_color_value/2; |
198 | 0 | gx_color_index value = (CYAN_BIT | MAGENTA_BIT | YELLOW_BIT); |
199 | 0 | const eprn_Device *dev = (eprn_Device *)device; |
200 | |
|
201 | | #ifdef EPRN_TRACE |
202 | | if_debug3(EPRN_TRACE_CHAR, |
203 | | "! eprn_map_rgb_color_for_CMY_or_K() called for RGB = (%hu, %hu, %hu),\n", |
204 | | red, green, blue); |
205 | | #endif |
206 | |
|
207 | 0 | assert((dev->eprn.colour_model == eprn_DeviceGray && red == green && |
208 | 0 | green == blue && (blue == 0 || blue == gx_max_color_value)) || |
209 | 0 | dev->eprn.colour_model == eprn_DeviceCMY || |
210 | 0 | dev->eprn.colour_model == eprn_DeviceCMY_plus_K); |
211 | | |
212 | | /* Map to CMY */ |
213 | 0 | if (red > half) value &= ~CYAN_BIT; |
214 | 0 | if (green > half) value &= ~MAGENTA_BIT; |
215 | 0 | if (blue > half) value &= ~YELLOW_BIT; |
216 | | |
217 | | /* Remap composite black to true black if available */ |
218 | 0 | if (dev->eprn.colour_model != eprn_DeviceCMY && |
219 | 0 | value == (CYAN_BIT | MAGENTA_BIT | YELLOW_BIT)) |
220 | 0 | value = BLACK_BIT; |
221 | |
|
222 | | #ifdef EPRN_TRACE |
223 | | if_debug1(EPRN_TRACE_CHAR, " returning 0x%lX.\n", (unsigned long)value); |
224 | | #endif |
225 | 0 | return value; |
226 | 0 | } |
227 | | |
228 | | /****************************************************************************** |
229 | | |
230 | | Function: eprn_map_rgb_color_for_RGB_flex |
231 | | |
232 | | This is a 'map_rgb_color' method for the process colour model 'DeviceRGB' |
233 | | supporting any number of intensity levels. |
234 | | |
235 | | ******************************************************************************/ |
236 | | |
237 | | gx_color_index eprn_map_rgb_color_for_RGB_flex(gx_device *device, |
238 | | const gx_color_value cv[]) |
239 | 0 | { |
240 | 0 | gx_color_value red = cv[0], green = cv[1], blue = cv[2]; |
241 | 0 | gx_color_index value = 0; |
242 | 0 | gx_color_value step; |
243 | 0 | gx_color_index level; |
244 | 0 | const eprn_Eprn *eprn = &((eprn_Device *)device)->eprn; |
245 | |
|
246 | | #ifdef EPRN_TRACE |
247 | | if_debug3(EPRN_TRACE_CHAR, |
248 | | "! eprn_map_rgb_color_for_RGB_flex() called for RGB = (%hu, %hu, %hu),\n", |
249 | | red, green, blue); |
250 | | #endif |
251 | | |
252 | | /* See the discussion in eprn_map_cmyk_color_flex() below. */ |
253 | |
|
254 | 0 | step = gx_max_color_value/eprn->non_black_levels; |
255 | | |
256 | | /* The order has to be BGR from left to right */ |
257 | 0 | level = blue/step; |
258 | 0 | if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1; |
259 | 0 | value = level << eprn->bits_per_colorant; |
260 | 0 | level = green/step; |
261 | 0 | if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1; |
262 | 0 | value = (value | level) << eprn->bits_per_colorant; |
263 | 0 | level = red/step; |
264 | 0 | if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1; |
265 | 0 | value = (value | level) << eprn->bits_per_colorant; |
266 | |
|
267 | | #ifdef EPRN_TRACE |
268 | | if_debug1(EPRN_TRACE_CHAR, " returning 0x%lX.\n", (unsigned long)value); |
269 | | #endif |
270 | 0 | return value; |
271 | 0 | } |
272 | | |
273 | | /****************************************************************************** |
274 | | |
275 | | Function: eprn_map_rgb_color_for_CMY_or_K_flex |
276 | | |
277 | | This is a flexible 'map_rgb_color' method. It must not be called for the |
278 | | process colour models 'DeviceRGB' and 'DeviceCMYK'. |
279 | | |
280 | | ******************************************************************************/ |
281 | | |
282 | | gx_color_index eprn_map_rgb_color_for_CMY_or_K_flex(gx_device *device, |
283 | | const gx_color_value cv[]) |
284 | 0 | { |
285 | 0 | gx_color_value red = cv[0], green = cv[1], blue = cv[2]; |
286 | 0 | const eprn_Device *dev = (eprn_Device *)device; |
287 | |
|
288 | | #ifdef EPRN_TRACE |
289 | | if_debug3(EPRN_TRACE_CHAR, |
290 | | "! eprn_map_rgb_color_for_CMY_or_K_flex() called for " |
291 | | "RGB = (%hu, %hu, %hu).\n", |
292 | | red, green, blue); |
293 | | #endif |
294 | | |
295 | | /* Treat pure grey levels differently if we have black. This implies that for |
296 | | CMY+K only "true" grey shades will be printed with black ink, all others |
297 | | will be mixed from CMY. */ |
298 | 0 | gx_color_value tmpcv[4]; |
299 | 0 | if (dev->eprn.colour_model != eprn_DeviceCMY && red == green && green == blue) { |
300 | 0 | tmpcv[0] = 0; tmpcv[1] = 0; tmpcv[2] = 0; |
301 | 0 | tmpcv[3] = gx_max_color_value - red; |
302 | 0 | return eprn_map_cmyk_color_flex(device, tmpcv); |
303 | |
|
304 | 0 | } |
305 | 0 | tmpcv[0] = gx_max_color_value - red; |
306 | 0 | tmpcv[1] = gx_max_color_value - green; |
307 | 0 | tmpcv[2] = gx_max_color_value - blue; |
308 | 0 | tmpcv[3] = 0; |
309 | 0 | return eprn_map_cmyk_color_flex(device, tmpcv); |
310 | 0 | } |
311 | | |
312 | | /****************************************************************************** |
313 | | |
314 | | Function: eprn_map_rgb_color_for_RGB_max |
315 | | |
316 | | Colour mapping function for the process colour model 'DeviceRGB' retaining as |
317 | | much information as possible. |
318 | | |
319 | | ******************************************************************************/ |
320 | | |
321 | | gx_color_index eprn_map_rgb_color_for_RGB_max(gx_device *device, |
322 | | const gx_color_value cv[]) |
323 | 0 | { |
324 | 0 | gx_color_value red = cv[0], green = cv[1], blue = cv[2]; |
325 | 0 | gx_color_index value; |
326 | |
|
327 | | #ifdef EPRN_TRACE |
328 | | if_debug3(EPRN_TRACE_CHAR, |
329 | | "! eprn_map_rgb_color_for_RGB_max() called for RGB = (%hu, %hu, %hu),\n", |
330 | | red, green, blue); |
331 | | #endif |
332 | |
|
333 | 0 | value = dominant_8bits(red) << 8; |
334 | 0 | value |= dominant_8bits(green) << 16; |
335 | 0 | value |= dominant_8bits(blue) << 24; |
336 | |
|
337 | | #ifdef EPRN_TRACE |
338 | | if_debug1(EPRN_TRACE_CHAR, " returning 0x%08lX.\n", (unsigned long)value); |
339 | | #endif |
340 | 0 | return value; |
341 | 0 | } |
342 | | |
343 | | /****************************************************************************** |
344 | | |
345 | | Function: eprn_map_rgb_color_for_CMY_or_K_max |
346 | | |
347 | | "Maximal" colour mapping function for the process colour models "DeviceGray", |
348 | | "DeviceCMY", and "CMY+K". |
349 | | |
350 | | ******************************************************************************/ |
351 | | |
352 | | gx_color_index eprn_map_rgb_color_for_CMY_or_K_max(gx_device *device, |
353 | | const gx_color_value cv[]) |
354 | 0 | { |
355 | 0 | gx_color_value red = cv[0], green = cv[1], blue = cv[2]; |
356 | 0 | const eprn_Device *dev = (eprn_Device *)device; |
357 | |
|
358 | | #ifdef EPRN_TRACE |
359 | | if_debug3(EPRN_TRACE_CHAR, |
360 | | "! eprn_map_rgb_color_for_CMY_or_K_max() called for " |
361 | | "RGB = (%hu, %hu, %hu).\n", |
362 | | red, green, blue); |
363 | | #endif |
364 | |
|
365 | 0 | gx_color_value tmpcv[4]; |
366 | 0 | if (dev->eprn.colour_model == eprn_DeviceGray) { |
367 | 0 | tmpcv[0] = 0; tmpcv[1] = 0; tmpcv[2] = 0; |
368 | 0 | tmpcv[3] = gx_max_color_value - red; |
369 | 0 | return eprn_map_cmyk_color_max(device, tmpcv); |
370 | 0 | } |
371 | | /* Note that the conversion from composite black to true black for CMY+K can |
372 | | only happen at the output pixel level, not here. */ |
373 | 0 | tmpcv[0] = gx_max_color_value - red; |
374 | 0 | tmpcv[1] = gx_max_color_value - green; |
375 | 0 | tmpcv[2] = gx_max_color_value - blue; |
376 | 0 | tmpcv[3] = 0; |
377 | 0 | return eprn_map_cmyk_color_max(device, tmpcv); |
378 | 0 | } |
379 | | |
380 | | /****************************************************************************** |
381 | | |
382 | | Function: eprn_map_color_rgb |
383 | | |
384 | | This function is a 'map_color_rgb' method. |
385 | | |
386 | | Such a method should return an RGB triple for the specified 'color'. This is |
387 | | apparently intended for devices supporting colour maps. |
388 | | |
389 | | The function param_HWColorMap() in gsdparam.c tries to compile such a |
390 | | colour map by calling this method repeatedly for all values from 0 to |
391 | | 2^color_info.depth - 1, provided the depth is less than or equal to 8 and |
392 | | the process colour model is not DeviceCMYK. If the function for one of these |
393 | | values returns a negative code, the assumption seems to be that there is no |
394 | | such colour map. Because there is a default method which always returns zero, |
395 | | such a colour map is always constructed if a device does not implement its |
396 | | own 'map_color_rgb' method. This can be seen in the appearance of the |
397 | | "HWColorMap" page device parameter. |
398 | | |
399 | | The key purpose of this function is therefore to return a negative code. |
400 | | |
401 | | ******************************************************************************/ |
402 | | |
403 | | int eprn_map_color_rgb(gx_device *device, gx_color_index color, |
404 | | gx_color_value rgb[3]) |
405 | 0 | { |
406 | | #ifdef EPRN_TRACE |
407 | | if_debug1(EPRN_TRACE_CHAR, |
408 | | "! eprn_map_color_rgb() called for 0x%lX.\n", (unsigned long)color); |
409 | | #endif |
410 | | |
411 | | /* Just to be safe we return defined values (white) */ |
412 | 0 | if (((eprn_Device *)device)->eprn.colour_model == eprn_DeviceRGB) |
413 | 0 | rgb[0] = rgb[1] = rgb[2] = gx_max_color_value; |
414 | 0 | else |
415 | 0 | rgb[0] = rgb[1] = rgb[2] = 0; |
416 | |
|
417 | 0 | return -1; |
418 | 0 | } |
419 | | |
420 | | /****************************************************************************** |
421 | | |
422 | | Function: eprn_map_cmyk_color |
423 | | |
424 | | Colour mapping function for a process colour model of 'DeviceCMYK' with |
425 | | 2 intensity levels for all colorants. |
426 | | |
427 | | ******************************************************************************/ |
428 | | |
429 | | gx_color_index eprn_map_cmyk_color(gx_device *device, |
430 | | const gx_color_value cv[]) |
431 | 0 | { |
432 | 0 | gx_color_value cyan = cv[0], magenta = cv[1], yellow = cv[2], black = cv[3]; |
433 | 0 | gx_color_index value = 0; |
434 | 0 | static const gx_color_value threshold = gx_max_color_value/2; |
435 | |
|
436 | | #ifdef EPRN_TRACE |
437 | | if_debug4(EPRN_TRACE_CHAR, |
438 | | "! eprn_map_cmyk_color() called for CMYK = (%hu, %hu, %hu, %hu),\n", |
439 | | cyan, magenta, yellow, black); |
440 | | #endif |
441 | |
|
442 | 0 | if (cyan > threshold) value |= CYAN_BIT; |
443 | 0 | if (magenta > threshold) value |= MAGENTA_BIT; |
444 | 0 | if (yellow > threshold) value |= YELLOW_BIT; |
445 | 0 | if (black > threshold) value |= BLACK_BIT; |
446 | |
|
447 | | #ifdef EPRN_TRACE |
448 | | if_debug1(EPRN_TRACE_CHAR, " returning 0x%lX.\n", (unsigned long)value); |
449 | | #endif |
450 | 0 | return value; |
451 | 0 | } |
452 | | |
453 | | /****************************************************************************** |
454 | | |
455 | | Function: eprn_map_cmyk_color_flex |
456 | | |
457 | | This is a 'map_cmyk_color' method supporting arbitrary numbers of intensity |
458 | | levels. It may be called for every colour model except DeviceRGB. Colorants |
459 | | not present in the model will be ignored. |
460 | | |
461 | | ******************************************************************************/ |
462 | | |
463 | | gx_color_index eprn_map_cmyk_color_flex(gx_device *device, |
464 | | const gx_color_value cv[]) |
465 | 0 | { |
466 | 0 | gx_color_value cyan = cv[0], magenta = cv[1], yellow = cv[2], black = cv[3]; |
467 | 0 | gx_color_index value = 0; |
468 | 0 | gx_color_value step; |
469 | 0 | gx_color_index level; |
470 | 0 | const eprn_Eprn *eprn = &((eprn_Device *)device)->eprn; |
471 | |
|
472 | | #ifdef EPRN_TRACE |
473 | | if_debug4(EPRN_TRACE_CHAR, |
474 | | "! eprn_map_cmyk_color_flex() called for CMYK = (%hu, %hu, %hu, %hu),\n", |
475 | | cyan, magenta, yellow, black); |
476 | | #endif |
477 | | |
478 | | /* I can think of three linear methods to extract discrete values from a |
479 | | continuous intensity in the range [0, 1]: |
480 | | (a) multiply by the number of levels minus 1 and truncate, |
481 | | (b) multiply by the number of levels minus 1 and round, and |
482 | | (c) multiply by the number of levels and truncate, except for an |
483 | | intensity of 1 in which case one returns the number of levels minus 1. |
484 | | For intensity values which can be represented exactly, i.e., |
485 | | |
486 | | intensity = i/(levels-1) for some non-negative i < levels, |
487 | | |
488 | | these three methods are identical. (a) is however inappropriate here |
489 | | because for less than 32 levels ghostscript already provides intensity |
490 | | values which have been adjusted to a representable level. A rounding |
491 | | error could now result in a level which is too small by one. I prefer (c) |
492 | | because it gives equal shares to all levels. |
493 | | |
494 | | I'm using integer arithmetic here although floating point numbers would |
495 | | be more accurate. This routine may, however, be called quite frequently, |
496 | | and the loss in accuray is acceptable as long as the values determined |
497 | | for 'step' are large compared to the number of levels. If you consider |
498 | | "large" as meaning "10 times as large", the critical boundary is at about |
499 | | 81 levels. The highest number of intensity levels at present supported by |
500 | | HP DeskJets is apparently 4. |
501 | | |
502 | | A more accurate implementation would determine 'step' as a floating point |
503 | | value, divide the intensity by it, and take the floor (entier) of the |
504 | | result as the component intensity. |
505 | | */ |
506 | | |
507 | | /* The order has to be (YMC)(K) from left to right */ |
508 | 0 | if (eprn->colour_model != eprn_DeviceGray) { |
509 | 0 | step = gx_max_color_value/eprn->non_black_levels; |
510 | |
|
511 | 0 | level = yellow/step; |
512 | 0 | if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1; |
513 | 0 | value = level << eprn->bits_per_colorant; |
514 | 0 | level = magenta/step; |
515 | 0 | if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1; |
516 | 0 | value = (value | level) << eprn->bits_per_colorant; |
517 | 0 | level = cyan/step; |
518 | 0 | if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1; |
519 | 0 | value = (value | level) << eprn->bits_per_colorant; |
520 | 0 | } |
521 | 0 | if (eprn->colour_model != eprn_DeviceCMY) { |
522 | 0 | step = gx_max_color_value/eprn->black_levels; |
523 | 0 | level = black/step; |
524 | 0 | if (level >= eprn->black_levels) level = eprn->black_levels - 1; |
525 | 0 | value |= level; |
526 | 0 | } |
527 | |
|
528 | | #ifdef EPRN_TRACE |
529 | | if_debug1(EPRN_TRACE_CHAR, " returning 0x%lX.\n", (unsigned long)value); |
530 | | #endif |
531 | 0 | return value; |
532 | 0 | } |
533 | | |
534 | | /****************************************************************************** |
535 | | |
536 | | Function: eprn_map_cmyk_color_max |
537 | | |
538 | | This is a 'map_cmyk_color' method retaining as much colour information as |
539 | | possible. The reduction to the printer's capabilities must happen in the |
540 | | output routine. |
541 | | |
542 | | ******************************************************************************/ |
543 | | |
544 | | gx_color_index eprn_map_cmyk_color_max(gx_device *device, |
545 | | const gx_color_value cv[]) |
546 | 0 | { |
547 | 0 | gx_color_value cyan = cv[0], magenta = cv[1], yellow = cv[2], black = cv[3]; |
548 | 0 | gx_color_index value; |
549 | |
|
550 | | #ifdef EPRN_TRACE |
551 | | if_debug4(EPRN_TRACE_CHAR, |
552 | | "! eprn_map_cmyk_color_max() called for CMYK = (%hu, %hu, %hu, %hu),\n", |
553 | | cyan, magenta, yellow, black); |
554 | | #endif |
555 | |
|
556 | 0 | value = dominant_8bits(black); |
557 | 0 | value |= dominant_8bits(cyan) << 8; |
558 | 0 | value |= dominant_8bits(magenta) << 16; |
559 | 0 | value |= dominant_8bits(yellow) << 24; |
560 | |
|
561 | | #ifdef EPRN_TRACE |
562 | | if_debug1(EPRN_TRACE_CHAR, " returning 0x%08lX.\n", (unsigned long)value); |
563 | | #endif |
564 | 0 | return value; |
565 | 0 | } |
566 | | |
567 | | /****************************************************************************** |
568 | | |
569 | | Function: eprn_map_cmyk_color_glob |
570 | | |
571 | | Global eprn_map_cmyk_color for all cases handled above used to |
572 | | be able to work together with ghostscript 8.15 and CMYK model. |
573 | | |
574 | | ******************************************************************************/ |
575 | | gx_color_index eprn_map_cmyk_color_glob(gx_device *device, const gx_color_value cv[]) |
576 | 0 | { |
577 | 0 | const eprn_Eprn *eprn = &((eprn_Device *)device)->eprn; |
578 | 0 | if (eprn->intensity_rendering == eprn_IR_FloydSteinberg) |
579 | 0 | return eprn_map_cmyk_color_max(device, cv); |
580 | 0 | else if (device->color_info.max_gray > 1 || device->color_info.max_color > 1) |
581 | 0 | return eprn_map_cmyk_color_flex(device, cv); |
582 | 0 | else |
583 | 0 | return eprn_map_cmyk_color(device, cv); |
584 | 0 | } |
585 | | |
586 | | /****************************************************************************** |
587 | | |
588 | | Function: eprn_finalize |
589 | | |
590 | | This function fills the last octet in a set of bit planes with white if |
591 | | needed and sets the lengths of all these planes. |
592 | | |
593 | | 'is_RGB' denotes whether the colour model is eprn_DeviceRGB, |
594 | | 'non_black_levels' is the number of intensity levels for non-black colorants, |
595 | | 'planes' the number of bit planes, |
596 | | 'plane' points to an array of at least 'planes' bit planes, |
597 | | 'ptr' points to an array of at least 'planes' pointers into the bit planes, |
598 | | 'pixels' is the number of pixels written to the group of bit planes. |
599 | | |
600 | | If 'pixels' is divisible by 8, the 'ptr' pointers point to octets after |
601 | | the last completely written octets. Otherwise, they point to the last |
602 | | incompletely written octet in which the pixels written so far occupy the |
603 | | least significant bits. |
604 | | |
605 | | ******************************************************************************/ |
606 | | |
607 | | void eprn_finalize(bool is_RGB, unsigned int non_black_levels, |
608 | | int planes, eprn_OctetString *plane, eprn_Octet **ptr, int pixels) |
609 | 0 | { |
610 | 0 | int j; |
611 | | |
612 | | /* Execute remaining left shifts in the last octet of the output planes when |
613 | | the number of pixels is not a multiple of 8, and fill with white on the |
614 | | right */ |
615 | 0 | if (pixels % 8 != 0) { |
616 | 0 | int shift = 8 - pixels % 8; |
617 | |
|
618 | 0 | if (is_RGB) { |
619 | | /* White may be any intensity, but it's the same for all three colorants, |
620 | | and it's the highest. */ |
621 | 0 | eprn_Octet imax = non_black_levels - 1; |
622 | 0 | int c, rgb_planes = eprn_bits_for_levels(non_black_levels); |
623 | |
|
624 | 0 | j = 0; /* next output plane */ |
625 | | |
626 | | /* Loop over RGB */ |
627 | 0 | for (c = 0; c < 3; c++) { |
628 | 0 | eprn_Octet value = imax; |
629 | 0 | int m; |
630 | | |
631 | | /* Loop over all planes for this colorant */ |
632 | 0 | for (m = 0; m < rgb_planes; m++, j++) { |
633 | 0 | eprn_Octet bit = value & 1; |
634 | 0 | int p; |
635 | |
|
636 | 0 | value = value >> 1; |
637 | | |
638 | | /* Put the bit into all remaining pixels for this plane */ |
639 | 0 | for (p = 0; p < shift; p++) |
640 | 0 | *ptr[j] = (*ptr[j] << 1) | bit; |
641 | 0 | } |
642 | 0 | } |
643 | 0 | } |
644 | 0 | else /* White is zero */ |
645 | 0 | for (j = 0; j < planes; j++) |
646 | 0 | *ptr[j] = *ptr[j] << shift; |
647 | | |
648 | | /* Advance all plane pointers by 1 */ |
649 | 0 | for (j = 0; j < planes; j++) ptr[j]++; |
650 | 0 | } |
651 | | |
652 | | /* Set the lengths of the bit plane strings */ |
653 | 0 | for (j = 0; j < planes; j++) { |
654 | 0 | if (pixels == 0) plane[j].length = 0; |
655 | 0 | else plane[j].length = ptr[j] - plane[j].str; |
656 | 0 | } |
657 | |
|
658 | 0 | return; |
659 | 0 | } |
660 | | |
661 | | /****************************************************************************** |
662 | | |
663 | | Function: split_line_le8 |
664 | | |
665 | | This is the first of the "split_line implementations". See the body of |
666 | | eprn_get_planes() for the calling conventions common to them. |
667 | | |
668 | | This particular implementation has the following restrictions: |
669 | | - The pixmap depth must be a divisor of 8. |
670 | | |
671 | | ******************************************************************************/ |
672 | | |
673 | | static void split_line_le8(eprn_Device *dev, const eprn_Octet *line, |
674 | | int length, eprn_OctetString plane[]) |
675 | 0 | { |
676 | 0 | gx_color_index |
677 | 0 | pixel; |
678 | 0 | int |
679 | 0 | black_planes, /* number of planes to send for black */ |
680 | 0 | non_black_planes, /* number of planes to send for each of CMY/RGB */ |
681 | 0 | j, |
682 | 0 | k, |
683 | 0 | pixels, /* number of pixels transferred to bit planes */ |
684 | 0 | planes; /* number of planes to send */ |
685 | 0 | eprn_Octet |
686 | 0 | comp_mask = 0, /* 'bits_per_component' 1s in the lowest part */ |
687 | 0 | pixel_mask = 0, /* 'depth' 1s in the lowest part */ |
688 | 0 | *ptr[8]; /* pointers into planes (next octet to write to) */ |
689 | | |
690 | | /* Number of planes to send */ |
691 | 0 | black_planes = eprn_bits_for_levels(dev->eprn.black_levels); |
692 | 0 | non_black_planes = eprn_bits_for_levels(dev->eprn.non_black_levels); |
693 | 0 | planes = black_planes + 3*non_black_planes; |
694 | | |
695 | | /* Initialize the bit plane pointers */ |
696 | 0 | for (j = 0; j < planes; j++) ptr[j] = plane[j].str; |
697 | | |
698 | | /* Determine some bit masks */ |
699 | 0 | for (j = 0; j < dev->color_info.depth; j++) |
700 | 0 | pixel_mask = (pixel_mask << 1) | 1; |
701 | 0 | for (j = 0; j < dev->eprn.bits_per_colorant; j++) |
702 | 0 | comp_mask = (comp_mask << 1) | 1; |
703 | | |
704 | | /* Copy from 'line' to 'plane[]', converting Z format to XY format */ |
705 | 0 | pixels = 0; |
706 | 0 | k = 0; /* Next octet index in the input line */ |
707 | 0 | while (k < length) { |
708 | 0 | int l, m, p; |
709 | | |
710 | | /* Initialize plane storage if it's a new output octet */ |
711 | 0 | if (pixels % 8 == 0) for (j = 0; j < planes; j++) *ptr[j] = 0; |
712 | | |
713 | | /* Loop over pixels within the input octet, starting at the leftmost |
714 | | pixel (highest-order bits) */ |
715 | 0 | p = 8/dev->color_info.depth - 1; |
716 | 0 | do { |
717 | 0 | eprn_Octet comp; |
718 | | |
719 | | /* Extract pixel */ |
720 | 0 | pixel = (line[k] >> p*dev->color_info.depth) & pixel_mask; |
721 | | |
722 | | /* Extract components from the pixel and distribute each over its planes |
723 | | */ |
724 | 0 | comp = pixel & comp_mask; /* black */ |
725 | 0 | for (j = 0; j < black_planes; j++) { |
726 | 0 | *ptr[j] = (*ptr[j] << 1) | (comp & 1); |
727 | 0 | comp >>= 1; |
728 | 0 | } |
729 | 0 | if (non_black_planes > 0) for (l = 1; l < 4; l++) { |
730 | 0 | comp = (pixel >> l*dev->eprn.bits_per_colorant) & comp_mask; |
731 | 0 | for (m = 0; m < non_black_planes; m++, j++) { |
732 | 0 | *ptr[j] = (*ptr[j] << 1) | (comp & 1); |
733 | 0 | comp >>= 1; |
734 | 0 | } |
735 | 0 | } |
736 | |
|
737 | 0 | pixels++; |
738 | 0 | p--; |
739 | 0 | } while (p >= 0); |
740 | 0 | k++; |
741 | | |
742 | | /* Increase plane pointers if an output octet boundary has been reached */ |
743 | 0 | if (pixels % 8 == 0) for (j = 0; j < planes; j++) ptr[j]++; |
744 | 0 | } |
745 | |
|
746 | 0 | eprn_finalize(dev->eprn.colour_model == eprn_DeviceRGB, |
747 | 0 | dev->eprn.non_black_levels, planes, plane, ptr, pixels); |
748 | |
|
749 | 0 | return; |
750 | 0 | } |
751 | | |
752 | | /****************************************************************************** |
753 | | |
754 | | Function: split_line_ge8 |
755 | | |
756 | | This split_line function has the following restrictions: |
757 | | - The pixmap depth must be a multiple of 8. |
758 | | - There may be at most 8 bits per colorant. |
759 | | (Hence the depth is at most 32.) |
760 | | - 'length' must be divisible by depth/8. |
761 | | |
762 | | ******************************************************************************/ |
763 | | |
764 | | static void split_line_ge8(eprn_Device *dev, const eprn_Octet *line, |
765 | | int length, eprn_OctetString plane[]) |
766 | 0 | { |
767 | 0 | gx_color_index |
768 | 0 | pixel; |
769 | 0 | int |
770 | 0 | black_planes, /* number of planes to send for black */ |
771 | 0 | non_black_planes, /* number of planes to send for each of CMY/RGB */ |
772 | 0 | j, |
773 | 0 | k, |
774 | 0 | octets_per_pixel = dev->color_info.depth/8, |
775 | 0 | pixels, /* number of pixels transferred to bit planes */ |
776 | 0 | planes; /* number of planes to send */ |
777 | 0 | eprn_Octet |
778 | 0 | comp_mask = 0, /* bits_per_component 1s in the lowest part */ |
779 | 0 | *ptr[32]; /* pointers into planes (next octet to write to) */ |
780 | | |
781 | | /* Number of planes to send */ |
782 | 0 | black_planes = eprn_bits_for_levels(dev->eprn.black_levels); |
783 | 0 | non_black_planes = eprn_bits_for_levels(dev->eprn.non_black_levels); |
784 | 0 | planes = black_planes + 3*non_black_planes; |
785 | | |
786 | | /* Initialize the bit plane pointers */ |
787 | 0 | for (j = 0; j < planes; j++) ptr[j] = plane[j].str; |
788 | | |
789 | | /* Determine the component mask */ |
790 | 0 | for (j = 0; j < dev->eprn.bits_per_colorant; j++) |
791 | 0 | comp_mask = (comp_mask << 1) | 1; |
792 | | |
793 | | /* Copy from 'line' to 'plane[]', converting Z format to XY format */ |
794 | 0 | pixels = 0; |
795 | 0 | k = 0; /* Next octet index in the input line */ |
796 | 0 | while (k < length) { |
797 | 0 | eprn_Octet comp; |
798 | 0 | int l, m; |
799 | | |
800 | | /* Initialize plane storage if it's a new octet */ |
801 | 0 | if (pixels % 8 == 0) for (j = 0; j < planes; j++) *ptr[j] = 0; |
802 | | |
803 | | /* Reconstruct pixel from several octets */ |
804 | 0 | j = 0; |
805 | 0 | pixel = line[k]; |
806 | 0 | do { |
807 | 0 | j++; k++; |
808 | 0 | if (j >= octets_per_pixel) break; |
809 | 0 | pixel = (pixel << 8) | line[k]; /* MSB (Big Endian) */ |
810 | 0 | } while (1); |
811 | | |
812 | | /* Split and distribute over planes */ |
813 | 0 | comp = pixel & comp_mask; /* black */ |
814 | 0 | for (j = 0; j < black_planes; j++) { |
815 | 0 | *ptr[j] = (*ptr[j] << 1) | (comp & 1); |
816 | 0 | comp >>= 1; |
817 | 0 | } |
818 | 0 | for (l = 1; l < 4; l++) { |
819 | 0 | comp = (pixel >> l*dev->eprn.bits_per_colorant) & comp_mask; |
820 | 0 | for (m = 0; m < non_black_planes; m++, j++) { |
821 | 0 | *ptr[j] = (*ptr[j] << 1) | (comp & 1); |
822 | 0 | comp >>= 1; |
823 | 0 | } |
824 | 0 | } |
825 | |
|
826 | 0 | pixels++; |
827 | | |
828 | | /* Increase plane pointers if an octet boundary has been reached */ |
829 | 0 | if (pixels % 8 == 0) for (j = 0; j < planes; j++) ptr[j]++; |
830 | 0 | } |
831 | |
|
832 | 0 | eprn_finalize(dev->eprn.colour_model == eprn_DeviceRGB, |
833 | 0 | dev->eprn.non_black_levels, planes, plane, ptr, pixels); |
834 | |
|
835 | 0 | return; |
836 | 0 | } |
837 | | |
838 | | /****************************************************************************** |
839 | | |
840 | | Function: split_line_3or4x1 |
841 | | |
842 | | This function is a split_line() implementation for a non-monochrome colour |
843 | | model (3 or 4 components) with 1 bit per component. |
844 | | |
845 | | ******************************************************************************/ |
846 | | |
847 | | static void split_line_3or4x1(eprn_Device *dev, const eprn_Octet *line, |
848 | | int length, eprn_OctetString plane[]) |
849 | 0 | { |
850 | 0 | int |
851 | 0 | from = (dev->eprn.colour_model == eprn_DeviceRGB || |
852 | 0 | dev->eprn.colour_model == eprn_DeviceCMY? 1: 0), |
853 | 0 | j, |
854 | 0 | k, |
855 | 0 | l; |
856 | 0 | eprn_Octet *ptr[4]; /* pointers into planes, indexed KCMY/-RGB */ |
857 | |
|
858 | 0 | ptr[0] = NULL; /* defensive programming */ |
859 | 0 | for (j = from; j < 4; j++) ptr[j] = plane[j-from].str; |
860 | | |
861 | | /* Loop over the input line, taking four octets (8 pixels) at a time, as far |
862 | | as available, and split them into four output octets, one for each |
863 | | colorant. |
864 | | */ |
865 | 0 | k = 0; |
866 | 0 | while (k < length) { |
867 | 0 | eprn_Octet octet[4] = {0, 0, 0, 0}; |
868 | |
|
869 | 0 | for (l = 0; l < 4 && k < length; l++, k++) { |
870 | 0 | eprn_Octet part; |
871 | 0 | #define treat_quartet() \ |
872 | 0 | octet[COLORANT_0_INDEX] <<= 1; \ |
873 | 0 | if (part & COLORANT_0_BIT) octet[COLORANT_0_INDEX] |= 1; \ |
874 | 0 | octet[COLORANT_1_INDEX] <<= 1; \ |
875 | 0 | if (part & COLORANT_1_BIT) octet[COLORANT_1_INDEX] |= 1; \ |
876 | 0 | octet[COLORANT_2_INDEX] <<= 1; \ |
877 | 0 | if (part & COLORANT_2_BIT) octet[COLORANT_2_INDEX] |= 1; \ |
878 | 0 | octet[COLORANT_3_INDEX] <<= 1; \ |
879 | 0 | if (part & COLORANT_3_BIT) octet[COLORANT_3_INDEX] |= 1; |
880 | | |
881 | | /* Upper four bits */ |
882 | 0 | part = (line[k] >> 4) & 0x0F; |
883 | 0 | treat_quartet() |
884 | | |
885 | | /* Lower four bits */ |
886 | 0 | part = line[k] & 0x0F; |
887 | 0 | treat_quartet() |
888 | |
|
889 | 0 | #undef treat_quartet |
890 | 0 | } |
891 | 0 | if (l < 4) { |
892 | 0 | for (j = from; j < 4; j++) octet[j] <<= 8 - 2*l; |
893 | 0 | if (dev->eprn.colour_model == eprn_DeviceRGB) { |
894 | | /* Add white in the last 8 - 2*l pixels */ |
895 | 0 | for (j = 1; j < 4; j++) { |
896 | 0 | int k; |
897 | | /* We add two pixels at a time */ |
898 | 0 | for (k = 3 - l; k >= 0; k--) octet[j] |= 0x03 << k; |
899 | 0 | } |
900 | 0 | } |
901 | 0 | } |
902 | 0 | for (j = from; j < 4; j++) *(ptr[j]++) = octet[j]; |
903 | 0 | } |
904 | | |
905 | | /* Set the lengths of the bit plane strings */ |
906 | 0 | for (j = 0; j < dev->eprn.output_planes; j++) { |
907 | 0 | if (length == 0) plane[j].length = 0; |
908 | 0 | else plane[j].length = ptr[from + j] - plane[j].str; |
909 | 0 | } |
910 | |
|
911 | 0 | return; |
912 | 0 | } |
913 | | |
914 | | /****************************************************************************** |
915 | | |
916 | | Function: split_line_4x2 |
917 | | |
918 | | This is a split_line() implementation for 4 colour components (i.e., CMYK) |
919 | | with 3 or 4 levels each (2 bit planes to send for each component). |
920 | | |
921 | | ******************************************************************************/ |
922 | | |
923 | | static void split_line_4x2(eprn_Device *dev, const eprn_Octet *line, |
924 | | int length, eprn_OctetString plane[]) |
925 | 0 | { |
926 | 0 | gx_color_index |
927 | 0 | pixel; |
928 | 0 | int |
929 | 0 | j, |
930 | 0 | k; |
931 | 0 | eprn_Octet |
932 | 0 | *ptr[8]; /* pointers into planes (next octet to write to) */ |
933 | | |
934 | | /* Initialize the bit plane pointers */ |
935 | 0 | for (j = 0; j < 8; j++) ptr[j] = plane[j].str; |
936 | | |
937 | | /* Copy from 'line' to 'plane[]', converting Z format to XY format */ |
938 | 0 | for (k = 0; k < length; k++) { |
939 | | /* k is the index of the next octet in the input line and the number of |
940 | | pixels processed so far. */ |
941 | | |
942 | | /* Initialize plane storage if it's a new octet */ |
943 | 0 | if (k % 8 == 0) for (j = 0; j < 8; j++) *ptr[j] = 0; |
944 | | |
945 | | /* Fetch pixel */ |
946 | 0 | pixel = line[k]; |
947 | | |
948 | | /* Split and distribute over planes */ |
949 | 0 | *ptr[0] = (*ptr[0] << 1) | (pixel & 0x01); |
950 | 0 | #define assign_bit(index) \ |
951 | 0 | *ptr[index] = (*ptr[index] << 1) | ((pixel >> index) & 0x01) |
952 | 0 | assign_bit(1); |
953 | 0 | assign_bit(2); |
954 | 0 | assign_bit(3); |
955 | 0 | assign_bit(4); |
956 | 0 | assign_bit(5); |
957 | 0 | assign_bit(6); |
958 | 0 | assign_bit(7); |
959 | 0 | #undef assign_bit |
960 | | |
961 | | /* Increase plane pointers if an output octet boundary has been reached */ |
962 | 0 | if (k % 8 == 7) for (j = 0; j < 8; j++) ptr[j]++; |
963 | 0 | } |
964 | | |
965 | | /* Execute remaining left shifts in the last octet of the output planes when |
966 | | the number of pixels is not a multiple of 8 */ |
967 | 0 | k = length % 8; |
968 | 0 | if (k != 0) { |
969 | 0 | int shift = 8 - k; |
970 | 0 | for (j = 0; j < 8; j++) |
971 | 0 | *(ptr[j]++) <<= shift; |
972 | 0 | } |
973 | | |
974 | | /* Set the lengths of the bit plane strings */ |
975 | 0 | for (j = 0; j < 8; j++) { |
976 | 0 | if (length == 0) plane[j].length = 0; |
977 | 0 | else plane[j].length = ptr[j] - plane[j].str; |
978 | 0 | } |
979 | |
|
980 | 0 | return; |
981 | 0 | } |
982 | | |
983 | | /****************************************************************************** |
984 | | |
985 | | Function: eprn_fetch_scan_line |
986 | | |
987 | | If there is a next scan line with y coordinate 'dev->eprn.next_y', this |
988 | | function fetches it into '*line' and returns zero. Otherwise the function |
989 | | returns a non-zero value. |
990 | | |
991 | | The storage allocated for 'line->str' must be at least of size |
992 | | 'dev->eprn.octets_per_line'. |
993 | | |
994 | | On success, the 'length' field in 'line' does not include trailing zero |
995 | | pixels. |
996 | | |
997 | | ******************************************************************************/ |
998 | | |
999 | | int eprn_fetch_scan_line(eprn_Device *dev, eprn_OctetString *line) |
1000 | 0 | { |
1001 | 0 | int rc; |
1002 | 0 | const eprn_Octet *str; |
1003 | |
|
1004 | 0 | rc = gdev_prn_copy_scan_lines((gx_device_printer *)dev, dev->eprn.next_y, |
1005 | 0 | line->str, dev->eprn.octets_per_line); |
1006 | | /* gdev_prn_copy_scan_lines() returns the number of scan lines it fetched |
1007 | | or a negative value on error. The number of lines to fetch is the value |
1008 | | of the last argument divided by the length of a single line, hence in |
1009 | | this case 1. */ |
1010 | 0 | if (rc != 1) return 1; |
1011 | | |
1012 | | /* Set the length to ignore trailing zero octets in the scan line */ |
1013 | 0 | str = line->str + (dev->eprn.octets_per_line - 1); |
1014 | 0 | while (str > line->str && *str == 0) str--; |
1015 | 0 | if (*str == 0) line->length = 0; |
1016 | 0 | else line->length = str - line->str + 1; |
1017 | | |
1018 | | /* Ensure we have an integral number of pixels in the line */ |
1019 | 0 | if (dev->color_info.depth > 8) { |
1020 | 0 | int rem; |
1021 | 0 | unsigned int octets_per_pixel = dev->color_info.depth/8; |
1022 | | /* If the depth is larger than 8, it is a multiple of 8. */ |
1023 | 0 | rem = line->length % octets_per_pixel; |
1024 | 0 | if (rem != 0) line->length += octets_per_pixel - rem; |
1025 | 0 | } |
1026 | |
|
1027 | | #if 0 && defined(EPRN_TRACE) |
1028 | | if (gs_debug_c(EPRN_TRACE_CHAR)) { |
1029 | | int j; |
1030 | | dmlprintf(dev->memory, "! eprn_fetch_scan_line(): Fetched "); |
1031 | | if (line->length == 0) dmprintf(dev->memory, "empty scan line."); |
1032 | | else { |
1033 | | dmprintf(dev->memory, "scan line: 0x"); |
1034 | | for (j = 0; j < line->length; j++) dmprintf1(dev->memory, "%02X", line->str[j]); |
1035 | | } |
1036 | | dmlprintf(dev->memory, "\n"); |
1037 | | } |
1038 | | #endif |
1039 | |
|
1040 | 0 | return 0; |
1041 | 0 | } |
1042 | | |
1043 | | /****************************************************************************** |
1044 | | |
1045 | | Function: eprn_get_planes |
1046 | | |
1047 | | For the description of this function, see gdeveprn.h. |
1048 | | |
1049 | | ******************************************************************************/ |
1050 | | |
1051 | | int eprn_get_planes(eprn_Device *dev, eprn_OctetString bitplanes[]) |
1052 | 0 | { |
1053 | 0 | eprn_OctetString *line; /* where to copy the scan line from the prn device */ |
1054 | 0 | int |
1055 | 0 | j, |
1056 | 0 | rc; |
1057 | | |
1058 | | /* Avoid a copying step for a depth of 1 */ |
1059 | 0 | if (dev->color_info.depth == 1) line = bitplanes; |
1060 | 0 | else line = &dev->eprn.scan_line; |
1061 | | |
1062 | | /* Fetch the scan line if available */ |
1063 | 0 | if (dev->eprn.intensity_rendering == eprn_IR_FloydSteinberg && |
1064 | 0 | dev->eprn.next_y == 0) return 1; |
1065 | 0 | rc = eprn_fetch_scan_line(dev, line); |
1066 | 0 | if (rc == 0) dev->eprn.next_y++; |
1067 | 0 | else { |
1068 | 0 | if (dev->eprn.intensity_rendering != eprn_IR_FloydSteinberg) return 1; |
1069 | 0 | dev->eprn.next_y = 0; |
1070 | 0 | } |
1071 | | |
1072 | 0 | if (dev->color_info.depth == 1) return 0; |
1073 | | |
1074 | 0 | if (dev->eprn.intensity_rendering == eprn_IR_FloydSteinberg) { |
1075 | 0 | eprn_OctetString tmp; |
1076 | |
|
1077 | 0 | eprn_split_FS(&dev->eprn.next_scan_line, &dev->eprn.scan_line, |
1078 | 0 | dev->eprn.octets_per_line, |
1079 | 0 | dev->eprn.colour_model, |
1080 | 0 | dev->eprn.black_levels, dev->eprn.non_black_levels, |
1081 | 0 | bitplanes); |
1082 | | |
1083 | | /* Switch 'next_scan_line' to refer to what is currently 'scan_line' */ |
1084 | 0 | tmp = dev->eprn.next_scan_line; |
1085 | 0 | dev->eprn.next_scan_line = dev->eprn.scan_line; |
1086 | 0 | dev->eprn.scan_line = tmp; |
1087 | 0 | } |
1088 | 0 | else { |
1089 | | /* Here we split multi-bit pixels which are already adapted to the |
1090 | | printer's capabilities. |
1091 | | |
1092 | | All the functions called here have the following signature: |
1093 | | |
1094 | | static void split_line...(eprn_Device *dev, const eprn_Octet *line, |
1095 | | int length, eprn_OctetString plane[]) |
1096 | | |
1097 | | Such a "split_line implementation" must take the scan line of length |
1098 | | 'length', pointed to by 'line', split it into bit planes according to |
1099 | | the state of 'dev', and return these planes via 'plane'. The length |
1100 | | fields of the planes must be set. Trailing zero octets should not be |
1101 | | removed because it's done here afterwards anyway. |
1102 | | */ |
1103 | |
|
1104 | 0 | if (dev->eprn.colour_model == eprn_DeviceGray) |
1105 | 0 | split_line_le8(dev, line->str, line->length, bitplanes); |
1106 | 0 | else { |
1107 | 0 | if (dev->eprn.bits_per_colorant == 1) { |
1108 | 0 | #ifndef EPRN_TRAILING_BIT_BUG_FIXED |
1109 | 0 | if (dev->eprn.colour_model == eprn_DeviceRGB && |
1110 | 0 | line->length == dev->eprn.octets_per_line) { |
1111 | | /* At least gs 6.01 and 6.50 sometimes generate pixel lines where the |
1112 | | last pixel is not white but black (last octet in 'line' is 0xE0 |
1113 | | instead of 0xEE; with pcl3 it shows up for A6 and A4, but not for |
1114 | | A3, A5, US Letter, or US Legal). |
1115 | | I'm overwriting it with white. */ |
1116 | | #ifdef EPRN_TRACE |
1117 | | if (gs_debug_c(EPRN_TRACE_CHAR)) { |
1118 | | static bool already_noted = false; |
1119 | | if (!already_noted && line->str[line->length - 1] != 0xEE) { |
1120 | | dmlprintf1(dev->memory, "! eprn_get_planes(): " |
1121 | | "Line-terminating octet is 0x%02X.\n", |
1122 | | line->str[line->length - 1]); |
1123 | | already_noted = true; |
1124 | | } |
1125 | | } |
1126 | | #endif /* EPRN_TRACE */ |
1127 | 0 | line->str[line->length - 1] |= RED_BIT | GREEN_BIT | BLUE_BIT; |
1128 | 0 | } |
1129 | 0 | #endif /* EPRN_TRAILING_BIT_BUG_FIXED */ |
1130 | 0 | split_line_3or4x1(dev, line->str, line->length, bitplanes); |
1131 | 0 | } |
1132 | 0 | else if (dev->eprn.bits_per_colorant == 2 && dev->eprn.black_levels > 2 && |
1133 | 0 | dev->eprn.non_black_levels > 2) |
1134 | 0 | split_line_4x2(dev, line->str, line->length, bitplanes); |
1135 | 0 | else if (dev->color_info.depth < 8) |
1136 | 0 | split_line_le8(dev, line->str, line->length, bitplanes); |
1137 | 0 | else split_line_ge8(dev, line->str, line->length, bitplanes); |
1138 | 0 | } |
1139 | 0 | } |
1140 | | |
1141 | | /* Reduce the lengths of the individual bit planes to not include trailing |
1142 | | zero octets */ |
1143 | 0 | for (j = 0; j < dev->eprn.output_planes; j++) { |
1144 | 0 | if (bitplanes[j].length > 0) { |
1145 | 0 | const eprn_Octet *str = bitplanes[j].str + (bitplanes[j].length - 1); |
1146 | 0 | while (str > bitplanes[j].str && *str == 0) str--; |
1147 | 0 | if (*str == 0) bitplanes[j].length = 0; |
1148 | 0 | else bitplanes[j].length = (str - bitplanes[j].str) + 1; |
1149 | 0 | } |
1150 | 0 | } |
1151 | |
|
1152 | 0 | return 0; |
1153 | 0 | } |