Tempest
view release on metacpan or search on metacpan
lib/Tempest/Gd.pm view on Meta::CPAN
}
}
$coordinates = [ values(%normal) ];
undef %normal;
# load plot image (presumably greyscale)
my $plot_file = GD::Image->new($parent->get_plot_file());
# calculate coord correction based on plot image size
my @plot_correct = ( ($plot_file->width / 2), ($plot_file->height / 2) );
# colorize opacity for how many times at most a point will be repeated
my $colorize_percent = 99 / $max_rep;
if($colorize_percent < 1) { $colorize_percent = 1; }
colorize($plot_file, $colorize_percent);
# paste one plot for each coordinate pair
for my $pair (@{$coordinates}) {
my $x = ($pair->[0] - $plot_correct[0]);
my $y = ($pair->[1] - $plot_correct[1]);
# for how many times coord pair was repeated
for (1..$pair->[2]) {
# paste plot, centered on given coords
composite($output_file, $plot_file, $x, $y);
}
}
# destroy plot file, as we don't need it anymore
undef $plot_file;
# open color lookup table
my $color_file = GD::Image->new($parent->get_color_file());
# apply color lookup table
my %cached_colors;
for my $x (0..$output_file->width) {
for my $y (0..$output_file->height) {
# calculate color lookup location
my $pixel_red = ($output_file->rgb( $output_file->getPixel($x, $y) ))[0];
# cache colors as we look them up
my @lookup_color;
if(exists($cached_colors{$pixel_red})) {
@lookup_color = @{ $cached_colors{$pixel_red} };
}
else {
my $color_offset = ($pixel_red / 255) * ($color_file->height - 1);
@lookup_color = $color_file->rgb( $color_file->getPixel(0, $color_offset) );
$cached_colors{$pixel_red} = \@lookup_color;
}
# allocate and set new color from lookup table
my $new_color = $output_file->colorAllocate(@lookup_color);
$output_file->setPixel($x, $y, $new_color);
$output_file->colorDeallocate($new_color);
}
}
# overlay heatmap over source image
if($parent->get_overlay()) {
$input_file->copyMerge($output_file, 0, 0, 0, 0, $output_file->width, $output_file->height, $parent->get_opacity());
undef $output_file;
$output_file = $input_file;
}
# write to output file
write_image($output_file, $parent->get_output_file());
return 1;
}
sub write_image {
my $image_file = shift;
my $filename = shift;
my $filetype;
if(($filetype) = $filename =~ m/\.(png|gif|jpe?g|gd2?|wbmp)$/i) {
$filetype = lc($filetype);
if($filetype eq 'jpe' || $filetype eq 'jpeg') {
$filetype = 'jpg';
}
my $image_data = $image_file->$filetype;
open(PNGFILE, '>', $filename) or croak("Failed to write output image: $!");
binmode PNGFILE;
print PNGFILE $image_data;
close(PNGFILE);
return;
}
croak("Failed to detect a supported file extension in file '$filename'");
}
sub composite {
my($source_image, $composite_image, $x, $y) = @_;
# set aside space to cache colors
my %cached_colors;
# for each pixel from x to x+composite_width
my $composite_x = $composite_image->width - 1;
my $composite_y = $composite_image->height - 1;
foreach my $x_offset (0..$composite_x) {
foreach my $y_offset (0..$composite_y) {
my $source_x = ($x + $x_offset);
my $source_y = ($y + $y_offset);
# skip negative coordinates
if($source_x < 0 || $source_y < 0) { next; }
# get colors to composite together
my @source_color = $source_image->rgb( $source_image->getPixel($source_x, $source_y) );
my @composite_color = $composite_image->rgb( $composite_image->getPixel($x_offset, $y_offset) );
# multiply colors together, caching them within the same composite call
my $cache_key = join(',', @source_color) . 'x' . join(',', @composite_color);
my @multiplied;
if(exists($cached_colors{$cache_key})) {
@multiplied = @{ $cached_colors{$cache_key} };
}
( run in 0.733 second using v1.01-cache-2.11-cpan-99c4e6809bf )