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