WIP, more context changes
[imager.git] / imgdouble.c
CommitLineData
2ce44e2a
TC
1/*
2=head1 NAME
3
4imgdouble.c - implements double per sample images
5
6=head1 SYNOPSIS
7
8d14daab 8 i_img *im = i_img_double_new(width, height, channels);
2ce44e2a
TC
9 # use like a normal image
10
11=head1 DESCRIPTION
12
13Implements double/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
156699af 23#define IMAGER_NO_CONTEXT
92bda632
TC
24#include "imager.h"
25#include "imageri.h"
2ce44e2a 26
8d14daab
TC
27static int i_ppix_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_color *val);
28static int i_gpix_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_color *val);
29static i_img_dim i_glin_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals);
30static i_img_dim i_plin_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals);
31static int i_ppixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val);
32static int i_gpixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val);
33static i_img_dim i_glinf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals);
34static i_img_dim i_plinf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals);
35static i_img_dim i_gsamp_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps,
18accb2a 36 int const *chans, int chan_count);
8d14daab 37static i_img_dim i_gsampf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps,
18accb2a 38 int const *chans, int chan_count);
836d9f54
TC
39static i_img_dim
40i_psamp_ddoub(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);
41static i_img_dim
42i_psampf_ddoub(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);
2ce44e2a
TC
43
44/*
45=item IIM_base_16bit_direct
46
47Base structure used to initialize a 16-bit/sample image.
48
49Internal.
50
51=cut
52*/
53static i_img IIM_base_double_direct =
54{
55 0, /* channels set */
56 0, 0, 0, /* xsize, ysize, bytes */
9a88a5e6 57 ~0U, /* ch_mask */
2ce44e2a
TC
58 i_double_bits, /* bits */
59 i_direct_type, /* type */
60 0, /* virtual */
61 NULL, /* idata */
62 { 0, 0, NULL }, /* tags */
63 NULL, /* ext_data */
64
65 i_ppix_ddoub, /* i_f_ppix */
66 i_ppixf_ddoub, /* i_f_ppixf */
67 i_plin_ddoub, /* i_f_plin */
68 i_plinf_ddoub, /* i_f_plinf */
69 i_gpix_ddoub, /* i_f_gpix */
70 i_gpixf_ddoub, /* i_f_gpixf */
71 i_glin_ddoub, /* i_f_glin */
72 i_glinf_ddoub, /* i_f_glinf */
73 i_gsamp_ddoub, /* i_f_gsamp */
74 i_gsampf_ddoub, /* i_f_gsampf */
75
76 NULL, /* i_f_gpal */
77 NULL, /* i_f_ppal */
bd8052a6
TC
78 NULL, /* i_f_addcolors */
79 NULL, /* i_f_getcolors */
2ce44e2a 80 NULL, /* i_f_colorcount */
bd8052a6 81 NULL, /* i_f_maxcolors */
2ce44e2a 82 NULL, /* i_f_findcolor */
bd8052a6 83 NULL, /* i_f_setcolors */
2ce44e2a
TC
84
85 NULL, /* i_f_destroy */
bd8052a6
TC
86
87 i_gsamp_bits_fb,
88 NULL, /* i_f_psamp_bits */
836d9f54
TC
89
90 i_psamp_ddoub, /* i_f_psamp */
91 i_psampf_ddoub /* i_f_psampf */
2ce44e2a
TC
92};
93
94/*
8d14daab 95=item i_img_double_new(i_img_dim x, i_img_dim y, int ch)
9167a5c6
TC
96=category Image creation/destruction
97=synopsis i_img *img = i_img_double_new(width, height, channels);
92bda632 98
2ce44e2a
TC
99Creates a new double per sample image.
100
101=cut
102*/
156699af
TC
103i_img *
104im_img_double_new(pIMCTX, i_img_dim x, i_img_dim y, int ch) {
8d14daab 105 size_t bytes;
bd8052a6 106 i_img *im;
653ea321 107
8d14daab
TC
108 mm_log((1,"i_img_double_new(x %" i_DF ", y %" i_DF ", ch %d)\n",
109 i_DFc(x), i_DFc(y), ch));
1501d9b3
TC
110
111 if (x < 1 || y < 1) {
156699af 112 im_push_error(aIMCTX, 0, "Image sizes must be positive");
1501d9b3
TC
113 return NULL;
114 }
115 if (ch < 1 || ch > MAXCHANNELS) {
156699af 116 im_push_errorf(aIMCTX, 0, "channels must be between 1 and %d", MAXCHANNELS);
1501d9b3
TC
117 return NULL;
118 }
653ea321
TC
119 bytes = x * y * ch * sizeof(double);
120 if (bytes / y / ch / sizeof(double) != x) {
156699af 121 im_push_errorf(aIMCTX, 0, "integer overflow calculating image allocation");
653ea321
TC
122 return NULL;
123 }
2ce44e2a 124
156699af 125 im = im_img_alloc(aIMCTX);
2ce44e2a
TC
126 *im = IIM_base_double_direct;
127 i_tags_new(&im->tags);
128 im->xsize = x;
129 im->ysize = y;
130 im->channels = ch;
653ea321 131 im->bytes = bytes;
2ce44e2a
TC
132 im->ext_data = NULL;
133 im->idata = mymalloc(im->bytes);
bd8052a6 134 memset(im->idata, 0, im->bytes);
156699af 135 im_img_init(aIMCTX, im);
2ce44e2a
TC
136
137 return im;
138}
139
8d14daab
TC
140static int i_ppix_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_color *val) {
141 i_img_dim off;
142 int ch;
2ce44e2a 143
837a4b43 144 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
2ce44e2a
TC
145 return -1;
146
147 off = (x + y * im->xsize) * im->channels;
35f40526
TC
148 if (I_ALL_CHANNELS_WRITABLE(im)) {
149 for (ch = 0; ch < im->channels; ++ch)
150 ((double*)im->idata)[off+ch] = Sample8ToF(val->channel[ch]);
151 }
152 else {
153 for (ch = 0; ch < im->channels; ++ch)
154 if (im->ch_mask & (1<<ch))
155 ((double*)im->idata)[off+ch] = Sample8ToF(val->channel[ch]);
156 }
2ce44e2a
TC
157
158 return 0;
159}
160
8d14daab
TC
161static int i_gpix_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_color *val) {
162 i_img_dim off;
163 int ch;
2ce44e2a 164
837a4b43 165 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
2ce44e2a
TC
166 return -1;
167
168 off = (x + y * im->xsize) * im->channels;
169 for (ch = 0; ch < im->channels; ++ch)
170 val->channel[ch] = SampleFTo8(((double *)im->idata)[off+ch]);
171
172 return 0;
173}
174
8d14daab
TC
175static int i_ppixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val) {
176 i_img_dim off;
177 int ch;
2ce44e2a 178
837a4b43 179 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
2ce44e2a
TC
180 return -1;
181
182 off = (x + y * im->xsize) * im->channels;
35f40526
TC
183 if (I_ALL_CHANNELS_WRITABLE(im)) {
184 for (ch = 0; ch < im->channels; ++ch)
185 ((double *)im->idata)[off+ch] = val->channel[ch];
186 }
187 else {
188 for (ch = 0; ch < im->channels; ++ch)
189 if (im->ch_mask & (1 << ch))
190 ((double *)im->idata)[off+ch] = val->channel[ch];
191 }
2ce44e2a
TC
192
193 return 0;
194}
195
8d14daab
TC
196static int i_gpixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val) {
197 i_img_dim off;
198 int ch;
2ce44e2a 199
837a4b43 200 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
2ce44e2a
TC
201 return -1;
202
203 off = (x + y * im->xsize) * im->channels;
204 for (ch = 0; ch < im->channels; ++ch)
205 val->channel[ch] = ((double *)im->idata)[off+ch];
206
207 return 0;
208}
209
8d14daab
TC
210static i_img_dim i_glin_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals) {
211 int ch;
212 i_img_dim count, i;
213 i_img_dim off;
2ce44e2a
TC
214 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
215 if (r > im->xsize)
216 r = im->xsize;
217 off = (l+y*im->xsize) * im->channels;
218 count = r - l;
219 for (i = 0; i < count; ++i) {
220 for (ch = 0; ch < im->channels; ++ch) {
221 vals[i].channel[ch] = SampleFTo8(((double *)im->idata)[off]);
222 ++off;
223 }
224 }
225 return count;
226 }
227 else {
228 return 0;
229 }
230}
231
8d14daab
TC
232static i_img_dim i_plin_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals) {
233 int ch;
234 i_img_dim count, i;
235 i_img_dim off;
2ce44e2a
TC
236 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
237 if (r > im->xsize)
238 r = im->xsize;
239 off = (l+y*im->xsize) * im->channels;
240 count = r - l;
35f40526
TC
241 if (I_ALL_CHANNELS_WRITABLE(im)) {
242 for (i = 0; i < count; ++i) {
243 for (ch = 0; ch < im->channels; ++ch) {
244 ((double *)im->idata)[off] = Sample8ToF(vals[i].channel[ch]);
245 ++off;
246 }
247 }
248 }
249 else {
250 for (i = 0; i < count; ++i) {
251 for (ch = 0; ch < im->channels; ++ch) {
252 if (im->ch_mask & (1 << ch))
253 ((double *)im->idata)[off] = Sample8ToF(vals[i].channel[ch]);
254 ++off;
255 }
2ce44e2a
TC
256 }
257 }
258 return count;
259 }
260 else {
261 return 0;
262 }
263}
264
8d14daab
TC
265static i_img_dim i_glinf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals) {
266 int ch;
267 i_img_dim count, i;
268 i_img_dim off;
2ce44e2a
TC
269 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
270 if (r > im->xsize)
271 r = im->xsize;
272 off = (l+y*im->xsize) * im->channels;
273 count = r - l;
274 for (i = 0; i < count; ++i) {
275 for (ch = 0; ch < im->channels; ++ch) {
276 vals[i].channel[ch] = ((double *)im->idata)[off];
277 ++off;
278 }
279 }
280 return count;
281 }
282 else {
283 return 0;
284 }
285}
286
8d14daab
TC
287static i_img_dim i_plinf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals) {
288 int ch;
289 i_img_dim count, i;
290 i_img_dim off;
2ce44e2a
TC
291 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
292 if (r > im->xsize)
293 r = im->xsize;
294 off = (l+y*im->xsize) * im->channels;
295 count = r - l;
35f40526
TC
296 if (I_ALL_CHANNELS_WRITABLE(im)) {
297 for (i = 0; i < count; ++i) {
298 for (ch = 0; ch < im->channels; ++ch) {
299 ((double *)im->idata)[off] = vals[i].channel[ch];
300 ++off;
301 }
302 }
303 }
304 else {
305 for (i = 0; i < count; ++i) {
306 for (ch = 0; ch < im->channels; ++ch) {
307 if (im->ch_mask & (1 << ch))
308 ((double *)im->idata)[off] = vals[i].channel[ch];
309 ++off;
310 }
2ce44e2a
TC
311 }
312 }
313 return count;
314 }
315 else {
316 return 0;
317 }
318}
319
8d14daab 320static i_img_dim i_gsamp_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps,
18accb2a 321 int const *chans, int chan_count) {
8d14daab
TC
322 int ch;
323 i_img_dim count, i, w;
324 i_img_dim off;
2ce44e2a
TC
325
326 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
327 if (r > im->xsize)
328 r = im->xsize;
329 off = (l+y*im->xsize) * im->channels;
330 w = r - l;
331 count = 0;
332
333 if (chans) {
334 /* make sure we have good channel numbers */
335 for (ch = 0; ch < chan_count; ++ch) {
336 if (chans[ch] < 0 || chans[ch] >= im->channels) {
156699af
TC
337 dIMCTXim(im);
338 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
2ce44e2a
TC
339 return 0;
340 }
341 }
342 for (i = 0; i < w; ++i) {
343 for (ch = 0; ch < chan_count; ++ch) {
344 *samps++ = SampleFTo8(((double *)im->idata)[off+chans[ch]]);
345 ++count;
346 }
347 off += im->channels;
348 }
349 }
350 else {
c7481ae1 351 if (chan_count <= 0 || chan_count > im->channels) {
156699af
TC
352 dIMCTXim(im);
353 im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
c7481ae1
TC
354 chan_count);
355 return 0;
356 }
2ce44e2a
TC
357 for (i = 0; i < w; ++i) {
358 for (ch = 0; ch < chan_count; ++ch) {
359 *samps++ = SampleFTo8(((double *)im->idata)[off+ch]);
360 ++count;
361 }
362 off += im->channels;
363 }
364 }
365
366 return count;
367 }
368 else {
369 return 0;
370 }
371}
372
8d14daab 373static i_img_dim i_gsampf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps,
18accb2a 374 int const *chans, int chan_count) {
8d14daab
TC
375 int ch;
376 i_img_dim count, i, w;
377 i_img_dim off;
2ce44e2a
TC
378
379 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
380 if (r > im->xsize)
381 r = im->xsize;
382 off = (l+y*im->xsize) * im->channels;
383 w = r - l;
384 count = 0;
385
386 if (chans) {
387 /* make sure we have good channel numbers */
388 for (ch = 0; ch < chan_count; ++ch) {
389 if (chans[ch] < 0 || chans[ch] >= im->channels) {
156699af
TC
390 dIMCTXim(im);
391 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
2ce44e2a
TC
392 return 0;
393 }
394 }
395 for (i = 0; i < w; ++i) {
396 for (ch = 0; ch < chan_count; ++ch) {
397 *samps++ = ((double *)im->idata)[off+chans[ch]];
398 ++count;
399 }
400 off += im->channels;
401 }
402 }
403 else {
c7481ae1 404 if (chan_count <= 0 || chan_count > im->channels) {
156699af
TC
405 dIMCTXim(im);
406 im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
c7481ae1
TC
407 chan_count);
408 return 0;
409 }
2ce44e2a
TC
410 for (i = 0; i < w; ++i) {
411 for (ch = 0; ch < chan_count; ++ch) {
412 *samps++ = ((double *)im->idata)[off+ch];
413 ++count;
414 }
415 off += im->channels;
416 }
417 }
418
419 return count;
420 }
421 else {
422 return 0;
423 }
424}
425
836d9f54
TC
426/*
427=item i_psamp_ddoub(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)
428
429Writes sample values to im for the horizontal line (l, y) to (r-1,y)
430for the channels specified by chans, an array of int with chan_count
431elements.
432
433Returns the number of samples written (which should be (r-l) *
434bits_set(chan_mask)
435
436=cut
437*/
438
439static
440i_img_dim
441i_psamp_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
442 const i_sample_t *samps, const int *chans, int chan_count) {
443 int ch;
444 i_img_dim count, i, w;
445
446 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
836d9f54
TC
447 i_img_dim offset;
448 if (r > im->xsize)
449 r = im->xsize;
450 offset = (l+y*im->xsize) * im->channels;
451 w = r - l;
452 count = 0;
453
454 if (chans) {
455 /* make sure we have good channel numbers */
456 /* and test if all channels specified are in the mask */
457 int all_in_mask = 1;
458 for (ch = 0; ch < chan_count; ++ch) {
459 if (chans[ch] < 0 || chans[ch] >= im->channels) {
156699af 460 dIMCTXim(im);
836d9f54
TC
461 i_push_errorf(0, "No channel %d in this image", chans[ch]);
462 return -1;
463 }
464 if (!((1 << chans[ch]) & im->ch_mask))
465 all_in_mask = 0;
466 }
467 if (all_in_mask) {
468 for (i = 0; i < w; ++i) {
469 for (ch = 0; ch < chan_count; ++ch) {
470 ((double*)im->idata)[offset + chans[ch]] = Sample8ToF(*samps);
471 ++samps;
472 ++count;
473 }
474 offset += im->channels;
475 }
476 }
477 else {
478 for (i = 0; i < w; ++i) {
479 for (ch = 0; ch < chan_count; ++ch) {
480 if (im->ch_mask & (1 << (chans[ch])))
481 ((double*)im->idata)[offset + chans[ch]] = Sample8ToF(*samps);
482
483 ++samps;
484 ++count;
485 }
486 offset += im->channels;
487 }
488 }
489 }
490 else {
491 if (chan_count <= 0 || chan_count > im->channels) {
156699af
TC
492 dIMCTXim(im);
493 im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
836d9f54
TC
494 chan_count);
495 return -1;
496 }
497 for (i = 0; i < w; ++i) {
498 unsigned mask = 1;
499 for (ch = 0; ch < chan_count; ++ch) {
500 if (im->ch_mask & mask)
501 ((double*)im->idata)[offset + ch] = Sample8ToF(*samps);
502
503 ++samps;
504 ++count;
505 mask <<= 1;
506 }
507 offset += im->channels;
508 }
509 }
510
511 return count;
512 }
513 else {
156699af 514 dIMCTXim(im);
836d9f54
TC
515 i_push_error(0, "Image position outside of image");
516 return -1;
517 }
518}
519
520/*
521=item i_psampf_ddoub(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)
522
523Writes sample values to im for the horizontal line (l, y) to (r-1,y)
524for the channels specified by chans, an array of int with chan_count
525elements.
526
527Returns the number of samples written (which should be (r-l) *
528bits_set(chan_mask)
529
530=cut
531*/
532
533static
534i_img_dim
535i_psampf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
536 const i_fsample_t *samps, const int *chans, int chan_count) {
537 int ch;
538 i_img_dim count, i, w;
539
540 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
836d9f54
TC
541 i_img_dim offset;
542 if (r > im->xsize)
543 r = im->xsize;
544 offset = (l+y*im->xsize) * im->channels;
545 w = r - l;
546 count = 0;
547
548 if (chans) {
549 /* make sure we have good channel numbers */
550 /* and test if all channels specified are in the mask */
551 int all_in_mask = 1;
552 for (ch = 0; ch < chan_count; ++ch) {
553 if (chans[ch] < 0 || chans[ch] >= im->channels) {
156699af
TC
554 dIMCTXim(im);
555 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
836d9f54
TC
556 return -1;
557 }
558 if (!((1 << chans[ch]) & im->ch_mask))
559 all_in_mask = 0;
560 }
561 if (all_in_mask) {
562 for (i = 0; i < w; ++i) {
563 for (ch = 0; ch < chan_count; ++ch) {
564 ((double*)im->idata)[offset + chans[ch]] = *samps;
565 ++samps;
566 ++count;
567 }
568 offset += im->channels;
569 }
570 }
571 else {
572 for (i = 0; i < w; ++i) {
573 for (ch = 0; ch < chan_count; ++ch) {
574 if (im->ch_mask & (1 << (chans[ch])))
575 ((double*)im->idata)[offset + chans[ch]] = *samps;
576
577 ++samps;
578 ++count;
579 }
580 offset += im->channels;
581 }
582 }
583 }
584 else {
585 if (chan_count <= 0 || chan_count > im->channels) {
156699af
TC
586 dIMCTXim(im);
587 im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
836d9f54
TC
588 chan_count);
589 return -1;
590 }
591 for (i = 0; i < w; ++i) {
592 unsigned mask = 1;
593 for (ch = 0; ch < chan_count; ++ch) {
594 if (im->ch_mask & mask)
595 ((double*)im->idata)[offset + ch] = *samps;
596
597 ++samps;
598 ++count;
599 mask <<= 1;
600 }
601 offset += im->channels;
602 }
603 }
604
605 return count;
606 }
607 else {
156699af 608 dIMCTXim(im);
836d9f54
TC
609 i_push_error(0, "Image position outside of image");
610 return -1;
611 }
612}
613
bfe6ba3f
TC
614/*
615=item i_img_to_drgb(im)
616
617=category Image creation
618
619Returns a double/sample version of the supplied image.
620
621Returns the image on success, or NULL on failure.
622
623=cut
624*/
625
626i_img *
627i_img_to_drgb(i_img *im) {
628 i_img *targ;
629 i_fcolor *line;
8d14daab 630 i_img_dim y;
156699af 631 dIMCTXim(im);
bfe6ba3f 632
156699af 633 targ = im_img_double_new(aIMCTX, im->xsize, im->ysize, im->channels);
bfe6ba3f
TC
634 if (!targ)
635 return NULL;
636 line = mymalloc(sizeof(i_fcolor) * im->xsize);
637 for (y = 0; y < im->ysize; ++y) {
638 i_glinf(im, 0, im->xsize, y, line);
639 i_plinf(targ, 0, im->xsize, y, line);
640 }
641
642 myfree(line);
643
644 return targ;
645}
b8c2033e
AMH
646
647/*
648=back
649
650=head1 AUTHOR
651
652Tony Cook <tony@develop-help.com>
653
654=head1 SEE ALSO
655
656Imager(3)
657
658=cut
659*/