File Coverage

blib/lib/Acme/DreamyImage.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Acme::DreamyImage;
2             our $VERSION = '1.1';
3              
4 1     1   928 use common::sense;
  1         9  
  1         7  
5 1     1   914 use Object::Tiny qw(seed width height);
  1         353  
  1         6  
6 1     1   1711 use Imager qw(:handy);
  1         61188  
  1         10  
7 1     1   1428 use Digest::SHA1 qw(sha1_hex);
  1         11505  
  1         695  
8 1     1   918 use self;
  0            
  0            
9              
10             sub new {
11             $self = $self->SUPER::new(@args);
12             die "'seed' is required\n" unless defined $self->{seed};
13             die "'width' is required, and cannot be 0.\n" unless defined $self->{width} && $self->{width} > 0;
14             die "'height' is required, and cannot be 0.\n" unless defined $self->{height} && $self->{height} > 0;
15              
16             $self->{seed} = sha1_hex($self->seed);
17             return $self;
18             }
19              
20             sub write {
21             my $image = $self->random_image;
22             $image->write(@args) or die $image->errstr;
23             return $self;
24             }
25              
26             sub random {
27             my ($upper_bound) = @args;
28             $upper_bound ||= 1;
29              
30             $self->{pos} = 0 unless defined($self->{pos});
31             my $value = substr($self->{seed}, $self->{pos}, 1);
32             $self->{pos} += 1;
33             $self->{pos} = 0 if $self->{pos} >= length($self->{seed});
34             return int(hex($value) / 15 * $upper_bound);
35             }
36              
37             sub random_color {
38             return [map { $self->random(255) } 1..4]
39             }
40              
41             sub random_background {
42             my $image = Imager->new(xsize => $self->width, ysize => $self->height, channels => 3);
43             $image->box(filled => 1, color => [255, 255, 255]);
44             $image->filter(type => "gradgen",
45             xo => [map { $self->random($self->width) } 1..2],
46             yo => [map { $self->random($self->height) } 1..2],
47             colors => [ map { $self->random_color } 1..2 ]);
48              
49             $image->filter(type => "noise", subtype => 0, amount => $self->random(10));
50             $image->filter(type => "gaussian", stddev => $self->random( ($self->width + $self->height) / 2 * 0.03 ));
51              
52             return $image;
53             }
54              
55             sub new_layer {
56             my ($xsize, $ysize, $cb) = @_;
57             my $layer = Imager->new(xsize => $xsize, ysize => $ysize, channels => 4);
58             $cb->($layer);
59             return $layer;
60             }
61              
62             sub random_image {
63             my $image = $self->random_background;
64             my $xsize = $self->width;
65             my $ysize = $self->height;
66             my $resize = 0;
67              
68             if ($xsize < 128) {
69             $resize = 1;
70             $xsize = 128;
71             }
72              
73             if ($ysize < 128) {
74             $resize = 1;
75             $ysize = 128;
76             }
77              
78             # Big Blur Circles
79             new_layer(
80             $xsize, $ysize,
81             sub {
82             my ($layer) = @_;
83             my $layer = Imager->new(xsize => $xsize, ysize => $ysize, channels => 4);
84             $layer->filter(type => "noise", subtype => 0, amout => 20);
85             for my $size (map { ($xsize + $ysize) / 16 + $_ } 1..20) {
86             my ($x, $y) = ($self->random($xsize), $self->random($ysize));
87             $layer->circle(fill => { solid => [255, 255, 255, $self->random(30) + 10], combine => "add" }, x => $x, y => $y, r => $size);
88             }
89             $layer->filter(type => "gaussian", stddev => $self->random(30));
90              
91             $image->compose(src => $layer, tx => 0, ty => 0, combine => 'add');
92             }
93             );
94              
95             # Big Blur Boxes
96             new_layer(
97             $xsize, $ysize,
98             sub {
99             my ($layer) = @_;
100             for my $size (map { ($xsize + $ysize) / 16 + $_ } 1..20) {
101             my ($x, $y) = ($self->random($xsize), $self->random($ysize));
102             $layer->box(fill => { solid => [255, 255, 255, $self->random(30) + 10], combine => "add" },
103             xmin => $x, ymin => $y,
104             xmax => $x + $size, ymax => $y + $size);
105             }
106             $layer->filter(type => "noise", amount => $self->random(($xsize + $ysize) /2 * 0.03 ), subtype => 1);
107             $layer->filter(type => "gaussian", stddev => $self->random(30));
108              
109             $image->compose(src => $layer, tx => 0, ty => 0, combine => 'add');
110             }
111             );
112              
113             # Small Sharp Circles
114             for (1..10+$self->random(20)) {
115             my $size = $self->random( ($xsize + $ysize) / 2 / 16);
116             my ($x, $y) = ($self->random($xsize), $self->random($ysize));
117             my $opacity = $self->random(30) + 10;
118             $image->circle(fill => { solid => [255, 255, 255, $opacity], combine => "add" }, x => $x, y => $y, r => $size);
119             }
120              
121             if ($resize) {
122             $image = $image->scale(type => "nonprop", xpixels => $self->width, ypixels => $self->height);
123             }
124              
125             return $image;
126             }
127              
128              
129             1;
130             __END__