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 9490 2009-02-19 17:13:36Z ray $*/
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 static dev_proc_map_rgb_color(sgi_map_rgb_color);
23 static dev_proc_map_color_rgb(sgi_map_color_rgb);
24
25 static dev_proc_print_page(sgi_print_page);
26
27 static 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 static 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 static 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 /* write a short int to disk as big-endean */
putshort(unsigned int val,FILE * outf)69 static int putshort(unsigned int val, FILE *outf)
70 {
71 unsigned char buf[2];
72
73 buf[0] = (val>>8);
74 buf[1] = val;
75 return fwrite(buf,2,1,outf);
76 }
77
78 /* write an int to disk as big-endean */
putint(unsigned int val,FILE * outf)79 static int putint(unsigned int val, FILE *outf)
80 {
81 unsigned char buf[4];
82
83 buf[0] = (val>>24);
84 buf[1] = (val>>16);
85 buf[2] = (val>>8);
86 buf[3] = val;
87 return fwrite(buf,4,1,outf);
88 }
89
90 /* write the header field by field in big-endian */
putheader(IMAGE * header,FILE * outf)91 static void putheader(IMAGE *header, FILE *outf)
92 {
93 int i;
94 char filler= '\0';
95
96 putshort(header->imagic, outf);
97 fputc(1, outf); /* RLE */
98 fputc(1, outf); /* bpp */
99 putshort(header->dim, outf);
100 putshort(header->xsize, outf);
101 putshort(header->ysize, outf);
102 putshort(header->zsize, outf);
103
104 putint(header->min_color, outf);
105 putint(header->max_color, outf);
106 putint(header->wastebytes, outf);
107
108 fwrite(header->name,80,1,outf);
109
110 putint(header->colormap, outf);
111
112 /* put the filler for the rest */
113 for (i=0; i<404; i++)
114 fputc(filler,outf);
115 }
116
117 static int
sgi_begin_page(gx_device_printer * bdev,FILE * pstream,sgi_cursor * pcur)118 sgi_begin_page(gx_device_printer *bdev, FILE *pstream, sgi_cursor *pcur)
119 {
120 uint line_size;
121 byte *data;
122 IMAGE *header;
123
124 if (bdev->PageCount >= 1 && !bdev->file_is_new) { /* support single page only */
125 eprintf("sgi rgb format only supports one page per file.\n"
126 "Please use the '%%d' OutputFile option to create one file for each page.\n");
127 return_error(gs_error_rangecheck);
128 }
129 line_size = gdev_mem_bytes_per_scan_line((gx_device_printer*)bdev);
130 data = (byte*)gs_malloc(bdev->memory, line_size, 1, "sgi_begin_page");
131 header= (IMAGE*)gs_malloc(bdev->memory, sizeof(IMAGE),1,"sgi_begin_page");
132
133 if ((data == (byte*)0)||(header == (IMAGE*)0)) {
134 gs_free(bdev->memory, data, line_size, 1, "sgi_begin_page");
135 gs_free(bdev->memory, header, sizeof(IMAGE),1,"sgi_begin_page");
136 return_error(gs_error_VMerror);
137 }
138 memset(header,0, sizeof(IMAGE));
139 header->imagic = IMAGIC;
140 header->type = RLE(1);
141 header->dim = 3;
142 header->xsize=bdev->width;
143 header->ysize=bdev->height;
144 header->zsize=3;
145 header->min_color = 0;
146 header->max_color = bdev->color_info.max_color;
147 header->wastebytes = 0;
148 strncpy(header->name,"gs picture",80);
149 header->colormap = CM_NORMAL;
150 header->dorev=0;
151 putheader(header,pstream);
152 pcur->dev = bdev;
153 pcur->bpp = bdev->color_info.depth;
154 pcur->line_size = line_size;
155 pcur->data = data;
156 return 0;
157 }
158
159 static int
sgi_next_row(sgi_cursor * pcur)160 sgi_next_row(sgi_cursor *pcur)
161 { if (pcur->lnum < 0)
162 return 1;
163 gdev_prn_copy_scan_lines((gx_device_printer*)pcur->dev,
164 pcur->lnum--, pcur->data, pcur->line_size);
165 return 0;
166 }
167
168 #define bdev ((gx_device_printer *)pdev)
169
170 static int
sgi_print_page(gx_device_printer * pdev,FILE * pstream)171 sgi_print_page(gx_device_printer *pdev, FILE *pstream)
172 { sgi_cursor cur;
173 int code = sgi_begin_page(bdev, pstream, &cur);
174 uint bpe, mask;
175 int separation;
176 int *rowsizes;
177 byte *edata ;
178 long lastval;
179 int rownumber;
180
181 if (pdev->PageCount >= 1 && !pdev->file_is_new)
182 return_error(gs_error_rangecheck); /* support single page only, can't happen */
183
184 #define aref2(a,b) (a)*bdev->height+(b)
185 rowsizes=(int*)gs_malloc(pdev->memory, sizeof(int),3*bdev->height,"sgi_print_page");
186 edata = (byte*)gs_malloc(pdev->memory, cur.line_size, 1, "sgi_begin_page");
187
188 if((code<0)||(rowsizes==(int*)NULL)||(edata==(byte*)NULL)) {
189 code = gs_note_error(gs_error_VMerror);
190 goto free_mem;
191 }
192
193 lastval = 512+4*6*bdev->height; /* skip offset table */
194 fseek(pstream,lastval,0);
195 for (separation=0; separation < 3; separation++)
196 {
197 cur.lnum = cur.dev->height-1;
198 rownumber = 0;
199 bpe = cur.bpp/3;
200 mask = (1<<bpe) - 1;
201 while ( !(code=sgi_next_row(&cur)))
202 { byte *bp;
203 uint x;
204 int shift;
205 byte *curcol=cur.data;
206 byte *startcol=edata;
207 int count;
208 byte todo, cc;
209 byte *iptr, *sptr, *optr, *ibufend;
210 for (bp = cur.data, x=0, shift = 8 - cur.bpp;
211 x < bdev->width;
212 )
213 { uint pixel = 0;
214 uint r, g, b;
215 switch (cur.bpp >> 3)
216 {
217 case 3: pixel = (uint)*bp << 16; bp++;
218 case 2: pixel += (uint)*bp << 8; bp++;
219 case 1: pixel += *bp; bp++; break;
220 case 0: pixel = *bp >> shift;
221 if ((shift-=cur.bpp) < 0)
222 bp++, shift += 8; break;
223 }
224 ++x;
225 b = pixel & mask; pixel >>= bpe;
226 g = pixel & mask; pixel >>= bpe;
227 r = pixel & mask;
228 switch(separation)
229 {
230 case 0: *curcol++=r; break;
231 case 1: *curcol++=g; break;
232 case 2: *curcol++=b; break;
233 }
234 }
235 iptr=cur.data;
236 optr=startcol;
237 ibufend=curcol-1;
238 while(iptr<ibufend) {
239 sptr = iptr;
240 iptr += 2;
241 while((iptr<ibufend)&&((iptr[-2]!=iptr[-1])||(iptr[-1]!=iptr[0])))
242 iptr++;
243 iptr -= 2;
244 count = iptr-sptr;
245 while(count) {
246 todo = count>126 ? 126:count;
247 count -= todo;
248 *optr++ = 0x80|todo;
249 while(todo--)
250 *optr++ = *sptr++;
251 }
252 sptr = iptr;
253 cc = *iptr++;
254 while( (iptr<ibufend) && (*iptr == cc) )
255 iptr++;
256 count = iptr-sptr;
257 while(count) {
258 todo = count>126 ? 126:count;
259 count -= todo;
260 *optr++ = todo;
261 *optr++ = cc;
262 }
263 }
264 *optr++ = 0;
265 rowsizes[aref2(separation,rownumber++)] = optr-startcol;
266 if (fwrite(startcol,1,optr-startcol,pstream) != optr-startcol) {
267 code = gs_note_error(gs_error_ioerror);
268 goto free_mem;
269 }
270 }
271 }
272 fseek(pstream,512L,0);
273 for(separation=0; separation<3; separation++)
274 for(rownumber=0; rownumber<bdev->height; rownumber++)
275 {putint(lastval,pstream);
276 lastval+=rowsizes[aref2(separation,rownumber)];}
277 for(separation=0; separation<3; separation++)
278 for(rownumber=0; rownumber<bdev->height; rownumber++)
279 {lastval=rowsizes[aref2(separation,rownumber)];
280 putint(lastval,pstream);}
281 free_mem:
282 gs_free(pdev->memory, (char*)cur.data, cur.line_size, 1,
283 "sgi_print_page(done)");
284 gs_free(pdev->memory, (char*)edata, cur.line_size, 1, "sgi_print_page(done)");
285 gs_free(pdev->memory, (char*)rowsizes,4,3*bdev->height,"sgi_print_page(done)");
286 return (code < 0 ? code : 0);
287 }
288