File Coverage

blib/lib/Graphics/DZI/Document.pm
Criterion Covered Total %
statement 11 13 84.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 16 18 88.8


line stmt bran cond sub pod time code
1             package Graphics::DZI::Document;
2              
3 1     1   3946 use strict;
  1         3  
  1         36  
4 1     1   5 use warnings;
  1         2  
  1         43  
5              
6             our $log;
7 1     1   373321 use Log::Log4perl;
  1         1574932  
  1         8  
8             BEGIN {
9 1     1   64 $log = Log::Log4perl->get_logger ();
10             }
11              
12             =head1 NAME
13              
14             Graphics::DZI::Document - DeepZoom Image Pyramid, Sparse Document Images
15              
16             =head1 SYNOPSIS
17              
18             # prepare a bunch of Image::Magick objects
19             @pages = ......;
20              
21             # create the overlay itself
22             use Graphics::DZI::Document;
23             my $o = new Graphics::DZI::Document (pages => \@pages,
24             x => 80000, 'y' => 40000,
25             pack => 'linear',
26             squeeze => 256);
27              
28             # use the Graphics::DZI::Files and add this as overlay
29              
30             =head1 DESCRIPTION
31              
32             This subclass of L<Graphics::DZI::Overlay> handles documents as overlays for extremely sparse
33             DeepZoom images. Documents here are also images, but not a single one, but one for each document
34             page.
35              
36             What is also different from a normal overlay image is that document overlays will show a different
37             number of images, depending on the zoom level. First, when the canvas is the dominant feature, only
38             a small first page is show. Whenever that first page is fairly readable, the first 4 pages are shown
39             in the slot. Then the next 9 or 16, depending on whether the growth is C<linear> or C<exponential>.
40              
41             =cut
42              
43 1     1   911 use Moose;
  0            
  0            
44             extends 'Graphics::DZI::Overlay';
45              
46             =head1 INTERFACE
47              
48             =head2 Constructor
49              
50             Different to the superclass not the image, but a sequence of pages have to be passed in. Optionally,
51             a parameter C<pack> determines between C<linear> and C<exponential> growth of pages at higher
52             resolutions. With linear you actually get 1, 4, 9, 16, 25... documents (so it is actually squared
53             linear). With exponential you get more aggressively 1, 4, 16, 32, ... pages.
54              
55             =cut
56              
57             use Moose::Util::TypeConstraints qw(enum);
58             enum 'packing' => qw( exponential linear );
59              
60             has 'pages' => (isa => 'ArrayRef', is => 'rw', required => 1);
61             has '+image' => (isa => 'Image::Magick', required => 0);
62             has 'W' => (isa => 'Int' , is => 'rw');
63             has 'H' => (isa => 'Int' , is => 'rw');
64             has 'sqrt' => (isa => 'Num', is => 'rw');
65             has 'pack' => (isa => 'packing', is => 'rw', default => 'exponential');
66              
67             sub BUILD {
68             my $self = shift;
69             ($self->{W}, $self->{H}) = $self->pages->[0]->GetAttributes ('width', 'height'); # single document
70              
71             use feature "switch";
72             given ($self->{pack}) {
73             when ('linear') {
74             use POSIX;
75             $self->{ sqrt } = POSIX::ceil ( sqrt ( scalar @{$self->pages}) ); # take the root + 1
76             }
77             when ('exponential') {
78             use POSIX;
79             my $log2 = POSIX::ceil (log (scalar @{$self->pages}) / log (2)); # next fitting 2-potenz
80             $log2++ if $log2 % 2; # we can only use even ones
81             $self->{ sqrt } = ( 2**($log2/2) ); # how many along one edge when we organize them into a square?
82             }
83             default { die "unhandled packing"; }
84             }
85              
86             $self->{ image } = _list2huge ($self->sqrt, $self->W, $self->H, @{ $self->pages }) ;
87             }
88              
89             sub _list2huge {
90             my $sqrt = shift;
91             my ($W, $H) = (shift, shift);
92              
93             my $dim = sprintf "%dx%d", map { $_ * $sqrt } ($W, $H);
94             $log->debug ("building composite document: DIM $dim ($sqrt)");
95             use Image::Magick;
96             my $huge = Image::Magick->new ($dim);
97             $huge->Read ('xc:white');
98             $huge->Transparent (color => 'white');
99              
100             foreach my $a (0 .. $sqrt*$sqrt - 1) {
101             last unless $_[$a];
102             my ($j, $i) = ( int( $a / $sqrt) , $a % $sqrt );
103             $log->debug (" index $a (x,y) = $i $j");
104              
105             $huge->Composite (image => $_[$a],
106             x => $i * $W,
107             'y' => $j * $H,
108             compose => 'Over',
109             );
110             }
111             # $huge->Display();
112             return $huge;
113             }
114              
115             =head2 Methods
116              
117             =over
118              
119             =item B<halfsize>
120              
121             This will be called by the overall DZI algorithm whenever this overlay is to be size-reduced by 2.
122              
123             =cut
124              
125             sub halfsize {
126             my $self = shift;
127              
128             my ($w, $h) = $self->image->GetAttributes ('width', 'height'); # current dimensions
129             if ($self->{ sqrt } > 1) {
130             use feature "switch";
131             given ($self->{pack}) {
132             when ('linear') { $self->{ sqrt }--; } # in linear packing we simply reduce the square root by one
133             when ('exponential') { $self->{ sqrt } /= 2; }
134             default {}
135             }
136             $self->{ image } = _list2huge ($self->sqrt, # pack sqrt x sqrt A4s into one image
137             $self->W, $self->H,
138             @{ $self->pages });
139             }
140             $self->image->Resize (width => int($w/2), height => int($h/2)); # half size
141             $self->{x} /= 2; # dont forget x, y
142             $self->{y} /= 2;
143             }
144              
145             =back
146              
147             =head1 AUTHOR
148              
149             Robert Barta, C<< <drrho at cpan.org> >>
150              
151             =head1 COPYRIGHT & LICENSE
152              
153             Copyright 2010 Robert Barta, all rights reserved.
154              
155             This program is free software; you can redistribute it and/or modify it under the same terms as Perl
156             itself.
157              
158             =cut
159              
160             our $VERSION = '0.01';
161              
162             "against all odds";
163              
164             __END__