Skip to content

Commit

Permalink
Merge 1c9bcce into 67a416d
Browse files Browse the repository at this point in the history
  • Loading branch information
digitaltom committed Jul 2, 2018
2 parents 67a416d + 1c9bcce commit 7f37e6e
Show file tree
Hide file tree
Showing 16 changed files with 212 additions and 129 deletions.
8 changes: 7 additions & 1 deletion .rubocop.yml
Expand Up @@ -10,7 +10,7 @@ AllCops:
- vendor/**/*

LineLength:
Max: 120
Max: 140

Layout/EmptyLinesAroundClassBody:
Enabled: false
Expand All @@ -21,6 +21,12 @@ Layout/EmptyLinesAroundBlockBody:
Metrics/MethodLength:
Max: 20

Metrics/ClassLength:
Max: 120

Metrics/BlockLength:
Max: 40

Metrics/AbcSize:
Max: 26

Expand Down
2 changes: 1 addition & 1 deletion .ruby-version
@@ -1 +1 @@
2.1.5
2.1.2
2 changes: 1 addition & 1 deletion app/controllers/picture_sets_controller.rb
Expand Up @@ -14,7 +14,7 @@ def create
end

def destroy
PictureSet.destroy(params[:id])
PictureSet.find(params[:id]).destroy
render json: ''
end
end
13 changes: 0 additions & 13 deletions app/models/drop_box_api.rb

This file was deleted.

116 changes: 74 additions & 42 deletions app/models/picture_set.rb
Expand Up @@ -6,69 +6,50 @@ class PictureSet
COMBINED_SUFFIX = '_combined.jpg'.freeze
PICTURE_PATH = Rails.root.join('public', 'picture_sets').to_s

attr_accessor :date, :dir, :animation, :combined, :pictures, :next, :last

class << self

def all
dirs = Dir.glob(File.join(PICTURE_PATH, "*/*#{ANIMATION_SUFFIX}")).map do |animation|
File.basename(File.dirname(animation))
end
dirs.sort.reverse.map { |dir| new(dir) }
Rails.logger.warn "No picture sets found at: #{PICTURE_PATH}" if dirs.empty?
dirs.sort.reverse.map { |dir| new(date: dir) }
end

def find(date)
all_sets = PictureSet.all
ps = all_sets.detect { |set| set[:date] == date }
ps = all_sets.detect { |set| set.date == date }
raise 'PictureSet not found' unless ps
ps[:next] = all_sets[all_sets.index(ps) - 1] if all_sets.index(ps) > 0
ps[:last] = all_sets[all_sets.index(ps) + 1] if all_sets.index(ps) < all_sets.size
ps.next = all_sets[all_sets.index(ps) - 1] if all_sets.index(ps) > 0
ps.last = all_sets[all_sets.index(ps) + 1] if all_sets.index(ps) < all_sets.size
ps
end

def new(date)
{ path: "picture_sets/#{date}", date: date,
animation: "#{date}#{ANIMATION_SUFFIX}", combined: "#{date}#{COMBINED_SUFFIX}",
pictures: (1..4).map { |i| { polaroid: "#{date}_#{i}#{POLAROID_SUFFIX}", full: "#{date}_#{i}.jpg" } } }
end

def create
date = Time.now.getlocal.strftime(DATE_FORMAT)
dir = "#{PICTURE_PATH}/#{date}"
def create(date: Time.now.getlocal.strftime(DATE_FORMAT))
picture_set = PictureSet.new(date: date)
FileUtils.mkdir(picture_set.dir)
angle = Random.rand(353..366)
Syscall.execute("mkdir #{date}", dir: PICTURE_PATH)
jobs = (1..4).collect { |i| capture_job(i, date, dir, angle) }
jobs = (1..4).collect { |i| capture_job(i, picture_set, angle) }
GpioPort.on(GpioPort::GPIO_PORTS['PROCESSING'])
# wait until convert jobs are finished
until jobs.none?(&:status) do end
# Merge all polaroid previews to an animated gif
Syscall.execute("time convert -delay 60 #{date}_*#{POLAROID_SUFFIX} #{date}#{ANIMATION_SUFFIX}", dir: dir)
# Merge all images in one combined image
combine_images(date, dir)
picture_set.create_animation
picture_set.combine_images
(1..4).each { |i| GpioPort.off(GpioPort::GPIO_PORTS["PICTURE#{i}"]) }
GpioPort.off(GpioPort::GPIO_PORTS['PROCESSING'])
new(date)
end

def destroy(date)
Syscall.execute("rm -r #{date}", dir: PICTURE_PATH)
picture_set
end

private

def combine_images(date, dir)
Thread.new do
Syscall.execute("time montage -geometry '25%x25%+25+25<' -background '#{OPTS.background_color}' " \
"-title '#{OPTS.image_caption}' -font '#{OPTS.font}' -fill '#{OPTS.font_color}' " \
"-pointsize #{OPTS.combined_image_fontsize} -gravity 'Center' #{date}_*.jpg #{date}#{COMBINED_SUFFIX}",
dir: dir)
end
end

def capture_job(num, date, dir, angle)
def capture_job(num, picture_set, angle)
GpioPort.on(GpioPort::GPIO_PORTS["PICTURE#{num}"])
begin
retries ||= 0
Syscall.execute("gphoto2 --capture-image-and-download --filename #{date}_#{num}.jpg", dir: dir)
raise 'Image capture failed' unless File.exist?(File.join(dir, "#{date}_#{num}.jpg"))
Syscall.execute("gphoto2 --capture-image-and-download --filename #{picture_set.date}_#{num}.jpg", dir: picture_set.dir)
raise 'Image capture failed' unless File.exist?(File.join(picture_set.dir, "#{picture_set.date}_#{num}.jpg"))
rescue StandardError => e
# rubocop:disable GuardClause
if (retries += 1) < 3
Expand All @@ -79,19 +60,70 @@ def capture_job(num, date, dir, angle)
end
# rubocop:enable GuardClause
end
convert_thread(num, date, dir, angle)
convert_thread(num, picture_set, angle)
end

def convert_thread(num, date, dir, angle)
caption = OPTS.image_caption || date
def convert_thread(num, picture_set, angle)
t = Thread.new do
Syscall.execute("time convert -caption '#{caption}' #{date}_#{num}.jpg -sample 600 -bordercolor Snow " \
"-density 100 -gravity center -pointsize #{OPTS.image_fontsize} " \
"-polaroid -#{angle} #{date}_#{num}#{POLAROID_SUFFIX}", dir: dir)
picture_set.convert_to_polaroid(num, angle)
end
t.abort_on_exception = true
t
end

end

def initialize(date: nil)
@date = date
@path = "picture_sets/#{date}"
@dir = "#{PICTURE_PATH}/#{date}"
@animation = "#{date}#{ANIMATION_SUFFIX}"
@combined = "#{date}#{COMBINED_SUFFIX}"
@pictures = (1..4).map { |i| { polaroid: "#{date}_#{i}#{POLAROID_SUFFIX}", full: "#{date}_#{i}.jpg" } }
end

def destroy
FileUtils.rm_r dir
end

def convert_to_polaroid(num, angle)
caption = OPTS.image_caption || date
Syscall.execute("time convert -caption '#{caption}' #{date}_#{num}.jpg " \
'-sample 600 ' \
'-bordercolor Snow ' \
'-density 100 ' \
'-gravity center ' \
"-pointsize #{OPTS.image_fontsize} " \
"-polaroid -#{angle} " \
'-trim +repage ' \
"#{date}_#{num}#{POLAROID_SUFFIX}", dir: dir)
end

# Merge all polaroid previews to an animated gif
def create_animation(overwrite: false)
if File.exist?(File.join(dir, animation)) && !overwrite
Rails.logger.info "Skipping for existing animation #{dir}"
else
Rails.logger.info "Creating animation for #{dir}"
Syscall.execute("time convert -delay 60 #{date}_{1..4}#{POLAROID_SUFFIX} #{animation}", dir: dir)
end
end

# Create collage of all images
def combine_images(overwrite: false)
if File.exist?(File.join(dir, combined)) && !overwrite
Rails.logger.info "Skipping for existing collage #{dir}"
else
Rails.logger.info "Creating collage for #{dir} in background thread"
Syscall.execute("time montage -geometry '25%x25%+25+25<' " \
"-background '#{OPTS.background_color}' " \
"-title '#{OPTS.image_caption}' " \
"-font '#{OPTS.font}' " \
"-fill '#{OPTS.font_color}' " \
"-pointsize #{OPTS.combined_image_fontsize} " \
"-gravity 'Center' #{date}_{1..4}.jpg " \
"#{date}#{COMBINED_SUFFIX}", dir: dir)
end
end

end
5 changes: 4 additions & 1 deletion config/environments/development.rb
Expand Up @@ -6,6 +6,9 @@
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false

# logging to stdout in development
config.logger = Logger.new(STDOUT)

# Do not eager load code on boot.
config.eager_load = false

Expand Down Expand Up @@ -40,7 +43,7 @@
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.perform_deliveries = true
config.action_mailer.logger = nil
config.action_mailer.logger = Logger.new(STDOUT)
config.action_mailer.smtp_settings = {
address: OPTS.mail_settings['address'],
port: OPTS.mail_settings['port'],
Expand Down
Empty file removed lib/tasks/.keep
Empty file.
77 changes: 24 additions & 53 deletions lib/tasks/picture_set.rake
@@ -1,67 +1,38 @@
require 'fileutils'

# rubocop:disable Metrics/BlockLength
namespace :picture_set do
COMBINED_SUFFIX = '_combined.jpg'.freeze

desc 'Combine all images into one'
task :combine_images, [:path] => [:environment] do |_task, args|
path = args[:path]
path = Rails.root.join('public', 'picture_sets') if path.blank?
puts "Using directory #{path}."
Dir.chdir(path) do
picture_sets = Dir.glob('*').select { |f| File.directory? f }
picture_sets.each do |date|
puts "Processing #{date}..."
combine_images(date, path)
end
end
desc 'Re-create collage images'
task :recreate_collage_images, [:path] => [:environment] do |_task, args|
PictureSet::PICTURE_PATH = args[:path] if args[:path].present?
PictureSet.all.each { |ps| ps.combine_images(overwrite: true) }
end

desc 'Remove combined images. Necessary before running combine_images task again.'
task :clean_combine_images, [:path] => [:environment] do |_task, args|
path = args[:path]
path = Rails.root.join('public', 'picture_sets') if path.blank?
puts "Using directory #{path}."
Dir.chdir(path) do
picture_sets = Dir.glob('*').select { |f| File.directory? f }
picture_sets.each do |date|
Dir.chdir(File.join(path, date)) do
FileUtils.rm("#{date}#{COMBINED_SUFFIX}", force: true)
end
end
desc 'Re-create single polaroid images'
task :recreate_polaroid_images, [:path] => [:environment] do |_task, args|
PictureSet::PICTURE_PATH = args[:path] if args[:path].present?
PictureSet.all.each do |ps|
angle = Random.rand(355..365)
(1..4).each { |num| ps.convert_to_polaroid(num, angle) }
end
end

desc 'Copies all images into one directory (without the single polaroids)'
task :copy, %i[path output] => [:environment] do |_task, args|
path = args[:path]
path = Rails.root.join('public', 'picture_sets') if path.blank?
puts "Using directory #{path}."
Dir.chdir(path) do
picture_sets = Dir.glob('*').select { |f| File.directory?(f) && f != 'all' }
picture_sets.each do |date|
begin
Syscall.execute("cp #{File.join(path, date, '*.jpg')} #{args[:output]}")
Syscall.execute("cp #{File.join(path, date, '*.gif')} #{args[:output]}")
rescue StandardError => e
puts e
end
end
end
desc 'Re-create animated gifs'
task :recreate_animations, [:path] => [:environment] do |_task, args|
PictureSet::PICTURE_PATH = args[:path] if args[:path].present?
PictureSet.all.each { |ps| ps.create_animation(overwrite: true) }
end

def combine_images(date, path)
dir = File.join(path, date)
return if File.exist?(File.join(dir, "#{date}#{COMBINED_SUFFIX}"))
begin
Syscall.execute("time montage -geometry '25%x25%+25+25<' -background '#{OPTS.background_color}' " \
"-title '#{OPTS.image_caption}' -font '#{OPTS.font}' -fill '#{OPTS.font_color}' " \
"-pointsize #{OPTS.combined_image_fontsize} -gravity 'Center' #{date}_*.jpg #{date}#{COMBINED_SUFFIX}",
dir: dir)
rescue StandardError => e
puts "Can not process #{dir}: #{e}"
desc 'Exports all images into a single directory (without the single polaroids)'
task :export, %i[output path] => [:environment] do |_task, args|
PictureSet::PICTURE_PATH = args[:path] if args[:path].present?
puts "copying from #{PictureSet::PICTURE_PATH} to #{args[:output]}."
PictureSet.all.each do |ps|
Dir.chdir(ps.dir) do
FileUtils.cp(ps.animation, args[:output])
FileUtils.cp(ps.pictures.map { |p| p[:full] }, args[:output])
end
end
end

end
# rubocop:enable Metrics/BlockLength
Empty file removed public/picture_sets/.gitkeep
Empty file.
Binary file modified public/picture_sets/00example/00example_animation.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions spec/features/picture_set_email_spec.rb
@@ -0,0 +1,22 @@
require 'rails_helper'

feature 'Photobox send picture set by email', js: true do

context 'navigating from index page' do
before do
visit '/'
find(:css, 'img.gallery-img', match: :first).click
click_link('Send per email')
end

it 'shows the email send form' do
expect(page).to have_text('Get your picture send to you immediately')
end

it 'can go back to picture set' do
click_link('Back')
expect(page).to have_css('.fullscreen img')
end
end

end
24 changes: 24 additions & 0 deletions spec/features/picture_set_spec.rb
Expand Up @@ -12,4 +12,28 @@
expect(page).to have_css('.fullscreen img')
end
end

context 'unavailable set' do

before do
visit '/?rw/#/picture_set/2018-04-10_11-22-3/'
end

it 'shows error' do
expect(page).to have_text('PictureSet not found')
end
end

context 'delete set' do

before do
visit '/?rw/#/picture_set/00example'
end

it 'shows error' do
expect_any_instance_of(PictureSet).to receive(:destroy)
click_button('Delete this set')
end
end

end

0 comments on commit 7f37e6e

Please sign in to comment.