File Coverage

blib/lib/Graphics/DZI/Overlay.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Graphics::DZI::Overlay;
2              
3 1     1   4628 use strict;
  1         2  
  1         43  
4 1     1   7 use warnings;
  1         2  
  1         28  
5              
6 1     1   472 use Moose;
  0            
  0            
7              
8             our $log;
9             use Log::Log4perl;
10             BEGIN {
11             $log = Log::Log4perl->get_logger ();
12             }
13              
14             =head1 NAME
15              
16             Graphics::DZI::Overlay - DeepZoom Image Pyramid, Sparse Images
17              
18             =head1 SYNOPSIS
19              
20             # build some overlays first
21             use Graphics::DZI::Overlay;
22             my $o1 = new Graphics::DZI::Overlay (image => ..., # what is the image?
23             x => 1000, y=>1000, # where on the canvas?
24             squeeze => 64); # how much smaller than the canvas?
25             my $o2 = new Graphics::DZI::Overlay (image => ..., # what is the image?
26             x => 2000, y=>2000, # where on the canvas?
27             squeeze => 32); # how much smaller than the canvas?
28             # then add the overlay over the canvas
29             use Graphics::DZI::Files;
30             my $dzi = new Graphics::DZI::Files (image => $image,
31             overlap => 4,
32             tilesize => 512,
33             format => 'png',
34             overlays => [ $o1, $o2],
35             path => $path . 'xxx_files/',
36             prefix => 'xxx',
37             );
38             # normal DZI generation
39             write_file ($path . 'xxx.xml', $dzi->descriptor);
40             $dzi->iterate ();
41              
42             =head1 DESCRIPTION
43              
44             This package can hold one overlay image, together with a coordinate and a factor how much this
45             images is smaller than the canvas onto which the image is to be put.
46              
47             =head1 INTERFACE
48              
49             =head2 Constructor
50              
51             It expects the following fields:
52              
53             =over
54              
55             =item C<image>: (required)
56              
57             L<Image::Magick> object.
58              
59             =item C<x>,C<y>: (integers, no default)
60              
61             Coordinates of the top-left corner of the above image on the canvas
62              
63             =item C<squeeze>: (integers, no default)
64              
65             A factor how much the image should be made smaller, relative to the canvas. I use a power of two to
66             avoid that the canvas is a bit fuzzy.
67              
68             =back
69              
70             =cut
71              
72             has 'image' => (isa => 'Image::Magick', is => 'rw', required => 1);
73             has 'x' => (isa => 'Int', is => 'rw');
74             has 'y' => (isa => 'Int', is => 'rw');
75             has 'squeeze' => (isa => 'Num', is => 'rw');
76              
77             =head2 Methods
78              
79             =over
80              
81             =item B<halfsize>
82              
83             Makes the overlay smaller by 2. This will be called by the DZI algorithm.
84              
85             =cut
86              
87             sub halfsize {
88             my $self = shift;
89             my ($w, $h) = $self->image->GetAttributes ('width', 'height'); # current dimensions
90             $self->image->Resize (width => int($w/2), height => int($h/2)); # half size
91             $self->{x} /= 2; # dont forget x, y
92             $self->{y} /= 2;
93             }
94              
95             =item B<crop>
96              
97             Gets a tile off the overlay.
98              
99             =cut
100              
101             sub crop {
102             my $self = shift;
103             my ($tx, $ty, $tdx, $tdy) = @_;
104              
105             my ($w, $h) = $self->{image}->GetAttributes ('width', 'height');
106             $self->{dx} = $w;
107             $self->{dy} = $h;
108              
109             # warn "before intersection tile $tile"; $tile->Display() if $tile;
110             if (my $r = _intersection ($tx, $ty, $tx+$tdx, $ty+$tdy, # tile and overlay intersect?
111             $self->{x}, $self->{y}, $self->{x} + $self->{dx}, $self->{y} +$self->{dy})) {
112             # warn " intersection!";
113             my ($ox, $oy, $dx, $dy) = (
114             $r->[0] - $self->{x}, # x relative to overlay
115             $r->[1] - $self->{y}, # y relative to overlay
116              
117             $r->[2] - $r->[0], # width of the intersection
118             $r->[3] - $r->[1], # height
119             );
120              
121             my $oc = $self->{image}->clone;
122             # warn "overlay clone "; $oc->Display();
123             $oc->Crop (geometry => "${dx}x${dy}+${ox}+${oy}");
124             # warn "cropped oc"; $oc->Display();
125              
126             # unless ($tile) { # this just makes sure that we are composing onto SOMETHING
127             ## warn "XXXXXXXXX generating substitute tile";
128             my $tile = Image::Magick->new ("${tdx}x${tdy}"); # create an empty one
129             $tile->Read ('xc:yellow'); # paint it white (otherwise composite would not work?)
130             $tile->Transparent (color => 'yellow');
131             # warn "substitute tile "; $tile->Display();
132             # }
133             # warn "before overlay tile "; $tile->Display();
134             $tile->Composite (image => $oc,
135             x => $r->[0] - $tx, # intersection left/top relative to tile
136             'y' => $r->[1] - $ty,
137             compose => 'Over',
138             );
139             # warn "after overlay tile "; $tile->Display();
140             return $tile;
141             }
142             return undef;
143             }
144              
145             sub _intersection {
146             my ($ax, $ay, $axx, $ayy,
147             $bx, $by, $bxx, $byy) = @_;
148              
149             if (_intersects ($ax, $ay, $axx, $ayy,
150             $bx, $by, $bxx, $byy)) {
151             return [
152             $ax > $bx ? $ax : $bx,
153             $ay > $by ? $ay : $by,
154             $axx > $bxx ? $bxx : $axx,
155             $ayy > $byy ? $byy : $ayy
156             ];
157             }
158             }
159              
160             sub _intersects {
161             my ($ax, $ay, $axx, $ayy,
162             $bx, $by, $bxx, $byy) = @_;
163              
164             return undef
165             if $axx < $bx
166             || $bxx < $ax
167             || $ayy < $by
168             || $byy < $ay;
169             return 1;
170             }
171              
172             =back
173              
174             =head1 AUTHOR
175              
176             Robert Barta, C<< <drrho at cpan.org> >>
177              
178             =head1 COPYRIGHT & LICENSE
179              
180             Copyright 2010 Robert Barta, all rights reserved.
181              
182             This program is free software; you can redistribute it and/or modify it under the same terms as Perl
183             itself.
184              
185             =cut
186              
187             our $VERSION = '0.01';
188              
189             "against all odds";
190