File Coverage

convert.im
Criterion Covered Total %
statement 108 117 92.3
branch 104 126 82.5
condition n/a
subroutine n/a
pod n/a
total 212 243 87.2


line stmt bran cond sub pod time code
1             /*
2             =head1 NAME
3              
4             convert.im - image conversions
5              
6             =head1 SYNOPSIS
7              
8             out = i_convert(srcimage, coeff, outchans, inchans)
9              
10             =head1 DESCRIPTION
11              
12             Converts images from one format to another, typically in this case for
13             converting from RGBA to greyscale and back.
14              
15             =over
16              
17             =cut
18             */
19              
20             #define IMAGER_NO_CONTEXT
21             #include "imager.h"
22              
23             struct chan_copy {
24             /* channels to copy */
25             int copy_count;
26             int from[MAXCHANNELS];
27             int to[MAXCHANNELS];
28              
29             /* channels to zero */
30             int zero_count;
31             int zero[MAXCHANNELS];
32              
33             /* channels to set to maxsample */
34             int one_count;
35             int one[MAXCHANNELS];
36             };
37              
38             static int
39             is_channel_copy(i_img *im, const double *coeff,
40             int outchan, int inchan,
41             struct chan_copy *info);
42              
43             static i_img *
44             convert_via_copy(i_img *im, i_img *src, struct chan_copy *info);
45              
46             /*
47             =item i_convert(src, coeff, outchan, inchan)
48              
49             Converts the image src into another image.
50              
51             coeff contains the co-efficients of an outchan x inchan matrix, for
52             each output pixel:
53              
54             coeff[0], coeff[1] ...
55             im[x,y] = [ coeff[inchan], coeff[inchan+1]... ] * [ src[x,y], 1]
56             ... coeff[inchan*outchan-1]
57              
58             If im has the wrong number of channels or is the wrong size then
59             i_convert() will re-create it.
60              
61             Now handles images with more than 8-bits/sample.
62              
63             =cut
64             */
65              
66             i_img *
67 28           i_convert(i_img *src, const double *coeff, int outchan, int inchan) {
68             double work[MAXCHANNELS];
69             i_img_dim x, y;
70             int i, j;
71             int ilimit;
72 28           i_img *im = NULL;
73 28           dIMCTXim(src);
74              
75 28           im_log((aIMCTX,1,"i_convert(im %p, src %p, coeff %p,outchan %d, inchan %d)\n",
76             im, src, coeff, outchan, inchan));
77            
78 28           im_clear_error(aIMCTX);
79              
80 28           ilimit = inchan;
81 28 100         if (ilimit > src->channels)
82 8           ilimit = src->channels;
83 28 50         if (outchan > MAXCHANNELS) {
84 0           im_push_error(aIMCTX, 0, "cannot have outchan > MAXCHANNELS");
85 0           return 0;
86             }
87              
88 28 100         if (src->type == i_direct_type) {
89             struct chan_copy info;
90 25           im = i_sametype_chans(src, src->xsize, src->ysize, outchan);
91            
92 25 100         if (is_channel_copy(src, coeff, outchan, inchan, &info)) {
93 18           return convert_via_copy(im, src, &info);
94             }
95             else {
96 7 100         #code src->bits <= i_8_bits
97             IM_COLOR *vals;
98            
99             /* we can always allocate a single scanline of i_color */
100 7           vals = mymalloc(sizeof(IM_COLOR) * src->xsize); /* checked 04Jul05 tonyc */
101 622 100         for (y = 0; y < src->ysize; ++y) {
    100          
102 615           IM_GLIN(src, 0, src->xsize, y, vals);
103 81145 100         for (x = 0; x < src->xsize; ++x) {
    100          
104 161060 100         for (j = 0; j < outchan; ++j) {
    100          
105 80530           work[j] = 0;
106 322120 100         for (i = 0; i < ilimit; ++i) {
    100          
107 241590           work[j] += coeff[i+inchan*j] * vals[x].channel[i];
108             }
109 80530 50         if (i < inchan) {
    100          
110 100           work[j] += coeff[i+inchan*j] * IM_SAMPLE_MAX;
111             }
112             }
113 161060 100         for (j = 0; j < outchan; ++j) {
    100          
114 80530 50         if (work[j] < 0)
    50          
115 0           vals[x].channel[j] = 0;
116 80530 50         else if (work[j] >= IM_SAMPLE_MAX)
    50          
117 0           vals[x].channel[j] = IM_SAMPLE_MAX;
118             else
119 80530           vals[x].channel[j] = work[j];
120             }
121             }
122 615           IM_PLIN(im, 0, src->xsize, y, vals);
123             }
124 7           myfree(vals);
125             #/code
126             }
127             }
128             else {
129             int count;
130             int outcount;
131             int index;
132             i_color *colors;
133             i_palidx *vals;
134              
135 3 50         im = im_img_pal_new(aIMCTX, src->xsize, src->ysize, outchan,
136 6           i_maxcolors(src));
137              
138             /* just translate the color table */
139 3 50         count = i_colorcount(src);
140 3 50         outcount = i_colorcount(im);
141             /* color table allocated for image, so it must fit */
142 3           colors = mymalloc(count * sizeof(i_color)); /* check 04Jul05 tonyc */
143 3 50         i_getcolors(src, 0, colors, count);
144 9 100         for (index = 0; index < count; ++index) {
145 25 100         for (j = 0; j < outchan; ++j) {
146 19           work[j] = 0;
147 52 100         for (i = 0; i < ilimit; ++i) {
148 33           work[j] += coeff[i+inchan*j] * colors[index].channel[i];
149             }
150 19 100         if (i < inchan) {
151 7           work[j] += coeff[i+inchan*j] * 255.9;
152             }
153             }
154 25 100         for (j = 0; j < outchan; ++j) {
155 19 50         if (work[j] < 0)
156 0           colors[index].channel[j] = 0;
157 19 100         else if (work[j] >= 255)
158 6           colors[index].channel[j] = 255;
159             else
160 13           colors[index].channel[j] = work[j];
161             }
162             }
163 3 50         if (count < outcount) {
164 0 0         i_setcolors(im, 0, colors, count);
165             }
166             else {
167 3 50         i_setcolors(im, 0, colors, outcount);
168 3 50         i_addcolors(im, colors, count-outcount);
169             }
170             /* and copy the indicies */
171             /* i_palidx is always unsigned char and will never be bigger than short
172             and since a line of 4-byte i_colors can fit then a line of i_palidx
173             will fit */
174 3           vals = mymalloc(sizeof(i_palidx) * im->xsize); /* checked 4jul05 tonyc */
175 324 100         for (y = 0; y < im->ysize; ++y) {
176 321 50         i_gpal(src, 0, im->xsize, y, vals);
177 321 50         i_ppal(im, 0, im->xsize, y, vals);
178             }
179 3           myfree(vals);
180 3           myfree(colors);
181             }
182              
183 28           return im;
184             }
185              
186             /*
187             =item is_channel_copy(coeff, outchan, inchan, chan_copy_info)
188              
189             Test if the coefficients represent just copying channels around, and
190             initialize lists of the channels to copy, zero or set to max.
191              
192             =cut
193             */
194              
195             static
196 25           int is_channel_copy(i_img *im, const double *coeff, int outchan, int inchan,
197             struct chan_copy *info) {
198             int srcchan[MAXCHANNELS];
199             int onechan[MAXCHANNELS];
200             int i, j;
201 25           int ilimit = im->channels > inchan ? inchan : im->channels;
202              
203 82 100         for (j = 0; j < outchan; ++j) {
204 57           srcchan[j] = -1;
205 57           onechan[j] = 0;
206             }
207              
208 75 100         for (j = 0; j < outchan; ++j) {
209 167 100         for (i = 0; i < ilimit; ++i) {
210 117 100         if (coeff[i+inchan*j] == 1.0) {
211 43 50         if (srcchan[j] != -1) {
212             /* from two or more channels, not a copy */
213 0           return 0;
214             }
215 43           srcchan[j] = i;
216             }
217 74 100         else if (coeff[i+inchan*j]) {
218             /* some other non-zero value, not a copy */
219 7           return 0;
220             }
221             }
222 50 100         if (i < inchan) {
223 16 100         if (coeff[i+inchan*j] == 1.0) {
224 5 50         if (srcchan[j] != -1) {
225             /* can't do both */
226 0           return 0;
227             }
228 5           onechan[j] = 1;
229             }
230 11 50         else if (coeff[i+inchan*j]) {
231             /* some other non-zero value, not a copy */
232 0           return 0;
233             }
234             }
235             }
236              
237             /* build our working data structures */
238 18           info->copy_count = info->zero_count = info->one_count = 0;
239 68 100         for (j = 0; j < outchan; ++j) {
240 50 100         if (srcchan[j] != -1) {
241 43           info->from[info->copy_count] = srcchan[j];
242 43           info->to[info->copy_count] = j;
243 43           ++info->copy_count;
244             }
245 7 100         else if (onechan[j]) {
246 5           info->one[info->one_count] = j;
247 5           ++info->one_count;
248             }
249             else {
250 2           info->zero[info->zero_count] = j;
251 2           ++info->zero_count;
252             }
253             }
254              
255             #if 0
256             {
257             for (i = 0; i < info->copy_count; ++i) {
258             printf("From %d to %d\n", info->from[i], info->to[i]);
259             }
260             for (i = 0; i < info->one_count; ++i) {
261             printf("One %d\n", info->one[i]);
262             }
263             for (i = 0; i < info->zero_count; ++i) {
264             printf("Zero %d\n", info->zero[i]);
265             }
266             fflush(stdout);
267             }
268             #endif
269              
270 25           return 1;
271             }
272              
273             /*
274             =item convert_via_copy(im, src, chan_copy_info)
275              
276             Perform a convert that only requires channel copies.
277              
278             =cut
279             */
280              
281             static i_img *
282 18           convert_via_copy(i_img *im, i_img *src, struct chan_copy *info) {
283 18 100         #code src->bits <= i_8_bits
284 18           IM_COLOR *in_line = mymalloc(sizeof(IM_COLOR) * src->xsize);
285 18           IM_COLOR *out_line = mymalloc(sizeof(IM_COLOR) * src->xsize);
286             i_img_dim x, y;
287             int i;
288             IM_COLOR *inp, *outp;
289              
290 1549 100         for (y = 0; y < src->ysize; ++y) {
    100          
291 1531           IM_GLIN(src, 0, src->xsize, y, in_line);
292              
293 1531           inp = in_line;
294 1531           outp = out_line;
295 250637 100         for (x = 0; x < src->xsize; ++x) {
    100          
296 587388 100         for (i = 0; i < info->copy_count; ++i) {
    100          
297 338282           outp->channel[info->to[i]] = inp->channel[info->from[i]];
298             }
299 438166 100         for (i = 0; i < info->one_count; ++i) {
    100          
300 189060           outp->channel[info->one[i]] = IM_SAMPLE_MAX;
301             }
302 329106 50         for (i = 0; i < info->zero_count; ++i) {
    100          
303 80000           outp->channel[info->zero[i]] = 0;
304             }
305 249106           ++inp;
306 249106           ++outp;
307             }
308            
309 1531           IM_PLIN(im, 0, src->xsize, y, out_line);
310             }
311            
312 18           myfree(in_line);
313 18           myfree(out_line);
314             #/code
315            
316 18           return im;
317             }
318              
319             /*
320             =back
321              
322             =head1 SEE ALSO
323              
324             Imager(3)
325              
326             =head1 AUTHOR
327              
328             Tony Cook
329              
330             =cut
331             */