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