]> git.imager.perl.org - imager.git/blob - convert.c
based on discussion with lathos on IRC
[imager.git] / convert.c
1 /*
2 =head1 NAME
3
4   convert.c - image conversions
5
6 =head1 SYNOPSIS
7
8   i_convert(outimage, 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 #include "image.h"
21
22
23 /*
24 =item i_convert(im, src, coeff, outchan, inchan)
25
26 Converts the image src into another image.
27
28 coeff contains the co-efficients of an outchan x inchan matrix, for
29 each output pixel:
30
31               coeff[0], coeff[1] ...
32   im[x,y] = [ coeff[inchan], coeff[inchan+1]...        ] * [ src[x,y], 1]
33               ...              coeff[inchan*outchan-1]
34
35 If im has the wrong number of channels or is the wrong size then
36 i_convert() will re-create it.
37
38 Now handles images with more than 8-bits/sample.
39
40 =cut
41 */
42
43 int
44 i_convert(i_img *im, i_img *src, float *coeff, int outchan, int inchan)
45 {
46   int x, y;
47   int i, j;
48   int ilimit;
49   double work[MAXCHANNELS];
50
51   mm_log((1,"i_convert(im %p, src, %p, coeff %p,outchan %d, inchan %d)\n",im,src, coeff,outchan, inchan));
52  
53   i_clear_error();
54
55   ilimit = inchan;
56   if (ilimit > src->channels)
57     ilimit = src->channels;
58   if (outchan > MAXCHANNELS) {
59     i_push_error(0, "cannot have outchan > MAXCHANNELS");
60     return 0;
61   }
62
63   if (im->type == i_direct_type || src->type == i_direct_type) {
64     /* first check the output image */
65     if (im->channels != outchan || im->xsize != src->xsize 
66         || im->ysize != src->ysize) {
67       i_img_exorcise(im);
68       i_img_empty_ch(im, src->xsize, src->ysize, outchan);
69     }
70     if (im->bits == i_8_bits && src->bits == i_8_bits) {
71       i_color *vals;
72       
73       vals = mymalloc(sizeof(i_color) * src->xsize);
74       for (y = 0; y < src->ysize; ++y) {
75         i_glin(src, 0, src->xsize, y, vals);
76         for (x = 0; x < src->xsize; ++x) {
77           for (j = 0; j < outchan; ++j) {
78             work[j] = 0;
79             for (i = 0; i < ilimit; ++i) {
80               work[j] += coeff[i+inchan*j] * vals[x].channel[i];
81             }
82             if (i < inchan) {
83               work[j] += coeff[i+inchan*j] * 255.9;
84             }
85           }
86           for (j = 0; j < outchan; ++j) {
87             if (work[j] < 0)
88               vals[x].channel[j] = 0;
89             else if (work[j] >= 256)
90               vals[x].channel[j] = 255;
91             else
92               vals[x].channel[j] = work[j];
93           }
94         }
95         i_plin(im, 0, src->xsize, y, vals);
96       }
97       myfree(vals);
98     }
99     else {
100       i_fcolor *vals;
101       
102       vals = mymalloc(sizeof(i_fcolor) * src->xsize);
103       for (y = 0; y < src->ysize; ++y) {
104         i_glinf(src, 0, src->xsize, y, vals);
105         for (x = 0; x < src->xsize; ++x) {
106           for (j = 0; j < outchan; ++j) {
107             work[j] = 0;
108             for (i = 0; i < ilimit; ++i) {
109               work[j] += coeff[i+inchan*j] * vals[x].channel[i];
110             }
111             if (i < inchan) {
112               work[j] += coeff[i+inchan*j];
113             }
114           }
115           for (j = 0; j < outchan; ++j) {
116             if (work[j] < 0)
117               vals[x].channel[j] = 0;
118             else if (work[j] >= 1)
119               vals[x].channel[j] = 1;
120             else
121               vals[x].channel[j] = work[j];
122           }
123         }
124         i_plinf(im, 0, src->xsize, y, vals);
125       }
126       myfree(vals);
127     }
128   }
129   else {
130     int count;
131     int outcount;
132     int index;
133     i_color *colors;
134     i_palidx *vals;
135
136     if (im->channels != outchan || im->xsize != src->xsize 
137         || im->ysize != src->ysize
138         || i_maxcolors(im) < i_colorcount(src)) {
139       i_img_exorcise(im);
140       i_img_pal_new_low(im, src->xsize, src->ysize, outchan, 
141                         i_maxcolors(src));
142     }
143     /* just translate the color table */
144     count = i_colorcount(src);
145     outcount = i_colorcount(im);
146     colors = mymalloc(count * sizeof(i_color));
147     i_getcolors(src, 0, colors, count);
148     for (index = 0; index < count; ++index) {
149       for (j = 0; j < outchan; ++j) {
150         work[j] = 0;
151         for (i = 0; i < ilimit; ++i) {
152           work[j] += coeff[i+inchan*j] * colors[index].channel[i];
153         }
154         if (i < inchan) {
155           work[j] += coeff[i+inchan*j] * 255.9;
156         }
157       }
158       for (j = 0; j < outchan; ++j) {
159         if (work[j] < 0)
160           colors[index].channel[j] = 0;
161         else if (work[j] >= 255)
162           colors[index].channel[j] = 255;
163         else
164           colors[index].channel[j] = work[j];
165       }
166     }
167     if (count < outcount) {
168       i_setcolors(im, 0, colors, count);
169     }
170     else {
171       i_setcolors(im, 0, colors, outcount);
172       i_addcolors(im, colors, count-outcount);
173     }
174     /* and copy the indicies */
175     vals = mymalloc(sizeof(i_palidx) * im->xsize);
176     for (y = 0; y < im->ysize; ++y) {
177       i_gpal(src, 0, im->xsize, y, vals);
178       i_ppal(im, 0, im->xsize, y, vals);
179     }
180   }
181
182   return 1;
183 }
184
185 /*
186 =back
187
188 =head1 SEE ALSO
189
190 Imager(3)
191
192 =head1 AUTHOR
193
194 Tony Cook <tony@develop-help.com>
195
196 =cut
197 */