support rotation (typically, of portrait images that came with no EXIF) from GUI...
authorgc <gc>
Tue, 29 Mar 2005 21:04:03 +0000 (21:04 +0000)
committergc <gc>
Tue, 29 Mar 2005 21:04:03 +0000 (21:04 +0000)
bin/booh
bin/booh-gui
lib/booh/GtkAutoTable.rb
lib/booh/booh-lib.rb

index 58788bcfc6c30eca98ff285c44a32cc851c907dc..9fa7e4574c6eeaf0c6cb57130f2587af4202d122 100755 (executable)
--- a/bin/booh
+++ b/bin/booh
@@ -24,7 +24,6 @@ require 'gettext'
 include GetText
 require 'rexml/document'
 include REXML
-require 'timeout'
 
 require 'booh/booh-lib'
 require 'booh/html-merges'
@@ -53,7 +52,6 @@ $options = [
 ]
 
 #- default values for some globals 
-$convert = 'convert -interlace line +profile "*"'
 $switches = []
 $stdout.sync = true
 
@@ -164,11 +162,9 @@ def check_installation
     if $no_check
         return
     end
-    %w(convert identify exif transcode mencoder).each { |prg|
-        if !system("which #{prg} >/dev/null")
-            die __("The `%s' program is typically needed. Re-run with --no-check if you're sure you're fine without it.", prg)
-        end
-    }
+    if missing = %w(convert identify exif transcode mencoder).delete_if { |prg| system("which #{prg} >/dev/null 2>/dev/null") }
+        die __("The following programs are typically needed: `%s'. Re-run with --no-check if you're sure you're fine without them.", missing.join(', '))
+    end
 end
 
 def replace_line(surround, keyword, line)
@@ -191,31 +187,6 @@ def build_html_skeletons
     end
 end
 
-def sys(cmd)
-    msg 2, cmd
-    system(cmd)
-end
-
-#- parallelizable sys
-def psys(cmd)
-    if $mproc
-        if pid = fork
-            $pids << pid
-        else
-            msg 2, cmd + ' &'
-            system(cmd)
-            exit 0
-        end
-        if $pids.length == $mproc
-            finished = Process.wait2
-            $pids.delete(finished[0])
-            $pids = $pids.find_all { |pid| Process.waitpid(pid, Process::WNOHANG) == nil }
-        end
-    else
-        sys(cmd)
-    end
-end
-
 def find_caption_value(xmldir, filename)
     xmldir.elements["[@filename='#{utf8(filename)}']"].attributes['caption']
 end
@@ -224,91 +195,6 @@ def find_captions(xmldir, images)
     return images.collect { |img| find_caption_value(xmldir, img) }
 end
 
-#- grab the results of a command but don't sleep forever on a runaway process
-def subproc_runaway_aware(command)
-    begin
-        timeout(5) {
-            return `#{command}`
-        }
-    rescue Timeout::Error    
-        msg 1, _("forgetting runaway process (transcode sucks again?)")
-        #- todo should slay transcode but dunno how to do that
-        return nil
-    end
-end
-
-def gen_thumbnails(orig, xmldir, dests)
-    if !dests.detect { |dest| !File.exists?(dest['filename']) } 
-        return true
-    end
-
-    felem = xmldir.elements["[@filename='#{utf8(File.basename(orig))}']"]
-
-    if entry2type(orig) == 'image'
-        convert_options = ''
-        if felem
-            rotate = felem.attributes['rotate']
-            if !rotate
-                orientation = `exif '#{orig}'`.detect { |line| line =~ /^Orientation/ }
-                if orientation =~ /right - top/
-                    rotate = '90'
-                end
-                if orientation =~ /left - bottom/
-                    rotate = '-90'
-                end
-                rotate ||= '0'
-                felem.add_attribute('rotate', rotate)
-            end
-            convert_options += "-rotate #{rotate} "
-        end
-        for dest in dests
-            if !File.exists?(dest['filename'])
-                psys("#{$convert} #{convert_options}-geometry #{dest['size']} '#{orig}' '#{dest['filename']}'")
-            end
-        end
-        return true
-
-    elsif entry2type(orig) == 'video'
-        dest_dir = make_dest_filename(File.dirname(dests[0]['filename']))
-        #- frame-offset is an attribute that allows to specify which frame to use for the thumbnail;
-        #- first try in dir to allow for: <dir .. subdirs-captionfile='/tmp/src2/people/pict0008.mov' pict0008.mov-frame-offset='100' ..>
-        frame_offset = xmldir.attributes["#{utf8(File.basename(orig))}-frame-offset"]
-        if !frame_offset
-            #- then try in elements to allow for: <video filename='bourrique.mov' frame-offset='200'/>
-            felem and frame_offset = felem.attributes['frame-offset']
-        end
-        frame_offset = (frame_offset || 5).to_i
-        for dest in dests
-            if !File.exists?("#{dest_dir}/screenshot.jpg000004.jpg")
-                cmd = "transcode -a 0 -c #{frame_offset-5}-#{frame_offset} -i '#{orig}' -y jpg -o '#{dest_dir}/screenshot.jpg' 2>&1"
-                msg 2, cmd
-                if subproc_runaway_aware(cmd) =~ /V: import format.*unknown/ || !File.exists?("#{dest_dir}/screenshot.jpg000004.jpg")
-                    msg 2, __("* could not extract first image of video %s with transcode, will try first converting with mencoder", orig)
-                    cmd = "mencoder '#{orig}' -nosound -ovc lavc -lavcopts vcodec=mjpeg -o '#{dest_dir}/foo.avi' -frames #{frame_offset} -fps 25 >/dev/null 2>/dev/null"
-                    msg 2, cmd
-                    system cmd
-                    if File.exists?("#{dest_dir}/foo.avi")
-                        cmd = "transcode -a 0 -c #{frame_offset-5}-#{frame_offset} -i '#{dest_dir}/foo.avi' -y jpg -o '#{dest_dir}/screenshot.jpg' 2>&1"
-                        msg 2, cmd
-                        results = subproc_runaway_aware(cmd)
-                        system("rm -f '#{dest_dir}/foo.avi'")
-                        if results =~ /V: import format.*unknown/ || !File.exists?("#{dest_dir}/screenshot.jpg000004.jpg")
-                            msg 0, __("could not extract first image of video %s encoded by mencoder", "#{dest_dir}/foo.avi")
-                            return false
-                        end
-                    else
-                        msg 0, __("could not make mencoder to encode %s to mpeg4", "#{orig}")
-                        return false
-                    end
-                end
-
-            end
-            sys("#{$convert} -geometry #{dest['size']} #{dest_dir}/screenshot.jpg000004.jpg '#{dest['filename']}'")
-        end
-        return true
-    end
-end
-
 #- stolen from CVSspam
 def urlencode(text)
   text.sub(/[^a-zA-Z0-9\-,.*_\/]/) do
index 7eb84bb5d9e1964b3d8fd54fb56a38c7edaed764..3d77abd73b97f37d819f7f5dd30afcc2b0f1b611 100755 (executable)
@@ -20,6 +20,7 @@
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 require 'getoptlong'
+require 'tempfile'
 
 require 'gtk2'
 require 'booh/GtkAutoTable'
@@ -163,6 +164,7 @@ def view_element(filename)
     w.show_all
 end
 
+$retail_tempfiles = {}
 def add_thumbnail(autotable, name, type, filename, caption)
 
     frame1 = Gtk::Frame.new
@@ -197,6 +199,29 @@ def add_thumbnail(autotable, name, type, filename, caption)
     #- to be able to find widgets by name
     $name2widgets[name] = { :textview => textview }
 
+    rotate = Proc.new { |angle|
+        set_mousecursor_wait(vbox.window)
+
+        #- update rotate attribute
+        xmldir = $xmldoc.elements["//dir[@path='#{$current_path}']"]
+        felem = xmldir.elements["[@filename='#{name}']"]
+        felem.add_attribute('rotate', felem.attributes['rotate'].to_i + angle)
+
+        #- rotate shown thumbnail
+        $retail_tempfiles[filename] = Tempfile.new('booh')
+        default_size = $images_size.detect { |sizeobj| sizeobj['default'] }
+        sys("#{$convert} -rotate #{angle} -geometry #{default_size['thumbnails']} '#{filename}' '#{$retail_tempfiles[filename].path}'")
+        img.set(filename = $retail_tempfiles[filename].path)
+
+        #- remove out of sync images
+        dest_img_base = build_full_dest_filename(name).sub(/\.[^\.]+$/, '')
+        for sizeobj in $images_size
+            system("rm -f #{dest_img_base}-#{sizeobj['fullscreen']}.jpg #{dest_img_base}-#{sizeobj['thumbnails']}.jpg")
+        end
+
+        set_mousecursor_normal(vbox.window)
+    }
+
     textview.signal_connect('key-press-event') { |w, event|
         propagate = true
         textview.set_editable(event.keyval != Gdk::Keyval::GDK_Tab)
@@ -207,6 +232,7 @@ def add_thumbnail(autotable, name, type, filename, caption)
             x, y = autotable.get_current_pos(vbox)
             control_pressed = event.state & Gdk::Window::CONTROL_MASK != 0
             shift_pressed = event.state & Gdk::Window::SHIFT_MASK != 0
+            alt_pressed = event.state & Gdk::Window::MOD1_MASK != 0
             if event.keyval == Gdk::Keyval::GDK_Up && y > 0
                 if control_pressed
                     $vbox2textview[autotable.get_widget_at_pos(x, y - 1)].grab_focus
@@ -227,7 +253,7 @@ def add_thumbnail(autotable, name, type, filename, caption)
             end
             if event.keyval == Gdk::Keyval::GDK_Left
                 previous = autotable.get_previous_widget(vbox)
-                if autotable.get_current_pos(previous)[0] < x
+                if previous && autotable.get_current_pos(previous)[0] < x
                     if control_pressed
                         $vbox2textview[previous].grab_focus
                     end
@@ -236,10 +262,13 @@ def add_thumbnail(autotable, name, type, filename, caption)
                         textview.grab_focus  #- because if moving, focus is stolen
                     end
                 end
+                if alt_pressed
+                    rotate.call(-90)
+                end
             end
             if event.keyval == Gdk::Keyval::GDK_Right
                 next_ = autotable.get_next_widget(vbox)
-                if autotable.get_current_pos(next_)[0] > x
+                if next_ && autotable.get_current_pos(next_)[0] > x
                     if control_pressed
                         $vbox2textview[next_].grab_focus
                     end
@@ -248,6 +277,9 @@ def add_thumbnail(autotable, name, type, filename, caption)
                         textview.grab_focus  #- because if moving, focus is stolen
                     end
                 end
+                if alt_pressed
+                    rotate.call(90)
+                end
             end
             if event.keyval == Gdk::Keyval::GDK_Delete && control_pressed
                 after = autotable.get_next_widget(vbox)
@@ -282,6 +314,23 @@ def add_thumbnail(autotable, name, type, filename, caption)
         end
     }
 
+    vbox.signal_connect('button-press-event') { |w, event|
+        $gesture_press = { :name => name, :x => event.x, :y => event.y }
+        false
+    }
+
+    vbox.signal_connect('drag-data-received') { |w, ctxt, x, y, selection_data, info, time|
+        if $gesture_press && $gesture_press[:name] == name
+            if (($gesture_press[:x]-x)/($gesture_press[:y]-y)).abs > 2 && ($gesture_press[:x]-x).abs > 5
+                angle = x-$gesture_press[:x] > 0 ? 90 : -90
+                msg 3, "gesture rotate: #{angle}"
+                rotate.call(angle)
+            end
+        end
+        $gesture_press = nil
+    }
+
+
     vbox.show_all
 end
 
index c2fc7cfa9cc1ad56baf5edcd98cd073b6eb7bf80..5c9c2136fc8efa80dc6b64817580fde2f10a8c49 100644 (file)
@@ -132,9 +132,11 @@ class Gtk::AutoTable < Gtk::VBox
 
     #- insert a widget before another by numbers
     def insert(src, dst)
-        chld = @children.delete_at(src)
-        @children[dst > src ? dst - 1 : dst, 0] = chld
-        redistribute(true)
+        if src != dst
+            chld = @children.delete_at(src)
+            @children[dst > src ? dst - 1 : dst, 0] = chld
+            redistribute(true)
+        end
     end
 
     #- get widget at [x, y] position of automatically handled table
index 2bc4159dfbe9f2f26d55fcdfc5b51aa72e9793b8..9ca28a29fcc1b297186b61a7dea2db03628064a8 100644 (file)
@@ -20,6 +20,7 @@
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 require 'iconv'
+require 'timeout'
 
 require 'gettext'
 include GetText
@@ -31,6 +32,7 @@ require 'booh/version.rb'
 module Booh
     $verbose_level = 2
     $CURRENT_CHARSET = `locale charmap`.chomp
+    $convert = 'convert -interlace line +profile "*"'
 
     def utf8(string)
         return Iconv::iconv("UTF-8", $CURRENT_CHARSET, string).to_s
@@ -107,4 +109,114 @@ module Booh
         end
     end
 
+    def sys(cmd)
+        msg 2, cmd
+        system(cmd)
+    end
+
+    #- parallelizable sys
+    def psys(cmd)
+        if $mproc
+            if pid = fork
+                $pids << pid
+            else
+                msg 2, cmd + ' &'
+                system(cmd)
+                exit 0
+            end
+            if $pids.length == $mproc
+                finished = Process.wait2
+                $pids.delete(finished[0])
+                $pids = $pids.find_all { |pid| Process.waitpid(pid, Process::WNOHANG) == nil }
+            end
+        else
+            sys(cmd)
+        end
+    end
+
+    #- grab the results of a command but don't sleep forever on a runaway process
+    def subproc_runaway_aware(command)
+        begin
+            timeout(5) {
+                return `#{command}`
+            }
+        rescue Timeout::Error    
+            msg 1, _("forgetting runaway process (transcode sucks again?)")
+            #- todo should slay transcode but dunno how to do that
+            return nil
+        end
+    end
+
+    def gen_thumbnails(orig, xmldir, dests)
+        if !dests.detect { |dest| !File.exists?(dest['filename']) } 
+            return true
+        end
+
+        felem = xmldir.elements["[@filename='#{utf8(File.basename(orig))}']"]
+
+        if entry2type(orig) == 'image'
+            convert_options = ''
+            if felem
+                rotate = felem.attributes['rotate']
+                if !rotate
+                    orientation = `exif '#{orig}'`.detect { |line| line =~ /^Orientation/ }
+                    if orientation =~ /right - top/
+                        rotate = '90'
+                    end
+                    if orientation =~ /left - bottom/
+                        rotate = '-90'
+                    end
+                    rotate ||= '0'
+                    felem.add_attribute('rotate', rotate)
+                end
+                convert_options += "-rotate #{rotate} "
+            end
+            for dest in dests
+                if !File.exists?(dest['filename'])
+                    psys("#{$convert} #{convert_options}-geometry #{dest['size']} '#{orig}' '#{dest['filename']}'")
+                end
+            end
+            return true
+
+        elsif entry2type(orig) == 'video'
+            dest_dir = make_dest_filename(File.dirname(dests[0]['filename']))
+            #- frame-offset is an attribute that allows to specify which frame to use for the thumbnail;
+            #- first try in dir to allow for: <dir .. subdirs-captionfile='/tmp/src2/people/pict0008.mov' pict0008.mov-frame-offset='100' ..>
+            frame_offset = xmldir.attributes["#{utf8(File.basename(orig))}-frame-offset"]
+            if !frame_offset
+                #- then try in elements to allow for: <video filename='bourrique.mov' frame-offset='200'/>
+                felem and frame_offset = felem.attributes['frame-offset']
+            end
+            frame_offset = (frame_offset || 5).to_i
+            for dest in dests
+                if !File.exists?("#{dest_dir}/screenshot.jpg000004.jpg")
+                    cmd = "transcode -a 0 -c #{frame_offset-5}-#{frame_offset} -i '#{orig}' -y jpg -o '#{dest_dir}/screenshot.jpg' 2>&1"
+                    msg 2, cmd
+                    if subproc_runaway_aware(cmd) =~ /V: import format.*unknown/ || !File.exists?("#{dest_dir}/screenshot.jpg000004.jpg")
+                        msg 2, __("* could not extract first image of video %s with transcode, will try first converting with mencoder", orig)
+                        cmd = "mencoder '#{orig}' -nosound -ovc lavc -lavcopts vcodec=mjpeg -o '#{dest_dir}/foo.avi' -frames #{frame_offset} -fps 25 >/dev/null 2>/dev/null"
+                        msg 2, cmd
+                        system cmd
+                        if File.exists?("#{dest_dir}/foo.avi")
+                            cmd = "transcode -a 0 -c #{frame_offset-5}-#{frame_offset} -i '#{dest_dir}/foo.avi' -y jpg -o '#{dest_dir}/screenshot.jpg' 2>&1"
+                            msg 2, cmd
+                            results = subproc_runaway_aware(cmd)
+                            system("rm -f '#{dest_dir}/foo.avi'")
+                            if results =~ /V: import format.*unknown/ || !File.exists?("#{dest_dir}/screenshot.jpg000004.jpg")
+                                msg 0, __("could not extract first image of video %s encoded by mencoder", "#{dest_dir}/foo.avi")
+                                return false
+                            end
+                        else
+                            msg 0, __("could not make mencoder to encode %s to mpeg4", "#{orig}")
+                            return false
+                        end
+                    end
+
+                end
+                sys("#{$convert} -geometry #{dest['size']} #{dest_dir}/screenshot.jpg000004.jpg '#{dest['filename']}'")
+            end
+            return true
+        end
+    end
+
 end