re-work XS handling of channel lists
[imager.git] / img16.c
CommitLineData
faa9b3e7
TC
1/*
2=head1 NAME
3
4img16.c - implements 16-bit images
5
6=head1 SYNOPSIS
7
8d14daab 8 i_img *im = i_img_16_new(i_img_dim x, i_img_dim y, int channels);
faa9b3e7
TC
9 # use like a normal image
10
11=head1 DESCRIPTION
12
13Implements 16-bit/sample images.
14
15This basic implementation is required so that we have some larger
16sample image type to work with.
17
18=over
19
20=cut
21*/
22
92bda632
TC
23#include "imager.h"
24#include "imageri.h"
faa9b3e7 25
8d14daab
TC
26static int i_ppix_d16(i_img *im, i_img_dim x, i_img_dim y, const i_color *val);
27static int i_gpix_d16(i_img *im, i_img_dim x, i_img_dim y, i_color *val);
28static i_img_dim i_glin_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals);
29static 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);
30static int i_ppixf_d16(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val);
31static int i_gpixf_d16(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val);
32static i_img_dim i_glinf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals);
33static 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);
34static 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,
18accb2a 35 int const *chans, int chan_count);
8d14daab 36static 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,
18accb2a 37 int const *chans, int chan_count);
8d14daab 38static i_img_dim i_gsamp_bits_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned *samps,
bd8052a6 39 int const *chans, int chan_count, int bits);
8d14daab 40static 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,
bd8052a6 41 int const *chans, int chan_count, int bits);
faa9b3e7
TC
42
43/*
44=item IIM_base_16bit_direct
45
46Base structure used to initialize a 16-bit/sample image.
47
48Internal.
49
50=cut
51*/
52static i_img IIM_base_16bit_direct =
53{
54 0, /* channels set */
55 0, 0, 0, /* xsize, ysize, bytes */
9a88a5e6 56 ~0U, /* ch_mask */
faa9b3e7
TC
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 */
bd8052a6
TC
77 NULL, /* i_f_addcolors */
78 NULL, /* i_f_getcolors */
faa9b3e7 79 NULL, /* i_f_colorcount */
bd8052a6 80 NULL, /* i_f_maxcolors */
faa9b3e7 81 NULL, /* i_f_findcolor */
bd8052a6 82 NULL, /* i_f_setcolors */
faa9b3e7
TC
83
84 NULL, /* i_f_destroy */
bd8052a6
TC
85
86 i_gsamp_bits_d16,
87 i_psamp_bits_d16,
faa9b3e7
TC
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
26fd367b
TC
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.
faa9b3e7 98*/
26fd367b 99#if __STDC_VERSION__ >= 199901L && !defined(OS_dec_osf)
faa9b3e7
TC
100/* C99 should define something useful */
101#include <stdint.h>
102#ifdef UINT16_MAX
103typedef 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
112typedef 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) \
bd8052a6 123 (((i_sample16_t *)(bytes))[offset] = (byte) * 256 + (byte))
faa9b3e7
TC
124#define GET16(bytes, offset) \
125 (((i_sample16_t *)(bytes))[offset])
faa9b3e7
TC
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)), \
bd8052a6 134 (((unsigned char *)(bytes))[(offset)*2+1] = (byte)))
faa9b3e7
TC
135
136#define GET16(bytes, offset) \
137 (((unsigned char *)(bytes))[(offset)*2] * 256 \
138 + ((unsigned char *)(bytes))[(offset)*2+1])
faa9b3e7
TC
139
140#endif
141
bd8052a6
TC
142#define GET16as8(bytes, offset) \
143 ((((i_sample16_t *)(bytes))[offset]+127) / 257)
144
faa9b3e7 145/*
bd8052a6 146=item i_img_16_new(x, y, ch)
faa9b3e7 147
6cfee9d1 148=category Image creation/destruction
bd8052a6
TC
149=synopsis i_img *img = i_img_16_new(width, height, channels);
150
151Create a new 16-bit/sample image.
152
153Returns the image on success, or NULL on failure.
365ea842
TC
154
155=cut
faa9b3e7 156*/
bd8052a6 157
8d14daab 158i_img *i_img_16_new(i_img_dim x, i_img_dim y, int ch) {
bd8052a6 159 i_img *im;
8d14daab 160 size_t bytes, line_bytes;
bd8052a6 161
8d14daab
TC
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));
1501d9b3
TC
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 }
653ea321
TC
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 }
faa9b3e7 178
f0960b14
TC
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
bd8052a6 188 im = i_img_alloc();
faa9b3e7
TC
189 *im = IIM_base_16bit_direct;
190 i_tags_new(&im->tags);
191 im->xsize = x;
192 im->ysize = y;
193 im->channels = ch;
653ea321 194 im->bytes = bytes;
faa9b3e7
TC
195 im->ext_data = NULL;
196 im->idata = mymalloc(im->bytes);
bd8052a6 197 memset(im->idata, 0, im->bytes);
92bda632 198
bd8052a6 199 i_img_init(im);
faa9b3e7 200
faa9b3e7
TC
201 return im;
202}
203
167660cd
TC
204/*
205=item i_img_to_rgb16(im)
206
207=category Image creation
208
209Returns a 16-bit/sample version of the supplied image.
210
211Returns the image on success, or NULL on failure.
212
213=cut
214*/
215
216i_img *
217i_img_to_rgb16(i_img *im) {
218 i_img *targ;
219 i_fcolor *line;
8d14daab 220 i_img_dim y;
167660cd
TC
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
8d14daab
TC
236static 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;
faa9b3e7 239
837a4b43 240 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
faa9b3e7
TC
241 return -1;
242
243 off = (x + y * im->xsize) * im->channels;
9b8ce4f4
TC
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 }
faa9b3e7
TC
253
254 return 0;
255}
256
8d14daab
TC
257static 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;
faa9b3e7 260
837a4b43 261 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
faa9b3e7
TC
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
8d14daab
TC
271static 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;
faa9b3e7 274
837a4b43 275 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
faa9b3e7
TC
276 return -1;
277
278 off = (x + y * im->xsize) * im->channels;
9b8ce4f4
TC
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 }
faa9b3e7
TC
288
289 return 0;
290}
291
8d14daab
TC
292static 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;
faa9b3e7 295
837a4b43 296 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
faa9b3e7
TC
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
8d14daab
TC
306static 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;
faa9b3e7
TC
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
8d14daab
TC
328static 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;
faa9b3e7
TC
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;
9b8ce4f4
TC
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 }
faa9b3e7
TC
352 }
353 }
354 return count;
355 }
356 else {
357 return 0;
358 }
359}
360
8d14daab
TC
361static 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;
faa9b3e7
TC
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
8d14daab
TC
383static 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;
faa9b3e7
TC
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;
9b8ce4f4
TC
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 }
faa9b3e7
TC
407 }
408 }
409 return count;
410 }
411 else {
412 return 0;
413 }
414}
415
8d14daab 416static 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,
18accb2a 417 int const *chans, int chan_count) {
8d14daab
TC
418 int ch;
419 i_img_dim count, i, w;
420 i_img_dim off;
faa9b3e7
TC
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 {
c7481ae1
TC
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 }
faa9b3e7
TC
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
8d14daab 467static 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,
18accb2a 468 int const *chans, int chan_count) {
8d14daab
TC
469 int ch;
470 i_img_dim count, i, w;
471 i_img_dim off;
faa9b3e7
TC
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 {
c7481ae1
TC
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 }
faa9b3e7
TC
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
8d14daab
TC
518static i_img_dim
519i_gsamp_bits_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned *samps,
bd8052a6 520 int const *chans, int chan_count, int bits) {
8d14daab
TC
521 int ch;
522 i_img_dim count, i, w;
523 i_img_dim off;
bd8052a6
TC
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
8d14daab
TC
574static i_img_dim
575i_psamp_bits_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned const *samps,
bd8052a6 576 int const *chans, int chan_count, int bits) {
8d14daab
TC
577 int ch;
578 i_img_dim count, i, w;
579 i_img_dim off;
bd8052a6
TC
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
b8c2033e
AMH
635/*
636=back
637
638=head1 AUTHOR
639
640Tony Cook <tony@develop-help.com>
641
642=head1 SEE ALSO
643
644Imager(3)
645
646=cut
647*/