Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 329 lines (274 sloc) 7.597 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
8 i_convert(outimage, srcimage, coeff, outchans, inchans)
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];
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
68 int x, y;
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
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
73 mm_log((1,"i_convert(src %p, coeff %p,outchan %d, inchan %d)\n",im,src, coeff,outchan, inchan));
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
74
75 i_clear_error();
76
77 ilimit = inchan;
78 if (ilimit > src->channels)
79 ilimit = src->channels;
80 if (outchan > MAXCHANNELS) {
81 i_push_error(0, "cannot have outchan > MAXCHANNELS");
82 return 0;
83 }
84
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
85 if (src->type == i_direct_type) {
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
86 struct chan_copy info;
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
87 im = i_sametype_chans(src, src->xsize, src->ysize, outchan);
6286932 reorganize convert.c to convert.im
Tony Cook authored
88
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
89 if (is_channel_copy(src, coeff, outchan, inchan, &info)) {
90 return convert_via_copy(im, src, &info);
91 }
92 else {
93 #code src->bits <= i_8_bits
94 IM_COLOR *vals;
95
96 /* we can always allocate a single scanline of i_color */
97 vals = mymalloc(sizeof(IM_COLOR) * src->xsize); /* checked 04Jul05 tonyc */
98 for (y = 0; y < src->ysize; ++y) {
99 IM_GLIN(src, 0, src->xsize, y, vals);
100 for (x = 0; x < src->xsize; ++x) {
101 for (j = 0; j < outchan; ++j) {
102 work[j] = 0;
103 for (i = 0; i < ilimit; ++i) {
104 work[j] += coeff[i+inchan*j] * vals[x].channel[i];
105 }
106 if (i < inchan) {
107 work[j] += coeff[i+inchan*j] * IM_SAMPLE_MAX;
108 }
6286932 reorganize convert.c to convert.im
Tony Cook authored
109 }
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
110 for (j = 0; j < outchan; ++j) {
111 if (work[j] < 0)
112 vals[x].channel[j] = 0;
113 else if (work[j] >= IM_SAMPLE_MAX)
114 vals[x].channel[j] = IM_SAMPLE_MAX;
115 else
116 vals[x].channel[j] = work[j];
6286932 reorganize convert.c to convert.im
Tony Cook authored
117 }
118 }
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
119 IM_PLIN(im, 0, src->xsize, y, vals);
faa9b3e Egads
Tony Cook authored
120 }
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
121 myfree(vals);
6286932 reorganize convert.c to convert.im
Tony Cook authored
122 #/code
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
123 }
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
124 }
faa9b3e Egads
Tony Cook authored
125 else {
126 int count;
127 int outcount;
128 int index;
129 i_color *colors;
130 i_palidx *vals;
131
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
132 im = i_img_pal_new(src->xsize, src->ysize, outchan,
133 i_maxcolors(src));
134
faa9b3e Egads
Tony Cook authored
135 /* just translate the color table */
136 count = i_colorcount(src);
137 outcount = i_colorcount(im);
f0960b1 - added integer overflow checks to many memory allocation calls
Tony Cook authored
138 /* color table allocated for image, so it must fit */
139 colors = mymalloc(count * sizeof(i_color)); /* check 04Jul05 tonyc */
faa9b3e Egads
Tony Cook authored
140 i_getcolors(src, 0, colors, count);
141 for (index = 0; index < count; ++index) {
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
142 for (j = 0; j < outchan; ++j) {
faa9b3e Egads
Tony Cook authored
143 work[j] = 0;
144 for (i = 0; i < ilimit; ++i) {
145 work[j] += coeff[i+inchan*j] * colors[index].channel[i];
146 }
147 if (i < inchan) {
148 work[j] += coeff[i+inchan*j] * 255.9;
149 }
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
150 }
151 for (j = 0; j < outchan; ++j) {
faa9b3e Egads
Tony Cook authored
152 if (work[j] < 0)
153 colors[index].channel[j] = 0;
154 else if (work[j] >= 255)
155 colors[index].channel[j] = 255;
156 else
157 colors[index].channel[j] = work[j];
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
158 }
159 }
faa9b3e Egads
Tony Cook authored
160 if (count < outcount) {
161 i_setcolors(im, 0, colors, count);
162 }
163 else {
164 i_setcolors(im, 0, colors, outcount);
165 i_addcolors(im, colors, count-outcount);
166 }
167 /* and copy the indicies */
f0960b1 - added integer overflow checks to many memory allocation calls
Tony Cook authored
168 /* i_palidx is always unsigned char and will never be bigger than short
169 and since a line of 4-byte i_colors can fit then a line of i_palidx
170 will fit */
171 vals = mymalloc(sizeof(i_palidx) * im->xsize); /* checked 4jul05 tonyc */
faa9b3e Egads
Tony Cook authored
172 for (y = 0; y < im->ysize; ++y) {
173 i_gpal(src, 0, im->xsize, y, vals);
174 i_ppal(im, 0, im->xsize, y, vals);
175 }
a73aeb5 Fixed most outstanding memory leaks that are revealed in the test cases.
Arnar Mar Hrafnkelsson authored
176 myfree(vals);
177 myfree(colors);
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
178 }
faa9b3e Egads
Tony Cook authored
179
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
180 return im;
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
181 }
182
183 /*
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
184 =item is_channel_copy(coeff, outchan, inchan, chan_copy_info)
185
186 Test if the coefficients represent just copying channels around, and
187 initialize lists of the channels to copy, zero or set to max.
188
189 =cut
190 */
191
192 static
193 int is_channel_copy(i_img *im, const double *coeff, int outchan, int inchan,
194 struct chan_copy *info) {
195 int srcchan[MAXCHANNELS];
196 int onechan[MAXCHANNELS];
197 int i, j;
198 int ilimit = im->channels > inchan ? inchan : im->channels;
199
200 for (j = 0; j < outchan; ++j) {
201 srcchan[j] = -1;
202 onechan[j] = 0;
203 }
204
205 for (j = 0; j < outchan; ++j) {
206 for (i = 0; i < ilimit; ++i) {
207 if (coeff[i+inchan*j] == 1.0) {
208 if (srcchan[j] != -1) {
209 /* from two or more channels, not a copy */
210 return 0;
211 }
212 srcchan[j] = i;
213 }
214 else if (coeff[i+inchan*j]) {
215 /* some other non-zero value, not a copy */
216 return 0;
217 }
218 }
219 if (i < inchan) {
220 if (coeff[i+inchan*j] == 1.0) {
221 if (srcchan[j] != -1) {
222 /* can't do both */
223 return 0;
224 }
225 onechan[j] = 1;
226 }
227 else if (coeff[i+inchan*j]) {
228 /* some other non-zero value, not a copy */
229 return 0;
230 }
231 }
232 }
233
234 /* build our working data structures */
235 info->copy_count = info->zero_count = info->one_count = 0;
236 for (j = 0; j < outchan; ++j) {
237 if (srcchan[j] != -1) {
238 info->from[info->copy_count] = srcchan[j];
239 info->to[info->copy_count] = j;
240 ++info->copy_count;
241 }
242 else if (onechan[j]) {
243 info->one[info->one_count] = j;
244 ++info->one_count;
245 }
246 else {
247 info->zero[info->zero_count] = j;
248 ++info->zero_count;
249 }
250 }
251
252 #if 0
253 {
254 for (i = 0; i < info->copy_count; ++i) {
255 printf("From %d to %d\n", info->from[i], info->to[i]);
256 }
257 for (i = 0; i < info->one_count; ++i) {
258 printf("One %d\n", info->one[i]);
259 }
260 for (i = 0; i < info->zero_count; ++i) {
261 printf("Zero %d\n", info->zero[i]);
262 }
263 fflush(stdout);
264 }
265 #endif
266
267 return 1;
268 }
269
270 /*
271 =item convert_via_copy(im, src, chan_copy_info)
272
273 Perform a convert that only requires channel copies.
274
275 =cut
276 */
277
278 i_img *
279 convert_via_copy(i_img *im, i_img *src, struct chan_copy *info) {
280 #code src->bits <= i_8_bits
281 IM_COLOR *in_line = mymalloc(sizeof(IM_COLOR) * src->xsize);
282 IM_COLOR *out_line = mymalloc(sizeof(IM_COLOR) * src->xsize);
283 i_img_dim x, y;
284 int i;
285 IM_COLOR *inp, *outp;
286
287 for (y = 0; y < src->ysize; ++y) {
288 IM_GLIN(src, 0, src->xsize, y, in_line);
289
290 inp = in_line;
291 outp = out_line;
292 for (x = 0; x < src->xsize; ++x) {
293 for (i = 0; i < info->copy_count; ++i) {
294 outp->channel[info->to[i]] = inp->channel[info->from[i]];
295 }
296 for (i = 0; i < info->one_count; ++i) {
297 outp->channel[info->one[i]] = IM_SAMPLE_MAX;
298 }
299 for (i = 0; i < info->zero_count; ++i) {
300 outp->channel[info->zero[i]] = 0;
301 }
302 ++inp;
303 ++outp;
304 }
305
306 IM_PLIN(im, 0, src->xsize, y, out_line);
307 }
308
309 myfree(in_line);
310 myfree(out_line);
311 #/code
312
313 return im;
314 }
315
316 /*
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
317 =back
318
319 =head1 SEE ALSO
320
321 Imager(3)
322
323 =head1 AUTHOR
324
325 Tony Cook <tony@develop-help.com>
326
327 =cut
328 */
Something went wrong with that request. Please try again.