- Finished/rewrote Arnar's old SGI RGB file format support, so Imager
[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 "imager.h"
21
22
23 /*
24 =item i_convert(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 i_img *
44 i_convert(i_img *src, const float *coeff, int outchan, int inchan) {
45   int x, y;
46   int i, j;
47   int ilimit;
48   double work[MAXCHANNELS];
49   i_img *im = NULL;
50
51   mm_log((1,"i_convert(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 (src->type == i_direct_type) {
64     im = i_sametype_chans(src, src->xsize, src->ysize, outchan);
65     if (src->bits == i_8_bits) {
66       i_color *vals;
67
68       /* we can always allocate a single scanline of i_color */
69       vals = mymalloc(sizeof(i_color) * src->xsize); /* checked 04Jul05 tonyc */
70       for (y = 0; y < src->ysize; ++y) {
71         i_glin(src, 0, src->xsize, y, vals);
72         for (x = 0; x < src->xsize; ++x) {
73           for (j = 0; j < outchan; ++j) {
74             work[j] = 0;
75             for (i = 0; i < ilimit; ++i) {
76               work[j] += coeff[i+inchan*j] * vals[x].channel[i];
77             }
78             if (i < inchan) {
79               work[j] += coeff[i+inchan*j] * 255.9;
80             }
81           }
82           for (j = 0; j < outchan; ++j) {
83             if (work[j] < 0)
84               vals[x].channel[j] = 0;
85             else if (work[j] >= 256)
86               vals[x].channel[j] = 255;
87             else
88               vals[x].channel[j] = work[j];
89           }
90         }
91         i_plin(im, 0, src->xsize, y, vals);
92       }
93       myfree(vals);
94     }
95     else {
96       i_fcolor *vals;
97
98       /* we can always allocate a single scanline of i_fcolor 
99          for a >8 image */
100       vals = mymalloc(sizeof(i_fcolor) * src->xsize); /* checked 4Jul05 tonyc */
101       for (y = 0; y < src->ysize; ++y) {
102         i_glinf(src, 0, src->xsize, y, vals);
103         for (x = 0; x < src->xsize; ++x) {
104           for (j = 0; j < outchan; ++j) {
105             work[j] = 0;
106             for (i = 0; i < ilimit; ++i) {
107               work[j] += coeff[i+inchan*j] * vals[x].channel[i];
108             }
109             if (i < inchan) {
110               work[j] += coeff[i+inchan*j];
111             }
112           }
113           for (j = 0; j < outchan; ++j) {
114             if (work[j] < 0)
115               vals[x].channel[j] = 0;
116             else if (work[j] >= 1)
117               vals[x].channel[j] = 1;
118             else
119               vals[x].channel[j] = work[j];
120           }
121         }
122         i_plinf(im, 0, src->xsize, y, vals);
123       }
124       myfree(vals);
125     }
126   }
127   else {
128     int count;
129     int outcount;
130     int index;
131     i_color *colors;
132     i_palidx *vals;
133
134     im = i_img_pal_new(src->xsize, src->ysize, outchan, 
135                        i_maxcolors(src));
136
137     /* just translate the color table */
138     count = i_colorcount(src);
139     outcount = i_colorcount(im);
140     /* color table allocated for image, so it must fit */
141     colors = mymalloc(count * sizeof(i_color)); /* check 04Jul05 tonyc */
142     i_getcolors(src, 0, colors, count);
143     for (index = 0; index < count; ++index) {
144       for (j = 0; j < outchan; ++j) {
145         work[j] = 0;
146         for (i = 0; i < ilimit; ++i) {
147           work[j] += coeff[i+inchan*j] * colors[index].channel[i];
148         }
149         if (i < inchan) {
150           work[j] += coeff[i+inchan*j] * 255.9;
151         }
152       }
153       for (j = 0; j < outchan; ++j) {
154         if (work[j] < 0)
155           colors[index].channel[j] = 0;
156         else if (work[j] >= 255)
157           colors[index].channel[j] = 255;
158         else
159           colors[index].channel[j] = work[j];
160       }
161     }
162     if (count < outcount) {
163       i_setcolors(im, 0, colors, count);
164     }
165     else {
166       i_setcolors(im, 0, colors, outcount);
167       i_addcolors(im, colors, count-outcount);
168     }
169     /* and copy the indicies */
170     /* i_palidx is always unsigned char and will never be bigger than short
171        and since a line of 4-byte i_colors can fit then a line of i_palidx
172        will fit */
173     vals = mymalloc(sizeof(i_palidx) * im->xsize); /* checked 4jul05 tonyc */
174     for (y = 0; y < im->ysize; ++y) {
175       i_gpal(src, 0, im->xsize, y, vals);
176       i_ppal(im, 0, im->xsize, y, vals);
177     }
178     myfree(vals);
179     myfree(colors);
180   }
181
182   return im;
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 */