]> git.imager.perl.org - imager.git/blob - imgdouble.c
pick up im_ prefix functions too
[imager.git] / imgdouble.c
1 /*
2 =head1 NAME
3
4 imgdouble.c - implements double per sample images
5
6 =head1 SYNOPSIS
7
8   i_img *im = i_img_double_new(width, height, channels);
9   # use like a normal image
10
11 =head1 DESCRIPTION
12
13 Implements double/sample images.
14
15 This basic implementation is required so that we have some larger 
16 sample image type to work with.
17
18 =over
19
20 =cut
21 */
22
23 #define IMAGER_NO_CONTEXT
24 #include "imager.h"
25 #include "imageri.h"
26
27 static int i_ppix_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_color *val);
28 static int i_gpix_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_color *val);
29 static i_img_dim i_glin_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals);
30 static 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);
31 static int i_ppixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val);
32 static int i_gpixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val);
33 static i_img_dim i_glinf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals);
34 static 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);
35 static 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, 
36                        int const *chans, int chan_count);
37 static 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, 
38                         int const *chans, int chan_count);
39 static i_img_dim 
40 i_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);
41 static i_img_dim 
42 i_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);
43
44 /*
45 =item IIM_base_16bit_direct
46
47 Base structure used to initialize a 16-bit/sample image.
48
49 Internal.
50
51 =cut
52 */
53 static i_img IIM_base_double_direct =
54 {
55   0, /* channels set */
56   0, 0, 0, /* xsize, ysize, bytes */
57   ~0U, /* ch_mask */
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 */
78   NULL, /* i_f_addcolors */
79   NULL, /* i_f_getcolors */
80   NULL, /* i_f_colorcount */
81   NULL, /* i_f_maxcolors */
82   NULL, /* i_f_findcolor */
83   NULL, /* i_f_setcolors */
84
85   NULL, /* i_f_destroy */
86
87   i_gsamp_bits_fb,
88   NULL, /* i_f_psamp_bits */
89
90   i_psamp_ddoub, /* i_f_psamp */
91   i_psampf_ddoub /* i_f_psampf */
92 };
93
94 /*
95 =item i_img_double_new(i_img_dim x, i_img_dim y, int ch)
96 =category Image creation/destruction
97 =synopsis i_img *img = i_img_double_new(width, height, channels);
98
99 Creates a new double per sample image.
100
101 =cut
102 */
103 i_img *
104 im_img_double_new(pIMCTX, i_img_dim x, i_img_dim y, int ch) {
105   size_t bytes;
106   i_img *im;
107
108   im_log((aIMCTX, 1,"i_img_double_new(x %" i_DF ", y %" i_DF ", ch %d)\n",
109           i_DFc(x), i_DFc(y), ch));
110
111   if (x < 1 || y < 1) {
112     im_push_error(aIMCTX, 0, "Image sizes must be positive");
113     return NULL;
114   }
115   if (ch < 1 || ch > MAXCHANNELS) {
116     im_push_errorf(aIMCTX, 0, "channels must be between 1 and %d", MAXCHANNELS);
117     return NULL;
118   }
119   bytes = x * y * ch * sizeof(double);
120   if (bytes / y / ch / sizeof(double) != x) {
121     im_push_errorf(aIMCTX, 0, "integer overflow calculating image allocation");
122     return NULL;
123   }
124   
125   im = im_img_alloc(aIMCTX);
126   *im = IIM_base_double_direct;
127   i_tags_new(&im->tags);
128   im->xsize = x;
129   im->ysize = y;
130   im->channels = ch;
131   im->bytes = bytes;
132   im->ext_data = NULL;
133   im->idata = mymalloc(im->bytes);
134   memset(im->idata, 0, im->bytes);
135   im_img_init(aIMCTX, im);
136   
137   return im;
138 }
139
140 static 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;
143
144   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
145     return -1;
146
147   off = (x + y * im->xsize) * im->channels;
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   }
157
158   return 0;
159 }
160
161 static 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;
164
165   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
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
175 static 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;
178
179   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
180     return -1;
181
182   off = (x + y * im->xsize) * im->channels;
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   }
192
193   return 0;
194 }
195
196 static 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;
199
200   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
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
210 static 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;
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
232 static 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;
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;
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         }
256       }
257     }
258     return count;
259   }
260   else {
261     return 0;
262   }
263 }
264
265 static 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;
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
287 static 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;
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;
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         }
311       }
312     }
313     return count;
314   }
315   else {
316     return 0;
317   }
318 }
319
320 static 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, 
321                        int const *chans, int chan_count) {
322   int ch;
323   i_img_dim count, i, w;
324   i_img_dim off;
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) {
337           dIMCTXim(im);
338           im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
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 {
351       if (chan_count <= 0 || chan_count > im->channels) {
352         dIMCTXim(im);
353         im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", 
354                       chan_count);
355         return 0;
356       }
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
373 static 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, 
374                         int const *chans, int chan_count) {
375   int ch;
376   i_img_dim count, i, w;
377   i_img_dim off;
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) {
390           dIMCTXim(im);
391           im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
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 {
404       if (chan_count <= 0 || chan_count > im->channels) {
405         dIMCTXim(im);
406         im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", 
407                       chan_count);
408         return 0;
409       }
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
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
429 Writes sample values to im for the horizontal line (l, y) to (r-1,y)
430 for the channels specified by chans, an array of int with chan_count
431 elements.
432
433 Returns the number of samples written (which should be (r-l) *
434 bits_set(chan_mask)
435
436 =cut
437 */
438
439 static
440 i_img_dim
441 i_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) {
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) {
460           dIMCTXim(im);
461           im_push_errorf(aIMCTX, 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) {
492         dIMCTXim(im);
493         im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", 
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 {
514     dIMCTXim(im);
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
523 Writes sample values to im for the horizontal line (l, y) to (r-1,y)
524 for the channels specified by chans, an array of int with chan_count
525 elements.
526
527 Returns the number of samples written (which should be (r-l) *
528 bits_set(chan_mask)
529
530 =cut
531 */
532
533 static
534 i_img_dim
535 i_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) {
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) {
554           dIMCTXim(im);
555           im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
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) {
586         dIMCTXim(im);
587         im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", 
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 {
608     dIMCTXim(im);
609     i_push_error(0, "Image position outside of image");
610     return -1;
611   }
612 }
613
614 /*
615 =item i_img_to_drgb(im)
616
617 =category Image creation
618
619 Returns a double/sample version of the supplied image.
620
621 Returns the image on success, or NULL on failure.
622
623 =cut
624 */
625
626 i_img *
627 i_img_to_drgb(i_img *im) {
628   i_img *targ;
629   i_fcolor *line;
630   i_img_dim y;
631   dIMCTXim(im);
632
633   targ = im_img_double_new(aIMCTX, im->xsize, im->ysize, im->channels);
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 }
646
647 /*
648 =back
649
650 =head1 AUTHOR
651
652 Tony Cook <tony@develop-help.com>
653
654 =head1 SEE ALSO
655
656 Imager(3)
657
658 =cut
659 */