File Coverage

palimg.c
Criterion Covered Total %
statement 268 299 89.6
branch 188 242 77.6
condition n/a
subroutine n/a
pod n/a
total 456 541 84.2


line stmt bran cond sub pod time code
1             /*
2             =head1 NAME
3              
4             palimg.c - implements paletted images for Imager.
5              
6             =head1 SYNOPSIS
7              
8             =head1 DESCRIPTION
9              
10             Implements paletted images using the new image interface.
11              
12             =over
13              
14             =item IIM_base_8bit_pal
15              
16             Basic 8-bit/sample paletted image
17              
18             =cut
19             */
20              
21             #define IMAGER_NO_CONTEXT
22              
23             #include "imager.h"
24             #include "imageri.h"
25              
26             #define PALEXT(im) ((i_img_pal_ext*)((im)->ext_data))
27             static int i_ppix_p(i_img *im, i_img_dim x, i_img_dim y, const i_color *val);
28             static int i_gpix_p(i_img *im, i_img_dim x, i_img_dim y, i_color *val);
29             static i_img_dim i_glin_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals);
30             static i_img_dim i_plin_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals);
31             static i_img_dim i_gsamp_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, int const *chans, int chan_count);
32             static i_img_dim i_gpal_p(i_img *pm, i_img_dim l, i_img_dim r, i_img_dim y, i_palidx *vals);
33             static i_img_dim i_ppal_p(i_img *pm, i_img_dim l, i_img_dim r, i_img_dim y, const i_palidx *vals);
34             static int i_addcolors_p(i_img *im, const i_color *color, int count);
35             static int i_getcolors_p(i_img *im, int i, i_color *color, int count);
36             static int i_colorcount_p(i_img *im);
37             static int i_maxcolors_p(i_img *im);
38             static int i_findcolor_p(i_img *im, const i_color *color, i_palidx *entry);
39             static int i_setcolors_p(i_img *im, int index, const i_color *color, int count);
40              
41             static void i_destroy_p(i_img *im);
42             static i_img_dim
43             i_psamp_p(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);
44             static i_img_dim
45             i_psampf_p(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);
46              
47             static i_img IIM_base_8bit_pal =
48             {
49             0, /* channels set */
50             0, 0, 0, /* xsize, ysize, bytes */
51             ~0U, /* ch_mask */
52             i_8_bits, /* bits */
53             i_palette_type, /* type */
54             0, /* virtual */
55             NULL, /* idata */
56             { 0, 0, NULL }, /* tags */
57             NULL, /* ext_data */
58              
59             i_ppix_p, /* i_f_ppix */
60             i_ppixf_fp, /* i_f_ppixf */
61             i_plin_p, /* i_f_plin */
62             i_plinf_fp, /* i_f_plinf */
63             i_gpix_p, /* i_f_gpix */
64             i_gpixf_fp, /* i_f_gpixf */
65             i_glin_p, /* i_f_glin */
66             i_glinf_fp, /* i_f_glinf */
67             i_gsamp_p, /* i_f_gsamp */
68             i_gsampf_fp, /* i_f_gsampf */
69              
70             i_gpal_p, /* i_f_gpal */
71             i_ppal_p, /* i_f_ppal */
72             i_addcolors_p, /* i_f_addcolors */
73             i_getcolors_p, /* i_f_getcolors */
74             i_colorcount_p, /* i_f_colorcount */
75             i_maxcolors_p, /* i_f_maxcolors */
76             i_findcolor_p, /* i_f_findcolor */
77             i_setcolors_p, /* i_f_setcolors */
78              
79             i_destroy_p, /* i_f_destroy */
80              
81             i_gsamp_bits_fb,
82             NULL, /* i_f_psamp_bits */
83            
84             i_psamp_p,
85             i_psampf_p
86             };
87              
88             /*
89             =item im_img_pal_new(ctx, C, C, C, C)
90             XX
91             =category Image creation/destruction
92             =synopsis i_img *img = im_img_pal_new(aIMCTX, width, height, channels, max_palette_size)
93             =synopsis i_img *img = i_img_pal_new(width, height, channels, max_palette_size)
94              
95             Creates a new paletted image of the supplied dimensions.
96              
97             C is the maximum palette size and should normally be 256.
98              
99             Returns a new image or NULL on failure.
100              
101             Also callable as C.
102              
103             =cut
104             */
105             i_img *
106 167           im_img_pal_new(pIMCTX, i_img_dim x, i_img_dim y, int channels, int maxpal) {
107             i_img *im;
108             i_img_pal_ext *palext;
109             size_t bytes, line_bytes;
110              
111 167           i_clear_error();
112 167 50         if (maxpal < 1 || maxpal > 256) {
    50          
113 0           i_push_error(0, "Maximum of 256 palette entries");
114 0           return NULL;
115             }
116 167 100         if (x < 1 || y < 1) {
    100          
117 3           i_push_error(0, "Image sizes must be positive");
118 3           return NULL;
119             }
120 164 100         if (channels < 1 || channels > MAXCHANNELS) {
    100          
121 2           im_push_errorf(aIMCTX, 0, "Channels must be positive and <= %d", MAXCHANNELS);
122 2           return NULL;
123             }
124 162           bytes = sizeof(i_palidx) * x * y;
125 162 50         if (bytes / y / sizeof(i_palidx) != x) {
126 0           i_push_error(0, "integer overflow calculating image allocation");
127 0           return NULL;
128             }
129              
130             /* basic assumption: we can always allocate a buffer representing a
131             line from the image, otherwise we're going to have trouble
132             working with the image */
133 162           line_bytes = sizeof(i_color) * x;
134 162 50         if (line_bytes / x != sizeof(i_color)) {
135 0           i_push_error(0, "integer overflow calculating scanline allocation");
136 0           return NULL;
137             }
138              
139 162           im = i_img_alloc();
140 162           memcpy(im, &IIM_base_8bit_pal, sizeof(i_img));
141 162           palext = mymalloc(sizeof(i_img_pal_ext));
142 162           palext->pal = mymalloc(sizeof(i_color) * maxpal);
143 162           palext->count = 0;
144 162           palext->alloc = maxpal;
145 162           palext->last_found = -1;
146 162           im->ext_data = palext;
147 162           i_tags_new(&im->tags);
148 162           im->bytes = bytes;
149 162           im->idata = mymalloc(im->bytes);
150 162           im->channels = channels;
151 162           memset(im->idata, 0, im->bytes);
152 162           im->xsize = x;
153 162           im->ysize = y;
154              
155 162           i_img_init(im);
156            
157 162           return im;
158             }
159              
160             /*
161             =item i_img_rgb_convert(i_img *targ, i_img *src)
162              
163             Converts paletted data in src to RGB data in targ
164              
165             Internal function.
166              
167             src must be a paletted image and targ must be an RGB image with the
168             same width, height and channels.
169              
170             =cut
171             */
172 8           static void i_img_rgb_convert(i_img *targ, i_img *src) {
173 8           i_color *row = mymalloc(sizeof(i_color) * targ->xsize);
174             i_img_dim y;
175 674 100         for (y = 0; y < targ->ysize; ++y) {
176 666           i_glin(src, 0, src->xsize, y, row);
177 666           i_plin(targ, 0, src->xsize, y, row);
178             }
179 8           myfree(row);
180 8           }
181              
182             /*
183             =item i_img_to_rgb_inplace(im)
184              
185             Converts im from a paletted image to an RGB image.
186              
187             The conversion is done in place.
188              
189             The conversion cannot be done for virtual images.
190              
191             =cut
192             */
193             int
194 7           i_img_to_rgb_inplace(i_img *im) {
195             i_img temp;
196 7           dIMCTXim(im);
197              
198 7 50         if (i_img_virtual(im))
199 0           return 0;
200              
201 7 50         if (im->type == i_direct_type)
202 0           return 1; /* trivial success */
203              
204 7           i_img_empty_ch(&temp, im->xsize, im->ysize, im->channels);
205 7           i_img_rgb_convert(&temp, im);
206              
207             /* nasty hack */
208 7           i_img_exorcise(im);
209 7           *im = temp;
210              
211             /* i_img_empty_ch() calls i_img_init() which takes a ref */
212 7           im_context_refdec(aIMCTX, "img_destroy");
213              
214 7           return 1;
215             }
216              
217             /*
218             =item i_img_to_pal(i_img *im, i_quantize *quant)
219              
220             Converts an RGB image to a paletted image
221              
222             =cut
223             */
224 18           i_img *i_img_to_pal(i_img *src, i_quantize *quant) {
225             i_palidx *result;
226             i_img *im;
227 18           dIMCTXim(src);
228              
229 18           i_clear_error();
230            
231 18           i_quant_makemap(quant, &src, 1);
232 18           result = i_quant_translate(quant, src);
233              
234 18 100         if (result) {
235              
236 17           im = i_img_pal_new(src->xsize, src->ysize, src->channels, quant->mc_size);
237              
238             /* copy things over */
239 17           memcpy(im->idata, result, im->bytes);
240 17           PALEXT(im)->count = quant->mc_count;
241 17           memcpy(PALEXT(im)->pal, quant->mc_colors, sizeof(i_color) * quant->mc_count);
242            
243 17           myfree(result);
244              
245 17           return im;
246             }
247             else {
248 1           return NULL;
249             }
250             }
251              
252             /*
253             =item i_img_to_rgb(i_img *src)
254              
255             =cut
256             */
257             i_img *
258 1           i_img_to_rgb(i_img *src) {
259 1           dIMCTXim(src);
260 1           i_img *im = i_img_empty_ch(NULL, src->xsize, src->ysize, src->channels);
261 1           i_img_rgb_convert(im, src);
262              
263 1           return im;
264             }
265              
266             /*
267             =item i_destroy_p(i_img *im)
268              
269             Destroys data related to a paletted image.
270              
271             =cut
272             */
273 162           static void i_destroy_p(i_img *im) {
274 162 50         if (im) {
275 162           i_img_pal_ext *palext = im->ext_data;
276 162 50         if (palext) {
277 162 50         if (palext->pal)
278 162           myfree(palext->pal);
279 162           myfree(palext);
280             }
281             }
282 162           }
283              
284             /*
285             =item i_ppix_p(i_img *im, i_img_dim x, i_img_dim y, const i_color *val)
286              
287             Write to a pixel in the image.
288              
289             Warning: converts the image to a RGB image if the color isn't already
290             present in the image.
291              
292             =cut
293             */
294             static int
295 11876           i_ppix_p(i_img *im, i_img_dim x, i_img_dim y, const i_color *val) {
296 11876           const i_color *work_val = val;
297             i_color workc;
298             i_palidx which;
299 11876           const unsigned all_mask = ( 1 << im->channels ) - 1;
300              
301 11876 100         if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
    100          
    100          
    100          
302 8           return -1;
303              
304 11868 100         if ((im->ch_mask & all_mask) != all_mask) {
305 4           unsigned mask = 1;
306             int ch;
307 4           i_gpix(im, x, y, &workc);
308 16 100         for (ch = 0; ch < im->channels; ++ch) {
309 12 100         if (im->ch_mask & mask)
310 8           workc.channel[ch] = val->channel[ch];
311 12           mask <<= 1;
312             }
313 4           work_val = &workc;
314             }
315              
316 11868 50         if (i_findcolor(im, work_val, &which)) {
    100          
317 11866           ((i_palidx *)im->idata)[x + y * im->xsize] = which;
318 11866           return 0;
319             }
320             else {
321 2           dIMCTXim(im);
322 2           im_log((aIMCTX, 1, "i_ppix: color(%d,%d,%d) not found, converting to rgb\n",
323             val->channel[0], val->channel[1], val->channel[2]));
324 2 50         if (i_img_to_rgb_inplace(im)) {
325 2           return i_ppix(im, x, y, val);
326             }
327             else
328 11876           return -1;
329             }
330             }
331              
332             /*
333             =item i_gpix_p(i_img *im, i_img_dim x, i_img_dim y, i_color *val)
334              
335             Retrieve a pixel, converting from a palette index to a color.
336              
337             =cut
338             */
339 682418           static int i_gpix_p(i_img *im, i_img_dim x, i_img_dim y, i_color *val) {
340             i_palidx which;
341 682418 100         if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) {
    100          
    100          
    100          
342 8           return -1;
343             }
344 682410           which = ((i_palidx *)im->idata)[x + y * im->xsize];
345 682410 50         if (which > PALEXT(im)->count)
346 0           return -1;
347 682410           *val = PALEXT(im)->pal[which];
348              
349 682410           return 0;
350             }
351              
352             /*
353             =item i_glinp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals)
354              
355             Retrieve a row of pixels.
356              
357             =cut
358             */
359 700           static i_img_dim i_glin_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals) {
360 700 50         if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
    50          
    50          
    50          
361 700           int palsize = PALEXT(im)->count;
362 700           i_color *pal = PALEXT(im)->pal;
363             i_palidx *data;
364             i_img_dim count, i;
365 700 50         if (r > im->xsize)
366 0           r = im->xsize;
367 700           data = ((i_palidx *)im->idata) + l + y * im->xsize;
368 700           count = r - l;
369 121557 100         for (i = 0; i < count; ++i) {
370 120857           i_palidx which = *data++;
371 120857 50         if (which < palsize)
372 120857           vals[i] = pal[which];
373             }
374 700           return count;
375             }
376             else {
377 0           return 0;
378             }
379             }
380              
381             /*
382             =item i_plin_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals)
383              
384             Write a line of color data to the image.
385              
386             If any color value is not in the image when the image is converted to
387             RGB.
388              
389             =cut
390             */
391             static i_img_dim
392 439           i_plin_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals) {
393             i_img_dim count, i;
394             i_palidx *data;
395             i_palidx which;
396 439 50         if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
    50          
    50          
    50          
397 439 50         if (r > im->xsize)
398 0           r = im->xsize;
399 439           data = ((i_palidx *)im->idata) + l + y * im->xsize;
400 439           count = r - l;
401 25983 100         for (i = 0; i < count; ++i) {
402 25549 50         if (i_findcolor(im, vals+i, &which)) {
    100          
403 25544           ((i_palidx *)data)[i] = which;
404             }
405             else {
406 5 50         if (i_img_to_rgb_inplace(im)) {
407 5           return i+i_plin(im, l+i, r, y, vals+i);
408             }
409             }
410             }
411 434           return count;
412             }
413             else {
414 439           return 0;
415             }
416             }
417              
418             /*
419             =item i_gsamp_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, int chans, int chan_count)
420              
421             =cut
422             */
423 207           static i_img_dim i_gsamp_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps,
424             int const *chans, int chan_count) {
425             int ch;
426 207 50         if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
    50          
    50          
    50          
427 207           int palsize = PALEXT(im)->count;
428 207           i_color *pal = PALEXT(im)->pal;
429             i_palidx *data;
430             i_img_dim count, i, w;
431 207 50         if (r > im->xsize)
432 0           r = im->xsize;
433 207           data = ((i_palidx *)im->idata) + l + y * im->xsize;
434 207           count = 0;
435 207           w = r - l;
436 207 100         if (chans) {
437 24 100         for (ch = 0; ch < chan_count; ++ch) {
438 18 50         if (chans[ch] < 0 || chans[ch] >= im->channels) {
    50          
439 0           dIMCTXim(im);
440 0           im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
441             }
442             }
443              
444 426 100         for (i = 0; i < w; ++i) {
445 420           i_palidx which = *data++;
446 420 50         if (which < palsize) {
447 1680 100         for (ch = 0; ch < chan_count; ++ch) {
448 1260           *samps++ = pal[which].channel[chans[ch]];
449 1260           ++count;
450             }
451             }
452             }
453             }
454             else {
455 201 50         if (chan_count <= 0 || chan_count > im->channels) {
    50          
456 0           dIMCTXim(im);
457 0           im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
458             chan_count);
459 0           return 0;
460             }
461 17028 100         for (i = 0; i < w; ++i) {
462 16827           i_palidx which = *data++;
463 16827 50         if (which < palsize) {
464 67308 100         for (ch = 0; ch < chan_count; ++ch) {
465 50481           *samps++ = pal[which].channel[ch];
466 50481           ++count;
467             }
468             }
469             }
470             }
471 207           return count;
472             }
473             else {
474 0           return 0;
475             }
476             }
477              
478             /*
479             =item i_gpal_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_palidx *vals)
480              
481             =cut
482             */
483              
484 14708           static i_img_dim i_gpal_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_palidx *vals) {
485 14708 50         if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
    50          
    50          
    50          
486             i_palidx *data;
487             i_img_dim i, w;
488 14708 50         if (r > im->xsize)
489 0           r = im->xsize;
490 14708           data = ((i_palidx *)im->idata) + l + y * im->xsize;
491 14708           w = r - l;
492 626539 100         for (i = 0; i < w; ++i) {
493 611831           *vals++ = *data++;
494             }
495 14708           return i;
496             }
497             else {
498 0           return 0;
499             }
500             }
501              
502             /*
503             =item i_ppal_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_palidx *vals)
504              
505             =cut
506             */
507              
508 92290           static i_img_dim i_ppal_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_palidx *vals) {
509 92290 50         if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
    50          
    50          
    50          
510             i_palidx *data;
511             i_img_dim i, w;
512 92290 50         if (r > im->xsize)
513 0           r = im->xsize;
514 92290           data = ((i_palidx *)im->idata) + l + y * im->xsize;
515 92290           w = r - l;
516 959759 100         for (i = 0; i < w; ++i) {
517 867469           *data++ = *vals++;
518             }
519 92290           return i;
520             }
521             else {
522 0           return 0;
523             }
524             }
525              
526             /*
527             =item i_addcolors_p(i_img *im, const i_color *color, int count)
528              
529             =cut
530             */
531 8800           static int i_addcolors_p(i_img *im, const i_color *color, int count) {
532 8800 50         if (PALEXT(im)->count + count <= PALEXT(im)->alloc) {
533 8800           int result = PALEXT(im)->count;
534 8800           int index = result;
535              
536 8800           PALEXT(im)->count += count;
537 17691 100         while (count) {
538 8891           PALEXT(im)->pal[index++] = *color++;
539 8891           --count;
540             }
541              
542 8800           return result;
543             }
544             else
545 0           return -1;
546             }
547              
548             /*
549             =item i_getcolors_p(i_img *im, int i, i_color *color, int count)
550              
551             =cut
552             */
553 2770           static int i_getcolors_p(i_img *im, int i, i_color *color, int count) {
554 2770 50         if (i >= 0 && i+count <= PALEXT(im)->count) {
    50          
555 5960 100         while (count) {
556 3190           *color++ = PALEXT(im)->pal[i++];
557 3190           --count;
558             }
559 2770           return 1;
560             }
561             else
562 0           return 0;
563             }
564              
565 74848           static int color_eq(i_img *im, const i_color *c1, const i_color *c2) {
566             int ch;
567 188050 100         for (ch = 0; ch < im->channels; ++ch) {
568 150609 100         if (c1->channel[ch] != c2->channel[ch])
569 37407           return 0;
570             }
571 37441           return 1;
572             }
573              
574             /*
575             =item i_colorcount_p(i_img *im)
576              
577             =cut
578             */
579 1576           static int i_colorcount_p(i_img *im) {
580 1576           return PALEXT(im)->count;
581             }
582              
583             /*
584             =item i_maxcolors_p(i_img *im)
585              
586             =cut
587             */
588 23           static int i_maxcolors_p(i_img *im) {
589 23           return PALEXT(im)->alloc;
590             }
591              
592             /*
593             =item i_setcolors_p(i_img *im, int index, const i_color *colors, int count)
594              
595             =cut
596             */
597 12           static int i_setcolors_p(i_img *im, int index, const i_color *colors, int count) {
598 12 100         if (index >= 0 && count >= 1 && index + count <= PALEXT(im)->count) {
    100          
    100          
599 13 100         while (count) {
600 8           PALEXT(im)->pal[index++] = *colors++;
601 8           --count;
602             }
603 5           return 1;
604             }
605              
606 7           return 0;
607             }
608              
609             /*
610             =item i_findcolor_p(i_img *im)
611              
612             =cut
613             */
614 37451           static int i_findcolor_p(i_img *im, const i_color *color, i_palidx *entry) {
615 37451 50         if (PALEXT(im)->count) {
616             int i;
617             /* often the same color comes up several times in a row */
618 37451 100         if (PALEXT(im)->last_found >= 0) {
619 37425 100         if (color_eq(im, color, PALEXT(im)->pal + PALEXT(im)->last_found)) {
620 12748           *entry = PALEXT(im)->last_found;
621 12748           return 1;
622             }
623             }
624 37433 100         for (i = 0; i < PALEXT(im)->count; ++i) {
625 37423 100         if (color_eq(im, color, PALEXT(im)->pal + i)) {
626 24693           PALEXT(im)->last_found = *entry = i;
627 24693           return 1;
628             }
629             }
630             }
631 10           return 0;
632             }
633              
634             /*
635             =item i_psamp_p(im, l, r, y, samps, chans, chan_count)
636              
637             Implement psamp() for paletted images.
638              
639             Since writing samples doesn't really work as a concept for paletted
640             images, this is slow.
641              
642             Also, writing samples may convert the image to a direct image in the
643             process, so use i_ppix/i_gpix instead of directly calling the paletted
644             handlers.
645              
646             =cut
647             */
648              
649             static i_img_dim
650 12           i_psamp_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
651             const i_sample_t *samps, const int *chans, int chan_count) {
652 12 100         if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
    100          
    100          
    100          
653 8           i_img_dim count = 0;
654             int ch;
655              
656 8 100         if (r > im->xsize)
657 1           r = im->xsize;
658            
659 8 100         if (chans) {
660             /* make sure we have good channel numbers */
661 21 100         for (ch = 0; ch < chan_count; ++ch) {
662 17 100         if (chans[ch] < 0 || chans[ch] >= im->channels) {
    100          
663 2           dIMCTXim(im);
664 2           im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
665 2           return -1;
666             }
667             }
668 19 100         while (l < r) {
669             i_color c;
670            
671 15           i_gpix(im, l, y, &c);
672 58 100         for (ch = 0; ch < chan_count; ++ch)
673 43           c.channel[chans[ch]] = *samps++;
674 15           i_ppix(im, l, y, &c);
675 15           count += chan_count;
676 15           ++l;
677             }
678             }
679             else {
680 2 50         if (chan_count <= 0 || chan_count > im->channels) {
    50          
681 0           dIMCTXim(im);
682 0           im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
683             chan_count);
684 0           return -1;
685             }
686              
687 4 100         while (l < r) {
688             i_color c;
689            
690 2           i_gpix(im, l, y, &c);
691 8 100         for (ch = 0; ch < chan_count; ++ch)
692 6           c.channel[ch] = *samps++;
693 2           i_ppix(im, l, y, &c);
694 2           count += chan_count;
695 2           ++l;
696             }
697             }
698              
699 6           return count;
700             }
701             else {
702 4           dIMCTXim(im);
703 4           i_push_error(0, "Image position outside of image");
704 4           return -1;
705             }
706             }
707              
708             /*
709             =item i_psampf_p(im, l, r, y, samps, chans, chan_count)
710              
711             Implement psampf() for paletted images.
712              
713             Since writing samples doesn't really work as a concept for paletted
714             images, this is slow.
715              
716             Also, writing samples may convert the image to a direct image in the
717             process, so use i_ppixf/i_gpixf instead of directly calling the paletted
718             handlers.
719              
720             =cut
721             */
722              
723             static i_img_dim
724 12           i_psampf_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
725             const i_fsample_t *samps, const int *chans, int chan_count) {
726 12 100         if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
    100          
    100          
    100          
727 8           i_img_dim count = 0;
728             int ch;
729              
730 8 100         if (r > im->xsize)
731 1           r = im->xsize;
732            
733 8 100         if (chans) {
734             /* make sure we have good channel numbers */
735 21 100         for (ch = 0; ch < chan_count; ++ch) {
736 17 100         if (chans[ch] < 0 || chans[ch] >= im->channels) {
    100          
737 2           dIMCTXim(im);
738 2           im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
739 2           return -1;
740             }
741             }
742 19 100         while (l < r) {
743             i_fcolor c;
744            
745 15           i_gpixf(im, l, y, &c);
746 58 100         for (ch = 0; ch < chan_count; ++ch)
747 43           c.channel[chans[ch]] = *samps++;
748 15           i_ppixf(im, l, y, &c);
749 15           count += chan_count;
750 15           ++l;
751             }
752             }
753             else {
754 2 50         if (chan_count <= 0 || chan_count > im->channels) {
    50          
755 0           dIMCTXim(im);
756 0           im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
757             chan_count);
758 0           return -1;
759             }
760              
761 4 100         while (l < r) {
762             i_fcolor c;
763            
764 2           i_gpixf(im, l, y, &c);
765 8 100         for (ch = 0; ch < chan_count; ++ch)
766 6           c.channel[ch] = *samps++;
767 2           i_ppixf(im, l, y, &c);
768 2           count += chan_count;
769 2           ++l;
770             }
771             }
772              
773 6           return count;
774             }
775             else {
776 4           dIMCTXim(im);
777 4           i_push_error(0, "Image position outside of image");
778 4           return -1;
779             }
780             }
781              
782             /*
783             =back
784              
785             =head1 AUTHOR
786              
787             Tony Cook
788              
789             =head1 SEE ALSO
790              
791             Imager(3)
792              
793             =cut
794             */