]> git.imager.perl.org - imager.git/blob - imgdouble.c
0.87 release
[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
39 /*
40 =item IIM_base_16bit_direct
41
42 Base structure used to initialize a 16-bit/sample image.
43
44 Internal.
45
46 =cut
47 */
48 static i_img IIM_base_double_direct =
49 {
50   0, /* channels set */
51   0, 0, 0, /* xsize, ysize, bytes */
52   ~0U, /* ch_mask */
53   i_double_bits, /* bits */
54   i_direct_type, /* type */
55   0, /* virtual */
56   NULL, /* idata */
57   { 0, 0, NULL }, /* tags */
58   NULL, /* ext_data */
59
60   i_ppix_ddoub, /* i_f_ppix */
61   i_ppixf_ddoub, /* i_f_ppixf */
62   i_plin_ddoub, /* i_f_plin */
63   i_plinf_ddoub, /* i_f_plinf */
64   i_gpix_ddoub, /* i_f_gpix */
65   i_gpixf_ddoub, /* i_f_gpixf */
66   i_glin_ddoub, /* i_f_glin */
67   i_glinf_ddoub, /* i_f_glinf */
68   i_gsamp_ddoub, /* i_f_gsamp */
69   i_gsampf_ddoub, /* i_f_gsampf */
70
71   NULL, /* i_f_gpal */
72   NULL, /* i_f_ppal */
73   NULL, /* i_f_addcolors */
74   NULL, /* i_f_getcolors */
75   NULL, /* i_f_colorcount */
76   NULL, /* i_f_maxcolors */
77   NULL, /* i_f_findcolor */
78   NULL, /* i_f_setcolors */
79
80   NULL, /* i_f_destroy */
81
82   i_gsamp_bits_fb,
83   NULL, /* i_f_psamp_bits */
84 };
85
86 /*
87 =item i_img_double_new(i_img_dim x, i_img_dim y, int ch)
88 =category Image creation/destruction
89 =synopsis i_img *img = i_img_double_new(width, height, channels);
90
91 Creates a new double per sample image.
92
93 =cut
94 */
95 i_img *i_img_double_new(i_img_dim x, i_img_dim y, int ch) {
96   size_t bytes;
97   i_img *im;
98
99   mm_log((1,"i_img_double_new(x %" i_DF ", y %" i_DF ", ch %d)\n",
100           i_DFc(x), i_DFc(y), ch));
101
102   if (x < 1 || y < 1) {
103     i_push_error(0, "Image sizes must be positive");
104     return NULL;
105   }
106   if (ch < 1 || ch > MAXCHANNELS) {
107     i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
108     return NULL;
109   }
110   bytes = x * y * ch * sizeof(double);
111   if (bytes / y / ch / sizeof(double) != x) {
112     i_push_errorf(0, "integer overflow calculating image allocation");
113     return NULL;
114   }
115   
116   im = i_img_alloc();
117   *im = IIM_base_double_direct;
118   i_tags_new(&im->tags);
119   im->xsize = x;
120   im->ysize = y;
121   im->channels = ch;
122   im->bytes = bytes;
123   im->ext_data = NULL;
124   im->idata = mymalloc(im->bytes);
125   memset(im->idata, 0, im->bytes);
126   i_img_init(im);
127   
128   return im;
129 }
130
131 static int i_ppix_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_color *val) {
132   i_img_dim off;
133   int ch;
134
135   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
136     return -1;
137
138   off = (x + y * im->xsize) * im->channels;
139   if (I_ALL_CHANNELS_WRITABLE(im)) {
140     for (ch = 0; ch < im->channels; ++ch)
141       ((double*)im->idata)[off+ch] = Sample8ToF(val->channel[ch]);
142   }
143   else {
144     for (ch = 0; ch < im->channels; ++ch)
145       if (im->ch_mask & (1<<ch))
146         ((double*)im->idata)[off+ch] = Sample8ToF(val->channel[ch]);
147   }
148
149   return 0;
150 }
151
152 static int i_gpix_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_color *val) {
153   i_img_dim off;
154   int ch;
155
156   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
157     return -1;
158
159   off = (x + y * im->xsize) * im->channels;
160   for (ch = 0; ch < im->channels; ++ch)
161     val->channel[ch] = SampleFTo8(((double *)im->idata)[off+ch]);
162
163   return 0;
164 }
165
166 static int i_ppixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val) {
167   i_img_dim off;
168   int ch;
169
170   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
171     return -1;
172
173   off = (x + y * im->xsize) * im->channels;
174   if (I_ALL_CHANNELS_WRITABLE(im)) {
175     for (ch = 0; ch < im->channels; ++ch)
176       ((double *)im->idata)[off+ch] = val->channel[ch];
177   }
178   else {
179     for (ch = 0; ch < im->channels; ++ch)
180       if (im->ch_mask & (1 << ch))
181         ((double *)im->idata)[off+ch] = val->channel[ch];
182   }
183
184   return 0;
185 }
186
187 static int i_gpixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val) {
188   i_img_dim off;
189   int ch;
190
191   if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) 
192     return -1;
193
194   off = (x + y * im->xsize) * im->channels;
195   for (ch = 0; ch < im->channels; ++ch)
196     val->channel[ch] = ((double *)im->idata)[off+ch];
197
198   return 0;
199 }
200
201 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) {
202   int ch;
203   i_img_dim count, i;
204   i_img_dim off;
205   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
206     if (r > im->xsize)
207       r = im->xsize;
208     off = (l+y*im->xsize) * im->channels;
209     count = r - l;
210     for (i = 0; i < count; ++i) {
211       for (ch = 0; ch < im->channels; ++ch) {
212         vals[i].channel[ch] = SampleFTo8(((double *)im->idata)[off]);
213         ++off;
214       }
215     }
216     return count;
217   }
218   else {
219     return 0;
220   }
221 }
222
223 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) {
224   int ch;
225   i_img_dim count, i;
226   i_img_dim off;
227   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
228     if (r > im->xsize)
229       r = im->xsize;
230     off = (l+y*im->xsize) * im->channels;
231     count = r - l;
232     if (I_ALL_CHANNELS_WRITABLE(im)) {
233       for (i = 0; i < count; ++i) {
234         for (ch = 0; ch < im->channels; ++ch) {
235           ((double *)im->idata)[off] = Sample8ToF(vals[i].channel[ch]);
236           ++off;
237         }
238       }
239     }
240     else {
241       for (i = 0; i < count; ++i) {
242         for (ch = 0; ch < im->channels; ++ch) {
243           if (im->ch_mask & (1 << ch))
244             ((double *)im->idata)[off] = Sample8ToF(vals[i].channel[ch]);
245           ++off;
246         }
247       }
248     }
249     return count;
250   }
251   else {
252     return 0;
253   }
254 }
255
256 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) {
257   int ch;
258   i_img_dim count, i;
259   i_img_dim off;
260   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
261     if (r > im->xsize)
262       r = im->xsize;
263     off = (l+y*im->xsize) * im->channels;
264     count = r - l;
265     for (i = 0; i < count; ++i) {
266       for (ch = 0; ch < im->channels; ++ch) {
267         vals[i].channel[ch] = ((double *)im->idata)[off];
268         ++off;
269       }
270     }
271     return count;
272   }
273   else {
274     return 0;
275   }
276 }
277
278 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) {
279   int ch;
280   i_img_dim count, i;
281   i_img_dim off;
282   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
283     if (r > im->xsize)
284       r = im->xsize;
285     off = (l+y*im->xsize) * im->channels;
286     count = r - l;
287     if (I_ALL_CHANNELS_WRITABLE(im)) {
288       for (i = 0; i < count; ++i) {
289         for (ch = 0; ch < im->channels; ++ch) {
290           ((double *)im->idata)[off] = vals[i].channel[ch];
291           ++off;
292         }
293       }
294     }
295     else {
296       for (i = 0; i < count; ++i) {
297         for (ch = 0; ch < im->channels; ++ch) {
298           if (im->ch_mask & (1 << ch))
299             ((double *)im->idata)[off] = vals[i].channel[ch];
300           ++off;
301         }
302       }
303     }
304     return count;
305   }
306   else {
307     return 0;
308   }
309 }
310
311 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, 
312                        int const *chans, int chan_count) {
313   int ch;
314   i_img_dim count, i, w;
315   i_img_dim off;
316
317   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
318     if (r > im->xsize)
319       r = im->xsize;
320     off = (l+y*im->xsize) * im->channels;
321     w = r - l;
322     count = 0;
323
324     if (chans) {
325       /* make sure we have good channel numbers */
326       for (ch = 0; ch < chan_count; ++ch) {
327         if (chans[ch] < 0 || chans[ch] >= im->channels) {
328           i_push_errorf(0, "No channel %d in this image", chans[ch]);
329           return 0;
330         }
331       }
332       for (i = 0; i < w; ++i) {
333         for (ch = 0; ch < chan_count; ++ch) {
334           *samps++ = SampleFTo8(((double *)im->idata)[off+chans[ch]]);
335           ++count;
336         }
337         off += im->channels;
338       }
339     }
340     else {
341       if (chan_count <= 0 || chan_count > im->channels) {
342         i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
343                       chan_count);
344         return 0;
345       }
346       for (i = 0; i < w; ++i) {
347         for (ch = 0; ch < chan_count; ++ch) {
348           *samps++ = SampleFTo8(((double *)im->idata)[off+ch]);
349           ++count;
350         }
351         off += im->channels;
352       }
353     }
354
355     return count;
356   }
357   else {
358     return 0;
359   }
360 }
361
362 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, 
363                         int const *chans, int chan_count) {
364   int ch;
365   i_img_dim count, i, w;
366   i_img_dim off;
367
368   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
369     if (r > im->xsize)
370       r = im->xsize;
371     off = (l+y*im->xsize) * im->channels;
372     w = r - l;
373     count = 0;
374
375     if (chans) {
376       /* make sure we have good channel numbers */
377       for (ch = 0; ch < chan_count; ++ch) {
378         if (chans[ch] < 0 || chans[ch] >= im->channels) {
379           i_push_errorf(0, "No channel %d in this image", chans[ch]);
380           return 0;
381         }
382       }
383       for (i = 0; i < w; ++i) {
384         for (ch = 0; ch < chan_count; ++ch) {
385           *samps++ = ((double *)im->idata)[off+chans[ch]];
386           ++count;
387         }
388         off += im->channels;
389       }
390     }
391     else {
392       if (chan_count <= 0 || chan_count > im->channels) {
393         i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
394                       chan_count);
395         return 0;
396       }
397       for (i = 0; i < w; ++i) {
398         for (ch = 0; ch < chan_count; ++ch) {
399           *samps++ = ((double *)im->idata)[off+ch];
400           ++count;
401         }
402         off += im->channels;
403       }
404     }
405
406     return count;
407   }
408   else {
409     return 0;
410   }
411 }
412
413 /*
414 =item i_img_to_drgb(im)
415
416 =category Image creation
417
418 Returns a double/sample version of the supplied image.
419
420 Returns the image on success, or NULL on failure.
421
422 =cut
423 */
424
425 i_img *
426 i_img_to_drgb(i_img *im) {
427   i_img *targ;
428   i_fcolor *line;
429   i_img_dim y;
430
431   targ = i_img_double_new(im->xsize, im->ysize, im->channels);
432   if (!targ)
433     return NULL;
434   line = mymalloc(sizeof(i_fcolor) * im->xsize);
435   for (y = 0; y < im->ysize; ++y) {
436     i_glinf(im, 0, im->xsize, y, line);
437     i_plinf(targ, 0, im->xsize, y, line);
438   }
439
440   myfree(line);
441
442   return targ;
443 }
444
445 /*
446 =back
447
448 =head1 AUTHOR
449
450 Tony Cook <tony@develop-help.com>
451
452 =head1 SEE ALSO
453
454 Imager(3)
455
456 =cut
457 */