]> git.imager.perl.org - imager.git/blob - rgb.c
log of discussion on IRC
[imager.git] / rgb.c
1 #include "image.h"
2 #include "io.h"
3 #include "log.h"
4 #include "iolayer.h"
5
6 #include <stdlib.h>
7 #include <errno.h>
8
9
10 /*
11 =head1 NAME
12
13 rgb.c - implements reading and writing sgi image files, uses io layer.
14
15 =head1 SYNOPSIS
16
17    io_glue *ig = io_new_fd( fd );
18    i_img *im   = i_readrgb_wiol(ig, -1); // no limit on how much is read
19    // or 
20    io_glue *ig = io_new_fd( fd );
21    return_code = i_writergb_wiol(im, ig); 
22
23 =head1 DESCRIPTION
24
25 rgb.c implements the basic functions to read and write portable targa
26 files.  It uses the iolayer and needs either a seekable source or an
27 entire memory mapped buffer.
28
29 =head1 FUNCTION REFERENCE
30
31 Some of these functions are internal.
32
33 =over
34
35 =cut
36 */
37
38 typedef struct {
39   unsigned short imagic;
40   unsigned char storagetype;
41   unsigned char BPC;
42   unsigned short dimensions;
43   unsigned short xsize, ysize, zsize;
44   unsigned int min, max;
45   char name[80];
46   unsigned int colormap;
47 } rgb_header;
48
49 typedef struct {
50   int start, length;
51 } stlen_pair;
52
53 typedef enum { NoInit, Raw, Rle } rle_state;
54
55
56
57 typedef struct {
58   int compressed;
59   int bytepp;
60   io_glue *ig;
61 } rgb_dest;
62
63
64
65
66
67
68 /*
69 =item rgb_header_unpack(header, headbuf)
70
71 Unpacks the header structure into from buffer and stores
72 in the header structure.
73
74     header - header structure
75     headbuf - buffer to unpack from
76
77 =cut
78 */
79
80
81 static
82 void
83 rgb_header_unpack(rgb_header *header, unsigned char *headbuf) {
84   header->imagic      = (headbuf[0]<<8) + headbuf[1];
85   header->storagetype = headbuf[2];
86   header->BPC         = headbuf[3];
87   header->dimensions  = (headbuf[4]<<8) + headbuf[5];
88   header->xsize       = (headbuf[6]<<8) + headbuf[7];
89   header->ysize       = (headbuf[8]<<8) + headbuf[9];
90   header->zsize       = (headbuf[10]<<8) + headbuf[11];
91   header->min         = (headbuf[12]<<24) + (headbuf[13]<<16)+(headbuf[14]<<8)+headbuf[15];
92   header->max         = (headbuf[16]<<24) + (headbuf[17]<<16)+(headbuf[18]<<8)+headbuf[19];
93   memcpy(header->name,headbuf+20,80);
94   header->colormap    = (headbuf[100]<<24) + (headbuf[101]<<16)+(headbuf[102]<<8)+headbuf[103];
95 }
96
97
98 /*
99 =item rgb_header_pack(header, headbuf)
100
101 Packs header structure into buffer for writing.
102
103     header - header structure
104     headbuf - buffer to pack into
105
106 =cut
107 */
108
109 static
110 void
111 rgb_header_pack(rgb_header *header, unsigned char headbuf[512]) {
112   
113   header->imagic      = (headbuf[0]<<8) + headbuf[1];
114   header->storagetype = headbuf[2];
115   header->BPC         = headbuf[3];
116   header->dimensions  = (headbuf[4]<<8) + headbuf[5];
117   header->xsize       = (headbuf[6]<<8) + headbuf[7];
118   header->ysize       = (headbuf[8]<<8) + headbuf[9];
119   header->zsize       = (headbuf[10]<<8) + headbuf[11];
120   header->min         = (headbuf[12]<<24) + (headbuf[13]<<16)+(headbuf[14]<<8)+headbuf[15];
121   header->max         = (headbuf[16]<<24) + (headbuf[17]<<16)+(headbuf[18]<<8)+headbuf[19];
122   memcpy(header->name,headbuf+20,80);
123   header->colormap    = (headbuf[100]<<24) + (headbuf[101]<<16)+(headbuf[102]<<8)+headbuf[103];
124
125 }
126
127
128
129
130
131 /*
132 =item rgb_dest_write(s, buf, pixels)
133
134 Writes pixels from buf to destination s.  Takes care of compressing if the
135 destination is compressed.
136
137     s - data destination
138     buf - source buffer
139     pixels - number of pixels to put write to destination
140
141 =cut
142 */
143
144 static
145 int
146 rgb_dest_write(rgb_dest *s, unsigned char *buf, size_t pixels) {
147
148 }
149
150
151
152
153
154
155
156
157 /*
158 =item i_readrgb_wiol(ig, length)
159
160 Read in an image from the iolayer data source and return the image structure to it.
161 Returns NULL on error.
162
163    ig     - io_glue object
164    length - maximum length to read from data source, before closing it -1 
165             signifies no limit.
166
167 =cut
168 */
169
170 i_img *
171 i_readrgb_wiol(io_glue *ig, int length) {
172   i_img *img;
173   int x, y, c,i;
174   int width, height, channels;
175   unsigned long maxlen;
176
177   int savemask;
178   
179   char *idstring = NULL;
180
181   rgb_header header;
182   unsigned char headbuf[512];
183   unsigned char *databuf;
184   unsigned char *reorderbuf;
185   unsigned long *starttab, *lengthtab;
186   i_color *linebuf = NULL;
187   i_mempool mp;
188
189   mm_log((1,"i_readrgb(ig %p, length %d)\n", ig, length));
190   i_clear_error();
191   i_mempool_init(&mp);
192   
193   io_glue_commit_types(ig);
194
195   if (ig->readcb(ig, headbuf, 512) != 512) {
196     i_push_error(errno, "could not read SGI rgb header");
197     return NULL;
198   }
199
200   rgb_header_unpack(&header, headbuf);
201   
202   
203   mm_log((1,"imagic:         %d\n", header.imagic));
204   mm_log((1,"storagetype:    %d\n", header.storagetype));
205   mm_log((1,"BPC:            %d\n", header.BPC));
206   mm_log((1,"dimensions:     %d\n", header.dimensions));
207   mm_log((1,"xsize:          %d\n", header.xsize));
208   mm_log((1,"ysize:          %d\n", header.ysize));
209   mm_log((1,"zsize:          %d\n", header.zsize));
210   mm_log((1,"min:            %d\n", header.min));
211   mm_log((1,"max:            %d\n", header.max));
212   mm_log((1,"name [skipped]\n"));
213   mm_log((1,"colormap:       %d\n", header.colormap));
214
215   if (header.colormap != 0) {
216     i_push_error(0, "SGI rgb image has a non zero colormap entry - obsolete format");
217     return NULL;
218   }
219
220   if (header.storagetype != 0 && header.storagetype != 1) {
221     i_push_error(0, "SGI rgb image has has invalid storage field");
222     return NULL;
223   }
224
225   width    = header.xsize;
226   height   = header.ysize;
227   channels = header.zsize;
228
229   img = i_img_empty_ch(NULL, width, height, channels);
230   
231   i_tags_add(&img->tags, "rgb_namestr", 0, header.name, 80, 0);
232
233
234   switch (header.storagetype) {
235   case 0: /* uncompressed */
236     
237     linebuf   = i_mempool_alloc(&mp, width*sizeof(i_color));
238     databuf   = i_mempool_alloc(&mp, width);
239
240     savemask = i_img_getmask(img);
241
242     for(c=0; c<channels; c++) {
243       i_img_setmask(img, 1<<c);
244       for(y=0; y<height; y++) {
245         int x;
246         
247         if (ig->readcb(ig, databuf, width) != width) {
248           i_push_error(0, "SGI rgb: cannot read");
249           goto ErrorReturn;
250         }
251
252         for(x=0; x<width; x++)
253           linebuf[x].channel[c] = databuf[x];
254         
255         i_plin(img, 0, width, height-1-y, linebuf);
256       }
257     }
258     i_img_setmask(img, savemask);
259     break;
260   case 1: /* RLE compressed */
261     
262     databuf   = i_mempool_alloc(&mp, height*channels*4);
263     starttab  = i_mempool_alloc(&mp, height*channels*sizeof(unsigned long));
264     lengthtab = i_mempool_alloc(&mp, height*channels*sizeof(unsigned long));
265     linebuf   = i_mempool_alloc(&mp, width*sizeof(i_color));
266     
267     /* Read offset table */
268     if (ig->readcb(ig, databuf, height*channels*4) != height*channels*4) goto ErrorReturn;
269     for(i=0; i<height*channels; i++) starttab[i] = 
270                                        (databuf[i*4]<<24) | 
271                                        (databuf[i*4+1]<<16) | 
272                                        (databuf[i*4+2]<<8) |
273                                        (databuf[i*4+3]);
274
275
276     /* Read length table */
277     if (ig->readcb(ig, databuf, height*channels*4) != height*channels*4) goto ErrorReturn;
278     for(i=0; i<height*channels; i++) lengthtab[i] = 
279                                        (databuf[i*4]<<24)+
280                                        (databuf[i*4+1]<<16)+
281                                        (databuf[i*4+2]<<8)+
282                                        (databuf[i*4+3]);
283
284     mm_log((3, "Offset/length table:\n"));
285     for(i=0; i<height*channels; i++)
286       mm_log((3, "%d: %d/%d\n", i, starttab[i], lengthtab[i]));
287
288
289     /* Find max spanlength if someone is making very badly formed RLE data */
290     maxlen = 0;
291     for(y=0; y<height; y++) maxlen = (maxlen>lengthtab[y])?maxlen:lengthtab[y];
292
293     mm_log((1, "maxlen for an rle buffer: %d\n", maxlen));
294
295     databuf = i_mempool_alloc(&mp, maxlen);
296
297     for(y=0; y<height; y++) {
298       for(c=0; c<channels; c++) {
299         unsigned long iidx = 0, oidx = 0, span = 0;
300         unsigned char cval;
301         int rle = 0;
302         int ci = height*c+y;
303         int datalen = lengthtab[ci];
304
305         if (ig->seekcb(ig, starttab[ci], SEEK_SET) != starttab[ci]) {
306           i_push_error(0, "SGI rgb: cannot seek");
307           goto ErrorReturn;
308         }
309         if (ig->readcb(ig, databuf, datalen) != datalen) {
310           i_push_error(0, "SGI rgb: cannot read");
311           goto ErrorReturn;
312         }
313
314         /*
315           mm_log((1, "Buffer length %d\n", datalen));
316           for(i=0; i<datalen; i++) 
317           mm_log((1, "0x%x\n", databuf[i]));
318         */
319
320         while( iidx <= datalen && oidx < width ) {
321           if (!span) {
322             span = databuf[iidx] & 0x7f;
323             rle  = !(databuf[iidx++] & 0x80);
324             /*      mm_log((1,"new span %d, rle %d\n", span, rle)); */
325             if (rle) {
326               if (iidx==datalen) {
327                 i_push_error(0, "SGI rgb: bad rle data");
328                 goto ErrorReturn;
329               }
330               cval = databuf[iidx++];
331               /* mm_log((1, "rle value %d\n", cval)); */
332             }
333           }
334           linebuf[oidx++].channel[c] = rle ? cval : databuf[iidx++];
335           span--;
336           /*
337             mm_log((1,"iidx=%d/%d, oidx=%d/%d, linebuf[%d].channel[%d] %d\n", iidx-1, datalen, oidx-1, width, oidx-1, c, linebuf[oidx-1].channel[c]));
338           */
339         }
340       }
341       i_plin(img, 0, width, height-1-y, linebuf);
342     }
343     
344     break;
345   }
346
347   i_mempool_destroy(&mp);
348   return img;
349
350  ErrorReturn:
351   i_mempool_destroy(&mp);
352   if (img) i_img_destroy(img);
353   return NULL;
354 }
355
356
357
358 /*
359 =item i_writergb_wiol(img, ig)
360
361 Writes an image in targa format.  Returns 0 on error.
362
363    img    - image to store
364    ig     - io_glue object
365
366 =cut
367 */
368
369 undef_int
370 i_writergb_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idstring, size_t idlen) {
371   
372
373
374
375 }
376