1/* 2=head1 NAME 3 4 convert.im - image conversions 5 6=head1 SYNOPSIS 7 8 out = i_convert(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 20#define IMAGER_NO_CONTEXT 21#include "imager.h" 22 23struct 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 38static int 39is_channel_copy(i_img *im, const double *coeff, 40 int outchan, int inchan, 41 struct chan_copy *info); 42 43static i_img * 44convert_via_copy(i_img *im, i_img *src, struct chan_copy *info); 45 46/* 47=item i_convert(src, coeff, outchan, inchan) 48 49Converts the image src into another image. 50 51coeff contains the co-efficients of an outchan x inchan matrix, for 52each 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 58If im has the wrong number of channels or is the wrong size then 59i_convert() will re-create it. 60 61Now handles images with more than 8-bits/sample. 62 63=cut 64*/ 65 66i_img * 67i_convert(i_img *src, const double *coeff, int outchan, int inchan) { 68 double work[MAXCHANNELS]; 69 i_img_dim x, y; 70 int i, j; 71 int ilimit; 72 i_img *im = NULL; 73 dIMCTXim(src); 74 75 im_log((aIMCTX,1,"i_convert(im %p, src %p, coeff %p,outchan %d, inchan %d)\n", 76 im, src, coeff, outchan, inchan)); 77 78 im_clear_error(aIMCTX); 79 80 ilimit = inchan; 81 if (ilimit > src->channels) 82 ilimit = src->channels; 83 if (outchan > MAXCHANNELS) { 84 im_push_error(aIMCTX, 0, "cannot have outchan > MAXCHANNELS"); 85 return 0; 86 } 87 88 if (src->type == i_direct_type) { 89 struct chan_copy info; 90 im = i_sametype_chans(src, src->xsize, src->ysize, outchan); 91 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 } 112 } 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]; 120 } 121 } 122 IM_PLIN(im, 0, src->xsize, y, vals); 123 } 124 myfree(vals); 125#/code 126 } 127 } 128 else { 129 int count; 130 int outcount; 131 int index; 132 i_color *colors; 133 i_palidx *vals; 134 135 im = im_img_pal_new(aIMCTX, src->xsize, src->ysize, outchan, 136 i_maxcolors(src)); 137 138 /* just translate the color table */ 139 count = i_colorcount(src); 140 outcount = i_colorcount(im); 141 /* color table allocated for image, so it must fit */ 142 colors = mymalloc(count * sizeof(i_color)); /* check 04Jul05 tonyc */ 143 i_getcolors(src, 0, colors, count); 144 for (index = 0; index < count; ++index) { 145 for (j = 0; j < outchan; ++j) { 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 } 153 } 154 for (j = 0; j < outchan; ++j) { 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]; 161 } 162 } 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 */ 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 */ 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 } 179 myfree(vals); 180 myfree(colors); 181 } 182 183 return im; 184} 185 186/* 187=item is_channel_copy(coeff, outchan, inchan, chan_copy_info) 188 189Test if the coefficients represent just copying channels around, and 190initialize lists of the channels to copy, zero or set to max. 191 192=cut 193*/ 194 195static 196int 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 276Perform a convert that only requires channel copies. 277 278=cut 279*/ 280 281static i_img * 282convert_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/* 320=back 321 322=head1 SEE ALSO 323 324Imager(3) 325 326=head1 AUTHOR 327 328Tony Cook <tony@develop-help.com> 329 330=cut 331*/ 332