Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Test

on:
push:
branches:
- master
pull_request:
branches:
- master

jobs:
rspec:
runs-on: ubuntu-latest
permissions:
contents: read

environment: test
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Run test suite
run: bundle exec rspec
env:
CI_NAME: github-actions
CI_JOB_ID: ${{ github.run_id }}
CI_BUILD_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
CI_BRANCH: ${{ github.head_ref || github.ref_name }}
CI_PULL_REQUEST: ${{ github.event.pull_request.html_url || '' }}
COVERALLS_SERVICE_NAME: github-actions
COVERALLS_REPO_TOKEN: ${{secrets.COVERALLS_REPO_TOKEN}}
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ spec/reports
test/tmp
test/version_tmp
tmp
.pryrc
.pryrc
.DS_Store
*.swp
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[![version](https://badge.fury.io/rb/powerpoint.svg)](https://badge.fury.io/rb/powerpointk)
[![downloads](https://ruby-gem-downloads-badge.herokuapp.com/powerpoint?type=total&total_label=downloads)](https://ruby-gem-downloads-badge.herokuapp.com/powerpoint?type=total&total_label=downloads)
[![Coverage # Status](https://coveralls.io/repos/mgmodell/powerpoint/badge.svg?branch=master&service=github)](https://coveralls.io/github/mgmodell/powerpoint?branch=master)

# 'powerpoint' gem -- for creating PowerPoint Slides in Ruby.

Expand Down Expand Up @@ -55,9 +55,25 @@ coords = {x: 124200, y: 3356451, cx: 2895600, cy: 1013460}
# Saving the pptx file to the current directory.
@deck.save('test.pptx')
```

Transitions can be configured per slide with a transition type and duration in
milliseconds:

```ruby
@deck.add_textual_slide(
'Agenda',
['Item 1', 'Item 2'],
{ transition: { type: :fade, duration: 750 } }
)
```

The transition type defaults to `fade`; supported types include `fade`,
`dissolve`, `wipe`, `push`, and `zoom`.

## Compatibility

Generated presentations use a 16:9 widescreen layout, and slide text is automatically sized to fit its placeholders.

'powerpoint' gem has been tested with LibreOffice (4.2.1.1) and Apache OpenOffice (4.0.1) on Mac OS X Mavericks, Microsoft PowerPoint 2010 on Windows 7 and Google Docs (latest version as of March 2014).

## Contributing
Expand Down
1 change: 1 addition & 0 deletions lib/powerpoint.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "powerpoint/version"
require 'powerpoint/util'
require 'powerpoint/slide/transition'
require 'powerpoint/slide/intro'
require 'powerpoint/slide/textual'
require 'powerpoint/slide/pictorial'
Expand Down
2 changes: 1 addition & 1 deletion lib/powerpoint/compression.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def self.decompress_pptx(in_path, out_path)
end

def self.compress_pptx(in_path, out_path)
Zip::File.open(out_path, Zip::File::CREATE) do |zip_file|
Zip::File.open(out_path, create: true) do |zip_file|
Dir.glob("#{in_path}/**/*", ::File::FNM_DOTMATCH).each do |path|
zip_path = path.gsub("#{in_path}/","")
next if zip_path == "." || zip_path == ".." || zip_path.match(/DS_Store/)
Expand Down
24 changes: 14 additions & 10 deletions lib/powerpoint/presentation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,34 @@ def initialize
@slides = []
end

def add_intro(title, subtitile = nil)
def add_intro(title, subtitile = nil, options = {})
if subtitile.is_a?(Hash) && options.empty?
options = subtitile
subtitile = nil
end
existing_intro_slide = @slides.select {|s| s.class == Powerpoint::Slide::Intro}[0]
slide = Powerpoint::Slide::Intro.new(presentation: self, title: title, subtitile: subtitile)
slide = Powerpoint::Slide::Intro.new(presentation: self, title: title, subtitile: subtitile, transition: options[:transition])
if existing_intro_slide
@slides[@slides.index(existing_intro_slide)] = slide
else
@slides.insert 0, slide
end
end

def add_textual_slide(title, content = [])
@slides << Powerpoint::Slide::Textual.new(presentation: self, title: title, content: content)
def add_textual_slide(title, content = [], options = {})
@slides << Powerpoint::Slide::Textual.new(presentation: self, title: title, content: content, transition: options[:transition])
end

def add_pictorial_slide(title, image_path, coords = {})
@slides << Powerpoint::Slide::Pictorial.new(presentation: self, title: title, image_path: image_path, coords: coords)
def add_pictorial_slide(title, image_path, coords = {}, options = {})
@slides << Powerpoint::Slide::Pictorial.new(presentation: self, title: title, image_path: image_path, coords: coords, transition: options[:transition])
end

def add_text_picture_slide(title, image_path, content = [])
@slides << Powerpoint::Slide::TextPicSplit.new(presentation: self, title: title, image_path: image_path, content: content)
def add_text_picture_slide(title, image_path, content = [], options = {})
@slides << Powerpoint::Slide::TextPicSplit.new(presentation: self, title: title, image_path: image_path, content: content, transition: options[:transition])
end

def add_picture_description_slide(title, image_path, content = [])
@slides << Powerpoint::Slide::DescriptionPic.new(presentation: self, title: title, image_path: image_path, content: content)
def add_picture_description_slide(title, image_path, content = [], options = {})
@slides << Powerpoint::Slide::DescriptionPic.new(presentation: self, title: title, image_path: image_path, content: content, transition: options[:transition])
end

def save(path)
Expand Down
3 changes: 2 additions & 1 deletion lib/powerpoint/slide/intro.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Powerpoint
module Slide
class Intro
include Powerpoint::Util
include Powerpoint::Slide::Transition

attr_reader :title, :subtitile

Expand All @@ -28,7 +29,7 @@ def save_rel_xml(extract_path, index)
private :save_rel_xml

def save_slide_xml(extract_path, index)
render_view('intro_slide.xml.erb', "#{extract_path}/ppt/slides/slide#{index}.xml")
render_view('intro_slide.xml.erb', "#{extract_path}/ppt/slides/slide#{index}.xml", transition_xml: transition_xml)
end
private :save_slide_xml
end
Expand Down
14 changes: 10 additions & 4 deletions lib/powerpoint/slide/pictorial.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module Powerpoint
module Slide
class Pictorial
include Powerpoint::Util
include Powerpoint::Slide::Transition

attr_reader :image_name, :title, :coords, :image_path

Expand All @@ -28,13 +29,18 @@ def file_type
end

def default_coords
slide_width = pixle_to_pt(720)
slide_width = pixle_to_pt(960)
default_width = pixle_to_pt(550)
default_height = pixle_to_pt(420)

return {} unless dimensions = FastImage.size(image_path)
image_width, image_height = dimensions.map {|d| pixle_to_pt(d)}
new_width = default_width < image_width ? default_width : image_width
ratio = new_width / image_width.to_f
ratio = [
default_width / image_width.to_f,
default_height / image_height.to_f,
1
].min
new_width = (image_width * ratio).round
new_height = (image_height.to_f * ratio).round
{x: (slide_width / 2) - (new_width/2), y: pixle_to_pt(120), cx: new_width, cy: new_height}
end
Expand All @@ -46,7 +52,7 @@ def save_rel_xml(extract_path, index)
private :save_rel_xml

def save_slide_xml(extract_path, index)
render_view('pictorial_slide.xml.erb', "#{extract_path}/ppt/slides/slide#{index}.xml")
render_view('pictorial_slide.xml.erb', "#{extract_path}/ppt/slides/slide#{index}.xml", transition_xml: transition_xml)
end
private :save_slide_xml
end
Expand Down
5 changes: 3 additions & 2 deletions lib/powerpoint/slide/picture_description.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module Powerpoint
module Slide
class DescriptionPic
include Powerpoint::Util
include Powerpoint::Slide::Transition

attr_reader :title, :content, :image_name, :image_path, :coords

Expand All @@ -28,7 +29,7 @@ def file_type
end

def default_coords
slide_width = pixle_to_pt(720)
slide_width = pixle_to_pt(960)
default_width = pixle_to_pt(550)
default_height = pixle_to_pt(300)

Expand All @@ -55,7 +56,7 @@ def save_rel_xml(extract_path, index)
private :save_rel_xml

def save_slide_xml(extract_path, index)
render_view('picture_description_slide.xml.erb', "#{extract_path}/ppt/slides/slide#{index}.xml")
render_view('picture_description_slide.xml.erb', "#{extract_path}/ppt/slides/slide#{index}.xml", transition_xml: transition_xml)
end
private :save_slide_xml
end
Expand Down
14 changes: 10 additions & 4 deletions lib/powerpoint/slide/text_picture_split.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module Powerpoint
module Slide
class TextPicSplit
include Powerpoint::Util
include Powerpoint::Slide::Transition

attr_reader :title, :content, :image_name, :image_path, :coords

Expand All @@ -28,13 +29,18 @@ def file_type
end

def default_coords
start_x = pixle_to_pt(360)
start_x = pixle_to_pt(480)
default_width = pixle_to_pt(300)
default_height = pixle_to_pt(420)

return {} unless dimensions = FastImage.size(image_path)
image_width, image_height = dimensions.map {|d| pixle_to_pt(d)}
new_width = default_width < image_width ? default_width : image_width
ratio = new_width / image_width.to_f
ratio = [
default_width / image_width.to_f,
default_height / image_height.to_f,
1
].min
new_width = (image_width * ratio).round
new_height = (image_height.to_f * ratio).round
{x: start_x, y: pixle_to_pt(120), cx: new_width, cy: new_height}
end
Expand All @@ -46,7 +52,7 @@ def save_rel_xml(extract_path, index)
private :save_rel_xml

def save_slide_xml(extract_path, index)
render_view('text_picture_split_slide.xml.erb', "#{extract_path}/ppt/slides/slide#{index}.xml")
render_view('text_picture_split_slide.xml.erb', "#{extract_path}/ppt/slides/slide#{index}.xml", transition_xml: transition_xml)
end
private :save_slide_xml
end
Expand Down
3 changes: 2 additions & 1 deletion lib/powerpoint/slide/textual.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Powerpoint
module Slide
class Textual
include Powerpoint::Util
include Powerpoint::Slide::Transition

attr_reader :title, :content

Expand All @@ -24,7 +25,7 @@ def save_rel_xml(extract_path, index)
private :save_rel_xml

def save_slide_xml(extract_path, index)
render_view('textual_slide.xml.erb', "#{extract_path}/ppt/slides/slide#{index}.xml")
render_view('textual_slide.xml.erb', "#{extract_path}/ppt/slides/slide#{index}.xml", transition_xml: transition_xml)
end
private :save_slide_xml
end
Expand Down
26 changes: 26 additions & 0 deletions lib/powerpoint/slide/transition.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module Powerpoint
module Slide
module Transition
TYPES = %w[
blinds checker circle comb cover cut diamond dissolve fade newsflash
plus pull push random randomBar split strips wedge wheel wipe zoom
].freeze

def transition_xml
return '' unless @transition
raise ArgumentError, 'transition must be a Hash' unless @transition.is_a?(Hash)

type = (@transition[:type] || @transition['type'] || 'fade').to_s
raise ArgumentError, "unsupported transition type: #{type}" unless TYPES.include?(type)

duration = @transition[:duration] || @transition['duration']
if duration && (!duration.is_a?(Integer) || duration <= 0)
raise ArgumentError, 'transition duration must be a positive integer in milliseconds'
end

duration_attribute = duration ? %( p14:dur="#{duration}") : ''
%(<p:transition#{duration_attribute} xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main"><p:#{type}/></p:transition>)
end
end
end
end
8 changes: 4 additions & 4 deletions lib/powerpoint/views/app.xml.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">
<TotalTime>0</TotalTime>
<Words>43</Words>
<Application>Microsoft Macintosh PowerPoint</Application>
<PresentationFormat>On-screen Show (4:3)</PresentationFormat>
<Application>Microsoft Office PowerPoint</Application>
<PresentationFormat>On-screen Show (16:9)</PresentationFormat>
<Paragraphs>15</Paragraphs>
<Slides><%= slides.length %></Slides>
<Notes>0</Notes>
Expand Down Expand Up @@ -39,13 +39,13 @@
<vt:lpstr>Calibri</vt:lpstr>
<vt:lpstr>Office Theme</vt:lpstr>
<% slides.each do |slide| %>
<vt:lpstr><%= slide.title %></vt:lpstr>
<vt:lpstr><%= ERB::Util.html_escape(slide.title) %></vt:lpstr>
<% end %>
</vt:vector>
</TitlesOfParts>
<Company></Company>
<LinksUpToDate>false</LinksUpToDate>
<SharedDoc>false</SharedDoc>
<HyperlinksChanged>false</HyperlinksChanged>
<AppVersion>15.0000</AppVersion>
<AppVersion>16.0000</AppVersion>
</Properties>
9 changes: 5 additions & 4 deletions lib/powerpoint/views/intro_slide.xml.erb
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@
</p:nvSpPr>
<p:spPr/>
<p:txBody>
<a:bodyPr/>
<a:bodyPr><a:normAutofit/></a:bodyPr>
<a:lstStyle/>
<a:p>
<a:r>
<a:rPr dirty="0" lang="en-US" smtClean="0"/>
<a:t><%= title %></a:t>
<a:t><%= ERB::Util.html_escape(title) %></a:t>
</a:r>
<a:endParaRPr dirty="0" lang="en-US"/>
</a:p>
Expand All @@ -50,12 +50,12 @@
</p:nvSpPr>
<p:spPr/>
<p:txBody>
<a:bodyPr/>
<a:bodyPr><a:normAutofit/></a:bodyPr>
<a:lstStyle/>
<a:p>
<a:r>
<a:rPr lang="en-US" smtClean="0"/>
<a:t><%= subtitile %></a:t>
<a:t><%= ERB::Util.html_escape(subtitile) %></a:t>
</a:r>
<a:endParaRPr lang="en-US"/>
</a:p>
Expand All @@ -71,4 +71,5 @@
<p:clrMapOvr>
<a:masterClrMapping/>
</p:clrMapOvr>
<%= transition_xml %>
</p:sld>
5 changes: 3 additions & 2 deletions lib/powerpoint/views/pictorial_slide.xml.erb
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@
</p:nvSpPr>
<p:spPr/>
<p:txBody>
<a:bodyPr/>
<a:bodyPr><a:normAutofit/></a:bodyPr>
<a:lstStyle/>
<a:p>
<a:r>
<a:rPr dirty="0" lang="en-US" smtClean="0"/>
<a:t><%= title %></a:t>
<a:t><%= ERB::Util.html_escape(title) %></a:t>
</a:r>
<a:endParaRPr dirty="0" lang="en-US"/>
</a:p>
Expand Down Expand Up @@ -84,4 +84,5 @@
<p:clrMapOvr>
<a:masterClrMapping/>
</p:clrMapOvr>
<%= transition_xml %>
</p:sld>
Loading