Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 330 lines (275 sloc) 7.612 kB
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
1 /*
2 =head1 NAME
3
6286932 reorganize convert.c to convert.im
Tony Cook authored
4 convert.im - image conversions
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
5
6 =head1 SYNOPSIS
7
55ebcc7 correct synopsis
Tony Cook authored
8 out = i_convert(srcimage, coeff, outchans, inchans)
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
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
20 #include "imager.h"
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
21
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
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
44
45 /*
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
46 =item i_convert(src, coeff, outchan, inchan)
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
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
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
62 =cut
63 */
64
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
65 i_img *
6286932 reorganize convert.c to convert.im
Tony Cook authored
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
67 double work[MAXCHANNELS];
8d14daa @tonycoz switch to using size_t and i_img_dim strictly
authored
68 i_img_dim x, y;
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
69 int i, j;
a743c0a Removed a bunch of unused variables and fixed an attempt to print out a
Arnar Mar Hrafnkelsson authored
70 int ilimit;
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
71 i_img *im = NULL;
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
72
8d14daa @tonycoz switch to using size_t and i_img_dim strictly
authored
73 mm_log((1,"i_convert(im %p, src %p, coeff %p,outchan %d, inchan %d)\n",
74 im, src, coeff, outchan, inchan));
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
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
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
86 if (src->type == i_direct_type) {
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
87 struct chan_copy info;
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
88 im = i_sametype_chans(src, src->xsize, src->ysize, outchan);
6286932 reorganize convert.c to convert.im
Tony Cook authored
89
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
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
110 }
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
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
118 }
119 }
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
120 IM_PLIN(im, 0, src->xsize, y, vals);
faa9b3e Egads
Tony Cook authored
121 }
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
122 myfree(vals);
6286932 reorganize convert.c to convert.im
Tony Cook authored
123 #/code
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
124 }
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
125 }
faa9b3e Egads
Tony Cook authored
126 else {
127 int count;
128 int outcount;
129 int index;
130 i_color *colors;
131 i_palidx *vals;
132
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
133 im = i_img_pal_new(src->xsize, src->ysize, outchan,
134 i_maxcolors(src));
135
faa9b3e Egads
Tony Cook authored
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
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
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
143 for (j = 0; j < outchan; ++j) {
faa9b3e Egads
Tony Cook authored
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
151 }
152 for (j = 0; j < outchan; ++j) {
faa9b3e Egads
Tony Cook authored
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
159 }
160 }
faa9b3e Egads
Tony Cook authored
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
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
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
177 myfree(vals);
178 myfree(colors);
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
179 }
faa9b3e Egads
Tony Cook authored
180
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
181 return im;
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
182 }
183
184 /*
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
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
279 i_img *
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
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.