2 * "$Id: raster.c 6061 2006-10-23 00:26:52Z mike $"
4 * Raster file routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2006 by Easy Software Products.
8 * This file is part of the CUPS Imaging library.
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
17 * Attn: CUPS Licensing Information
18 * Easy Software Products
19 * 44141 Airport View Drive, Suite 204
20 * Hollywood, Maryland 20636 USA
22 * Voice: (301) 373-9600
23 * EMail: cups-info@cups.org
24 * WWW: http://www.cups.org
26 * This file is subject to the Apple OS-Developed Software exception.
30 * cupsRasterClose() - Close a raster stream.
31 * cupsRasterOpen() - Open a raster stream.
32 * cupsRasterReadHeader() - Read a raster page header and store it in a
33 * V1 page header structure.
34 * cupsRasterReadHeader2() - Read a raster page header and store it in a
35 * V2 page header structure.
36 * cupsRasterReadPixels() - Read raster pixels.
37 * cupsRasterWriteHeader() - Write a raster page header from a V1 page
39 * cupsRasterWriteHeader2() - Write a raster page header from a V2 page
41 * cupsRasterWritePixels() - Write raster pixels.
42 * cups_raster_read() - Read through the raster buffer.
43 * cups_raster_read_header() - Read a raster page header.
44 * cups_raster_update() - Update the raster header and row count for the
46 * cups_read() - Read bytes from a file.
47 * cups_swap() - Swap bytes in raster data...
48 * cups_write() - Write bytes to a file.
52 * Include necessary headers...
56 #include <cups/debug.h>
59 #include <cups/string.h>
61 #if defined(WIN32) || defined(__EMX__)
65 #endif /* WIN32 || __EMX__ */
69 * Private structures...
72 struct _cups_raster_s
/**** Raster stream data ****/
74 unsigned sync
; /* Sync word from start of stream */
75 int fd
; /* File descriptor */
76 cups_mode_t mode
; /* Read/write mode */
77 cups_page_header2_t header
; /* Raster header for current page */
78 int count
, /* Current row run-length count */
79 remaining
, /* Remaining rows in page image */
80 bpp
; /* Bytes per pixel/color */
81 unsigned char *pixels
, /* Pixels for current row */
82 *pend
, /* End of pixel buffer */
83 *pcurrent
; /* Current byte in pixel buffer */
84 int compressed
, /* Non-zero if data is compressed */
85 swapped
; /* Non-zero if data is byte-swapped */
86 unsigned char *buffer
, /* Read/write buffer */
87 *bufptr
, /* Current (read) position in buffer */
88 *bufend
; /* End of current (read) buffer */
89 int bufsize
; /* Buffer size */
97 static unsigned cups_raster_read_header(cups_raster_t
*r
);
98 static int cups_raster_read(cups_raster_t
*r
, unsigned char *buf
,
100 static void cups_raster_update(cups_raster_t
*r
);
101 static int cups_read(int fd
, unsigned char *buf
, int bytes
);
102 static void cups_swap(unsigned char *buf
, int bytes
);
103 static int cups_write(int fd
, const unsigned char *buf
, int bytes
);
107 * 'cupsRasterClose()' - Close a raster stream.
111 cupsRasterClose(cups_raster_t
*r
) /* I - Stream to close */
127 * 'cupsRasterOpen()' - Open a raster stream.
130 cups_raster_t
* /* O - New stream */
131 cupsRasterOpen(int fd
, /* I - File descriptor */
132 cups_mode_t mode
) /* I - Mode */
134 cups_raster_t
*r
; /* New stream */
137 if ((r
= calloc(sizeof(cups_raster_t
), 1)) == NULL
)
143 if (mode
== CUPS_RASTER_READ
)
146 * Open for read - get sync word...
149 if (!cups_read(r
->fd
, (unsigned char *)&(r
->sync
), sizeof(r
->sync
)))
155 if (r
->sync
!= CUPS_RASTER_SYNC
&&
156 r
->sync
!= CUPS_RASTER_REVSYNC
&&
157 r
->sync
!= CUPS_RASTER_SYNCv1
&&
158 r
->sync
!= CUPS_RASTER_REVSYNCv1
&&
159 r
->sync
!= CUPS_RASTER_SYNCv2
&&
160 r
->sync
!= CUPS_RASTER_REVSYNCv2
)
166 if (r
->sync
== CUPS_RASTER_SYNCv2
||
167 r
->sync
== CUPS_RASTER_REVSYNCv2
)
170 if (r
->sync
== CUPS_RASTER_REVSYNC
||
171 r
->sync
== CUPS_RASTER_REVSYNCv1
||
172 r
->sync
== CUPS_RASTER_REVSYNCv2
)
178 * Open for write - put sync word...
181 r
->sync
= CUPS_RASTER_SYNC
;
183 if (cups_write(r
->fd
, (unsigned char *)&(r
->sync
), sizeof(r
->sync
))
196 * 'cupsRasterReadHeader()' - Read a raster page header and store it in a
197 * V1 page header structure.
200 unsigned /* O - 1 on success, 0 on fail */
201 cupsRasterReadHeader(
202 cups_raster_t
*r
, /* I - Raster stream */
203 cups_page_header_t
*h
) /* I - Pointer to header data */
206 * Get the raster header...
209 if (!cups_raster_read_header(r
))
213 * Copy the header to the user-supplied buffer...
216 memcpy(h
, &(r
->header
), sizeof(cups_page_header_t
));
223 * 'cupsRasterReadHeader2()' - Read a raster page header and store it in a
224 * V2 page header structure.
229 unsigned /* O - 1 on success, 0 on fail */
230 cupsRasterReadHeader2(
231 cups_raster_t
*r
, /* I - Raster stream */
232 cups_page_header2_t
*h
) /* I - Pointer to header data */
235 * Get the raster header...
238 if (!cups_raster_read_header(r
))
242 * Copy the header to the user-supplied buffer...
245 memcpy(h
, &(r
->header
), sizeof(cups_page_header2_t
));
252 * 'cupsRasterReadPixels()' - Read raster pixels.
255 unsigned /* O - Number of bytes read */
256 cupsRasterReadPixels(cups_raster_t
*r
, /* I - Raster stream */
257 unsigned char *p
, /* I - Pointer to pixel buffer */
258 unsigned len
) /* I - Number of bytes to read */
260 int bytes
; /* Bytes read */
261 unsigned cupsBytesPerLine
; /* cupsBytesPerLine value */
262 unsigned remaining
; /* Bytes remaining */
263 unsigned char *ptr
, /* Pointer to read buffer */
264 byte
, /* Byte from file */
265 *temp
; /* Pointer into buffer */
266 int count
; /* Repetition count */
269 if (r
== NULL
|| r
->mode
!= CUPS_RASTER_READ
|| r
->remaining
== 0)
275 * Read without compression...
278 r
->remaining
-= len
/ r
->header
.cupsBytesPerLine
;
280 if (!cups_read(r
->fd
, p
, len
))
284 * Swap bytes as needed...
287 if ((r
->header
.cupsBitsPerColor
== 16 ||
288 r
->header
.cupsBitsPerPixel
== 12 ||
289 r
->header
.cupsBitsPerPixel
== 16) &&
301 * Read compressed data...
305 cupsBytesPerLine
= r
->header
.cupsBytesPerLine
;
307 while (remaining
> 0 && r
->remaining
> 0)
312 * Need to read a new row...
315 if (remaining
== cupsBytesPerLine
)
321 * Read using a modified TIFF "packbits" compression...
324 if (!cups_raster_read(r
, &byte
, 1))
333 bytes
= cupsBytesPerLine
;
338 * Get a new repeat count...
341 if (!cups_raster_read(r
, &byte
, 1))
347 * Copy N literal pixels...
350 count
= (257 - byte
) * r
->bpp
;
355 if (!cups_raster_read(r
, temp
, count
))
364 * Repeat the next N bytes...
367 count
= (byte
+ 1) * r
->bpp
;
376 if (!cups_raster_read(r
, temp
, r
->bpp
))
384 memcpy(temp
, temp
- r
->bpp
, r
->bpp
);
392 * Swap bytes as needed...
395 if ((r
->header
.cupsBitsPerColor
== 16 ||
396 r
->header
.cupsBitsPerPixel
== 12 ||
397 r
->header
.cupsBitsPerPixel
== 16) &&
399 cups_swap(ptr
, bytes
);
405 if (remaining
>= cupsBytesPerLine
)
407 bytes
= cupsBytesPerLine
;
408 r
->pcurrent
= r
->pixels
;
415 r
->pcurrent
= r
->pixels
+ bytes
;
419 * Copy data as needed...
423 memcpy(p
, ptr
, bytes
);
428 * Copy fragment from buffer...
431 if ((bytes
= r
->pend
- r
->pcurrent
) > remaining
)
434 memcpy(p
, r
->pcurrent
, bytes
);
435 r
->pcurrent
+= bytes
;
437 if (r
->pcurrent
>= r
->pend
)
439 r
->pcurrent
= r
->pixels
;
454 * 'cupsRasterWriteHeader()' - Write a raster page header from a V1 page
458 unsigned /* O - 1 on success, 0 on failure */
459 cupsRasterWriteHeader(
460 cups_raster_t
*r
, /* I - Raster stream */
461 cups_page_header_t
*h
) /* I - Raster page header */
463 if (r
== NULL
|| r
->mode
!= CUPS_RASTER_WRITE
)
467 * Make a copy of the header, and compute the number of raster
468 * lines in the page image...
471 memset(&(r
->header
), 0, sizeof(r
->header
));
472 memcpy(&(r
->header
), h
, sizeof(cups_page_header_t
));
474 cups_raster_update(r
);
477 * Write the raster header...
480 return (cups_write(r
->fd
, (unsigned char *)&(r
->header
), sizeof(r
->header
))
486 * 'cupsRasterWriteHeader2()' - Write a raster page header from a V2 page
492 unsigned /* O - 1 on success, 0 on failure */
493 cupsRasterWriteHeader2(
494 cups_raster_t
*r
, /* I - Raster stream */
495 cups_page_header2_t
*h
) /* I - Raster page header */
497 if (r
== NULL
|| r
->mode
!= CUPS_RASTER_WRITE
)
501 * Make a copy of the header, and compute the number of raster
502 * lines in the page image...
505 memcpy(&(r
->header
), h
, sizeof(cups_page_header2_t
));
507 cups_raster_update(r
);
510 * Write the raster header...
513 return (cups_write(r
->fd
, (unsigned char *)&(r
->header
), sizeof(r
->header
))
519 * 'cupsRasterWritePixels()' - Write raster pixels.
522 unsigned /* O - Number of bytes written */
523 cupsRasterWritePixels(cups_raster_t
*r
, /* I - Raster stream */
524 unsigned char *p
, /* I - Bytes to write */
525 unsigned len
)/* I - Number of bytes to write */
528 fprintf(stderr
, "cupsRasterWritePixels(r=%p, p=%p, len=%u), remaining=%u\n",
529 r
, p
, len
, r
->remaining
);
532 if (r
== NULL
|| r
->mode
!= CUPS_RASTER_WRITE
|| r
->remaining
== 0)
536 * No write compression, just write the raster data raw...
539 r
->remaining
-= len
/ r
->header
.cupsBytesPerLine
;
541 return (cups_write(r
->fd
, p
, len
));
546 * 'cups_raster_read_header()' - Read a raster page header.
549 static unsigned /* O - 1 on success, 0 on fail */
550 cups_raster_read_header(
551 cups_raster_t
*r
) /* I - Raster stream */
553 int len
; /* Number of words to swap */
554 union swap_s
/* Swapping structure */
561 if (r
== NULL
|| r
->mode
!= CUPS_RASTER_READ
)
565 * Get the length of the raster header...
568 if (r
->sync
== CUPS_RASTER_SYNCv1
|| r
->sync
== CUPS_RASTER_REVSYNCv1
)
569 len
= sizeof(cups_page_header_t
);
571 len
= sizeof(cups_page_header2_t
);
577 memset(&(r
->header
), 0, sizeof(r
->header
));
579 if (cups_raster_read(r
, (unsigned char *)&(r
->header
), len
) < len
)
583 * Swap bytes as needed...
587 for (len
= 81, s
= (union swap_s
*)&(r
->header
.AdvanceDistance
);
590 s
->v
= (((((s
->b
[3] << 8) | s
->b
[2]) << 8) | s
->b
[1]) << 8) | s
->b
[0];
593 * Update the header and row count...
596 cups_raster_update(r
);
603 * 'cups_raster_read()' - Read through the raster buffer.
606 static int /* O - Number of bytes read */
607 cups_raster_read(cups_raster_t
*r
, /* I - Raster stream */
608 unsigned char *buf
, /* I - Buffer */
609 int bytes
) /* I - Number of bytes to read */
611 int count
, /* Number of bytes read */
612 remaining
, /* Remaining bytes in buffer */
613 total
; /* Total bytes read */
616 DEBUG_printf(("cups_raster_read(r=%p, buf=%p, bytes=%d)\n", r
, buf
, bytes
));
619 return (cups_read(r
->fd
, buf
, bytes
));
622 * Allocate a read buffer as needed...
625 count
= 2 * r
->header
.cupsBytesPerLine
;
627 if (count
> r
->bufsize
)
629 int offset
= r
->bufptr
- r
->buffer
; /* Offset to current start of buffer */
630 int end
= r
->bufend
- r
->buffer
; /* Offset to current end of buffer */
631 unsigned char *rptr
; /* Pointer in read buffer */
634 rptr
= realloc(r
->buffer
, count
);
636 rptr
= malloc(count
);
642 r
->bufptr
= rptr
+ offset
;
643 r
->bufend
= rptr
+ end
;
648 * Loop until we have read everything...
651 for (total
= 0, remaining
= r
->bufend
- r
->bufptr
;
653 total
+= count
, buf
+= count
)
655 count
= bytes
- total
;
657 DEBUG_printf(("count=%d, remaining=%d, buf=%p, bufptr=%p, bufend=%p...\n",
658 count
, remaining
, buf
, r
->bufptr
, r
->bufend
));
665 * Read into the raster buffer and then copy...
668 remaining
= cups_read(r
->fd
, r
->buffer
, r
->bufsize
);
672 r
->bufptr
= r
->buffer
;
673 r
->bufend
= r
->buffer
+ remaining
;
678 * Read directly into "buf"...
681 count
= cups_read(r
->fd
, buf
, count
);
691 * Copy bytes from raster buffer to "buf"...
694 if (count
> remaining
)
703 *buf
= *(r
->bufptr
)++;
706 else if (count
< 128)
709 * Copy up to 127 bytes without using memcpy(); this is
710 * faster because it avoids an extra function call and is
711 * often further optimized by the compiler...
714 unsigned char *bufptr
; /* Temporary buffer pointer */
719 for (bufptr
= r
->bufptr
; count
> 0; count
--, total
++)
727 * Use memcpy() for a large read...
730 memcpy(buf
, r
->bufptr
, count
);
741 * 'cups_raster_update()' - Update the raster header and row count for the
746 cups_raster_update(cups_raster_t
*r
) /* I - Raster stream */
748 if (r
->sync
== CUPS_RASTER_SYNCv1
|| r
->sync
== CUPS_RASTER_REVSYNCv1
||
749 r
->header
.cupsNumColors
== 0)
752 * Set the "cupsNumColors" field according to the colorspace...
755 switch (r
->header
.cupsColorSpace
)
759 case CUPS_CSPACE_WHITE
:
760 case CUPS_CSPACE_GOLD
:
761 case CUPS_CSPACE_SILVER
:
762 r
->header
.cupsNumColors
= 1;
765 case CUPS_CSPACE_RGB
:
766 case CUPS_CSPACE_CMY
:
767 case CUPS_CSPACE_YMC
:
768 case CUPS_CSPACE_CIEXYZ
:
769 case CUPS_CSPACE_CIELab
:
770 case CUPS_CSPACE_ICC1
:
771 case CUPS_CSPACE_ICC2
:
772 case CUPS_CSPACE_ICC3
:
773 case CUPS_CSPACE_ICC4
:
774 case CUPS_CSPACE_ICC5
:
775 case CUPS_CSPACE_ICC6
:
776 case CUPS_CSPACE_ICC7
:
777 case CUPS_CSPACE_ICC8
:
778 case CUPS_CSPACE_ICC9
:
779 case CUPS_CSPACE_ICCA
:
780 case CUPS_CSPACE_ICCB
:
781 case CUPS_CSPACE_ICCC
:
782 case CUPS_CSPACE_ICCD
:
783 case CUPS_CSPACE_ICCE
:
784 case CUPS_CSPACE_ICCF
:
785 r
->header
.cupsNumColors
= 3;
788 case CUPS_CSPACE_RGBA
:
789 case CUPS_CSPACE_RGBW
:
790 case CUPS_CSPACE_CMYK
:
791 case CUPS_CSPACE_YMCK
:
792 case CUPS_CSPACE_KCMY
:
793 case CUPS_CSPACE_GMCK
:
794 case CUPS_CSPACE_GMCS
:
795 r
->header
.cupsNumColors
= 4;
798 case CUPS_CSPACE_KCMYcm
:
799 if (r
->header
.cupsBitsPerPixel
< 8)
800 r
->header
.cupsNumColors
= 6;
802 r
->header
.cupsNumColors
= 4;
808 * Set the number of bytes per pixel/color...
811 if (r
->header
.cupsColorOrder
== CUPS_ORDER_CHUNKED
)
812 r
->bpp
= (r
->header
.cupsBitsPerPixel
+ 7) / 8;
814 r
->bpp
= (r
->header
.cupsBitsPerColor
+ 7) / 8;
817 * Set the number of remaining rows...
820 if (r
->header
.cupsColorOrder
== CUPS_ORDER_PLANAR
)
821 r
->remaining
= r
->header
.cupsHeight
* r
->header
.cupsNumColors
;
823 r
->remaining
= r
->header
.cupsHeight
;
826 * Allocate the compression buffer...
831 if (r
->pixels
!= NULL
)
834 r
->pixels
= calloc(r
->header
.cupsBytesPerLine
, 1);
835 r
->pcurrent
= r
->pixels
;
836 r
->pend
= r
->pixels
+ r
->header
.cupsBytesPerLine
;
843 * 'cups_read()' - Read bytes from a file.
846 static int /* O - Bytes read or -1 */
847 cups_read(int fd
, /* I - File descriptor */
848 unsigned char *buf
, /* I - Buffer for read */
849 int bytes
) /* I - Number of bytes to read */
851 int count
, /* Number of bytes read */
852 total
; /* Total bytes read */
855 for (total
= 0; total
< bytes
; total
+= count
, buf
+= count
)
857 count
= read(fd
, buf
, bytes
- total
);
875 * 'cups_swap()' - Swap bytes in raster data...
879 cups_swap(unsigned char *buf
, /* I - Buffer to swap */
880 int bytes
) /* I - Number of bytes to swap */
882 unsigned char even
, odd
; /* Temporary variables */
901 * 'cups_write()' - Write bytes to a file.
904 static int /* O - Bytes written or -1 */
905 cups_write(int fd
, /* I - File descriptor */
906 const unsigned char *buf
, /* I - Bytes to write */
907 int bytes
) /* I - Number of bytes to write */
909 int count
, /* Number of bytes written */
910 total
; /* Total bytes written */
913 for (total
= 0; total
< bytes
; total
+= count
, buf
+= count
)
915 count
= write(fd
, buf
, bytes
- total
);
931 * End of "$Id: raster.c 6061 2006-10-23 00:26:52Z mike $".