- previously, if you supplied to_paletted and empty color map
[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 const *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 const *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   ~0U, /* 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    "Compaq C V6.4-009 on Compaq Tru64 UNIX V5.1A (Rev. 1885)" says it
87    supports C99, but doesn't supply stdint.h, which is required for
88    both hosted and freestanding implementations.  So guard against it.
89 */
90 #if __STDC_VERSION__ >= 199901L && !defined(OS_dec_osf)
91 /* C99 should define something useful */
92 #include <stdint.h>
93 #ifdef UINT16_MAX
94 typedef uint16_t i_sample16_t;
95 #define GOT16
96 #endif
97 #endif
98
99 /* check out unsigned short */
100 #ifndef GOT16
101 #include <limits.h>
102 #if USHRT_MAX == 65535
103 typedef unsigned short i_sample16_t;
104 #define GOT16
105 #endif
106 #endif
107
108 #ifdef GOT16
109
110 /* we have a real 16-bit unsigned integer */
111 #define STORE16(bytes, offset, word) \
112    (((i_sample16_t *)(bytes))[offset] = (word))
113 #define STORE8as16(bytes, offset, byte) \
114    (((i_sample16_t *)(bytes))[offset] = (byte) * 256)
115 #define GET16(bytes, offset) \
116      (((i_sample16_t *)(bytes))[offset])
117 #define GET16as8(bytes, offset) \
118      (((i_sample16_t *)(bytes))[offset] / 256)
119
120 #else
121
122 /* we have to do this the hard way */
123 #define STORE16(bytes, offset, word) \
124    ((((unsigned char *)(bytes))[(offset)*2] = (word) >> 8), \
125     (((unsigned char *)(bytes))[(offset)*2+1] = (word) & 0xFF))
126 #define STORE8as16(bytes, offset, byte) \
127    ((((unsigned char *)(bytes))[(offset)*2] = (byte)), \
128     (((unsigned char *)(bytes))[(offset)*2+1] = 0))
129    
130 #define GET16(bytes, offset) \
131    (((unsigned char *)(bytes))[(offset)*2] * 256 \
132     + ((unsigned char *)(bytes))[(offset)*2+1])
133 #define GET16as8(bytes, offset) \
134    (((unsigned char *)(bytes))[(offset)*2] << 8)
135
136 #endif
137
138 /*
139 =item i_img_16_new(int x, int y, int ch)
140
141 Creates a new 16-bit per sample image.
142
143 =cut
144 */
145 i_img *i_img_16_new_low(i_img *im, int x, int y, int ch) {
146   mm_log((1,"i_img_16_new(x %d, y %d, ch %d)\n", x, y, ch));
147
148   if (x < 1 || y < 1) {
149     i_push_error(0, "Image sizes must be positive");
150     return NULL;
151   }
152   if (ch < 1 || ch > MAXCHANNELS) {
153     i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
154     return NULL;
155   }
156   
157   *im = IIM_base_16bit_direct;
158   i_tags_new(&im->tags);
159   im->xsize = x;
160   im->ysize = y;
161   im->channels = ch;
162   im->bytes = x * y * ch * 2;
163   im->ext_data = NULL;
164   im->idata = mymalloc(im->bytes);
165   if (im->idata) {
166     memset(im->idata, 0, im->bytes);
167   }
168   else {
169     i_tags_destroy(&im->tags);
170     im = NULL;
171   }
172   
173   return im;
174 }
175
176 i_img *i_img_16_new(int x, int y, int ch) {
177   i_img *im;
178   
179   i_clear_error();
180
181   im = mymalloc(sizeof(i_img));
182   if (im) {
183     if (!i_img_16_new_low(im, x, y, ch)) {
184       myfree(im);
185       im = NULL;
186     }
187   }
188   
189   mm_log((1, "(%p) <- i_img_16_new\n", im));
190   
191   return im;
192 }
193
194 static int i_ppix_d16(i_img *im, int x, int y, i_color *val) {
195   int off, ch;
196
197   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
198     return -1;
199
200   off = (x + y * im->xsize) * im->channels;
201   for (ch = 0; ch < im->channels; ++ch)
202     STORE8as16(im->idata, off+ch, val->channel[ch]);
203
204   return 0;
205 }
206
207 static int i_gpix_d16(i_img *im, int x, int y, i_color *val) {
208   int off, ch;
209
210   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
211     return -1;
212
213   off = (x + y * im->xsize) * im->channels;
214   for (ch = 0; ch < im->channels; ++ch)
215     val->channel[ch] = GET16as8(im->idata, off+ch);
216
217   return 0;
218 }
219
220 static int i_ppixf_d16(i_img *im, int x, int y, i_fcolor *val) {
221   int off, ch;
222
223   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
224     return -1;
225
226   off = (x + y * im->xsize) * im->channels;
227   for (ch = 0; ch < im->channels; ++ch)
228     STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
229
230   return 0;
231 }
232
233 static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val) {
234   int off, ch;
235
236   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
237     return -1;
238
239   off = (x + y * im->xsize) * im->channels;
240   for (ch = 0; ch < im->channels; ++ch)
241     val->channel[ch] = Sample16ToF(GET16(im->idata, off+ch));
242
243   return 0;
244 }
245
246 static int i_glin_d16(i_img *im, int l, int r, int y, i_color *vals) {
247   int ch, count, i;
248   int off;
249   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
250     if (r > im->xsize)
251       r = im->xsize;
252     off = (l+y*im->xsize) * im->channels;
253     count = r - l;
254     for (i = 0; i < count; ++i) {
255       for (ch = 0; ch < im->channels; ++ch) {
256         vals[i].channel[ch] = GET16as8(im->idata, off);
257         ++off;
258       }
259     }
260     return count;
261   }
262   else {
263     return 0;
264   }
265 }
266
267 static int i_plin_d16(i_img *im, int l, int r, int y, i_color *vals) {
268   int ch, count, i;
269   int off;
270   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
271     if (r > im->xsize)
272       r = im->xsize;
273     off = (l+y*im->xsize) * im->channels;
274     count = r - l;
275     for (i = 0; i < count; ++i) {
276       for (ch = 0; ch < im->channels; ++ch) {
277         STORE8as16(im->idata, off, vals[i].channel[ch]);
278         ++off;
279       }
280     }
281     return count;
282   }
283   else {
284     return 0;
285   }
286 }
287
288 static int i_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
289   int ch, count, i;
290   int off;
291   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
292     if (r > im->xsize)
293       r = im->xsize;
294     off = (l+y*im->xsize) * im->channels;
295     count = r - l;
296     for (i = 0; i < count; ++i) {
297       for (ch = 0; ch < im->channels; ++ch) {
298         vals[i].channel[ch] = Sample16ToF(GET16(im->idata, off));
299         ++off;
300       }
301     }
302     return count;
303   }
304   else {
305     return 0;
306   }
307 }
308
309 static int i_plinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
310   int ch, count, i;
311   int off;
312   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
313     if (r > im->xsize)
314       r = im->xsize;
315     off = (l+y*im->xsize) * im->channels;
316     count = r - l;
317     for (i = 0; i < count; ++i) {
318       for (ch = 0; ch < im->channels; ++ch) {
319         STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
320         ++off;
321       }
322     }
323     return count;
324   }
325   else {
326     return 0;
327   }
328 }
329
330 static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps, 
331                        int const *chans, int chan_count) {
332   int ch, count, i, w;
333   int off;
334
335   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
336     if (r > im->xsize)
337       r = im->xsize;
338     off = (l+y*im->xsize) * im->channels;
339     w = r - l;
340     count = 0;
341
342     if (chans) {
343       /* make sure we have good channel numbers */
344       for (ch = 0; ch < chan_count; ++ch) {
345         if (chans[ch] < 0 || chans[ch] >= im->channels) {
346           i_push_errorf(0, "No channel %d in this image", chans[ch]);
347           return 0;
348         }
349       }
350       for (i = 0; i < w; ++i) {
351         for (ch = 0; ch < chan_count; ++ch) {
352           *samps++ = GET16as8(im->idata, off+chans[ch]);
353           ++count;
354         }
355         off += im->channels;
356       }
357     }
358     else {
359       for (i = 0; i < w; ++i) {
360         for (ch = 0; ch < chan_count; ++ch) {
361           *samps++ = GET16as8(im->idata, off+ch);
362           ++count;
363         }
364         off += im->channels;
365       }
366     }
367
368     return count;
369   }
370   else {
371     return 0;
372   }
373 }
374
375 static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps, 
376                         int const *chans, int chan_count) {
377   int ch, count, i, w;
378   int off;
379
380   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
381     if (r > im->xsize)
382       r = im->xsize;
383     off = (l+y*im->xsize) * im->channels;
384     w = r - l;
385     count = 0;
386
387     if (chans) {
388       /* make sure we have good channel numbers */
389       for (ch = 0; ch < chan_count; ++ch) {
390         if (chans[ch] < 0 || chans[ch] >= im->channels) {
391           i_push_errorf(0, "No channel %d in this image", chans[ch]);
392           return 0;
393         }
394       }
395       for (i = 0; i < w; ++i) {
396         for (ch = 0; ch < chan_count; ++ch) {
397           *samps++ = Sample16ToF(GET16(im->idata, off+chans[ch]));
398           ++count;
399         }
400         off += im->channels;
401       }
402     }
403     else {
404       for (i = 0; i < w; ++i) {
405         for (ch = 0; ch < chan_count; ++ch) {
406           *samps++ = Sample16ToF(GET16(im->idata, off+ch));
407           ++count;
408         }
409         off += im->channels;
410       }
411     }
412
413     return count;
414   }
415   else {
416     return 0;
417   }
418 }
419
420 /*
421 =back
422
423 =head1 AUTHOR
424
425 Tony Cook <tony@develop-help.com>
426
427 =head1 SEE ALSO
428
429 Imager(3)
430
431 =cut
432 */