]> git.imager.perl.org - imager.git/blob - imgdouble.c
[rt #70388] debug mymalloc() no longer builds a string, just stores the pointer
[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 #include "imager.h"
24 #include "imageri.h"
25
26 static int i_ppix_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_color *val);
27 static int i_gpix_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_color *val);
28 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);
29 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);
30 static int i_ppixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val);
31 static int i_gpixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val);
32 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);
33 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);
34 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, 
35                        int const *chans, int chan_count);
36 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, 
37                         int const *chans, int chan_count);
38 static i_img_dim 
39 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);
40 static i_img_dim 
41 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);
42
43 /*
44 =item IIM_base_16bit_direct
45
46 Base structure used to initialize a 16-bit/sample image.
47
48 Internal.
49
50 =cut
51 */
52 static i_img IIM_base_double_direct =
53 {
54   0, /* channels set */
55   0, 0, 0, /* xsize, ysize, bytes */
56   ~0U, /* ch_mask */
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 */
77   NULL, /* i_f_addcolors */
78   NULL, /* i_f_getcolors */
79   NULL, /* i_f_colorcount */
80   NULL, /* i_f_maxcolors */
81   NULL, /* i_f_findcolor */
82   NULL, /* i_f_setcolors */
83
84   NULL, /* i_f_destroy */
85
86   i_gsamp_bits_fb,
87   NULL, /* i_f_psamp_bits */
88
89   i_psamp_ddoub, /* i_f_psamp */
90   i_psampf_ddoub /* i_f_psampf */
91 };
92
93 /*
94 =item i_img_double_new(i_img_dim x, i_img_dim y, int ch)
95 =category Image creation/destruction
96 =synopsis i_img *img = i_img_double_new(width, height, channels);
97
98 Creates a new double per sample image.
99
100 =cut
101 */
102 i_img *i_img_double_new(i_img_dim x, i_img_dim y, int ch) {
103   size_t bytes;
104   i_img *im;
105
106   mm_log((1,"i_img_double_new(x %" i_DF ", y %" i_DF ", ch %d)\n",
107           i_DFc(x), i_DFc(y), ch));
108
109   if (x < 1 || y < 1) {
110     i_push_error(0, "Image sizes must be positive");
111     return NULL;
112   }
113   if (ch < 1 || ch > MAXCHANNELS) {
114     i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
115     return NULL;
116   }
117   bytes = x * y * ch * sizeof(double);
118   if (bytes / y / ch / sizeof(double) != x) {
119     i_push_errorf(0, "integer overflow calculating image allocation");
120     return NULL;
121   }
122   
123   im = i_img_alloc();
124   *im = IIM_base_double_direct;
125   i_tags_new(&im->tags);
126   im->xsize = x;
127   im->ysize = y;
128   im->channels = ch;
129   im->bytes = bytes;
130   im->ext_data = NULL;
131   im->idata = mymalloc(im->bytes);
132   memset(im->idata, 0, im->bytes);
133   i_img_init(im);
134   
135   return im;
136 }
137
138 static 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;
141
142   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
143     return -1;
144
145   off = (x + y * im->xsize) * im->channels;
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   }
155
156   return 0;
157 }
158
159 static 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;
162
163   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
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
173 static 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;
176
177   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
178     return -1;
179
180   off = (x + y * im->xsize) * im->channels;
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   }
190
191   return 0;
192 }
193
194 static 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;
197
198   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
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
208 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) {
209   int ch;
210   i_img_dim count, i;
211   i_img_dim off;
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
230 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) {
231   int ch;
232   i_img_dim count, i;
233   i_img_dim off;
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;
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         }
254       }
255     }
256     return count;
257   }
258   else {
259     return 0;
260   }
261 }
262
263 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) {
264   int ch;
265   i_img_dim count, i;
266   i_img_dim off;
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
285 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) {
286   int ch;
287   i_img_dim count, i;
288   i_img_dim off;
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;
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         }
309       }
310     }
311     return count;
312   }
313   else {
314     return 0;
315   }
316 }
317
318 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, 
319                        int const *chans, int chan_count) {
320   int ch;
321   i_img_dim count, i, w;
322   i_img_dim off;
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) {
335           i_push_errorf(0, "No channel %d in this image", chans[ch]);
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 {
348       if (chan_count <= 0 || chan_count > im->channels) {
349         i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
350                       chan_count);
351         return 0;
352       }
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
369 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, 
370                         int const *chans, int chan_count) {
371   int ch;
372   i_img_dim count, i, w;
373   i_img_dim off;
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) {
386           i_push_errorf(0, "No channel %d in this image", chans[ch]);
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 {
399       if (chan_count <= 0 || chan_count > im->channels) {
400         i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
401                       chan_count);
402         return 0;
403       }
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
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
423 Writes sample values to im for the horizontal line (l, y) to (r-1,y)
424 for the channels specified by chans, an array of int with chan_count
425 elements.
426
427 Returns the number of samples written (which should be (r-l) *
428 bits_set(chan_mask)
429
430 =cut
431 */
432
433 static
434 i_img_dim
435 i_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) {
441     int all_unmasked;
442     i_img_dim offset;
443     if (r > im->xsize)
444       r = im->xsize;
445     offset = (l+y*im->xsize) * im->channels;
446     w = r - l;
447     count = 0;
448
449     if (chans) {
450       /* make sure we have good channel numbers */
451       /* and test if all channels specified are in the mask */
452       int all_in_mask = 1;
453       for (ch = 0; ch < chan_count; ++ch) {
454         if (chans[ch] < 0 || chans[ch] >= im->channels) {
455           i_push_errorf(0, "No channel %d in this image", chans[ch]);
456           return -1;
457         }
458         if (!((1 << chans[ch]) & im->ch_mask))
459           all_in_mask = 0;
460       }
461       if (all_in_mask) {
462         for (i = 0; i < w; ++i) {
463           for (ch = 0; ch < chan_count; ++ch) {
464             ((double*)im->idata)[offset + chans[ch]] = Sample8ToF(*samps);
465             ++samps;
466             ++count;
467           }
468           offset += im->channels;
469         }
470       }
471       else {
472         for (i = 0; i < w; ++i) {
473           for (ch = 0; ch < chan_count; ++ch) {
474             if (im->ch_mask & (1 << (chans[ch])))
475               ((double*)im->idata)[offset + chans[ch]] = Sample8ToF(*samps);
476             
477             ++samps;
478             ++count;
479           }
480           offset += im->channels;
481         }
482       }
483     }
484     else {
485       if (chan_count <= 0 || chan_count > im->channels) {
486         i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
487                       chan_count);
488         return -1;
489       }
490       for (i = 0; i < w; ++i) {
491         unsigned mask = 1;
492         for (ch = 0; ch < chan_count; ++ch) {
493           if (im->ch_mask & mask)
494             ((double*)im->idata)[offset + ch] = Sample8ToF(*samps);
495
496           ++samps;
497           ++count;
498           mask <<= 1;
499         }
500         offset += im->channels;
501       }
502     }
503
504     return count;
505   }
506   else {
507     i_push_error(0, "Image position outside of image");
508     return -1;
509   }
510 }
511
512 /*
513 =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)
514
515 Writes sample values to im for the horizontal line (l, y) to (r-1,y)
516 for the channels specified by chans, an array of int with chan_count
517 elements.
518
519 Returns the number of samples written (which should be (r-l) *
520 bits_set(chan_mask)
521
522 =cut
523 */
524
525 static
526 i_img_dim
527 i_psampf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, 
528                const i_fsample_t *samps, const int *chans, int chan_count) {
529   int ch;
530   i_img_dim count, i, w;
531
532   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
533     int all_unmasked;
534     i_img_dim offset;
535     if (r > im->xsize)
536       r = im->xsize;
537     offset = (l+y*im->xsize) * im->channels;
538     w = r - l;
539     count = 0;
540
541     if (chans) {
542       /* make sure we have good channel numbers */
543       /* and test if all channels specified are in the mask */
544       int all_in_mask = 1;
545       for (ch = 0; ch < chan_count; ++ch) {
546         if (chans[ch] < 0 || chans[ch] >= im->channels) {
547           i_push_errorf(0, "No channel %d in this image", chans[ch]);
548           return -1;
549         }
550         if (!((1 << chans[ch]) & im->ch_mask))
551           all_in_mask = 0;
552       }
553       if (all_in_mask) {
554         for (i = 0; i < w; ++i) {
555           for (ch = 0; ch < chan_count; ++ch) {
556             ((double*)im->idata)[offset + chans[ch]] = *samps;
557             ++samps;
558             ++count;
559           }
560           offset += im->channels;
561         }
562       }
563       else {
564         for (i = 0; i < w; ++i) {
565           for (ch = 0; ch < chan_count; ++ch) {
566             if (im->ch_mask & (1 << (chans[ch])))
567               ((double*)im->idata)[offset + chans[ch]] = *samps;
568             
569             ++samps;
570             ++count;
571           }
572           offset += im->channels;
573         }
574       }
575     }
576     else {
577       if (chan_count <= 0 || chan_count > im->channels) {
578         i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
579                       chan_count);
580         return -1;
581       }
582       for (i = 0; i < w; ++i) {
583         unsigned mask = 1;
584         for (ch = 0; ch < chan_count; ++ch) {
585           if (im->ch_mask & mask)
586             ((double*)im->idata)[offset + ch] = *samps;
587
588           ++samps;
589           ++count;
590           mask <<= 1;
591         }
592         offset += im->channels;
593       }
594     }
595
596     return count;
597   }
598   else {
599     i_push_error(0, "Image position outside of image");
600     return -1;
601   }
602 }
603
604 /*
605 =item i_img_to_drgb(im)
606
607 =category Image creation
608
609 Returns a double/sample version of the supplied image.
610
611 Returns the image on success, or NULL on failure.
612
613 =cut
614 */
615
616 i_img *
617 i_img_to_drgb(i_img *im) {
618   i_img *targ;
619   i_fcolor *line;
620   i_img_dim y;
621
622   targ = i_img_double_new(im->xsize, im->ysize, im->channels);
623   if (!targ)
624     return NULL;
625   line = mymalloc(sizeof(i_fcolor) * im->xsize);
626   for (y = 0; y < im->ysize; ++y) {
627     i_glinf(im, 0, im->xsize, y, line);
628     i_plinf(targ, 0, im->xsize, y, line);
629   }
630
631   myfree(line);
632
633   return targ;
634 }
635
636 /*
637 =back
638
639 =head1 AUTHOR
640
641 Tony Cook <tony@develop-help.com>
642
643 =head1 SEE ALSO
644
645 Imager(3)
646
647 =cut
648 */