]> git.imager.perl.org - imager.git/blob - img8.c
update flip.im with IMAGER_NO_CONTEXT
[imager.git] / img8.c
1 #define IMAGER_NO_CONTEXT
2
3 #include "imager.h"
4 #include "imageri.h"
5
6 static int i_ppix_d(i_img *im, i_img_dim x, i_img_dim y, const i_color *val);
7 static int i_gpix_d(i_img *im, i_img_dim x, i_img_dim y, i_color *val);
8 static i_img_dim i_glin_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals);
9 static i_img_dim i_plin_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals);
10 static int i_ppixf_d(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val);
11 static int i_gpixf_d(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val);
12 static i_img_dim i_glinf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals);
13 static i_img_dim i_plinf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals);
14 static i_img_dim i_gsamp_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, const int *chans, int chan_count);
15 static i_img_dim i_gsampf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps, const int *chans, int chan_count);
16 static i_img_dim i_psamp_d(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);
17 static i_img_dim i_psampf_d(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);
18
19 /*
20 =item IIM_base_8bit_direct (static)
21
22 A static i_img object used to initialize direct 8-bit per sample images.
23
24 =cut
25 */
26 static i_img IIM_base_8bit_direct =
27 {
28   0, /* channels set */
29   0, 0, 0, /* xsize, ysize, bytes */
30   ~0U, /* ch_mask */
31   i_8_bits, /* bits */
32   i_direct_type, /* type */
33   0, /* virtual */
34   NULL, /* idata */
35   { 0, 0, NULL }, /* tags */
36   NULL, /* ext_data */
37
38   i_ppix_d, /* i_f_ppix */
39   i_ppixf_d, /* i_f_ppixf */
40   i_plin_d, /* i_f_plin */
41   i_plinf_d, /* i_f_plinf */
42   i_gpix_d, /* i_f_gpix */
43   i_gpixf_d, /* i_f_gpixf */
44   i_glin_d, /* i_f_glin */
45   i_glinf_d, /* i_f_glinf */
46   i_gsamp_d, /* i_f_gsamp */
47   i_gsampf_d, /* i_f_gsampf */
48
49   NULL, /* i_f_gpal */
50   NULL, /* i_f_ppal */
51   NULL, /* i_f_addcolors */
52   NULL, /* i_f_getcolors */
53   NULL, /* i_f_colorcount */
54   NULL, /* i_f_maxcolors */
55   NULL, /* i_f_findcolor */
56   NULL, /* i_f_setcolors */
57
58   NULL, /* i_f_destroy */
59
60   i_gsamp_bits_fb,
61   NULL, /* i_f_psamp_bits */
62
63   i_psamp_d,
64   i_psampf_d
65 };
66
67 /*static void set_8bit_direct(i_img *im) {
68   im->i_f_ppix = i_ppix_d;
69   im->i_f_ppixf = i_ppixf_d;
70   im->i_f_plin = i_plin_d;
71   im->i_f_plinf = i_plinf_d;
72   im->i_f_gpix = i_gpix_d;
73   im->i_f_gpixf = i_gpixf_d;
74   im->i_f_glin = i_glin_d;
75   im->i_f_glinf = i_glinf_d;
76   im->i_f_gpal = NULL;
77   im->i_f_ppal = NULL;
78   im->i_f_addcolor = NULL;
79   im->i_f_getcolor = NULL;
80   im->i_f_colorcount = NULL;
81   im->i_f_findcolor = NULL;
82   }*/
83
84 /*
85 =item i_img_8_new(x, y, ch)
86
87 =category Image creation/destruction
88
89 =synopsis i_img *img = i_img_8_new(width, height, channels);
90
91 Creates a new image object I<x> pixels wide, and I<y> pixels high with
92 I<ch> channels.
93
94 =cut
95 */
96
97
98 i_img *
99 im_img_8_new(pIMCTX, i_img_dim x,i_img_dim y,int ch) {
100   i_img *im;
101
102   mm_log((1,"IIM_new(x %" i_DF ", y %" i_DF ", ch %d)\n",
103           i_DFc(x), i_DFc(y), ch));
104
105   im = im_img_empty_ch(aIMCTX, NULL,x,y,ch);
106   
107   mm_log((1,"(%p) <- IIM_new\n",im));
108   return im;
109 }
110
111 #if 0
112 /* 
113 =item i_img_new()
114
115 Create new image reference - notice that this isn't an object yet and
116 this should be fixed asap.
117
118 =cut
119 */
120
121
122 i_img *
123 i_img_new() {
124   i_img *im;
125   
126   mm_log((1,"i_img_struct()\n"));
127
128   im = i_img_alloc();
129   
130   *im = IIM_base_8bit_direct;
131   im->xsize=0;
132   im->ysize=0;
133   im->channels=3;
134   im->ch_mask=MAXINT;
135   im->bytes=0;
136   im->idata=NULL;
137
138   i_img_init(im);
139   
140   mm_log((1,"(%p) <- i_img_struct\n",im));
141   return im;
142 }
143
144 #endif
145
146 /* 
147 =item i_img_empty(im, x, y)
148
149 Re-new image reference (assumes 3 channels)
150
151    im - Image pointer
152    x - xsize of destination image
153    y - ysize of destination image
154
155 **FIXME** what happens if a live image is passed in here?
156
157 Should this just call i_img_empty_ch()?
158
159 =cut
160 */
161
162 i_img *
163 im_img_empty(pIMCTX, i_img *im,i_img_dim x,i_img_dim y) {
164   mm_log((1,"i_img_empty(*im %p, x %" i_DF ", y %" i_DF ")\n",
165           im, i_DFc(x), i_DFc(y)));
166   return im_img_empty_ch(aIMCTX, im, x, y, 3);
167 }
168
169 /* 
170 =item i_img_empty_ch(im, x, y, ch)
171
172 Re-new image reference 
173
174    im - Image pointer
175    x  - xsize of destination image
176    y  - ysize of destination image
177    ch - number of channels
178
179 =cut
180 */
181
182 i_img *
183 im_img_empty_ch(pIMCTX, i_img *im,i_img_dim x,i_img_dim y,int ch) {
184   size_t bytes;
185
186   mm_log((1,"i_img_empty_ch(*im %p, x %" i_DF ", y %" i_DF ", ch %d)\n",
187           im, i_DFc(x), i_DFc(y), ch));
188
189   if (x < 1 || y < 1) {
190     im_push_error(aIMCTX, 0, "Image sizes must be positive");
191     return NULL;
192   }
193   if (ch < 1 || ch > MAXCHANNELS) {
194     im_push_errorf(aIMCTX, 0, "channels must be between 1 and %d", MAXCHANNELS);
195     return NULL;
196   }
197   /* check this multiplication doesn't overflow */
198   bytes = x*y*ch;
199   if (bytes / y / ch != x) {
200     im_push_errorf(aIMCTX, 0, "integer overflow calculating image allocation");
201     return NULL;
202   }
203
204   if (im == NULL)
205     im = im_img_alloc(aIMCTX);
206
207   memcpy(im, &IIM_base_8bit_direct, sizeof(i_img));
208   i_tags_new(&im->tags);
209   im->xsize    = x;
210   im->ysize    = y;
211   im->channels = ch;
212   im->ch_mask  = MAXINT;
213   im->bytes=bytes;
214   if ( (im->idata=mymalloc(im->bytes)) == NULL) 
215     i_fatal(2,"malloc() error\n"); 
216   memset(im->idata,0,(size_t)im->bytes);
217   
218   im->ext_data = NULL;
219
220   im_img_init(aIMCTX, im);
221   
222   mm_log((1,"(%p) <- i_img_empty_ch\n",im));
223   return im;
224 }
225
226 /*
227 =head2 8-bit per sample image internal functions
228
229 These are the functions installed in an 8-bit per sample image.
230
231 =over
232
233 =item i_ppix_d(im, x, y, col)
234
235 Internal function.
236
237 This is the function kept in the i_f_ppix member of an i_img object.
238 It does a normal store of a pixel into the image with range checking.
239
240 Returns 0 if the pixel could be set, -1 otherwise.
241
242 =cut
243 */
244 static
245 int
246 i_ppix_d(i_img *im, i_img_dim x, i_img_dim y, const i_color *val) {
247   int ch;
248   
249   if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
250     for(ch=0;ch<im->channels;ch++)
251       if (im->ch_mask&(1<<ch)) 
252         im->idata[(x+y*im->xsize)*im->channels+ch]=val->channel[ch];
253     return 0;
254   }
255   return -1; /* error was clipped */
256 }
257
258 /*
259 =item i_gpix_d(im, x, y, &col)
260
261 Internal function.
262
263 This is the function kept in the i_f_gpix member of an i_img object.
264 It does normal retrieval of a pixel from the image with range checking.
265
266 Returns 0 if the pixel could be set, -1 otherwise.
267
268 =cut
269 */
270 static
271 int 
272 i_gpix_d(i_img *im, i_img_dim x, i_img_dim y, i_color *val) {
273   int ch;
274   if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
275     for(ch=0;ch<im->channels;ch++) 
276       val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch];
277     return 0;
278   }
279   for(ch=0;ch<im->channels;ch++) val->channel[ch] = 0;
280   return -1; /* error was cliped */
281 }
282
283 /*
284 =item i_glin_d(im, l, r, y, vals)
285
286 Reads a line of data from the image, storing the pixels at vals.
287
288 The line runs from (l,y) inclusive to (r,y) non-inclusive
289
290 vals should point at space for (r-l) pixels.
291
292 l should never be less than zero (to avoid confusion about where to
293 put the pixels in vals).
294
295 Returns the number of pixels copied (eg. if r, l or y is out of range)
296
297 =cut
298 */
299 static
300 i_img_dim
301 i_glin_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals) {
302   int ch;
303   i_img_dim count, i;
304   unsigned char *data;
305   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
306     if (r > im->xsize)
307       r = im->xsize;
308     data = im->idata + (l+y*im->xsize) * im->channels;
309     count = r - l;
310     for (i = 0; i < count; ++i) {
311       for (ch = 0; ch < im->channels; ++ch)
312         vals[i].channel[ch] = *data++;
313     }
314     return count;
315   }
316   else {
317     return 0;
318   }
319 }
320
321 /*
322 =item i_plin_d(im, l, r, y, vals)
323
324 Writes a line of data into the image, using the pixels at vals.
325
326 The line runs from (l,y) inclusive to (r,y) non-inclusive
327
328 vals should point at (r-l) pixels.
329
330 l should never be less than zero (to avoid confusion about where to
331 get the pixels in vals).
332
333 Returns the number of pixels copied (eg. if r, l or y is out of range)
334
335 =cut
336 */
337 static
338 i_img_dim
339 i_plin_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals) {
340   int ch;
341   i_img_dim count, i;
342   unsigned char *data;
343   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
344     if (r > im->xsize)
345       r = im->xsize;
346     data = im->idata + (l+y*im->xsize) * im->channels;
347     count = r - l;
348     for (i = 0; i < count; ++i) {
349       for (ch = 0; ch < im->channels; ++ch) {
350         if (im->ch_mask & (1 << ch)) 
351           *data = vals[i].channel[ch];
352         ++data;
353       }
354     }
355     return count;
356   }
357   else {
358     return 0;
359   }
360 }
361
362 /*
363 =item i_ppixf_d(im, x, y, val)
364
365 =cut
366 */
367 static
368 int
369 i_ppixf_d(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val) {
370   int ch;
371   
372   if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
373     for(ch=0;ch<im->channels;ch++)
374       if (im->ch_mask&(1<<ch)) {
375         im->idata[(x+y*im->xsize)*im->channels+ch] = 
376           SampleFTo8(val->channel[ch]);
377       }
378     return 0;
379   }
380   return -1; /* error was clipped */
381 }
382
383 /*
384 =item i_gpixf_d(im, x, y, val)
385
386 =cut
387 */
388 static
389 int
390 i_gpixf_d(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val) {
391   int ch;
392   if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
393     for(ch=0;ch<im->channels;ch++) {
394       val->channel[ch] = 
395         Sample8ToF(im->idata[(x+y*im->xsize)*im->channels+ch]);
396     }
397     return 0;
398   }
399   return -1; /* error was cliped */
400 }
401
402 /*
403 =item i_glinf_d(im, l, r, y, vals)
404
405 Reads a line of data from the image, storing the pixels at vals.
406
407 The line runs from (l,y) inclusive to (r,y) non-inclusive
408
409 vals should point at space for (r-l) pixels.
410
411 l should never be less than zero (to avoid confusion about where to
412 put the pixels in vals).
413
414 Returns the number of pixels copied (eg. if r, l or y is out of range)
415
416 =cut
417 */
418 static
419 i_img_dim
420 i_glinf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals) {
421   int ch;
422   i_img_dim count, i;
423   unsigned char *data;
424   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
425     if (r > im->xsize)
426       r = im->xsize;
427     data = im->idata + (l+y*im->xsize) * im->channels;
428     count = r - l;
429     for (i = 0; i < count; ++i) {
430       for (ch = 0; ch < im->channels; ++ch)
431         vals[i].channel[ch] = Sample8ToF(*data++);
432     }
433     return count;
434   }
435   else {
436     return 0;
437   }
438 }
439
440 /*
441 =item i_plinf_d(im, l, r, y, vals)
442
443 Writes a line of data into the image, using the pixels at vals.
444
445 The line runs from (l,y) inclusive to (r,y) non-inclusive
446
447 vals should point at (r-l) pixels.
448
449 l should never be less than zero (to avoid confusion about where to
450 get the pixels in vals).
451
452 Returns the number of pixels copied (eg. if r, l or y is out of range)
453
454 =cut
455 */
456 static
457 i_img_dim
458 i_plinf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals) {
459   int ch;
460   i_img_dim count, i;
461   unsigned char *data;
462   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
463     if (r > im->xsize)
464       r = im->xsize;
465     data = im->idata + (l+y*im->xsize) * im->channels;
466     count = r - l;
467     for (i = 0; i < count; ++i) {
468       for (ch = 0; ch < im->channels; ++ch) {
469         if (im->ch_mask & (1 << ch)) 
470           *data = SampleFTo8(vals[i].channel[ch]);
471         ++data;
472       }
473     }
474     return count;
475   }
476   else {
477     return 0;
478   }
479 }
480
481 /*
482 =item i_gsamp_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, int *chans, int chan_count)
483
484 Reads sample values from im for the horizontal line (l, y) to (r-1,y)
485 for the channels specified by chans, an array of int with chan_count
486 elements.
487
488 Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
489
490 =cut
491 */
492 static
493 i_img_dim
494 i_gsamp_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, 
495               const int *chans, int chan_count) {
496   int ch;
497   i_img_dim count, i, w;
498   unsigned char *data;
499
500   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
501     if (r > im->xsize)
502       r = im->xsize;
503     data = im->idata + (l+y*im->xsize) * im->channels;
504     w = r - l;
505     count = 0;
506
507     if (chans) {
508       /* make sure we have good channel numbers */
509       for (ch = 0; ch < chan_count; ++ch) {
510         if (chans[ch] < 0 || chans[ch] >= im->channels) {
511           i_push_errorf(0, "No channel %d in this image", chans[ch]);
512           return 0;
513         }
514       }
515       for (i = 0; i < w; ++i) {
516         for (ch = 0; ch < chan_count; ++ch) {
517           *samps++ = data[chans[ch]];
518           ++count;
519         }
520         data += im->channels;
521       }
522     }
523     else {
524       if (chan_count <= 0 || chan_count > im->channels) {
525         i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
526                       chan_count);
527         return 0;
528       }
529       for (i = 0; i < w; ++i) {
530         for (ch = 0; ch < chan_count; ++ch) {
531           *samps++ = data[ch];
532           ++count;
533         }
534         data += im->channels;
535       }
536     }
537
538     return count;
539   }
540   else {
541     return 0;
542   }
543 }
544
545 /*
546 =item i_gsampf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps, int *chans, int chan_count)
547
548 Reads sample values from im for the horizontal line (l, y) to (r-1,y)
549 for the channels specified by chan_mask, where bit 0 is the first
550 channel.
551
552 Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
553
554 =cut
555 */
556 static
557 i_img_dim
558 i_gsampf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps, 
559            const int *chans, int chan_count) {
560   int ch;
561   i_img_dim count, i, w;
562   unsigned char *data;
563   for (ch = 0; ch < chan_count; ++ch) {
564     if (chans[ch] < 0 || chans[ch] >= im->channels) {
565       i_push_errorf(0, "No channel %d in this image", chans[ch]);
566     }
567   }
568   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
569     if (r > im->xsize)
570       r = im->xsize;
571     data = im->idata + (l+y*im->xsize) * im->channels;
572     w = r - l;
573     count = 0;
574
575     if (chans) {
576       /* make sure we have good channel numbers */
577       for (ch = 0; ch < chan_count; ++ch) {
578         if (chans[ch] < 0 || chans[ch] >= im->channels) {
579           i_push_errorf(0, "No channel %d in this image", chans[ch]);
580           return 0;
581         }
582       }
583       for (i = 0; i < w; ++i) {
584         for (ch = 0; ch < chan_count; ++ch) {
585           *samps++ = Sample8ToF(data[chans[ch]]);
586           ++count;
587         }
588         data += im->channels;
589       }
590     }
591     else {
592       if (chan_count <= 0 || chan_count > im->channels) {
593         i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
594                       chan_count);
595         return 0;
596       }
597       for (i = 0; i < w; ++i) {
598         for (ch = 0; ch < chan_count; ++ch) {
599           *samps++ = Sample8ToF(data[ch]);
600           ++count;
601         }
602         data += im->channels;
603       }
604     }
605     return count;
606   }
607   else {
608     return 0;
609   }
610 }
611
612 /*
613 =item i_psamp_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, int *chans, int chan_count)
614
615 Writes sample values to im for the horizontal line (l, y) to (r-1,y)
616 for the channels specified by chans, an array of int with chan_count
617 elements.
618
619 Returns the number of samples written (which should be (r-l) *
620 bits_set(chan_mask)
621
622 =cut
623 */
624
625 static
626 i_img_dim
627 i_psamp_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, 
628           const i_sample_t *samps, const int *chans, int chan_count) {
629   int ch;
630   i_img_dim count, i, w;
631   unsigned char *data;
632
633   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
634     if (r > im->xsize)
635       r = im->xsize;
636     data = im->idata + (l+y*im->xsize) * im->channels;
637     w = r - l;
638     count = 0;
639
640     if (chans) {
641       /* make sure we have good channel numbers */
642       /* and test if all channels specified are in the mask */
643       int all_in_mask = 1;
644       for (ch = 0; ch < chan_count; ++ch) {
645         if (chans[ch] < 0 || chans[ch] >= im->channels) {
646           i_push_errorf(0, "No channel %d in this image", chans[ch]);
647           return -1;
648         }
649         if (!((1 << chans[ch]) & im->ch_mask))
650           all_in_mask = 0;
651       }
652       if (all_in_mask) {
653         for (i = 0; i < w; ++i) {
654           for (ch = 0; ch < chan_count; ++ch) {
655             data[chans[ch]] = *samps++;
656             ++count;
657           }
658           data += im->channels;
659         }
660       }
661       else {
662         for (i = 0; i < w; ++i) {
663           for (ch = 0; ch < chan_count; ++ch) {
664             if (im->ch_mask & (1 << (chans[ch])))
665               data[chans[ch]] = *samps;
666             ++samps;
667             ++count;
668           }
669           data += im->channels;
670         }
671       }
672     }
673     else {
674       if (chan_count <= 0 || chan_count > im->channels) {
675         i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
676                       chan_count);
677         return -1;
678       }
679       for (i = 0; i < w; ++i) {
680         unsigned mask = 1;
681         for (ch = 0; ch < chan_count; ++ch) {
682           if (im->ch_mask & mask)
683             data[ch] = *samps;
684           ++samps;
685           ++count;
686           mask <<= 1;
687         }
688         data += im->channels;
689       }
690     }
691
692     return count;
693   }
694   else {
695     dIMCTXim(im);
696     i_push_error(0, "Image position outside of image");
697     return -1;
698   }
699 }
700
701 /*
702 =item i_psampf_d(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)
703
704 Writes sample values to im for the horizontal line (l, y) to (r-1,y)
705 for the channels specified by chans, an array of int with chan_count
706 elements.
707
708 Returns the number of samples written (which should be (r-l) *
709 bits_set(chan_mask)
710
711 =cut
712 */
713
714 static
715 i_img_dim
716 i_psampf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, 
717           const i_fsample_t *samps, const int *chans, int chan_count) {
718   int ch;
719   i_img_dim count, i, w;
720   unsigned char *data;
721
722   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
723     if (r > im->xsize)
724       r = im->xsize;
725     data = im->idata + (l+y*im->xsize) * im->channels;
726     w = r - l;
727     count = 0;
728
729     if (chans) {
730       /* make sure we have good channel numbers */
731       /* and test if all channels specified are in the mask */
732       int all_in_mask = 1;
733       for (ch = 0; ch < chan_count; ++ch) {
734         if (chans[ch] < 0 || chans[ch] >= im->channels) {
735           i_push_errorf(0, "No channel %d in this image", chans[ch]);
736           return -1;
737         }
738         if (!((1 << chans[ch]) & im->ch_mask))
739           all_in_mask = 0;
740       }
741       if (all_in_mask) {
742         for (i = 0; i < w; ++i) {
743           for (ch = 0; ch < chan_count; ++ch) {
744             data[chans[ch]] = SampleFTo8(*samps);
745             ++samps;
746             ++count;
747           }
748           data += im->channels;
749         }
750       }
751       else {
752         for (i = 0; i < w; ++i) {
753           for (ch = 0; ch < chan_count; ++ch) {
754             if (im->ch_mask & (1 << (chans[ch])))
755               data[chans[ch]] = SampleFTo8(*samps);
756             ++samps;
757             ++count;
758           }
759           data += im->channels;
760         }
761       }
762     }
763     else {
764       if (chan_count <= 0 || chan_count > im->channels) {
765         i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels", 
766                       chan_count);
767         return -1;
768       }
769       for (i = 0; i < w; ++i) {
770         unsigned mask = 1;
771         for (ch = 0; ch < chan_count; ++ch) {
772           if (im->ch_mask & mask)
773             data[ch] = SampleFTo8(*samps);
774           ++samps;
775           ++count;
776           mask <<= 1;
777         }
778         data += im->channels;
779       }
780     }
781
782     return count;
783   }
784   else {
785     dIMCTXim(im);
786     i_push_error(0, "Image position outside of image");
787     return -1;
788   }
789 }
790
791 /*
792 =back
793
794 =head1 AUTHOR
795
796 Arnar M. Hrafnkelsson <addi@umich.edu>
797
798 Tony Cook <tony@develop-help.com>
799
800 =head1 SEE ALSO
801
802 L<Imager>
803
804 =cut
805 */