Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 332 lines (277 sloc) 7.688 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
b571048 @tonycoz update convert.im to IMAGER_NO_CONTEXT
authored
20 #define IMAGER_NO_CONTEXT
92bda63 - start of external Imager API access:
Tony Cook authored
21 #include "imager.h"
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
22
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
23 struct chan_copy {
24 /* channels to copy */
25 int copy_count;
26 int from[MAXCHANNELS];
27 int to[MAXCHANNELS];
28
29 /* channels to zero */
30 int zero_count;
31 int zero[MAXCHANNELS];
32
33 /* channels to set to maxsample */
34 int one_count;
35 int one[MAXCHANNELS];
36 };
37
38 static int
39 is_channel_copy(i_img *im, const double *coeff,
40 int outchan, int inchan,
41 struct chan_copy *info);
42
43 static i_img *
44 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
45
46 /*
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
47 =item i_convert(src, coeff, outchan, inchan)
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
48
49 Converts the image src into another image.
50
51 coeff contains the co-efficients of an outchan x inchan matrix, for
52 each output pixel:
53
54 coeff[0], coeff[1] ...
55 im[x,y] = [ coeff[inchan], coeff[inchan+1]... ] * [ src[x,y], 1]
56 ... coeff[inchan*outchan-1]
57
58 If im has the wrong number of channels or is the wrong size then
59 i_convert() will re-create it.
60
faa9b3e Egads
Tony Cook authored
61 Now handles images with more than 8-bits/sample.
62
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
63 =cut
64 */
65
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
66 i_img *
6286932 reorganize convert.c to convert.im
Tony Cook authored
67 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
68 double work[MAXCHANNELS];
8d14daa @tonycoz switch to using size_t and i_img_dim strictly
authored
69 i_img_dim x, y;
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
70 int i, j;
a743c0a Removed a bunch of unused variables and fixed an attempt to print out a
Arnar Mar Hrafnkelsson authored
71 int ilimit;
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
72 i_img *im = NULL;
b571048 @tonycoz update convert.im to IMAGER_NO_CONTEXT
authored
73 dIMCTXim(src);
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
74
b571048 @tonycoz update convert.im to IMAGER_NO_CONTEXT
authored
75 im_log((aIMCTX,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
76 im, src, coeff, outchan, inchan));
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
77
b571048 @tonycoz update convert.im to IMAGER_NO_CONTEXT
authored
78 im_clear_error(aIMCTX);
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
79
80 ilimit = inchan;
81 if (ilimit > src->channels)
82 ilimit = src->channels;
83 if (outchan > MAXCHANNELS) {
b571048 @tonycoz update convert.im to IMAGER_NO_CONTEXT
authored
84 im_push_error(aIMCTX, 0, "cannot have outchan > MAXCHANNELS");
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
85 return 0;
86 }
87
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
88 if (src->type == i_direct_type) {
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
89 struct chan_copy info;
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
90 im = i_sametype_chans(src, src->xsize, src->ysize, outchan);
6286932 reorganize convert.c to convert.im
Tony Cook authored
91
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
92 if (is_channel_copy(src, coeff, outchan, inchan, &info)) {
93 return convert_via_copy(im, src, &info);
94 }
95 else {
96 #code src->bits <= i_8_bits
97 IM_COLOR *vals;
98
99 /* we can always allocate a single scanline of i_color */
100 vals = mymalloc(sizeof(IM_COLOR) * src->xsize); /* checked 04Jul05 tonyc */
101 for (y = 0; y < src->ysize; ++y) {
102 IM_GLIN(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] * IM_SAMPLE_MAX;
111 }
6286932 reorganize convert.c to convert.im
Tony Cook authored
112 }
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
113 for (j = 0; j < outchan; ++j) {
114 if (work[j] < 0)
115 vals[x].channel[j] = 0;
116 else if (work[j] >= IM_SAMPLE_MAX)
117 vals[x].channel[j] = IM_SAMPLE_MAX;
118 else
119 vals[x].channel[j] = work[j];
6286932 reorganize convert.c to convert.im
Tony Cook authored
120 }
121 }
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
122 IM_PLIN(im, 0, src->xsize, y, vals);
faa9b3e Egads
Tony Cook authored
123 }
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
124 myfree(vals);
6286932 reorganize convert.c to convert.im
Tony Cook authored
125 #/code
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
126 }
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
127 }
faa9b3e Egads
Tony Cook authored
128 else {
129 int count;
130 int outcount;
131 int index;
132 i_color *colors;
133 i_palidx *vals;
134
b571048 @tonycoz update convert.im to IMAGER_NO_CONTEXT
authored
135 im = im_img_pal_new(aIMCTX, src->xsize, src->ysize, outchan,
136 i_maxcolors(src));
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
137
faa9b3e Egads
Tony Cook authored
138 /* just translate the color table */
139 count = i_colorcount(src);
140 outcount = i_colorcount(im);
f0960b1 - added integer overflow checks to many memory allocation calls
Tony Cook authored
141 /* color table allocated for image, so it must fit */
142 colors = mymalloc(count * sizeof(i_color)); /* check 04Jul05 tonyc */
faa9b3e Egads
Tony Cook authored
143 i_getcolors(src, 0, colors, count);
144 for (index = 0; index < count; ++index) {
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
145 for (j = 0; j < outchan; ++j) {
faa9b3e Egads
Tony Cook authored
146 work[j] = 0;
147 for (i = 0; i < ilimit; ++i) {
148 work[j] += coeff[i+inchan*j] * colors[index].channel[i];
149 }
150 if (i < inchan) {
151 work[j] += coeff[i+inchan*j] * 255.9;
152 }
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
153 }
154 for (j = 0; j < outchan; ++j) {
faa9b3e Egads
Tony Cook authored
155 if (work[j] < 0)
156 colors[index].channel[j] = 0;
157 else if (work[j] >= 255)
158 colors[index].channel[j] = 255;
159 else
160 colors[index].channel[j] = work[j];
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
161 }
162 }
faa9b3e Egads
Tony Cook authored
163 if (count < outcount) {
164 i_setcolors(im, 0, colors, count);
165 }
166 else {
167 i_setcolors(im, 0, colors, outcount);
168 i_addcolors(im, colors, count-outcount);
169 }
170 /* and copy the indicies */
f0960b1 - added integer overflow checks to many memory allocation calls
Tony Cook authored
171 /* i_palidx is always unsigned char and will never be bigger than short
172 and since a line of 4-byte i_colors can fit then a line of i_palidx
173 will fit */
174 vals = mymalloc(sizeof(i_palidx) * im->xsize); /* checked 4jul05 tonyc */
faa9b3e Egads
Tony Cook authored
175 for (y = 0; y < im->ysize; ++y) {
176 i_gpal(src, 0, im->xsize, y, vals);
177 i_ppal(im, 0, im->xsize, y, vals);
178 }
a73aeb5 Fixed most outstanding memory leaks that are revealed in the test cases.
Arnar Mar Hrafnkelsson authored
179 myfree(vals);
180 myfree(colors);
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
181 }
faa9b3e Egads
Tony Cook authored
182
d5477d3 - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
Tony Cook authored
183 return im;
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
184 }
185
186 /*
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
187 =item is_channel_copy(coeff, outchan, inchan, chan_copy_info)
188
189 Test if the coefficients represent just copying channels around, and
190 initialize lists of the channels to copy, zero or set to max.
191
192 =cut
193 */
194
195 static
196 int is_channel_copy(i_img *im, const double *coeff, int outchan, int inchan,
197 struct chan_copy *info) {
198 int srcchan[MAXCHANNELS];
199 int onechan[MAXCHANNELS];
200 int i, j;
201 int ilimit = im->channels > inchan ? inchan : im->channels;
202
203 for (j = 0; j < outchan; ++j) {
204 srcchan[j] = -1;
205 onechan[j] = 0;
206 }
207
208 for (j = 0; j < outchan; ++j) {
209 for (i = 0; i < ilimit; ++i) {
210 if (coeff[i+inchan*j] == 1.0) {
211 if (srcchan[j] != -1) {
212 /* from two or more channels, not a copy */
213 return 0;
214 }
215 srcchan[j] = i;
216 }
217 else if (coeff[i+inchan*j]) {
218 /* some other non-zero value, not a copy */
219 return 0;
220 }
221 }
222 if (i < inchan) {
223 if (coeff[i+inchan*j] == 1.0) {
224 if (srcchan[j] != -1) {
225 /* can't do both */
226 return 0;
227 }
228 onechan[j] = 1;
229 }
230 else if (coeff[i+inchan*j]) {
231 /* some other non-zero value, not a copy */
232 return 0;
233 }
234 }
235 }
236
237 /* build our working data structures */
238 info->copy_count = info->zero_count = info->one_count = 0;
239 for (j = 0; j < outchan; ++j) {
240 if (srcchan[j] != -1) {
241 info->from[info->copy_count] = srcchan[j];
242 info->to[info->copy_count] = j;
243 ++info->copy_count;
244 }
245 else if (onechan[j]) {
246 info->one[info->one_count] = j;
247 ++info->one_count;
248 }
249 else {
250 info->zero[info->zero_count] = j;
251 ++info->zero_count;
252 }
253 }
254
255 #if 0
256 {
257 for (i = 0; i < info->copy_count; ++i) {
258 printf("From %d to %d\n", info->from[i], info->to[i]);
259 }
260 for (i = 0; i < info->one_count; ++i) {
261 printf("One %d\n", info->one[i]);
262 }
263 for (i = 0; i < info->zero_count; ++i) {
264 printf("Zero %d\n", info->zero[i]);
265 }
266 fflush(stdout);
267 }
268 #endif
269
270 return 1;
271 }
272
273 /*
274 =item convert_via_copy(im, src, chan_copy_info)
275
276 Perform a convert that only requires channel copies.
277
278 =cut
279 */
280
6f43652 @tonycoz fix a static vs extern function mismatch
authored
281 static i_img *
2a2c791 the convert() method now optimizes the case where all output
Tony Cook authored
282 convert_via_copy(i_img *im, i_img *src, struct chan_copy *info) {
283 #code src->bits <= i_8_bits
284 IM_COLOR *in_line = mymalloc(sizeof(IM_COLOR) * src->xsize);
285 IM_COLOR *out_line = mymalloc(sizeof(IM_COLOR) * src->xsize);
286 i_img_dim x, y;
287 int i;
288 IM_COLOR *inp, *outp;
289
290 for (y = 0; y < src->ysize; ++y) {
291 IM_GLIN(src, 0, src->xsize, y, in_line);
292
293 inp = in_line;
294 outp = out_line;
295 for (x = 0; x < src->xsize; ++x) {
296 for (i = 0; i < info->copy_count; ++i) {
297 outp->channel[info->to[i]] = inp->channel[info->from[i]];
298 }
299 for (i = 0; i < info->one_count; ++i) {
300 outp->channel[info->one[i]] = IM_SAMPLE_MAX;
301 }
302 for (i = 0; i < info->zero_count; ++i) {
303 outp->channel[info->zero[i]] = 0;
304 }
305 ++inp;
306 ++outp;
307 }
308
309 IM_PLIN(im, 0, src->xsize, y, out_line);
310 }
311
312 myfree(in_line);
313 myfree(out_line);
314 #/code
315
316 return im;
317 }
318
319 /*
f5991c0 implement the convert() method for converting between numbers of chan…
Tony Cook authored
320 =back
321
322 =head1 SEE ALSO
323
324 Imager(3)
325
326 =head1 AUTHOR
327
328 Tony Cook <tony@develop-help.com>
329
330 =cut
331 */
Something went wrong with that request. Please try again.