xref: /plan9/sys/src/cmd/gs/src/gdevsgi.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /*
2  * This file is distributed with Ghostscript, but its author,
3  * Tanmoy Bhattacharya (tanmoy@qcd.lanl.gov) hereby places it in the
4  * public domain.
5  */
6 
7 /* $Id: gdevsgi.c,v 1.6 2004/08/10 13:02:36 stefan Exp $*/
8 /* SGI raster file driver */
9 #include "gdevprn.h"
10 #include "gdevsgi.h"
11 
12 #define X_DPI 72
13 #define Y_DPI 72
14 
15 #define sgi_prn_device(procs, dev_name, num_comp, depth, max_gray, max_color, print_page)\
16 {prn_device_body(gx_device_printer, procs, dev_name, \
17 		 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI, \
18 		 0, 0, 0, 0, \
19 		 num_comp, depth, max_gray, max_color, max_gray+1, max_color+1, \
20 		 print_page)}
21 
22 private dev_proc_map_rgb_color(sgi_map_rgb_color);
23 private dev_proc_map_color_rgb(sgi_map_color_rgb);
24 
25 private dev_proc_print_page(sgi_print_page);
26 
27 private gx_device_procs sgi_procs =
28   prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
29 		  sgi_map_rgb_color, sgi_map_color_rgb);
30 
31 const gx_device_printer far_data gs_sgirgb_device =
32   sgi_prn_device(sgi_procs, "sgirgb", 3, 24, 255, 255, sgi_print_page);
33 
34 private gx_color_index
sgi_map_rgb_color(gx_device * dev,const ushort cv[])35 sgi_map_rgb_color(gx_device * dev, const ushort cv[])
36 {      ushort bitspercolor = dev->color_info.depth / 3;
37        ulong max_value = (1 << bitspercolor) - 1;
38        ushort red, green, blue;
39        red = cv[0]; green = cv[1]; blue = cv[2];
40 
41        return ((red*max_value / gx_max_color_value) << (bitspercolor * 2)) +
42 	      ((green*max_value / gx_max_color_value) << bitspercolor) +
43 	      (blue*max_value / gx_max_color_value);
44 }
45 
46 private int
sgi_map_color_rgb(gx_device * dev,gx_color_index color,ushort prgb[3])47 sgi_map_color_rgb(gx_device *dev, gx_color_index color, ushort prgb[3])
48 {	ushort bitspercolor = dev->color_info.depth / 3;
49 	ushort colormask = (1 << bitspercolor) - 1;
50 
51 	prgb[0] = (ushort)(((color >> (bitspercolor * 2)) & colormask) *
52 		(ulong)gx_max_color_value / colormask);
53 	prgb[1] = (ushort)(((color >> bitspercolor) & colormask) *
54 		(ulong)gx_max_color_value / colormask);
55 	prgb[2] = (ushort)((color & colormask) *
56 		(ulong)gx_max_color_value / colormask);
57 	return 0;
58 }
59 
60 typedef struct sgi_cursor_s {
61   gx_device_printer *dev;
62   int bpp;
63   uint line_size;
64   byte *data;
65   int lnum;
66 } sgi_cursor;
67 
68 private int
sgi_begin_page(gx_device_printer * bdev,FILE * pstream,sgi_cursor * pcur)69 sgi_begin_page(gx_device_printer *bdev, FILE *pstream, sgi_cursor *pcur)
70 {
71      uint line_size = gdev_mem_bytes_per_scan_line((gx_device_printer*)bdev);
72      byte *data = (byte*)gs_malloc(bdev->memory, line_size, 1, "sgi_begin_page");
73      IMAGE *header= (IMAGE*)gs_malloc(bdev->memory, sizeof(IMAGE),1,"sgi_begin_page");
74      char filler= '\0';
75      int i;
76 
77      if ((data == (byte*)0)||(header == (IMAGE*)0)) return -1;
78 
79      bzero(header,sizeof(IMAGE));
80      header->imagic = IMAGIC;
81      header->type = RLE(1);
82      header->dim = 3;
83      header->xsize=bdev->width;
84      header->ysize=bdev->height;
85      header->zsize=3;
86      header->min_color  = 0;
87      header->max_color  = bdev->color_info.max_color;
88      header->wastebytes = 0;
89      strncpy(header->name,"gs picture",80);
90      header->colormap = CM_NORMAL;
91      header->dorev=0;
92      fwrite(header,sizeof(IMAGE),1,pstream);
93      for (i=0; i<512-sizeof(IMAGE); i++) fputc(filler,pstream);
94      pcur->dev = bdev;
95      pcur->bpp = bdev->color_info.depth;
96      pcur->line_size = line_size;
97      pcur->data = data;
98      return 0;
99 }
100 
101 private int
sgi_next_row(sgi_cursor * pcur)102 sgi_next_row(sgi_cursor *pcur)
103 {    if (pcur->lnum < 0)
104        return 1;
105      gdev_prn_copy_scan_lines((gx_device_printer*)pcur->dev,
106 			      pcur->lnum--, pcur->data, pcur->line_size);
107      return 0;
108 }
109 
110 #define bdev ((gx_device_printer *)pdev)
111 
112 private int
sgi_print_page(gx_device_printer * pdev,FILE * pstream)113 sgi_print_page(gx_device_printer *pdev, FILE *pstream)
114 {      sgi_cursor cur;
115        int code = sgi_begin_page(bdev, pstream, &cur);
116        uint bpe, mask;
117        int separation;
118        long *rowsizes=(long*)gs_malloc(pdev->memory, 4,3*bdev->height,"sgi_print_page");
119        byte *edata ;
120        long lastval;
121        int rownumber;
122 #define aref2(a,b) a*bdev->height+b
123        edata =  (byte*)gs_malloc(pdev->memory, cur.line_size, 1, "sgi_begin_page");
124        if((code<0)||(rowsizes==(long*)NULL)||(edata==(byte*)NULL)) return(-1);
125        fwrite(rowsizes,sizeof(long),3*bdev->height,pstream); /* rowstarts */
126        fwrite(rowsizes,sizeof(long),3*bdev->height,pstream); /* rowsizes */
127        lastval = 512+sizeof(long)*6*bdev->height;
128        fseek(pstream,lastval,0);
129        for (separation=0; separation < 3; separation++)
130 	 {
131 	   cur.lnum = cur.dev->height-1;
132 	   rownumber = 0;
133 	   bpe = cur.bpp/3;
134 	   mask = (1<<bpe) - 1;
135 	   while ( !(code=sgi_next_row(&cur)))
136 	     { byte *bp;
137 	       uint x;
138 	       int shift;
139 	       byte *curcol=cur.data;
140 	       byte *startcol=edata;
141 	       int count;
142 	       byte todo, cc;
143 	       byte *iptr, *sptr, *optr, *ibufend;
144 	       for (bp = cur.data, x=0, shift = 8 - cur.bpp;
145 		    x < bdev->width;
146 		    )
147 		 { ulong pixel = 0;
148 		   uint r, g, b;
149 		   switch (cur.bpp >> 3)
150 		     {
151 		     case 3: pixel = (ulong)*bp << 16; bp++;
152 		     case 2: pixel += (uint)*bp << 8; bp++;
153 		     case 1: pixel += *bp; bp++; break;
154 		     case 0: pixel = *bp >> shift;
155 		       if ((shift-=cur.bpp) < 0)
156 			 bp++, shift += 8; break;
157 		     }
158 		   ++x;
159 		   b = pixel & mask; pixel >>= bpe;
160 		   g = pixel & mask; pixel >>= bpe;
161 		   r = pixel & mask;
162 		   switch(separation)
163 		     {
164 		     case 0: *curcol++=r; break;
165 		     case 1: *curcol++=g; break;
166 		     case 2: *curcol++=b; break;
167 		     }
168 		 }
169 	       iptr=cur.data;
170 	       optr=startcol;
171 	       ibufend=curcol-1;
172 	       while(iptr<ibufend) {
173 		 sptr = iptr;
174 		 iptr += 2;
175 		 while((iptr<ibufend)&&((iptr[-2]!=iptr[-1])||(iptr[-1]!=iptr[0])))
176 		   iptr++;
177 		 iptr -= 2;
178 		 count = iptr-sptr;
179 		 while(count) {
180 		   todo = count>126 ? 126:count;
181 		   count -= todo;
182 		   *optr++ = 0x80|todo;
183 		   while(todo--)
184 		     *optr++ = *sptr++;
185 		 }
186 		 sptr = iptr;
187 		 cc = *iptr++;
188 		 while( (iptr<ibufend) && (*iptr == cc) )
189 		   iptr++;
190 		 count = iptr-sptr;
191 		 while(count) {
192 		   todo = count>126 ? 126:count;
193 		   count -= todo;
194 		   *optr++ = todo;
195 		   *optr++ = cc;
196 		 }
197 	       }
198                *optr++ = 0;
199 	       rowsizes[aref2(separation,rownumber++)] = optr-startcol;
200 	       fwrite(startcol,1,optr-startcol,pstream);
201 	     }
202 	 }
203        fseek(pstream,512L,0);
204        for(separation=0; separation<3; separation++)
205 	 for(rownumber=0; rownumber<bdev->height; rownumber++)
206 	   {fputc((char)(lastval>>24),pstream);
207 	    fputc((char)(lastval>>16),pstream);
208 	    fputc((char)(lastval>>8),pstream);
209 	    fputc((char)(lastval),pstream);
210 	    lastval+=rowsizes[aref2(separation,rownumber)];}
211        for(separation=0; separation<3; separation++)
212 	 for(rownumber=0; rownumber<bdev->height; rownumber++)
213 	   {lastval=rowsizes[aref2(separation,rownumber)];
214 	    fputc((char)(lastval>>24),pstream);
215 	    fputc((char)(lastval>>16),pstream);
216 	    fputc((char)(lastval>>8),pstream);
217 	    fputc((char)(lastval),pstream);}
218        gs_free(pdev->memory, (char*)cur.data, cur.line_size, 1,
219 		 "sgi_print_page(done)");
220        gs_free(pdev->memory, (char*)edata, cur.line_size, 1, "sgi_print_page(done)");
221        gs_free(pdev->memory, (char*)rowsizes,4,3*bdev->height,"sgi_print_page(done)");
222        return (code < 0 ? code : 0);
223 }
224