13 rgb.c - implements reading and writing sgi image files, uses io layer.
17 io_glue *ig = io_new_fd( fd );
18 i_img *im = i_readrgb_wiol(ig, -1); // no limit on how much is read
20 io_glue *ig = io_new_fd( fd );
21 return_code = i_writergb_wiol(im, ig);
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.
29 =head1 FUNCTION REFERENCE
31 Some of these functions are internal.
39 unsigned short imagic;
40 unsigned char storagetype;
42 unsigned short dimensions;
43 unsigned short xsize, ysize, zsize;
44 unsigned int min, max;
46 unsigned int colormap;
53 typedef enum { NoInit, Raw, Rle } rle_state;
69 =item rgb_header_unpack(header, headbuf)
71 Unpacks the header structure into from buffer and stores
72 in the header structure.
74 header - header structure
75 headbuf - buffer to unpack from
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];
99 =item rgb_header_pack(header, headbuf)
101 Packs header structure into buffer for writing.
103 header - header structure
104 headbuf - buffer to pack into
111 rgb_header_pack(rgb_header *header, unsigned char headbuf[512]) {
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];
132 =item rgb_dest_write(s, buf, pixels)
134 Writes pixels from buf to destination s. Takes care of compressing if the
135 destination is compressed.
139 pixels - number of pixels to put write to destination
146 rgb_dest_write(rgb_dest *s, unsigned char *buf, size_t pixels) {
158 =item i_readrgb_wiol(ig, length)
160 Read in an image from the iolayer data source and return the image structure to it.
161 Returns NULL on error.
164 length - maximum length to read from data source, before closing it -1
171 i_readrgb_wiol(io_glue *ig, int length) {
174 int width, height, channels;
175 unsigned long maxlen;
179 char *idstring = NULL;
182 unsigned char headbuf[512];
183 unsigned char *databuf;
184 unsigned char *reorderbuf;
185 unsigned long *starttab, *lengthtab;
186 i_color *linebuf = NULL;
189 mm_log((1,"i_readrgb(ig %p, length %d)\n", ig, length));
193 io_glue_commit_types(ig);
195 if (ig->readcb(ig, headbuf, 512) != 512) {
196 i_push_error(errno, "could not read SGI rgb header");
200 rgb_header_unpack(&header, headbuf);
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));
215 if (header.colormap != 0) {
216 i_push_error(0, "SGI rgb image has a non zero colormap entry - obsolete format");
220 if (header.storagetype != 0 && header.storagetype != 1) {
221 i_push_error(0, "SGI rgb image has has invalid storage field");
225 width = header.xsize;
226 height = header.ysize;
227 channels = header.zsize;
229 img = i_img_empty_ch(NULL, width, height, channels);
231 i_tags_add(&img->tags, "rgb_namestr", 0, header.name, 80, 0);
234 switch (header.storagetype) {
235 case 0: /* uncompressed */
237 linebuf = i_mempool_alloc(&mp, width*sizeof(i_color));
238 databuf = i_mempool_alloc(&mp, width);
240 savemask = i_img_getmask(img);
242 for(c=0; c<channels; c++) {
243 i_img_setmask(img, 1<<c);
244 for(y=0; y<height; y++) {
247 if (ig->readcb(ig, databuf, width) != width) {
248 i_push_error(0, "SGI rgb: cannot read");
252 for(x=0; x<width; x++)
253 linebuf[x].channel[c] = databuf[x];
255 i_plin(img, 0, width, height-1-y, linebuf);
258 i_img_setmask(img, savemask);
260 case 1: /* RLE compressed */
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));
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] =
271 (databuf[i*4+1]<<16) |
272 (databuf[i*4+2]<<8) |
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] =
280 (databuf[i*4+1]<<16)+
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]));
289 /* Find max spanlength if someone is making very badly formed RLE data */
291 for(y=0; y<height; y++) maxlen = (maxlen>lengthtab[y])?maxlen:lengthtab[y];
293 mm_log((1, "maxlen for an rle buffer: %d\n", maxlen));
295 databuf = i_mempool_alloc(&mp, maxlen);
297 for(y=0; y<height; y++) {
298 for(c=0; c<channels; c++) {
299 unsigned long iidx = 0, oidx = 0, span = 0;
303 int datalen = lengthtab[ci];
305 if (ig->seekcb(ig, starttab[ci], SEEK_SET) != starttab[ci]) {
306 i_push_error(0, "SGI rgb: cannot seek");
309 if (ig->readcb(ig, databuf, datalen) != datalen) {
310 i_push_error(0, "SGI rgb: cannot read");
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]));
320 while( iidx <= datalen && oidx < width ) {
322 span = databuf[iidx] & 0x7f;
323 rle = !(databuf[iidx++] & 0x80);
324 /* mm_log((1,"new span %d, rle %d\n", span, rle)); */
327 i_push_error(0, "SGI rgb: bad rle data");
330 cval = databuf[iidx++];
331 /* mm_log((1, "rle value %d\n", cval)); */
334 linebuf[oidx++].channel[c] = rle ? cval : databuf[iidx++];
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]));
341 i_plin(img, 0, width, height-1-y, linebuf);
347 i_mempool_destroy(&mp);
351 i_mempool_destroy(&mp);
352 if (img) i_img_destroy(img);
359 =item i_writergb_wiol(img, ig)
361 Writes an image in targa format. Returns 0 on error.
370 i_writergb_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idstring, size_t idlen) {