af477cef2072b3031b486b7cb886aa2c46c2b32b
[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 "imager.h"
24 #include "imageri.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_low(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   int bytes, line_bytes;
147   mm_log((1,"i_img_16_new(x %d, y %d, ch %d)\n", x, y, ch));
148
149   if (x < 1 || y < 1) {
150     i_push_error(0, "Image sizes must be positive");
151     return NULL;
152   }
153   if (ch < 1 || ch > MAXCHANNELS) {
154     i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
155     return NULL;
156   }
157   bytes =  x * y * ch * 2;
158   if (bytes / y / ch / 2 != x) {
159     i_push_errorf(0, "integer overflow calculating image allocation");
160     return NULL;
161   }
162   
163   /* basic assumption: we can always allocate a buffer representing a
164      line from the image, otherwise we're going to have trouble
165      working with the image */
166   line_bytes = sizeof(i_fcolor) * x;
167   if (line_bytes / x != sizeof(i_fcolor)) {
168     i_push_error(0, "integer overflow calculating scanline allocation");
169     return NULL;
170   }
171
172   *im = IIM_base_16bit_direct;
173   i_tags_new(&im->tags);
174   im->xsize = x;
175   im->ysize = y;
176   im->channels = ch;
177   im->bytes = bytes;
178   im->ext_data = NULL;
179   im->idata = mymalloc(im->bytes);
180   if (im->idata) {
181     memset(im->idata, 0, im->bytes);
182   }
183   else {
184     i_tags_destroy(&im->tags);
185     im = NULL;
186   }
187   
188   return im;
189 }
190
191 /*
192 =item i_img_16_new(x, y, ch)
193
194 =category Image creation
195
196 Create a new 16-bit/sample image.
197
198 Returns the image on success, or NULL on failure.
199
200 =cut
201 */
202
203 i_img *i_img_16_new(int x, int y, int ch) {
204   i_img *im;
205   
206   i_clear_error();
207
208   im = mymalloc(sizeof(i_img));
209   if (im) {
210     if (!i_img_16_new_low(im, x, y, ch)) {
211       myfree(im);
212       im = NULL;
213     }
214   }
215   
216   mm_log((1, "(%p) <- i_img_16_new\n", im));
217   
218   return im;
219 }
220
221 static int i_ppix_d16(i_img *im, int x, int y, i_color *val) {
222   int off, ch;
223
224   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
225     return -1;
226
227   off = (x + y * im->xsize) * im->channels;
228   if (I_ALL_CHANNELS_WRITABLE(im)) {
229     for (ch = 0; ch < im->channels; ++ch)
230       STORE8as16(im->idata, off+ch, val->channel[ch]);
231   }
232   else {
233     for (ch = 0; ch < im->channels; ++ch)
234       if (im->ch_mask & (1 << ch))
235         STORE8as16(im->idata, off+ch, val->channel[ch]);
236   }
237
238   return 0;
239 }
240
241 static int i_gpix_d16(i_img *im, int x, int y, i_color *val) {
242   int off, ch;
243
244   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
245     return -1;
246
247   off = (x + y * im->xsize) * im->channels;
248   for (ch = 0; ch < im->channels; ++ch)
249     val->channel[ch] = GET16as8(im->idata, off+ch);
250
251   return 0;
252 }
253
254 static int i_ppixf_d16(i_img *im, int x, int y, i_fcolor *val) {
255   int off, ch;
256
257   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
258     return -1;
259
260   off = (x + y * im->xsize) * im->channels;
261   if (I_ALL_CHANNELS_WRITABLE(im)) {
262     for (ch = 0; ch < im->channels; ++ch)
263       STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
264   }
265   else {
266     for (ch = 0; ch < im->channels; ++ch)
267       if (im->ch_mask & (1 << ch))
268         STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
269   }
270
271   return 0;
272 }
273
274 static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val) {
275   int off, ch;
276
277   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
278     return -1;
279
280   off = (x + y * im->xsize) * im->channels;
281   for (ch = 0; ch < im->channels; ++ch)
282     val->channel[ch] = Sample16ToF(GET16(im->idata, off+ch));
283
284   return 0;
285 }
286
287 static int i_glin_d16(i_img *im, int l, int r, int y, i_color *vals) {
288   int ch, count, i;
289   int off;
290   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
291     if (r > im->xsize)
292       r = im->xsize;
293     off = (l+y*im->xsize) * im->channels;
294     count = r - l;
295     for (i = 0; i < count; ++i) {
296       for (ch = 0; ch < im->channels; ++ch) {
297         vals[i].channel[ch] = GET16as8(im->idata, off);
298         ++off;
299       }
300     }
301     return count;
302   }
303   else {
304     return 0;
305   }
306 }
307
308 static int i_plin_d16(i_img *im, int l, int r, int y, i_color *vals) {
309   int ch, count, i;
310   int off;
311   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
312     if (r > im->xsize)
313       r = im->xsize;
314     off = (l+y*im->xsize) * im->channels;
315     count = r - l;
316     if (I_ALL_CHANNELS_WRITABLE(im)) {
317       for (i = 0; i < count; ++i) {
318         for (ch = 0; ch < im->channels; ++ch) {
319           STORE8as16(im->idata, off, vals[i].channel[ch]);
320           ++off;
321         }
322       }
323     }
324     else {
325       for (i = 0; i < count; ++i) {
326         for (ch = 0; ch < im->channels; ++ch) {
327           if (im->ch_mask & (1 << ch))
328             STORE8as16(im->idata, off, vals[i].channel[ch]);
329           ++off;
330         }
331       }
332     }
333     return count;
334   }
335   else {
336     return 0;
337   }
338 }
339
340 static int i_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
341   int ch, count, i;
342   int off;
343   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
344     if (r > im->xsize)
345       r = im->xsize;
346     off = (l+y*im->xsize) * im->channels;
347     count = r - l;
348     for (i = 0; i < count; ++i) {
349       for (ch = 0; ch < im->channels; ++ch) {
350         vals[i].channel[ch] = Sample16ToF(GET16(im->idata, off));
351         ++off;
352       }
353     }
354     return count;
355   }
356   else {
357     return 0;
358   }
359 }
360
361 static int i_plinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
362   int ch, count, i;
363   int off;
364   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
365     if (r > im->xsize)
366       r = im->xsize;
367     off = (l+y*im->xsize) * im->channels;
368     count = r - l;
369     if (I_ALL_CHANNELS_WRITABLE(im)) {
370       for (i = 0; i < count; ++i) {
371         for (ch = 0; ch < im->channels; ++ch) {
372           STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
373           ++off;
374         }
375       }
376     }
377     else {
378       for (i = 0; i < count; ++i) {
379         for (ch = 0; ch < im->channels; ++ch) {
380           if (im->ch_mask & (1 << ch))
381             STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
382           ++off;
383         }
384       }
385     }
386     return count;
387   }
388   else {
389     return 0;
390   }
391 }
392
393 static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps, 
394                        int const *chans, int chan_count) {
395   int ch, count, i, w;
396   int off;
397
398   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
399     if (r > im->xsize)
400       r = im->xsize;
401     off = (l+y*im->xsize) * im->channels;
402     w = r - l;
403     count = 0;
404
405     if (chans) {
406       /* make sure we have good channel numbers */
407       for (ch = 0; ch < chan_count; ++ch) {
408         if (chans[ch] < 0 || chans[ch] >= im->channels) {
409           i_push_errorf(0, "No channel %d in this image", chans[ch]);
410           return 0;
411         }
412       }
413       for (i = 0; i < w; ++i) {
414         for (ch = 0; ch < chan_count; ++ch) {
415           *samps++ = GET16as8(im->idata, off+chans[ch]);
416           ++count;
417         }
418         off += im->channels;
419       }
420     }
421     else {
422       for (i = 0; i < w; ++i) {
423         for (ch = 0; ch < chan_count; ++ch) {
424           *samps++ = GET16as8(im->idata, off+ch);
425           ++count;
426         }
427         off += im->channels;
428       }
429     }
430
431     return count;
432   }
433   else {
434     return 0;
435   }
436 }
437
438 static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps, 
439                         int const *chans, int chan_count) {
440   int ch, count, i, w;
441   int off;
442
443   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
444     if (r > im->xsize)
445       r = im->xsize;
446     off = (l+y*im->xsize) * im->channels;
447     w = r - l;
448     count = 0;
449
450     if (chans) {
451       /* make sure we have good channel numbers */
452       for (ch = 0; ch < chan_count; ++ch) {
453         if (chans[ch] < 0 || chans[ch] >= im->channels) {
454           i_push_errorf(0, "No channel %d in this image", chans[ch]);
455           return 0;
456         }
457       }
458       for (i = 0; i < w; ++i) {
459         for (ch = 0; ch < chan_count; ++ch) {
460           *samps++ = Sample16ToF(GET16(im->idata, off+chans[ch]));
461           ++count;
462         }
463         off += im->channels;
464       }
465     }
466     else {
467       for (i = 0; i < w; ++i) {
468         for (ch = 0; ch < chan_count; ++ch) {
469           *samps++ = Sample16ToF(GET16(im->idata, off+ch));
470           ++count;
471         }
472         off += im->channels;
473       }
474     }
475
476     return count;
477   }
478   else {
479     return 0;
480   }
481 }
482
483 /*
484 =back
485
486 =head1 AUTHOR
487
488 Tony Cook <tony@develop-help.com>
489
490 =head1 SEE ALSO
491
492 Imager(3)
493
494 =cut
495 */