1 /* Copyright (C) 1992, 2000 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gdevpcl.c,v 1.8 2002/08/22 07:12:28 henrys Exp $ */
18 /* Utilities for PCL printers */
19 #include "gdevprn.h"
20 #include "gdevpcl.h"
21 #include "math_.h"
22
23 /* ------ Get paper size ------ */
24
25 /* Get the paper size code, based on width and height. */
26 int
gdev_pcl_paper_size(gx_device * dev)27 gdev_pcl_paper_size(gx_device * dev)
28 {
29 float width_inches = dev->width / dev->x_pixels_per_inch;
30 float height_inches = dev->height / dev->y_pixels_per_inch;
31 /* The initial value for height_difference, and for code below, is
32 unnecessary and is here just to stop the compiler from
33 complaining about a possible uninitialized variable usage. */
34 float width_difference = -1.0, height_difference = -1.0;
35 float new_width_difference, new_height_difference;
36 int code = PAPER_SIZE_LETTER;
37
38 /* Since we're telling the printer when to eject and start a new
39 page, the paper height doesn't matter a great deal, as long as
40 we ensure that it's at least as high as we want our pages to
41 be. However, the paper width is important, because on printers
42 which center the paper in the input tray, having the wrong
43 width will cause the image to appear in the wrong place on the
44 paper (perhaps even partially missing the paper completely).
45 Therefore, we choose our paper size by finding one whose width
46 and height are both equal to or greater than the desired width
47 and height and whose width is the closest to what we want. We
48 only pay close attention to the height when the widths of two
49 different paper sizes are equal.
50
51 We use "foo - bar > -0.01" instead of "foo >= bar" to avoid
52 minor floating point and rounding errors.
53 */
54 #define CHECK_PAPER_SIZE(w,h,c) \
55 new_width_difference = w - width_inches; \
56 new_height_difference = h - height_inches; \
57 if ((new_width_difference > -0.01) && (new_height_difference > -0.01) && \
58 ((width_difference == -1.0) || \
59 (new_width_difference < width_difference) || \
60 ((new_width_difference == width_difference) && \
61 (new_height_difference < height_difference)))) { \
62 width_difference = new_width_difference; \
63 height_difference = new_height_difference; \
64 code = c; \
65 }
66
67 CHECK_PAPER_SIZE( 7.25, 10.5, PAPER_SIZE_EXECUTIVE);
68 CHECK_PAPER_SIZE( 8.5 , 11.0, PAPER_SIZE_LETTER);
69 CHECK_PAPER_SIZE( 8.5 , 14.0, PAPER_SIZE_LEGAL);
70 CHECK_PAPER_SIZE(11.0 , 17.0, PAPER_SIZE_LEDGER);
71 CHECK_PAPER_SIZE( 8.27, 11.69, PAPER_SIZE_A4);
72 CHECK_PAPER_SIZE(11.69, 16.54, PAPER_SIZE_A3);
73 CHECK_PAPER_SIZE(16.54, 23.39, PAPER_SIZE_A2);
74 CHECK_PAPER_SIZE(23.39, 33.11, PAPER_SIZE_A1);
75 CHECK_PAPER_SIZE(33.11, 46.81, PAPER_SIZE_A0);
76 CHECK_PAPER_SIZE( 7.16, 10.12, PAPER_SIZE_JIS_B5);
77 CHECK_PAPER_SIZE(10.12, 14.33, PAPER_SIZE_JIS_B4);
78 CHECK_PAPER_SIZE( 3.94, 5.83, PAPER_SIZE_JPOST);
79 CHECK_PAPER_SIZE( 5.83, 7.87, PAPER_SIZE_JPOSTD);
80 CHECK_PAPER_SIZE( 3.87, 7.5 , PAPER_SIZE_MONARCH);
81 CHECK_PAPER_SIZE( 4.12, 9.5 , PAPER_SIZE_COM10);
82 CHECK_PAPER_SIZE( 4.33, 8.66, PAPER_SIZE_DL);
83 CHECK_PAPER_SIZE( 6.38, 9.01, PAPER_SIZE_C5);
84 CHECK_PAPER_SIZE( 6.93, 9.84, PAPER_SIZE_B5);
85
86 #undef CHECK_PAPER_SIZE
87
88 return code;
89 }
90
91 /* ------ Color mapping ------ */
92
93 /* The PaintJet and DeskJet 500C use additive colors in separate planes. */
94 /* We only keep one bit of color, with 1 = R, 2 = G, 4 = B. */
95 /* Because the buffering routines assume 0 = white, */
96 /* we complement all the color components. */
97 #define cv_shift (sizeof(gx_color_value) * 8 - 1)
98
99 /* Map an RGB color to a printer color. */
100 gx_color_index
gdev_pcl_3bit_map_rgb_color(gx_device * dev,const gx_color_value cv[])101 gdev_pcl_3bit_map_rgb_color(gx_device * dev, const gx_color_value cv[])
102 {
103 gx_color_value r, g, b;
104 r = cv[0]; g = cv[1]; b = cv[2];
105 return (((b >> cv_shift) << 2) + ((g >> cv_shift) << 1) + (r >> cv_shift)) ^ 7;
106 }
107
108 /* Map the printer color back to RGB. */
109 int
gdev_pcl_3bit_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])110 gdev_pcl_3bit_map_color_rgb(gx_device * dev, gx_color_index color,
111 gx_color_value prgb[3])
112 {
113 ushort cc = (ushort) color ^ 7;
114
115 prgb[0] = -(cc & 1);
116 prgb[1] = -((cc >> 1) & 1);
117 prgb[2] = -(cc >> 2);
118 return 0;
119 }
120
121 /* ------ Compression ------ */
122
123 /*
124 * Mode 2 Row compression routine for the HP DeskJet & LaserJet IIp.
125 * Compresses data from row up to end_row, storing the result
126 * starting at compressed. Returns the number of bytes stored.
127 * Runs of K<=127 literal bytes are encoded as K-1 followed by
128 * the bytes; runs of 2<=K<=127 identical bytes are encoded as
129 * 257-K followed by the byte.
130 * In the worst case, the result is N+(N/127)+1 bytes long,
131 * where N is the original byte count (end_row - row).
132 * To speed up the search, we examine an entire word at a time.
133 * We will miss a few blocks of identical bytes; tant pis.
134 */
135 int
gdev_pcl_mode2compress_padded(const word * row,const word * end_row,byte * compressed,bool pad)136 gdev_pcl_mode2compress_padded(const word * row, const word * end_row,
137 byte * compressed, bool pad)
138 {
139 register const word *exam = row; /* word being examined in the row to compress */
140 register byte *cptr = compressed; /* output pointer into compressed bytes */
141
142 while (exam < end_row) { /* Search ahead in the input looking for a run */
143 /* of at least 4 identical bytes. */
144 const byte *compr = (const byte *)exam;
145 const byte *end_dis;
146 const word *next;
147 register word test = *exam;
148
149 while (((test << 8) ^ test) > 0xff) {
150 if (++exam >= end_row)
151 break;
152 test = *exam;
153 }
154
155 /* Find out how long the run is */
156 end_dis = (const byte *)exam;
157 if (exam == end_row) { /* no run */
158 /* See if any of the last 3 "dissimilar" bytes are 0. */
159 if (!pad && end_dis > compr && end_dis[-1] == 0) {
160 if (end_dis[-2] != 0)
161 end_dis--;
162 else if (end_dis[-3] != 0)
163 end_dis -= 2;
164 else
165 end_dis -= 3;
166 }
167 next = --end_row;
168 } else {
169 next = exam + 1;
170 while (next < end_row && *next == test)
171 next++;
172 /* See if any of the last 3 "dissimilar" bytes */
173 /* are the same as the repeated byte. */
174 if (end_dis > compr && end_dis[-1] == (byte) test) {
175 if (end_dis[-2] != (byte) test)
176 end_dis--;
177 else if (end_dis[-3] != (byte) test)
178 end_dis -= 2;
179 else
180 end_dis -= 3;
181 }
182 }
183
184 /* Now [compr..end_dis) should be encoded as dissimilar, */
185 /* and [end_dis..next) should be encoded as similar. */
186 /* Note that either of these ranges may be empty. */
187
188 for (;;) { /* Encode up to 127 dissimilar bytes */
189 uint count = end_dis - compr; /* uint for faster switch */
190
191 switch (count) { /* Use memcpy only if it's worthwhile. */
192 case 6:
193 cptr[6] = compr[5];
194 case 5:
195 cptr[5] = compr[4];
196 case 4:
197 cptr[4] = compr[3];
198 case 3:
199 cptr[3] = compr[2];
200 case 2:
201 cptr[2] = compr[1];
202 case 1:
203 cptr[1] = compr[0];
204 *cptr = count - 1;
205 cptr += count + 1;
206 case 0: /* all done */
207 break;
208 default:
209 if (count > 127)
210 count = 127;
211 *cptr++ = count - 1;
212 memcpy(cptr, compr, count);
213 cptr += count, compr += count;
214 continue;
215 }
216 break;
217 }
218
219 { /* Encode up to 127 similar bytes. */
220 /* Note that count may be <0 at end of row. */
221 int count = (const byte *)next - end_dis;
222
223 while (count > 0) {
224 int this = (count > 127 ? 127 : count);
225
226 *cptr++ = 257 - this;
227 *cptr++ = (byte) test;
228 count -= this;
229 }
230 exam = next;
231 }
232 }
233 return (cptr - compressed);
234 }
235 int
gdev_pcl_mode2compress(const word * row,const word * end_row,byte * compressed)236 gdev_pcl_mode2compress(const word * row, const word * end_row,
237 byte * compressed)
238 {
239 return gdev_pcl_mode2compress_padded(row, end_row, compressed, false);
240 }
241
242 /*
243 * Mode 3 compression routine for the HP LaserJet III family.
244 * Compresses bytecount bytes starting at current, storing the result
245 * in compressed, comparing against and updating previous.
246 * Returns the number of bytes stored. In the worst case,
247 * the number of bytes is bytecount+(bytecount/8)+1.
248 */
249 int
gdev_pcl_mode3compress(int bytecount,const byte * current,byte * previous,byte * compressed)250 gdev_pcl_mode3compress(int bytecount, const byte * current, byte * previous, byte * compressed)
251 {
252 register const byte *cur = current;
253 register byte *prev = previous;
254 register byte *out = compressed;
255 const byte *end = current + bytecount;
256
257 while (cur < end) { /* Detect a maximum run of unchanged bytes. */
258 const byte *run = cur;
259 register const byte *diff;
260 const byte *stop;
261 int offset, cbyte;
262
263 while (cur < end && *cur == *prev) {
264 cur++, prev++;
265 }
266 if (cur == end)
267 break; /* rest of row is unchanged */
268 /* Detect a run of up to 8 changed bytes. */
269 /* We know that *cur != *prev. */
270 diff = cur;
271 stop = (end - cur > 8 ? cur + 8 : end);
272 do {
273 *prev++ = *cur++;
274 }
275 while (cur < stop && *cur != *prev);
276 /* Now [run..diff) are unchanged, and */
277 /* [diff..cur) are changed. */
278 /* Generate the command byte(s). */
279 offset = diff - run;
280 cbyte = (cur - diff - 1) << 5;
281 if (offset < 31)
282 *out++ = cbyte + offset;
283 else {
284 *out++ = cbyte + 31;
285 offset -= 31;
286 while (offset >= 255)
287 *out++ = 255, offset -= 255;
288 *out++ = offset;
289 }
290 /* Copy the changed data. */
291 while (diff < cur)
292 *out++ = *diff++;
293 }
294 return out - compressed;
295 }
296
297 /*
298 * Mode 9 2D compression for the HP DeskJets . This mode can give
299 * very good compression ratios, especially if there are areas of flat
300 * colour (or blank areas), and so is 'highly recommended' for colour
301 * printing in particular because of the very large amounts of data which
302 * can be generated
303 */
304 int
gdev_pcl_mode9compress(int bytecount,const byte * current,const byte * previous,byte * compressed)305 gdev_pcl_mode9compress(int bytecount, const byte *current,
306 const byte *previous, byte *compressed)
307 {
308 register const byte *cur = current;
309 register const byte *prev = previous;
310 register byte *out = compressed;
311 const byte *end = current + bytecount;
312
313 while (cur < end) { /* Detect a run of unchanged bytes. */
314 const byte *run = cur;
315 register const byte *diff;
316 int offset;
317
318 while (cur < end && *cur == *prev) {
319 cur++, prev++;
320 }
321 if (cur == end)
322 break; /* rest of row is unchanged */
323 /* Detect a run of changed bytes. */
324 /* We know that *cur != *prev. */
325 diff = cur;
326 do {
327 prev++;
328 cur++;
329 }
330 while (cur < end && *cur != *prev);
331 /* Now [run..diff) are unchanged, and */
332 /* [diff..cur) are changed. */
333 offset = diff - run;
334 {
335 const byte *stop_test = cur - 4;
336 int dissimilar, similar;
337
338 while (diff < cur) {
339 const byte *compr = diff;
340 const byte *next; /* end of run */
341 byte value = 0;
342
343 while (diff <= stop_test &&
344 ((value = *diff) != diff[1] ||
345 value != diff[2] ||
346 value != diff[3]))
347 diff++;
348
349 /* Find out how long the run is */
350 if (diff > stop_test) /* no run */
351 next = diff = cur;
352 else {
353 next = diff + 4;
354 while (next < cur && *next == value)
355 next++;
356 }
357
358 #define MAXOFFSETU 15
359 #define MAXCOUNTU 7
360 /* output 'dissimilar' bytes, uncompressed */
361 if ((dissimilar = diff - compr)) {
362 int temp, i;
363
364 if ((temp = --dissimilar) > MAXCOUNTU)
365 temp = MAXCOUNTU;
366 if (offset < MAXOFFSETU)
367 *out++ = (offset << 3) | (byte) temp;
368 else {
369 *out++ = (MAXOFFSETU << 3) | (byte) temp;
370 offset -= MAXOFFSETU;
371 while (offset >= 255) {
372 *out++ = 255;
373 offset -= 255;
374 }
375 *out++ = offset;
376 }
377 if (temp == MAXCOUNTU) {
378 temp = dissimilar - MAXCOUNTU;
379 while (temp >= 255) {
380 *out++ = 255;
381 temp -= 255;
382 }
383 *out++ = (byte) temp;
384 }
385 for (i = 0; i <= dissimilar; i++)
386 *out++ = *compr++;
387 offset = 0;
388 } /* end uncompressed */
389 #undef MAXOFFSETU
390 #undef MAXCOUNTU
391
392 #define MAXOFFSETC 3
393 #define MAXCOUNTC 31
394 /* output 'similar' bytes, run-length encoded */
395 if ((similar = next - diff)) {
396 int temp;
397
398 if ((temp = (similar -= 2)) > MAXCOUNTC)
399 temp = MAXCOUNTC;
400 if (offset < MAXOFFSETC)
401 *out++ = 0x80 | (offset << 5) | (byte) temp;
402 else {
403 *out++ = 0x80 | (MAXOFFSETC << 5) | (byte) temp;
404 offset -= MAXOFFSETC;
405 while (offset >= 255) {
406 *out++ = 255;
407 offset -= 255;
408 }
409 *out++ = offset;
410 }
411 if (temp == MAXCOUNTC) {
412 temp = similar - MAXCOUNTC;
413 while (temp >= 255) {
414 *out++ = 255;
415 temp -= 255;
416 }
417 *out++ = (byte) temp;
418 }
419 *out++ = value;
420 offset = 0;
421 } /* end compressed */
422 #undef MAXOFFSETC
423 #undef MAXCOUNTC
424
425 diff = next;
426 }
427 }
428 }
429 return out - compressed;
430 }
431