correct an old bug link
[imager.git] / convert.im
CommitLineData
f5991c03
TC
1/*
2=head1 NAME
3
62869327 4 convert.im - image conversions
f5991c03
TC
5
6=head1 SYNOPSIS
7
55ebcc7b 8 out = i_convert(srcimage, coeff, outchans, inchans)
f5991c03
TC
9
10=head1 DESCRIPTION
11
12Converts images from one format to another, typically in this case for
13converting from RGBA to greyscale and back.
14
15=over
16
17=cut
18*/
19
b5710486 20#define IMAGER_NO_CONTEXT
92bda632 21#include "imager.h"
f5991c03 22
2a2c791f
TC
23struct 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
38static int
39is_channel_copy(i_img *im, const double *coeff,
40 int outchan, int inchan,
41 struct chan_copy *info);
42
43static i_img *
44convert_via_copy(i_img *im, i_img *src, struct chan_copy *info);
f5991c03
TC
45
46/*
d5477d3d 47=item i_convert(src, coeff, outchan, inchan)
f5991c03
TC
48
49Converts the image src into another image.
50
51coeff contains the co-efficients of an outchan x inchan matrix, for
52each 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
58If im has the wrong number of channels or is the wrong size then
59i_convert() will re-create it.
60
faa9b3e7
TC
61Now handles images with more than 8-bits/sample.
62
f5991c03
TC
63=cut
64*/
65
d5477d3d 66i_img *
62869327 67i_convert(i_img *src, const double *coeff, int outchan, int inchan) {
2a2c791f 68 double work[MAXCHANNELS];
8d14daab 69 i_img_dim x, y;
f5991c03 70 int i, j;
a743c0a6 71 int ilimit;
d5477d3d 72 i_img *im = NULL;
b5710486 73 dIMCTXim(src);
f5991c03 74
b5710486 75 im_log((aIMCTX,1,"i_convert(im %p, src %p, coeff %p,outchan %d, inchan %d)\n",
8d14daab 76 im, src, coeff, outchan, inchan));
f5991c03 77
b5710486 78 im_clear_error(aIMCTX);
f5991c03
TC
79
80 ilimit = inchan;
81 if (ilimit > src->channels)
82 ilimit = src->channels;
83 if (outchan > MAXCHANNELS) {
b5710486 84 im_push_error(aIMCTX, 0, "cannot have outchan > MAXCHANNELS");
f5991c03
TC
85 return 0;
86 }
87
d5477d3d 88 if (src->type == i_direct_type) {
2a2c791f 89 struct chan_copy info;
d5477d3d 90 im = i_sametype_chans(src, src->xsize, src->ysize, outchan);
62869327 91
2a2c791f
TC
92 if (is_channel_copy(src, coeff, outchan, inchan, &info)) {
93 return convert_via_copy(im, src, &info);
94 }
95 else {
96#code src->bits <= i_8_bits
97 IM_COLOR *vals;
98
99 /* we can always allocate a single scanline of i_color */
100 vals = mymalloc(sizeof(IM_COLOR) * src->xsize); /* checked 04Jul05 tonyc */
101 for (y = 0; y < src->ysize; ++y) {
102 IM_GLIN(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] * IM_SAMPLE_MAX;
111 }
62869327 112 }
2a2c791f
TC
113 for (j = 0; j < outchan; ++j) {
114 if (work[j] < 0)
115 vals[x].channel[j] = 0;
116 else if (work[j] >= IM_SAMPLE_MAX)
117 vals[x].channel[j] = IM_SAMPLE_MAX;
118 else
119 vals[x].channel[j] = work[j];
62869327
TC
120 }
121 }
2a2c791f 122 IM_PLIN(im, 0, src->xsize, y, vals);
faa9b3e7 123 }
2a2c791f 124 myfree(vals);
62869327 125#/code
2a2c791f 126 }
f5991c03 127 }
faa9b3e7
TC
128 else {
129 int count;
130 int outcount;
131 int index;
132 i_color *colors;
133 i_palidx *vals;
134
b5710486
TC
135 im = im_img_pal_new(aIMCTX, src->xsize, src->ysize, outchan,
136 i_maxcolors(src));
d5477d3d 137
faa9b3e7
TC
138 /* just translate the color table */
139 count = i_colorcount(src);
140 outcount = i_colorcount(im);
f0960b14
TC
141 /* color table allocated for image, so it must fit */
142 colors = mymalloc(count * sizeof(i_color)); /* check 04Jul05 tonyc */
faa9b3e7
TC
143 i_getcolors(src, 0, colors, count);
144 for (index = 0; index < count; ++index) {
f5991c03 145 for (j = 0; j < outchan; ++j) {
faa9b3e7
TC
146 work[j] = 0;
147 for (i = 0; i < ilimit; ++i) {
148 work[j] += coeff[i+inchan*j] * colors[index].channel[i];
149 }
150 if (i < inchan) {
151 work[j] += coeff[i+inchan*j] * 255.9;
152 }
f5991c03
TC
153 }
154 for (j = 0; j < outchan; ++j) {
faa9b3e7
TC
155 if (work[j] < 0)
156 colors[index].channel[j] = 0;
157 else if (work[j] >= 255)
158 colors[index].channel[j] = 255;
159 else
160 colors[index].channel[j] = work[j];
f5991c03
TC
161 }
162 }
faa9b3e7
TC
163 if (count < outcount) {
164 i_setcolors(im, 0, colors, count);
165 }
166 else {
167 i_setcolors(im, 0, colors, outcount);
168 i_addcolors(im, colors, count-outcount);
169 }
170 /* and copy the indicies */
f0960b14
TC
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 vals = mymalloc(sizeof(i_palidx) * im->xsize); /* checked 4jul05 tonyc */
faa9b3e7
TC
175 for (y = 0; y < im->ysize; ++y) {
176 i_gpal(src, 0, im->xsize, y, vals);
177 i_ppal(im, 0, im->xsize, y, vals);
178 }
a73aeb5f
AMH
179 myfree(vals);
180 myfree(colors);
f5991c03 181 }
faa9b3e7 182
d5477d3d 183 return im;
f5991c03
TC
184}
185
2a2c791f
TC
186/*
187=item is_channel_copy(coeff, outchan, inchan, chan_copy_info)
188
189Test if the coefficients represent just copying channels around, and
190initialize lists of the channels to copy, zero or set to max.
191
192=cut
193*/
194
195static
196int 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 int ilimit = im->channels > inchan ? inchan : im->channels;
202
203 for (j = 0; j < outchan; ++j) {
204 srcchan[j] = -1;
205 onechan[j] = 0;
206 }
207
208 for (j = 0; j < outchan; ++j) {
209 for (i = 0; i < ilimit; ++i) {
210 if (coeff[i+inchan*j] == 1.0) {
211 if (srcchan[j] != -1) {
212 /* from two or more channels, not a copy */
213 return 0;
214 }
215 srcchan[j] = i;
216 }
217 else if (coeff[i+inchan*j]) {
218 /* some other non-zero value, not a copy */
219 return 0;
220 }
221 }
222 if (i < inchan) {
223 if (coeff[i+inchan*j] == 1.0) {
224 if (srcchan[j] != -1) {
225 /* can't do both */
226 return 0;
227 }
228 onechan[j] = 1;
229 }
230 else if (coeff[i+inchan*j]) {
231 /* some other non-zero value, not a copy */
232 return 0;
233 }
234 }
235 }
236
237 /* build our working data structures */
238 info->copy_count = info->zero_count = info->one_count = 0;
239 for (j = 0; j < outchan; ++j) {
240 if (srcchan[j] != -1) {
241 info->from[info->copy_count] = srcchan[j];
242 info->to[info->copy_count] = j;
243 ++info->copy_count;
244 }
245 else if (onechan[j]) {
246 info->one[info->one_count] = j;
247 ++info->one_count;
248 }
249 else {
250 info->zero[info->zero_count] = j;
251 ++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 return 1;
271}
272
273/*
274=item convert_via_copy(im, src, chan_copy_info)
275
276Perform a convert that only requires channel copies.
277
278=cut
279*/
280
6f436528 281static i_img *
2a2c791f
TC
282convert_via_copy(i_img *im, i_img *src, struct chan_copy *info) {
283#code src->bits <= i_8_bits
284 IM_COLOR *in_line = mymalloc(sizeof(IM_COLOR) * src->xsize);
285 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 for (y = 0; y < src->ysize; ++y) {
291 IM_GLIN(src, 0, src->xsize, y, in_line);
292
293 inp = in_line;
294 outp = out_line;
295 for (x = 0; x < src->xsize; ++x) {
296 for (i = 0; i < info->copy_count; ++i) {
297 outp->channel[info->to[i]] = inp->channel[info->from[i]];
298 }
299 for (i = 0; i < info->one_count; ++i) {
300 outp->channel[info->one[i]] = IM_SAMPLE_MAX;
301 }
302 for (i = 0; i < info->zero_count; ++i) {
303 outp->channel[info->zero[i]] = 0;
304 }
305 ++inp;
306 ++outp;
307 }
308
309 IM_PLIN(im, 0, src->xsize, y, out_line);
310 }
311
312 myfree(in_line);
313 myfree(out_line);
314#/code
315
316 return im;
317}
318
f5991c03
TC
319/*
320=back
321
322=head1 SEE ALSO
323
324Imager(3)
325
326=head1 AUTHOR
327
328Tony Cook <tony@develop-help.com>
329
330=cut
331*/