API documentation (mostly)
[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, const 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, const i_color *vals);
30 static int i_ppixf_d16(i_img *im, int x, int y, const 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, const 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 static int i_gsamp_bits_d16(i_img *im, int l, int r, int y, unsigned *samps, 
39                             int const *chans, int chan_count, int bits);
40 static int i_psamp_bits_d16(i_img *im, int l, int r, int y, unsigned const *samps, 
41                             int const *chans, int chan_count, int bits);
42
43 /*
44 =item IIM_base_16bit_direct
45
46 Base structure used to initialize a 16-bit/sample image.
47
48 Internal.
49
50 =cut
51 */
52 static i_img IIM_base_16bit_direct =
53 {
54   0, /* channels set */
55   0, 0, 0, /* xsize, ysize, bytes */
56   ~0U, /* ch_mask */
57   i_16_bits, /* bits */
58   i_direct_type, /* type */
59   0, /* virtual */
60   NULL, /* idata */
61   { 0, 0, NULL }, /* tags */
62   NULL, /* ext_data */
63
64   i_ppix_d16, /* i_f_ppix */
65   i_ppixf_d16, /* i_f_ppixf */
66   i_plin_d16, /* i_f_plin */
67   i_plinf_d16, /* i_f_plinf */
68   i_gpix_d16, /* i_f_gpix */
69   i_gpixf_d16, /* i_f_gpixf */
70   i_glin_d16, /* i_f_glin */
71   i_glinf_d16, /* i_f_glinf */
72   i_gsamp_d16, /* i_f_gsamp */
73   i_gsampf_d16, /* i_f_gsampf */
74
75   NULL, /* i_f_gpal */
76   NULL, /* i_f_ppal */
77   NULL, /* i_f_addcolors */
78   NULL, /* i_f_getcolors */
79   NULL, /* i_f_colorcount */
80   NULL, /* i_f_maxcolors */
81   NULL, /* i_f_findcolor */
82   NULL, /* i_f_setcolors */
83
84   NULL, /* i_f_destroy */
85
86   i_gsamp_bits_d16,
87   i_psamp_bits_d16,
88 };
89
90 /* it's possible some platforms won't have a 16-bit integer type,
91    so we check for one otherwise we work by bytes directly
92
93    We do assume 8-bit char
94
95    "Compaq C V6.4-009 on Compaq Tru64 UNIX V5.1A (Rev. 1885)" says it
96    supports C99, but doesn't supply stdint.h, which is required for
97    both hosted and freestanding implementations.  So guard against it.
98 */
99 #if __STDC_VERSION__ >= 199901L && !defined(OS_dec_osf)
100 /* C99 should define something useful */
101 #include <stdint.h>
102 #ifdef UINT16_MAX
103 typedef uint16_t i_sample16_t;
104 #define GOT16
105 #endif
106 #endif
107
108 /* check out unsigned short */
109 #ifndef GOT16
110 #include <limits.h>
111 #if USHRT_MAX == 65535
112 typedef unsigned short i_sample16_t;
113 #define GOT16
114 #endif
115 #endif
116
117 #ifdef GOT16
118
119 /* we have a real 16-bit unsigned integer */
120 #define STORE16(bytes, offset, word) \
121    (((i_sample16_t *)(bytes))[offset] = (word))
122 #define STORE8as16(bytes, offset, byte) \
123    (((i_sample16_t *)(bytes))[offset] = (byte) * 256 + (byte))
124 #define GET16(bytes, offset) \
125      (((i_sample16_t *)(bytes))[offset])
126 #else
127
128 /* we have to do this the hard way */
129 #define STORE16(bytes, offset, word) \
130    ((((unsigned char *)(bytes))[(offset)*2] = (word) >> 8), \
131     (((unsigned char *)(bytes))[(offset)*2+1] = (word) & 0xFF))
132 #define STORE8as16(bytes, offset, byte) \
133    ((((unsigned char *)(bytes))[(offset)*2] = (byte)), \
134     (((unsigned char *)(bytes))[(offset)*2+1] = (byte)))
135    
136 #define GET16(bytes, offset) \
137    (((unsigned char *)(bytes))[(offset)*2] * 256 \
138     + ((unsigned char *)(bytes))[(offset)*2+1])
139
140 #endif
141
142 #define GET16as8(bytes, offset) \
143      ((((i_sample16_t *)(bytes))[offset]+127) / 257)
144
145 /*
146 =item i_img_16_new(x, y, ch)
147
148 =category Image creation/destruction
149 =synopsis i_img *img = i_img_16_new(width, height, channels);
150
151 Create a new 16-bit/sample image.
152
153 Returns the image on success, or NULL on failure.
154
155 =cut
156 */
157
158 i_img *i_img_16_new(int x, int y, int ch) {
159   i_img *im;
160   int bytes, line_bytes;
161
162   mm_log((1,"i_img_16_new(x %d, y %d, ch %d)\n", x, y, ch));
163
164   if (x < 1 || y < 1) {
165     i_push_error(0, "Image sizes must be positive");
166     return NULL;
167   }
168   if (ch < 1 || ch > MAXCHANNELS) {
169     i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
170     return NULL;
171   }
172   bytes =  x * y * ch * 2;
173   if (bytes / y / ch / 2 != x) {
174     i_push_errorf(0, "integer overflow calculating image allocation");
175     return NULL;
176   }
177   
178   /* basic assumption: we can always allocate a buffer representing a
179      line from the image, otherwise we're going to have trouble
180      working with the image */
181   line_bytes = sizeof(i_fcolor) * x;
182   if (line_bytes / x != sizeof(i_fcolor)) {
183     i_push_error(0, "integer overflow calculating scanline allocation");
184     return NULL;
185   }
186
187   im = i_img_alloc();
188   *im = IIM_base_16bit_direct;
189   i_tags_new(&im->tags);
190   im->xsize = x;
191   im->ysize = y;
192   im->channels = ch;
193   im->bytes = bytes;
194   im->ext_data = NULL;
195   im->idata = mymalloc(im->bytes);
196   memset(im->idata, 0, im->bytes);
197
198   i_img_init(im);
199
200   return im;
201 }
202
203 /*
204 =item i_img_to_rgb16(im)
205
206 =category Image creation
207
208 Returns a 16-bit/sample version of the supplied image.
209
210 Returns the image on success, or NULL on failure.
211
212 =cut
213 */
214
215 i_img *
216 i_img_to_rgb16(i_img *im) {
217   i_img *targ;
218   i_fcolor *line;
219   int y;
220
221   targ = i_img_16_new(im->xsize, im->ysize, im->channels);
222   if (!targ)
223     return NULL;
224   line = mymalloc(sizeof(i_fcolor) * im->xsize);
225   for (y = 0; y < im->ysize; ++y) {
226     i_glinf(im, 0, im->xsize, y, line);
227     i_plinf(targ, 0, im->xsize, y, line);
228   }
229
230   myfree(line);
231
232   return targ;
233 }
234
235 static int i_ppix_d16(i_img *im, int x, int y, const i_color *val) {
236   int off, ch;
237
238   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
239     return -1;
240
241   off = (x + y * im->xsize) * im->channels;
242   if (I_ALL_CHANNELS_WRITABLE(im)) {
243     for (ch = 0; ch < im->channels; ++ch)
244       STORE8as16(im->idata, off+ch, val->channel[ch]);
245   }
246   else {
247     for (ch = 0; ch < im->channels; ++ch)
248       if (im->ch_mask & (1 << ch))
249         STORE8as16(im->idata, off+ch, val->channel[ch]);
250   }
251
252   return 0;
253 }
254
255 static int i_gpix_d16(i_img *im, int x, int y, i_color *val) {
256   int off, ch;
257
258   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
259     return -1;
260
261   off = (x + y * im->xsize) * im->channels;
262   for (ch = 0; ch < im->channels; ++ch)
263     val->channel[ch] = GET16as8(im->idata, off+ch);
264
265   return 0;
266 }
267
268 static int i_ppixf_d16(i_img *im, int x, int y, const i_fcolor *val) {
269   int off, ch;
270
271   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
272     return -1;
273
274   off = (x + y * im->xsize) * im->channels;
275   if (I_ALL_CHANNELS_WRITABLE(im)) {
276     for (ch = 0; ch < im->channels; ++ch)
277       STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
278   }
279   else {
280     for (ch = 0; ch < im->channels; ++ch)
281       if (im->ch_mask & (1 << ch))
282         STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
283   }
284
285   return 0;
286 }
287
288 static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val) {
289   int off, ch;
290
291   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
292     return -1;
293
294   off = (x + y * im->xsize) * im->channels;
295   for (ch = 0; ch < im->channels; ++ch)
296     val->channel[ch] = Sample16ToF(GET16(im->idata, off+ch));
297
298   return 0;
299 }
300
301 static int i_glin_d16(i_img *im, int l, int r, int y, i_color *vals) {
302   int ch, count, i;
303   int off;
304   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
305     if (r > im->xsize)
306       r = im->xsize;
307     off = (l+y*im->xsize) * im->channels;
308     count = r - l;
309     for (i = 0; i < count; ++i) {
310       for (ch = 0; ch < im->channels; ++ch) {
311         vals[i].channel[ch] = GET16as8(im->idata, off);
312         ++off;
313       }
314     }
315     return count;
316   }
317   else {
318     return 0;
319   }
320 }
321
322 static int i_plin_d16(i_img *im, int l, int r, int y, const i_color *vals) {
323   int ch, count, i;
324   int off;
325   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
326     if (r > im->xsize)
327       r = im->xsize;
328     off = (l+y*im->xsize) * im->channels;
329     count = r - l;
330     if (I_ALL_CHANNELS_WRITABLE(im)) {
331       for (i = 0; i < count; ++i) {
332         for (ch = 0; ch < im->channels; ++ch) {
333           STORE8as16(im->idata, off, vals[i].channel[ch]);
334           ++off;
335         }
336       }
337     }
338     else {
339       for (i = 0; i < count; ++i) {
340         for (ch = 0; ch < im->channels; ++ch) {
341           if (im->ch_mask & (1 << ch))
342             STORE8as16(im->idata, off, vals[i].channel[ch]);
343           ++off;
344         }
345       }
346     }
347     return count;
348   }
349   else {
350     return 0;
351   }
352 }
353
354 static int i_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
355   int ch, count, i;
356   int off;
357   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
358     if (r > im->xsize)
359       r = im->xsize;
360     off = (l+y*im->xsize) * im->channels;
361     count = r - l;
362     for (i = 0; i < count; ++i) {
363       for (ch = 0; ch < im->channels; ++ch) {
364         vals[i].channel[ch] = Sample16ToF(GET16(im->idata, off));
365         ++off;
366       }
367     }
368     return count;
369   }
370   else {
371     return 0;
372   }
373 }
374
375 static int i_plinf_d16(i_img *im, int l, int r, int y, const i_fcolor *vals) {
376   int ch, count, i;
377   int off;
378   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
379     if (r > im->xsize)
380       r = im->xsize;
381     off = (l+y*im->xsize) * im->channels;
382     count = r - l;
383     if (I_ALL_CHANNELS_WRITABLE(im)) {
384       for (i = 0; i < count; ++i) {
385         for (ch = 0; ch < im->channels; ++ch) {
386           STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
387           ++off;
388         }
389       }
390     }
391     else {
392       for (i = 0; i < count; ++i) {
393         for (ch = 0; ch < im->channels; ++ch) {
394           if (im->ch_mask & (1 << ch))
395             STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
396           ++off;
397         }
398       }
399     }
400     return count;
401   }
402   else {
403     return 0;
404   }
405 }
406
407 static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps, 
408                        int const *chans, int chan_count) {
409   int ch, count, i, w;
410   int off;
411
412   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
413     if (r > im->xsize)
414       r = im->xsize;
415     off = (l+y*im->xsize) * im->channels;
416     w = r - l;
417     count = 0;
418
419     if (chans) {
420       /* make sure we have good channel numbers */
421       for (ch = 0; ch < chan_count; ++ch) {
422         if (chans[ch] < 0 || chans[ch] >= im->channels) {
423           i_push_errorf(0, "No channel %d in this image", chans[ch]);
424           return 0;
425         }
426       }
427       for (i = 0; i < w; ++i) {
428         for (ch = 0; ch < chan_count; ++ch) {
429           *samps++ = GET16as8(im->idata, off+chans[ch]);
430           ++count;
431         }
432         off += im->channels;
433       }
434     }
435     else {
436       if (chan_count <= 0 || chan_count > im->channels) {
437         i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
438                       chan_count);
439         return 0;
440       }
441       for (i = 0; i < w; ++i) {
442         for (ch = 0; ch < chan_count; ++ch) {
443           *samps++ = GET16as8(im->idata, off+ch);
444           ++count;
445         }
446         off += im->channels;
447       }
448     }
449
450     return count;
451   }
452   else {
453     return 0;
454   }
455 }
456
457 static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps, 
458                         int const *chans, int chan_count) {
459   int ch, count, i, w;
460   int off;
461
462   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
463     if (r > im->xsize)
464       r = im->xsize;
465     off = (l+y*im->xsize) * im->channels;
466     w = r - l;
467     count = 0;
468
469     if (chans) {
470       /* make sure we have good channel numbers */
471       for (ch = 0; ch < chan_count; ++ch) {
472         if (chans[ch] < 0 || chans[ch] >= im->channels) {
473           i_push_errorf(0, "No channel %d in this image", chans[ch]);
474           return 0;
475         }
476       }
477       for (i = 0; i < w; ++i) {
478         for (ch = 0; ch < chan_count; ++ch) {
479           *samps++ = Sample16ToF(GET16(im->idata, off+chans[ch]));
480           ++count;
481         }
482         off += im->channels;
483       }
484     }
485     else {
486       if (chan_count <= 0 || chan_count > im->channels) {
487         i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
488                       chan_count);
489         return 0;
490       }
491       for (i = 0; i < w; ++i) {
492         for (ch = 0; ch < chan_count; ++ch) {
493           *samps++ = Sample16ToF(GET16(im->idata, off+ch));
494           ++count;
495         }
496         off += im->channels;
497       }
498     }
499
500     return count;
501   }
502   else {
503     return 0;
504   }
505 }
506
507 static int 
508 i_gsamp_bits_d16(i_img *im, int l, int r, int y, unsigned *samps, 
509                             int const *chans, int chan_count, int bits) {
510   int ch, count, i, w;
511   int off;
512
513   if (bits != 16) {
514     return i_gsamp_bits_fb(im, l, r, y, samps, chans, chan_count, bits);
515   }
516
517   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
518     if (r > im->xsize)
519       r = im->xsize;
520     off = (l+y*im->xsize) * im->channels;
521     w = r - l;
522     count = 0;
523
524     if (chans) {
525       /* make sure we have good channel numbers */
526       for (ch = 0; ch < chan_count; ++ch) {
527         if (chans[ch] < 0 || chans[ch] >= im->channels) {
528           i_push_errorf(0, "No channel %d in this image", chans[ch]);
529           return -1;
530         }
531       }
532       for (i = 0; i < w; ++i) {
533         for (ch = 0; ch < chan_count; ++ch) {
534           *samps++ = GET16(im->idata, off+chans[ch]);
535           ++count;
536         }
537         off += im->channels;
538       }
539     }
540     else {
541       if (chan_count <= 0 || chan_count > im->channels) {
542         i_push_error(0, "Invalid channel count");
543         return -1;
544       }
545       for (i = 0; i < w; ++i) {
546         for (ch = 0; ch < chan_count; ++ch) {
547           *samps++ = GET16(im->idata, off+ch);
548           ++count;
549         }
550         off += im->channels;
551       }
552     }
553
554     return count;
555   }
556   else {
557     i_push_error(0, "Image position outside of image");
558     return -1;
559   }
560 }
561
562 static int 
563 i_psamp_bits_d16(i_img *im, int l, int r, int y, unsigned const *samps, 
564                             int const *chans, int chan_count, int bits) {
565   int ch, count, i, w;
566   int off;
567
568   if (bits != 16) {
569     i_push_error(0, "Invalid bits for 16-bit image");
570     return -1;
571   }
572
573   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
574     if (r > im->xsize)
575       r = im->xsize;
576     off = (l+y*im->xsize) * im->channels;
577     w = r - l;
578     count = 0;
579
580     if (chans) {
581       /* make sure we have good channel numbers */
582       for (ch = 0; ch < chan_count; ++ch) {
583         if (chans[ch] < 0 || chans[ch] >= im->channels) {
584           i_push_errorf(0, "No channel %d in this image", chans[ch]);
585           return -1;
586         }
587       }
588       for (i = 0; i < w; ++i) {
589         for (ch = 0; ch < chan_count; ++ch) {
590           if (im->ch_mask & (1 << ch))
591             STORE16(im->idata, off+chans[ch], *samps);
592           ++samps;
593           ++count;
594         }
595         off += im->channels;
596       }
597     }
598     else {
599       if (chan_count <= 0 || chan_count > im->channels) {
600         i_push_error(0, "Invalid channel count");
601         return -1;
602       }
603       for (i = 0; i < w; ++i) {
604         for (ch = 0; ch < chan_count; ++ch) {
605           if (im->ch_mask & (1 << ch)) 
606             STORE16(im->idata, off+ch, *samps);
607           ++samps;
608           ++count;
609         }
610         off += im->channels;
611       }
612     }
613
614     return count;
615   }
616   else {
617     i_push_error(0, "Image position outside of image");
618     return -1;
619   }
620 }
621
622 /*
623 =back
624
625 =head1 AUTHOR
626
627 Tony Cook <tony@develop-help.com>
628
629 =head1 SEE ALSO
630
631 Imager(3)
632
633 =cut
634 */