Load cups into easysw/current.
[thirdparty/cups.git] / filter / raster.c
1 /*
2  * "$Id: raster.c 4903 2006-01-10 20:02:46Z mike $"
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 V1 raster page header.
40  *   cupsRasterReadHeader2()  - Read a V2 raster page header.
41  *   cupsRasterReadPixels()   - Read raster pixels.
42  *   cupsRasterWriteHeader()  - Write a V1 raster page header.
43  *   cupsRasterWriteHeader2() - Write a V2 raster page header.
44  *   cupsRasterWritePixels()  - Write raster pixels.
45  *   cups_raster_update()     - Update the raster header and row count for the
46  *                              current page.
47  *   cups_raster_write()      - Write a row of raster data...
48  *   cups_read()              - Read bytes from a file.
49  *   cups_write()             - Write bytes to a file.
50  */
51
52 /*
53  * Include necessary headers...
54  */
55
56 #include "raster.h"
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <errno.h>
60 #include <cups/string.h>
61
62 #if defined(WIN32) || defined(__EMX__)
63 #  include <io.h>
64 #else
65 #  include <unistd.h>
66 #endif /* WIN32 || __EMX__ */
67
68
69 /*
70  * Local functions...
71  */
72
73 static unsigned cups_raster_read_header(cups_raster_t *r);
74 static void     cups_raster_update(cups_raster_t *r);
75 static int      cups_raster_write(cups_raster_t *r);
76 static int      cups_read(int fd, unsigned char *buf, int bytes);
77 static int      cups_write(int fd, const unsigned char *buf, int bytes);
78
79
80 /*
81  * 'cupsRasterClose()' - Close a raster stream.
82  */
83
84 void
85 cupsRasterClose(cups_raster_t *r)       /* I - Stream to close */
86 {
87   if (r != NULL)
88   {
89     if (r->pixels)
90       free(r->pixels);
91
92     free(r);
93   }
94 }
95
96
97 /*
98  * 'cupsRasterOpen()' - Open a raster stream.
99  */
100
101 cups_raster_t *                         /* O - New stream */
102 cupsRasterOpen(int         fd,          /* I - File descriptor */
103                cups_mode_t mode)        /* I - Mode */
104 {
105   cups_raster_t *r;                     /* New stream */
106
107
108   if ((r = calloc(sizeof(cups_raster_t), 1)) == NULL)
109     return (NULL);
110
111   r->fd   = fd;
112   r->mode = mode;
113
114   if (mode == CUPS_RASTER_READ)
115   {
116    /*
117     * Open for read - get sync word...
118     */
119
120     if (cups_read(r->fd, (unsigned char *)&(r->sync), sizeof(r->sync))
121             < sizeof(r->sync))
122     {
123       free(r);
124       return (NULL);
125     }
126
127     if (r->sync != CUPS_RASTER_SYNC &&
128         r->sync != CUPS_RASTER_REVSYNC &&
129         r->sync != CUPS_RASTER_SYNCv1 &&
130         r->sync != CUPS_RASTER_REVSYNCv1)
131     {
132       free(r);
133       return (NULL);
134     }
135   }
136   else
137   {
138    /*
139     * Open for write - put sync word...
140     */
141
142     r->sync = CUPS_RASTER_SYNC;
143     if (cups_write(r->fd, (unsigned char *)&(r->sync), sizeof(r->sync))
144             < sizeof(r->sync))
145     {
146       free(r);
147       return (NULL);
148     }
149   }
150
151   return (r);
152 }
153
154
155 /*
156  * 'cupsRasterReadHeader()' - Read a V1 raster page header.
157  */
158
159 unsigned                                /* O - 1 on success, 0 on fail */
160 cupsRasterReadHeader(
161     cups_raster_t      *r,              /* I - Raster stream */
162     cups_page_header_t *h)              /* I - Pointer to header data */
163 {
164  /*
165   * Get the raster header...
166   */
167
168   if (!cups_raster_read_header(r))
169     return (0);
170   
171  /*
172   * Copy the header to the user-supplied buffer...
173   */
174
175   memcpy(h, &(r->header), sizeof(cups_page_header_t));
176
177   return (1);
178 }
179
180
181 /*
182  * 'cupsRasterReadHeader2()' - Read a V2 raster page header.
183  *
184  * @since CUPS 1.2@
185  */
186
187 unsigned                                /* O - 1 on success, 0 on fail */
188 cupsRasterReadHeader2(
189     cups_raster_t       *r,             /* I - Raster stream */
190     cups_page_header2_t *h)             /* I - Pointer to header data */
191 {
192  /*
193   * Get the raster header...
194   */
195
196   if (!cups_raster_read_header(r))
197     return (0);
198   
199  /*
200   * Copy the header to the user-supplied buffer...
201   */
202
203   memcpy(h, &(r->header), sizeof(cups_page_header2_t));
204
205   return (1);
206 }
207
208
209 /*
210  * 'cupsRasterReadPixels()' - Read raster pixels.
211  */
212
213 unsigned                                /* O - Number of bytes read */
214 cupsRasterReadPixels(cups_raster_t *r,  /* I - Raster stream */
215                      unsigned char *p,  /* I - Pointer to pixel buffer */
216                      unsigned      len) /* I - Number of bytes to read */
217 {
218   int           bytes;                  /* Bytes read */
219   unsigned      remaining;              /* Bytes remaining */
220   unsigned char *ptr,                   /* Pointer to read buffer */
221                 byte;                   /* Byte from file */
222
223
224   if (r == NULL || r->mode != CUPS_RASTER_READ || r->remaining == 0)
225     return (0);
226
227   remaining = len;
228
229   while (remaining > 0 && r->remaining > 0)
230   {
231     if (r->count == 0)
232     {
233      /*
234       * Need to read a new row...
235       */
236
237       if (remaining == r->header.cupsBytesPerLine)
238         ptr = p;
239       else
240         ptr = r->pixels;
241
242       if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1)
243       {
244        /*
245         * Read without compression...
246         */
247
248         if (cups_read(r->fd, ptr, r->header.cupsBytesPerLine) <
249                 r->header.cupsBytesPerLine)
250           return (0);
251
252         r->count = 1;
253       }
254       else
255       {
256        /*
257         * Read using a modified TIFF "packbits" compression...
258         */
259
260         unsigned char   *temp;          /* Pointer into buffer */
261         int             count;          /* Repetition count */
262
263
264         if (cups_read(r->fd, &byte, 1) < 1)
265           return (0);
266
267         r->count = byte + 1;
268
269         if (r->count > 1)
270           ptr = r->pixels;
271
272         temp  = ptr;
273         bytes = r->header.cupsBytesPerLine;
274
275         while (bytes > 0)
276         {
277          /*
278           * Get a new repeat count...
279           */
280
281           if (cups_read(r->fd, &byte, 1) < 1)
282             return (0);
283
284           if (byte & 128)
285           {
286            /*
287             * Copy N literal pixels...
288             */
289
290             count = (257 - byte) * r->bpp;
291
292             if (count > bytes)
293               count = bytes;
294
295             if (cups_read(r->fd, temp, count) < count)
296               return (0);
297
298             temp  += count;
299             bytes -= count;
300           }
301           else
302           {
303            /*
304             * Repeat the next N bytes...
305             */
306
307             count = (byte + 1) * r->bpp;
308             if (count > bytes)
309               count = bytes;
310
311             if (count < r->bpp)
312               break;
313
314             bytes -= count;
315
316             if (cups_read(r->fd, temp, r->bpp) < r->bpp)
317               return (0);
318
319             temp  += r->bpp;
320             count -= r->bpp;
321
322             while (count > 0)
323             {
324               memcpy(temp, temp - r->bpp, r->bpp);
325               temp  += r->bpp;
326               count -= r->bpp;
327             }
328           }
329         }
330       }
331
332       if (r->header.cupsBitsPerColor == 16 &&
333           (r->sync == CUPS_RASTER_REVSYNC || r->sync == CUPS_RASTER_REVSYNCv1))
334       {
335        /*
336         * Swap bytes in the pixel data...
337         */
338
339         unsigned char   *temp;
340         int             count;
341
342
343         for (temp = ptr, count = r->header.cupsBytesPerLine;
344              count > 0;
345              temp += 2, count -= 2)
346         {
347           byte    = temp[0];
348           temp[0] = temp[1];
349           temp[1] = byte;
350         }
351       }
352
353       if (remaining >= r->header.cupsBytesPerLine)
354       {
355         bytes       = r->header.cupsBytesPerLine;
356         r->pcurrent = r->pixels;
357         r->count --;
358         r->remaining --;
359       }
360       else
361       {
362         bytes       = remaining;
363         r->pcurrent = r->pixels + bytes;
364       }
365
366       if (ptr != p)
367         memcpy(p, ptr, bytes);
368     }
369     else
370     {
371      /*
372       * Copy fragment from buffer...
373       */
374
375       if ((bytes = r->pend - r->pcurrent) > remaining)
376         bytes = remaining;
377
378       memcpy(p, r->pcurrent, bytes);
379       r->pcurrent += bytes;
380
381       if (r->pcurrent >= r->pend)
382       {
383         r->pcurrent = r->pixels;
384         r->count --;
385         r->remaining --;
386       }
387     }
388
389     remaining -= bytes;
390     p         += bytes;
391   }
392
393   return (len);
394 }
395
396
397 /*
398  * 'cupsRasterWriteHeader()' - Write a V2 raster page header.
399  */
400  
401 unsigned                                /* O - 1 on success, 0 on failure */
402 cupsRasterWriteHeader(
403     cups_raster_t      *r,              /* I - Raster stream */
404     cups_page_header_t *h)              /* I - Raster page header */
405 {
406   if (r == NULL || r->mode != CUPS_RASTER_WRITE)
407     return (0);
408
409  /*
410   * Make a copy of the header, and compute the number of raster
411   * lines in the page image...
412   */
413
414   memset(&(r->header), 0, sizeof(r->header));
415   memcpy(&(r->header), h, sizeof(cups_page_header_t));
416
417   cups_raster_update(r);
418
419  /*
420   * Write the raster header...
421   */
422
423   return (cups_write(r->fd, (unsigned char *)&(r->header), sizeof(r->header))
424               > 0);
425 }
426
427
428 /*
429  * 'cupsRasterWriteHeader2()' - Write a V2 raster page header.
430  *
431  * @since CUPS 1.2@
432  */
433  
434 unsigned                                /* O - 1 on success, 0 on failure */
435 cupsRasterWriteHeader2(
436     cups_raster_t       *r,             /* I - Raster stream */
437     cups_page_header2_t *h)             /* I - Raster page header */
438 {
439   if (r == NULL || r->mode != CUPS_RASTER_WRITE)
440     return (0);
441
442  /*
443   * Make a copy of the header, and compute the number of raster
444   * lines in the page image...
445   */
446
447   memcpy(&(r->header), h, sizeof(cups_page_header2_t));
448
449   cups_raster_update(r);
450
451  /*
452   * Write the raster header...
453   */
454
455   return (cups_write(r->fd, (unsigned char *)&(r->header), sizeof(r->header))
456               > 0);
457 }
458
459
460 /*
461  * 'cupsRasterWritePixels()' - Write raster pixels.
462  */
463
464 unsigned                                /* O - Number of bytes written */
465 cupsRasterWritePixels(cups_raster_t *r, /* I - Raster stream */
466                       unsigned char *p, /* I - Bytes to write */
467                       unsigned      len)/* I - Number of bytes to write */
468 {
469   int           bytes;                  /* Bytes read */
470   unsigned      remaining;              /* Bytes remaining */
471
472
473   if (r == NULL || r->mode != CUPS_RASTER_WRITE || r->remaining == 0)
474     return (0);
475
476   remaining = len;
477
478   while (remaining > 0)
479   {
480    /*
481     * Figure out the number of remaining bytes on the current line...
482     */
483
484     if ((bytes = remaining) > (r->pend - r->pcurrent))
485       bytes = r->pend - r->pcurrent;
486
487     if (r->count > 0)
488     {
489      /*
490       * Check to see if this line is the same as the previous line...
491       */
492
493       if (memcmp(p, r->pcurrent, bytes))
494       {
495         if (!cups_raster_write(r))
496           return (0);
497
498         r->count = 0;
499       }
500       else
501       {
502        /*
503         * Mark more bytes as the same...
504         */
505
506         r->pcurrent += bytes;
507
508         if (r->pcurrent >= r->pend)
509         {
510          /*
511           * Increase the repeat count...
512           */
513
514           r->count ++;
515           r->pcurrent = r->pixels;
516
517          /*
518           * Flush out this line if it is the last one...
519           */
520
521           r->remaining --;
522           if (r->remaining == 0)
523             return (cups_raster_write(r));
524           else if (r->count == 256)
525           {
526             cups_raster_write(r);
527             r->count = 0;
528           }
529         }
530       }
531     }
532
533     if (r->count == 0)
534     {
535      /*
536       * Copy the raster data to the buffer...
537       */
538
539       memcpy(r->pcurrent, p, bytes);
540
541       r->pcurrent += bytes;
542
543       if (r->pcurrent >= r->pend)
544       {
545        /*
546         * Increase the repeat count...
547         */
548
549         r->count ++;
550         r->pcurrent = r->pixels;
551
552        /*
553         * Flush out this line if it is the last one...
554         */
555
556         r->remaining --;
557         if (r->remaining == 0)
558           return (cups_raster_write(r));
559       }
560     }
561
562     remaining -= bytes;
563     p         += bytes;
564   }
565
566   return (len);
567 }
568
569
570 /*
571  * 'cups_raster_read_header()' - Read a raster page header.
572  */
573
574 static unsigned                         /* O - 1 on success, 0 on fail */
575 cups_raster_read_header(
576     cups_raster_t *r)                   /* I - Raster stream */
577 {
578   int           len;                    /* Number of words to swap */
579   union swap_s                          /* Swapping structure */
580   {
581     unsigned char       b[4];
582     unsigned            v;
583   }             *s;
584
585
586   if (r == NULL || r->mode != CUPS_RASTER_READ)
587     return (0);
588
589  /*
590   * Get the length of the raster header...
591   */
592
593   if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1)
594     len = sizeof(cups_page_header_t);
595   else
596     len = sizeof(cups_page_header2_t);
597
598  /*
599   * Read the header...
600   */
601
602   memset(&(r->header), 0, sizeof(r->header));
603
604   if (cups_read(r->fd, (unsigned char *)&(r->header), len) < len)
605     return (0);
606
607  /*
608   * Swap bytes as needed...
609   */
610
611   if (r->sync == CUPS_RASTER_REVSYNC || r->sync == CUPS_RASTER_REVSYNCv1)
612     for (len = 74, s = (union swap_s *)&(r->header.AdvanceDistance);
613          len > 0;
614          len --, s ++)
615       s->v = (((((s->b[3] << 8) | s->b[2]) << 8) | s->b[1]) << 8) | s->b[0];
616
617  /*
618   * Update the header and row count...
619   */
620
621   cups_raster_update(r);
622
623   return (1);
624 }
625
626
627 /*
628  * 'cups_raster_update()' - Update the raster header and row count for the
629  *                          current page.
630  */
631
632 static void
633 cups_raster_update(cups_raster_t *r)    /* I - Raster stream */
634 {
635   if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1)
636   {
637    /*
638     * Set the "cupsNumColors" field according to the colorspace...
639     */
640
641     switch (r->header.cupsColorSpace)
642     {
643       case CUPS_CSPACE_W :
644       case CUPS_CSPACE_K :
645       case CUPS_CSPACE_WHITE :
646       case CUPS_CSPACE_GOLD :
647       case CUPS_CSPACE_SILVER :
648       case CUPS_CSPACE_ICC1 :
649           r->header.cupsNumColors = 1;
650           break;
651
652       case CUPS_CSPACE_ICC2 :
653           r->header.cupsNumColors = 2;
654           break;
655
656       case CUPS_CSPACE_RGB :
657       case CUPS_CSPACE_CMY :
658       case CUPS_CSPACE_YMC :
659       case CUPS_CSPACE_CIEXYZ :
660       case CUPS_CSPACE_CIELab :
661       case CUPS_CSPACE_ICC3 :
662           r->header.cupsNumColors = 3;
663           break;
664
665       case CUPS_CSPACE_RGBA :
666       case CUPS_CSPACE_RGBW :
667       case CUPS_CSPACE_CMYK :
668       case CUPS_CSPACE_YMCK :
669       case CUPS_CSPACE_KCMY :
670       case CUPS_CSPACE_GMCK :
671       case CUPS_CSPACE_GMCS :
672       case CUPS_CSPACE_ICC4 :
673           r->header.cupsNumColors = 4;
674           break;
675
676       case CUPS_CSPACE_KCMYcm :
677           if (r->header.cupsBitsPerPixel < 8)
678             r->header.cupsNumColors = 6;
679           else
680             r->header.cupsNumColors = 4;
681           break;
682
683       case CUPS_CSPACE_ICC5 :
684       case CUPS_CSPACE_ICC6 :
685       case CUPS_CSPACE_ICC7 :
686       case CUPS_CSPACE_ICC8 :
687       case CUPS_CSPACE_ICC9 :
688       case CUPS_CSPACE_ICCA :
689       case CUPS_CSPACE_ICCB :
690       case CUPS_CSPACE_ICCC :
691       case CUPS_CSPACE_ICCD :
692       case CUPS_CSPACE_ICCE :
693       case CUPS_CSPACE_ICCF :
694           r->header.cupsNumColors = r->header.cupsColorSpace -
695                                     CUPS_CSPACE_ICC1 + 1;
696           break;
697     }
698   }
699
700  /*
701   * Set the number of bytes per pixel/color...
702   */
703
704   if (r->header.cupsColorOrder == CUPS_ORDER_CHUNKED)
705     r->bpp = (r->header.cupsBitsPerPixel + 7) / 8;
706   else
707     r->bpp = (r->header.cupsBitsPerColor + 7) / 8;
708
709  /*
710   * Set the number of remaining rows...
711   */
712
713   if (r->header.cupsColorOrder == CUPS_ORDER_PLANAR)
714     r->remaining = r->header.cupsHeight * r->header.cupsNumColors;
715   else
716     r->remaining = r->header.cupsHeight;
717
718  /*
719   * Allocate the read/write buffer...
720   */
721
722   if (r->pixels != NULL)
723     free(r->pixels);
724
725   r->pixels   = calloc(r->header.cupsBytesPerLine, 1);
726   r->pcurrent = r->pixels;
727   r->pend     = r->pixels + r->header.cupsBytesPerLine;
728   r->count    = 0;
729 }
730
731
732 /*
733  * 'cups_raster_write()' - Write a row of raster data...
734  */
735
736 static int                              /* O - Number of bytes written */
737 cups_raster_write(cups_raster_t *r)     /* I - Raster stream */
738 {
739   unsigned char *start,                 /* Start of sequence */
740                 *ptr,                   /* Current pointer in sequence */
741                 byte;                   /* Byte to write */
742   int           count;                  /* Count */
743
744
745  /*
746   * Write the row repeat count...
747   */
748
749   byte = r->count - 1;
750
751   if (cups_write(r->fd, &byte, 1) < 1)
752     return (0);
753
754  /*
755   * Write using a modified TIFF "packbits" compression...
756   */
757
758   for (ptr = r->pixels; ptr < r->pend;)
759   {
760     start = ptr;
761     ptr += r->bpp;
762
763     if (ptr == r->pend)
764     {
765      /*
766       * Encode a single pixel at the end...
767       */
768
769       byte = 0;
770       if (cups_write(r->fd, &byte, 1) < 1)
771         return (0);
772
773       if (cups_write(r->fd, start, r->bpp) < r->bpp)
774         return (0);
775     }
776     else if (!memcmp(start, ptr, r->bpp))
777     {
778      /*
779       * Encode a sequence of repeating pixels...
780       */
781
782       for (count = 2; count < 128 && ptr < (r->pend - r->bpp); count ++, ptr += r->bpp)
783         if (memcmp(ptr, ptr + r->bpp, r->bpp) != 0)
784           break;
785
786       ptr += r->bpp;
787
788       byte = count - 1;
789
790       if (cups_write(r->fd, &byte, 1) < 1)
791         return (0);
792
793       if (cups_write(r->fd, start, r->bpp) < r->bpp)
794         return (0);
795     }
796     else
797     {
798      /*
799       * Encode a sequence of non-repeating pixels...
800       */
801
802       for (count = 1; count < 127 && ptr < (r->pend - r->bpp); count ++, ptr += r->bpp)
803         if (!memcmp(ptr, ptr + r->bpp, r->bpp))
804           break;
805
806       if (ptr >= (r->pend - r->bpp) && count < 128)
807       {
808         count ++;
809         ptr += r->bpp;
810       }
811  
812       byte = 257 - count;
813
814       if (cups_write(r->fd, &byte, 1) < 1)
815         return (0);
816
817       count *= r->bpp;
818
819       if (cups_write(r->fd, start, count) < count)
820         return (0);
821     }
822   }
823
824   return (r->header.cupsBytesPerLine);
825 }
826
827
828 /*
829  * 'cups_read()' - Read bytes from a file.
830  */
831
832 static int                              /* O - Bytes read or -1 */
833 cups_read(int           fd,             /* I - File descriptor */
834           unsigned char *buf,           /* I - Buffer for read */
835           int           bytes)          /* I - Number of bytes to read */
836 {
837   int   count,                          /* Number of bytes read */
838         total;                          /* Total bytes read */
839
840
841   for (total = 0; total < bytes; total += count, buf += count)
842   {
843     count = read(fd, buf, bytes - total);
844
845     if (count == 0)
846       return (0);
847     else if (count < 0)
848     {
849       if (errno == EINTR)
850         count = 0;
851       else
852         return (-1);
853     }
854   }
855
856   return (total);
857 }
858
859
860 /*
861  * 'cups_write()' - Write bytes to a file.
862  */
863
864 static int                              /* O - Bytes written or -1 */
865 cups_write(int                 fd,      /* I - File descriptor */
866            const unsigned char *buf,    /* I - Bytes to write */
867            int                 bytes)   /* I - Number of bytes to write */
868 {
869   int   count,                          /* Number of bytes written */
870         total;                          /* Total bytes written */
871
872
873   for (total = 0; total < bytes; total += count, buf += count)
874   {
875     count = write(fd, buf, bytes - total);
876
877     if (count < 0)
878     {
879       if (errno == EINTR)
880         count = 0;
881       else
882         return (-1);
883     }
884   }
885
886   return (total);
887 }
888
889
890 /*
891  * End of "$Id: raster.c 4903 2006-01-10 20:02:46Z mike $".
892  */