load Imager::Color::Float in NCF
[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/*
d5477d3d 24=item i_convert(src, coeff, outchan, inchan)
f5991c03
TC
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
d5477d3d
TC
43i_img *
44i_convert(i_img *src, const float *coeff, int outchan, int inchan) {
f5991c03
TC
45 int x, y;
46 int i, j;
a743c0a6 47 int ilimit;
f5991c03 48 double work[MAXCHANNELS];
d5477d3d 49 i_img *im = NULL;
f5991c03 50
d5477d3d 51 mm_log((1,"i_convert(src %p, coeff %p,outchan %d, inchan %d)\n",im,src, coeff,outchan, inchan));
f5991c03
TC
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
d5477d3d
TC
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) {
faa9b3e7 66 i_color *vals;
f0960b14
TC
67
68 /* we can always allocate a single scanline of i_color */
69 vals = mymalloc(sizeof(i_color) * src->xsize); /* checked 04Jul05 tonyc */
faa9b3e7
TC
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;
f0960b14
TC
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 */
faa9b3e7
TC
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 }
f5991c03 126 }
faa9b3e7
TC
127 else {
128 int count;
129 int outcount;
130 int index;
131 i_color *colors;
132 i_palidx *vals;
133
d5477d3d
TC
134 im = i_img_pal_new(src->xsize, src->ysize, outchan,
135 i_maxcolors(src));
136
faa9b3e7
TC
137 /* just translate the color table */
138 count = i_colorcount(src);
139 outcount = i_colorcount(im);
f0960b14
TC
140 /* color table allocated for image, so it must fit */
141 colors = mymalloc(count * sizeof(i_color)); /* check 04Jul05 tonyc */
faa9b3e7
TC
142 i_getcolors(src, 0, colors, count);
143 for (index = 0; index < count; ++index) {
f5991c03 144 for (j = 0; j < outchan; ++j) {
faa9b3e7
TC
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 }
f5991c03
TC
152 }
153 for (j = 0; j < outchan; ++j) {
faa9b3e7
TC
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];
f5991c03
TC
160 }
161 }
faa9b3e7
TC
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 */
f0960b14
TC
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 */
faa9b3e7
TC
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 }
a73aeb5f
AMH
178 myfree(vals);
179 myfree(colors);
f5991c03 180 }
faa9b3e7 181
d5477d3d 182 return im;
f5991c03
TC
183}
184
185/*
186=back
187
188=head1 SEE ALSO
189
190Imager(3)
191
192=head1 AUTHOR
193
194Tony Cook <tony@develop-help.com>
195
196=cut
197*/