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