Imagerでグラデーションパレットを作る
カオスCGやジュリア集合に着色するのにパレットを用意してるんだけど、
良い感じのパレットのバリエーションを増やすべく、
その処理を切り出して検討してみた。
use v5.14;
use strict;
use warnings;
use Imager;
sub look_up_func {
my $params = shift;
my $n = scalar( @{$params} );
return sub {
my $t = shift;
for (my $i=0; $i<($n - 1); $i++) {
my ( $p1, $p2 ) = @{$params}[$i, ($i + 1)];
if ( $t <= $p2->[0] ) {
my $dt = $p2->[0] - $p1->[0];
my $dv = $p2->[1] - $p1->[1];
$t -= $p1->[0];
return $p1->[1] + ($dv * ($t / $dt));
}
}
return $params->[-1]->[1];
}
}
sub create_palette {
my ( $n, $args ) = @_;
my $func_hue = look_up_func( $args->{hue} );
my $func_val = look_up_func( $args->{val} );
my $func_sat = look_up_func( $args->{sat} );
my @palette = map {
my $t = $_ / ($n - 1);
my $hue = $func_hue->( $t );
my $val = $func_val->( $t );
my $sat = $func_sat->( $t );
#printf( "%3d: %5.2f, %5.2f, %5.2f\n", $_, $hue, $val, $sat );
Imager::Color->new( hue => $hue, v => $val, s => $sat );
} 0..($n - 1);
return \@palette;
}
my ( $w, $h ) = ( 640, 480 );
my $img = Imager->new(
xsize => $w, ysize => $h, channels => 1, type => 'paletted' );
my $palette = create_palette( 256, {
hue => [
[ 0.0, 0.0 ],
[ 0.2, 0.0 ],
[ 0.6, 48.0 ]
],
val => [
[ 0.0, 0.0 ],
[ 0.1, 0.2 ],
[ 0.4, 1.0 ]
],
sat => [
[ 0.0, 0.8 ],
[ 0.5, 0.8 ],
[ 1.0, 0.0 ]
]
} );
$img->addcolors( colors => $palette );
my @samples = map {
my $tmp = $_ / ($w - 1);
int( (255 * $tmp) + 0.5 );
} 0..($w - 1);
for (my $iy=0; $iy<$h; $iy++) {
$img->setscanline(
y => $iy,
type => 'index',
pixels => \@samples );
}
my $dst_file = 'test.gif';
$img->write( file => $dst_file ) or die $img->errstr;
say 'wrote: ', $dst_file;
線形補間だけど、個人的には満足の出来。
ちなみに、これを実行するとこんな感じ。
$ perl bbb.pl
wrote: test.gif
これを利用しつつ、ガンマ補正を2.0でレンダリングするとこんな感じ。
perl aaa.pl --param="0.262,0.627" --dst="test2"
ガンマ補正も実行時引数に加えた方が良いかな?
(ここで言うところの、281行目付近の数字。)
おしまい。


Leave a Comment