Permalink
Browse files

alpha channel fixes for mixing scaling

  • Loading branch information...
1 parent cfa61c8 commit 874c55db7c148f8995a27beb75a5279c054c0ffe Tony Cook committed Nov 12, 2007
Showing with 115 additions and 15 deletions.
  1. +10 −0 Changes
  2. +1 −1 TODO
  3. +10 −1 imtoc.perl
  4. +77 −11 scale.im
  5. +17 −2 t/t40scale.t
View
10 Changes
@@ -1,5 +1,15 @@
Imager release history. Older releases can be found in Changes.old
+Imager 0.62 - not yet release
+
+Bug fixes:
+
+ - Imager::Fountain couldn't read GIMP gradient files with 10 or more
+ segments
+
+ - the scale() method with qtype mixing now handles images with an
+ alpha channel correctly.
+
Imager 0.61 - 5 November 2007
===========
View
2 TODO
@@ -30,7 +30,7 @@ both contig and non-contiguous
Makefile.PL --incpath and --libpath should expand ~/ paths (#29484)
-scaling alpha channel image issues
+scaling alpha channel image issues (done)
For 0.61:
View
@@ -16,7 +16,12 @@
my @out;
my $failed;
-push @out, "#line 1 \"$src\"\n";
+push @out,
+ "#define IM_ROUND_8(x) ((int)((x)+0.5))\n",
+ "#define IM_ROUND_double(x) (x)\n",
+ "#define IM_LIMIT_8(x) ((x) < 0 ? 0 : (x) > 255 ? 255 : (x))\n",
+ "#define IM_LIMIT_double(x) ((x) < 0.0 ? 0.0 : (x) > 1.0 ? 1.0 : (x))\n",
+ "#line 1 \"$src\"\n";
while (defined(my $line = <SRC>)) {
if ($line =~ /^\#code\s+(\S.+)$/) {
$save_code
@@ -99,6 +104,8 @@ sub byte_samples {
s/\bIM_Sf\b/"%d"/g;
s/\bIM_Wf\b/"%d"/g;
s/\bIM_SUFFIX\((\w+)\)/$1_8/g;
+ s/\bIM_ROUND\(/IM_ROUND_8(/g;
+ s/\bIM_LIMIT\(/IM_LIMIT_8(/g;
}
@lines;
@@ -121,6 +128,8 @@ sub double_samples {
s/\bIM_Sf\b/"%f"/g;
s/\bIM_Wf\b/"%f"/g;
s/\bIM_SUFFIX\((\w+)\)/$1_double/g;
+ s/\bIM_ROUND\(/IM_ROUND_double(/g;
+ s/\bIM_LIMIT\(/IM_LIMIT_double(/g;
}
@lines;
View
@@ -1,4 +1,5 @@
#include "imager.h"
+#include "imageri.h"
/*
* i_scale_mixing() is based on code contained in pnmscale.c, part of
@@ -51,7 +52,7 @@ i_img *
i_scale_mixing(i_img *src, int x_out, int y_out) {
i_img *result;
i_fcolor *accum_row = NULL;
- int y;
+ int x, y, ch;
int accum_row_bytes;
double rowsleft, fracrowtofill;
int rowsread;
@@ -125,6 +126,15 @@ i_scale_mixing(i_img *src, int x_out, int y_out) {
#else
IM_GLIN(src, 0, src->xsize, y, accum_row);
#endif
+ /* alpha adjust if needed */
+ if (src->channels == 2 || src->channels == 4) {
+ for (x = 0; x < src->xsize; ++x) {
+ for (ch = 0; ch < src->channels-1; ++ch) {
+ accum_row[x].channel[ch] *=
+ accum_row[x].channel[src->channels-1] / IM_SAMPLE_MAX;
+ }
+ }
+ }
}
else {
fracrowtofill = 1.0;
@@ -158,9 +168,24 @@ i_scale_mixing(i_img *src, int x_out, int y_out) {
#if IM_EIGHT_BIT
int x, ch;
/* no need to scale, but we need to convert it */
- for (x = 0; x < x_out; ++x) {
- for (ch = 0; ch < result->channels; ++ch)
- xscale_row[x].channel[ch] = accum_row[x].channel[ch];
+ if (result->channels == 2 || result->channels == 4) {
+ int alpha_chan = result->channels - 1;
+ for (x = 0; x < x_out; ++x) {
+ double alpha = accum_row[x].channel[alpha_chan] / IM_SAMPLE_MAX;
+ if (alpha) {
+ for (ch = 0; ch < alpha_chan; ++ch) {
+ int val = accum_row[x].channel[ch] / alpha + 0.5;
+ xscale_row[x].channel[ch] = IM_LIMIT(val);
+ }
+ }
+ xscale_row[x].channel[alpha_chan] = IM_LIMIT(accum_row[x].channel[alpha_chan]+0.5);
+ }
+ }
+ else {
+ for (x = 0; x < x_out; ++x) {
+ for (ch = 0; ch < result->channels; ++ch)
+ xscale_row[x].channel[ch] = IM_LIMIT(accum_row[x].channel[ch]+0.5);
+ }
}
IM_PLIN(result, 0, x_out, y, xscale_row);
#else
@@ -205,9 +230,19 @@ IM_SUFFIX(accum_output_row)(i_fcolor *accum, double fraction, IM_COLOR const *in
/* it's tempting to change this into a pointer iteration loop but
modern CPUs do the indexing as part of the instruction */
- for (x = 0; x < width; ++x) {
- for (ch = 0; ch < channels; ++ch) {
- accum[x].channel[ch] += in[x].channel[ch] * fraction;
+ if (channels == 2 || channels == 4) {
+ for (x = 0; x < width; ++x) {
+ for (ch = 0; ch < channels-1; ++ch) {
+ accum[x].channel[ch] += in[x].channel[ch] * fraction * in[x].channel[channels-1] / IM_SAMPLE_MAX;
+ }
+ accum[x].channel[channels-1] += in[x].channel[channels-1] * fraction;
+ }
+ }
+ else {
+ for (x = 0; x < width; ++x) {
+ for (ch = 0; ch < channels; ++ch) {
+ accum[x].channel[ch] += in[x].channel[ch] * fraction;
+ }
}
}
}
@@ -231,10 +266,25 @@ IM_SUFFIX(horizontal_scale)(IM_COLOR *out, int out_width,
for (ch = 0; ch < channels; ++ch)
accum[ch] += frac_col_to_fill * in[in_x].channel[ch];
- for (ch = 0; ch < channels; ++ch) {
- out[out_x].channel[ch] = accum[ch];
- accum[ch] = 0;
+ if (channels == 2 || channels == 4) {
+ int alpha_chan = channels - 1;
+ double alpha = accum[alpha_chan] / IM_SAMPLE_MAX;
+ if (alpha) {
+ for (ch = 0; ch < alpha_chan; ++ch) {
+ IM_WORK_T val = IM_ROUND(accum[ch] / alpha);
+ out[out_x].channel[ch] = IM_LIMIT(val);
+ }
+ }
+ out[out_x].channel[alpha_chan] = IM_LIMIT(IM_ROUND(accum[alpha_chan]));
}
+ else {
+ for (ch = 0; ch < channels; ++ch) {
+ IM_WORK_T val = IM_ROUND(accum[ch]);
+ out[out_x].channel[ch] = IM_LIMIT(val);
+ }
+ }
+ for (ch = 0; ch < channels; ++ch)
+ accum[ch] = 0;
frac_col_left -= frac_col_to_fill;
frac_col_to_fill = 1.0;
++out_x;
@@ -255,7 +305,23 @@ IM_SUFFIX(horizontal_scale)(IM_COLOR *out, int out_width,
if (out_x < out_width) {
for (ch = 0; ch < channels; ++ch) {
accum[ch] += frac_col_to_fill * in[in_width-1].channel[ch];
- out[out_x].channel[ch] = accum[ch];
+ }
+ if (channels == 2 || channels == 4) {
+ int alpha_chan = channels - 1;
+ double alpha = accum[alpha_chan] / IM_SAMPLE_MAX;
+ if (alpha) {
+ for (ch = 0; ch < alpha_chan; ++ch) {
+ IM_WORK_T val = IM_ROUND(accum[ch] / alpha);
+ out[out_x].channel[ch] = IM_LIMIT(val);
+ }
+ }
+ out[out_x].channel[alpha_chan] = IM_LIMIT(IM_ROUND(accum[alpha_chan]));
+ }
+ else {
+ for (ch = 0; ch < channels; ++ch) {
+ IM_WORK_T val = IM_ROUND(accum[ch]);
+ out[out_x].channel[ch] = IM_LIMIT(val);
+ }
}
}
}
View
@@ -1,10 +1,11 @@
#!perl -w
use strict;
-use Test::More tests => 223;
+use Test::More tests => 224;
BEGIN { use_ok(Imager=>':all') }
+use Imager::Test qw(is_image);
-require "t/testtools.pl";
+#require "t/testtools.pl";
Imager::init('log'=>'testout/t40scale.log');
my $img=Imager->new();
@@ -181,6 +182,20 @@ SKIP:
pixels => 144);
}
+{ # check proper alpha handling
+ my $im = Imager->new(xsize => 40, ysize => 40, channels => 4);
+ $im->box(filled => 1, color => 'C0C0C0');
+ my $rot = $im->rotate(degrees => -4)
+ or die;
+ $rot = $rot->to_rgb16;
+ my $sc = $rot->scale(qtype => 'mixing', xpixels => 40);
+ my $out = Imager->new(xsize => $sc->getwidth, ysize => $sc->getheight);
+ $out->box(filled => 1, color => 'C0C0C0');
+ my $cmp = $out->copy;
+ $out->rubthrough(src => $sc);
+ is_image($out, $cmp, "check we get the right image after scaling");
+}
+
sub scale_test {
my ($in, $method, $exp_width, $exp_height, $note, @parms) = @_;

0 comments on commit 874c55d

Please sign in to comment.