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