module MpoTools

The core library. This module provides methods for converting and extracing data from MPO format 3D photographs. It uses imagemagick and exiftool to do this, so both libraries must be installed on your system for this code to work

Constants

FORMATS

List of supported output formats

VERSION

Public Class Methods

convert(source, destination=nil, format=FORMATS.first, scale=1) click to toggle source

Convert the provided MPO file into the desired format

Parameters

source

The location of disk of the .mpo file

destination

The desired output location of the new file (Optional)

format

The desired output format. A list of valid formats can be found in

the +FORMATS+ constant (Optional, defaults to :stereo)
scale

The size of the outputted image. This can be provided as a scale

with 1 representing the original size. Alternatively an array can be
passed in with the format [x_size, y_size]

Returns

  • The location on disk of the newly created output file.

Raises

  • MpoError - Raised when the provided source file cannot be converted

# File lib/mpo_tools.rb, line 29
def self.convert(source, destination=nil, format=FORMATS.first, scale=1)
  raise MpoError.new "Invalid format: #{format}" if !FORMATS.include?(format)
  source, destination = validate_paths source, destination, format
  left, right = extract_images source
  left, right = scale_images left, right, scale unless scale == 1
  send "output_as_#{format}", left, right, destination
end
exif_data(source) click to toggle source

Reads the source MPO file and returns a hash of exif data

Parameters

source

The location on disk of the .mpo file

Returns

  • A ruby hash containing the file’s exif meta data

Raises

  • MpoError - Raised when exif data cannot be read from the source or when

    the exiftool application has not been installed
# File lib/mpo_tools.rb, line 47
def self.exif_data(source)
  exif = `exiftool -u -d "%Y-%m-%d %H:%M:%S" -json #{source}`
  return JSON.parse(exif).first
rescue Errno::ENOENT => e
  raise MpoError.new "Please install 'exiftool' on your machine.\n  \"sudo apt-get install libimage-exiftool-perl\" on Ubuntu"
rescue JSON::ParserError => e
  raise MpoError.new 'Unable to read exif data'
end
extract_images(source) click to toggle source

Extracts two images from the MPO file

Parameters

source

The location on disk of the .mpo file

Returns

  • The left eye image in Magick::Image format

  • The right eye image in Magick::Image format

Raises

  • MpoError - Raised when two images cannot be created based on the provided

    source file or when the exiftool application has not been installed
# File lib/mpo_tools.rb, line 67
def self.extract_images(source)
  left = Magick::Image.from_blob(`exiftool -trailer:all= #{source} -o -`)[0]
  right = Magick::Image.from_blob(`exiftool #{source} -mpimage2 -b`)[0]
  return left, right
rescue Errno::ENOENT => e
  raise MpoError.new "Please install 'exiftool' on your machine.\n  \"sudo apt-get install libimage-exiftool-perl\" on Ubuntu"
rescue Magick::ImageMagickError => e
  raise MpoError.new 'Unable to extract images'
end

Private Class Methods

output_as_analglyph(left, right, destination) click to toggle source

Outputs as an analglyph that can be viewed with coloured glasses

# File lib/mpo_tools.rb, line 104
def self.output_as_analglyph(left, right, destination)
  destination = "#{destination}.jpg" unless destination =~ /.jpg$/i
  left.stereo(right).write(destination)
  return destination
end
output_as_cross_eyed(left, right, destination) click to toggle source

Creates a reversed stereo image, which can be viewed by going cross-eyed

# File lib/mpo_tools.rb, line 99
def self.output_as_cross_eyed(left, right, destination)
  output_as_stereo right, left, destination
end
output_as_stereo(left, right, destination) click to toggle source

Outputs the 3D image in stereo, left image on the left and right image on the right

# File lib/mpo_tools.rb, line 92
def self.output_as_stereo(left, right, destination)
  destination = "#{destination}.jpg" unless destination =~ /.jpg$/i
  Magick::ImageList.new.push(left, right).append(false).write(destination)
  return destination
end
output_as_wiggle(left, right, destination) click to toggle source

Outputs as a ‘wiggle’ gif. An animated gif that rapidly cycles between left and right image

# File lib/mpo_tools.rb, line 112
def self.output_as_wiggle(left, right, destination)
  destination = "#{destination}.gif" unless destination =~ /.gif$/i
  gif = Magick::ImageList.new.push(left, right)
  gif.delay = 5
  gif.write(destination)
  return destination
end
scale_images(left, right, scale) click to toggle source

Resizes both left and right images

# File lib/mpo_tools.rb, line 80
def self.scale_images left, right, scale
  if scale.is_a?(Array) && scale.length == 2
    return left.scale(*scale), right.scale(*scale)
  elsif scale.is_a?(Float) || scale.is_a?(Integer)
    return left.scale(scale), right.scale(scale)
  else
    raise MpoError.new 'Invalid scale'
  end
end
validate_paths(source, destination, format) click to toggle source

Validates the provided source and destination paths, builds the destination path if a full file path has not been provided

# File lib/mpo_tools.rb, line 122
def self.validate_paths(source, destination, format)
  raise MpoError.new('Source not an mpo') unless source =~ /\.mpo$/i
  raise MpoError.new('Source not found') unless File.exists?(source)
  source = Pathname.new(source)
  if destination && File.directory?(destination)
    source_name = source.basename.to_s.gsub(/\.mpo$/, '')
    destination = Pathname.new(destination) + "#{source_name}_#{format}"
  elsif destination
    destination = Pathname.new(destination)
  else
    stripped_source = source.realpath.to_s.gsub(/\.mpo$/, '')
    destination = Pathname.new(stripped_source + "_#{format}")
  end
  return source.realpath.to_s, destination.to_s
end