]> git.imager.perl.org - imager.git/blob - img8.c
don't define mm_log() 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   im_log((aIMCTX, 1,"im_img_8_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   im_log((aIMCTX, 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   im_log((aIMCTX, 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   im_log((aIMCTX, 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   im_log((aIMCTX, 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           dIMCTXim(im);
512           im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
513           return 0;
514         }
515       }
516       for (i = 0; i < w; ++i) {
517         for (ch = 0; ch < chan_count; ++ch) {
518           *samps++ = data[chans[ch]];
519           ++count;
520         }
521         data += im->channels;
522       }
523     }
524     else {
525       if (chan_count <= 0 || chan_count > im->channels) {
526         dIMCTXim(im);
527         im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", 
528                       chan_count);
529         return 0;
530       }
531       for (i = 0; i < w; ++i) {
532         for (ch = 0; ch < chan_count; ++ch) {
533           *samps++ = data[ch];
534           ++count;
535         }
536         data += im->channels;
537       }
538     }
539
540     return count;
541   }
542   else {
543     return 0;
544   }
545 }
546
547 /*
548 =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)
549
550 Reads sample values from im for the horizontal line (l, y) to (r-1,y)
551 for the channels specified by chan_mask, where bit 0 is the first
552 channel.
553
554 Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
555
556 =cut
557 */
558 static
559 i_img_dim
560 i_gsampf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps, 
561            const int *chans, int chan_count) {
562   int ch;
563   i_img_dim count, i, w;
564   unsigned char *data;
565   for (ch = 0; ch < chan_count; ++ch) {
566     if (chans[ch] < 0 || chans[ch] >= im->channels) {
567       dIMCTXim(im);
568       im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
569     }
570   }
571   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
572     if (r > im->xsize)
573       r = im->xsize;
574     data = im->idata + (l+y*im->xsize) * im->channels;
575     w = r - l;
576     count = 0;
577
578     if (chans) {
579       /* make sure we have good channel numbers */
580       for (ch = 0; ch < chan_count; ++ch) {
581         if (chans[ch] < 0 || chans[ch] >= im->channels) {
582           dIMCTXim(im);
583           im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
584           return 0;
585         }
586       }
587       for (i = 0; i < w; ++i) {
588         for (ch = 0; ch < chan_count; ++ch) {
589           *samps++ = Sample8ToF(data[chans[ch]]);
590           ++count;
591         }
592         data += im->channels;
593       }
594     }
595     else {
596       if (chan_count <= 0 || chan_count > im->channels) {
597         dIMCTXim(im);
598         im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", 
599                       chan_count);
600         return 0;
601       }
602       for (i = 0; i < w; ++i) {
603         for (ch = 0; ch < chan_count; ++ch) {
604           *samps++ = Sample8ToF(data[ch]);
605           ++count;
606         }
607         data += im->channels;
608       }
609     }
610     return count;
611   }
612   else {
613     return 0;
614   }
615 }
616
617 /*
618 =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)
619
620 Writes sample values to im for the horizontal line (l, y) to (r-1,y)
621 for the channels specified by chans, an array of int with chan_count
622 elements.
623
624 Returns the number of samples written (which should be (r-l) *
625 bits_set(chan_mask)
626
627 =cut
628 */
629
630 static
631 i_img_dim
632 i_psamp_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, 
633           const i_sample_t *samps, const int *chans, int chan_count) {
634   int ch;
635   i_img_dim count, i, w;
636   unsigned char *data;
637
638   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
639     if (r > im->xsize)
640       r = im->xsize;
641     data = im->idata + (l+y*im->xsize) * im->channels;
642     w = r - l;
643     count = 0;
644
645     if (chans) {
646       /* make sure we have good channel numbers */
647       /* and test if all channels specified are in the mask */
648       int all_in_mask = 1;
649       for (ch = 0; ch < chan_count; ++ch) {
650         if (chans[ch] < 0 || chans[ch] >= im->channels) {
651           dIMCTXim(im);
652           im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
653           return -1;
654         }
655         if (!((1 << chans[ch]) & im->ch_mask))
656           all_in_mask = 0;
657       }
658       if (all_in_mask) {
659         for (i = 0; i < w; ++i) {
660           for (ch = 0; ch < chan_count; ++ch) {
661             data[chans[ch]] = *samps++;
662             ++count;
663           }
664           data += im->channels;
665         }
666       }
667       else {
668         for (i = 0; i < w; ++i) {
669           for (ch = 0; ch < chan_count; ++ch) {
670             if (im->ch_mask & (1 << (chans[ch])))
671               data[chans[ch]] = *samps;
672             ++samps;
673             ++count;
674           }
675           data += im->channels;
676         }
677       }
678     }
679     else {
680       if (chan_count <= 0 || chan_count > im->channels) {
681         dIMCTXim(im);
682         im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", 
683                       chan_count);
684         return -1;
685       }
686       for (i = 0; i < w; ++i) {
687         unsigned mask = 1;
688         for (ch = 0; ch < chan_count; ++ch) {
689           if (im->ch_mask & mask)
690             data[ch] = *samps;
691           ++samps;
692           ++count;
693           mask <<= 1;
694         }
695         data += im->channels;
696       }
697     }
698
699     return count;
700   }
701   else {
702     dIMCTXim(im);
703     i_push_error(0, "Image position outside of image");
704     return -1;
705   }
706 }
707
708 /*
709 =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)
710
711 Writes sample values to im for the horizontal line (l, y) to (r-1,y)
712 for the channels specified by chans, an array of int with chan_count
713 elements.
714
715 Returns the number of samples written (which should be (r-l) *
716 bits_set(chan_mask)
717
718 =cut
719 */
720
721 static
722 i_img_dim
723 i_psampf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, 
724           const i_fsample_t *samps, const int *chans, int chan_count) {
725   int ch;
726   i_img_dim count, i, w;
727   unsigned char *data;
728
729   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
730     if (r > im->xsize)
731       r = im->xsize;
732     data = im->idata + (l+y*im->xsize) * im->channels;
733     w = r - l;
734     count = 0;
735
736     if (chans) {
737       /* make sure we have good channel numbers */
738       /* and test if all channels specified are in the mask */
739       int all_in_mask = 1;
740       for (ch = 0; ch < chan_count; ++ch) {
741         if (chans[ch] < 0 || chans[ch] >= im->channels) {
742           dIMCTXim(im);
743           im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
744           return -1;
745         }
746         if (!((1 << chans[ch]) & im->ch_mask))
747           all_in_mask = 0;
748       }
749       if (all_in_mask) {
750         for (i = 0; i < w; ++i) {
751           for (ch = 0; ch < chan_count; ++ch) {
752             data[chans[ch]] = SampleFTo8(*samps);
753             ++samps;
754             ++count;
755           }
756           data += im->channels;
757         }
758       }
759       else {
760         for (i = 0; i < w; ++i) {
761           for (ch = 0; ch < chan_count; ++ch) {
762             if (im->ch_mask & (1 << (chans[ch])))
763               data[chans[ch]] = SampleFTo8(*samps);
764             ++samps;
765             ++count;
766           }
767           data += im->channels;
768         }
769       }
770     }
771     else {
772       if (chan_count <= 0 || chan_count > im->channels) {
773         dIMCTXim(im);
774         im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", 
775                       chan_count);
776         return -1;
777       }
778       for (i = 0; i < w; ++i) {
779         unsigned mask = 1;
780         for (ch = 0; ch < chan_count; ++ch) {
781           if (im->ch_mask & mask)
782             data[ch] = SampleFTo8(*samps);
783           ++samps;
784           ++count;
785           mask <<= 1;
786         }
787         data += im->channels;
788       }
789     }
790
791     return count;
792   }
793   else {
794     dIMCTXim(im);
795     i_push_error(0, "Image position outside of image");
796     return -1;
797   }
798 }
799
800 /*
801 =back
802
803 =head1 AUTHOR
804
805 Arnar M. Hrafnkelsson <addi@umich.edu>
806
807 Tony Cook <tony@develop-help.com>
808
809 =head1 SEE ALSO
810
811 L<Imager>
812
813 =cut
814 */