File Coverage

blib/lib/Math/FitRect.pm
Criterion Covered Total %
statement 39 48 81.2
branch 8 16 50.0
condition n/a
subroutine 9 9 100.0
pod 2 2 100.0
total 58 75 77.3


line stmt bran cond sub pod time code
1             package Math::FitRect;
2             BEGIN {
3 1     1   59883 $Math::FitRect::VERSION = '0.04';
4             }
5 1     1   10 use strict;
  1         2  
  1         39  
6 1     1   6 use warnings;
  1         2  
  1         125  
7              
8             =head1 NAME
9              
10             Math::FitRect - Resize one rect in to another while preserving aspect ratio.
11              
12             =head1 SYNOPSIS
13              
14             use Math::FitRect;
15            
16             # This will return: {w=>40, h=>20, x=>0, y=>10}
17             my $rect = fit_rect( [80,40] => 40 );
18            
19             # This will return: {w=>80, h=>40, x=>-19, y=>0}
20             my $rect = crop_rect( [80,40] => 40 );
21              
22             =head1 DESCRIPTION
23              
24             This module is very simple in its content but can save much time, much like
25             other simplistic modules like L. This module is useful for
26             calculating what size you should resize images as for such things as
27             thumbnails.
28              
29             =cut
30              
31 1     1   5 use Carp qw( croak );
  1         3  
  1         532  
32              
33 1     1   7 use Exporter qw( import );
  1         2  
  1         627  
34             our @EXPORT_OK = qw(
35             fit_rect
36             crop_rect
37             );
38              
39             =head1 RECTANGLES
40              
41             Rectangles may be specified in several different forms to fit your needs.
42              
43             =over
44              
45             =item A simple scalar integer containg the pixel width/height of a square.
46              
47             =item An array ref containing the width and height of a rectangle: [$width,$height]
48              
49             =item A hash ref containg a w (width) and h (height) key: {w=>$width,h=>$height}
50              
51             =back
52              
53             =head1 FUNCTIONS
54              
55             =head2 fit_rect
56              
57             # This will return: {w=>40, h=>20, x=>0, y=>10}
58             my $rect = fit_rect( [80,40] => 40 );
59              
60             Takes two rectangles and fits the first one inside the second one. The rectangle
61             that will be returned will be a hash ref with a 'w' and 'h' parameter as well
62             as 'x' and 'y' parameters which will specify any offset.
63              
64             =cut
65              
66             sub fit_rect {
67 4     4 1 20 return _calc_rect('fit',@_);
68             }
69              
70             =head2 crop_rect
71              
72             # This will return: {w=>80, h=>40, x=>-19, y=>0}
73             my $rect = crop_rect( [80,40] => 40 );
74              
75             Like the fit_rect function, crop_rect takes two rectangles as a parameter and it
76             makes $rect1 completely fill $rect2. This can mean that the top and bottom or
77             the left and right get chopped off (cropped). This method returns a hash ref just
78             like fit_rect.
79              
80             =cut
81              
82             sub crop_rect {
83 4     4 1 10 return _calc_rect('crop',@_);
84             }
85              
86             sub _calc_rect {
87 8     8   14 my($type,$from,$to) = @_;
88 8         16 $from = _normalize($from);
89 8         15 $to = _normalize($to);
90 8         13 my($w,$h,$x,$y);
91 8 100       20 if($type eq 'crop'){ ($to->{r},$from->{r}) = ($from->{r},$to->{r}); }
  4         12  
92              
93 8 100       35 if($from->{r} < $to->{r}){
94 2         6 $w = $from->{w} * ($to->{h}/$from->{h});
95 2         3 $h = $to->{h};
96 2         4 $x = ($to->{w}-$w)/2;
97 2         3 $y = 0;
98             }else{
99 6         13 $h = $from->{h} * ($to->{w}/$from->{w});
100 6         10 $w = $to->{w};
101 6         13 $y = ($to->{h}-$h)/2;
102 6         7 $x = 0;
103             }
104              
105 8         104 return {w=>int($w+0.5),h=>int($h+0.5),x=>int($x+0.5),y=>int($y+0.5)};
106             }
107              
108             sub _normalize {
109 16     16   19 my $rect = shift;
110 16         20 my($w,$h,$r);
111 16 100       49 if(!ref($rect)){ # square
    50          
    50          
    0          
112 8         10 $w = $h = $rect;
113             }elsif(ref($rect) eq 'HASH'){ # rect hash ref
114 0         0 $w = $rect->{w};
115 0         0 $h = $rect->{h};
116             }elsif(@$rect==2){ # width, height
117 8         13 $w = $rect->[0];
118 8         40 $h = $rect->[1];
119             }elsif(@$rect==4){ # x1, y1, x2, y2
120 0 0       0 if($rect->[0]<$rect->[2]){ $w=($rect->[2]-$rect->[0])+1; }
  0         0  
121 0         0 else{ $w=($rect->[0]-$rect->[2])+1; }
122 0 0       0 if($rect->[1]<$rect->[3]){ $h=($rect->[3]-$rect->[1])+1; }
  0         0  
123 0         0 else{ $h=($rect->[1]-$rect->[3])+1; }
124             }else{
125 0         0 croak('Invalid rectangle parameter');
126             }
127 16         21 $r = $w/$h;
128 16         67 return {w=>$w,h=>$h,r=>$r};
129             }
130              
131             1;
132             __END__