]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/raster.c
Merge changes from CUPS 1.5.1-r9875.
[thirdparty/cups.git] / filter / raster.c
1 /*
2 * "$Id: raster.c 7720 2008-07-11 22:46:21Z mike $"
3 *
4 * Raster file routines for CUPS.
5 *
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products.
8 *
9 * This file is part of the CUPS Imaging library.
10 *
11 * These coded instructions, statements, and computer programs are the
12 * property of Apple Inc. and are protected by Federal copyright
13 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
14 * which should have been included with this file. If this file is
15 * file is missing or damaged, see the license at "http://www.cups.org/".
16 *
17 * This file is subject to the Apple OS-Developed Software exception.
18 *
19 * Contents:
20 *
21 * cupsRasterClose() - Close a raster stream.
22 * cupsRasterOpen() - Open a raster stream using a file descriptor.
23 * cupsRasterOpenIO() - Open a raster stream using a callback function.
24 * cupsRasterReadHeader() - Read a raster page header and store it in a
25 * version 1 page header structure.
26 * cupsRasterReadHeader2() - Read a raster page header and store it in a
27 * version 2 page header structure.
28 * cupsRasterReadPixels() - Read raster pixels.
29 * cupsRasterWriteHeader() - Write a raster page header from a version 1
30 * page header structure.
31 * cupsRasterWriteHeader2() - Write a raster page header from a version 2
32 * page header structure.
33 * cupsRasterWritePixels() - Write raster pixels.
34 * cups_raster_read_header() - Read a raster page header.
35 * cups_raster_read() - Read through the raster buffer.
36 * cups_raster_update() - Update the raster header and row count for the
37 * current page.
38 * cups_raster_write() - Write a row of compressed raster data...
39 * cups_read_fd() - Read bytes from a file.
40 * cups_swap() - Swap bytes in raster data...
41 * cups_write_fd() - Write bytes to a file.
42 */
43
44 /*
45 * Include necessary headers...
46 */
47
48 #include "image-private.h"
49 #if defined(WIN32) || defined(__EMX__)
50 # include <io.h>
51 # include <winsock2.h> /* for htonl() definition */
52 #else
53 # include <unistd.h>
54 #endif /* WIN32 || __EMX__ */
55
56
57 /*
58 * Private structures...
59 */
60
61 struct _cups_raster_s /**** Raster stream data ****/
62 {
63 unsigned sync; /* Sync word from start of stream */
64 void *ctx; /* File descriptor */
65 cups_raster_iocb_t iocb; /* IO callback */
66 cups_mode_t mode; /* Read/write mode */
67 cups_page_header2_t header; /* Raster header for current page */
68 int count, /* Current row run-length count */
69 remaining, /* Remaining rows in page image */
70 bpp; /* Bytes per pixel/color */
71 unsigned char *pixels, /* Pixels for current row */
72 *pend, /* End of pixel buffer */
73 *pcurrent; /* Current byte in pixel buffer */
74 int compressed, /* Non-zero if data is compressed */
75 swapped; /* Non-zero if data is byte-swapped */
76 unsigned char *buffer, /* Read/write buffer */
77 *bufptr, /* Current (read) position in buffer */
78 *bufend; /* End of current (read) buffer */
79 size_t bufsize; /* Buffer size */
80 };
81
82
83 /*
84 * Local functions...
85 */
86
87 static int cups_raster_io(cups_raster_t *r, unsigned char *buf, int bytes);
88 static unsigned cups_raster_read_header(cups_raster_t *r);
89 static int cups_raster_read(cups_raster_t *r, unsigned char *buf,
90 int bytes);
91 static void cups_raster_update(cups_raster_t *r);
92 static int cups_raster_write(cups_raster_t *r,
93 const unsigned char *pixels);
94 static ssize_t cups_read_fd(void *ctx, unsigned char *buf, size_t bytes);
95 static void cups_swap(unsigned char *buf, int bytes);
96 static ssize_t cups_write_fd(void *ctx, unsigned char *buf, size_t bytes);
97
98
99 /*
100 * 'cupsRasterClose()' - Close a raster stream.
101 *
102 * The file descriptor associated with the raster stream must be closed
103 * separately as needed.
104 */
105
106 void
107 cupsRasterClose(cups_raster_t *r) /* I - Stream to close */
108 {
109 if (r != NULL)
110 {
111 if (r->buffer)
112 free(r->buffer);
113
114 if (r->pixels)
115 free(r->pixels);
116
117 free(r);
118 }
119 }
120
121
122 /*
123 * 'cupsRasterOpen()' - Open a raster stream using a file descriptor.
124 *
125 * This function associates a raster stream with the given file descriptor.
126 * For most printer driver filters, "fd" will be 0 (stdin). For most raster
127 * image processor (RIP) filters that generate raster data, "fd" will be 1
128 * (stdout).
129 *
130 * When writing raster data, the @code CUPS_RASTER_WRITE@,
131 * @code CUPS_RASTER_WRITE_COMPRESS@, or @code CUPS_RASTER_WRITE_PWG@ mode can
132 * be used - compressed and PWG output is generally 25-50% smaller but adds a
133 * 100-300% execution time overhead.
134 */
135
136 cups_raster_t * /* O - New stream */
137 cupsRasterOpen(int fd, /* I - File descriptor */
138 cups_mode_t mode) /* I - Mode - @code CUPS_RASTER_READ@,
139 @code CUPS_RASTER_WRITE@,
140 @code CUPS_RASTER_WRITE_COMPRESSED@,
141 or @code CUPS_RASTER_WRITE_PWG@ */
142 {
143 if (mode == CUPS_RASTER_READ)
144 return (cupsRasterOpenIO(cups_read_fd, (void *)((intptr_t)fd), mode));
145 else
146 return (cupsRasterOpenIO(cups_write_fd, (void *)((intptr_t)fd), mode));
147 }
148
149
150 /*
151 * 'cupsRasterOpenIO()' - Open a raster stream using a callback function.
152 *
153 * This function associates a raster stream with the given callback function and
154 * context pointer.
155 *
156 * When writing raster data, the @code CUPS_RASTER_WRITE@,
157 * @code CUPS_RASTER_WRITE_COMPRESS@, or @code CUPS_RASTER_WRITE_PWG@ mode can
158 * be used - compressed and PWG output is generally 25-50% smaller but adds a
159 * 100-300% execution time overhead.
160 */
161
162 cups_raster_t * /* O - New stream */
163 cupsRasterOpenIO(
164 cups_raster_iocb_t iocb, /* I - Read/write callback */
165 void *ctx, /* I - Context pointer for callback */
166 cups_mode_t mode) /* I - Mode - @code CUPS_RASTER_READ@,
167 @code CUPS_RASTER_WRITE@,
168 @code CUPS_RASTER_WRITE_COMPRESSED@,
169 or @code CUPS_RASTER_WRITE_PWG@ */
170 {
171 cups_raster_t *r; /* New stream */
172
173
174 _cupsRasterClearError();
175
176 if ((r = calloc(sizeof(cups_raster_t), 1)) == NULL)
177 {
178 _cupsRasterAddError("Unable to allocate memory for raster stream: %s\n",
179 strerror(errno));
180 return (NULL);
181 }
182
183 r->ctx = ctx;
184 r->iocb = iocb;
185 r->mode = mode;
186
187 if (mode == CUPS_RASTER_READ)
188 {
189 /*
190 * Open for read - get sync word...
191 */
192
193 if (cups_raster_io(r, (unsigned char *)&(r->sync), sizeof(r->sync)) !=
194 sizeof(r->sync))
195 {
196 _cupsRasterAddError("Unable to read header from raster stream: %s\n",
197 strerror(errno));
198 free(r);
199 return (NULL);
200 }
201
202 if (r->sync != CUPS_RASTER_SYNC &&
203 r->sync != CUPS_RASTER_REVSYNC &&
204 r->sync != CUPS_RASTER_SYNCv1 &&
205 r->sync != CUPS_RASTER_REVSYNCv1 &&
206 r->sync != CUPS_RASTER_SYNCv2 &&
207 r->sync != CUPS_RASTER_REVSYNCv2)
208 {
209 _cupsRasterAddError("Unknown raster format %08x!\n", r->sync);
210 free(r);
211 return (NULL);
212 }
213
214 if (r->sync == CUPS_RASTER_SYNCv2 ||
215 r->sync == CUPS_RASTER_REVSYNCv2)
216 r->compressed = 1;
217
218 if (r->sync == CUPS_RASTER_REVSYNC ||
219 r->sync == CUPS_RASTER_REVSYNCv1 ||
220 r->sync == CUPS_RASTER_REVSYNCv2)
221 r->swapped = 1;
222
223 DEBUG_printf(("r->swapped=%d, r->sync=%08x\n", r->swapped, r->sync));
224 }
225 else
226 {
227 /*
228 * Open for write - put sync word...
229 */
230
231 switch (mode)
232 {
233 default :
234 case CUPS_RASTER_WRITE :
235 r->sync = CUPS_RASTER_SYNC;
236 break;
237
238 case CUPS_RASTER_WRITE_COMPRESSED :
239 r->compressed = 1;
240 r->sync = CUPS_RASTER_SYNCv2;
241 break;
242
243 case CUPS_RASTER_WRITE_PWG :
244 r->compressed = 1;
245 r->sync = htonl(CUPS_RASTER_SYNC_PWG);
246 r->swapped = r->sync != CUPS_RASTER_SYNC_PWG;
247 break;
248 }
249
250 if (cups_raster_io(r, (unsigned char *)&(r->sync), sizeof(r->sync))
251 < sizeof(r->sync))
252 {
253 _cupsRasterAddError("Unable to write raster stream header: %s\n",
254 strerror(errno));
255 free(r);
256 return (NULL);
257 }
258 }
259
260 return (r);
261 }
262
263
264 /*
265 * 'cupsRasterReadHeader()' - Read a raster page header and store it in a
266 * version 1 page header structure.
267 *
268 * This function is deprecated. Use @link cupsRasterReadHeader2@ instead.
269 *
270 * Version 1 page headers were used in CUPS 1.0 and 1.1 and contain a subset
271 * of the version 2 page header data. This function handles reading version 2
272 * page headers and copying only the version 1 data into the provided buffer.
273 *
274 * @deprecated@
275 */
276
277 unsigned /* O - 1 on success, 0 on failure/end-of-file */
278 cupsRasterReadHeader(
279 cups_raster_t *r, /* I - Raster stream */
280 cups_page_header_t *h) /* I - Pointer to header data */
281 {
282 /*
283 * Get the raster header...
284 */
285
286 if (!cups_raster_read_header(r))
287 return (0);
288
289 /*
290 * Copy the header to the user-supplied buffer...
291 */
292
293 memcpy(h, &(r->header), sizeof(cups_page_header_t));
294
295 return (1);
296 }
297
298
299 /*
300 * 'cupsRasterReadHeader2()' - Read a raster page header and store it in a
301 * version 2 page header structure.
302 *
303 * @since CUPS 1.2/Mac OS X 10.5@
304 */
305
306 unsigned /* O - 1 on success, 0 on failure/end-of-file */
307 cupsRasterReadHeader2(
308 cups_raster_t *r, /* I - Raster stream */
309 cups_page_header2_t *h) /* I - Pointer to header data */
310 {
311 /*
312 * Get the raster header...
313 */
314
315 if (!cups_raster_read_header(r))
316 return (0);
317
318 /*
319 * Copy the header to the user-supplied buffer...
320 */
321
322 memcpy(h, &(r->header), sizeof(cups_page_header2_t));
323
324 return (1);
325 }
326
327
328 /*
329 * 'cupsRasterReadPixels()' - Read raster pixels.
330 *
331 * For best performance, filters should read one or more whole lines.
332 * The "cupsBytesPerLine" value from the page header can be used to allocate
333 * the line buffer and as the number of bytes to read.
334 */
335
336 unsigned /* O - Number of bytes read */
337 cupsRasterReadPixels(cups_raster_t *r, /* I - Raster stream */
338 unsigned char *p, /* I - Pointer to pixel buffer */
339 unsigned len) /* I - Number of bytes to read */
340 {
341 int bytes; /* Bytes read */
342 unsigned cupsBytesPerLine; /* cupsBytesPerLine value */
343 unsigned remaining; /* Bytes remaining */
344 unsigned char *ptr, /* Pointer to read buffer */
345 byte, /* Byte from file */
346 *temp; /* Pointer into buffer */
347 int count; /* Repetition count */
348
349
350 if (r == NULL || r->mode != CUPS_RASTER_READ || r->remaining == 0)
351 return (0);
352
353 if (!r->compressed)
354 {
355 /*
356 * Read without compression...
357 */
358
359 r->remaining -= len / r->header.cupsBytesPerLine;
360
361 if (cups_raster_io(r, p, len) < (ssize_t)len)
362 return (0);
363
364 /*
365 * Swap bytes as needed...
366 */
367
368 if (r->swapped &&
369 (r->header.cupsBitsPerColor == 16 ||
370 r->header.cupsBitsPerPixel == 12 ||
371 r->header.cupsBitsPerPixel == 16))
372 cups_swap(p, len);
373
374 /*
375 * Return...
376 */
377
378 return (len);
379 }
380
381 /*
382 * Read compressed data...
383 */
384
385 remaining = len;
386 cupsBytesPerLine = r->header.cupsBytesPerLine;
387
388 while (remaining > 0 && r->remaining > 0)
389 {
390 if (r->count == 0)
391 {
392 /*
393 * Need to read a new row...
394 */
395
396 if (remaining == cupsBytesPerLine)
397 ptr = p;
398 else
399 ptr = r->pixels;
400
401 /*
402 * Read using a modified PackBits compression...
403 */
404
405 if (!cups_raster_read(r, &byte, 1))
406 return (0);
407
408 r->count = byte + 1;
409
410 if (r->count > 1)
411 ptr = r->pixels;
412
413 temp = ptr;
414 bytes = cupsBytesPerLine;
415
416 while (bytes > 0)
417 {
418 /*
419 * Get a new repeat count...
420 */
421
422 if (!cups_raster_read(r, &byte, 1))
423 return (0);
424
425 if (byte & 128)
426 {
427 /*
428 * Copy N literal pixels...
429 */
430
431 count = (257 - byte) * r->bpp;
432
433 if (count > bytes)
434 count = bytes;
435
436 if (!cups_raster_read(r, temp, count))
437 return (0);
438
439 temp += count;
440 bytes -= count;
441 }
442 else
443 {
444 /*
445 * Repeat the next N bytes...
446 */
447
448 count = (byte + 1) * r->bpp;
449 if (count > bytes)
450 count = bytes;
451
452 if (count < r->bpp)
453 break;
454
455 bytes -= count;
456
457 if (!cups_raster_read(r, temp, r->bpp))
458 return (0);
459
460 temp += r->bpp;
461 count -= r->bpp;
462
463 while (count > 0)
464 {
465 memcpy(temp, temp - r->bpp, r->bpp);
466 temp += r->bpp;
467 count -= r->bpp;
468 }
469 }
470 }
471
472 /*
473 * Swap bytes as needed...
474 */
475
476 if ((r->header.cupsBitsPerColor == 16 ||
477 r->header.cupsBitsPerPixel == 12 ||
478 r->header.cupsBitsPerPixel == 16) &&
479 r->swapped)
480 cups_swap(ptr, bytes);
481
482 /*
483 * Update pointers...
484 */
485
486 if (remaining >= cupsBytesPerLine)
487 {
488 bytes = cupsBytesPerLine;
489 r->pcurrent = r->pixels;
490 r->count --;
491 r->remaining --;
492 }
493 else
494 {
495 bytes = remaining;
496 r->pcurrent = r->pixels + bytes;
497 }
498
499 /*
500 * Copy data as needed...
501 */
502
503 if (ptr != p)
504 memcpy(p, ptr, bytes);
505 }
506 else
507 {
508 /*
509 * Copy fragment from buffer...
510 */
511
512 if ((unsigned)(bytes = r->pend - r->pcurrent) > remaining)
513 bytes = remaining;
514
515 memcpy(p, r->pcurrent, bytes);
516 r->pcurrent += bytes;
517
518 if (r->pcurrent >= r->pend)
519 {
520 r->pcurrent = r->pixels;
521 r->count --;
522 r->remaining --;
523 }
524 }
525
526 remaining -= bytes;
527 p += bytes;
528 }
529
530 return (len);
531 }
532
533
534 /*
535 * 'cupsRasterWriteHeader()' - Write a raster page header from a version 1 page
536 * header structure.
537 *
538 * This function is deprecated. Use @link cupsRasterWriteHeader2@ instead.
539 *
540 * @deprecated@
541 */
542
543 unsigned /* O - 1 on success, 0 on failure */
544 cupsRasterWriteHeader(
545 cups_raster_t *r, /* I - Raster stream */
546 cups_page_header_t *h) /* I - Raster page header */
547 {
548 if (r == NULL || r->mode == CUPS_RASTER_READ)
549 return (0);
550
551 /*
552 * Make a copy of the header, and compute the number of raster
553 * lines in the page image...
554 */
555
556 memset(&(r->header), 0, sizeof(r->header));
557 memcpy(&(r->header), h, sizeof(cups_page_header_t));
558
559 cups_raster_update(r);
560
561 /*
562 * Write the raster header...
563 */
564
565 if (r->mode == CUPS_RASTER_WRITE_PWG)
566 {
567 /*
568 * PWG raster data is always network byte order with most of the page header
569 * zeroed.
570 */
571
572 cups_page_header2_t fh; /* File page header */
573
574 memset(&fh, 0, sizeof(fh));
575 fh.HWResolution[0] = htonl(r->header.HWResolution[0]);
576 fh.HWResolution[1] = htonl(r->header.HWResolution[1]);
577 fh.cupsWidth = htonl(r->header.cupsWidth);
578 fh.cupsHeight = htonl(r->header.cupsHeight);
579 fh.cupsBitsPerColor = htonl(r->header.cupsBitsPerColor);
580 fh.cupsBitsPerPixel = htonl(r->header.cupsBitsPerPixel);
581 fh.cupsBytesPerLine = htonl(r->header.cupsBytesPerLine);
582 fh.cupsColorOrder = htonl(r->header.cupsColorOrder);
583 fh.cupsColorSpace = htonl(r->header.cupsColorSpace);
584
585 return (cups_raster_io(r, (unsigned char *)&fh, sizeof(fh)) == sizeof(fh));
586 }
587 else
588 return (cups_raster_io(r, (unsigned char *)&(r->header), sizeof(r->header))
589 == sizeof(r->header));
590 }
591
592
593 /*
594 * 'cupsRasterWriteHeader2()' - Write a raster page header from a version 2
595 * page header structure.
596 *
597 * The page header can be initialized using @link cupsRasterInterpretPPD@.
598 *
599 * @since CUPS 1.2/Mac OS X 10.5@
600 */
601
602 unsigned /* O - 1 on success, 0 on failure */
603 cupsRasterWriteHeader2(
604 cups_raster_t *r, /* I - Raster stream */
605 cups_page_header2_t *h) /* I - Raster page header */
606 {
607 if (r == NULL || r->mode == CUPS_RASTER_READ)
608 return (0);
609
610 /*
611 * Make a copy of the header, and compute the number of raster
612 * lines in the page image...
613 */
614
615 memcpy(&(r->header), h, sizeof(cups_page_header2_t));
616
617 cups_raster_update(r);
618
619 /*
620 * Write the raster header...
621 */
622
623 if (r->mode == CUPS_RASTER_WRITE_PWG)
624 {
625 /*
626 * PWG raster data is always network byte order with most of the page header
627 * zeroed.
628 */
629
630 cups_page_header2_t fh; /* File page header */
631
632 memset(&fh, 0, sizeof(fh));
633 strlcpy(fh.MediaClass, "PwgRaster", sizeof(fh.MediaClass));
634 strlcpy(fh.MediaColor, r->header.MediaColor, sizeof(fh.MediaColor));
635 strlcpy(fh.MediaType, r->header.MediaType, sizeof(fh.MediaType));
636 strlcpy(fh.OutputType, r->header.OutputType, sizeof(fh.OutputType));
637 strlcpy(fh.cupsRenderingIntent, r->header.cupsRenderingIntent,
638 sizeof(fh.cupsRenderingIntent));
639 strlcpy(fh.cupsPageSizeName, r->header.cupsPageSizeName,
640 sizeof(fh.cupsPageSizeName));
641
642 fh.CutMedia = htonl(r->header.CutMedia);
643 fh.Duplex = htonl(r->header.Duplex);
644 fh.HWResolution[0] = htonl(r->header.HWResolution[0]);
645 fh.HWResolution[1] = htonl(r->header.HWResolution[1]);
646 fh.ImagingBoundingBox[0] = htonl(r->header.ImagingBoundingBox[0]);
647 fh.ImagingBoundingBox[1] = htonl(r->header.ImagingBoundingBox[1]);
648 fh.ImagingBoundingBox[2] = htonl(r->header.ImagingBoundingBox[2]);
649 fh.ImagingBoundingBox[3] = htonl(r->header.ImagingBoundingBox[3]);
650 fh.InsertSheet = htonl(r->header.InsertSheet);
651 fh.Jog = htonl(r->header.Jog);
652 fh.LeadingEdge = htonl(r->header.LeadingEdge);
653 fh.ManualFeed = htonl(r->header.ManualFeed);
654 fh.MediaPosition = htonl(r->header.MediaPosition);
655 fh.MediaWeight = htonl(r->header.MediaWeight);
656 fh.NumCopies = htonl(r->header.NumCopies);
657 fh.Orientation = htonl(r->header.Orientation);
658 fh.PageSize[0] = htonl(r->header.PageSize[0]);
659 fh.PageSize[1] = htonl(r->header.PageSize[1]);
660 fh.Tumble = htonl(r->header.Tumble);
661 fh.cupsWidth = htonl(r->header.cupsWidth);
662 fh.cupsHeight = htonl(r->header.cupsHeight);
663 fh.cupsBitsPerColor = htonl(r->header.cupsBitsPerColor);
664 fh.cupsBitsPerPixel = htonl(r->header.cupsBitsPerPixel);
665 fh.cupsBytesPerLine = htonl(r->header.cupsBytesPerLine);
666 fh.cupsColorOrder = htonl(r->header.cupsColorOrder);
667 fh.cupsColorSpace = htonl(r->header.cupsColorSpace);
668 fh.cupsNumColors = htonl(r->header.cupsNumColors);
669 fh.cupsInteger[0] = htonl(r->header.cupsInteger[0]);
670 fh.cupsInteger[1] = htonl(r->header.cupsInteger[1]);
671 fh.cupsInteger[2] = htonl(r->header.cupsInteger[2]);
672 fh.cupsInteger[3] = htonl(r->header.cupsImagingBBox[0] *
673 r->header.HWResolution[0]);
674 fh.cupsInteger[4] = htonl(r->header.cupsImagingBBox[1] *
675 r->header.HWResolution[1]);
676 fh.cupsInteger[5] = htonl(r->header.cupsImagingBBox[2] *
677 r->header.HWResolution[0]);
678 fh.cupsInteger[6] = htonl(r->header.cupsImagingBBox[3] *
679 r->header.HWResolution[1]);
680 fh.cupsInteger[7] = htonl(0xffffff);
681
682 return (cups_raster_io(r, (unsigned char *)&fh, sizeof(fh)) == sizeof(fh));
683 }
684 else
685 return (cups_raster_io(r, (unsigned char *)&(r->header), sizeof(r->header))
686 == sizeof(r->header));
687 }
688
689
690 /*
691 * 'cupsRasterWritePixels()' - Write raster pixels.
692 *
693 * For best performance, filters should write one or more whole lines.
694 * The "cupsBytesPerLine" value from the page header can be used to allocate
695 * the line buffer and as the number of bytes to write.
696 */
697
698 unsigned /* O - Number of bytes written */
699 cupsRasterWritePixels(cups_raster_t *r, /* I - Raster stream */
700 unsigned char *p, /* I - Bytes to write */
701 unsigned len)/* I - Number of bytes to write */
702 {
703 int bytes; /* Bytes read */
704 unsigned remaining; /* Bytes remaining */
705
706
707 DEBUG_printf(("cupsRasterWritePixels(r=%p, p=%p, len=%u), remaining=%u\n",
708 r, p, len, r->remaining));
709
710 if (r == NULL || r->mode == CUPS_RASTER_READ || r->remaining == 0)
711 return (0);
712
713 if (!r->compressed)
714 {
715 /*
716 * Without compression, just write the raster data raw unless the data needs
717 * to be swapped...
718 */
719
720 r->remaining -= len / r->header.cupsBytesPerLine;
721
722 if (r->swapped &&
723 (r->header.cupsBitsPerColor == 16 ||
724 r->header.cupsBitsPerPixel == 12 ||
725 r->header.cupsBitsPerPixel == 16))
726 {
727 unsigned char *bufptr; /* Pointer into write buffer */
728 unsigned count; /* Remaining count */
729
730 /*
731 * Allocate a write buffer as needed...
732 */
733
734 if ((size_t)len > r->bufsize)
735 {
736 if (r->buffer)
737 bufptr = realloc(r->buffer, len);
738 else
739 bufptr = malloc(len);
740
741 if (!bufptr)
742 return (0);
743
744 r->buffer = bufptr;
745 r->bufsize = len;
746 }
747
748 /*
749 * Byte swap the pixels...
750 */
751
752 for (bufptr = r->buffer, count = len; count > 1; count -= 2, bufptr += 2)
753 {
754 bufptr[1] = *p++;
755 bufptr[0] = *p++;
756 }
757
758 if (count) /* This should never happen... */
759 *bufptr = *p;
760
761 /*
762 * Write the byte-swapped buffer...
763 */
764
765 return (cups_raster_io(r, r->buffer, len));
766 }
767 else
768 return (cups_raster_io(r, p, len));
769 }
770
771 /*
772 * Otherwise, compress each line...
773 */
774
775 for (remaining = len; remaining > 0; remaining -= bytes, p += bytes)
776 {
777 /*
778 * Figure out the number of remaining bytes on the current line...
779 */
780
781 if ((bytes = remaining) > (r->pend - r->pcurrent))
782 bytes = r->pend - r->pcurrent;
783
784 if (r->count > 0)
785 {
786 /*
787 * Check to see if this line is the same as the previous line...
788 */
789
790 if (memcmp(p, r->pcurrent, bytes))
791 {
792 if (!cups_raster_write(r, r->pixels))
793 return (0);
794
795 r->count = 0;
796 }
797 else
798 {
799 /*
800 * Mark more bytes as the same...
801 */
802
803 r->pcurrent += bytes;
804
805 if (r->pcurrent >= r->pend)
806 {
807 /*
808 * Increase the repeat count...
809 */
810
811 r->count ++;
812 r->pcurrent = r->pixels;
813
814 /*
815 * Flush out this line if it is the last one...
816 */
817
818 r->remaining --;
819
820 if (r->remaining == 0)
821 return (cups_raster_write(r, r->pixels));
822 else if (r->count == 256)
823 {
824 if (cups_raster_write(r, r->pixels) == 0)
825 return (0);
826
827 r->count = 0;
828 }
829 }
830
831 continue;
832 }
833 }
834
835 if (r->count == 0)
836 {
837 /*
838 * Copy the raster data to the buffer...
839 */
840
841 memcpy(r->pcurrent, p, bytes);
842
843 r->pcurrent += bytes;
844
845 if (r->pcurrent >= r->pend)
846 {
847 /*
848 * Increase the repeat count...
849 */
850
851 r->count ++;
852 r->pcurrent = r->pixels;
853
854 /*
855 * Flush out this line if it is the last one...
856 */
857
858 r->remaining --;
859
860 if (r->remaining == 0)
861 return (cups_raster_write(r, r->pixels));
862 }
863 }
864 }
865
866 return (len);
867 }
868
869
870 /*
871 * 'cups_raster_read_header()' - Read a raster page header.
872 */
873
874 static unsigned /* O - 1 on success, 0 on fail */
875 cups_raster_read_header(
876 cups_raster_t *r) /* I - Raster stream */
877 {
878 int len; /* Length for read/swap */
879
880
881 if (r == NULL || r->mode != CUPS_RASTER_READ)
882 return (0);
883
884 /*
885 * Get the length of the raster header...
886 */
887
888 if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1)
889 len = sizeof(cups_page_header_t);
890 else
891 len = sizeof(cups_page_header2_t);
892
893 /*
894 * Read the header...
895 */
896
897 memset(&(r->header), 0, sizeof(r->header));
898
899 if (cups_raster_read(r, (unsigned char *)&(r->header), len) < len)
900 return (0);
901
902 /*
903 * Swap bytes as needed...
904 */
905
906 if (r->swapped)
907 {
908 unsigned *s, /* Current word */
909 temp; /* Temporary copy */
910
911
912 DEBUG_puts("Swapping header bytes...");
913
914 for (len = 81, s = &(r->header.AdvanceDistance);
915 len > 0;
916 len --, s ++)
917 {
918 DEBUG_printf(("%08x =>", *s));
919
920 temp = *s;
921 *s = ((temp & 0xff) << 24) |
922 ((temp & 0xff00) << 8) |
923 ((temp & 0xff0000) >> 8) |
924 ((temp & 0xff000000) >> 24);
925
926 DEBUG_printf((" %08x\n", *s));
927 }
928 }
929
930 /*
931 * Update the header and row count...
932 */
933
934 cups_raster_update(r);
935
936 return (1);
937 }
938
939
940 /*
941 * 'cups_raster_io()' - Read/write bytes from a context, handling interruptions.
942 */
943
944 static int /* O - Bytes read or -1 */
945 cups_raster_io(cups_raster_t *r, /* I - Raster stream */
946 unsigned char *buf, /* I - Buffer for read/write */
947 int bytes) /* I - Number of bytes to read/write */
948 {
949 ssize_t count; /* Number of bytes read/written */
950 size_t total; /* Total bytes read/written */
951
952
953 DEBUG_printf(("4cups_raster_io(r=%p, buf=%p, bytes=%d)", r, buf, bytes));
954
955 for (total = 0; total < bytes; total += count, buf += count)
956 {
957 count = (*r->iocb)(r->ctx, buf, bytes - total);
958
959 DEBUG_printf(("5cups_raster_io: count=%d, total=%d", (int)count,
960 (int)total));
961 if (count == 0)
962 return (0);
963 else if (count < 0)
964 return (-1);
965 }
966
967 return ((int)total);
968 }
969
970
971 /*
972 * 'cups_raster_read()' - Read through the raster buffer.
973 */
974
975 static int /* O - Number of bytes read */
976 cups_raster_read(cups_raster_t *r, /* I - Raster stream */
977 unsigned char *buf, /* I - Buffer */
978 int bytes) /* I - Number of bytes to read */
979 {
980 int count, /* Number of bytes read */
981 remaining, /* Remaining bytes in buffer */
982 total; /* Total bytes read */
983
984
985 DEBUG_printf(("cups_raster_read(r=%p, buf=%p, bytes=%d)\n", r, buf, bytes));
986
987 if (!r->compressed)
988 return (cups_raster_io(r, buf, bytes));
989
990 /*
991 * Allocate a read buffer as needed...
992 */
993
994 count = 2 * r->header.cupsBytesPerLine;
995
996 if ((size_t)count > r->bufsize)
997 {
998 int offset = r->bufptr - r->buffer; /* Offset to current start of buffer */
999 int end = r->bufend - r->buffer; /* Offset to current end of buffer */
1000 unsigned char *rptr; /* Pointer in read buffer */
1001
1002 if (r->buffer)
1003 rptr = realloc(r->buffer, count);
1004 else
1005 rptr = malloc(count);
1006
1007 if (!rptr)
1008 return (0);
1009
1010 r->buffer = rptr;
1011 r->bufptr = rptr + offset;
1012 r->bufend = rptr + end;
1013 r->bufsize = count;
1014 }
1015
1016 /*
1017 * Loop until we have read everything...
1018 */
1019
1020 for (total = 0, remaining = r->bufend - r->bufptr;
1021 total < bytes;
1022 total += count, buf += count)
1023 {
1024 count = bytes - total;
1025
1026 DEBUG_printf(("count=%d, remaining=%d, buf=%p, bufptr=%p, bufend=%p...\n",
1027 count, remaining, buf, r->bufptr, r->bufend));
1028
1029 if (remaining == 0)
1030 {
1031 if (count < 16)
1032 {
1033 /*
1034 * Read into the raster buffer and then copy...
1035 */
1036
1037 remaining = (*r->iocb)(r->ctx, r->buffer, r->bufsize);
1038 if (remaining <= 0)
1039 return (0);
1040
1041 r->bufptr = r->buffer;
1042 r->bufend = r->buffer + remaining;
1043 }
1044 else
1045 {
1046 /*
1047 * Read directly into "buf"...
1048 */
1049
1050 count = (*r->iocb)(r->ctx, buf, count);
1051
1052 if (count <= 0)
1053 return (0);
1054
1055 continue;
1056 }
1057 }
1058
1059 /*
1060 * Copy bytes from raster buffer to "buf"...
1061 */
1062
1063 if (count > remaining)
1064 count = remaining;
1065
1066 if (count == 1)
1067 {
1068 /*
1069 * Copy 1 byte...
1070 */
1071
1072 *buf = *(r->bufptr)++;
1073 remaining --;
1074 }
1075 else if (count < 128)
1076 {
1077 /*
1078 * Copy up to 127 bytes without using memcpy(); this is
1079 * faster because it avoids an extra function call and is
1080 * often further optimized by the compiler...
1081 */
1082
1083 unsigned char *bufptr; /* Temporary buffer pointer */
1084
1085 remaining -= count;
1086
1087 for (bufptr = r->bufptr; count > 0; count --, total ++)
1088 *buf++ = *bufptr++;
1089
1090 r->bufptr = bufptr;
1091 }
1092 else
1093 {
1094 /*
1095 * Use memcpy() for a large read...
1096 */
1097
1098 memcpy(buf, r->bufptr, count);
1099 r->bufptr += count;
1100 remaining -= count;
1101 }
1102 }
1103
1104 return (total);
1105 }
1106
1107
1108 /*
1109 * 'cups_raster_update()' - Update the raster header and row count for the
1110 * current page.
1111 */
1112
1113 static void
1114 cups_raster_update(cups_raster_t *r) /* I - Raster stream */
1115 {
1116 if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1 ||
1117 r->header.cupsNumColors == 0)
1118 {
1119 /*
1120 * Set the "cupsNumColors" field according to the colorspace...
1121 */
1122
1123 switch (r->header.cupsColorSpace)
1124 {
1125 case CUPS_CSPACE_W :
1126 case CUPS_CSPACE_K :
1127 case CUPS_CSPACE_WHITE :
1128 case CUPS_CSPACE_GOLD :
1129 case CUPS_CSPACE_SILVER :
1130 case CUPS_CSPACE_SW :
1131 r->header.cupsNumColors = 1;
1132 break;
1133
1134 case CUPS_CSPACE_RGB :
1135 case CUPS_CSPACE_CMY :
1136 case CUPS_CSPACE_YMC :
1137 case CUPS_CSPACE_CIEXYZ :
1138 case CUPS_CSPACE_CIELab :
1139 case CUPS_CSPACE_SRGB :
1140 case CUPS_CSPACE_ADOBERGB :
1141 case CUPS_CSPACE_ICC1 :
1142 case CUPS_CSPACE_ICC2 :
1143 case CUPS_CSPACE_ICC3 :
1144 case CUPS_CSPACE_ICC4 :
1145 case CUPS_CSPACE_ICC5 :
1146 case CUPS_CSPACE_ICC6 :
1147 case CUPS_CSPACE_ICC7 :
1148 case CUPS_CSPACE_ICC8 :
1149 case CUPS_CSPACE_ICC9 :
1150 case CUPS_CSPACE_ICCA :
1151 case CUPS_CSPACE_ICCB :
1152 case CUPS_CSPACE_ICCC :
1153 case CUPS_CSPACE_ICCD :
1154 case CUPS_CSPACE_ICCE :
1155 case CUPS_CSPACE_ICCF :
1156 r->header.cupsNumColors = 3;
1157 break;
1158
1159 case CUPS_CSPACE_RGBA :
1160 case CUPS_CSPACE_RGBW :
1161 case CUPS_CSPACE_CMYK :
1162 case CUPS_CSPACE_YMCK :
1163 case CUPS_CSPACE_KCMY :
1164 case CUPS_CSPACE_GMCK :
1165 case CUPS_CSPACE_GMCS :
1166 r->header.cupsNumColors = 4;
1167 break;
1168
1169 case CUPS_CSPACE_KCMYcm :
1170 if (r->header.cupsBitsPerPixel < 8)
1171 r->header.cupsNumColors = 6;
1172 else
1173 r->header.cupsNumColors = 4;
1174 break;
1175
1176 case CUPS_CSPACE_DEVICE1 :
1177 case CUPS_CSPACE_DEVICE2 :
1178 case CUPS_CSPACE_DEVICE3 :
1179 case CUPS_CSPACE_DEVICE4 :
1180 case CUPS_CSPACE_DEVICE5 :
1181 case CUPS_CSPACE_DEVICE6 :
1182 case CUPS_CSPACE_DEVICE7 :
1183 case CUPS_CSPACE_DEVICE8 :
1184 case CUPS_CSPACE_DEVICE9 :
1185 case CUPS_CSPACE_DEVICEA :
1186 case CUPS_CSPACE_DEVICEB :
1187 case CUPS_CSPACE_DEVICEC :
1188 case CUPS_CSPACE_DEVICED :
1189 case CUPS_CSPACE_DEVICEE :
1190 case CUPS_CSPACE_DEVICEF :
1191 r->header.cupsNumColors = r->header.cupsColorSpace -
1192 CUPS_CSPACE_DEVICE1 + 1;
1193 break;
1194 }
1195 }
1196
1197 /*
1198 * Set the number of bytes per pixel/color...
1199 */
1200
1201 if (r->header.cupsColorOrder == CUPS_ORDER_CHUNKED)
1202 r->bpp = (r->header.cupsBitsPerPixel + 7) / 8;
1203 else
1204 r->bpp = (r->header.cupsBitsPerColor + 7) / 8;
1205
1206 /*
1207 * Set the number of remaining rows...
1208 */
1209
1210 if (r->header.cupsColorOrder == CUPS_ORDER_PLANAR)
1211 r->remaining = r->header.cupsHeight * r->header.cupsNumColors;
1212 else
1213 r->remaining = r->header.cupsHeight;
1214
1215 /*
1216 * Allocate the compression buffer...
1217 */
1218
1219 if (r->compressed)
1220 {
1221 if (r->pixels != NULL)
1222 free(r->pixels);
1223
1224 r->pixels = calloc(r->header.cupsBytesPerLine, 1);
1225 r->pcurrent = r->pixels;
1226 r->pend = r->pixels + r->header.cupsBytesPerLine;
1227 r->count = 0;
1228 }
1229 }
1230
1231
1232 /*
1233 * 'cups_raster_write()' - Write a row of compressed raster data...
1234 */
1235
1236 static int /* O - Number of bytes written */
1237 cups_raster_write(
1238 cups_raster_t *r, /* I - Raster stream */
1239 const unsigned char *pixels) /* I - Pixel data to write */
1240 {
1241 const unsigned char *start, /* Start of sequence */
1242 *ptr, /* Current pointer in sequence */
1243 *pend, /* End of raster buffer */
1244 *plast; /* Pointer to last pixel */
1245 unsigned char *wptr; /* Pointer into write buffer */
1246 int bpp, /* Bytes per pixel */
1247 count; /* Count */
1248
1249
1250 DEBUG_printf(("cups_raster_write(r=%p, pixels=%p)\n", r, pixels));
1251
1252 /*
1253 * Allocate a write buffer as needed...
1254 */
1255
1256 count = r->header.cupsBytesPerLine * 2;
1257 if ((size_t)count > r->bufsize)
1258 {
1259 if (r->buffer)
1260 wptr = realloc(r->buffer, count);
1261 else
1262 wptr = malloc(count);
1263
1264 if (!wptr)
1265 return (-1);
1266
1267 r->buffer = wptr;
1268 r->bufsize = count;
1269 }
1270
1271 /*
1272 * Write the row repeat count...
1273 */
1274
1275 bpp = r->bpp;
1276 pend = pixels + r->header.cupsBytesPerLine;
1277 plast = pend - bpp;
1278 wptr = r->buffer;
1279 *wptr++ = r->count - 1;
1280
1281 /*
1282 * Write using a modified PackBits compression...
1283 */
1284
1285 for (ptr = pixels; ptr < pend;)
1286 {
1287 start = ptr;
1288 ptr += bpp;
1289
1290 if (ptr == pend)
1291 {
1292 /*
1293 * Encode a single pixel at the end...
1294 */
1295
1296 *wptr++ = 0;
1297 for (count = bpp; count > 0; count --)
1298 *wptr++ = *start++;
1299 }
1300 else if (!memcmp(start, ptr, bpp))
1301 {
1302 /*
1303 * Encode a sequence of repeating pixels...
1304 */
1305
1306 for (count = 2; count < 128 && ptr < plast; count ++, ptr += bpp)
1307 if (memcmp(ptr, ptr + bpp, bpp))
1308 break;
1309
1310 *wptr++ = count - 1;
1311 for (count = bpp; count > 0; count --)
1312 *wptr++ = *ptr++;
1313 }
1314 else
1315 {
1316 /*
1317 * Encode a sequence of non-repeating pixels...
1318 */
1319
1320 for (count = 1; count < 128 && ptr < plast; count ++, ptr += bpp)
1321 if (!memcmp(ptr, ptr + bpp, bpp))
1322 break;
1323
1324 if (ptr >= plast && count < 128)
1325 {
1326 count ++;
1327 ptr += bpp;
1328 }
1329
1330 *wptr++ = 257 - count;
1331
1332 count *= bpp;
1333 memcpy(wptr, start, count);
1334 wptr += count;
1335 }
1336 }
1337
1338 return (cups_raster_io(r, r->buffer, wptr - r->buffer));
1339 }
1340
1341
1342 /*
1343 * 'cups_read_fd()' - Read bytes from a file.
1344 */
1345
1346 static ssize_t /* O - Bytes read or -1 */
1347 cups_read_fd(void *ctx, /* I - File descriptor as pointer */
1348 unsigned char *buf, /* I - Buffer for read */
1349 size_t bytes) /* I - Maximum number of bytes to read */
1350 {
1351 int fd = (int)((intptr_t)ctx);
1352 /* File descriptor */
1353 ssize_t count; /* Number of bytes read */
1354
1355
1356 while ((count = read(fd, buf, bytes)) < 0)
1357 if (errno != EINTR && errno != EAGAIN)
1358 return (-1);
1359
1360 return (count);
1361 }
1362
1363
1364 /*
1365 * 'cups_swap()' - Swap bytes in raster data...
1366 */
1367
1368 static void
1369 cups_swap(unsigned char *buf, /* I - Buffer to swap */
1370 int bytes) /* I - Number of bytes to swap */
1371 {
1372 unsigned char even, odd; /* Temporary variables */
1373
1374
1375 bytes /= 2;
1376
1377 while (bytes > 0)
1378 {
1379 even = buf[0];
1380 odd = buf[1];
1381 buf[0] = odd;
1382 buf[1] = even;
1383
1384 buf += 2;
1385 bytes --;
1386 }
1387 }
1388
1389
1390 /*
1391 * 'cups_write_fd()' - Write bytes to a file.
1392 */
1393
1394 static ssize_t /* O - Bytes written or -1 */
1395 cups_write_fd(void *ctx, /* I - File descriptor pointer */
1396 unsigned char *buf, /* I - Bytes to write */
1397 size_t bytes) /* I - Number of bytes to write */
1398 {
1399 int fd = (int)((intptr_t)ctx);
1400 /* File descriptor */
1401 ssize_t count; /* Number of bytes written */
1402
1403
1404 while ((count = write(fd, buf, bytes)) < 0)
1405 if (errno != EINTR && errno != EAGAIN)
1406 return (-1);
1407
1408 return (count);
1409 }
1410
1411
1412 /*
1413 * End of "$Id: raster.c 7720 2008-07-11 22:46:21Z mike $".
1414 */