img_composition.pl 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. #!/usr/bin/perl
  2. # Author: Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 15 April 2015
  5. # Edit: 18 September 2016
  6. # Website: https://github.com/trizen
  7. # Compose two images together by merging all the pixels, color by color.
  8. use 5.010;
  9. use strict;
  10. use autodie;
  11. use warnings;
  12. use GD;
  13. use List::Util qw(min);
  14. use Getopt::Long qw(GetOptions);
  15. GD::Image->trueColor(1);
  16. my $output_file = 'output.png';
  17. my $scale_percentage = 0;
  18. sub usage {
  19. print <<"USAGE";
  20. usage: $0 [options] [img1] [img2]
  21. options:
  22. -o --output : output file (default: $output_file)
  23. -s --scale-percent : scale images by a given percentage (default: $scale_percentage)
  24. example:
  25. $0 -s -40 img1.png img2.jpg
  26. USAGE
  27. exit 2;
  28. }
  29. GetOptions(
  30. 'o|output=s' => \$output_file,
  31. 's|scale-percentage=i' => \$scale_percentage,
  32. 'h|help' => \&usage,
  33. );
  34. sub scale_image {
  35. my ($img, $scale_percentage) = @_;
  36. my ($width, $height) = $img->getBounds;
  37. my $scale_width = $width + int($scale_percentage / 100 * $width);
  38. my $scale_height = $height + int($scale_percentage / 100 * $height);
  39. my $scaled_gd = GD::Image->new($scale_width, $scale_height);
  40. $scaled_gd->copyResampled($img, 0, 0, 0, 0, $scale_width, $scale_height, $width, $height);
  41. return $scaled_gd;
  42. }
  43. sub make_matrix {
  44. my ($file, $scale_percentage) = @_;
  45. my $img = GD::Image->new($file) // do {
  46. warn "Can't load image `$file': $!\n";
  47. return;
  48. };
  49. if ($scale_percentage != 0) {
  50. $img = scale_image($img, $scale_percentage);
  51. }
  52. my @matrix;
  53. my ($width, $height) = $img->getBounds();
  54. foreach my $x (0 .. $width - 1) {
  55. foreach my $y (0 .. $height - 1) {
  56. $matrix[$x][$y] = [$img->rgb($img->getPixel($x, $y))];
  57. }
  58. }
  59. return \@matrix;
  60. }
  61. sub compose_images {
  62. my ($A, $B) = @_;
  63. local $| = 1;
  64. my ($rows, $cols) = (min($#{$A}, $#{$B}), min($#{$A->[0]}, $#{$B->[0]}));
  65. my @C;
  66. foreach my $r (0 .. $rows) {
  67. foreach my $i (0 .. $cols) {
  68. foreach my $c (0 .. 2) {
  69. $C[$i][$r][$c] = int(($A->[$r][$i][$c] + $B->[$r][$i][$c]) / 2);
  70. }
  71. }
  72. print "$r of $rows...\r";
  73. }
  74. return \@C;
  75. }
  76. sub write_matrix {
  77. my ($matrix, $file) = @_;
  78. my ($rows, $cols) = ($#{$matrix}, $#{$matrix->[0]});
  79. my $img = GD::Image->new($cols + 1, $rows + 1);
  80. foreach my $y (0 .. $rows) {
  81. foreach my $x (0 .. $cols) {
  82. $img->setPixel($x, $y, $img->colorAllocate(@{$matrix->[$y][$x]}));
  83. }
  84. }
  85. open my $fh, '>:raw', $file;
  86. print $fh lc($file) =~ /\.png\z/
  87. ? $img->png()
  88. : $img->jpeg();
  89. close $fh;
  90. }
  91. say "** Reading images...";
  92. my $A = make_matrix(shift(@ARGV) // usage(), $scale_percentage) // die "error 1: $!";
  93. my $B = make_matrix(shift(@ARGV) // usage(), $scale_percentage) // die "error 2: $!";
  94. say "** Composing images...";
  95. my $C = compose_images($A, $B);
  96. say "** Writing the output image...";
  97. write_matrix($C, $output_file)
  98. ? (say "** All done!")
  99. : (die "Error: $!");