WIP, more context changes
[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
696cb85d
TC
23#define IMAGER_NO_CONTEXT
24
92bda632
TC
25#include "imager.h"
26#include "imageri.h"
faa9b3e7 27
8d14daab
TC
28static int i_ppix_d16(i_img *im, i_img_dim x, i_img_dim y, const i_color *val);
29static int i_gpix_d16(i_img *im, i_img_dim x, i_img_dim y, i_color *val);
30static i_img_dim i_glin_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals);
31static 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);
32static int i_ppixf_d16(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val);
33static int i_gpixf_d16(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val);
34static i_img_dim i_glinf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals);
35static 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);
36static 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 37 int const *chans, int chan_count);
8d14daab 38static 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 39 int const *chans, int chan_count);
8d14daab 40static 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 41 int const *chans, int chan_count, int bits);
8d14daab 42static 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 43 int const *chans, int chan_count, int bits);
836d9f54
TC
44static 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);
45static 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);
faa9b3e7
TC
46
47/*
48=item IIM_base_16bit_direct
49
50Base structure used to initialize a 16-bit/sample image.
51
52Internal.
53
54=cut
55*/
56static i_img IIM_base_16bit_direct =
57{
58 0, /* channels set */
59 0, 0, 0, /* xsize, ysize, bytes */
9a88a5e6 60 ~0U, /* ch_mask */
faa9b3e7
TC
61 i_16_bits, /* bits */
62 i_direct_type, /* type */
63 0, /* virtual */
64 NULL, /* idata */
65 { 0, 0, NULL }, /* tags */
66 NULL, /* ext_data */
67
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 */
78
79 NULL, /* i_f_gpal */
80 NULL, /* i_f_ppal */
bd8052a6
TC
81 NULL, /* i_f_addcolors */
82 NULL, /* i_f_getcolors */
faa9b3e7 83 NULL, /* i_f_colorcount */
bd8052a6 84 NULL, /* i_f_maxcolors */
faa9b3e7 85 NULL, /* i_f_findcolor */
bd8052a6 86 NULL, /* i_f_setcolors */
faa9b3e7
TC
87
88 NULL, /* i_f_destroy */
bd8052a6
TC
89
90 i_gsamp_bits_d16,
91 i_psamp_bits_d16,
836d9f54
TC
92
93 i_psamp_d16,
94 i_psampf_d16
faa9b3e7
TC
95};
96
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
99
100 We do assume 8-bit char
26fd367b
TC
101
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.
faa9b3e7 105*/
26fd367b 106#if __STDC_VERSION__ >= 199901L && !defined(OS_dec_osf)
faa9b3e7
TC
107/* C99 should define something useful */
108#include <stdint.h>
109#ifdef UINT16_MAX
110typedef uint16_t i_sample16_t;
111#define GOT16
112#endif
113#endif
114
115/* check out unsigned short */
116#ifndef GOT16
117#include <limits.h>
118#if USHRT_MAX == 65535
119typedef unsigned short i_sample16_t;
120#define GOT16
121#endif
122#endif
123
124#ifdef GOT16
125
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) \
bd8052a6 130 (((i_sample16_t *)(bytes))[offset] = (byte) * 256 + (byte))
faa9b3e7
TC
131#define GET16(bytes, offset) \
132 (((i_sample16_t *)(bytes))[offset])
faa9b3e7
TC
133#else
134
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)), \
bd8052a6 141 (((unsigned char *)(bytes))[(offset)*2+1] = (byte)))
faa9b3e7
TC
142
143#define GET16(bytes, offset) \
144 (((unsigned char *)(bytes))[(offset)*2] * 256 \
145 + ((unsigned char *)(bytes))[(offset)*2+1])
faa9b3e7
TC
146
147#endif
148
bd8052a6
TC
149#define GET16as8(bytes, offset) \
150 ((((i_sample16_t *)(bytes))[offset]+127) / 257)
151
faa9b3e7 152/*
d03fd5a4
TC
153=item i_img_16_new(x, y, ch)
154
6cfee9d1 155=category Image creation/destruction
bd8052a6
TC
156=synopsis i_img *img = i_img_16_new(width, height, channels);
157
158Create a new 16-bit/sample image.
159
160Returns the image on success, or NULL on failure.
365ea842
TC
161
162=cut
faa9b3e7 163*/
bd8052a6 164
696cb85d
TC
165i_img *
166im_img_16_new(pIMCTX, i_img_dim x, i_img_dim y, int ch) {
bd8052a6 167 i_img *im;
8d14daab 168 size_t bytes, line_bytes;
bd8052a6 169
d03fd5a4 170 mm_log((1,"i_img_16_new(x %" i_DF ", y %" i_DF ", ch %d)\n",
8d14daab 171 i_DFc(x), i_DFc(y), ch));
1501d9b3
TC
172
173 if (x < 1 || y < 1) {
696cb85d 174 im_push_error(aIMCTX, 0, "Image sizes must be positive");
1501d9b3
TC
175 return NULL;
176 }
177 if (ch < 1 || ch > MAXCHANNELS) {
696cb85d 178 im_push_errorf(aIMCTX, 0, "channels must be between 1 and %d", MAXCHANNELS);
1501d9b3
TC
179 return NULL;
180 }
653ea321
TC
181 bytes = x * y * ch * 2;
182 if (bytes / y / ch / 2 != x) {
696cb85d 183 im_push_errorf(aIMCTX, 0, "integer overflow calculating image allocation");
653ea321
TC
184 return NULL;
185 }
faa9b3e7 186
f0960b14
TC
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)) {
696cb85d 192 im_push_error(aIMCTX, 0, "integer overflow calculating scanline allocation");
f0960b14
TC
193 return NULL;
194 }
195
696cb85d 196 im = im_img_alloc(aIMCTX);
faa9b3e7
TC
197 *im = IIM_base_16bit_direct;
198 i_tags_new(&im->tags);
199 im->xsize = x;
200 im->ysize = y;
201 im->channels = ch;
653ea321 202 im->bytes = bytes;
faa9b3e7
TC
203 im->ext_data = NULL;
204 im->idata = mymalloc(im->bytes);
bd8052a6 205 memset(im->idata, 0, im->bytes);
92bda632 206
696cb85d 207 im_img_init(aIMCTX, im);
faa9b3e7 208
faa9b3e7
TC
209 return im;
210}
211
167660cd
TC
212/*
213=item i_img_to_rgb16(im)
214
215=category Image creation
216
217Returns a 16-bit/sample version of the supplied image.
218
219Returns the image on success, or NULL on failure.
220
221=cut
222*/
223
224i_img *
225i_img_to_rgb16(i_img *im) {
226 i_img *targ;
227 i_fcolor *line;
8d14daab 228 i_img_dim y;
696cb85d 229 dIMCTXim(im);
167660cd 230
696cb85d 231 targ = im_img_16_new(aIMCTX, im->xsize, im->ysize, im->channels);
167660cd
TC
232 if (!targ)
233 return NULL;
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);
238 }
239
240 myfree(line);
241
242 return targ;
243}
244
8d14daab
TC
245static int i_ppix_d16(i_img *im, i_img_dim x, i_img_dim y, const i_color *val) {
246 i_img_dim off;
247 int ch;
faa9b3e7 248
837a4b43 249 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
faa9b3e7
TC
250 return -1;
251
252 off = (x + y * im->xsize) * im->channels;
9b8ce4f4
TC
253 if (I_ALL_CHANNELS_WRITABLE(im)) {
254 for (ch = 0; ch < im->channels; ++ch)
255 STORE8as16(im->idata, off+ch, val->channel[ch]);
256 }
257 else {
258 for (ch = 0; ch < im->channels; ++ch)
259 if (im->ch_mask & (1 << ch))
260 STORE8as16(im->idata, off+ch, val->channel[ch]);
261 }
faa9b3e7
TC
262
263 return 0;
264}
265
8d14daab
TC
266static int i_gpix_d16(i_img *im, i_img_dim x, i_img_dim y, i_color *val) {
267 i_img_dim off;
268 int ch;
faa9b3e7 269
837a4b43 270 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
faa9b3e7
TC
271 return -1;
272
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);
276
277 return 0;
278}
279
8d14daab
TC
280static int i_ppixf_d16(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val) {
281 i_img_dim off;
282 int ch;
faa9b3e7 283
837a4b43 284 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
faa9b3e7
TC
285 return -1;
286
287 off = (x + y * im->xsize) * im->channels;
9b8ce4f4
TC
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]));
291 }
292 else {
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]));
296 }
faa9b3e7
TC
297
298 return 0;
299}
300
8d14daab
TC
301static int i_gpixf_d16(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val) {
302 i_img_dim off;
303 int ch;
faa9b3e7 304
837a4b43 305 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
faa9b3e7
TC
306 return -1;
307
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));
311
312 return 0;
313}
314
8d14daab
TC
315static i_img_dim i_glin_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals) {
316 int ch;
317 i_img_dim count, i;
318 i_img_dim off;
faa9b3e7
TC
319 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
320 if (r > im->xsize)
321 r = im->xsize;
322 off = (l+y*im->xsize) * im->channels;
323 count = r - l;
324 for (i = 0; i < count; ++i) {
325 for (ch = 0; ch < im->channels; ++ch) {
326 vals[i].channel[ch] = GET16as8(im->idata, off);
327 ++off;
328 }
329 }
330 return count;
331 }
332 else {
333 return 0;
334 }
335}
336
8d14daab
TC
337static 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) {
338 int ch;
339 i_img_dim count, i;
340 i_img_dim off;
faa9b3e7
TC
341 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
342 if (r > im->xsize)
343 r = im->xsize;
344 off = (l+y*im->xsize) * im->channels;
345 count = r - l;
9b8ce4f4
TC
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]);
350 ++off;
351 }
352 }
353 }
354 else {
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]);
359 ++off;
360 }
faa9b3e7
TC
361 }
362 }
363 return count;
364 }
365 else {
366 return 0;
367 }
368}
369
8d14daab
TC
370static i_img_dim i_glinf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals) {
371 int ch;
372 i_img_dim count, i;
373 i_img_dim off;
faa9b3e7
TC
374 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
375 if (r > im->xsize)
376 r = im->xsize;
377 off = (l+y*im->xsize) * im->channels;
378 count = r - l;
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));
382 ++off;
383 }
384 }
385 return count;
386 }
387 else {
388 return 0;
389 }
390}
391
8d14daab
TC
392static 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) {
393 int ch;
394 i_img_dim count, i;
395 i_img_dim off;
faa9b3e7
TC
396 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
397 if (r > im->xsize)
398 r = im->xsize;
399 off = (l+y*im->xsize) * im->channels;
400 count = r - l;
9b8ce4f4
TC
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]));
405 ++off;
406 }
407 }
408 }
409 else {
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]));
414 ++off;
415 }
faa9b3e7
TC
416 }
417 }
418 return count;
419 }
420 else {
421 return 0;
422 }
423}
424
8d14daab 425static 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 426 int const *chans, int chan_count) {
8d14daab
TC
427 int ch;
428 i_img_dim count, i, w;
429 i_img_dim off;
faa9b3e7
TC
430
431 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
432 if (r > im->xsize)
433 r = im->xsize;
434 off = (l+y*im->xsize) * im->channels;
435 w = r - l;
436 count = 0;
437
438 if (chans) {
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) {
d03fd5a4 442 i_push_errorf(0, "No channel %d in this image", chans[ch]);
faa9b3e7
TC
443 return 0;
444 }
445 }
446 for (i = 0; i < w; ++i) {
447 for (ch = 0; ch < chan_count; ++ch) {
448 *samps++ = GET16as8(im->idata, off+chans[ch]);
449 ++count;
450 }
451 off += im->channels;
452 }
453 }
454 else {
c7481ae1 455 if (chan_count <= 0 || chan_count > im->channels) {
d03fd5a4 456 i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
c7481ae1
TC
457 chan_count);
458 return 0;
459 }
faa9b3e7
TC
460 for (i = 0; i < w; ++i) {
461 for (ch = 0; ch < chan_count; ++ch) {
462 *samps++ = GET16as8(im->idata, off+ch);
463 ++count;
464 }
465 off += im->channels;
466 }
467 }
468
469 return count;
470 }
471 else {
472 return 0;
473 }
474}
475
8d14daab 476static 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 477 int const *chans, int chan_count) {
8d14daab
TC
478 int ch;
479 i_img_dim count, i, w;
480 i_img_dim off;
faa9b3e7
TC
481
482 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
483 if (r > im->xsize)
484 r = im->xsize;
485 off = (l+y*im->xsize) * im->channels;
486 w = r - l;
487 count = 0;
488
489 if (chans) {
490 /* make sure we have good channel numbers */
491 for (ch = 0; ch < chan_count; ++ch) {
492 if (chans[ch] < 0 || chans[ch] >= im->channels) {
d03fd5a4 493 i_push_errorf(0, "No channel %d in this image", chans[ch]);
faa9b3e7
TC
494 return 0;
495 }
496 }
497 for (i = 0; i < w; ++i) {
498 for (ch = 0; ch < chan_count; ++ch) {
499 *samps++ = Sample16ToF(GET16(im->idata, off+chans[ch]));
500 ++count;
501 }
502 off += im->channels;
503 }
504 }
505 else {
c7481ae1 506 if (chan_count <= 0 || chan_count > im->channels) {
d03fd5a4 507 i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
c7481ae1
TC
508 chan_count);
509 return 0;
510 }
faa9b3e7
TC
511 for (i = 0; i < w; ++i) {
512 for (ch = 0; ch < chan_count; ++ch) {
513 *samps++ = Sample16ToF(GET16(im->idata, off+ch));
514 ++count;
515 }
516 off += im->channels;
517 }
518 }
519
520 return count;
521 }
522 else {
523 return 0;
524 }
525}
526
8d14daab
TC
527static i_img_dim
528i_gsamp_bits_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned *samps,
bd8052a6 529 int const *chans, int chan_count, int bits) {
8d14daab
TC
530 int ch;
531 i_img_dim count, i, w;
532 i_img_dim off;
bd8052a6
TC
533
534 if (bits != 16) {
535 return i_gsamp_bits_fb(im, l, r, y, samps, chans, chan_count, bits);
536 }
537
538 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
539 if (r > im->xsize)
540 r = im->xsize;
541 off = (l+y*im->xsize) * im->channels;
542 w = r - l;
543 count = 0;
544
545 if (chans) {
546 /* make sure we have good channel numbers */
547 for (ch = 0; ch < chan_count; ++ch) {
548 if (chans[ch] < 0 || chans[ch] >= im->channels) {
d03fd5a4 549 i_push_errorf(0, "No channel %d in this image", chans[ch]);
bd8052a6
TC
550 return -1;
551 }
552 }
553 for (i = 0; i < w; ++i) {
554 for (ch = 0; ch < chan_count; ++ch) {
555 *samps++ = GET16(im->idata, off+chans[ch]);
556 ++count;
557 }
558 off += im->channels;
559 }
560 }
561 else {
562 if (chan_count <= 0 || chan_count > im->channels) {
696cb85d 563 dIMCTXim(im);
bd8052a6
TC
564 i_push_error(0, "Invalid channel count");
565 return -1;
566 }
567 for (i = 0; i < w; ++i) {
568 for (ch = 0; ch < chan_count; ++ch) {
569 *samps++ = GET16(im->idata, off+ch);
570 ++count;
571 }
572 off += im->channels;
573 }
574 }
575
576 return count;
577 }
578 else {
696cb85d 579 dIMCTXim(im);
bd8052a6
TC
580 i_push_error(0, "Image position outside of image");
581 return -1;
582 }
583}
584
8d14daab
TC
585static i_img_dim
586i_psamp_bits_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned const *samps,
bd8052a6 587 int const *chans, int chan_count, int bits) {
8d14daab
TC
588 int ch;
589 i_img_dim count, i, w;
590 i_img_dim off;
bd8052a6
TC
591
592 if (bits != 16) {
696cb85d 593 dIMCTXim(im);
bd8052a6
TC
594 i_push_error(0, "Invalid bits for 16-bit image");
595 return -1;
596 }
597
598 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
599 if (r > im->xsize)
600 r = im->xsize;
601 off = (l+y*im->xsize) * im->channels;
602 w = r - l;
603 count = 0;
604
605 if (chans) {
606 /* make sure we have good channel numbers */
607 for (ch = 0; ch < chan_count; ++ch) {
608 if (chans[ch] < 0 || chans[ch] >= im->channels) {
d03fd5a4 609 i_push_errorf(0, "No channel %d in this image", chans[ch]);
bd8052a6
TC
610 return -1;
611 }
612 }
613 for (i = 0; i < w; ++i) {
614 for (ch = 0; ch < chan_count; ++ch) {
615 if (im->ch_mask & (1 << ch))
616 STORE16(im->idata, off+chans[ch], *samps);
617 ++samps;
618 ++count;
619 }
620 off += im->channels;
621 }
622 }
623 else {
624 if (chan_count <= 0 || chan_count > im->channels) {
696cb85d 625 dIMCTXim(im);
bd8052a6
TC
626 i_push_error(0, "Invalid channel count");
627 return -1;
628 }
629 for (i = 0; i < w; ++i) {
630 for (ch = 0; ch < chan_count; ++ch) {
631 if (im->ch_mask & (1 << ch))
632 STORE16(im->idata, off+ch, *samps);
633 ++samps;
634 ++count;
635 }
636 off += im->channels;
637 }
638 }
639
640 return count;
641 }
642 else {
696cb85d 643 dIMCTXim(im);
bd8052a6
TC
644 i_push_error(0, "Image position outside of image");
645 return -1;
646 }
647}
648
836d9f54
TC
649/*
650=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)
651
652Writes sample values to im for the horizontal line (l, y) to (r-1,y)
653for the channels specified by chans, an array of int with chan_count
654elements.
655
656Returns the number of samples written (which should be (r-l) *
657bits_set(chan_mask)
658
659=cut
660*/
661
662static
663i_img_dim
664i_psamp_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
665 const i_sample_t *samps, const int *chans, int chan_count) {
666 int ch;
667 i_img_dim count, i, w;
668
669 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
836d9f54
TC
670 i_img_dim offset;
671 if (r > im->xsize)
672 r = im->xsize;
673 offset = (l+y*im->xsize) * im->channels;
674 w = r - l;
675 count = 0;
676
677 if (chans) {
678 /* make sure we have good channel numbers */
679 /* and test if all channels specified are in the mask */
680 int all_in_mask = 1;
681 for (ch = 0; ch < chan_count; ++ch) {
682 if (chans[ch] < 0 || chans[ch] >= im->channels) {
d03fd5a4 683 i_push_errorf(0, "No channel %d in this image", chans[ch]);
836d9f54
TC
684 return -1;
685 }
686 if (!((1 << chans[ch]) & im->ch_mask))
687 all_in_mask = 0;
688 }
689 if (all_in_mask) {
690 for (i = 0; i < w; ++i) {
691 for (ch = 0; ch < chan_count; ++ch) {
692 STORE8as16(im->idata, offset + chans[ch], *samps);
693 ++samps;
694 ++count;
695 }
696 offset += im->channels;
697 }
698 }
699 else {
700 for (i = 0; i < w; ++i) {
701 for (ch = 0; ch < chan_count; ++ch) {
702 if (im->ch_mask & (1 << (chans[ch])))
703 STORE8as16(im->idata, offset + chans[ch], *samps);
704 ++samps;
705 ++count;
706 }
707 offset += im->channels;
708 }
709 }
710 }
711 else {
712 if (chan_count <= 0 || chan_count > im->channels) {
d03fd5a4 713 i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
836d9f54
TC
714 chan_count);
715 return -1;
716 }
717 for (i = 0; i < w; ++i) {
718 unsigned mask = 1;
719 for (ch = 0; ch < chan_count; ++ch) {
720 if (im->ch_mask & mask)
721 STORE8as16(im->idata, offset + ch, *samps);
722 ++samps;
723 ++count;
724 mask <<= 1;
725 }
726 offset += im->channels;
727 }
728 }
729
730 return count;
731 }
732 else {
696cb85d 733 dIMCTXim(im);
836d9f54
TC
734 i_push_error(0, "Image position outside of image");
735 return -1;
736 }
737}
738
739/*
740=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)
741
742Writes sample values to im for the horizontal line (l, y) to (r-1,y)
743for the channels specified by chans, an array of int with chan_count
744elements.
745
746Returns the number of samples written (which should be (r-l) *
747bits_set(chan_mask)
748
749=cut
750*/
751
752static
753i_img_dim
754i_psampf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
755 const i_fsample_t *samps, const int *chans, int chan_count) {
756 int ch;
757 i_img_dim count, i, w;
758
759 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
836d9f54
TC
760 i_img_dim offset;
761 if (r > im->xsize)
762 r = im->xsize;
763 offset = (l+y*im->xsize) * im->channels;
764 w = r - l;
765 count = 0;
766
767 if (chans) {
768 /* make sure we have good channel numbers */
769 /* and test if all channels specified are in the mask */
770 int all_in_mask = 1;
771 for (ch = 0; ch < chan_count; ++ch) {
772 if (chans[ch] < 0 || chans[ch] >= im->channels) {
d03fd5a4 773 i_push_errorf(0, "No channel %d in this image", chans[ch]);
836d9f54
TC
774 return -1;
775 }
776 if (!((1 << chans[ch]) & im->ch_mask))
777 all_in_mask = 0;
778 }
779 if (all_in_mask) {
780 for (i = 0; i < w; ++i) {
781 for (ch = 0; ch < chan_count; ++ch) {
782 unsigned samp16 = SampleFTo16(*samps);
783 STORE16(im->idata, offset + chans[ch], samp16);
784 ++samps;
785 ++count;
786 }
787 offset += im->channels;
788 }
789 }
790 else {
791 for (i = 0; i < w; ++i) {
792 for (ch = 0; ch < chan_count; ++ch) {
793 if (im->ch_mask & (1 << (chans[ch]))) {
794 unsigned samp16 = SampleFTo16(*samps);
795 STORE16(im->idata, offset + chans[ch], samp16);
796 }
797 ++samps;
798 ++count;
799 }
800 offset += im->channels;
801 }
802 }
803 }
804 else {
805 if (chan_count <= 0 || chan_count > im->channels) {
d03fd5a4 806 i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
836d9f54
TC
807 chan_count);
808 return -1;
809 }
810 for (i = 0; i < w; ++i) {
811 unsigned mask = 1;
812 for (ch = 0; ch < chan_count; ++ch) {
813 if (im->ch_mask & mask) {
814 unsigned samp16 = SampleFTo16(*samps);
815 STORE16(im->idata, offset + ch, samp16);
816 }
817 ++samps;
818 ++count;
819 mask <<= 1;
820 }
821 offset += im->channels;
822 }
823 }
824
825 return count;
826 }
827 else {
696cb85d 828 dIMCTXim(im);
836d9f54
TC
829 i_push_error(0, "Image position outside of image");
830 return -1;
831 }
832}
833
b8c2033e
AMH
834/*
835=back
836
837=head1 AUTHOR
838
839Tony Cook <tony@develop-help.com>
840
841=head1 SEE ALSO
842
843Imager(3)
844
845=cut
846*/