File Coverage

blib/lib/MojoMojo/Schema/Result/Photo.pm
Criterion Covered Total %
statement 18 68 26.4
branch 0 12 0.0
condition n/a
subroutine 6 14 42.8
pod 8 8 100.0
total 32 102 31.3


line stmt bran cond sub pod time code
1             package MojoMojo::Schema::Result::Photo;
2              
3 40     40   56345 use strict;
  40         110  
  40         1060  
4 40     40   298 use warnings;
  40         89  
  40         1128  
5              
6 40     40   209 use parent qw/MojoMojo::Schema::Base::Result/;
  40         88  
  40         260  
7              
8 40     40   3736 use DateTime;
  40         812440  
  40         490  
9 40     40   48800 use Image::ExifTool;
  40         1423652  
  40         3187  
10 40     40   21575 use Image::Math::Constrain;
  40         36098  
  40         7167  
11             my $exif = Image::ExifTool->new();
12              
13             __PACKAGE__->load_components(
14             qw/DateTime::Epoch TimeStamp Ordered Core/);
15              
16             __PACKAGE__->position_column("position");
17             __PACKAGE__->table("photo");
18             __PACKAGE__->add_columns(
19             "id",
20             {
21             data_type => "INTEGER",
22             is_nullable => 0,
23             size => undef,
24             is_auto_increment => 1
25             },
26             "position",
27             { data_type => "INTEGER", is_nullable => 0, size => undef },
28             "title",
29             { data_type => "TEXT", is_nullable => 0, size => undef },
30             "description",
31             { data_type => "TEXT", is_nullable => 1, size => undef },
32             "camera",
33             { data_type => "TEXT", is_nullable => 1, size => undef },
34             "taken",
35             {
36             data_type => "INTEGER",
37             is_nullable => 1,
38             size => undef,
39             default_value => undef,
40             inflate_datetime => 'epoch',
41             datetime_undef_if_invalid => 1,
42             },
43             "iso",
44             { data_type => "INTEGER", is_nullable => 1, size => undef },
45             "lens",
46             { data_type => "TEXT", is_nullable => 1, size => undef },
47             "aperture",
48             { data_type => "TEXT", is_nullable => 1, size => undef },
49             "flash",
50             { data_type => "TEXT", is_nullable => 1, size => undef },
51             "height",
52             { data_type => "INT", is_nullable => 1, size => undef },
53             "width",
54             { data_type => "INT", is_nullable => 1, size => undef },
55             );
56             __PACKAGE__->set_primary_key("id");
57             __PACKAGE__->has_many(
58             "tags",
59             "MojoMojo::Schema::Result::Tag",
60             { "foreign.photo" => "self.id" }
61             );
62             __PACKAGE__->has_many(
63             "comments",
64             "MojoMojo::Schema::Result::Comment",
65             { "foreign.picture" => "self.id" }
66             );
67             __PACKAGE__->has_one( "attachment", "MojoMojo::Schema::Result::Attachment" );
68              
69             =head1 NAME
70              
71             MojoMojo::Schema::Result::Photo - store photos
72              
73             =head1 METHODS
74              
75             =cut
76              
77             =head2 extract_exif
78              
79             Extracts EXIF information from a given Attachment and
80             populates the Photo object.
81              
82             =cut
83              
84             sub extract_exif {
85 0     0 1   my ( $self, $att ) = @_;
86 0           my $info = $exif->ImageInfo( $att->filename );
87 0           $self->camera( $info->{'Model'} );
88 0           $self->lens( $info->{'FocalLength'} );
89 0           $self->iso( $info->{'ISO'} );
90 0           $self->aperture( $info->{'Aperture'} );
91 0           $self->flash( $info->{'Flash'} );
92 0           $self->description( $info->{'UserComment'} );
93 0           $self->taken( $self->exif2datetime( $info->{'DateTimeOriginal'} ) );
94             }
95              
96             =head2 exif2datetime datetime
97              
98             Creates a L<DateTime> object from an EXIF timestamp.
99              
100             =cut
101              
102             sub exif2datetime {
103 0     0 1   my ( $self, $datetime ) = @_;
104 0 0         return undef unless $datetime;
105 0           my ( $date, $time ) = split( ' ', $datetime );
106 0           my ( $y, $M, $d ) = split ':', $date;
107 0           my ( $h, $m, $s ) = split ':', $time;
108 0           my $dto;
109 0           eval {
110 0           $dto = DateTime->new(
111             year => $y,
112             month => $M,
113             day => $d,
114             hour => $h,
115             minute => $m,
116             second => $s
117             );
118             };
119 0           return $dto;
120             }
121              
122             =head2 prev_by_tag <tag>
123              
124             Return previous image when browsing by the given tag.
125              
126             =cut
127              
128             sub prev_by_tag {
129 0     0 1   my ( $self, $tag ) = @_;
130 0           return $self->result_source->resultset->search(
131             { 'me.id' => { '>', $self->id },
132             'tags.tag' => $tag
133             },
134             { order_by => 'taken',
135             join => [qw/tags/],rows=>1
136             }
137             )->next;
138             }
139              
140             =head2 next_by_tag <tag>
141              
142             Return the next image when browsing by the given tag.
143              
144             =cut
145              
146             sub next_by_tag {
147 0     0 1   my ( $self, $tag ) = @_;
148 0           return $self->result_source->resultset->search(
149             { 'me.id' => { '<', $self->id },
150             'tags.tag' => $tag
151             },
152             { order_by => 'taken DESC',
153             join => [qw/tags/], rows => 1 }
154             )->next;
155             }
156              
157             =head2 others_tags <user>
158              
159             Tags other users have given to this photo.
160              
161             =cut
162              
163             sub others_tags {
164 0     0 1   my ( $self, $user ) = @_;
165 0           my (@tags) = $self->related_resultset('tags')->search(
166             {
167             photo => $self->id,
168             person => { '!=', $user },
169             },
170             {
171             select => [ 'me.tag', 'count(me.tag) AS refcount' ],
172             as => [ 'tag', 'refcount' ],
173             'group_by' => ['me.tag'],
174             'order_by' => 'refcount',
175             }
176             );
177 0           return @tags;
178             }
179              
180             =head2 user_tags <user>
181              
182             Tags this user has given to this photo.
183              
184             =cut
185              
186             sub user_tags {
187 0     0 1   my ( $self, $user ) = @_;
188 0           my (@tags) = $self->related_resultset('tags')->search(
189             {
190             photo => $self->id,
191             person => $user,
192             },
193             { 'order_by' => ['me.tag'] }
194             );
195 0           return @tags;
196             }
197              
198             =head2 make_inline
199              
200             Create a resized version of a photo suitable for inline usage.
201              
202             =cut
203              
204             sub make_inline {
205 0     0 1   my ($self) = shift;
206 0           my $img = Imager->new();
207 0           my $att = $self->attachment;
208 0 0         $img->open( file => $att->filename ) or die $img->errstr;
209 0           my $constrain = Image::Math::Constrain->new( 800, 600 );
210 0           my $image = $img->scale( constrain => $constrain );
211              
212 0 0         $image->write( file => $att->filename . '.inline', type => 'jpeg' )
213             or die $img->errstr;
214             }
215              
216             =head2 make_thumb
217              
218             Create a thumbnail version of a photo, for gallery views and linking to pages.
219              
220             =cut
221              
222             sub make_thumb {
223 0     0 1   my ($self) = shift;
224 0           my $img = Imager->new();
225 0           my $att = $self->attachment;
226 0 0         $img->open( file => $att->filename ) or die $img->errstr;
227 0           my $h = $img->getheight;
228 0           my $w = $img->getwidth;
229 0           my ( $image, $result );
230 0 0         if ( $h > $w ) {
231 0           $image = $img->scale( xpixels => 80 );
232 0           $h = $image->getheight;
233 0           $result = $image->crop(
234             top => int( ( $h - 80 ) / 2 ),
235             left => 0,
236             width => 80,
237             height => 80
238             );
239             }
240             else {
241 0           $image = $img->scale( ypixels => 80 );
242 0           $w = $image->getwidth;
243 0           $result = $image->crop(
244             left => int( ( $w - 80 ) / 2 ),
245             top => 0,
246             width => 80,
247             height => 80
248             );
249             }
250 0 0         $result->write( file => $att->filename . '.thumb', type => 'jpeg' )
251             or die $img->errstr;
252             }
253              
254             =head1 AUTHOR
255              
256             Marcus Ramberg <mramberg@cpan.org>
257              
258             =head1 LICENSE
259              
260             This library is free software. You can redistribute it and/or modify
261             it under the same terms as Perl itself.
262              
263             =cut
264              
265             1;