X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/628693278076bbfea8cf69d4807be68f0c7bc851..c53290be69f0ac24b6ab74f2e7aab883e2f489d4:/convert.im diff --git a/convert.im b/convert.im index ada2f266..2d5a8a96 100644 --- a/convert.im +++ b/convert.im @@ -5,7 +5,7 @@ =head1 SYNOPSIS - i_convert(outimage, srcimage, coeff, outchans, inchans) + out = i_convert(srcimage, coeff, outchans, inchans) =head1 DESCRIPTION @@ -17,8 +17,31 @@ converting from RGBA to greyscale and back. =cut */ +#define IMAGER_NO_CONTEXT #include "imager.h" +struct chan_copy { + /* channels to copy */ + int copy_count; + int from[MAXCHANNELS]; + int to[MAXCHANNELS]; + + /* channels to zero */ + int zero_count; + int zero[MAXCHANNELS]; + + /* channels to set to maxsample */ + int one_count; + int one[MAXCHANNELS]; +}; + +static int +is_channel_copy(i_img *im, const double *coeff, + int outchan, int inchan, + struct chan_copy *info); + +static i_img * +convert_via_copy(i_img *im, i_img *src, struct chan_copy *info); /* =item i_convert(src, coeff, outchan, inchan) @@ -42,56 +65,65 @@ Now handles images with more than 8-bits/sample. i_img * i_convert(i_img *src, const double *coeff, int outchan, int inchan) { - int x, y; + double work[MAXCHANNELS]; + i_img_dim x, y; int i, j; int ilimit; - double work[MAXCHANNELS]; i_img *im = NULL; + dIMCTXim(src); - mm_log((1,"i_convert(src %p, coeff %p,outchan %d, inchan %d)\n",im,src, coeff,outchan, inchan)); + im_log((aIMCTX,1,"i_convert(im %p, src %p, coeff %p,outchan %d, inchan %d)\n", + im, src, coeff, outchan, inchan)); - i_clear_error(); + im_clear_error(aIMCTX); ilimit = inchan; if (ilimit > src->channels) ilimit = src->channels; if (outchan > MAXCHANNELS) { - i_push_error(0, "cannot have outchan > MAXCHANNELS"); + im_push_error(aIMCTX, 0, "cannot have outchan > MAXCHANNELS"); return 0; } if (src->type == i_direct_type) { + struct chan_copy info; im = i_sametype_chans(src, src->xsize, src->ysize, outchan); -#code src->bits <= i_8_bits - IM_COLOR *vals; - /* we can always allocate a single scanline of i_color */ - vals = mymalloc(sizeof(IM_COLOR) * src->xsize); /* checked 04Jul05 tonyc */ - for (y = 0; y < src->ysize; ++y) { - IM_GLIN(src, 0, src->xsize, y, vals); - for (x = 0; x < src->xsize; ++x) { - for (j = 0; j < outchan; ++j) { - work[j] = 0; - for (i = 0; i < ilimit; ++i) { - work[j] += coeff[i+inchan*j] * vals[x].channel[i]; + if (is_channel_copy(src, coeff, outchan, inchan, &info)) { + return convert_via_copy(im, src, &info); + } + else { +#code src->bits <= i_8_bits + IM_COLOR *vals; + + /* we can always allocate a single scanline of i_color */ + vals = mymalloc(sizeof(IM_COLOR) * src->xsize); /* checked 04Jul05 tonyc */ + for (y = 0; y < src->ysize; ++y) { + IM_GLIN(src, 0, src->xsize, y, vals); + for (x = 0; x < src->xsize; ++x) { + for (j = 0; j < outchan; ++j) { + work[j] = 0; + for (i = 0; i < ilimit; ++i) { + work[j] += coeff[i+inchan*j] * vals[x].channel[i]; + } + if (i < inchan) { + work[j] += coeff[i+inchan*j] * IM_SAMPLE_MAX; + } } - if (i < inchan) { - work[j] += coeff[i+inchan*j] * IM_SAMPLE_MAX; + for (j = 0; j < outchan; ++j) { + if (work[j] < 0) + vals[x].channel[j] = 0; + else if (work[j] >= IM_SAMPLE_MAX) + vals[x].channel[j] = IM_SAMPLE_MAX; + else + vals[x].channel[j] = work[j]; } } - for (j = 0; j < outchan; ++j) { - if (work[j] < 0) - vals[x].channel[j] = 0; - else if (work[j] >= IM_SAMPLE_MAX) - vals[x].channel[j] = IM_SAMPLE_MAX; - else - vals[x].channel[j] = work[j]; - } + IM_PLIN(im, 0, src->xsize, y, vals); } - IM_PLIN(im, 0, src->xsize, y, vals); - } - myfree(vals); + myfree(vals); #/code + } } else { int count; @@ -100,8 +132,8 @@ i_convert(i_img *src, const double *coeff, int outchan, int inchan) { i_color *colors; i_palidx *vals; - im = i_img_pal_new(src->xsize, src->ysize, outchan, - i_maxcolors(src)); + im = im_img_pal_new(aIMCTX, src->xsize, src->ysize, outchan, + i_maxcolors(src)); /* just translate the color table */ count = i_colorcount(src); @@ -151,6 +183,139 @@ i_convert(i_img *src, const double *coeff, int outchan, int inchan) { return im; } +/* +=item is_channel_copy(coeff, outchan, inchan, chan_copy_info) + +Test if the coefficients represent just copying channels around, and +initialize lists of the channels to copy, zero or set to max. + +=cut +*/ + +static +int is_channel_copy(i_img *im, const double *coeff, int outchan, int inchan, + struct chan_copy *info) { + int srcchan[MAXCHANNELS]; + int onechan[MAXCHANNELS]; + int i, j; + int ilimit = im->channels > inchan ? inchan : im->channels; + + for (j = 0; j < outchan; ++j) { + srcchan[j] = -1; + onechan[j] = 0; + } + + for (j = 0; j < outchan; ++j) { + for (i = 0; i < ilimit; ++i) { + if (coeff[i+inchan*j] == 1.0) { + if (srcchan[j] != -1) { + /* from two or more channels, not a copy */ + return 0; + } + srcchan[j] = i; + } + else if (coeff[i+inchan*j]) { + /* some other non-zero value, not a copy */ + return 0; + } + } + if (i < inchan) { + if (coeff[i+inchan*j] == 1.0) { + if (srcchan[j] != -1) { + /* can't do both */ + return 0; + } + onechan[j] = 1; + } + else if (coeff[i+inchan*j]) { + /* some other non-zero value, not a copy */ + return 0; + } + } + } + + /* build our working data structures */ + info->copy_count = info->zero_count = info->one_count = 0; + for (j = 0; j < outchan; ++j) { + if (srcchan[j] != -1) { + info->from[info->copy_count] = srcchan[j]; + info->to[info->copy_count] = j; + ++info->copy_count; + } + else if (onechan[j]) { + info->one[info->one_count] = j; + ++info->one_count; + } + else { + info->zero[info->zero_count] = j; + ++info->zero_count; + } + } + +#if 0 + { + for (i = 0; i < info->copy_count; ++i) { + printf("From %d to %d\n", info->from[i], info->to[i]); + } + for (i = 0; i < info->one_count; ++i) { + printf("One %d\n", info->one[i]); + } + for (i = 0; i < info->zero_count; ++i) { + printf("Zero %d\n", info->zero[i]); + } + fflush(stdout); + } +#endif + + return 1; +} + +/* +=item convert_via_copy(im, src, chan_copy_info) + +Perform a convert that only requires channel copies. + +=cut +*/ + +static i_img * +convert_via_copy(i_img *im, i_img *src, struct chan_copy *info) { +#code src->bits <= i_8_bits + IM_COLOR *in_line = mymalloc(sizeof(IM_COLOR) * src->xsize); + IM_COLOR *out_line = mymalloc(sizeof(IM_COLOR) * src->xsize); + i_img_dim x, y; + int i; + IM_COLOR *inp, *outp; + + for (y = 0; y < src->ysize; ++y) { + IM_GLIN(src, 0, src->xsize, y, in_line); + + inp = in_line; + outp = out_line; + for (x = 0; x < src->xsize; ++x) { + for (i = 0; i < info->copy_count; ++i) { + outp->channel[info->to[i]] = inp->channel[info->from[i]]; + } + for (i = 0; i < info->one_count; ++i) { + outp->channel[info->one[i]] = IM_SAMPLE_MAX; + } + for (i = 0; i < info->zero_count; ++i) { + outp->channel[info->zero[i]] = 0; + } + ++inp; + ++outp; + } + + IM_PLIN(im, 0, src->xsize, y, out_line); + } + + myfree(in_line); + myfree(out_line); +#/code + + return im; +} + /* =back