switch to using size_t and i_img_dim strictly
[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(i_img_dim x, i_img_dim 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, i_img_dim x, i_img_dim y, const i_color *val);
27 static int i_gpix_d16(i_img *im, i_img_dim x, i_img_dim y, i_color *val);
28 static i_img_dim i_glin_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals);
29 static i_img_dim i_plin_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals);
30 static int i_ppixf_d16(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val);
31 static int i_gpixf_d16(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val);
32 static i_img_dim i_glinf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals);
33 static i_img_dim i_plinf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals);
34 static i_img_dim i_gsamp_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, 
35                        int const *chans, int chan_count);
36 static i_img_dim i_gsampf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps, 
37                         int const *chans, int chan_count);
38 static i_img_dim i_gsamp_bits_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned *samps, 
39                             int const *chans, int chan_count, int bits);
40 static i_img_dim i_psamp_bits_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim 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(i_img_dim x, i_img_dim y, int ch) {
159   i_img *im;
160   size_t bytes, line_bytes;
161
162   mm_log((1,"i_img_16_new(x %" i_DF ", y %" i_DF ", ch %d)\n",
163           i_DFc(x), i_DFc(y), ch));
164
165   if (x < 1 || y < 1) {
166     i_push_error(0, "Image sizes must be positive");
167     return NULL;
168   }
169   if (ch < 1 || ch > MAXCHANNELS) {
170     i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
171     return NULL;
172   }
173   bytes =  x * y * ch * 2;
174   if (bytes / y / ch / 2 != x) {
175     i_push_errorf(0, "integer overflow calculating image allocation");
176     return NULL;
177   }
178   
179   /* basic assumption: we can always allocate a buffer representing a
180      line from the image, otherwise we're going to have trouble
181      working with the image */
182   line_bytes = sizeof(i_fcolor) * x;
183   if (line_bytes / x != sizeof(i_fcolor)) {
184     i_push_error(0, "integer overflow calculating scanline allocation");
185     return NULL;
186   }
187
188   im = i_img_alloc();
189   *im = IIM_base_16bit_direct;
190   i_tags_new(&im->tags);
191   im->xsize = x;
192   im->ysize = y;
193   im->channels = ch;
194   im->bytes = bytes;
195   im->ext_data = NULL;
196   im->idata = mymalloc(im->bytes);
197   memset(im->idata, 0, im->bytes);
198
199   i_img_init(im);
200
201   return im;
202 }
203
204 /*
205 =item i_img_to_rgb16(im)
206
207 =category Image creation
208
209 Returns a 16-bit/sample version of the supplied image.
210
211 Returns the image on success, or NULL on failure.
212
213 =cut
214 */
215
216 i_img *
217 i_img_to_rgb16(i_img *im) {
218   i_img *targ;
219   i_fcolor *line;
220   i_img_dim y;
221
222   targ = i_img_16_new(im->xsize, im->ysize, im->channels);
223   if (!targ)
224     return NULL;
225   line = mymalloc(sizeof(i_fcolor) * im->xsize);
226   for (y = 0; y < im->ysize; ++y) {
227     i_glinf(im, 0, im->xsize, y, line);
228     i_plinf(targ, 0, im->xsize, y, line);
229   }
230
231   myfree(line);
232
233   return targ;
234 }
235
236 static int i_ppix_d16(i_img *im, i_img_dim x, i_img_dim y, const i_color *val) {
237   i_img_dim off;
238   int ch;
239
240   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
241     return -1;
242
243   off = (x + y * im->xsize) * im->channels;
244   if (I_ALL_CHANNELS_WRITABLE(im)) {
245     for (ch = 0; ch < im->channels; ++ch)
246       STORE8as16(im->idata, off+ch, val->channel[ch]);
247   }
248   else {
249     for (ch = 0; ch < im->channels; ++ch)
250       if (im->ch_mask & (1 << ch))
251         STORE8as16(im->idata, off+ch, val->channel[ch]);
252   }
253
254   return 0;
255 }
256
257 static int i_gpix_d16(i_img *im, i_img_dim x, i_img_dim y, i_color *val) {
258   i_img_dim off;
259   int ch;
260
261   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
262     return -1;
263
264   off = (x + y * im->xsize) * im->channels;
265   for (ch = 0; ch < im->channels; ++ch)
266     val->channel[ch] = GET16as8(im->idata, off+ch);
267
268   return 0;
269 }
270
271 static int i_ppixf_d16(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val) {
272   i_img_dim off;
273   int ch;
274
275   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
276     return -1;
277
278   off = (x + y * im->xsize) * im->channels;
279   if (I_ALL_CHANNELS_WRITABLE(im)) {
280     for (ch = 0; ch < im->channels; ++ch)
281       STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
282   }
283   else {
284     for (ch = 0; ch < im->channels; ++ch)
285       if (im->ch_mask & (1 << ch))
286         STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
287   }
288
289   return 0;
290 }
291
292 static int i_gpixf_d16(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val) {
293   i_img_dim off;
294   int ch;
295
296   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
297     return -1;
298
299   off = (x + y * im->xsize) * im->channels;
300   for (ch = 0; ch < im->channels; ++ch)
301     val->channel[ch] = Sample16ToF(GET16(im->idata, off+ch));
302
303   return 0;
304 }
305
306 static i_img_dim i_glin_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals) {
307   int ch;
308   i_img_dim count, i;
309   i_img_dim off;
310   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
311     if (r > im->xsize)
312       r = im->xsize;
313     off = (l+y*im->xsize) * im->channels;
314     count = r - l;
315     for (i = 0; i < count; ++i) {
316       for (ch = 0; ch < im->channels; ++ch) {
317         vals[i].channel[ch] = GET16as8(im->idata, off);
318         ++off;
319       }
320     }
321     return count;
322   }
323   else {
324     return 0;
325   }
326 }
327
328 static i_img_dim i_plin_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals) {
329   int ch;
330   i_img_dim count, i;
331   i_img_dim off;
332   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
333     if (r > im->xsize)
334       r = im->xsize;
335     off = (l+y*im->xsize) * im->channels;
336     count = r - l;
337     if (I_ALL_CHANNELS_WRITABLE(im)) {
338       for (i = 0; i < count; ++i) {
339         for (ch = 0; ch < im->channels; ++ch) {
340           STORE8as16(im->idata, off, vals[i].channel[ch]);
341           ++off;
342         }
343       }
344     }
345     else {
346       for (i = 0; i < count; ++i) {
347         for (ch = 0; ch < im->channels; ++ch) {
348           if (im->ch_mask & (1 << ch))
349             STORE8as16(im->idata, off, vals[i].channel[ch]);
350           ++off;
351         }
352       }
353     }
354     return count;
355   }
356   else {
357     return 0;
358   }
359 }
360
361 static i_img_dim i_glinf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals) {
362   int ch;
363   i_img_dim count, i;
364   i_img_dim off;
365   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
366     if (r > im->xsize)
367       r = im->xsize;
368     off = (l+y*im->xsize) * im->channels;
369     count = r - l;
370     for (i = 0; i < count; ++i) {
371       for (ch = 0; ch < im->channels; ++ch) {
372         vals[i].channel[ch] = Sample16ToF(GET16(im->idata, off));
373         ++off;
374       }
375     }
376     return count;
377   }
378   else {
379     return 0;
380   }
381 }
382
383 static i_img_dim i_plinf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals) {
384   int ch;
385   i_img_dim count, i;
386   i_img_dim off;
387   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
388     if (r > im->xsize)
389       r = im->xsize;
390     off = (l+y*im->xsize) * im->channels;
391     count = r - l;
392     if (I_ALL_CHANNELS_WRITABLE(im)) {
393       for (i = 0; i < count; ++i) {
394         for (ch = 0; ch < im->channels; ++ch) {
395           STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
396           ++off;
397         }
398       }
399     }
400     else {
401       for (i = 0; i < count; ++i) {
402         for (ch = 0; ch < im->channels; ++ch) {
403           if (im->ch_mask & (1 << ch))
404             STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
405           ++off;
406         }
407       }
408     }
409     return count;
410   }
411   else {
412     return 0;
413   }
414 }
415
416 static i_img_dim i_gsamp_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, 
417                        int const *chans, int chan_count) {
418   int ch;
419   i_img_dim count, i, w;
420   i_img_dim off;
421
422   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
423     if (r > im->xsize)
424       r = im->xsize;
425     off = (l+y*im->xsize) * im->channels;
426     w = r - l;
427     count = 0;
428
429     if (chans) {
430       /* make sure we have good channel numbers */
431       for (ch = 0; ch < chan_count; ++ch) {
432         if (chans[ch] < 0 || chans[ch] >= im->channels) {
433           i_push_errorf(0, "No channel %d in this image", chans[ch]);
434           return 0;
435         }
436       }
437       for (i = 0; i < w; ++i) {
438         for (ch = 0; ch < chan_count; ++ch) {
439           *samps++ = GET16as8(im->idata, off+chans[ch]);
440           ++count;
441         }
442         off += im->channels;
443       }
444     }
445     else {
446       if (chan_count <= 0 || chan_count > im->channels) {
447         i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
448                       chan_count);
449         return 0;
450       }
451       for (i = 0; i < w; ++i) {
452         for (ch = 0; ch < chan_count; ++ch) {
453           *samps++ = GET16as8(im->idata, off+ch);
454           ++count;
455         }
456         off += im->channels;
457       }
458     }
459
460     return count;
461   }
462   else {
463     return 0;
464   }
465 }
466
467 static i_img_dim i_gsampf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps, 
468                         int const *chans, int chan_count) {
469   int ch;
470   i_img_dim count, i, w;
471   i_img_dim off;
472
473   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
474     if (r > im->xsize)
475       r = im->xsize;
476     off = (l+y*im->xsize) * im->channels;
477     w = r - l;
478     count = 0;
479
480     if (chans) {
481       /* make sure we have good channel numbers */
482       for (ch = 0; ch < chan_count; ++ch) {
483         if (chans[ch] < 0 || chans[ch] >= im->channels) {
484           i_push_errorf(0, "No channel %d in this image", chans[ch]);
485           return 0;
486         }
487       }
488       for (i = 0; i < w; ++i) {
489         for (ch = 0; ch < chan_count; ++ch) {
490           *samps++ = Sample16ToF(GET16(im->idata, off+chans[ch]));
491           ++count;
492         }
493         off += im->channels;
494       }
495     }
496     else {
497       if (chan_count <= 0 || chan_count > im->channels) {
498         i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
499                       chan_count);
500         return 0;
501       }
502       for (i = 0; i < w; ++i) {
503         for (ch = 0; ch < chan_count; ++ch) {
504           *samps++ = Sample16ToF(GET16(im->idata, off+ch));
505           ++count;
506         }
507         off += im->channels;
508       }
509     }
510
511     return count;
512   }
513   else {
514     return 0;
515   }
516 }
517
518 static i_img_dim 
519 i_gsamp_bits_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned *samps, 
520                             int const *chans, int chan_count, int bits) {
521   int ch;
522   i_img_dim count, i, w;
523   i_img_dim off;
524
525   if (bits != 16) {
526     return i_gsamp_bits_fb(im, l, r, y, samps, chans, chan_count, bits);
527   }
528
529   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
530     if (r > im->xsize)
531       r = im->xsize;
532     off = (l+y*im->xsize) * im->channels;
533     w = r - l;
534     count = 0;
535
536     if (chans) {
537       /* make sure we have good channel numbers */
538       for (ch = 0; ch < chan_count; ++ch) {
539         if (chans[ch] < 0 || chans[ch] >= im->channels) {
540           i_push_errorf(0, "No channel %d in this image", chans[ch]);
541           return -1;
542         }
543       }
544       for (i = 0; i < w; ++i) {
545         for (ch = 0; ch < chan_count; ++ch) {
546           *samps++ = GET16(im->idata, off+chans[ch]);
547           ++count;
548         }
549         off += im->channels;
550       }
551     }
552     else {
553       if (chan_count <= 0 || chan_count > im->channels) {
554         i_push_error(0, "Invalid channel count");
555         return -1;
556       }
557       for (i = 0; i < w; ++i) {
558         for (ch = 0; ch < chan_count; ++ch) {
559           *samps++ = GET16(im->idata, off+ch);
560           ++count;
561         }
562         off += im->channels;
563       }
564     }
565
566     return count;
567   }
568   else {
569     i_push_error(0, "Image position outside of image");
570     return -1;
571   }
572 }
573
574 static i_img_dim 
575 i_psamp_bits_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned const *samps, 
576                             int const *chans, int chan_count, int bits) {
577   int ch;
578   i_img_dim count, i, w;
579   i_img_dim off;
580
581   if (bits != 16) {
582     i_push_error(0, "Invalid bits for 16-bit image");
583     return -1;
584   }
585
586   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
587     if (r > im->xsize)
588       r = im->xsize;
589     off = (l+y*im->xsize) * im->channels;
590     w = r - l;
591     count = 0;
592
593     if (chans) {
594       /* make sure we have good channel numbers */
595       for (ch = 0; ch < chan_count; ++ch) {
596         if (chans[ch] < 0 || chans[ch] >= im->channels) {
597           i_push_errorf(0, "No channel %d in this image", chans[ch]);
598           return -1;
599         }
600       }
601       for (i = 0; i < w; ++i) {
602         for (ch = 0; ch < chan_count; ++ch) {
603           if (im->ch_mask & (1 << ch))
604             STORE16(im->idata, off+chans[ch], *samps);
605           ++samps;
606           ++count;
607         }
608         off += im->channels;
609       }
610     }
611     else {
612       if (chan_count <= 0 || chan_count > im->channels) {
613         i_push_error(0, "Invalid channel count");
614         return -1;
615       }
616       for (i = 0; i < w; ++i) {
617         for (ch = 0; ch < chan_count; ++ch) {
618           if (im->ch_mask & (1 << ch)) 
619             STORE16(im->idata, off+ch, *samps);
620           ++samps;
621           ++count;
622         }
623         off += im->channels;
624       }
625     }
626
627     return count;
628   }
629   else {
630     i_push_error(0, "Image position outside of image");
631     return -1;
632   }
633 }
634
635 /*
636 =back
637
638 =head1 AUTHOR
639
640 Tony Cook <tony@develop-help.com>
641
642 =head1 SEE ALSO
643
644 Imager(3)
645
646 =cut
647 */