Egads
[imager.git] / img16.c
1 /*
2 =head1 NAME
3
4 img16.c - implements 16-bit images
5
6 =head1 SYNOPSIS
7
8   i_img *im = i_img_16_new(int x, int y, int channels);
9   # use like a normal image
10
11 =head1 DESCRIPTION
12
13 Implements 16-bit/sample images.
14
15 This basic implementation is required so that we have some larger 
16 sample image type to work with.
17
18 =over
19
20 =cut
21 */
22
23 #include "image.h"
24 #include "imagei.h"
25
26 static int i_ppix_d16(i_img *im, int x, int y, i_color *val);
27 static int i_gpix_d16(i_img *im, int x, int y, i_color *val);
28 static int i_glin_d16(i_img *im, int l, int r, int y, i_color *vals);
29 static int i_plin_d16(i_img *im, int l, int r, int y, i_color *vals);
30 static int i_ppixf_d16(i_img *im, int x, int y, i_fcolor *val);
31 static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val);
32 static int i_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals);
33 static int i_plinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals);
34 static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps, 
35                        int *chans, int chan_count);
36 static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps, 
37                         int *chans, int chan_count);
38
39 /*
40 =item IIM_base_16bit_direct
41
42 Base structure used to initialize a 16-bit/sample image.
43
44 Internal.
45
46 =cut
47 */
48 static i_img IIM_base_16bit_direct =
49 {
50   0, /* channels set */
51   0, 0, 0, /* xsize, ysize, bytes */
52   ~0, /* ch_mask */
53   i_16_bits, /* bits */
54   i_direct_type, /* type */
55   0, /* virtual */
56   NULL, /* idata */
57   { 0, 0, NULL }, /* tags */
58   NULL, /* ext_data */
59
60   i_ppix_d16, /* i_f_ppix */
61   i_ppixf_d16, /* i_f_ppixf */
62   i_plin_d16, /* i_f_plin */
63   i_plinf_d16, /* i_f_plinf */
64   i_gpix_d16, /* i_f_gpix */
65   i_gpixf_d16, /* i_f_gpixf */
66   i_glin_d16, /* i_f_glin */
67   i_glinf_d16, /* i_f_glinf */
68   i_gsamp_d16, /* i_f_gsamp */
69   i_gsampf_d16, /* i_f_gsampf */
70
71   NULL, /* i_f_gpal */
72   NULL, /* i_f_ppal */
73   NULL, /* i_f_addcolor */
74   NULL, /* i_f_getcolor */
75   NULL, /* i_f_colorcount */
76   NULL, /* i_f_findcolor */
77
78   NULL, /* i_f_destroy */
79 };
80
81 /* it's possible some platforms won't have a 16-bit integer type,
82    so we check for one otherwise we work by bytes directly
83
84    We do assume 8-bit char
85 */
86 #if __STDC_VERSION__ >= 199901L
87 /* C99 should define something useful */
88 #include <stdint.h>
89 #ifdef UINT16_MAX
90 typedef uint16_t i_sample16_t;
91 #define GOT16
92 #endif
93 #endif
94
95 /* check out unsigned short */
96 #ifndef GOT16
97 #include <limits.h>
98 #if USHRT_MAX == 65535
99 typedef unsigned short i_sample16_t;
100 #define GOT16
101 #endif
102 #endif
103
104 #ifdef GOT16
105
106 /* we have a real 16-bit unsigned integer */
107 #define STORE16(bytes, offset, word) \
108    (((i_sample16_t *)(bytes))[offset] = (word))
109 #define STORE8as16(bytes, offset, byte) \
110    (((i_sample16_t *)(bytes))[offset] = (byte) * 256)
111 #define GET16(bytes, offset) \
112      (((i_sample16_t *)(bytes))[offset])
113 #define GET16as8(bytes, offset) \
114      (((i_sample16_t *)(bytes))[offset] / 256)
115
116 #else
117
118 /* we have to do this the hard way */
119 #define STORE16(bytes, offset, word) \
120    ((((unsigned char *)(bytes))[(offset)*2] = (word) >> 8), \
121     (((unsigned char *)(bytes))[(offset)*2+1] = (word) & 0xFF))
122 #define STORE8as16(bytes, offset, byte) \
123    ((((unsigned char *)(bytes))[(offset)*2] = (byte)), \
124     (((unsigned char *)(bytes))[(offset)*2+1] = 0))
125    
126 #define GET16(bytes, offset) \
127    (((unsigned char *)(bytes))[(offset)*2] * 256 \
128     + ((unsigned char *)(bytes))[(offset)*2+1])
129 #define GET16as8(bytes, offset) \
130    (((unsigned char *)(bytes))[(offset)*2] << 8)
131
132 #endif
133
134 /*
135 =item i_img_16_new(int x, int y, int ch)
136
137 Creates a new 16-bit per sample image.
138 */
139 i_img *i_img_16_new_low(i_img *im, int x, int y, int ch) {
140   mm_log((1,"i_img_16_new(x %d, y %d, ch %d)\n", x, y, ch));
141   
142   *im = IIM_base_16bit_direct;
143   i_tags_new(&im->tags);
144   im->xsize = x;
145   im->ysize = y;
146   im->channels = ch;
147   im->bytes = x * y * ch * 2;
148   im->ext_data = NULL;
149   im->idata = mymalloc(im->bytes);
150   if (im->idata) {
151     memset(im->idata, 0, im->bytes);
152   }
153   else {
154     i_tags_destroy(&im->tags);
155     im = NULL;
156   }
157   
158   return im;
159 }
160
161 i_img *i_img_16_new(int x, int y, int ch) {
162   i_img *im;
163
164   im = mymalloc(sizeof(i_img));
165   if (im) {
166     if (!i_img_16_new_low(im, x, y, ch)) {
167       myfree(im);
168       im = NULL;
169     }
170   }
171   
172   mm_log((1, "(%p) <- i_img_16_new\n", im));
173   
174   return im;
175 }
176
177 static int i_ppix_d16(i_img *im, int x, int y, i_color *val) {
178   int off, ch;
179
180   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
181     return -1;
182
183   off = (x + y * im->xsize) * im->channels;
184   for (ch = 0; ch < im->channels; ++ch)
185     STORE8as16(im->idata, off+ch, val->channel[ch]);
186
187   return 0;
188 }
189
190 static int i_gpix_d16(i_img *im, int x, int y, i_color *val) {
191   int off, ch;
192
193   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
194     return -1;
195
196   off = (x + y * im->xsize) * im->channels;
197   for (ch = 0; ch < im->channels; ++ch)
198     val->channel[ch] = GET16as8(im->idata, off+ch);
199
200   return 0;
201 }
202
203 static int i_ppixf_d16(i_img *im, int x, int y, i_fcolor *val) {
204   int off, ch;
205
206   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
207     return -1;
208
209   off = (x + y * im->xsize) * im->channels;
210   for (ch = 0; ch < im->channels; ++ch)
211     STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
212
213   return 0;
214 }
215
216 static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val) {
217   int off, ch;
218
219   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
220     return -1;
221
222   off = (x + y * im->xsize) * im->channels;
223   for (ch = 0; ch < im->channels; ++ch)
224     val->channel[ch] = Sample16ToF(GET16(im->idata, off+ch));
225
226   return 0;
227 }
228
229 static int i_glin_d16(i_img *im, int l, int r, int y, i_color *vals) {
230   int ch, count, i;
231   int off;
232   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
233     if (r > im->xsize)
234       r = im->xsize;
235     off = (l+y*im->xsize) * im->channels;
236     count = r - l;
237     for (i = 0; i < count; ++i) {
238       for (ch = 0; ch < im->channels; ++ch) {
239         vals[i].channel[ch] = GET16as8(im->idata, off);
240         ++off;
241       }
242     }
243     return count;
244   }
245   else {
246     return 0;
247   }
248 }
249
250 static int i_plin_d16(i_img *im, int l, int r, int y, i_color *vals) {
251   int ch, count, i;
252   int off;
253   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
254     if (r > im->xsize)
255       r = im->xsize;
256     off = (l+y*im->xsize) * im->channels;
257     count = r - l;
258     for (i = 0; i < count; ++i) {
259       for (ch = 0; ch < im->channels; ++ch) {
260         STORE8as16(im->idata, off, vals[i].channel[ch]);
261         ++off;
262       }
263     }
264     return count;
265   }
266   else {
267     return 0;
268   }
269 }
270
271 static int i_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
272   int ch, count, i;
273   int off;
274   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
275     if (r > im->xsize)
276       r = im->xsize;
277     off = (l+y*im->xsize) * im->channels;
278     count = r - l;
279     for (i = 0; i < count; ++i) {
280       for (ch = 0; ch < im->channels; ++ch) {
281         vals[i].channel[ch] = Sample16ToF(GET16(im->idata, off));
282         ++off;
283       }
284     }
285     return count;
286   }
287   else {
288     return 0;
289   }
290 }
291
292 static int i_plinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
293   int ch, count, i;
294   int off;
295   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
296     if (r > im->xsize)
297       r = im->xsize;
298     off = (l+y*im->xsize) * im->channels;
299     count = r - l;
300     for (i = 0; i < count; ++i) {
301       for (ch = 0; ch < im->channels; ++ch) {
302         STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
303         ++off;
304       }
305     }
306     return count;
307   }
308   else {
309     return 0;
310   }
311 }
312
313 static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps, 
314                        int *chans, int chan_count) {
315   int ch, count, i, w;
316   int off;
317
318   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
319     if (r > im->xsize)
320       r = im->xsize;
321     off = (l+y*im->xsize) * im->channels;
322     w = r - l;
323     count = 0;
324
325     if (chans) {
326       /* make sure we have good channel numbers */
327       for (ch = 0; ch < chan_count; ++ch) {
328         if (chans[ch] < 0 || chans[ch] >= im->channels) {
329           i_push_errorf(0, "No channel %d in this image", chans[ch]);
330           return 0;
331         }
332       }
333       for (i = 0; i < w; ++i) {
334         for (ch = 0; ch < chan_count; ++ch) {
335           *samps++ = GET16as8(im->idata, off+chans[ch]);
336           ++count;
337         }
338         off += im->channels;
339       }
340     }
341     else {
342       for (i = 0; i < w; ++i) {
343         for (ch = 0; ch < chan_count; ++ch) {
344           *samps++ = GET16as8(im->idata, off+ch);
345           ++count;
346         }
347         off += im->channels;
348       }
349     }
350
351     return count;
352   }
353   else {
354     return 0;
355   }
356 }
357
358 static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps, 
359                         int *chans, int chan_count) {
360   int ch, count, i, w;
361   int off;
362
363   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
364     if (r > im->xsize)
365       r = im->xsize;
366     off = (l+y*im->xsize) * im->channels;
367     w = r - l;
368     count = 0;
369
370     if (chans) {
371       /* make sure we have good channel numbers */
372       for (ch = 0; ch < chan_count; ++ch) {
373         if (chans[ch] < 0 || chans[ch] >= im->channels) {
374           i_push_errorf(0, "No channel %d in this image", chans[ch]);
375           return 0;
376         }
377       }
378       for (i = 0; i < w; ++i) {
379         for (ch = 0; ch < chan_count; ++ch) {
380           *samps++ = Sample16ToF(GET16(im->idata, off+chans[ch]));
381           ++count;
382         }
383         off += im->channels;
384       }
385     }
386     else {
387       for (i = 0; i < w; ++i) {
388         for (ch = 0; ch < chan_count; ++ch) {
389           *samps++ = Sample16ToF(GET16(im->idata, off+ch));
390           ++count;
391         }
392         off += im->channels;
393       }
394     }
395
396     return count;
397   }
398   else {
399     return 0;
400   }
401 }
402