- start of external Imager API access:
[imager.git] / convert.c
CommitLineData
f5991c03
TC
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
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
TC
21
22
23/*
24=item i_convert(im, src, coeff, outchan, inchan)
25
26Converts the image src into another image.
27
28coeff contains the co-efficients of an outchan x inchan matrix, for
29each 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
35If im has the wrong number of channels or is the wrong size then
36i_convert() will re-create it.
37
faa9b3e7
TC
38Now handles images with more than 8-bits/sample.
39
f5991c03
TC
40=cut
41*/
42
43int
a73aeb5f 44i_convert(i_img *im, i_img *src, float *coeff, int outchan, int inchan) {
f5991c03
TC
45 int x, y;
46 int i, j;
a743c0a6 47 int ilimit;
f5991c03
TC
48 double work[MAXCHANNELS];
49
299a3866 50 mm_log((1,"i_convert(im %p, src, %p, coeff %p,outchan %d, inchan %d)\n",im,src, coeff,outchan, inchan));
f5991c03
TC
51
52 i_clear_error();
53
54 ilimit = inchan;
55 if (ilimit > src->channels)
56 ilimit = src->channels;
57 if (outchan > MAXCHANNELS) {
58 i_push_error(0, "cannot have outchan > MAXCHANNELS");
59 return 0;
60 }
61
faa9b3e7
TC
62 if (im->type == i_direct_type || src->type == i_direct_type) {
63 /* first check the output image */
64 if (im->channels != outchan || im->xsize != src->xsize
65 || im->ysize != src->ysize) {
66 i_img_exorcise(im);
67 i_img_empty_ch(im, src->xsize, src->ysize, outchan);
68 }
69 if (im->bits == i_8_bits && src->bits == i_8_bits) {
70 i_color *vals;
f0960b14
TC
71
72 /* we can always allocate a single scanline of i_color */
73 vals = mymalloc(sizeof(i_color) * src->xsize); /* checked 04Jul05 tonyc */
faa9b3e7
TC
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;
f0960b14
TC
101
102 /* we can always allocate a single scanline of i_fcolor
103 for a >8 image */
104 vals = mymalloc(sizeof(i_fcolor) * src->xsize); /* checked 4Jul05 tonyc */
faa9b3e7
TC
105 for (y = 0; y < src->ysize; ++y) {
106 i_glinf(src, 0, src->xsize, y, vals);
107 for (x = 0; x < src->xsize; ++x) {
108 for (j = 0; j < outchan; ++j) {
109 work[j] = 0;
110 for (i = 0; i < ilimit; ++i) {
111 work[j] += coeff[i+inchan*j] * vals[x].channel[i];
112 }
113 if (i < inchan) {
114 work[j] += coeff[i+inchan*j];
115 }
116 }
117 for (j = 0; j < outchan; ++j) {
118 if (work[j] < 0)
119 vals[x].channel[j] = 0;
120 else if (work[j] >= 1)
121 vals[x].channel[j] = 1;
122 else
123 vals[x].channel[j] = work[j];
124 }
125 }
126 i_plinf(im, 0, src->xsize, y, vals);
127 }
128 myfree(vals);
129 }
f5991c03 130 }
faa9b3e7
TC
131 else {
132 int count;
133 int outcount;
134 int index;
135 i_color *colors;
136 i_palidx *vals;
137
138 if (im->channels != outchan || im->xsize != src->xsize
139 || im->ysize != src->ysize
140 || i_maxcolors(im) < i_colorcount(src)) {
141 i_img_exorcise(im);
142 i_img_pal_new_low(im, src->xsize, src->ysize, outchan,
143 i_maxcolors(src));
144 }
145 /* just translate the color table */
146 count = i_colorcount(src);
147 outcount = i_colorcount(im);
f0960b14
TC
148 /* color table allocated for image, so it must fit */
149 colors = mymalloc(count * sizeof(i_color)); /* check 04Jul05 tonyc */
faa9b3e7
TC
150 i_getcolors(src, 0, colors, count);
151 for (index = 0; index < count; ++index) {
f5991c03 152 for (j = 0; j < outchan; ++j) {
faa9b3e7
TC
153 work[j] = 0;
154 for (i = 0; i < ilimit; ++i) {
155 work[j] += coeff[i+inchan*j] * colors[index].channel[i];
156 }
157 if (i < inchan) {
158 work[j] += coeff[i+inchan*j] * 255.9;
159 }
f5991c03
TC
160 }
161 for (j = 0; j < outchan; ++j) {
faa9b3e7
TC
162 if (work[j] < 0)
163 colors[index].channel[j] = 0;
164 else if (work[j] >= 255)
165 colors[index].channel[j] = 255;
166 else
167 colors[index].channel[j] = work[j];
f5991c03
TC
168 }
169 }
faa9b3e7
TC
170 if (count < outcount) {
171 i_setcolors(im, 0, colors, count);
172 }
173 else {
174 i_setcolors(im, 0, colors, outcount);
175 i_addcolors(im, colors, count-outcount);
176 }
177 /* and copy the indicies */
f0960b14
TC
178 /* i_palidx is always unsigned char and will never be bigger than short
179 and since a line of 4-byte i_colors can fit then a line of i_palidx
180 will fit */
181 vals = mymalloc(sizeof(i_palidx) * im->xsize); /* checked 4jul05 tonyc */
faa9b3e7
TC
182 for (y = 0; y < im->ysize; ++y) {
183 i_gpal(src, 0, im->xsize, y, vals);
184 i_ppal(im, 0, im->xsize, y, vals);
185 }
a73aeb5f
AMH
186 myfree(vals);
187 myfree(colors);
f5991c03 188 }
faa9b3e7 189
f5991c03
TC
190 return 1;
191}
192
193/*
194=back
195
196=head1 SEE ALSO
197
198Imager(3)
199
200=head1 AUTHOR
201
202Tony Cook <tony@develop-help.com>
203
204=cut
205*/