Class: Rbpptx::Presentation

Inherits:
Object
  • Object
show all
Defined in:
lib/rbpptx/presentation.rb

Overview

A PowerPoint presentation loaded from a .pptx file.

Reading is the only mode wired up at present: the package is opened, the presentation part is located via _rels/.rels, the slide id list is read in document order, and slides are resolved through the presentation’s own rels. Each Slide retains a handle on the underlying ZIP and parses its XML lazily.

Constant Summary collapse

P_NS =
"http://schemas.openxmlformats.org/presentationml/2006/main".freeze
A_NS =
"http://schemas.openxmlformats.org/drawingml/2006/main".freeze
R_NS =
"http://schemas.openxmlformats.org/officeDocument/2006/relationships".freeze
PKG_REL_NS =
"http://schemas.openxmlformats.org/package/2006/relationships".freeze
OFFICE_DOC_REL_TYPE =
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument".freeze
SLIDE_REL_TYPE =
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide".freeze
LEGACY_PPT_SIGNATURE =
"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1".b.freeze
ZIP_SIGNATURE =
"PK\x03\x04".b.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ Presentation

Returns a new instance of Presentation.



29
30
31
32
33
34
35
36
37
38
# File 'lib/rbpptx/presentation.rb', line 29

def initialize(path)
  @path = path.to_s
  @closed = false
  validate_signature!
  begin
    @zip = Zip::File.open(@path)
  rescue Zip::Error => e
    raise UnsupportedFormatError, "#{@path}: not a valid .pptx (#{e.message})"
  end
end

Instance Attribute Details

#pathString (readonly)

Returns absolute path the presentation was loaded from.

Returns:

  • (String)

    absolute path the presentation was loaded from



21
22
23
# File 'lib/rbpptx/presentation.rb', line 21

def path
  @path
end

Class Method Details

.open(path) ⇒ Object

Opens an existing presentation. See Rbpptx.open for the public entry point that supports the block-with-auto-close idiom.



25
26
27
# File 'lib/rbpptx/presentation.rb', line 25

def self.open(path)
  new(path)
end

Instance Method Details

#closeBoolean

Releases the underlying ZIP file. Idempotent.

Returns:

  • (Boolean)

    true on the first call, false on subsequent calls



94
95
96
97
98
99
100
101
# File 'lib/rbpptx/presentation.rb', line 94

def close
  return false if @closed

  @zip&.close
  @zip = nil
  @closed = true
  true
end

#closed?Boolean

Returns:

  • (Boolean)


104
105
106
# File 'lib/rbpptx/presentation.rb', line 104

def closed?
  @closed
end

#save(path) ⇒ String

Writes the presentation out to path, preserving every part that has not been mutated byte-for-byte. Slides whose shapes have been edited are re-serialized from their in-memory Nokogiri document; all other entries (themes, masters, layouts, media, fonts, rels) are streamed straight from the source ZIP without re-parsing, so unknown PowerPoint features round-trip unchanged.

path may equal the original load path; the new file is written to a temp file in the same directory and atomically renamed into place. On success, dirty flags on each slide are cleared.

Parameters:

  • path (String, #to_path)

Returns:

  • (String)

    the path that was written



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/rbpptx/presentation.rb', line 60

def save(path)
  ensure_open!
  out_path = path.to_s
  overrides = (@slides || []).each_with_object({}) do |slide, h|
    h[slide.part_name] = slide.to_xml if slide.dirty?
  end

  tmp_path = "#{out_path}.rbpptx-tmp.#{Process.pid}.#{rand(1 << 32).to_s(16)}"
  begin
    Zip::OutputStream.open(tmp_path) do |out|
      @zip.each do |entry|
        next if entry.directory?

        if (override_xml = overrides[entry.name])
          out.put_next_entry(entry.name)
          out.write(override_xml)
        else
          out.copy_raw_entry(entry)
        end
      end
    end
    File.rename(tmp_path, out_path)
  rescue StandardError
    File.unlink(tmp_path) if File.exist?(tmp_path)
    raise
  end

  (@slides || []).each(&:clear_dirty!)
  out_path
end

#slidesArray<Slide>

Returns slides in presentation order (matches the order of <p:sldId> entries inside ppt/presentation.xml).

Returns:

  • (Array<Slide>)

    slides in presentation order (matches the order of <p:sldId> entries inside ppt/presentation.xml)



42
43
44
45
# File 'lib/rbpptx/presentation.rb', line 42

def slides
  ensure_open!
  @slides ||= build_slides
end