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