App-WIoZ

 view release on metacpan or  search on metacpan

lib/App/WIoZ.pm  view on Meta::CPAN

C<chg_font> : change font

C<font> : read font object

Usage :

  $wioz = App::WIoZ->new( font_min => 18, font_max => 64,
                          set_font => 'DejaVuSans,normal,bold');
  
  $fontname = $wioz->font->{font};
  $wioz->chg_font('LiberationSans,normal,bold');


=cut

has 'font' => (
   isa    => 'HashRef',
   is => 'ro', lazy => 1,
   writer => 'chg_font',
   builder => '_set_font'
);

# for font builder
has 'set_font' => ( is => 'rw',isa => 'Str' );

sub _set_font {
    my ($self,$font) = @_;
    my ($fname,$ftype,$fweight) = split ',', ($self->set_font || ',,');
    return ( { font => $fname || 'LiberationSans',
               type => $ftype || 'normal',
               weight => $fweight || 'bold' });
};

# for font change
around 'chg_font' => sub  {
        my ($next,$self,$font) = @_;
        my ($fname,$ftype,$fweight) = split ',', $font;
        $self->$next( {font => $fname, type => $ftype, weight => $fweight});
};

has 'backcolor' => (
    is => 'ro', isa => 'Str',
    default => 'white'
);

has 'cr' => (
    is => 'rw', isa => 'Cairo::Context',
    lazy => 1, builder => '_create_cr'
);

has 'surface' => (
    is => 'rw', isa => 'Cairo::ImageSurface',
);

has 'svgsurface' => (
    is => 'rw', isa => 'Cairo::SvgSurface',
);

=head2 filename

file name output, extension C<.png> or C<.svg> will be added 

=cut

has 'filename' => (
    is => 'rw', isa => 'Str',
);

=head2 svg

produce a svg output, default value

set to 0 to write a png

=cut

has 'svg' => (
  is => 'ro', isa => 'Int', default => 1
);

has 'fcurve' => (
    is => 'rw', isa => 'Math::PlanePath',
);

=head2 scale

Scale for the Hilbert Curve granularity default to 10

Higer value produces better speed but more words recovery.

=cut

has 'scale' => (
    is =>'ro', isa => 'Int', default => 10 # 20 better
);

has 'cused' => (
    is => 'rw', isa => 'ArrayRef[Int]', default => sub {[]}
);

=head2 basecolor

Base color for color theme, default to 882222

=cut

has 'basecolor' => (
    is =>'ro', isa => 'Str', default => '882222'
);

=head1 METHODS

=cut

sub _create_cr {
    my $self = shift;
    my $scale = $self->scale;
    my $hilbert = Math::PlanePath::HilbertCurve->new;
    $self->fcurve($hilbert);
    my $cr;

    if ($self->svg) {
        my $svgsurface = Cairo::SvgSurface->create ($self->filename.'.svg', $self->width, $self->height);
        $self->svgsurface($svgsurface);
        $cr = Cairo::Context->create($svgsurface);
    }
    else {
        my $surface = Cairo::ImageSurface->create ('argb32', $self->width, $self->height);
        $self->surface($surface);
        $cr = Cairo::Context->create($surface);
    };

    $cr->save;

lib/App/WIoZ.pm  view on Meta::CPAN

    foreach my $l (@L) {
        my ($t,$n) = split /;/,$l;
        if ( $t && $n ) {
            $t =~ s/\s*$//g; $n =~ s/\s*$//g;
            #$all_weight += $n;
            $weight_max = $n if ( $n >$weight_max );
            $weight_min = $n if ( $n <$weight_min );
            my $w = new App::WIoZ::Word(text => $t, weight => $n, font => $self->font);
            push @res, $w;
        } else {
            warn "error line: $_";
        }
    }
    # set initial size and color
    my @color = Color::Mix->new->analogous($self->basecolor, 12, 12);
    foreach my $v (@res) {
       $v->size( (($v->weight - $weight_min) / ($weight_max - $weight_min)) *
                      ($self->font_max - $self->font_min) +
                      $self->font_min );
       $v->color($color[int(rand(12))]);
    }
    return @res;
}


=head2 update_colors

Read words position from file and update colors.

Usage:

   $wioz->update_colors("file.sl.txt");

=cut

sub update_colors{
    my ($self, $filename) = @_;

    open my $fh, '<:utf8', $filename or die $filename . ' : ' .$!;
    my @L = <$fh>;
    close $fh;

    my @color = Color::Mix->new->analogous($self->basecolor, 12, 12);

    # reset background
    $self->cr->rectangle (0, 0, $self->width, $self->height);
    my $po = Graphics::ColorNames->new;
    my @rgb = $po->rgb($self->backcolor);
    $self->cr->set_source_rgb ($rgb[0]/255.0, $rgb[1]/255.0, $rgb[2]/255.0);
    $self->cr->fill;

    foreach my $l (@L) {
        my ($show,$text,$size,$x,$y,$angle) = split /\t/,$l;
        #say "$text - $size - $angle";
        my $w = App::WIoZ::Word->new(text => $text, size => $size, angle => $angle, show => $show, color => $color[int(rand(12))], font => $self->font);
        my $newc = App::WIoZ::Point->new( x => $x, y => $y);
        $w->update_size($self,$size);
        $w->update_c($newc);
        $self->_show_word($w);
    }
    $self->_save_to_png if (!$self->svg);
}

=head2 do_layout

Compute words position, save result to svg or png image, save in C<filename.sl.txt> words positions to update colors.

Usage :
   $wioz->do_layout(@words);

=cut

sub do_layout {
    my ($self,@words) = @_;
    my $c = 0;
    my $current = undef;
    my @dx = (1, 1, 0, 0,-1,-1,-1,-1, 0, 0, 1, 1);
    my @dy = (0, 1, 1, 1, 1, 0, 0,-1,-1,-1,-1, 0);

    #foreach my $w (@words) {
    foreach my $w (sort {$b->weight cmp $a->weight} @words) {
      # init
      $w->show(1);
      $w->update_size($self,$w->size) if (!$w->height && !$w->width);
      $current = $w if (! $current);

      # process
      my $inside;
      my @ranges;

    my ($x1, $y1) = my ($x, $y) = (int($self->width/2), int($self->height/2));
    my $step = $self->scale;
    my $dir = 0;
    my $i = 0;
    do {
        # spiral
        my $newc = App::WIoZ::Point->new( x => int($x), y => int($y));
        $x1 = $x1 + $dx[$i%12] * $step;
        $y1 = $y1 + $dy[$i%12] * $step;
        $x = $x1; $y = $y1;
        $step += 2 ;
        $w->update_c($newc);
        # is in free space
        $inside = ($w->p->x > 0 && $w->p->x <= $self->width &&
          $w->p2->x > 0 && $w->p2->x <= $self->width &&
          $w->p->y > 0 && $w->p->y <= $self->height &&
          $w->p2->y > 0 && $w->p2->y <= $self->height) || 0;
        @ranges = $w->is_free($self) if $inside;
        # try some other strategy
        $i++;
        if ($i>60 || !$inside) {
            $i = 10;
            $step=$self->scale;
            my ($xt,$yt) = $self->_random_point($current->width,$current->height);
            ($x1, $y1) = ($x, $y) = ($current->p->x + $xt,$current->p->y - $yt);
            if ( ! $dir ) {
                $dir = 1;
                #say '  revert : '.$w->text;
                my @rdx = reverse @dx;
                my @rdy = reverse @dy;
                @dx = @rdx; @dy = @rdy;
            }
            else {
                $dir = 0;
                if ($w->size - 1 <= 5) {
                    #say '  no place for : '.$w->text;
                    $w->show(0);
                    next;
                }
                #say '  decrease : '.$w->text;
                $w->update_size($self,$w->size - 1);
            }
        };
    } while ( ! $inside  || scalar @ranges == 1 );

    # register used space
    map { if ($_) {push @{ $self->cused }, $_} } @ranges;

    # show
    $self->_show_word($w) if ($w->show);

    #$c++; last if $c > 2;
    }

    $self->_save_to_png if (!$self->svg);

    $self->_save_layout(@words);

}

sub _save_to_png {
        my $self = shift;
        $self->surface->write_to_png ($self->filename . '.png');
}

# Save words position to a file. Usefull to update colors.
sub _save_layout {
    my ($self, @words) = @_;
    my $fh;
    open $fh, '>:utf8', $self->filename . '.sl.txt';
    foreach my $w (@words) {
        print $fh $w->show."\t".$w->text."\t".$w->size."\t".$w->c->x."\t".$w->c->y."\t".$w->angle."\n";
    }
    close $fh;
}


sub _show_word {
    my ($self,$w) = @_;

    $self->cr->select_font_face(
        $w->font->{font},$w->font->{type},$w->font->{weight});
    $self->cr->set_font_size($w->size);
    my $po = Graphics::ColorNames->new;
    my @rgb = $po->rgb($w->color);
    $self->cr->set_source_rgb ($rgb[0]/255.0, $rgb[1]/255.0, $rgb[2]/255.0);
    #say '  '.$w->text.' '.$w->color;
    if ($w->angle < 0) {
        $self->cr->save;
        $self->cr->move_to($w->p->x+$w->width,$w->p->y);
        $self->cr->rotate($w->angle);
        $self->cr->show_text($w->text);
        $self->cr->restore;
    }
    else {
     $self->cr->move_to($w->p->x,$w->p->y);
     $self->cr->show_text($w->text);
    }

}

sub _random_point {
    my ($self,$width, $height) = @_;
    my $x = rand( $width * 0.8 ) + $width * 0.1 ;
    my $y = rand( $height * 0.8 ) + $height * 0.1 ;
    return ($x, $y);
}

=head1 Git

L<https://github.com/yvesago/WIoZ/>

=head1 AUTHORS

Yves Agostini, C<< <yveago@cpan.org> >>

=head1 LICENSE AND COPYRIGHT

Copyright 2013 - Yves Agostini 

This program is free software and may be modified or distributed under the same terms as Perl itself.

=cut



( run in 3.829 seconds using v1.01-cache-2.11-cpan-744e820c463 )