4 img16.c - implements 16-bit images
8 i_img *im = i_img_16_new(i_img_dim x, i_img_dim y, int channels);
9 # use like a normal image
13 Implements 16-bit/sample images.
15 This basic implementation is required so that we have some larger
16 sample image type to work with.
23 #define IMAGER_NO_CONTEXT
28 static int i_ppix_d16(i_img *im, i_img_dim x, i_img_dim y, const i_color *val);
29 static int i_gpix_d16(i_img *im, i_img_dim x, i_img_dim y, i_color *val);
30 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);
31 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);
32 static int i_ppixf_d16(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val);
33 static int i_gpixf_d16(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val);
34 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);
35 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);
36 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,
37 int const *chans, int chan_count);
38 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,
39 int const *chans, int chan_count);
40 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,
41 int const *chans, int chan_count, int bits);
42 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,
43 int const *chans, int chan_count, int bits);
44 static i_img_dim i_psamp_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *samps, const int *chans, int chan_count);
45 static i_img_dim i_psampf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fsample_t *samps, const int *chans, int chan_count);
48 =item IIM_base_16bit_direct
50 Base structure used to initialize a 16-bit/sample image.
56 static i_img IIM_base_16bit_direct =
59 0, 0, 0, /* xsize, ysize, bytes */
62 i_direct_type, /* type */
65 { 0, 0, NULL }, /* tags */
68 i_ppix_d16, /* i_f_ppix */
69 i_ppixf_d16, /* i_f_ppixf */
70 i_plin_d16, /* i_f_plin */
71 i_plinf_d16, /* i_f_plinf */
72 i_gpix_d16, /* i_f_gpix */
73 i_gpixf_d16, /* i_f_gpixf */
74 i_glin_d16, /* i_f_glin */
75 i_glinf_d16, /* i_f_glinf */
76 i_gsamp_d16, /* i_f_gsamp */
77 i_gsampf_d16, /* i_f_gsampf */
81 NULL, /* i_f_addcolors */
82 NULL, /* i_f_getcolors */
83 NULL, /* i_f_colorcount */
84 NULL, /* i_f_maxcolors */
85 NULL, /* i_f_findcolor */
86 NULL, /* i_f_setcolors */
88 NULL, /* i_f_destroy */
97 /* it's possible some platforms won't have a 16-bit integer type,
98 so we check for one otherwise we work by bytes directly
100 We do assume 8-bit char
102 "Compaq C V6.4-009 on Compaq Tru64 UNIX V5.1A (Rev. 1885)" says it
103 supports C99, but doesn't supply stdint.h, which is required for
104 both hosted and freestanding implementations. So guard against it.
106 #if __STDC_VERSION__ >= 199901L && !defined(OS_dec_osf)
107 /* C99 should define something useful */
110 typedef uint16_t i_sample16_t;
115 /* check out unsigned short */
118 #if USHRT_MAX == 65535
119 typedef unsigned short i_sample16_t;
126 /* we have a real 16-bit unsigned integer */
127 #define STORE16(bytes, offset, word) \
128 (((i_sample16_t *)(bytes))[offset] = (word))
129 #define STORE8as16(bytes, offset, byte) \
130 (((i_sample16_t *)(bytes))[offset] = (byte) * 256 + (byte))
131 #define GET16(bytes, offset) \
132 (((i_sample16_t *)(bytes))[offset])
135 /* we have to do this the hard way */
136 #define STORE16(bytes, offset, word) \
137 ((((unsigned char *)(bytes))[(offset)*2] = (word) >> 8), \
138 (((unsigned char *)(bytes))[(offset)*2+1] = (word) & 0xFF))
139 #define STORE8as16(bytes, offset, byte) \
140 ((((unsigned char *)(bytes))[(offset)*2] = (byte)), \
141 (((unsigned char *)(bytes))[(offset)*2+1] = (byte)))
143 #define GET16(bytes, offset) \
144 (((unsigned char *)(bytes))[(offset)*2] * 256 \
145 + ((unsigned char *)(bytes))[(offset)*2+1])
149 #define GET16as8(bytes, offset) \
150 ((((i_sample16_t *)(bytes))[offset]+127) / 257)
153 =item i_img_16_new(x, y, ch)
155 =category Image creation/destruction
156 =synopsis i_img *img = i_img_16_new(width, height, channels);
158 Create a new 16-bit/sample image.
160 Returns the image on success, or NULL on failure.
166 im_img_16_new(pIMCTX, i_img_dim x, i_img_dim y, int ch) {
168 size_t bytes, line_bytes;
170 im_log((aIMCTX, 1,"i_img_16_new(x %" i_DF ", y %" i_DF ", ch %d)\n",
171 i_DFc(x), i_DFc(y), ch));
173 if (x < 1 || y < 1) {
174 im_push_error(aIMCTX, 0, "Image sizes must be positive");
177 if (ch < 1 || ch > MAXCHANNELS) {
178 im_push_errorf(aIMCTX, 0, "channels must be between 1 and %d", MAXCHANNELS);
181 bytes = x * y * ch * 2;
182 if (bytes / y / ch / 2 != x) {
183 im_push_errorf(aIMCTX, 0, "integer overflow calculating image allocation");
187 /* basic assumption: we can always allocate a buffer representing a
188 line from the image, otherwise we're going to have trouble
189 working with the image */
190 line_bytes = sizeof(i_fcolor) * x;
191 if (line_bytes / x != sizeof(i_fcolor)) {
192 im_push_error(aIMCTX, 0, "integer overflow calculating scanline allocation");
196 im = im_img_alloc(aIMCTX);
197 *im = IIM_base_16bit_direct;
198 i_tags_new(&im->tags);
204 im->idata = mymalloc(im->bytes);
205 memset(im->idata, 0, im->bytes);
207 im_img_init(aIMCTX, im);
213 =item i_img_to_rgb16(im)
215 =category Image creation
217 Returns a 16-bit/sample version of the supplied image.
219 Returns the image on success, or NULL on failure.
225 i_img_to_rgb16(i_img *im) {
231 targ = im_img_16_new(aIMCTX, im->xsize, im->ysize, im->channels);
234 line = mymalloc(sizeof(i_fcolor) * im->xsize);
235 for (y = 0; y < im->ysize; ++y) {
236 i_glinf(im, 0, im->xsize, y, line);
237 i_plinf(targ, 0, im->xsize, y, line);
245 static int i_ppix_d16(i_img *im, i_img_dim x, i_img_dim y, const i_color *val) {
249 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
252 off = (x + y * im->xsize) * im->channels;
253 if (I_ALL_CHANNELS_WRITABLE(im)) {
254 for (ch = 0; ch < im->channels; ++ch)
255 STORE8as16(im->idata, off+ch, val->channel[ch]);
258 for (ch = 0; ch < im->channels; ++ch)
259 if (im->ch_mask & (1 << ch))
260 STORE8as16(im->idata, off+ch, val->channel[ch]);
266 static int i_gpix_d16(i_img *im, i_img_dim x, i_img_dim y, i_color *val) {
270 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
273 off = (x + y * im->xsize) * im->channels;
274 for (ch = 0; ch < im->channels; ++ch)
275 val->channel[ch] = GET16as8(im->idata, off+ch);
280 static int i_ppixf_d16(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val) {
284 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
287 off = (x + y * im->xsize) * im->channels;
288 if (I_ALL_CHANNELS_WRITABLE(im)) {
289 for (ch = 0; ch < im->channels; ++ch)
290 STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
293 for (ch = 0; ch < im->channels; ++ch)
294 if (im->ch_mask & (1 << ch))
295 STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
301 static int i_gpixf_d16(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val) {
305 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
308 off = (x + y * im->xsize) * im->channels;
309 for (ch = 0; ch < im->channels; ++ch)
310 val->channel[ch] = Sample16ToF(GET16(im->idata, off+ch));
315 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) {
319 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
322 off = (l+y*im->xsize) * im->channels;
324 for (i = 0; i < count; ++i) {
325 for (ch = 0; ch < im->channels; ++ch) {
326 vals[i].channel[ch] = GET16as8(im->idata, off);
337 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) {
341 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
344 off = (l+y*im->xsize) * im->channels;
346 if (I_ALL_CHANNELS_WRITABLE(im)) {
347 for (i = 0; i < count; ++i) {
348 for (ch = 0; ch < im->channels; ++ch) {
349 STORE8as16(im->idata, off, vals[i].channel[ch]);
355 for (i = 0; i < count; ++i) {
356 for (ch = 0; ch < im->channels; ++ch) {
357 if (im->ch_mask & (1 << ch))
358 STORE8as16(im->idata, off, vals[i].channel[ch]);
370 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) {
374 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
377 off = (l+y*im->xsize) * im->channels;
379 for (i = 0; i < count; ++i) {
380 for (ch = 0; ch < im->channels; ++ch) {
381 vals[i].channel[ch] = Sample16ToF(GET16(im->idata, off));
392 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) {
396 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
399 off = (l+y*im->xsize) * im->channels;
401 if (I_ALL_CHANNELS_WRITABLE(im)) {
402 for (i = 0; i < count; ++i) {
403 for (ch = 0; ch < im->channels; ++ch) {
404 STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
410 for (i = 0; i < count; ++i) {
411 for (ch = 0; ch < im->channels; ++ch) {
412 if (im->ch_mask & (1 << ch))
413 STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
425 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,
426 int const *chans, int chan_count) {
428 i_img_dim count, i, w;
431 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
434 off = (l+y*im->xsize) * im->channels;
439 /* make sure we have good channel numbers */
440 for (ch = 0; ch < chan_count; ++ch) {
441 if (chans[ch] < 0 || chans[ch] >= im->channels) {
443 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
447 for (i = 0; i < w; ++i) {
448 for (ch = 0; ch < chan_count; ++ch) {
449 *samps++ = GET16as8(im->idata, off+chans[ch]);
456 if (chan_count <= 0 || chan_count > im->channels) {
458 im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
462 for (i = 0; i < w; ++i) {
463 for (ch = 0; ch < chan_count; ++ch) {
464 *samps++ = GET16as8(im->idata, off+ch);
478 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,
479 int const *chans, int chan_count) {
481 i_img_dim count, i, w;
484 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
487 off = (l+y*im->xsize) * im->channels;
492 /* make sure we have good channel numbers */
493 for (ch = 0; ch < chan_count; ++ch) {
494 if (chans[ch] < 0 || chans[ch] >= im->channels) {
496 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
500 for (i = 0; i < w; ++i) {
501 for (ch = 0; ch < chan_count; ++ch) {
502 *samps++ = Sample16ToF(GET16(im->idata, off+chans[ch]));
509 if (chan_count <= 0 || chan_count > im->channels) {
511 im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
515 for (i = 0; i < w; ++i) {
516 for (ch = 0; ch < chan_count; ++ch) {
517 *samps++ = Sample16ToF(GET16(im->idata, off+ch));
532 i_gsamp_bits_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned *samps,
533 int const *chans, int chan_count, int bits) {
535 i_img_dim count, i, w;
539 return i_gsamp_bits_fb(im, l, r, y, samps, chans, chan_count, bits);
542 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
545 off = (l+y*im->xsize) * im->channels;
550 /* make sure we have good channel numbers */
551 for (ch = 0; ch < chan_count; ++ch) {
552 if (chans[ch] < 0 || chans[ch] >= im->channels) {
554 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
558 for (i = 0; i < w; ++i) {
559 for (ch = 0; ch < chan_count; ++ch) {
560 *samps++ = GET16(im->idata, off+chans[ch]);
567 if (chan_count <= 0 || chan_count > im->channels) {
569 i_push_error(0, "Invalid channel count");
572 for (i = 0; i < w; ++i) {
573 for (ch = 0; ch < chan_count; ++ch) {
574 *samps++ = GET16(im->idata, off+ch);
585 i_push_error(0, "Image position outside of image");
591 i_psamp_bits_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned const *samps,
592 int const *chans, int chan_count, int bits) {
594 i_img_dim count, i, w;
599 i_push_error(0, "Invalid bits for 16-bit image");
603 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
606 off = (l+y*im->xsize) * im->channels;
611 /* make sure we have good channel numbers */
612 for (ch = 0; ch < chan_count; ++ch) {
613 if (chans[ch] < 0 || chans[ch] >= im->channels) {
615 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
619 for (i = 0; i < w; ++i) {
620 for (ch = 0; ch < chan_count; ++ch) {
621 if (im->ch_mask & (1 << ch))
622 STORE16(im->idata, off+chans[ch], *samps);
630 if (chan_count <= 0 || chan_count > im->channels) {
632 i_push_error(0, "Invalid channel count");
635 for (i = 0; i < w; ++i) {
636 for (ch = 0; ch < chan_count; ++ch) {
637 if (im->ch_mask & (1 << ch))
638 STORE16(im->idata, off+ch, *samps);
650 i_push_error(0, "Image position outside of image");
656 =item i_psamp_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *samps, int *chans, int chan_count)
658 Writes sample values to im for the horizontal line (l, y) to (r-1,y)
659 for the channels specified by chans, an array of int with chan_count
662 Returns the number of samples written (which should be (r-l) *
670 i_psamp_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
671 const i_sample_t *samps, const int *chans, int chan_count) {
673 i_img_dim count, i, w;
675 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
679 offset = (l+y*im->xsize) * im->channels;
684 /* make sure we have good channel numbers */
685 /* and test if all channels specified are in the mask */
687 for (ch = 0; ch < chan_count; ++ch) {
688 if (chans[ch] < 0 || chans[ch] >= im->channels) {
690 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
693 if (!((1 << chans[ch]) & im->ch_mask))
697 for (i = 0; i < w; ++i) {
698 for (ch = 0; ch < chan_count; ++ch) {
699 STORE8as16(im->idata, offset + chans[ch], *samps);
703 offset += im->channels;
707 for (i = 0; i < w; ++i) {
708 for (ch = 0; ch < chan_count; ++ch) {
709 if (im->ch_mask & (1 << (chans[ch])))
710 STORE8as16(im->idata, offset + chans[ch], *samps);
714 offset += im->channels;
719 if (chan_count <= 0 || chan_count > im->channels) {
721 im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
725 for (i = 0; i < w; ++i) {
727 for (ch = 0; ch < chan_count; ++ch) {
728 if (im->ch_mask & mask)
729 STORE8as16(im->idata, offset + ch, *samps);
734 offset += im->channels;
742 i_push_error(0, "Image position outside of image");
748 =item i_psampf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fsample_t *samps, int *chans, int chan_count)
750 Writes sample values to im for the horizontal line (l, y) to (r-1,y)
751 for the channels specified by chans, an array of int with chan_count
754 Returns the number of samples written (which should be (r-l) *
762 i_psampf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
763 const i_fsample_t *samps, const int *chans, int chan_count) {
765 i_img_dim count, i, w;
767 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
771 offset = (l+y*im->xsize) * im->channels;
776 /* make sure we have good channel numbers */
777 /* and test if all channels specified are in the mask */
779 for (ch = 0; ch < chan_count; ++ch) {
780 if (chans[ch] < 0 || chans[ch] >= im->channels) {
782 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
785 if (!((1 << chans[ch]) & im->ch_mask))
789 for (i = 0; i < w; ++i) {
790 for (ch = 0; ch < chan_count; ++ch) {
791 unsigned samp16 = SampleFTo16(*samps);
792 STORE16(im->idata, offset + chans[ch], samp16);
796 offset += im->channels;
800 for (i = 0; i < w; ++i) {
801 for (ch = 0; ch < chan_count; ++ch) {
802 if (im->ch_mask & (1 << (chans[ch]))) {
803 unsigned samp16 = SampleFTo16(*samps);
804 STORE16(im->idata, offset + chans[ch], samp16);
809 offset += im->channels;
814 if (chan_count <= 0 || chan_count > im->channels) {
816 im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
820 for (i = 0; i < w; ++i) {
822 for (ch = 0; ch < chan_count; ++ch) {
823 if (im->ch_mask & mask) {
824 unsigned samp16 = SampleFTo16(*samps);
825 STORE16(im->idata, offset + ch, samp16);
831 offset += im->channels;
839 i_push_error(0, "Image position outside of image");
849 Tony Cook <tony@develop-help.com>