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