Skip to content
Newer
Older
100644 330 lines (275 sloc) 7.44 KB
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
1 /*
2 =head1 NAME
3
6286932 reorganize convert.c to convert.im
Tony Cook authored Oct 23, 2010
4 convert.im - image conversions
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
5
6 =head1 SYNOPSIS
7
55ebcc7 correct synopsis
Tony Cook authored Oct 31, 2010
8 out = i_convert(srcimage, coeff, outchans, inchans)
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
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
92bda63 - start of external Imager API access:
Tony Cook authored Jan 10, 2006
20 #include "imager.h"
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
21
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored Oct 24, 2010
22 struct 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
37 static int
38 is_channel_copy(i_img *im, const double *coeff,
39 int outchan, int inchan,
40 struct chan_copy *info);
41
42 static i_img *
43 convert_via_copy(i_img *im, i_img *src, struct chan_copy *info);
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
44
45 /*
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored Jul 31, 2007
46 =item i_convert(src, coeff, outchan, inchan)
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
47
48 Converts the image src into another image.
49
50 coeff contains the co-efficients of an outchan x inchan matrix, for
51 each 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
57 If im has the wrong number of channels or is the wrong size then
58 i_convert() will re-create it.
59
faa9b3e Egads
Tony Cook authored Aug 13, 2001
60 Now handles images with more than 8-bits/sample.
61
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
62 =cut
63 */
64
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored Jul 31, 2007
65 i_img *
6286932 reorganize convert.c to convert.im
Tony Cook authored Oct 23, 2010
66 i_convert(i_img *src, const double *coeff, int outchan, int inchan) {
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored Oct 24, 2010
67 double work[MAXCHANNELS];
8d14daa @tonycoz switch to using size_t and i_img_dim strictly
authored Jun 14, 2011
68 i_img_dim x, y;
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
69 int i, j;
a743c0a Removed a bunch of unused variables and fixed an attempt to print out a
Arnar Mar Hrafnkelsson authored May 14, 2001
70 int ilimit;
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored Jul 31, 2007
71 i_img *im = NULL;
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
72
d03fd5a @tonycoz revert threading changes, they aren't ready for the mainline yet
authored Sep 29, 2012
73 mm_log((1,"i_convert(im %p, src %p, coeff %p,outchan %d, inchan %d)\n",
8d14daa @tonycoz switch to using size_t and i_img_dim strictly
authored Jun 14, 2011
74 im, src, coeff, outchan, inchan));
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
75
d03fd5a @tonycoz revert threading changes, they aren't ready for the mainline yet
authored Sep 29, 2012
76 i_clear_error();
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
77
78 ilimit = inchan;
79 if (ilimit > src->channels)
80 ilimit = src->channels;
81 if (outchan > MAXCHANNELS) {
d03fd5a @tonycoz revert threading changes, they aren't ready for the mainline yet
authored Sep 29, 2012
82 i_push_error(0, "cannot have outchan > MAXCHANNELS");
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
83 return 0;
84 }
85
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored Jul 31, 2007
86 if (src->type == i_direct_type) {
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored Oct 24, 2010
87 struct chan_copy info;
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored Jul 31, 2007
88 im = i_sametype_chans(src, src->xsize, src->ysize, outchan);
6286932 reorganize convert.c to convert.im
Tony Cook authored Oct 23, 2010
89
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored Oct 24, 2010
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 }
6286932 reorganize convert.c to convert.im
Tony Cook authored Oct 23, 2010
110 }
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored Oct 24, 2010
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];
6286932 reorganize convert.c to convert.im
Tony Cook authored Oct 23, 2010
118 }
119 }
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored Oct 24, 2010
120 IM_PLIN(im, 0, src->xsize, y, vals);
faa9b3e Egads
Tony Cook authored Aug 13, 2001
121 }
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored Oct 24, 2010
122 myfree(vals);
6286932 reorganize convert.c to convert.im
Tony Cook authored Oct 23, 2010
123 #/code
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored Oct 24, 2010
124 }
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
125 }
faa9b3e Egads
Tony Cook authored Aug 13, 2001
126 else {
127 int count;
128 int outcount;
129 int index;
130 i_color *colors;
131 i_palidx *vals;
132
d03fd5a @tonycoz revert threading changes, they aren't ready for the mainline yet
authored Sep 29, 2012
133 im = i_img_pal_new(src->xsize, src->ysize, outchan,
134 i_maxcolors(src));
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored Jul 31, 2007
135
faa9b3e Egads
Tony Cook authored Aug 13, 2001
136 /* just translate the color table */
137 count = i_colorcount(src);
138 outcount = i_colorcount(im);
f0960b1 - added integer overflow checks to many memory allocation calls
Tony Cook authored Dec 5, 2005
139 /* color table allocated for image, so it must fit */
140 colors = mymalloc(count * sizeof(i_color)); /* check 04Jul05 tonyc */
faa9b3e Egads
Tony Cook authored Aug 13, 2001
141 i_getcolors(src, 0, colors, count);
142 for (index = 0; index < count; ++index) {
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
143 for (j = 0; j < outchan; ++j) {
faa9b3e Egads
Tony Cook authored Aug 13, 2001
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 }
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
151 }
152 for (j = 0; j < outchan; ++j) {
faa9b3e Egads
Tony Cook authored Aug 13, 2001
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];
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
159 }
160 }
faa9b3e Egads
Tony Cook authored Aug 13, 2001
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 */
f0960b1 - added integer overflow checks to many memory allocation calls
Tony Cook authored Dec 5, 2005
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 */
faa9b3e Egads
Tony Cook authored Aug 13, 2001
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 }
a73aeb5 Fixed most outstanding memory leaks that are revealed in the test cases.
Arnar Mar Hrafnkelsson authored Nov 1, 2001
177 myfree(vals);
178 myfree(colors);
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
179 }
faa9b3e Egads
Tony Cook authored Aug 13, 2001
180
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored Jul 31, 2007
181 return im;
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
182 }
183
184 /*
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored Oct 24, 2010
185 =item is_channel_copy(coeff, outchan, inchan, chan_copy_info)
186
187 Test if the coefficients represent just copying channels around, and
188 initialize lists of the channels to copy, zero or set to max.
189
190 =cut
191 */
192
193 static
194 int 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
274 Perform a convert that only requires channel copies.
275
276 =cut
277 */
278
6f43652 @tonycoz fix a static vs extern function mismatch
authored Aug 11, 2012
279 static i_img *
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored Oct 24, 2010
280 convert_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
317 /*
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored May 9, 2001
318 =back
319
320 =head1 SEE ALSO
321
322 Imager(3)
323
324 =head1 AUTHOR
325
326 Tony Cook <tony@develop-help.com>
327
328 =cut
329 */
Something went wrong with that request. Please try again.