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 im_img_16_new(ctx, x, y, ch)
154 X<im_img_16_new API>X<i_img_16_new API>
155 =category Image creation/destruction
156 =synopsis i_img *img = im_img_16_new(aIMCTX, width, height, channels);
157 =synopsis i_img *img = i_img_16_new(width, height, channels);
159 Create a new 16-bit/sample image.
161 Returns the image on success, or NULL on failure.
163 Also callable as C<i_img_16_new(x, y, ch)>
169 im_img_16_new(pIMCTX, i_img_dim x, i_img_dim y, int ch) {
171 size_t bytes, line_bytes;
173 im_log((aIMCTX, 1,"i_img_16_new(x %" i_DF ", y %" i_DF ", ch %d)\n",
174 i_DFc(x), i_DFc(y), ch));
176 if (x < 1 || y < 1) {
177 im_push_error(aIMCTX, 0, "Image sizes must be positive");
180 if (ch < 1 || ch > MAXCHANNELS) {
181 im_push_errorf(aIMCTX, 0, "channels must be between 1 and %d", MAXCHANNELS);
184 bytes = x * y * ch * 2;
185 if (bytes / y / ch / 2 != x) {
186 im_push_errorf(aIMCTX, 0, "integer overflow calculating image allocation");
190 /* basic assumption: we can always allocate a buffer representing a
191 line from the image, otherwise we're going to have trouble
192 working with the image */
193 line_bytes = sizeof(i_fcolor) * x;
194 if (line_bytes / x != sizeof(i_fcolor)) {
195 im_push_error(aIMCTX, 0, "integer overflow calculating scanline allocation");
199 im = im_img_alloc(aIMCTX);
200 *im = IIM_base_16bit_direct;
201 i_tags_new(&im->tags);
207 im->idata = mymalloc(im->bytes);
208 memset(im->idata, 0, im->bytes);
210 im_img_init(aIMCTX, im);
216 =item i_img_to_rgb16(im)
218 =category Image creation
220 Returns a 16-bit/sample version of the supplied image.
222 Returns the image on success, or NULL on failure.
228 i_img_to_rgb16(i_img *im) {
234 targ = im_img_16_new(aIMCTX, im->xsize, im->ysize, im->channels);
237 line = mymalloc(sizeof(i_fcolor) * im->xsize);
238 for (y = 0; y < im->ysize; ++y) {
239 i_glinf(im, 0, im->xsize, y, line);
240 i_plinf(targ, 0, im->xsize, y, line);
248 static int i_ppix_d16(i_img *im, i_img_dim x, i_img_dim y, const i_color *val) {
252 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
255 off = (x + y * im->xsize) * im->channels;
256 if (I_ALL_CHANNELS_WRITABLE(im)) {
257 for (ch = 0; ch < im->channels; ++ch)
258 STORE8as16(im->idata, off+ch, val->channel[ch]);
261 for (ch = 0; ch < im->channels; ++ch)
262 if (im->ch_mask & (1 << ch))
263 STORE8as16(im->idata, off+ch, val->channel[ch]);
269 static int i_gpix_d16(i_img *im, i_img_dim x, i_img_dim y, i_color *val) {
273 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
276 off = (x + y * im->xsize) * im->channels;
277 for (ch = 0; ch < im->channels; ++ch)
278 val->channel[ch] = GET16as8(im->idata, off+ch);
283 static int i_ppixf_d16(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val) {
287 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
290 off = (x + y * im->xsize) * im->channels;
291 if (I_ALL_CHANNELS_WRITABLE(im)) {
292 for (ch = 0; ch < im->channels; ++ch)
293 STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
296 for (ch = 0; ch < im->channels; ++ch)
297 if (im->ch_mask & (1 << ch))
298 STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
304 static int i_gpixf_d16(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val) {
308 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
311 off = (x + y * im->xsize) * im->channels;
312 for (ch = 0; ch < im->channels; ++ch)
313 val->channel[ch] = Sample16ToF(GET16(im->idata, off+ch));
318 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) {
322 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
325 off = (l+y*im->xsize) * im->channels;
327 for (i = 0; i < count; ++i) {
328 for (ch = 0; ch < im->channels; ++ch) {
329 vals[i].channel[ch] = GET16as8(im->idata, off);
340 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) {
344 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
347 off = (l+y*im->xsize) * im->channels;
349 if (I_ALL_CHANNELS_WRITABLE(im)) {
350 for (i = 0; i < count; ++i) {
351 for (ch = 0; ch < im->channels; ++ch) {
352 STORE8as16(im->idata, off, vals[i].channel[ch]);
358 for (i = 0; i < count; ++i) {
359 for (ch = 0; ch < im->channels; ++ch) {
360 if (im->ch_mask & (1 << ch))
361 STORE8as16(im->idata, off, vals[i].channel[ch]);
373 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) {
377 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
380 off = (l+y*im->xsize) * im->channels;
382 for (i = 0; i < count; ++i) {
383 for (ch = 0; ch < im->channels; ++ch) {
384 vals[i].channel[ch] = Sample16ToF(GET16(im->idata, off));
395 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) {
399 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
402 off = (l+y*im->xsize) * im->channels;
404 if (I_ALL_CHANNELS_WRITABLE(im)) {
405 for (i = 0; i < count; ++i) {
406 for (ch = 0; ch < im->channels; ++ch) {
407 STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
413 for (i = 0; i < count; ++i) {
414 for (ch = 0; ch < im->channels; ++ch) {
415 if (im->ch_mask & (1 << ch))
416 STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
428 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,
429 int const *chans, int chan_count) {
431 i_img_dim count, i, w;
434 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
437 off = (l+y*im->xsize) * im->channels;
442 /* make sure we have good channel numbers */
443 for (ch = 0; ch < chan_count; ++ch) {
444 if (chans[ch] < 0 || chans[ch] >= im->channels) {
446 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
450 for (i = 0; i < w; ++i) {
451 for (ch = 0; ch < chan_count; ++ch) {
452 *samps++ = GET16as8(im->idata, off+chans[ch]);
459 if (chan_count <= 0 || chan_count > im->channels) {
461 im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
465 for (i = 0; i < w; ++i) {
466 for (ch = 0; ch < chan_count; ++ch) {
467 *samps++ = GET16as8(im->idata, off+ch);
481 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,
482 int const *chans, int chan_count) {
484 i_img_dim count, i, w;
487 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
490 off = (l+y*im->xsize) * im->channels;
495 /* make sure we have good channel numbers */
496 for (ch = 0; ch < chan_count; ++ch) {
497 if (chans[ch] < 0 || chans[ch] >= im->channels) {
499 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
503 for (i = 0; i < w; ++i) {
504 for (ch = 0; ch < chan_count; ++ch) {
505 *samps++ = Sample16ToF(GET16(im->idata, off+chans[ch]));
512 if (chan_count <= 0 || chan_count > im->channels) {
514 im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
518 for (i = 0; i < w; ++i) {
519 for (ch = 0; ch < chan_count; ++ch) {
520 *samps++ = Sample16ToF(GET16(im->idata, off+ch));
535 i_gsamp_bits_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned *samps,
536 int const *chans, int chan_count, int bits) {
538 i_img_dim count, i, w;
542 return i_gsamp_bits_fb(im, l, r, y, samps, chans, chan_count, bits);
545 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
548 off = (l+y*im->xsize) * im->channels;
553 /* make sure we have good channel numbers */
554 for (ch = 0; ch < chan_count; ++ch) {
555 if (chans[ch] < 0 || chans[ch] >= im->channels) {
557 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
561 for (i = 0; i < w; ++i) {
562 for (ch = 0; ch < chan_count; ++ch) {
563 *samps++ = GET16(im->idata, off+chans[ch]);
570 if (chan_count <= 0 || chan_count > im->channels) {
572 i_push_error(0, "Invalid channel count");
575 for (i = 0; i < w; ++i) {
576 for (ch = 0; ch < chan_count; ++ch) {
577 *samps++ = GET16(im->idata, off+ch);
588 i_push_error(0, "Image position outside of image");
594 i_psamp_bits_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned const *samps,
595 int const *chans, int chan_count, int bits) {
597 i_img_dim count, i, w;
602 i_push_error(0, "Invalid bits for 16-bit image");
606 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
609 off = (l+y*im->xsize) * im->channels;
614 /* make sure we have good channel numbers */
615 for (ch = 0; ch < chan_count; ++ch) {
616 if (chans[ch] < 0 || chans[ch] >= im->channels) {
618 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
622 for (i = 0; i < w; ++i) {
623 for (ch = 0; ch < chan_count; ++ch) {
624 if (im->ch_mask & (1 << ch))
625 STORE16(im->idata, off+chans[ch], *samps);
633 if (chan_count <= 0 || chan_count > im->channels) {
635 i_push_error(0, "Invalid channel count");
638 for (i = 0; i < w; ++i) {
639 for (ch = 0; ch < chan_count; ++ch) {
640 if (im->ch_mask & (1 << ch))
641 STORE16(im->idata, off+ch, *samps);
653 i_push_error(0, "Image position outside of image");
659 =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)
661 Writes sample values to im for the horizontal line (l, y) to (r-1,y)
662 for the channels specified by chans, an array of int with chan_count
665 Returns the number of samples written (which should be (r-l) *
673 i_psamp_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
674 const i_sample_t *samps, const int *chans, int chan_count) {
676 i_img_dim count, i, w;
678 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
682 offset = (l+y*im->xsize) * im->channels;
687 /* make sure we have good channel numbers */
688 /* and test if all channels specified are in the mask */
690 for (ch = 0; ch < chan_count; ++ch) {
691 if (chans[ch] < 0 || chans[ch] >= im->channels) {
693 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
696 if (!((1 << chans[ch]) & im->ch_mask))
700 for (i = 0; i < w; ++i) {
701 for (ch = 0; ch < chan_count; ++ch) {
702 STORE8as16(im->idata, offset + chans[ch], *samps);
706 offset += im->channels;
710 for (i = 0; i < w; ++i) {
711 for (ch = 0; ch < chan_count; ++ch) {
712 if (im->ch_mask & (1 << (chans[ch])))
713 STORE8as16(im->idata, offset + chans[ch], *samps);
717 offset += im->channels;
722 if (chan_count <= 0 || chan_count > im->channels) {
724 im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
728 for (i = 0; i < w; ++i) {
730 for (ch = 0; ch < chan_count; ++ch) {
731 if (im->ch_mask & mask)
732 STORE8as16(im->idata, offset + ch, *samps);
737 offset += im->channels;
745 i_push_error(0, "Image position outside of image");
751 =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)
753 Writes sample values to im for the horizontal line (l, y) to (r-1,y)
754 for the channels specified by chans, an array of int with chan_count
757 Returns the number of samples written (which should be (r-l) *
765 i_psampf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
766 const i_fsample_t *samps, const int *chans, int chan_count) {
768 i_img_dim count, i, w;
770 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
774 offset = (l+y*im->xsize) * im->channels;
779 /* make sure we have good channel numbers */
780 /* and test if all channels specified are in the mask */
782 for (ch = 0; ch < chan_count; ++ch) {
783 if (chans[ch] < 0 || chans[ch] >= im->channels) {
785 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
788 if (!((1 << chans[ch]) & im->ch_mask))
792 for (i = 0; i < w; ++i) {
793 for (ch = 0; ch < chan_count; ++ch) {
794 unsigned samp16 = SampleFTo16(*samps);
795 STORE16(im->idata, offset + chans[ch], samp16);
799 offset += im->channels;
803 for (i = 0; i < w; ++i) {
804 for (ch = 0; ch < chan_count; ++ch) {
805 if (im->ch_mask & (1 << (chans[ch]))) {
806 unsigned samp16 = SampleFTo16(*samps);
807 STORE16(im->idata, offset + chans[ch], samp16);
812 offset += im->channels;
817 if (chan_count <= 0 || chan_count > im->channels) {
819 im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
823 for (i = 0; i < w; ++i) {
825 for (ch = 0; ch < chan_count; ++ch) {
826 if (im->ch_mask & mask) {
827 unsigned samp16 = SampleFTo16(*samps);
828 STORE16(im->idata, offset + ch, samp16);
834 offset += im->channels;
842 i_push_error(0, "Image position outside of image");
852 Tony Cook <tony@develop-help.com>