]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/raster.c
953f359c4cd71ec6fcd32b9a0e0fc0843432e332
[thirdparty/cups.git] / filter / raster.c
1 /*
2 * "$Id$"
3 *
4 * Raster file routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products.
7 *
8 * This file is part of the CUPS Imaging library.
9 *
10 * These coded instructions, statements, and computer programs are the
11 * property of Easy Software Products and are protected by Federal
12 * copyright law. Distribution and use rights are outlined in the file
13 * "LICENSE.txt" which should have been included with this file. If this
14 * file is missing or damaged please contact Easy Software Products
15 * at:
16 *
17 * Attn: CUPS Licensing Information
18 * Easy Software Products
19 * 44141 Airport View Drive, Suite 204
20 * Hollywood, Maryland 20636 USA
21 *
22 * Voice: (301) 373-9600
23 * EMail: cups-info@cups.org
24 * WWW: http://www.cups.org
25 *
26 * This code and any derivative of it may be used and distributed
27 * freely under the terms of the GNU General Public License when
28 * used with GNU/GPL Ghostscript or its derivatives. Use of the
29 * code (or any derivative of it) with software other than GNU/GPL
30 * GhostScript (or its derivatives) is governed by the CUPS license
31 * agreement.
32 *
33 * This file is subject to the Apple OS-Developed Software exception.
34 *
35 * Contents:
36 *
37 * cupsRasterClose() - Close a raster stream.
38 * cupsRasterOpen() - Open a raster stream.
39 * cupsRasterReadHeader() - Read a raster page header and store it in a
40 * V1 page header structure.
41 * cupsRasterReadHeader2() - Read a raster page header and store it in a
42 * V2 page header structure.
43 * cupsRasterReadPixels() - Read raster pixels.
44 * cupsRasterWriteHeader() - Write a raster page header from a V1 page
45 * header structure.
46 * cupsRasterWriteHeader2() - Write a raster page header from a V2 page
47 * header structure.
48 * cupsRasterWritePixels() - Write raster pixels.
49 * cups_raster_read() - Read through the raster buffer.
50 * cups_raster_read_header() - Read a raster page header.
51 * cups_raster_update() - Update the raster header and row count for the
52 * current page.
53 * cups_raster_write() - Write a row of raster data...
54 * cups_read() - Read bytes from a file.
55 * cups_swap() - Swap bytes in raster data...
56 * cups_write() - Write bytes to a file.
57 */
58
59 /*
60 * Include necessary headers...
61 */
62
63 #include "raster.h"
64 #include <cups/debug.h>
65 #include <stdlib.h>
66 #include <errno.h>
67 #include <cups/string.h>
68
69 #if defined(WIN32) || defined(__EMX__)
70 # include <io.h>
71 #else
72 # include <unistd.h>
73 #endif /* WIN32 || __EMX__ */
74
75
76 /*
77 * Private structures...
78 */
79
80 struct _cups_raster_s /**** Raster stream data ****/
81 {
82 unsigned sync; /* Sync word from start of stream */
83 int fd; /* File descriptor */
84 cups_mode_t mode; /* Read/write mode */
85 cups_page_header2_t header; /* Raster header for current page */
86 int count, /* Current row run-length count */
87 remaining, /* Remaining rows in page image */
88 bpp; /* Bytes per pixel/color */
89 unsigned char *pixels, /* Pixels for current row */
90 *pend, /* End of pixel buffer */
91 *pcurrent; /* Current byte in pixel buffer */
92 int compressed, /* Non-zero if data is compressed */
93 swapped; /* Non-zero if data is byte-swapped */
94 unsigned char *buffer, /* Read/write buffer */
95 *bufptr, /* Current (read) position in buffer */
96 *bufend; /* End of current (read) buffer */
97 int bufsize; /* Buffer size */
98 };
99
100
101 /*
102 * Local functions...
103 */
104
105 static unsigned cups_raster_read_header(cups_raster_t *r);
106 static int cups_raster_read(cups_raster_t *r, unsigned char *buf,
107 int bytes);
108 static void cups_raster_update(cups_raster_t *r);
109 static int cups_raster_write(cups_raster_t *r, const unsigned char *pixels);
110 static int cups_read(int fd, unsigned char *buf, int bytes);
111 static void cups_swap(unsigned char *buf, int bytes);
112 static int cups_write(int fd, const unsigned char *buf, int bytes);
113
114
115 /*
116 * 'cupsRasterClose()' - Close a raster stream.
117 */
118
119 void
120 cupsRasterClose(cups_raster_t *r) /* I - Stream to close */
121 {
122 if (r != NULL)
123 {
124 if (r->buffer)
125 free(r->buffer);
126
127 if (r->pixels)
128 free(r->pixels);
129
130 free(r);
131 }
132 }
133
134
135 /*
136 * 'cupsRasterOpen()' - Open a raster stream.
137 */
138
139 cups_raster_t * /* O - New stream */
140 cupsRasterOpen(int fd, /* I - File descriptor */
141 cups_mode_t mode) /* I - Mode */
142 {
143 cups_raster_t *r; /* New stream */
144
145
146 if ((r = calloc(sizeof(cups_raster_t), 1)) == NULL)
147 return (NULL);
148
149 r->fd = fd;
150 r->mode = mode == CUPS_RASTER_WRITE_COMPRESSED ? CUPS_RASTER_WRITE : mode;
151
152 if (mode == CUPS_RASTER_READ)
153 {
154 /*
155 * Open for read - get sync word...
156 */
157
158 if (!cups_read(r->fd, (unsigned char *)&(r->sync), sizeof(r->sync)))
159 {
160 free(r);
161 return (NULL);
162 }
163
164 if (r->sync != CUPS_RASTER_SYNC &&
165 r->sync != CUPS_RASTER_REVSYNC &&
166 r->sync != CUPS_RASTER_SYNCv1 &&
167 r->sync != CUPS_RASTER_REVSYNCv1 &&
168 r->sync != CUPS_RASTER_SYNCv2 &&
169 r->sync != CUPS_RASTER_REVSYNCv2)
170 {
171 free(r);
172 return (NULL);
173 }
174
175 if (r->sync == CUPS_RASTER_SYNCv2 ||
176 r->sync == CUPS_RASTER_REVSYNCv2)
177 r->compressed = 1;
178
179 if (r->sync == CUPS_RASTER_REVSYNC ||
180 r->sync == CUPS_RASTER_REVSYNCv1 ||
181 r->sync == CUPS_RASTER_REVSYNCv2)
182 r->swapped = 1;
183 }
184 else
185 {
186 /*
187 * Open for write - put sync word...
188 */
189
190 if (mode == CUPS_RASTER_WRITE_COMPRESSED)
191 {
192 r->compressed = 1;
193 r->sync = CUPS_RASTER_SYNCv2;
194 }
195 else
196 r->sync = CUPS_RASTER_SYNC;
197
198 if (cups_write(r->fd, (unsigned char *)&(r->sync), sizeof(r->sync))
199 < sizeof(r->sync))
200 {
201 free(r);
202 return (NULL);
203 }
204 }
205
206 return (r);
207 }
208
209
210 /*
211 * 'cupsRasterReadHeader()' - Read a raster page header and store it in a
212 * V1 page header structure.
213 */
214
215 unsigned /* O - 1 on success, 0 on fail */
216 cupsRasterReadHeader(
217 cups_raster_t *r, /* I - Raster stream */
218 cups_page_header_t *h) /* I - Pointer to header data */
219 {
220 /*
221 * Get the raster header...
222 */
223
224 if (!cups_raster_read_header(r))
225 return (0);
226
227 /*
228 * Copy the header to the user-supplied buffer...
229 */
230
231 memcpy(h, &(r->header), sizeof(cups_page_header_t));
232
233 return (1);
234 }
235
236
237 /*
238 * 'cupsRasterReadHeader2()' - Read a raster page header and store it in a
239 * V2 page header structure.
240 *
241 * @since CUPS 1.2@
242 */
243
244 unsigned /* O - 1 on success, 0 on fail */
245 cupsRasterReadHeader2(
246 cups_raster_t *r, /* I - Raster stream */
247 cups_page_header2_t *h) /* I - Pointer to header data */
248 {
249 /*
250 * Get the raster header...
251 */
252
253 if (!cups_raster_read_header(r))
254 return (0);
255
256 /*
257 * Copy the header to the user-supplied buffer...
258 */
259
260 memcpy(h, &(r->header), sizeof(cups_page_header2_t));
261
262 return (1);
263 }
264
265
266 /*
267 * 'cupsRasterReadPixels()' - Read raster pixels.
268 */
269
270 unsigned /* O - Number of bytes read */
271 cupsRasterReadPixels(cups_raster_t *r, /* I - Raster stream */
272 unsigned char *p, /* I - Pointer to pixel buffer */
273 unsigned len) /* I - Number of bytes to read */
274 {
275 int bytes; /* Bytes read */
276 unsigned cupsBytesPerLine; /* cupsBytesPerLine value */
277 unsigned remaining; /* Bytes remaining */
278 unsigned char *ptr, /* Pointer to read buffer */
279 byte, /* Byte from file */
280 *temp; /* Pointer into buffer */
281 int count; /* Repetition count */
282
283
284 if (r == NULL || r->mode != CUPS_RASTER_READ || r->remaining == 0)
285 return (0);
286
287 if (!r->compressed)
288 {
289 /*
290 * Read without compression...
291 */
292
293 r->remaining -= len / r->header.cupsBytesPerLine;
294
295 if (!cups_read(r->fd, p, len))
296 return (0);
297
298 /*
299 * Swap bytes as needed...
300 */
301
302 if ((r->header.cupsBitsPerColor == 16 ||
303 r->header.cupsBitsPerPixel == 12 ||
304 r->header.cupsBitsPerPixel == 16) &&
305 r->swapped)
306 cups_swap(p, len);
307
308 /*
309 * Return...
310 */
311
312 return (len);
313 }
314
315 /*
316 * Read compressed data...
317 */
318
319 remaining = len;
320 cupsBytesPerLine = r->header.cupsBytesPerLine;
321
322 while (remaining > 0 && r->remaining > 0)
323 {
324 if (r->count == 0)
325 {
326 /*
327 * Need to read a new row...
328 */
329
330 if (remaining == cupsBytesPerLine)
331 ptr = p;
332 else
333 ptr = r->pixels;
334
335 /*
336 * Read using a modified TIFF "packbits" compression...
337 */
338
339 if (!cups_raster_read(r, &byte, 1))
340 return (0);
341
342 r->count = byte + 1;
343
344 if (r->count > 1)
345 ptr = r->pixels;
346
347 temp = ptr;
348 bytes = cupsBytesPerLine;
349
350 while (bytes > 0)
351 {
352 /*
353 * Get a new repeat count...
354 */
355
356 if (!cups_raster_read(r, &byte, 1))
357 return (0);
358
359 if (byte & 128)
360 {
361 /*
362 * Copy N literal pixels...
363 */
364
365 count = (257 - byte) * r->bpp;
366
367 if (count > bytes)
368 count = bytes;
369
370 if (!cups_raster_read(r, temp, count))
371 return (0);
372
373 temp += count;
374 bytes -= count;
375 }
376 else
377 {
378 /*
379 * Repeat the next N bytes...
380 */
381
382 count = (byte + 1) * r->bpp;
383 if (count > bytes)
384 count = bytes;
385
386 if (count < r->bpp)
387 break;
388
389 bytes -= count;
390
391 if (!cups_raster_read(r, temp, r->bpp))
392 return (0);
393
394 temp += r->bpp;
395 count -= r->bpp;
396
397 while (count > 0)
398 {
399 memcpy(temp, temp - r->bpp, r->bpp);
400 temp += r->bpp;
401 count -= r->bpp;
402 }
403 }
404 }
405
406 /*
407 * Swap bytes as needed...
408 */
409
410 if ((r->header.cupsBitsPerColor == 16 ||
411 r->header.cupsBitsPerPixel == 12 ||
412 r->header.cupsBitsPerPixel == 16) &&
413 r->swapped)
414 cups_swap(ptr, bytes);
415
416 /*
417 * Update pointers...
418 */
419
420 if (remaining >= cupsBytesPerLine)
421 {
422 bytes = cupsBytesPerLine;
423 r->pcurrent = r->pixels;
424 r->count --;
425 r->remaining --;
426 }
427 else
428 {
429 bytes = remaining;
430 r->pcurrent = r->pixels + bytes;
431 }
432
433 /*
434 * Copy data as needed...
435 */
436
437 if (ptr != p)
438 memcpy(p, ptr, bytes);
439 }
440 else
441 {
442 /*
443 * Copy fragment from buffer...
444 */
445
446 if ((bytes = r->pend - r->pcurrent) > remaining)
447 bytes = remaining;
448
449 memcpy(p, r->pcurrent, bytes);
450 r->pcurrent += bytes;
451
452 if (r->pcurrent >= r->pend)
453 {
454 r->pcurrent = r->pixels;
455 r->count --;
456 r->remaining --;
457 }
458 }
459
460 remaining -= bytes;
461 p += bytes;
462 }
463
464 return (len);
465 }
466
467
468 /*
469 * 'cupsRasterWriteHeader()' - Write a raster page header from a V1 page
470 * header structure.
471 */
472
473 unsigned /* O - 1 on success, 0 on failure */
474 cupsRasterWriteHeader(
475 cups_raster_t *r, /* I - Raster stream */
476 cups_page_header_t *h) /* I - Raster page header */
477 {
478 if (r == NULL || r->mode != CUPS_RASTER_WRITE)
479 return (0);
480
481 /*
482 * Make a copy of the header, and compute the number of raster
483 * lines in the page image...
484 */
485
486 memset(&(r->header), 0, sizeof(r->header));
487 memcpy(&(r->header), h, sizeof(cups_page_header_t));
488
489 cups_raster_update(r);
490
491 /*
492 * Write the raster header...
493 */
494
495 return (cups_write(r->fd, (unsigned char *)&(r->header), sizeof(r->header))
496 > 0);
497 }
498
499
500 /*
501 * 'cupsRasterWriteHeader2()' - Write a raster page header from a V2 page
502 * header structure.
503 *
504 * @since CUPS 1.2@
505 */
506
507 unsigned /* O - 1 on success, 0 on failure */
508 cupsRasterWriteHeader2(
509 cups_raster_t *r, /* I - Raster stream */
510 cups_page_header2_t *h) /* I - Raster page header */
511 {
512 if (r == NULL || r->mode != CUPS_RASTER_WRITE)
513 return (0);
514
515 /*
516 * Make a copy of the header, and compute the number of raster
517 * lines in the page image...
518 */
519
520 memcpy(&(r->header), h, sizeof(cups_page_header2_t));
521
522 cups_raster_update(r);
523
524 /*
525 * Write the raster header...
526 */
527
528 return (cups_write(r->fd, (unsigned char *)&(r->header), sizeof(r->header))
529 > 0);
530 }
531
532
533 /*
534 * 'cupsRasterWritePixels()' - Write raster pixels.
535 */
536
537 unsigned /* O - Number of bytes written */
538 cupsRasterWritePixels(cups_raster_t *r, /* I - Raster stream */
539 unsigned char *p, /* I - Bytes to write */
540 unsigned len)/* I - Number of bytes to write */
541 {
542 int bytes; /* Bytes read */
543 unsigned remaining; /* Bytes remaining */
544
545
546 #ifdef DEBUG
547 fprintf(stderr, "cupsRasterWritePixels(r=%p, p=%p, len=%u), remaining=%u\n",
548 r, p, len, r->remaining);
549 #endif /* DEBUG */
550
551 if (r == NULL || r->mode != CUPS_RASTER_WRITE || r->remaining == 0)
552 return (0);
553
554 if (!r->compressed)
555 {
556 /*
557 * Without compression, just write the raster data raw...
558 */
559
560 r->remaining -= len / r->header.cupsBytesPerLine;
561
562 return (cups_write(r->fd, p, len));
563 }
564
565 /*
566 * Otherwise, compress each line...
567 */
568
569 for (remaining = len; remaining > 0; remaining -= bytes, p += bytes)
570 {
571 /*
572 * Figure out the number of remaining bytes on the current line...
573 */
574
575 if ((bytes = remaining) > (r->pend - r->pcurrent))
576 bytes = r->pend - r->pcurrent;
577
578 if (r->count > 0)
579 {
580 /*
581 * Check to see if this line is the same as the previous line...
582 */
583
584 if (memcmp(p, r->pcurrent, bytes))
585 {
586 if (!cups_raster_write(r, r->pixels))
587 return (0);
588
589 r->count = 0;
590 }
591 else
592 {
593 /*
594 * Mark more bytes as the same...
595 */
596
597 r->pcurrent += bytes;
598
599 if (r->pcurrent >= r->pend)
600 {
601 /*
602 * Increase the repeat count...
603 */
604
605 r->count ++;
606 r->pcurrent = r->pixels;
607
608 /*
609 * Flush out this line if it is the last one...
610 */
611
612 r->remaining --;
613
614 if (r->remaining == 0)
615 return (cups_raster_write(r, r->pixels));
616 else if (r->count == 256)
617 {
618 if (cups_raster_write(r, r->pixels) == 0)
619 return (0);
620
621 r->count = 0;
622 }
623 }
624
625 continue;
626 }
627 }
628
629 if (r->count == 0)
630 {
631 /*
632 * Copy the raster data to the buffer...
633 */
634
635 memcpy(r->pcurrent, p, bytes);
636
637 r->pcurrent += bytes;
638
639 if (r->pcurrent >= r->pend)
640 {
641 /*
642 * Increase the repeat count...
643 */
644
645 r->count ++;
646 r->pcurrent = r->pixels;
647
648 /*
649 * Flush out this line if it is the last one...
650 */
651
652 r->remaining --;
653
654 if (r->remaining == 0)
655 return (cups_raster_write(r, r->pixels));
656 }
657 }
658 }
659
660 return (len);
661 }
662
663
664 /*
665 * 'cups_raster_read_header()' - Read a raster page header.
666 */
667
668 static unsigned /* O - 1 on success, 0 on fail */
669 cups_raster_read_header(
670 cups_raster_t *r) /* I - Raster stream */
671 {
672 int len; /* Number of words to swap */
673 union swap_s /* Swapping structure */
674 {
675 unsigned char b[4];
676 unsigned v;
677 } *s;
678
679
680 if (r == NULL || r->mode != CUPS_RASTER_READ)
681 return (0);
682
683 /*
684 * Get the length of the raster header...
685 */
686
687 if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1)
688 len = sizeof(cups_page_header_t);
689 else
690 len = sizeof(cups_page_header2_t);
691
692 /*
693 * Read the header...
694 */
695
696 memset(&(r->header), 0, sizeof(r->header));
697
698 if (cups_raster_read(r, (unsigned char *)&(r->header), len) < len)
699 return (0);
700
701 /*
702 * Swap bytes as needed...
703 */
704
705 if (r->swapped)
706 for (len = 81, s = (union swap_s *)&(r->header.AdvanceDistance);
707 len > 0;
708 len --, s ++)
709 s->v = (((((s->b[3] << 8) | s->b[2]) << 8) | s->b[1]) << 8) | s->b[0];
710
711 /*
712 * Update the header and row count...
713 */
714
715 cups_raster_update(r);
716
717 return (1);
718 }
719
720
721 /*
722 * 'cups_raster_read()' - Read through the raster buffer.
723 */
724
725 static int /* O - Number of bytes read */
726 cups_raster_read(cups_raster_t *r, /* I - Raster stream */
727 unsigned char *buf, /* I - Buffer */
728 int bytes) /* I - Number of bytes to read */
729 {
730 int count, /* Number of bytes read */
731 remaining, /* Remaining bytes in buffer */
732 total; /* Total bytes read */
733
734
735 DEBUG_printf(("cups_raster_read(r=%p, buf=%p, bytes=%d)\n", r, buf, bytes));
736
737 if (!r->compressed)
738 return (cups_read(r->fd, buf, bytes));
739
740 /*
741 * Allocate a read buffer as needed...
742 */
743
744 count = 2 * r->header.cupsBytesPerLine;
745
746 if (count > r->bufsize)
747 {
748 int offset = r->bufptr - r->buffer; /* Offset to current start of buffer */
749 int end = r->bufend - r->buffer; /* Offset to current end of buffer */
750 unsigned char *rptr; /* Pointer in read buffer */
751
752 if (r->buffer)
753 rptr = realloc(r->buffer, count);
754 else
755 rptr = malloc(count);
756
757 if (!rptr)
758 return (0);
759
760 r->buffer = rptr;
761 r->bufptr = rptr + offset;
762 r->bufend = rptr + end;
763 r->bufsize = count;
764 }
765
766 /*
767 * Loop until we have read everything...
768 */
769
770 for (total = 0, remaining = r->bufend - r->bufptr;
771 total < bytes;
772 total += count, buf += count)
773 {
774 count = bytes - total;
775
776 DEBUG_printf(("count=%d, remaining=%d, buf=%p, bufptr=%p, bufend=%p...\n",
777 count, remaining, buf, r->bufptr, r->bufend));
778
779 if (remaining == 0)
780 {
781 if (count < 16)
782 {
783 /*
784 * Read into the raster buffer and then copy...
785 */
786
787 remaining = cups_read(r->fd, r->buffer, r->bufsize);
788 if (remaining <= 0)
789 return (0);
790
791 r->bufptr = r->buffer;
792 r->bufend = r->buffer + remaining;
793 }
794 else
795 {
796 /*
797 * Read directly into "buf"...
798 */
799
800 count = cups_read(r->fd, buf, count);
801
802 if (count <= 0)
803 return (0);
804
805 continue;
806 }
807 }
808
809 /*
810 * Copy bytes from raster buffer to "buf"...
811 */
812
813 if (count > remaining)
814 count = remaining;
815
816 if (count == 1)
817 {
818 /*
819 * Copy 1 byte...
820 */
821
822 *buf = *(r->bufptr)++;
823 remaining --;
824 }
825 else if (count < 128)
826 {
827 /*
828 * Copy up to 127 bytes without using memcpy(); this is
829 * faster because it avoids an extra function call and is
830 * often further optimized by the compiler...
831 */
832
833 unsigned char *bufptr; /* Temporary buffer pointer */
834
835
836 remaining -= count;
837
838 for (bufptr = r->bufptr; count > 0; count --, total ++)
839 *buf++ = *bufptr++;
840
841 r->bufptr = bufptr;
842 }
843 else
844 {
845 /*
846 * Use memcpy() for a large read...
847 */
848
849 memcpy(buf, r->bufptr, count);
850 r->bufptr += count;
851 remaining -= count;
852 }
853 }
854
855 return (total);
856 }
857
858
859 /*
860 * 'cups_raster_update()' - Update the raster header and row count for the
861 * current page.
862 */
863
864 static void
865 cups_raster_update(cups_raster_t *r) /* I - Raster stream */
866 {
867 if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1 ||
868 r->header.cupsNumColors == 0)
869 {
870 /*
871 * Set the "cupsNumColors" field according to the colorspace...
872 */
873
874 switch (r->header.cupsColorSpace)
875 {
876 case CUPS_CSPACE_W :
877 case CUPS_CSPACE_K :
878 case CUPS_CSPACE_WHITE :
879 case CUPS_CSPACE_GOLD :
880 case CUPS_CSPACE_SILVER :
881 r->header.cupsNumColors = 1;
882 break;
883
884 case CUPS_CSPACE_RGB :
885 case CUPS_CSPACE_CMY :
886 case CUPS_CSPACE_YMC :
887 case CUPS_CSPACE_CIEXYZ :
888 case CUPS_CSPACE_CIELab :
889 case CUPS_CSPACE_ICC1 :
890 case CUPS_CSPACE_ICC2 :
891 case CUPS_CSPACE_ICC3 :
892 case CUPS_CSPACE_ICC4 :
893 case CUPS_CSPACE_ICC5 :
894 case CUPS_CSPACE_ICC6 :
895 case CUPS_CSPACE_ICC7 :
896 case CUPS_CSPACE_ICC8 :
897 case CUPS_CSPACE_ICC9 :
898 case CUPS_CSPACE_ICCA :
899 case CUPS_CSPACE_ICCB :
900 case CUPS_CSPACE_ICCC :
901 case CUPS_CSPACE_ICCD :
902 case CUPS_CSPACE_ICCE :
903 case CUPS_CSPACE_ICCF :
904 r->header.cupsNumColors = 3;
905 break;
906
907 case CUPS_CSPACE_RGBA :
908 case CUPS_CSPACE_RGBW :
909 case CUPS_CSPACE_CMYK :
910 case CUPS_CSPACE_YMCK :
911 case CUPS_CSPACE_KCMY :
912 case CUPS_CSPACE_GMCK :
913 case CUPS_CSPACE_GMCS :
914 r->header.cupsNumColors = 4;
915 break;
916
917 case CUPS_CSPACE_KCMYcm :
918 if (r->header.cupsBitsPerPixel < 8)
919 r->header.cupsNumColors = 6;
920 else
921 r->header.cupsNumColors = 4;
922 break;
923 }
924 }
925
926 /*
927 * Set the number of bytes per pixel/color...
928 */
929
930 if (r->header.cupsColorOrder == CUPS_ORDER_CHUNKED)
931 r->bpp = (r->header.cupsBitsPerPixel + 7) / 8;
932 else
933 r->bpp = (r->header.cupsBitsPerColor + 7) / 8;
934
935 /*
936 * Set the number of remaining rows...
937 */
938
939 if (r->header.cupsColorOrder == CUPS_ORDER_PLANAR)
940 r->remaining = r->header.cupsHeight * r->header.cupsNumColors;
941 else
942 r->remaining = r->header.cupsHeight;
943
944 /*
945 * Allocate the compression buffer...
946 */
947
948 if (r->compressed)
949 {
950 if (r->pixels != NULL)
951 free(r->pixels);
952
953 r->pixels = calloc(r->header.cupsBytesPerLine, 1);
954 r->pcurrent = r->pixels;
955 r->pend = r->pixels + r->header.cupsBytesPerLine;
956 r->count = 0;
957 }
958 }
959
960
961 /*
962 * 'cups_raster_write()' - Write a row of compressed raster data...
963 */
964
965 static int /* O - Number of bytes written */
966 cups_raster_write(
967 cups_raster_t *r, /* I - Raster stream */
968 const unsigned char *pixels) /* I - Pixel data to write */
969 {
970 const unsigned char *start, /* Start of sequence */
971 *ptr, /* Current pointer in sequence */
972 *pend, /* End of raster buffer */
973 *plast; /* Pointer to last pixel */
974 unsigned char *wptr; /* Pointer into write buffer */
975 int bpp, /* Bytes per pixel */
976 count, /* Count */
977 maxrun; /* Maximum run of 128 * bpp */
978
979
980 #ifdef DEBUG
981 fprintf(stderr, "cups_raster_write(r=%p, pixels=%p)\n", r, pixels);
982 #endif /* DEBUG */
983
984 /*
985 * Allocate a write buffer as needed...
986 */
987
988 count = r->header.cupsBytesPerLine * 2;
989 if (count > r->bufsize)
990 {
991 if (r->buffer)
992 wptr = realloc(r->buffer, count);
993 else
994 wptr = malloc(count);
995
996 if (!wptr)
997 return (-1);
998
999 r->buffer = wptr;
1000 r->bufsize = count;
1001 }
1002
1003 /*
1004 * Write the row repeat count...
1005 */
1006
1007 bpp = r->bpp;
1008 pend = pixels + r->header.cupsBytesPerLine;
1009 plast = pend - bpp;
1010 wptr = r->buffer;
1011 *wptr++ = r->count - 1;
1012 maxrun = 128 * bpp;
1013
1014 /*
1015 * Write using a modified TIFF "packbits" compression...
1016 */
1017
1018 for (ptr = pixels; ptr < pend;)
1019 {
1020 start = ptr;
1021 ptr += bpp;
1022
1023 if (ptr == pend)
1024 {
1025 /*
1026 * Encode a single pixel at the end...
1027 */
1028
1029 *wptr++ = 0;
1030 for (count = bpp; count > 0; count --)
1031 *wptr++ = *start++;
1032 }
1033 else if (!memcmp(start, ptr, bpp))
1034 {
1035 /*
1036 * Encode a sequence of repeating pixels...
1037 */
1038
1039 for (count = 2; count < 128 && ptr < plast; count ++, ptr += bpp)
1040 if (memcmp(ptr, ptr + bpp, bpp))
1041 break;
1042
1043 *wptr++ = count - 1;
1044 for (count = bpp; count > 0; count --)
1045 *wptr++ = *ptr++;
1046 }
1047 else
1048 {
1049 /*
1050 * Encode a sequence of non-repeating pixels...
1051 */
1052
1053 for (count = 1; count < 127 && ptr < plast; count ++, ptr += bpp)
1054 if (!memcmp(ptr, ptr + bpp, bpp))
1055 break;
1056
1057 if (ptr >= plast && count < 128)
1058 {
1059 count ++;
1060 ptr += bpp;
1061 }
1062
1063 *wptr++ = 257 - count;
1064
1065 count *= bpp;
1066 memcpy(wptr, start, count);
1067 wptr += count;
1068 }
1069 }
1070
1071 return (cups_write(r->fd, r->buffer, wptr - r->buffer));
1072 }
1073
1074
1075 /*
1076 * 'cups_read()' - Read bytes from a file.
1077 */
1078
1079 static int /* O - Bytes read or -1 */
1080 cups_read(int fd, /* I - File descriptor */
1081 unsigned char *buf, /* I - Buffer for read */
1082 int bytes) /* I - Number of bytes to read */
1083 {
1084 int count, /* Number of bytes read */
1085 total; /* Total bytes read */
1086
1087
1088 for (total = 0; total < bytes; total += count, buf += count)
1089 {
1090 count = read(fd, buf, bytes - total);
1091
1092 if (count == 0)
1093 return (0);
1094 else if (count < 0)
1095 {
1096 if (errno == EINTR)
1097 count = 0;
1098 else
1099 return (-1);
1100 }
1101 }
1102
1103 return (total);
1104 }
1105
1106
1107 /*
1108 * 'cups_swap()' - Swap bytes in raster data...
1109 */
1110
1111 static void
1112 cups_swap(unsigned char *buf, /* I - Buffer to swap */
1113 int bytes) /* I - Number of bytes to swap */
1114 {
1115 unsigned char even, odd; /* Temporary variables */
1116
1117
1118 bytes /= 2;
1119
1120 while (bytes > 0)
1121 {
1122 even = buf[0];
1123 odd = buf[1];
1124 buf[0] = odd;
1125 buf[1] = even;
1126
1127 buf += 2;
1128 bytes --;
1129 }
1130 }
1131
1132
1133 /*
1134 * 'cups_write()' - Write bytes to a file.
1135 */
1136
1137 static int /* O - Bytes written or -1 */
1138 cups_write(int fd, /* I - File descriptor */
1139 const unsigned char *buf, /* I - Bytes to write */
1140 int bytes) /* I - Number of bytes to write */
1141 {
1142 int count, /* Number of bytes written */
1143 total; /* Total bytes written */
1144
1145
1146 for (total = 0; total < bytes; total += count, buf += count)
1147 {
1148 count = write(fd, buf, bytes - total);
1149
1150 if (count < 0)
1151 {
1152 if (errno == EINTR)
1153 count = 0;
1154 else
1155 return (-1);
1156 }
1157 }
1158
1159 return (total);
1160 }
1161
1162
1163 /*
1164 * End of "$Id$".
1165 */