switch to using size_t and i_img_dim strictly
[imager.git] / raw.c
1 #include "imager.h"
2 #include <stdio.h>
3 #include "iolayer.h"
4 #ifndef _MSC_VER
5 #include <unistd.h>
6 #endif
7 #include <string.h>
8 #include <errno.h>
9
10
11
12 /*
13
14  Image loader for raw files.
15
16  This is a barebones raw loader...
17
18              fd: filedescriptor
19               x: xsize
20               y: ysize
21    datachannels: the number of channels the file contains
22   storechannels: the bitmap of channels we will read
23           intrl: interlace flag,
24                        0 = sample interleaving
25                        1 = line interleaving
26                        2 = image interleaving (not implemented)
27
28 */
29
30 static
31 void
32 interleave(unsigned char *inbuffer,unsigned char *outbuffer,i_img_dim rowsize,int channels) {
33   i_img_dim ind,i;
34   int ch;
35   i=0;
36   if (inbuffer == outbuffer) return; /* Check if data is already in interleaved format */
37   for (ind=0; ind<rowsize; ind++) 
38     for (ch=0; ch<channels; ch++) 
39       outbuffer[i++] = inbuffer[rowsize*ch+ind]; 
40 }
41
42 static
43 void
44 expandchannels(unsigned char *inbuffer, unsigned char *outbuffer, 
45                i_img_dim xsize, int datachannels, int storechannels) {
46   i_img_dim x;
47   int ch;
48   int copy_chans = storechannels > datachannels ? datachannels : storechannels;
49   if (inbuffer == outbuffer)
50     return; /* Check if data is already in expanded format */
51   for(x = 0; x < xsize; x++) {
52     for (ch = 0; ch < copy_chans; ch++) 
53       outbuffer[x*storechannels+ch] = inbuffer[x*datachannels+ch];
54     for (; ch < storechannels; ch++)
55       outbuffer[x*storechannels+ch] = 0;
56   }
57 }
58
59 i_img *
60 i_readraw_wiol(io_glue *ig, i_img_dim x, i_img_dim y, int datachannels, int storechannels, int intrl) {
61   i_img* im;
62   ssize_t rc;
63   i_img_dim k;
64
65   unsigned char *inbuffer;
66   unsigned char *ilbuffer;
67   unsigned char *exbuffer;
68   
69   size_t inbuflen,ilbuflen,exbuflen;
70
71   i_clear_error();
72   
73   io_glue_commit_types(ig);
74   mm_log((1, "i_readraw(ig %p,x %" i_DF ",y %" i_DF ",datachannels %d,storechannels %d,intrl %d)\n",
75           ig, i_DFc(x), i_DFc(y), datachannels, storechannels, intrl));
76
77   if (intrl != 0 && intrl != 1) {
78     i_push_error(0, "raw_interleave must be 0 or 1");
79     return NULL;
80   }
81   if (storechannels < 1 || storechannels > 4) {
82     i_push_error(0, "raw_storechannels must be between 1 and 4");
83     return NULL;
84   }
85   
86   im = i_img_empty_ch(NULL,x,y,storechannels);
87   if (!im)
88     return NULL;
89   
90   inbuflen = im->xsize*datachannels;
91   ilbuflen = inbuflen;
92   exbuflen = im->xsize*storechannels;
93   inbuffer = (unsigned char*)mymalloc(inbuflen);
94   mm_log((1,"inbuflen: %ld, ilbuflen: %ld, exbuflen: %ld.\n",
95           (long)inbuflen, (long)ilbuflen, (long)exbuflen));
96
97   if (intrl==0) ilbuffer = inbuffer; 
98   else ilbuffer=mymalloc(inbuflen);
99
100   if (datachannels==storechannels) exbuffer=ilbuffer; 
101   else exbuffer= mymalloc(exbuflen);
102   
103   k=0;
104   while( k<im->ysize ) {
105     rc = ig->readcb(ig, inbuffer, inbuflen);
106     if (rc != inbuflen) { 
107       if (rc < 0)
108         i_push_error(0, "error reading file");
109       else
110         i_push_error(0, "premature end of file");
111       i_img_destroy(im);
112       myfree(inbuffer);
113       if (intrl != 0) myfree(ilbuffer);
114       if (datachannels != storechannels) myfree(exbuffer);
115       return NULL;
116     }
117     interleave(inbuffer,ilbuffer,im->xsize,datachannels);
118     expandchannels(ilbuffer,exbuffer,im->xsize,datachannels,storechannels);
119     /* FIXME: Do we ever want to save to a virtual image? */
120     memcpy(&(im->idata[im->xsize*storechannels*k]),exbuffer,exbuflen);
121     k++;
122   }
123
124   myfree(inbuffer);
125   if (intrl != 0) myfree(ilbuffer);
126   if (datachannels != storechannels) myfree(exbuffer);
127
128   i_tags_add(&im->tags, "i_format", 0, "raw", -1, 0);
129
130   return im;
131 }
132
133
134
135 undef_int
136 i_writeraw_wiol(i_img* im, io_glue *ig) {
137   ssize_t rc;
138
139   io_glue_commit_types(ig);
140   i_clear_error();
141   mm_log((1,"writeraw(im %p,ig %p)\n", im, ig));
142   
143   if (im == NULL) { mm_log((1,"Image is empty\n")); return(0); }
144   if (!im->virtual) {
145     rc = ig->writecb(ig,im->idata,im->bytes);
146     if (rc != im->bytes) { 
147       i_push_error(errno, "Could not write to file");
148       mm_log((1,"i_writeraw: Couldn't write to file\n")); 
149       return(0);
150     }
151   } else {
152     if (im->type == i_direct_type) {
153       /* just save it as 8-bits, maybe support saving higher bit count
154          raw images later */
155       size_t line_size = im->xsize * im->channels;
156       unsigned char *data = mymalloc(line_size);
157
158       i_img_dim y = 0;
159       rc = line_size;
160       while (rc == line_size && y < im->ysize) {
161         i_gsamp(im, 0, im->xsize, y, data, NULL, im->channels);
162         rc = ig->writecb(ig, data, line_size);
163         ++y;
164       }
165       if (rc != line_size) {
166         i_push_error(errno, "write error");
167         return 0;
168       }
169       myfree(data);
170     } else {
171       /* paletted image - assumes the caller puts the palette somewhere 
172          else
173       */
174       size_t line_size = sizeof(i_palidx) * im->xsize;
175       i_palidx *data = mymalloc(sizeof(i_palidx) * im->xsize);
176
177       i_img_dim y = 0;
178       rc = line_size;
179       while (rc == line_size && y < im->ysize) {
180         i_gpal(im, 0, im->xsize, y, data);
181         rc = ig->writecb(ig, data, line_size);
182         ++y;
183       }
184       myfree(data);
185       if (rc != line_size) {
186         i_push_error(errno, "write error");
187         return 0;
188       }
189     }
190   }
191
192   ig->closecb(ig);
193
194   return(1);
195 }