2 * "$Id: raster.c 7720 2008-07-11 22:46:21Z mike $"
4 * Raster file routines for CUPS.
6 * Copyright 2007-2012 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products.
9 * This file is part of the CUPS Imaging library.
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/".
17 * This file is subject to the Apple OS-Developed Software exception.
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
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.
45 * Include necessary headers...
48 #include <cups/raster-private.h>
52 * Private structures...
55 struct _cups_raster_s
/**** Raster stream data ****/
57 unsigned sync
; /* Sync word from start of stream */
58 void *ctx
; /* File descriptor */
59 cups_raster_iocb_t iocb
; /* IO callback */
60 cups_mode_t mode
; /* Read/write mode */
61 cups_page_header2_t header
; /* Raster header for current page */
62 int count
, /* Current row run-length count */
63 remaining
, /* Remaining rows in page image */
64 bpp
; /* Bytes per pixel/color */
65 unsigned char *pixels
, /* Pixels for current row */
66 *pend
, /* End of pixel buffer */
67 *pcurrent
; /* Current byte in pixel buffer */
68 int compressed
, /* Non-zero if data is compressed */
69 swapped
; /* Non-zero if data is byte-swapped */
70 unsigned char *buffer
, /* Read/write buffer */
71 *bufptr
, /* Current (read) position in buffer */
72 *bufend
; /* End of current (read) buffer */
73 size_t bufsize
; /* Buffer size */
81 static int cups_raster_io(cups_raster_t
*r
, unsigned char *buf
, int bytes
);
82 static unsigned cups_raster_read_header(cups_raster_t
*r
);
83 static int cups_raster_read(cups_raster_t
*r
, unsigned char *buf
,
85 static void cups_raster_update(cups_raster_t
*r
);
86 static int cups_raster_write(cups_raster_t
*r
,
87 const unsigned char *pixels
);
88 static ssize_t
cups_read_fd(void *ctx
, unsigned char *buf
, size_t bytes
);
89 static void cups_swap(unsigned char *buf
, int bytes
);
90 static ssize_t
cups_write_fd(void *ctx
, unsigned char *buf
, size_t bytes
);
94 * 'cupsRasterClose()' - Close a raster stream.
96 * The file descriptor associated with the raster stream must be closed
97 * separately as needed.
101 cupsRasterClose(cups_raster_t
*r
) /* I - Stream to close */
117 * 'cupsRasterOpen()' - Open a raster stream using a file descriptor.
119 * This function associates a raster stream with the given file descriptor.
120 * For most printer driver filters, "fd" will be 0 (stdin). For most raster
121 * image processor (RIP) filters that generate raster data, "fd" will be 1
124 * When writing raster data, the @code CUPS_RASTER_WRITE@,
125 * @code CUPS_RASTER_WRITE_COMPRESS@, or @code CUPS_RASTER_WRITE_PWG@ mode can
126 * be used - compressed and PWG output is generally 25-50% smaller but adds a
127 * 100-300% execution time overhead.
130 cups_raster_t
* /* O - New stream */
131 cupsRasterOpen(int fd
, /* I - File descriptor */
132 cups_mode_t mode
) /* I - Mode - @code CUPS_RASTER_READ@,
133 @code CUPS_RASTER_WRITE@,
134 @code CUPS_RASTER_WRITE_COMPRESSED@,
135 or @code CUPS_RASTER_WRITE_PWG@ */
137 if (mode
== CUPS_RASTER_READ
)
138 return (cupsRasterOpenIO(cups_read_fd
, (void *)((intptr_t)fd
), mode
));
140 return (cupsRasterOpenIO(cups_write_fd
, (void *)((intptr_t)fd
), mode
));
145 * 'cupsRasterOpenIO()' - Open a raster stream using a callback function.
147 * This function associates a raster stream with the given callback function and
150 * When writing raster data, the @code CUPS_RASTER_WRITE@,
151 * @code CUPS_RASTER_WRITE_COMPRESS@, or @code CUPS_RASTER_WRITE_PWG@ mode can
152 * be used - compressed and PWG output is generally 25-50% smaller but adds a
153 * 100-300% execution time overhead.
156 cups_raster_t
* /* O - New stream */
158 cups_raster_iocb_t iocb
, /* I - Read/write callback */
159 void *ctx
, /* I - Context pointer for callback */
160 cups_mode_t mode
) /* I - Mode - @code CUPS_RASTER_READ@,
161 @code CUPS_RASTER_WRITE@,
162 @code CUPS_RASTER_WRITE_COMPRESSED@,
163 or @code CUPS_RASTER_WRITE_PWG@ */
165 cups_raster_t
*r
; /* New stream */
168 _cupsRasterClearError();
170 if ((r
= calloc(sizeof(cups_raster_t
), 1)) == NULL
)
172 _cupsRasterAddError("Unable to allocate memory for raster stream: %s\n",
181 if (mode
== CUPS_RASTER_READ
)
184 * Open for read - get sync word...
187 if (cups_raster_io(r
, (unsigned char *)&(r
->sync
), sizeof(r
->sync
)) !=
190 _cupsRasterAddError("Unable to read header from raster stream: %s\n",
196 if (r
->sync
!= CUPS_RASTER_SYNC
&&
197 r
->sync
!= CUPS_RASTER_REVSYNC
&&
198 r
->sync
!= CUPS_RASTER_SYNCv1
&&
199 r
->sync
!= CUPS_RASTER_REVSYNCv1
&&
200 r
->sync
!= CUPS_RASTER_SYNCv2
&&
201 r
->sync
!= CUPS_RASTER_REVSYNCv2
)
203 _cupsRasterAddError("Unknown raster format %08x!\n", r
->sync
);
208 if (r
->sync
== CUPS_RASTER_SYNCv2
||
209 r
->sync
== CUPS_RASTER_REVSYNCv2
)
212 if (r
->sync
== CUPS_RASTER_REVSYNC
||
213 r
->sync
== CUPS_RASTER_REVSYNCv1
||
214 r
->sync
== CUPS_RASTER_REVSYNCv2
)
217 DEBUG_printf(("r->swapped=%d, r->sync=%08x\n", r
->swapped
, r
->sync
));
222 * Open for write - put sync word...
228 case CUPS_RASTER_WRITE
:
229 r
->sync
= CUPS_RASTER_SYNC
;
232 case CUPS_RASTER_WRITE_COMPRESSED
:
234 r
->sync
= CUPS_RASTER_SYNCv2
;
237 case CUPS_RASTER_WRITE_PWG
:
239 r
->sync
= htonl(CUPS_RASTER_SYNC_PWG
);
240 r
->swapped
= r
->sync
!= CUPS_RASTER_SYNC_PWG
;
244 if (cups_raster_io(r
, (unsigned char *)&(r
->sync
), sizeof(r
->sync
))
247 _cupsRasterAddError("Unable to write raster stream header: %s\n",
259 * 'cupsRasterReadHeader()' - Read a raster page header and store it in a
260 * version 1 page header structure.
262 * This function is deprecated. Use @link cupsRasterReadHeader2@ instead.
264 * Version 1 page headers were used in CUPS 1.0 and 1.1 and contain a subset
265 * of the version 2 page header data. This function handles reading version 2
266 * page headers and copying only the version 1 data into the provided buffer.
271 unsigned /* O - 1 on success, 0 on failure/end-of-file */
272 cupsRasterReadHeader(
273 cups_raster_t
*r
, /* I - Raster stream */
274 cups_page_header_t
*h
) /* I - Pointer to header data */
277 * Get the raster header...
280 if (!cups_raster_read_header(r
))
284 * Copy the header to the user-supplied buffer...
287 memcpy(h
, &(r
->header
), sizeof(cups_page_header_t
));
294 * 'cupsRasterReadHeader2()' - Read a raster page header and store it in a
295 * version 2 page header structure.
297 * @since CUPS 1.2/OS X 10.5@
300 unsigned /* O - 1 on success, 0 on failure/end-of-file */
301 cupsRasterReadHeader2(
302 cups_raster_t
*r
, /* I - Raster stream */
303 cups_page_header2_t
*h
) /* I - Pointer to header data */
306 * Get the raster header...
309 if (!cups_raster_read_header(r
))
313 * Copy the header to the user-supplied buffer...
316 memcpy(h
, &(r
->header
), sizeof(cups_page_header2_t
));
323 * 'cupsRasterReadPixels()' - Read raster pixels.
325 * For best performance, filters should read one or more whole lines.
326 * The "cupsBytesPerLine" value from the page header can be used to allocate
327 * the line buffer and as the number of bytes to read.
330 unsigned /* O - Number of bytes read */
331 cupsRasterReadPixels(cups_raster_t
*r
, /* I - Raster stream */
332 unsigned char *p
, /* I - Pointer to pixel buffer */
333 unsigned len
) /* I - Number of bytes to read */
335 int bytes
; /* Bytes read */
336 unsigned cupsBytesPerLine
; /* cupsBytesPerLine value */
337 unsigned remaining
; /* Bytes remaining */
338 unsigned char *ptr
, /* Pointer to read buffer */
339 byte
, /* Byte from file */
340 *temp
; /* Pointer into buffer */
341 int count
; /* Repetition count */
344 if (r
== NULL
|| r
->mode
!= CUPS_RASTER_READ
|| r
->remaining
== 0 ||
345 r
->header
.cupsBytesPerLine
== 0)
351 * Read without compression...
354 r
->remaining
-= len
/ r
->header
.cupsBytesPerLine
;
356 if (cups_raster_io(r
, p
, len
) < (ssize_t
)len
)
360 * Swap bytes as needed...
364 (r
->header
.cupsBitsPerColor
== 16 ||
365 r
->header
.cupsBitsPerPixel
== 12 ||
366 r
->header
.cupsBitsPerPixel
== 16))
377 * Read compressed data...
381 cupsBytesPerLine
= r
->header
.cupsBytesPerLine
;
383 while (remaining
> 0 && r
->remaining
> 0)
388 * Need to read a new row...
391 if (remaining
== cupsBytesPerLine
)
397 * Read using a modified PackBits compression...
400 if (!cups_raster_read(r
, &byte
, 1))
409 bytes
= cupsBytesPerLine
;
414 * Get a new repeat count...
417 if (!cups_raster_read(r
, &byte
, 1))
423 * Copy N literal pixels...
426 count
= (257 - byte
) * r
->bpp
;
431 if (!cups_raster_read(r
, temp
, count
))
440 * Repeat the next N bytes...
443 count
= (byte
+ 1) * r
->bpp
;
452 if (!cups_raster_read(r
, temp
, r
->bpp
))
460 memcpy(temp
, temp
- r
->bpp
, r
->bpp
);
468 * Swap bytes as needed...
471 if ((r
->header
.cupsBitsPerColor
== 16 ||
472 r
->header
.cupsBitsPerPixel
== 12 ||
473 r
->header
.cupsBitsPerPixel
== 16) &&
475 cups_swap(ptr
, bytes
);
481 if (remaining
>= cupsBytesPerLine
)
483 bytes
= cupsBytesPerLine
;
484 r
->pcurrent
= r
->pixels
;
491 r
->pcurrent
= r
->pixels
+ bytes
;
495 * Copy data as needed...
499 memcpy(p
, ptr
, bytes
);
504 * Copy fragment from buffer...
507 if ((unsigned)(bytes
= (int)(r
->pend
- r
->pcurrent
)) > remaining
)
510 memcpy(p
, r
->pcurrent
, bytes
);
511 r
->pcurrent
+= bytes
;
513 if (r
->pcurrent
>= r
->pend
)
515 r
->pcurrent
= r
->pixels
;
530 * 'cupsRasterWriteHeader()' - Write a raster page header from a version 1 page
533 * This function is deprecated. Use @link cupsRasterWriteHeader2@ instead.
538 unsigned /* O - 1 on success, 0 on failure */
539 cupsRasterWriteHeader(
540 cups_raster_t
*r
, /* I - Raster stream */
541 cups_page_header_t
*h
) /* I - Raster page header */
543 if (r
== NULL
|| r
->mode
== CUPS_RASTER_READ
)
547 * Make a copy of the header, and compute the number of raster
548 * lines in the page image...
551 memset(&(r
->header
), 0, sizeof(r
->header
));
552 memcpy(&(r
->header
), h
, sizeof(cups_page_header_t
));
554 cups_raster_update(r
);
557 * Write the raster header...
560 if (r
->mode
== CUPS_RASTER_WRITE_PWG
)
563 * PWG raster data is always network byte order with much of the page header
567 cups_page_header2_t fh
; /* File page header */
569 memset(&fh
, 0, sizeof(fh
));
571 strlcpy(fh
.MediaClass
, "PwgRaster", sizeof(fh
.MediaClass
));
573 strlcpy(fh
.MediaColor
, r
->header
.MediaColor
, sizeof(fh
.MediaColor
));
574 strlcpy(fh
.MediaType
, r
->header
.MediaType
, sizeof(fh
.MediaType
));
575 strlcpy(fh
.OutputType
, r
->header
.OutputType
, sizeof(fh
.OutputType
));
576 /* PrintContentType */
578 fh
.CutMedia
= htonl(r
->header
.CutMedia
);
579 fh
.Duplex
= htonl(r
->header
.Duplex
);
580 fh
.HWResolution
[0] = htonl(r
->header
.HWResolution
[0]);
581 fh
.HWResolution
[1] = htonl(r
->header
.HWResolution
[1]);
582 fh
.ImagingBoundingBox
[0] = htonl(r
->header
.ImagingBoundingBox
[0]);
583 fh
.ImagingBoundingBox
[1] = htonl(r
->header
.ImagingBoundingBox
[1]);
584 fh
.ImagingBoundingBox
[2] = htonl(r
->header
.ImagingBoundingBox
[2]);
585 fh
.ImagingBoundingBox
[3] = htonl(r
->header
.ImagingBoundingBox
[3]);
586 fh
.InsertSheet
= htonl(r
->header
.InsertSheet
);
587 fh
.Jog
= htonl(r
->header
.Jog
);
588 fh
.LeadingEdge
= htonl(r
->header
.LeadingEdge
);
589 fh
.ManualFeed
= htonl(r
->header
.ManualFeed
);
590 fh
.MediaPosition
= htonl(r
->header
.MediaPosition
);
591 fh
.MediaWeight
= htonl(r
->header
.MediaWeight
);
592 fh
.NumCopies
= htonl(r
->header
.NumCopies
);
593 fh
.Orientation
= htonl(r
->header
.Orientation
);
594 fh
.PageSize
[0] = htonl(r
->header
.PageSize
[0]);
595 fh
.PageSize
[1] = htonl(r
->header
.PageSize
[1]);
596 fh
.Tumble
= htonl(r
->header
.Tumble
);
597 fh
.cupsWidth
= htonl(r
->header
.cupsWidth
);
598 fh
.cupsHeight
= htonl(r
->header
.cupsHeight
);
599 fh
.cupsBitsPerColor
= htonl(r
->header
.cupsBitsPerColor
);
600 fh
.cupsBitsPerPixel
= htonl(r
->header
.cupsBitsPerPixel
);
601 fh
.cupsBytesPerLine
= htonl(r
->header
.cupsBytesPerLine
);
602 fh
.cupsColorOrder
= htonl(r
->header
.cupsColorOrder
);
603 fh
.cupsColorSpace
= htonl(r
->header
.cupsColorSpace
);
604 fh
.cupsNumColors
= htonl(r
->header
.cupsNumColors
);
605 fh
.cupsInteger
[0] = htonl(r
->header
.cupsInteger
[0]);
607 fh
.cupsInteger
[1] = htonl(r
->header
.cupsInteger
[1]);
608 /* CrossFeedTransform */
609 fh
.cupsInteger
[2] = htonl(r
->header
.cupsInteger
[2]);
611 fh
.cupsInteger
[3] = htonl(r
->header
.cupsInteger
[3]);
613 fh
.cupsInteger
[4] = htonl(r
->header
.cupsInteger
[4]);
615 fh
.cupsInteger
[5] = htonl(r
->header
.cupsInteger
[5]);
617 fh
.cupsInteger
[6] = htonl(r
->header
.cupsInteger
[6]);
619 fh
.cupsInteger
[7] = htonl(r
->header
.cupsInteger
[7]);
621 fh
.cupsInteger
[8] = htonl(r
->header
.cupsInteger
[8]);
623 fh
.cupsInteger
[14] = htonl(r
->header
.cupsInteger
[14]);
624 /* VendorIdentifier */
625 fh
.cupsInteger
[15] = htonl(r
->header
.cupsInteger
[15]);
628 memcpy(fh
.cupsReal
, r
->header
.cupsReal
,
629 sizeof(fh
.cupsReal
) + sizeof(fh
.cupsString
));
632 strlcpy(fh
.cupsRenderingIntent
, r
->header
.cupsRenderingIntent
,
633 sizeof(fh
.cupsRenderingIntent
));
634 strlcpy(fh
.cupsPageSizeName
, r
->header
.cupsPageSizeName
,
635 sizeof(fh
.cupsPageSizeName
));
637 return (cups_raster_io(r
, (unsigned char *)&fh
, sizeof(fh
)) == sizeof(fh
));
640 return (cups_raster_io(r
, (unsigned char *)&(r
->header
), sizeof(r
->header
))
641 == sizeof(r
->header
));
646 * 'cupsRasterWriteHeader2()' - Write a raster page header from a version 2
647 * page header structure.
649 * The page header can be initialized using @link cupsRasterInterpretPPD@.
651 * @since CUPS 1.2/OS X 10.5@
654 unsigned /* O - 1 on success, 0 on failure */
655 cupsRasterWriteHeader2(
656 cups_raster_t
*r
, /* I - Raster stream */
657 cups_page_header2_t
*h
) /* I - Raster page header */
659 if (r
== NULL
|| r
->mode
== CUPS_RASTER_READ
)
663 * Make a copy of the header, and compute the number of raster
664 * lines in the page image...
667 memcpy(&(r
->header
), h
, sizeof(cups_page_header2_t
));
669 cups_raster_update(r
);
672 * Write the raster header...
675 if (r
->mode
== CUPS_RASTER_WRITE_PWG
)
678 * PWG raster data is always network byte order with most of the page header
682 cups_page_header2_t fh
; /* File page header */
684 memset(&fh
, 0, sizeof(fh
));
685 strlcpy(fh
.MediaClass
, "PwgRaster", sizeof(fh
.MediaClass
));
686 strlcpy(fh
.MediaColor
, r
->header
.MediaColor
, sizeof(fh
.MediaColor
));
687 strlcpy(fh
.MediaType
, r
->header
.MediaType
, sizeof(fh
.MediaType
));
688 strlcpy(fh
.OutputType
, r
->header
.OutputType
, sizeof(fh
.OutputType
));
689 strlcpy(fh
.cupsRenderingIntent
, r
->header
.cupsRenderingIntent
,
690 sizeof(fh
.cupsRenderingIntent
));
691 strlcpy(fh
.cupsPageSizeName
, r
->header
.cupsPageSizeName
,
692 sizeof(fh
.cupsPageSizeName
));
694 fh
.CutMedia
= htonl(r
->header
.CutMedia
);
695 fh
.Duplex
= htonl(r
->header
.Duplex
);
696 fh
.HWResolution
[0] = htonl(r
->header
.HWResolution
[0]);
697 fh
.HWResolution
[1] = htonl(r
->header
.HWResolution
[1]);
698 fh
.ImagingBoundingBox
[0] = htonl(r
->header
.ImagingBoundingBox
[0]);
699 fh
.ImagingBoundingBox
[1] = htonl(r
->header
.ImagingBoundingBox
[1]);
700 fh
.ImagingBoundingBox
[2] = htonl(r
->header
.ImagingBoundingBox
[2]);
701 fh
.ImagingBoundingBox
[3] = htonl(r
->header
.ImagingBoundingBox
[3]);
702 fh
.InsertSheet
= htonl(r
->header
.InsertSheet
);
703 fh
.Jog
= htonl(r
->header
.Jog
);
704 fh
.LeadingEdge
= htonl(r
->header
.LeadingEdge
);
705 fh
.ManualFeed
= htonl(r
->header
.ManualFeed
);
706 fh
.MediaPosition
= htonl(r
->header
.MediaPosition
);
707 fh
.MediaWeight
= htonl(r
->header
.MediaWeight
);
708 fh
.NumCopies
= htonl(r
->header
.NumCopies
);
709 fh
.Orientation
= htonl(r
->header
.Orientation
);
710 fh
.PageSize
[0] = htonl(r
->header
.PageSize
[0]);
711 fh
.PageSize
[1] = htonl(r
->header
.PageSize
[1]);
712 fh
.Tumble
= htonl(r
->header
.Tumble
);
713 fh
.cupsWidth
= htonl(r
->header
.cupsWidth
);
714 fh
.cupsHeight
= htonl(r
->header
.cupsHeight
);
715 fh
.cupsBitsPerColor
= htonl(r
->header
.cupsBitsPerColor
);
716 fh
.cupsBitsPerPixel
= htonl(r
->header
.cupsBitsPerPixel
);
717 fh
.cupsBytesPerLine
= htonl(r
->header
.cupsBytesPerLine
);
718 fh
.cupsColorOrder
= htonl(r
->header
.cupsColorOrder
);
719 fh
.cupsColorSpace
= htonl(r
->header
.cupsColorSpace
);
720 fh
.cupsNumColors
= htonl(r
->header
.cupsNumColors
);
721 fh
.cupsInteger
[0] = htonl(r
->header
.cupsInteger
[0]);
722 fh
.cupsInteger
[1] = htonl(r
->header
.cupsInteger
[1]);
723 fh
.cupsInteger
[2] = htonl(r
->header
.cupsInteger
[2]);
724 fh
.cupsInteger
[3] = htonl((unsigned)(r
->header
.cupsImagingBBox
[0] *
725 r
->header
.HWResolution
[0]));
726 fh
.cupsInteger
[4] = htonl((unsigned)(r
->header
.cupsImagingBBox
[1] *
727 r
->header
.HWResolution
[1]));
728 fh
.cupsInteger
[5] = htonl((unsigned)(r
->header
.cupsImagingBBox
[2] *
729 r
->header
.HWResolution
[0]));
730 fh
.cupsInteger
[6] = htonl((unsigned)(r
->header
.cupsImagingBBox
[3] *
731 r
->header
.HWResolution
[1]));
732 fh
.cupsInteger
[7] = htonl(0xffffff);
734 return (cups_raster_io(r
, (unsigned char *)&fh
, sizeof(fh
)) == sizeof(fh
));
737 return (cups_raster_io(r
, (unsigned char *)&(r
->header
), sizeof(r
->header
))
738 == sizeof(r
->header
));
743 * 'cupsRasterWritePixels()' - Write raster pixels.
745 * For best performance, filters should write one or more whole lines.
746 * The "cupsBytesPerLine" value from the page header can be used to allocate
747 * the line buffer and as the number of bytes to write.
750 unsigned /* O - Number of bytes written */
751 cupsRasterWritePixels(cups_raster_t
*r
, /* I - Raster stream */
752 unsigned char *p
, /* I - Bytes to write */
753 unsigned len
)/* I - Number of bytes to write */
755 int bytes
; /* Bytes read */
756 unsigned remaining
; /* Bytes remaining */
759 DEBUG_printf(("cupsRasterWritePixels(r=%p, p=%p, len=%u), remaining=%u\n",
760 r
, p
, len
, r
->remaining
));
762 if (r
== NULL
|| r
->mode
== CUPS_RASTER_READ
|| r
->remaining
== 0)
768 * Without compression, just write the raster data raw unless the data needs
772 r
->remaining
-= len
/ r
->header
.cupsBytesPerLine
;
775 (r
->header
.cupsBitsPerColor
== 16 ||
776 r
->header
.cupsBitsPerPixel
== 12 ||
777 r
->header
.cupsBitsPerPixel
== 16))
779 unsigned char *bufptr
; /* Pointer into write buffer */
780 unsigned count
; /* Remaining count */
783 * Allocate a write buffer as needed...
786 if ((size_t)len
> r
->bufsize
)
789 bufptr
= realloc(r
->buffer
, len
);
791 bufptr
= malloc(len
);
801 * Byte swap the pixels...
804 for (bufptr
= r
->buffer
, count
= len
; count
> 1; count
-= 2, bufptr
+= 2)
810 if (count
) /* This should never happen... */
814 * Write the byte-swapped buffer...
817 return (cups_raster_io(r
, r
->buffer
, len
));
820 return (cups_raster_io(r
, p
, len
));
824 * Otherwise, compress each line...
827 for (remaining
= len
; remaining
> 0; remaining
-= bytes
, p
+= bytes
)
830 * Figure out the number of remaining bytes on the current line...
833 if ((bytes
= remaining
) > (int)(r
->pend
- r
->pcurrent
))
834 bytes
= (int)(r
->pend
- r
->pcurrent
);
839 * Check to see if this line is the same as the previous line...
842 if (memcmp(p
, r
->pcurrent
, bytes
))
844 if (!cups_raster_write(r
, r
->pixels
))
852 * Mark more bytes as the same...
855 r
->pcurrent
+= bytes
;
857 if (r
->pcurrent
>= r
->pend
)
860 * Increase the repeat count...
864 r
->pcurrent
= r
->pixels
;
867 * Flush out this line if it is the last one...
872 if (r
->remaining
== 0)
873 return (cups_raster_write(r
, r
->pixels
));
874 else if (r
->count
== 256)
876 if (cups_raster_write(r
, r
->pixels
) == 0)
890 * Copy the raster data to the buffer...
893 memcpy(r
->pcurrent
, p
, bytes
);
895 r
->pcurrent
+= bytes
;
897 if (r
->pcurrent
>= r
->pend
)
900 * Increase the repeat count...
904 r
->pcurrent
= r
->pixels
;
907 * Flush out this line if it is the last one...
912 if (r
->remaining
== 0)
913 return (cups_raster_write(r
, r
->pixels
));
923 * 'cups_raster_read_header()' - Read a raster page header.
926 static unsigned /* O - 1 on success, 0 on fail */
927 cups_raster_read_header(
928 cups_raster_t
*r
) /* I - Raster stream */
930 int len
; /* Length for read/swap */
933 if (r
== NULL
|| r
->mode
!= CUPS_RASTER_READ
)
937 * Get the length of the raster header...
940 if (r
->sync
== CUPS_RASTER_SYNCv1
|| r
->sync
== CUPS_RASTER_REVSYNCv1
)
941 len
= sizeof(cups_page_header_t
);
943 len
= sizeof(cups_page_header2_t
);
949 memset(&(r
->header
), 0, sizeof(r
->header
));
951 if (cups_raster_read(r
, (unsigned char *)&(r
->header
), len
) < len
)
955 * Swap bytes as needed...
960 unsigned *s
, /* Current word */
961 temp
; /* Temporary copy */
964 DEBUG_puts("Swapping header bytes...");
966 for (len
= 81, s
= &(r
->header
.AdvanceDistance
);
970 DEBUG_printf(("%08x =>", *s
));
973 *s
= ((temp
& 0xff) << 24) |
974 ((temp
& 0xff00) << 8) |
975 ((temp
& 0xff0000) >> 8) |
976 ((temp
& 0xff000000) >> 24);
978 DEBUG_printf((" %08x\n", *s
));
983 * Update the header and row count...
986 cups_raster_update(r
);
988 return (r
->header
.cupsBytesPerLine
!= 0 && r
->header
.cupsHeight
!= 0);
993 * 'cups_raster_io()' - Read/write bytes from a context, handling interruptions.
996 static int /* O - Bytes read or -1 */
997 cups_raster_io(cups_raster_t
*r
, /* I - Raster stream */
998 unsigned char *buf
, /* I - Buffer for read/write */
999 int bytes
) /* I - Number of bytes to read/write */
1001 ssize_t count
; /* Number of bytes read/written */
1002 size_t total
; /* Total bytes read/written */
1005 DEBUG_printf(("4cups_raster_io(r=%p, buf=%p, bytes=%d)", r
, buf
, bytes
));
1007 for (total
= 0; total
< (size_t)bytes
; total
+= count
, buf
+= count
)
1009 count
= (*r
->iocb
)(r
->ctx
, buf
, bytes
- total
);
1011 DEBUG_printf(("5cups_raster_io: count=%d, total=%d", (int)count
,
1019 return ((int)total
);
1024 * 'cups_raster_read()' - Read through the raster buffer.
1027 static int /* O - Number of bytes read */
1028 cups_raster_read(cups_raster_t
*r
, /* I - Raster stream */
1029 unsigned char *buf
, /* I - Buffer */
1030 int bytes
) /* I - Number of bytes to read */
1032 int count
, /* Number of bytes read */
1033 remaining
, /* Remaining bytes in buffer */
1034 total
; /* Total bytes read */
1037 DEBUG_printf(("cups_raster_read(r=%p, buf=%p, bytes=%d)\n", r
, buf
, bytes
));
1040 return (cups_raster_io(r
, buf
, bytes
));
1043 * Allocate a read buffer as needed...
1046 count
= 2 * r
->header
.cupsBytesPerLine
;
1048 if ((size_t)count
> r
->bufsize
)
1050 int offset
= (int)(r
->bufptr
- r
->buffer
);
1051 /* Offset to current start of buffer */
1052 int end
= (int)(r
->bufend
- r
->buffer
);
1053 /* Offset to current end of buffer */
1054 unsigned char *rptr
; /* Pointer in read buffer */
1057 rptr
= realloc(r
->buffer
, count
);
1059 rptr
= malloc(count
);
1065 r
->bufptr
= rptr
+ offset
;
1066 r
->bufend
= rptr
+ end
;
1071 * Loop until we have read everything...
1074 for (total
= 0, remaining
= (int)(r
->bufend
- r
->bufptr
);
1076 total
+= count
, buf
+= count
)
1078 count
= bytes
- total
;
1080 DEBUG_printf(("count=%d, remaining=%d, buf=%p, bufptr=%p, bufend=%p...\n",
1081 count
, remaining
, buf
, r
->bufptr
, r
->bufend
));
1088 * Read into the raster buffer and then copy...
1091 remaining
= (*r
->iocb
)(r
->ctx
, r
->buffer
, r
->bufsize
);
1095 r
->bufptr
= r
->buffer
;
1096 r
->bufend
= r
->buffer
+ remaining
;
1101 * Read directly into "buf"...
1104 count
= (*r
->iocb
)(r
->ctx
, buf
, count
);
1114 * Copy bytes from raster buffer to "buf"...
1117 if (count
> remaining
)
1126 *buf
= *(r
->bufptr
)++;
1129 else if (count
< 128)
1132 * Copy up to 127 bytes without using memcpy(); this is
1133 * faster because it avoids an extra function call and is
1134 * often further optimized by the compiler...
1137 unsigned char *bufptr
; /* Temporary buffer pointer */
1141 for (bufptr
= r
->bufptr
; count
> 0; count
--, total
++)
1149 * Use memcpy() for a large read...
1152 memcpy(buf
, r
->bufptr
, count
);
1163 * 'cups_raster_update()' - Update the raster header and row count for the
1168 cups_raster_update(cups_raster_t
*r
) /* I - Raster stream */
1170 if (r
->sync
== CUPS_RASTER_SYNCv1
|| r
->sync
== CUPS_RASTER_REVSYNCv1
||
1171 r
->header
.cupsNumColors
== 0)
1174 * Set the "cupsNumColors" field according to the colorspace...
1177 switch (r
->header
.cupsColorSpace
)
1179 case CUPS_CSPACE_W
:
1180 case CUPS_CSPACE_K
:
1181 case CUPS_CSPACE_WHITE
:
1182 case CUPS_CSPACE_GOLD
:
1183 case CUPS_CSPACE_SILVER
:
1184 case CUPS_CSPACE_SW
:
1185 r
->header
.cupsNumColors
= 1;
1188 case CUPS_CSPACE_RGB
:
1189 case CUPS_CSPACE_CMY
:
1190 case CUPS_CSPACE_YMC
:
1191 case CUPS_CSPACE_CIEXYZ
:
1192 case CUPS_CSPACE_CIELab
:
1193 case CUPS_CSPACE_SRGB
:
1194 case CUPS_CSPACE_ADOBERGB
:
1195 case CUPS_CSPACE_ICC1
:
1196 case CUPS_CSPACE_ICC2
:
1197 case CUPS_CSPACE_ICC3
:
1198 case CUPS_CSPACE_ICC4
:
1199 case CUPS_CSPACE_ICC5
:
1200 case CUPS_CSPACE_ICC6
:
1201 case CUPS_CSPACE_ICC7
:
1202 case CUPS_CSPACE_ICC8
:
1203 case CUPS_CSPACE_ICC9
:
1204 case CUPS_CSPACE_ICCA
:
1205 case CUPS_CSPACE_ICCB
:
1206 case CUPS_CSPACE_ICCC
:
1207 case CUPS_CSPACE_ICCD
:
1208 case CUPS_CSPACE_ICCE
:
1209 case CUPS_CSPACE_ICCF
:
1210 r
->header
.cupsNumColors
= 3;
1213 case CUPS_CSPACE_RGBA
:
1214 case CUPS_CSPACE_RGBW
:
1215 case CUPS_CSPACE_CMYK
:
1216 case CUPS_CSPACE_YMCK
:
1217 case CUPS_CSPACE_KCMY
:
1218 case CUPS_CSPACE_GMCK
:
1219 case CUPS_CSPACE_GMCS
:
1220 r
->header
.cupsNumColors
= 4;
1223 case CUPS_CSPACE_KCMYcm
:
1224 if (r
->header
.cupsBitsPerPixel
< 8)
1225 r
->header
.cupsNumColors
= 6;
1227 r
->header
.cupsNumColors
= 4;
1230 case CUPS_CSPACE_DEVICE1
:
1231 case CUPS_CSPACE_DEVICE2
:
1232 case CUPS_CSPACE_DEVICE3
:
1233 case CUPS_CSPACE_DEVICE4
:
1234 case CUPS_CSPACE_DEVICE5
:
1235 case CUPS_CSPACE_DEVICE6
:
1236 case CUPS_CSPACE_DEVICE7
:
1237 case CUPS_CSPACE_DEVICE8
:
1238 case CUPS_CSPACE_DEVICE9
:
1239 case CUPS_CSPACE_DEVICEA
:
1240 case CUPS_CSPACE_DEVICEB
:
1241 case CUPS_CSPACE_DEVICEC
:
1242 case CUPS_CSPACE_DEVICED
:
1243 case CUPS_CSPACE_DEVICEE
:
1244 case CUPS_CSPACE_DEVICEF
:
1245 r
->header
.cupsNumColors
= r
->header
.cupsColorSpace
-
1246 CUPS_CSPACE_DEVICE1
+ 1;
1252 * Set the number of bytes per pixel/color...
1255 if (r
->header
.cupsColorOrder
== CUPS_ORDER_CHUNKED
)
1256 r
->bpp
= (r
->header
.cupsBitsPerPixel
+ 7) / 8;
1258 r
->bpp
= (r
->header
.cupsBitsPerColor
+ 7) / 8;
1261 * Set the number of remaining rows...
1264 if (r
->header
.cupsColorOrder
== CUPS_ORDER_PLANAR
)
1265 r
->remaining
= r
->header
.cupsHeight
* r
->header
.cupsNumColors
;
1267 r
->remaining
= r
->header
.cupsHeight
;
1270 * Allocate the compression buffer...
1275 if (r
->pixels
!= NULL
)
1278 r
->pixels
= calloc(r
->header
.cupsBytesPerLine
, 1);
1279 r
->pcurrent
= r
->pixels
;
1280 r
->pend
= r
->pixels
+ r
->header
.cupsBytesPerLine
;
1287 * 'cups_raster_write()' - Write a row of compressed raster data...
1290 static int /* O - Number of bytes written */
1292 cups_raster_t
*r
, /* I - Raster stream */
1293 const unsigned char *pixels
) /* I - Pixel data to write */
1295 const unsigned char *start
, /* Start of sequence */
1296 *ptr
, /* Current pointer in sequence */
1297 *pend
, /* End of raster buffer */
1298 *plast
; /* Pointer to last pixel */
1299 unsigned char *wptr
; /* Pointer into write buffer */
1300 int bpp
, /* Bytes per pixel */
1304 DEBUG_printf(("cups_raster_write(r=%p, pixels=%p)\n", r
, pixels
));
1307 * Allocate a write buffer as needed...
1310 count
= r
->header
.cupsBytesPerLine
* 2;
1311 if ((size_t)count
> r
->bufsize
)
1314 wptr
= realloc(r
->buffer
, count
);
1316 wptr
= malloc(count
);
1326 * Write the row repeat count...
1330 pend
= pixels
+ r
->header
.cupsBytesPerLine
;
1333 *wptr
++ = r
->count
- 1;
1336 * Write using a modified PackBits compression...
1339 for (ptr
= pixels
; ptr
< pend
;)
1347 * Encode a single pixel at the end...
1351 for (count
= bpp
; count
> 0; count
--)
1354 else if (!memcmp(start
, ptr
, bpp
))
1357 * Encode a sequence of repeating pixels...
1360 for (count
= 2; count
< 128 && ptr
< plast
; count
++, ptr
+= bpp
)
1361 if (memcmp(ptr
, ptr
+ bpp
, bpp
))
1364 *wptr
++ = count
- 1;
1365 for (count
= bpp
; count
> 0; count
--)
1371 * Encode a sequence of non-repeating pixels...
1374 for (count
= 1; count
< 128 && ptr
< plast
; count
++, ptr
+= bpp
)
1375 if (!memcmp(ptr
, ptr
+ bpp
, bpp
))
1378 if (ptr
>= plast
&& count
< 128)
1384 *wptr
++ = 257 - count
;
1387 memcpy(wptr
, start
, count
);
1392 return (cups_raster_io(r
, r
->buffer
, (int)(wptr
- r
->buffer
)));
1397 * 'cups_read_fd()' - Read bytes from a file.
1400 static ssize_t
/* O - Bytes read or -1 */
1401 cups_read_fd(void *ctx
, /* I - File descriptor as pointer */
1402 unsigned char *buf
, /* I - Buffer for read */
1403 size_t bytes
) /* I - Maximum number of bytes to read */
1405 int fd
= (int)((intptr_t)ctx
);
1406 /* File descriptor */
1407 ssize_t count
; /* Number of bytes read */
1410 #ifdef WIN32 /* Sigh */
1411 while ((count
= read(fd
, buf
, (unsigned)bytes
)) < 0)
1413 while ((count
= read(fd
, buf
, bytes
)) < 0)
1415 if (errno
!= EINTR
&& errno
!= EAGAIN
)
1423 * 'cups_swap()' - Swap bytes in raster data...
1427 cups_swap(unsigned char *buf
, /* I - Buffer to swap */
1428 int bytes
) /* I - Number of bytes to swap */
1430 unsigned char even
, odd
; /* Temporary variables */
1449 * 'cups_write_fd()' - Write bytes to a file.
1452 static ssize_t
/* O - Bytes written or -1 */
1453 cups_write_fd(void *ctx
, /* I - File descriptor pointer */
1454 unsigned char *buf
, /* I - Bytes to write */
1455 size_t bytes
) /* I - Number of bytes to write */
1457 int fd
= (int)((intptr_t)ctx
);
1458 /* File descriptor */
1459 ssize_t count
; /* Number of bytes written */
1462 #ifdef WIN32 /* Sigh */
1463 while ((count
= write(fd
, buf
, (unsigned)bytes
)) < 0)
1465 while ((count
= write(fd
, buf
, bytes
)) < 0)
1467 if (errno
!= EINTR
&& errno
!= EAGAIN
)
1475 * End of "$Id: raster.c 7720 2008-07-11 22:46:21Z mike $".