Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

330 lines (275 sloc) 7.612 kb
/*
=head1 NAME
convert.im - image conversions
=head1 SYNOPSIS
out = i_convert(srcimage, coeff, outchans, inchans)
=head1 DESCRIPTION
Converts images from one format to another, typically in this case for
converting from RGBA to greyscale and back.
=over
=cut
*/
#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)
Converts the image src into another image.
coeff contains the co-efficients of an outchan x inchan matrix, for
each output pixel:
coeff[0], coeff[1] ...
im[x,y] = [ coeff[inchan], coeff[inchan+1]... ] * [ src[x,y], 1]
... coeff[inchan*outchan-1]
If im has the wrong number of channels or is the wrong size then
i_convert() will re-create it.
Now handles images with more than 8-bits/sample.
=cut
*/
i_img *
i_convert(i_img *src, const double *coeff, int outchan, int inchan) {
double work[MAXCHANNELS];
i_img_dim x, y;
int i, j;
int ilimit;
i_img *im = NULL;
mm_log((1,"i_convert(im %p, src %p, coeff %p,outchan %d, inchan %d)\n",
im, src, coeff, outchan, inchan));
i_clear_error();
ilimit = inchan;
if (ilimit > src->channels)
ilimit = src->channels;
if (outchan > MAXCHANNELS) {
i_push_error(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);
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;
}
}
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);
}
myfree(vals);
#/code
}
}
else {
int count;
int outcount;
int index;
i_color *colors;
i_palidx *vals;
im = i_img_pal_new(src->xsize, src->ysize, outchan,
i_maxcolors(src));
/* just translate the color table */
count = i_colorcount(src);
outcount = i_colorcount(im);
/* color table allocated for image, so it must fit */
colors = mymalloc(count * sizeof(i_color)); /* check 04Jul05 tonyc */
i_getcolors(src, 0, colors, count);
for (index = 0; index < count; ++index) {
for (j = 0; j < outchan; ++j) {
work[j] = 0;
for (i = 0; i < ilimit; ++i) {
work[j] += coeff[i+inchan*j] * colors[index].channel[i];
}
if (i < inchan) {
work[j] += coeff[i+inchan*j] * 255.9;
}
}
for (j = 0; j < outchan; ++j) {
if (work[j] < 0)
colors[index].channel[j] = 0;
else if (work[j] >= 255)
colors[index].channel[j] = 255;
else
colors[index].channel[j] = work[j];
}
}
if (count < outcount) {
i_setcolors(im, 0, colors, count);
}
else {
i_setcolors(im, 0, colors, outcount);
i_addcolors(im, colors, count-outcount);
}
/* and copy the indicies */
/* i_palidx is always unsigned char and will never be bigger than short
and since a line of 4-byte i_colors can fit then a line of i_palidx
will fit */
vals = mymalloc(sizeof(i_palidx) * im->xsize); /* checked 4jul05 tonyc */
for (y = 0; y < im->ysize; ++y) {
i_gpal(src, 0, im->xsize, y, vals);
i_ppal(im, 0, im->xsize, y, vals);
}
myfree(vals);
myfree(colors);
}
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
*/
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
=head1 SEE ALSO
Imager(3)
=head1 AUTHOR
Tony Cook <tony@develop-help.com>
=cut
*/
Jump to Line
Something went wrong with that request. Please try again.