123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- #!/usr/bin/perl
- # Author: Trizen
- # Date: 29 April 2022
- # https://github.com/trizen
- # Generate an ASCII representation for an image, using only digits, such that the number is a prime.
- # Inspired by the following Matt Parker video:
- # https://yewtu.be/watch?v=dET2l8l3upU
- # See also:
- # https://github.com/TotalTechGeek/pictoprime
- use 5.010;
- use strict;
- use autodie;
- use warnings;
- use GD qw();
- use List::Util qw(max);
- use Getopt::Long qw(GetOptions);
- use Math::Prime::Util::GMP qw(is_prob_prime);
- use constant {
- GENERATE_PRIME => 1, # true to generate primes (slow)
- };
- GD::Image->trueColor(1);
- my $size = 80;
- sub help {
- my ($code) = @_;
- print <<"HELP";
- usage: $0 [options] [files]
- options:
- -w --width=i : width size of the ASCII image (default: $size)
- example:
- perl $0 --width 200 image.png
- HELP
- exit($code);
- }
- GetOptions('w|width=s' => \$size,
- 'h|help' => sub { help(0) },)
- or die "Error in command-line arguments!";
- sub map_value {
- my ($value, $in_min, $in_max, $out_min, $out_max) = @_;
- ($value - $in_min) * ($out_max - $out_min) / ($in_max - $in_min) + $out_min;
- }
- my @digits = split(//, "7772299408");
- #my @digits = 0..9;
- # The ways that we allow the algorithm to substitute a character.
- # Like 0 can become 8 or 9, so on and so forth.
- my %substitutions = (
- '0' => ['8', '9'],
- '1' => ['7'],
- '7' => ['1'],
- '8' => ['0', '9'],
- '9' => ['4'],
- '4' => ['9'],
- );
- # These are used to swap out the last digit if necessary.
- my %edge_digit_substitutions = (
- '0' => '3',
- '2' => '3',
- '4' => '9',
- '6' => '9',
- '8' => '9',
- '5' => '3'
- );
- sub create_prime {
- my ($pixels) = @_;
- GENERATE_PRIME || return $pixels;
- if (substr($pixels, 0, 1) == 0) {
- substr($pixels, 0, 1, $edge_digit_substitutions{0});
- }
- if (exists($edge_digit_substitutions{substr($pixels, -1)})) {
- my $digit = chop $pixels;
- $pixels .= $edge_digit_substitutions{$digit};
- }
- my $count = 0;
- my $copy = $pixels;
- my $length = length($pixels);
- my @substitution_indices = grep { exists $substitutions{substr($pixels, $_, 1)} } 0 .. $length - 1;
- while (1) {
- if (is_prob_prime($pixels)) {
- return $pixels;
- }
- if (++$count > 5) {
- $pixels = $copy;
- $count = 0;
- }
- my $rand = $substitution_indices[int rand scalar @substitution_indices];
- my $digit = substr($pixels, $rand, 1);
- my $alt = $substitutions{$digit};
- substr($pixels, $rand, 1, $alt->[int rand scalar @$alt]);
- }
- }
- sub img2prime {
- my ($image) = @_;
- my $img = GD::Image->new($image) // return;
- my ($width, $height) = $img->getBounds;
- if ($size != 0) {
- my $scale_width = $size;
- my $scale_height = int($height / ($width / ($size / 2)));
- my $resized = GD::Image->new($scale_width, $scale_height);
- $resized->copyResampled($img, 0, 0, 0, 0, $scale_width, $scale_height, $width, $height);
- ($width, $height) = ($scale_width, $scale_height);
- $img = $resized;
- }
- my $avg = 0;
- my @averages;
- foreach my $y (0 .. $height - 1) {
- foreach my $x (0 .. $width - 1) {
- my $index = $img->getPixel($x, $y);
- my ($r, $g, $b) = $img->rgb($index);
- my $value = max($r, $g, $b);
- push @averages, $digits[map_value($value, 0, 255, 0, $#digits)];
- }
- }
- my $prime = create_prime(join('', @averages));
- unpack("(A$width)*", $prime);
- }
- say for img2prime($ARGV[0] // help(1));
- __END__
- 30000000000000000000000000000000000000000000000000000000000000000000000000000000
- 00000000000000000000000000000000000000000000000000000000000000000000000000000000
- 00000000000000000000000000000000000000000000000000000000000000000000000000000000
- 00000000000000000000000000000000000000000000000000000000000000000000000000000000
- 00000000000000000000000000000000000000000000000000000000000000000000000000000000
- 00000000000000000000001002222333222221100000000000000000000000000000000000000000
- 00000000000000000001101343344444444333332211000000000000000000000000000000000000
- 00000000000000000000355455555555556666666665544332100000000000000000000000000000
- 00000000000000003543245666666666777777777666665544321000000000000000000000000000
- 00000000000000001256666666677777777777777776666655432100000000000000000000000000
- 00000000011144433225666678888888876555556655543433322100000000000000000000000000
- 00000000012234667777767888888753135554300134310000000000000000000000000000000000
- 00000000001233356777888888884013366653000000000000000000000110000000000000000000
- 00000000000013345678888888711335667631000000000000000000000000010000000000000000
- 00001124556666656888888888123456776520000000000000111111100000011110000000000000
- 00033334567777788888888885245667776651000000000010000000000000001110001000000000
- 00021034355667788888888884456778877766520000000100000000022000000100000100000000
- 00000013044455888888888887788888888875300000000110000000132032111000000110000000
- 00000000012053888888888888888888888888400000000111001110220301211000001110000000
- 00000000000020788888888888888888888888830000001000000022021013133211001100000000
- 00000000000020788888888888888888888888830000010000000001221121121011000001000000
- 00000000013054888888888888888888888888400000001000001222222122231000000001000000
- 00000013044455888888888887778888888885400000000001100000001221021000000010000000
- 00022034355677788888888884456668877766420000000001110000011000000001111000000000
- 00033335567777788888888885235667776651000000000000100000000000000001100000000000
- 00000124455666655888888888123456777520000800000000011000011110000011000000000000
- 00000000000023345678888888711334667641000000000000000110000011111100000000000000
- 00000000001233356777888888884113366653000000000000000000000000000000000000000000
- 00000000012234667777767888888753135554300134310000000000000000000000000000000000
- 00000000011134332225666678888888876555556655544433332100000000000000000000000000
- 00000000000000001256666666667777777777777776666655432100000000000000000000000000
- 00000000000000013443245666666666777777777666665544321000000000000000000000000000
- 00000000000000000000354455555555555666665555543321100000000000000000000000000000
- 00000000000000000001101343344344434343332210000000000000000000000000000000000000
- 00000000000000000000001002222223222221100000000000000000000000000000000000000000
- 00000000000000000000000000000000000000000000000000000000000000000000000000000000
- 00000000000000000000000000000000000000000000000000000000000000000000000000000000
- 00000000000000000000000000000000000000000000000000000000000000000000000000000000
- 00000000000000000000000000000000000000000000000000000000000000000000000000000000
- 00000000000000000000000000000000000000000000000000000000000000000000000000000003
|