Win32::PowerPoint - helps to convert texts to PP slides


Win32-PowerPoint documentation Contained in the Win32-PowerPoint distribution.

Index


Code Index:

NAME

Top

Win32::PowerPoint - helps to convert texts to PP slides

SYNOPSIS

Top

    use Win32::PowerPoint;

    # invoke (or connect to) PowerPoint
    my $pp = Win32::PowerPoint->new;

    # set presentation-wide information
    $pp->new_presentation(
      background_forecolor => [255,255,255],
      background_backcolor => 'RGB(0, 0, 0)',
      pattern => 'Shingle',
    );

    # and master footer if you prefer (optional)
    $pp->set_master_footer(
      visible         => 1,
      text            => 'My Slides',
      slide_number    => 1,
      datetime        => 1,
      datetime_format => 'MMMMyy',
    );

    (load and parse your slide text)

    # do whatever you want to do for each of your slides
    foreach my $slide (@slides) {
      $pp->new_slide;

      $pp->add_text($slide->title, { size => 40, bold => 1 });
      $pp->add_text($slide->body);
      $pp->add_text($slide->link,  { link => $slide->link });

      # you may add pictures
      $pp->add_picture($file, { left => 10, top => 10 });
    }

    $pp->save_presentation('slide.ppt');

    $pp->close_presentation;

    # PowerPoint closes automatically

DESCRIPTION

Top

Win32::PowerPoint mainly aims to help to convert Spork (or Sporx) texts to PowerPoint slides. Though there's no converter at the moment, you can add texts to your new slides/presentation and save it.

METHODS

Top

new

Invokes (or connects to) PowerPoint.

connect_or_invoke

Explicitly connects to (or invoke) PowerPoint.

quit

Explicitly disconnects from PowerPoint, and closes it if this module invoked it.

new_presentation (options)

Creates a new (probably blank) presentation. Options are:

background_forecolor, background_backcolor

You can specify background colors of the slides with an array ref of RGB components ([255, 255, 255] for white) or formatted string ('255, 0, 0' for red). You can use '(0, 255, 255)' or 'RGB(0, 255, 255)' format for clarity. These colors are applied to all the slides you'll add, unless you specify other colors for the slides explicitly.

You can use 'masterbkgforecolor' and 'masterbkgbackcolor' as aliases.

pattern

You also can specify default background pattern for the slides. See Win32::PowerPoint::Constants (or MSDN or PowerPoint's help) for supported pattern names. You can omit 'msoPattern' part and the names are case-sensitive.

save_presentation (path)

Saves the presentation to where you specified. Accepts relative path. You might want to save it as .pps (slideshow) file to make it easy to show slides (it just starts full screen slideshow with a doubleclick).

close_presentation

Explicitly closes the presentation.

new_slide (options)

Adds a new (blank) slide to the presentation. Options are:

background_forecolor, background_backcolor

You can set colors just for the slide with these options. You can use 'bkgforecolor' and 'bkgbackcolor' as aliases.

pattern

You also can set background pattern just for the slide.

add_text (text, options)

Adds (formatted) text to the slide. Options are:

left, top, width, height

of the Textbox.

See 'decorate_range' for other options.

add_picture (file, options)

Adds file to the slide. Options are:

left, top, width, height

of the picture. width and height are optional.

If set to true, the picture will be linked, otherwise, embedded.

insert_before (text, options)

insert_after (text, options)

Prepends/Appends text to the current Textbox. See 'decorate_range' for options.

decorate_range (range, options)

Decorates text of the range. Options are:

bold, italic, underline, shadow, subscript, superscript

Boolean.

size

Integer.

color

See above for the convention.

font

Font name of the text. You can use 'name' as an alias.

alignment

One of the 'left' (default), 'center', 'right', 'justify', 'distribute'.

You can use 'align' as an alias.

hyperlink address of the Text.

(This method is mainly for the internal use).

IF YOU WANT TO GO INTO DETAIL

Top

This module uses Win32::OLE internally. You can fully control PowerPoint through these accessors. If you don't know what to do with them, launch PowerPoint, and try Record New Macro (from the Tools menu, then, Macro, and voila) and do what you want, and see what's recorded (from the Tools menu, then Macro, and Macro... submenu. You'll see Visual Basic Editor screen). If you don't know how to convert Visual Basic statements to perl's OLE methods, see Win32::OLE and other appropriate documents like intermediate books on PowerPoint and Visual Basic (after all, this module is just a thin wrapper of them).

application

returns an Application object.

    print $pp->application->Name;

presentation

returns a current Presentation object (maybe ActivePresentation but that's not assured).

    $pp->save_presentation('sample.ppt') unless $pp->presentation->Saved;

    while (my $last = $pp->presentation->Slides->Count) {
      $pp->presentation->Slides($last)->Delete;
    }

slide

returns a current Slide object.

    $pp->slide->Export(".\\slide_01.jpg",'jpg');

    $pp->slide->Shapes(1)->TextFrame->TextRange
       ->Characters(1, 5)->Font->{Bold} = $pp->c->True;

c

returns Win32::PowerPoint::Constants object.

CAVEATS FOR CYGWIN USERS

Top

This module itself seems to work under the Cygwin environment. However, MS PowerPoint expects paths to be Windows-ish, namely without /cygdrive/. So, when you load or save a presentation, or import some materials with OLE (native) methods, you usually need to convert them by yourself. As of 0.08, Win32::PowerPoint::Utils has a convert_cygwin_path function for this. Win32::PowerPoint methods use this function internally, so you don't need to convert paths explicitly.

AUTHOR

Top

Kenichi Ishigaki, <ishigaki@cpan.org>

COPYRIGHT AND LICENSE

Top


Win32-PowerPoint documentation Contained in the Win32-PowerPoint distribution.

package Win32::PowerPoint;

use strict;
use warnings;
use Carp;
use base qw( Class::Accessor::Fast );

our $VERSION = '0.09';

use File::Spec;
use File::Basename;
use Win32::OLE;
use Win32::PowerPoint::Constants;
use Win32::PowerPoint::Utils qw(
  RGB
  canonical_alignment
  canonical_pattern
  canonical_datetime
  convert_cygwin_path
  _defined_or
);

__PACKAGE__->mk_ro_accessors( qw( c application presentation slide ) );

sub new {
  my $class = shift;
  my $self  = bless {
    c            => Win32::PowerPoint::Constants->new,
    was_invoked  => 0,
    application  => undef,
    presentation => undef,
    slide        => undef,
  }, $class;

  $self->connect_or_invoke;

  return $self;
}

##### application #####

sub connect_or_invoke {
  my $self = shift;

  $self->{application} = Win32::OLE->GetActiveObject('PowerPoint.Application');

  unless (defined $self->{application}) {
    $self->{application} = Win32::OLE->new('PowerPoint.Application')
      or die Win32::OLE->LastError;
    $self->{was_invoked} = 1;
  }
}

sub quit {
  my $self = shift;

  return unless $self->application;

  $self->application->Quit;
  $self->{application} = undef;
}

##### presentation #####

sub new_presentation {
  my $self = shift;

  return unless $self->{application};

  my %options = ( @_ == 1 and ref $_[0] eq 'HASH' ) ? %{ $_[0] } : @_;

  $self->{slide} = undef;

  $self->{presentation} = $self->application->Presentations->Add
    or die Win32::OLE->LastError;

  $self->_apply_background(
    $self->presentation->SlideMaster->Background->Fill,
    %options
  );
}

sub _apply_background {
  my ($self, $target, %options) = @_;

  my $forecolor = _defined_or(
    $options{background_forecolor},
    $options{masterbkgforecolor}
  );
  if ( defined $forecolor ) {
    $target->ForeColor->{RGB} = RGB($forecolor);
    $self->slide->{FollowMasterBackground} = $self->c->msoFalse if $options{slide};
  }

  my $backcolor = _defined_or(
    $options{background_backcolor},
    $options{masterbkgbackcolor}
  );
  if ( defined $backcolor ) {
    $target->BackColor->{RGB} = RGB($backcolor);
    $self->slide->{FollowMasterBackground} = $self->c->msoFalse if $options{slide};
  }

  if ( defined $options{pattern} ) {
    if ( $options{pattern} =~ /\D/ ) {
      my $method = canonical_pattern($options{pattern});
      $options{pattern} = $self->c->$method;
    }
    $target->Patterned( $options{pattern} );
  }
}

sub save_presentation {
  my ($self, $file) = @_;

  return unless $self->presentation;
  return unless defined $file;

  my $absfile   = File::Spec->rel2abs($file);
  my $directory = dirname( $file );
  unless (-d $directory) {
    require File::Path;
    File::Path::mkpath($directory);
  }

  $self->presentation->SaveAs( convert_cygwin_path( $absfile ) );
}

sub close_presentation {
  my $self = shift;

  return unless $self->presentation;

  $self->presentation->Close;
  $self->{presentation} = undef;
}

sub set_master_footer {
  my $self = shift;

  return unless $self->presentation;
  my $master_footers = $self->presentation->SlideMaster;
  $self->_set_footer($master_footers, @_);
}

sub _set_footer {
  my ($self, $slide, @args) = @_;

  my $target = $slide->HeadersFooters;

  my %options = ( @args == 1 and ref $args[0] eq 'HASH' ) ? %{ $args[0] } : @args;

  if ( defined $options{visible} ) {
    $target->Footer->{Visible} = $options{visible} ? $self->c->msoTrue : $self->c->msoFalse;
  }

  if ( defined $options{text} ) {
    $target->Footer->{Text} = $options{text};
  }

  if ( defined $options{slide_number} ) {
    $target->SlideNumber->{Visible} = $options{slide_number} ? $self->c->msoTrue : $self->c->msoFalse;
  }

  if ( defined $options{datetime} ) {
    $target->DateAndTime->{Visible} = $options{datetime} ? $self->c->msoTrue : $self->c->msoFalse;
  }

  if ( defined $options{datetime_format} ) {
    if ( !$options{datetime_format} ) {
      $target->DateAndTime->{UseFormat} = $self->c->msoFalse;
    }
    else {
      if ( $options{datetime_format} =~ /\D/ ) {
        my $format = canonical_datetime($options{datetime_format});
        $options{datetime_format} = $self->c->$format;
      }
      $target->DateAndTime->{UseFormat} = $self->c->msoTrue;
      $target->DateAndTime->{Format}    = $options{datetime_format};
    }
  }
}

##### slide #####

sub new_slide {
  my $self = shift;

  my %options = ( @_ == 1 and ref $_[0] eq 'HASH' ) ? %{ $_[0] } : @_;

  $self->{slide} = $self->presentation->Slides->Add(
    $self->presentation->Slides->Count + 1,
    $self->c->LayoutBlank
  ) or die Win32::OLE->LastError;

  $self->_apply_background(
    $self->slide->Background->Fill,
    %options,
    slide => 1,
  );
}

sub set_footer {
  my $self = shift;

  return unless $self->slide;
  $self->_set_footer($self->slide, @_);
}

sub add_text {
  my ($self, $text, $options) = @_;

  return unless $self->slide;
  return unless defined $text;

  $options = {} unless ref $options eq 'HASH';

  $text =~ s/\n/\r/gs;

  my $num_of_boxes = $self->slide->Shapes->Count;
  my $last  = $num_of_boxes ? $self->slide->Shapes($num_of_boxes) : undef;
  my ($left, $top, $width, $height);
  if ($last) {
    $left   = _defined_or($options->{left},   $last->Left);
    $top    = _defined_or($options->{top},    $last->Top + $last->Height + 20);
    $width  = _defined_or($options->{width},  $last->Width);
    $height = _defined_or($options->{height}, $last->Height);
  }
  else {
    $left   = _defined_or($options->{left},   30);
    $top    = _defined_or($options->{top},    30);
    $width  = _defined_or($options->{width},  600);
    $height = _defined_or($options->{height}, 200);
  }

  my $new_textbox = $self->slide->Shapes->AddTextbox(
    $self->c->TextOrientationHorizontal,
    $left, $top, $width, $height
  );

  my $frame = $new_textbox->TextFrame;
  my $range = $frame->TextRange;

  $frame->{WordWrap} = $self->c->True;
  $range->ParagraphFormat->{FarEastLineBreakControl} = $self->c->True;
  $range->{Text} = $text;

  $self->decorate_range( $range, $options );

  $frame->{AutoSize} = $self->c->AutoSizeNone;
  $frame->{AutoSize} = $self->c->AutoSizeShapeToFitText;

  return $new_textbox;
}

sub add_picture {
  my ($self, $file, $options) = @_;

  return unless $self->slide;
  return unless defined $file and -f $file;

  $options = {} unless ref $options eq 'HASH';

  my $num_of_boxes = $self->slide->Shapes->Count;
  my $last  = $num_of_boxes ? $self->slide->Shapes($num_of_boxes) : undef;
  my ($left, $top);
  if ($last) {
    $left   = _defined_or($options->{left}, $last->Left);
    $top    = _defined_or($options->{top},  $last->Top + $last->Height + 20);
  }
  else {
    $left   = _defined_or($options->{left}, 30);
    $top    = _defined_or($options->{top},  30);
  }

  my $new_picture = $self->slide->Shapes->AddPicture(
    convert_cygwin_path( $file ),
    ( $options->{link}
      ? ( $self->c->msoTrue,  $self->c->msoFalse )
      : ( $self->c->msoFalse, $self->c->msoTrue )
    ),
    $left, $top, $options->{width}, $options->{height}
  );

  return $new_picture;
}

sub insert_before {
  my ($self, $text, $options) = @_;

  return unless $self->slide;
  return unless defined $text;

  $options = {} unless ref $options eq 'HASH';

  $text =~ s/\n/\r/gs;

  my $num_of_boxes = $self->slide->Shapes->Count;
  my $last  = $num_of_boxes ? $self->slide->Shapes($num_of_boxes) : undef;
  my $range = $self->slide->Shapes($num_of_boxes)->TextFrame->TextRange;

  my $selection = $range->InsertBefore($text);

  $self->decorate_range( $selection, $options );

  return $selection;
}

sub insert_after {
  my ($self, $text, $options) = @_;

  return unless $self->slide;
  return unless defined $text;

  $options = {} unless ref $options eq 'HASH';

  $text =~ s/\n/\r/gs;

  my $num_of_boxes = $self->slide->Shapes->Count;
  my $last  = $num_of_boxes ? $self->slide->Shapes($num_of_boxes) : undef;
  my $range = $self->{slide}->Shapes($num_of_boxes)->TextFrame->TextRange;

  my $selection = $range->InsertAfter($text);

  $self->decorate_range( $selection, $options );

  return $selection;
}

sub decorate_range {
  my ($self, $range, $options) = @_;

  return unless defined $range;

  $options = {} unless ref $options eq 'HASH';

  my ($true, $false) = ($self->c->True, $self->c->False);

  $range->Font->{Bold}        = $options->{bold}        ? $true : $false;
  $range->Font->{Italic}      = $options->{italic}      ? $true : $false;
  $range->Font->{Underline}   = $options->{underline}   ? $true : $false;
  $range->Font->{Shadow}      = $options->{shadow}      ? $true : $false;
  $range->Font->{Subscript}   = $options->{subscript}   ? $true : $false;
  $range->Font->{Superscript} = $options->{superscript} ? $true : $false;
  $range->Font->{Size}        = $options->{size}       if $options->{size};
  $range->Font->{Name}        = $options->{name}       if $options->{name};
  $range->Font->{Name}        = $options->{font}       if $options->{font};
  $range->Font->Color->{RGB}  = RGB($options->{color}) if $options->{color};

  my $align = $options->{alignment} || $options->{align} || 'left';
  if ( $align =~ /\D/ ) {
    my $method = canonical_alignment( $align );
    $align = $self->c->$method;
  }
  $range->ParagraphFormat->{Alignment} = $align;

  $range->ActionSettings(
    $self->c->MouseClick
  )->Hyperlink->{Address} = $options->{link} if $options->{link};
}

sub DESTROY {
  my $self = shift;

  $self->quit if $self->{was_invoked};
}

1;
__END__