API documentation (mostly)
[imager.git] / img16.c
CommitLineData
faa9b3e7
TC
1/*
2=head1 NAME
3
4img16.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
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
97ac0a96 26static int i_ppix_d16(i_img *im, int x, int y, const i_color *val);
faa9b3e7
TC
27static int i_gpix_d16(i_img *im, int x, int y, i_color *val);
28static int i_glin_d16(i_img *im, int l, int r, int y, i_color *vals);
97ac0a96
TC
29static int i_plin_d16(i_img *im, int l, int r, int y, const i_color *vals);
30static int i_ppixf_d16(i_img *im, int x, int y, const i_fcolor *val);
faa9b3e7
TC
31static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val);
32static int i_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals);
97ac0a96 33static int i_plinf_d16(i_img *im, int l, int r, int y, const i_fcolor *vals);
faa9b3e7 34static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps,
18accb2a 35 int const *chans, int chan_count);
faa9b3e7 36static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps,
18accb2a 37 int const *chans, int chan_count);
bd8052a6
TC
38static 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);
40static 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);
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
TC
157
158i_img *i_img_16_new(int x, int y, int ch) {
159 i_img *im;
f0960b14 160 int bytes, line_bytes;
bd8052a6 161
faa9b3e7 162 mm_log((1,"i_img_16_new(x %d, y %d, ch %d)\n", x, y, ch));
1501d9b3
TC
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 }
653ea321
TC
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 }
faa9b3e7 177
f0960b14
TC
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
bd8052a6 187 im = i_img_alloc();
faa9b3e7
TC
188 *im = IIM_base_16bit_direct;
189 i_tags_new(&im->tags);
190 im->xsize = x;
191 im->ysize = y;
192 im->channels = ch;
653ea321 193 im->bytes = bytes;
faa9b3e7
TC
194 im->ext_data = NULL;
195 im->idata = mymalloc(im->bytes);
bd8052a6 196 memset(im->idata, 0, im->bytes);
92bda632 197
bd8052a6 198 i_img_init(im);
faa9b3e7 199
faa9b3e7
TC
200 return im;
201}
202
167660cd
TC
203/*
204=item i_img_to_rgb16(im)
205
206=category Image creation
207
208Returns a 16-bit/sample version of the supplied image.
209
210Returns the image on success, or NULL on failure.
211
212=cut
213*/
214
215i_img *
216i_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
97ac0a96 235static int i_ppix_d16(i_img *im, int x, int y, const i_color *val) {
faa9b3e7
TC
236 int off, ch;
237
837a4b43 238 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
faa9b3e7
TC
239 return -1;
240
241 off = (x + y * im->xsize) * im->channels;
9b8ce4f4
TC
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 }
faa9b3e7
TC
251
252 return 0;
253}
254
255static int i_gpix_d16(i_img *im, int x, int y, i_color *val) {
256 int off, ch;
257
837a4b43 258 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
faa9b3e7
TC
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
97ac0a96 268static int i_ppixf_d16(i_img *im, int x, int y, const i_fcolor *val) {
faa9b3e7
TC
269 int off, ch;
270
837a4b43 271 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
faa9b3e7
TC
272 return -1;
273
274 off = (x + y * im->xsize) * im->channels;
9b8ce4f4
TC
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 }
faa9b3e7
TC
284
285 return 0;
286}
287
288static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val) {
289 int off, ch;
290
837a4b43 291 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
faa9b3e7
TC
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
301static 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
97ac0a96 322static int i_plin_d16(i_img *im, int l, int r, int y, const i_color *vals) {
faa9b3e7
TC
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;
9b8ce4f4
TC
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 }
faa9b3e7
TC
345 }
346 }
347 return count;
348 }
349 else {
350 return 0;
351 }
352}
353
354static 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
97ac0a96 375static int i_plinf_d16(i_img *im, int l, int r, int y, const i_fcolor *vals) {
faa9b3e7
TC
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;
9b8ce4f4
TC
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 }
faa9b3e7
TC
398 }
399 }
400 return count;
401 }
402 else {
403 return 0;
404 }
405}
406
407static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps,
18accb2a 408 int const *chans, int chan_count) {
faa9b3e7
TC
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 {
c7481ae1
TC
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 }
faa9b3e7
TC
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
457static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps,
18accb2a 458 int const *chans, int chan_count) {
faa9b3e7
TC
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 {
c7481ae1
TC
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 }
faa9b3e7
TC
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
bd8052a6
TC
507static int
508i_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
562static int
563i_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
b8c2033e
AMH
622/*
623=back
624
625=head1 AUTHOR
626
627Tony Cook <tony@develop-help.com>
628
629=head1 SEE ALSO
630
631Imager(3)
632
633=cut
634*/