File Coverage

blib/lib/Image/Magick/Text/AutoBreak.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Image::Magick::Text::AutoBreak;
2 1     1   33301 use warnings;
  1         3  
  1         34  
3 1     1   5 use strict;
  1         2  
  1         36  
4 1     1   6 use Carp;
  1         5  
  1         108  
5 1     1   482 use Image::Magick;
  0            
  0            
6             use Encode qw(decode);
7             our $VERSION = '0.02';
8              
9             ### ---------------------------------------------------------------------------
10             ### Constractor
11             ### ---------------------------------------------------------------------------
12             sub new {
13            
14             my $class = shift;
15             my $self =
16             bless {
17             magick => undef,
18             charset => 'utf8',
19             ngCharaForHead => undef,
20             ngCharaForTail => undef,
21             ngCharaForSepa => undef,
22             x => 0,
23             y => 0,
24             width => undef,
25             height => undef,
26             'line-spacing' => 4,
27             _plan => [],
28             _result => undef,
29             @_}, $class;
30            
31             if (! $self->{width}) {
32            
33             $self->{width} = $self->{magick}->Get('width') - $self->{x};
34             }
35            
36             if (! $self->{height}) {
37            
38             $self->{height} = $self->{magick}->Get('height') - $self->{y};
39             }
40            
41             return $self;
42             }
43              
44             ### ---------------------------------------------------------------------------
45             ### Prepare the plan for annotation
46             ### This calls for same params as Image::Magick->Annotate
47             ### ---------------------------------------------------------------------------
48             sub prepare {
49            
50             my $self = shift;
51             my %args = (
52             text => '',
53             fill => '#000000',
54             pointsize => 9,
55             @_);
56            
57             $self->{_result} = {width => 0, height => 0};
58            
59             my $in_str =
60             utf8::is_utf8($args{text})
61             ? $args{text}
62             : decode($self->{charset}, $args{text});
63            
64             my $y_pos = $self->{y};
65            
66             foreach my $line (split(/\r\n|\n|\r/, $args{text})) {
67            
68             if ($y_pos > $self->{y} + $self->{height}) {
69            
70             last;
71             }
72            
73             if (! $line) {
74            
75             $y_pos += $args{pointsize} + $self->{'line-spacing'};
76             next;
77             }
78            
79             $y_pos =
80             $self->_makePlan(
81             %args,
82             text => $line,
83             x => $self->{x},
84             y => $y_pos + $self->{'line-spacing'}
85             );
86             }
87            
88             if ($y_pos > $self->{_result}->{height}) {
89            
90             $self->{_result}->{height} = $y_pos;
91             }
92            
93             return $self->getResult();
94             }
95              
96             ### ---------------------------------------------------------------------------
97             ### make plan for annotation
98             ### @return int height
99             ### ---------------------------------------------------------------------------
100             sub _makePlan {
101            
102             my $self = shift;
103             my %args = (@_);
104            
105             $args{text} =~ s/^\s//;
106            
107             my @box;
108            
109             ### set initial position to last length
110             my $pos1 = ($args{_last_length} or 1);
111            
112             @box =
113             $self->{magick}->QueryFontMetrics(
114             %args, text => substr($args{text}, 0, $pos1)
115             );
116            
117             ### Set destination of search for horizontal limit
118             my $increment = ($box[4] > $self->{width}) ? -1 : 1;
119            
120             ### Search for horizontal limit
121             for (my $i = $pos1;
122             $i > 0 and $i <= length($args{text});
123             $i += $increment) {
124            
125             @box =
126             $self->{magick}->QueryFontMetrics(
127             %args,
128             text => substr($args{text}, 0, $i),
129             );
130            
131             if ($increment == 1 and $box[4] > $self->{width}) {
132            
133             last;
134             }
135            
136             $pos1 = $i;
137            
138             if ($increment == -1 and $box[4] < $self->{width}) {
139            
140             last;
141             }
142             }
143            
144             if ($args{y} + $box[5] > $self->{y} + $self->{height}) {
145            
146             return $args{y};
147             }
148            
149             ### word wrapping
150             if ($pos1 < length($args{text})) {
151            
152             while ($pos1 > 1) {
153            
154             my $next = substr($args{text}, $pos1, 1);
155            
156             if ($next and $next =~ $self->{ngCharaForHead}) {
157            
158             $pos1--; next;
159             }
160            
161             my $last = substr($args{text}, $pos1 - 1, 1);
162            
163             if ($last and $last =~ $self->{ngCharaForTail}) {
164            
165             $pos1--; next;
166             }
167            
168             if ($last =~ $self->{'ngCharaForSepa'} and
169             $next =~ $self->{'ngCharaForSepa'}) {
170            
171             $pos1--; next;
172             }
173            
174             last;
175             }
176            
177             @box =
178             $self->{magick}->QueryFontMetrics(
179             %args,
180             text => substr($args{text}, 0, $pos1)
181             );
182             }
183            
184             ### Record result
185             if ($box[4] > $self->{_result}->{width}) {
186            
187             $self->{_result}->{width} = $box[4];
188             }
189              
190             $args{_last_length} = $pos1;
191            
192             push(@{$self->{_plan}},
193             {
194             %args,
195             text => substr($args{text}, 0, $pos1),
196             y => $args{y} + $box[5]
197             }
198             );
199            
200             ### Evaluate tail str
201             if ($pos1 < length($args{text})) {
202            
203             return
204             $self->_makePlan(
205             %args,
206             y => $args{y} + $box[5] + $self->{'line-spacing'},
207             text => substr($args{text}, $pos1)
208             );
209             }
210            
211             ### Returns bottom position of written box
212             return $args{y} + $args{pointsize};
213             }
214              
215             ### ----------------------------------------------------------------------------
216             ### annotate
217             ### This calls for same params as Image::Magick->Annotate
218             ### ----------------------------------------------------------------------------
219             sub annotate {
220            
221             my $self = shift;
222             my %args = (@_);
223            
224             for my $default_args (@{$self->{_plan}}) {
225            
226             $self->{magick}->Annotate(%$default_args, %args);
227             }
228            
229             return $self->getResult();
230             }
231             ### ----------------------------------------------------------------------------
232             ### get result
233             ### @return int width or height
234             ### ----------------------------------------------------------------------------
235             sub getResult {
236            
237             my $self = shift;
238            
239             if ($_[0]) {
240            
241             return $self->{_result}->{$_[0]};
242             }
243            
244             return ($self->{_result}->{width}, $self->{_result}->{height});
245             }
246              
247             1; # Magic true value required at end of module
248             __END__