File Coverage

blib/lib/GD/Window.pm
Criterion Covered Total %
statement 15 88 17.0
branch 0 46 0.0
condition 0 9 0.0
subroutine 5 17 29.4
pod 2 10 20.0
total 22 170 12.9


line stmt bran cond sub pod time code
1             package GD::Window;
2              
3 1     1   31164 use 5.008006;
  1         4  
  1         50  
4 1     1   5 use strict;
  1         3  
  1         43  
5 1     1   7 use warnings;
  1         5  
  1         45  
6 1     1   5 use Carp qw( croak );
  1         1  
  1         83  
7 1     1   6 use vars qw/$VERSION $AUTOLOAD/;
  1         2  
  1         1795  
8              
9             require Exporter;
10              
11             our @ISA = qw(Exporter);
12              
13             our %EXPORT_TAGS = ( 'all' => [ qw(
14            
15             ) ] );
16              
17             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
18              
19             our @EXPORT = qw(
20            
21             );
22              
23             our $VERSION = '0.02';
24              
25              
26             my %imWindowedFuncs = (
27             setPixel => {x => [0], 'y' => [1]},
28             line => {x => [0,2], 'y' => [1,3]},
29             dashedLine => {x => [0,2], 'y' => [1,3]},
30             rectangle => {x => [0,2], 'y' => [1,3]},
31             filledRectangle => {x => [0,2], 'y' => [1,3]},
32             ellipse => {x => [0], 'y' => [1], w => [2], h => [3]},
33             filledEllipse => {x => [0], 'y' => [1], w => [2], h => [3]},
34             arc => {x => [0], 'y' => [1], w => [2], h => [3]},
35             filledArc => {x => [0], 'y' => [1], w => [2], h => [3]},
36             fill => {x => [0], 'y' => [1]},
37             fillToBorder => {x => [0], 'y' => [1]},
38             copy => {x => [1], 'y' => [2]},
39             copyMerge => {x => [1], 'y' => [2]},
40             copyMergeGray => {x => [1], 'y' => [2]},
41             copyResized => {x => [1], 'y' => [2], w => [5], h => [6]},
42             copyResampled => {x => [1], 'y' => [2], w => [5], h => [6]},
43             copyRotated => {x => [1], 'y' => [2]},
44             string => {x => [1], 'y' => [2]},
45             stringUp => {x => [1], 'y' => [2]},
46             char => {x => [1], 'y' => [2]},
47             charUp => {x => [1], 'y' => [2]},
48             stringFT => {x => [4], 'y' => [5]},
49             stringFTCircle => {x => [0], 'y' => [1]},
50             clip => {x => [0,2], 'y' => [1,3]},
51             );
52              
53             my %imWindowedPolyFuncs = (openPolygon => 1,
54             unclosedPolygon => 1,
55             filledPolygon => 1);
56              
57              
58             my $invertY_g = 0;
59              
60              
61             sub new {
62 0     0 1   my $that = shift;
63 0   0       my $class = ref($that) || $that;
64 0           my ($im, $imX1, $imY1, $imX2, $imY2,
65             $winX1, $winY1, $winX2, $winY2,
66             %args) = @_;
67              
68 0 0         if (scalar(@_) < 9) {
69 0           croak "Missing some arguments for new GD::Window";
70             }
71              
72             # Fill in the window's boundary
73 0 0         my $self = { im => $im,
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
74             minX => $winX1 > $winX2 ? $winX2 : $winX1,
75             minY => $winY1 > $winY2 ? $winY2 : $winY1,
76             maxX => $winX1 > $winX2 ? $winX1 : $winX2,
77             maxY => $winY1 > $winY2 ? $winY1 : $winY2,
78             imMinX => $imX1 > $imX2 ? $imX2 : $imX1,
79             imMinY => $imY1 > $imY2 ? $imY2 : $imY1,
80             imMaxX => $imX1 > $imX2 ? $imX1 : $imX2,
81             imMaxY => $imY1 > $imY2 ? $imY1 : $imY2,
82             passThroughIfUnsupported => $args{passThrough},
83             useImage => $args{useImage},
84             invertY => defined $args{invertY} ? $args{invertY} : $invertY_g,
85             };
86              
87 0 0         if ($self->{useImage}) {
88             # Need to make our own internal image
89 0           $self->{parentIm} = $im;
90 0           $self->{im} = GD::Image->new(($self->{maxX} - $self->{minX}), ($self->{maxY} - $self->{minY}), 1);
91 0           $self->{scaleX} = 1;
92 0           $self->{scaleY} = 1;
93 0           $self->{srcImMinX} = $self->{imMinX};
94 0           $self->{srcImMinY} = $self->{imMinY};
95 0           $self->{imMinX} = 0;
96 0           $self->{imMinY} = 0;
97             }
98             else {
99 0           $self->{scaleX} = ($self->{imMaxX} - $self->{imMinX})/($self->{maxX} - $self->{minX});
100 0           $self->{scaleY} = ($self->{imMaxY} - $self->{imMinY})/($self->{maxY} - $self->{minY});
101             }
102              
103             # print "PostSub: $postSub\n";
104 0 0         if ($@) {
105 0           die "Failed eval of autoloaded sub: $@";
106             }
107              
108 0           bless ($self, $class);
109 0           return $self;
110             }
111              
112              
113             ##
114             # The autoload function catches all the supported image functions and
115             # creates the appropriate transformations for them.
116             #
117             # If passThrough is defined on window creation, then unsupported
118             # functions will simply be forwarded to the image. Otherwise,
119             # we will croak.
120             ##
121             sub AUTOLOAD {
122 0     0     my ($self) = @_;
123 0           my ($name) = ($AUTOLOAD =~ /::([^:]+)$/);
124 0           my @args = @_;
125              
126 0 0         if (exists $imWindowedFuncs{$name}) {
    0          
127 0           my $fi = $imWindowedFuncs{$name};
128              
129             # Create the function that should be called
130 0           my $body = " my \$s = shift;my \@args = \@_;\n";
131              
132 0           foreach my $dim (qw(x y w h)) {
133 0 0         if ($fi->{$dim}) {
134 0           foreach my $idx (@{$fi->{$dim}}) {
  0            
135 0           $body .= " \$args[$idx] = \$s->translate". uc($dim) ."(\$args[$idx]);\n";
136             }
137             }
138             }
139             # $body .= " print \"calling $name with \$s->{im} -> \@args\\n\"; my \$res = \$s->{im}->$name(\@args); \$s->postRenderAdjustment(); return \$res; \n";
140 0           $body .= " my \$res = \$s->{im}->$name(\@args); \$s->postRenderAdjustment(); return \$res; \n";
141             # print "Eval: $body\n";
142 0           eval "sub $name { $body }; return $name(\@args);";
143 0 0         if ($@) {
144 0           die "Failed eval of autoloaded sub: $@";
145             }
146             }
147             elsif (exists $imWindowedPolyFuncs{$name}) {
148              
149 0           my $body = qq ^
150             my (\$self, \$poly, \$color) = \@_;
151             my \$transPoly = GD::Polygon->new;
152              
153             # Need to go through all the points and adjust them
154             foreach my \$vertex (\$poly->vertices) {
155             \$transPoly->addPt(\$self->translateX(\$vertex->[0]), \$self->translateY(\$vertex->[1]));
156             }
157             \$self->{im}->$name(\$transPoly, \$color);
158             ^;
159             # print "Adding \@{\$vertex}\n";
160             # my \@v = \$transPoly->vertices;
161             #foreach my \$v (\@v) {
162             # print "poly: \@{\$v}\n";
163             #}
164              
165             # print "BODY: $body\n";
166 0           eval "sub $name { $body }; return $name(\@args);";
167 0 0         if ($@) {
168 0           die "Failed eval of autoloaded sub: $@";
169             }
170              
171             }
172             else {
173 0 0 0       if ($self->{passThroughIfUnsupported} || $self->{useImage}) {
174 0           eval("sub $name { my \$s = shift; my \$res = \$s->{im}->$name(\@_); \$s->postRenderAdjustment(); return \$res;}; return $name(\@_);");
175 0 0         if ($@) {
176 0           die "Failed eval of autoloaded sub: $@";
177             }
178             }
179             else {
180 0           croak "Sub $name is not supported by GD::Window";
181             }
182             }
183             }
184              
185              
186              
187             ##
188             # Methods that can't be handled by the AUTOLOAD
189             ##
190             sub boundsSafe {
191 0     0 0   my ($self, $x, $y) = @_;
192 0   0       return ($x >= $self->{minX} &&
193             $x <= $self->{maxX} &&
194             $y >= $self->{minY} &&
195             $y <= $self->{maxY});
196             }
197              
198             sub bounds {
199 0     0 0   my ($self) = @_;
200 0 0         if (!$self->{invertY}) {
201 0           return($self->{minX},
202             $self->{minY},
203             $self->{maxX},
204             $self->{maxY});
205             }
206             else {
207 0           return($self->{minX},
208             $self->{maxY},
209             $self->{maxX},
210             $self->{minY});
211             }
212             }
213              
214              
215             sub dimensions {
216 0     0 0   my ($self) = @_;
217 0           return($self->{maxX} - $self->{minX},
218             $self->{maxY} - $self->{minY});
219             }
220              
221              
222             ##
223             # Public Methods for changing globals
224             ##
225             sub invertY {
226 0     0 1   my ($that, $val) = @_;
227              
228 0 0         if (ref($that)) {
229 0           $that->{invertY} = $val;
230             }
231             else {
232 0           $invertY_g = $val;
233             }
234              
235             }
236              
237              
238             ##
239             # Private Methods
240             ##
241             sub translateX {
242 0     0 0   my ($self, $x) = @_;
243 0           my $newX = ($x - $self->{minX}) * $self->{scaleX} + $self->{imMinX};
244             # print "translate from $x to $newX, $self->{scaleX}, $self->{minX}, $self->{imMinX}\n";
245 0           return $newX;
246             }
247              
248             sub translateY {
249 0     0 0   my ($self, $y) = @_;
250 0 0         if ($self->{invertY}) {
251 0           $y = $self->{maxY} - $y;
252             }
253 0           my $newY = ($y - $self->{minY}) * $self->{scaleY} + $self->{imMinY};
254             # print "translate from $y to $newY, $self->{scaleY}\n";
255 0           return $newY;
256             }
257              
258             sub translateW {
259 0     0 0   my ($self, $w) = @_;
260 0           return $w * $self->{scaleX};
261             }
262              
263             sub translateH {
264 0     0 0   my ($self, $h) = @_;
265 0           return $h * $self->{scaleY};
266             }
267              
268             sub postRenderAdjustment {
269 0     0 0   my $self = shift;
270 0 0         return if !$self->{useImage};
271 0           $self->{parentIm}->copyResampled(
272             $self->{im}, $self->{srcImMinX}, $self->{srcImMinY}, 0, 0,
273             ($self->{imMaxX} - $self->{srcImMinX}), ($self->{imMaxY} - $self->{srcImMinY}),
274             ($self->{maxX} - $self->{minX}), ($self->{maxY} - $self->{minY}));
275             };
276              
277              
278 0     0     sub DESTROY {}
279              
280              
281             1;
282             __END__