Devel-WxProf
view release on metacpan or search on metacpan
lib/Devel/WxProf/Treemap/Output/Imager.pm view on Meta::CPAN
#my $top_pad = int(( $height - $metrix[5] ) * 0.1 );
#$top_pad = ( $top_pad > 5 ) ? 5 : $top_pad;
#$y = $y1 + $metrix[5] + $top_pad;
$self->{IMAGE}->string(
font => $self->{FONT},
text => $text,
x => $x1 + 1,
y => $y1 + $size,
color => $self->{SOLID_FONT},
size => $size,
);
return 1;
}
## font fitting algorhythm
# moved to seperate function, merged with guessing function
sub _font_fit {
my $self = shift;
my ( $width, $height, $text ) = @_;
my $DEBUG = $self->{TEXT_DEBUG};
return unless $text && ( length( $text ) ) && $height && $width;
my $local_iters = 0;
# Search for suitable font size
$self->{TEXT_DEBUG} && print STDERR "$text:\n";
# fetch a guess at the starting point:
# if not initialized:
unless ( $self->{ACWPP} )
{
# find average character width per point
$self->{ACWPP} = $self->_calc_avg_char_weight_per_pt();
croak( "Initialization of font fitting algorhythm failed." )
unless ( $self->{ACWPP} );
}
my $size = int( ( $width / length( $text ) ) / $self->{ACWPP} );
# because it is guaranteed to be not worth it:
return if ( $size <= ( $self->{MIN_FONT_SIZE} - 2 ) );
return $self->{ MAX_FONT_SIZE } if $size > $self->{ MAX_FONT_SIZE };
# test guess:
my @metrix = $self->{FONT}->bounding_box(
string => $text,
size => $size,
canon => 1 );
# two corrective measures:
# 1. if the width fits, but not the height, then we have a height
# restricted case. These tend to be expensive, so we "correct" our
# guess.
if (( $metrix[2] <= $width ) && ( $metrix[3] > $height )) {
# if there is a major difference in height, correct guess
if (( abs( $height - $metrix[3] ) / $height ) * $size >= 3 )
{
$self->{font_iters}++; $local_iters++; # track iterations
$self->{TEXT_DEBUG} && print STDERR "\tHeight restricted, changing $size =>";
$size = int( $size * ( $height / $metrix[3] ));
$self->{TEXT_DEBUG} && print STDERR "$size.\n";
@metrix = $self->{FONT}->bounding_box(
string => $text,
size => $size,
canon => 1 );
}
}
# 2. if our guess is way off width-wise, correct:
# if a correction would yeild a size change of more than 3,
# it is obviously worth it.
elsif ( ( abs( $width - $metrix[2] ) / $width ) * $size >= 3 )
{
$self->{font_iters}++; $local_iters++; # track iterations
$self->{TEXT_DEBUG} && print STDERR "\tOff by 3pts+, changing $size =>";
$size = int( $size * ( $width / $metrix[2] ));
$self->{TEXT_DEBUG} && print STDERR "$size.\n";
@metrix = $self->{FONT}->bounding_box(
string => $text,
size => $size,
canon => 1 );
}
# if our guess was too large, try smaller values until there is a fit:
if (( $metrix[2] > $width ) || ( $metrix[3] > $height )) {
$self->{TEXT_DEBUG} && print STDERR "\tGuess ($size) too large.\n";
while ( ( $metrix[2] > $width ) || ( $metrix[3] > $height ) )
{
$self->{font_iters}++; $local_iters++; # track iterations
$size--;
return if ( $size < 5 );
@metrix = $self->{FONT}->bounding_box(
string => $text,
size => $size,
canon => 1 );
}
}
# if our guess is too small, try larger values until there is a -no- fit:
elsif ( ( $metrix[2] <= $width ) && ( $metrix[3] <= $height )) {
$self->{TEXT_DEBUG} && print STDERR "\tGuess ($size) fits, adjusting.\n";
while ( ( $metrix[2] <= $width ) && ( $metrix[3] <= $height ) )
{
$self->{font_iters}++; $local_iters++; # track iterations
$size++;
$size++ if ( $size > 50 ); # grow a bit faster for big fonts
@metrix = $self->{FONT}->bounding_box(
string => $text,
size => $size,
canon => 1 );
}
$size--; # because this overshoots
}
$self->{TEXT_DEBUG} && print STDERR "\t$local_iters :: " . $self->{font_iters} . " => $size\n";
$size = int( $size * 0.9 ); # reduce size to fit comfortably
return if ( $size < $self->{MIN_FONT_SIZE} );
return $size;
}
###############################################
#
# private: _calc_avg_char_weight_per_pt
# input: none
# output: ACWPP
#
# pardon the size of this function name
# it only needs to be called in one place
#
sub _calc_avg_char_weight_per_pt {
my $self = shift;
my $wieghting_string = "rstlnaei0RST.-";
my $sample_size = 50;
# get metrix for sample:
my @metrix = $self->{FONT}->bounding_box(
string => $wieghting_string,
size => $sample_size,
canon => 1 );
my $sample_width = $metrix[2];
return unless ( $sample_width );
# avg width per character per point
return ( $sample_width / length( $wieghting_string ) / $sample_size );
}
sub width {
my $self = shift;
return $self->{WIDTH};
}
sub height {
my $self = shift;
return $self->{HEIGHT};
}
sub font_height {
( run in 3.599 seconds using v1.01-cache-2.11-cpan-800906f7e73 )