Saturday, May 19, 2012

Batch Image Resizing from the GIMP command-line

The following TinyScheme (Script-Fu) script resizes one or more image files as specified with a file glob, and writes the resized image files into an output directory:

(define (scale-to-max-fileglob
         file-pattern
         out-dir
         newmax
         )
  (let* ((filelist (cadr (file-glob file-pattern 1))))
    (while (not (null? filelist))
      (let* ((in-file (car filelist))
             (image (car (gimp-file-load RUN-NONINTERACTIVE in-file in-file)))
             (drawable (car (gimp-image-get-active-drawable image)))
             (old-width (car (gimp-image-width image)))
             (old-height (car (gimp-image-height image)))
             (old-max (max old-width old-height))
             (new-width (round (/ (* old-width newmax) old-max)))
             (new-height (round (/ (* old-height newmax) old-max))))
        ;; http://tinyurl.com/7bvura2 states "... because saving undo
        ;; steps can be time and memory intensive" and so we don't
        ;; care about undo operations for batch runs:
        (gimp-image-undo-disable image)
        (gimp-image-scale image new-width new-height)
        (let ((out-file
               (string-append out-dir
                              ;; Insert a slash character if
                              ;; not already at the tail-end
                              ;; of out-dir:
                              (if (char=? #\/ (car (last (string->list out-dir))))
                                  ""
                                  "/")
                              ;; Take the basename of in-file which may be a fully-qualified path:
                              (car (last (strbreakup in-file "/"))))))
          ;; The print function does not show output on standard
          ;; output, so use gimp-message instead:
          (gimp-message (string-append "   scale-to-max-fileglob: scaling "
                                       in-file " into " out-file
                                       " with these dimensions: "
                                       (number->string new-width) "x" (number->string new-height)))
          (gimp-file-save RUN-NONINTERACTIVE image drawable out-file out-file))
        (gimp-image-delete image))
      (set! filelist (cdr filelist)))))

Store this into ~/.gimp-2.6/scripts/batch-resize.scm and the definition of scale-to-max-fileglob will load into all future gimp sessions.


Example run: This was executed using GIMP 2.6 on a 64-bit Debian Linux machine.  The "script-fu-Warning" is coming from the gimp-message function:



user@somehost:/tmp/images_dir$ time gimp -i -b '(begin (scale-to-max-fileglob "*.jpg" "outdir" 1000) (gimp-quit 0))'

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-43-42_676.jpg into outdir/2012-05-19_16-43-42_676.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-44-35_210.jpg into outdir/2012-05-19_16-44-35_210.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-41-21_785.jpg into outdir/2012-05-19_16-41-21_785.jpg with these dimensions: 1000x562

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-44-02_760.jpg into outdir/2012-05-19_16-44-02_760.jpg with these dimensions: 1000x562

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-45-34_771.jpg into outdir/2012-05-19_16-45-34_771.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-43-15_141.jpg into outdir/2012-05-19_16-43-15_141.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-42-39_886.jpg into outdir/2012-05-19_16-42-39_886.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-45-13_128.jpg into outdir/2012-05-19_16-45-13_128.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-42-52_376.jpg into outdir/2012-05-19_16-42-52_376.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-41-49_429.jpg into outdir/2012-05-19_16-41-49_429.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-42-08_196.jpg into outdir/2012-05-19_16-42-08_196.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-41-54_552.jpg into outdir/2012-05-19_16-41-54_552.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-42-34_497.jpg into outdir/2012-05-19_16-42-34_497.jpg with these dimensions: 562x1000



real    0m16.179s
user    0m13.229s
sys    0m2.236s




The above code was cobbled together from these sources:
  1. Christopher Campbell's blog: Batch image scaling with Gimp
  2. TinySCHEME Version 1.40 Manual is rather skimpy so you may desire to refer to The Racket Reference instead.
  3. Gimp Batch Mode Introduction

Saturday, October 8, 2011

Developing Software Productively through selective automation

How do you increase your software development productivity over the long haul? Here's how: Examine your daily task work to identify tasks that are amenable to automation, and then automate it. For me, this means to do the following:
  1. Maintain a constant awareness of all of your development activities, specifically patterns of behavior or groups of actions that are repeated multiple times throughout the day.
  2. Of those patterns, identify the ones that are comprised of tasks that do not change regardless of the circumstances.
  3. Determine if those tasks are amenable to automation (some will, some won't). This excludes tasks that should be delegated to someone else to do.
  4. Schedule time to encapsulate the tasks in a software routine.
  5. Make executing that routine mindless and effortless, by associating the execution of the routine to a new and unique combination of key-bindings in the main window of the primary editing tool you use (e.g. Emacs, Eclipse, Jedit, etc.).
Some may think that the "schedule time" item will eat into their productivity. However, I have found in practice that the time saved by automation will pay for itself over time. But there is one more benefit: Having a machine execute the tasks frees up your mind to think at a higher level of abstraction, in a given project. Making a task mindless and effortless has the goal of not distracting your mind from the flow of adding, deleting, and moving code around. Any requirement to pull down menus, bring other windows to the front, type in and execute long command lines, etc., are distracting to the mental process of software development and should be gradually eliminated by delegating those tasks to push-button automation. Therefore, as a software developer, those activities are best done right there in the text editing window itself, to be driven by carefully chosen key sequences that are easy to memorize. Below are some examples of tasks I discovered fit the above criteria, and that I could automate (this is specific to my focus on code development, but they could be generalized for other work domains):
  1. When the cursor is on a full or relative path to a file somewhere on the filesystem, typing a keystroke to open the file in the text editor. Compare that to opening up a new window, moving the mouse cursor into that window, navigating a file browser to find the file or typing in the full path to the file in the file system. Think about how often that task is done in given developers work day.
  2. When the cursor is sitting on a URL, typing a keystroke to open the URL in a browser. Think about how often you need to refer to reference material that is only on some remote web server somewhere.
  3. When the cursor is sitting on a symbol whose definition you need to alter, typing a keystroke to drive your editor to view and edit that definition. Compare that with using a file search to find the definition, and filter out the false positives.
  4. You need to go back to where you started when editing some code, so type a keystroke to go back to the place where you started. The idea here is that each time you navigate to a new view on some source, there is the equivalent of a "back" button in the form of a key sequence. This should be applicable for all types of navigation to some file, symbol, or web page.
  5. You need to reload your brain with the context after an interruption. The thing being automated away is the time wasted wondering where you left off, or clicking through various windows or views to answer that question. The solution is to track notes of decisions you are making in a searchable set of interlinked note files. This excludes writing them down on paper, since there is no search capability (and filing cabinets and other filing systems are yet another mental distraction). In my case, I use multiple text files that are interlinked (Muse mode in GNU Emacs). This also pays dividends later on when you need to refresh your memory on decisions that were made on the project done months later.

How to install Adobe Flash plugin versus Gnash under 32-bit FireFox 7.0.1 on Debian Linux


Overview


Herein I show a step-by-step procedure to install Adobe Flash plugin into Firefox, and remove the Gnash plugin which seems to be buggy as of 2011-10-08.  The version of Firefox I am using here is not the one that is installed using the Debian package manager, but the Firefox I downloaded directly from the Mozilla website.

Provided below is Procedure followed by the Backstory.

Procedure

  1. Close down Firefox. 
  2. Do step 165  which states: "If you installed via apt-get/aptitude (Debian/Ubuntu): sudo apt-get remove flashplugin-nonfree"
  3. Do step 167:
    1. Type about:config in the address bar and press Enter. 
    2. Find the option plugin.expose_full_path and change the value to "true" (double-clicking the preference name will toggle the setting).
    3. Type about:plugins and locate the flash plugin
  4. If you see the Gnash Shockwave plugin (you will see "gnash" somewhere in the pathname), then you need to continue below and remove it:
    1. Remove the gnash plugin from the Debian installation: sudo apt-get remove browser-plugin-gnash gnash-dbg
  5. Install Adobe Flash plugin:
    1. Download the .tar.gz file from the Adobe website specifically for 32-bit Linux (I did this by disabling all Shockwave plugins, then browsing to YouTube, and then clicking on the link to the Adobe website to find the link specifically for Linux).
    2. Into a temporary directory, extract the tarball via tar zxvf thefile.tar.gz
    3. Copy the file into ~/.mozilla/plugins/libflashplayer.so, overwriting any file that will be there.
  6. Reinvoke Firefox
  7. In the Address field, type about:plugins
  8. You should not see any Gnash references under any Shockwave Flash entry
  9. Test it out on a YouTube video:
    1. Browse to http://www.youtube.com
    2. Right mouse click on the video and insure it does not say HTML5. If it does, keep looking for other videos that are true flash videos.
    3. Right mouse click on the video and it should say "About Adobe Flash player ".
  10. Test it out on http://www.tfd.com/browser
    1. Click on the tiny blue speaker symbol to the right of the "browser" word in the definition. It should pronounce the word.
    2. Right mouse click on the icon and it should also say "About Adobe Flash Player ".

Backstory

I am using the Firefox version 7.0.1 that was downloaded directly from the Mozilla website, and not the one provided by Debian (i.e., I did not want the one rebranded as Iceweasel).  I did this because I want to be able to upgrade Firefox using the built-in Firefox upgrade mechanism versus be held up by the Debian release schedule.




I had recently upgraded my 32-bit laptop to use a recent version of Debian. I reused my existing Firefox installation that was installed into my HOME directory.  Everything was working smoothly, until today when I discovered that clicking on the pronunciation icons for definitions inside the http://www.tfd.com site no longer played the pronunciation links, but Flash YouTube videos would play properly.  This post shows what I did to fix the problem.

This post pertains to Firefox 7.0.1 and not Iceweasel running on a 32-bit Debian system.

From what I can gather, the main problem was that the gnash package was being used as the Shockwave Flash player and not the Adobe Flash player plugin.  Why Gnash could not handle http://www.tfd.com I do not know.

I discovered that there were two different kinds of flash plugin being referenced in my Firefox sessions. This may not be the underlying cause of the problem, but having both in the mix seemed wrong in concept, so this shows how I removed the Gnash plugin from my system, and install the latest version of Adobe Flash plugin.

The key trick is to step 167 which states (grammar editing applied):
  1. Type about:config in the address bar and press Enter. Find the option plugin.expose_full_path and change the value to "true" (double-clicking the preference name will toggle the setting).
  2. type about:plugins and locate the flash plugin.
I saw two flash plugins be displayed from the about:plugins page:
Shockwave Flash
File: /home/brentg/.mozilla/plugins/libflashplayer.so
Version:
Shockwave Flash 11.0 r1
MIME Type    Description    Suffixes
application/x-shockwave-flash    Shockwave Flash    swf
application/futuresplash    FutureSplash Player    spl

Shockwave Flash
File: /usr/lib/gnash/libgnashplugin.so
Version:
Shockwave Flash 10.1 r999.
Gnash 0.8.8, the GNU SWF Player. Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Gnash comes with NO WARRANTY, to the extent permitted by law. You may redistribute copies of Gnash under the terms of the GNU General Public License. For more information about Gnash, see http://www.gnu.org/software/gnash.
Compatible Shockwave Flash 10.1 r999.
MIME Type    Description    Suffixes
application/x-shockwave-flash    Shockwave Flash    swf

Setting the "plugin.expose_full_path" option inside about:config to true is what causes the about:config output above to show the "File:" lines highlighted above.  That was the key information I needed, since with that file path, I could find out what provides the gnash plugin and remove the corresponding Debian packages:

brentg@bg1:~/Downloads/flash$ apt-file search /usr/lib/gnash/libgnashplugin.so
browser-plugin-gnash: /usr/lib/gnash/libgnashplugin.so
gnash-dbg: /usr/lib/debug/usr/lib/gnash/libgnashplugin.so
brentg@bg1:~/Downloads/flash$ sudo apt-get remove browser-plugin-gnash gnash-dbg
Reading package lists... Done
Building dependency tree      
Reading state information... Done
Package gnash-dbg is not installed, so not removed
The following packages will be REMOVED:
 browser-plugin-gnash
0 upgraded, 0 newly installed, 1 to remove and 0 not upgraded.
After this operation, 369 kB disk space will be freed.
Do you want to continue [Y/n]? y
(Reading database ... 116648 files and directories currently installed.)
Removing browser-plugin-gnash ...
I believe that the removal is required so as to prevent Firefox from even considering gnash as the plugin that handles Flash videos when using the Adobe Flash plugin is the one I had intended to use.

I did try step 165 below but it turns out that I did not have the flashplugin-nonfree package(s) installed (but I left in that step in the procedure for completeness).


Sunday, November 28, 2010

YouTranscript for text transcripts of online videos

It's interesting what you stumble upon by accident. I ran across a project the author of Let Over Lambda is working on, called YouTranscript. It is something I've wanted for a long time. It provides transcripts of some technically oriented YouTube videos. What I thought was really interesting is the way the web page for each video highlights the text as the video is playing, and each fragment of text is a clickable entity. For example, 6-Minute Memristor Guide.

Friday, August 14, 2009

Usage of SSH and VLC

This is a followup to an earlier post about VLC in order to elaborate a bit on how I use SSH in that context. First, you need to insure that your SSH works properly from the local to the remote hosts. I am assuming that you know the IP addresses of both hosts here, and both machines are expected to be running Linux. To that end, insure that you can run this command to list files on the remote machine:
echo ls -d .bash\* | ssh -X -Y "REMOTE_USER_NAME@REMOTE_IP_ADDRESS"
You need to change "REMOTE_USER_NAME" to be the username on that remote host, and "REMOTE_IP_ADDRESS" should be the IP address of that remote host (I am using an IP address instead of a hostname to side-step questions discussion about how to set up DNS on your local network given the complexity of DNS). When I do this from my Linux laptop to my Linux desktop, both of which are on my local area network, I simply see a list of files that match the ".b*" expression:
.bash_history
.bash_logout
.bash_profile
.bashrc
Note the backslash in front of the "*" on the command on the local machine, which avoids shell expansion on the local host. If you are able to do that, then you should be able to use the same "echo" command to send vlc commands to the remote host. You may or may not have a SSH agent running on your local system. I do, and it is called seahorse. If you are running GNOME on Debian Linux, it is likely to be available to you by running "seahorse" at a shell command prompt. That seahorse program is an interface to a daemon that runs in the background, handling requests for passwords and such, such that when you request a ssh connection to a remote machine, the seahorse daemon will display an X window dialog box that prompts you for the password for authentication. I'm not exactly sure as to how it determines the password to type in if you don't have a ~/.ssh/ directory setup. If you don't have a .ssh directory, I would encourage you to read up on Linux SSH tutorials on the web for more detailed info. Second, you need to use the ssh command to send a VLC command to stream the AVI file back to the local host, and invoke VLC in GUI mode to receive the stream and display it. Below is the VLC commands I run from the local machine to (a) start the remote VLC session to stream it back, and (b) to start a VLC GUI session locally that will be the receiver:
LOCAL_IP_ADDRESS=you_must_set_this_value
REMOTE_IP_ADDRESS=you_must_set_this_value

# senderVLCCommand is the command we want to execute on the remote
# machine.  I included the sed command that just adds " sender --> "
# to the front of every line so that we can see it on the local
# terminal. Note that although this is placed in the background
# (&), we will still see the "sender" output lines:

senderVLCCommand="vlc -vvv --sout \
  '#std{access=udp,mux=ts,dst=${LOCAL_IP_ADDRESS}:1234}' \\\"$file\\\" 2>&1 \
  | sed 's%^%  sender --> %g'"
sshSenderCommand="echo \"$senderVLCCommand\" \
  | ssh -X -Y \"${REMOTE_USER_NAME}@${REMOTE_IP_ADDRESS}\" sh &"
sh "$sshSenderCommand"

# Note spawn the local VLC session, which will read the stream. Note
# the port number used here in the sender and receiver sessions
# happens to be 1234 (chosen arbitrarily, as long as the number is >
# 1024 and not in use by some other process).

$receiverVLCCommand="vlc -vvv udp://\@:1234 2>&1 | sed 's%^%receiver -->%g' &"
sh "$receiverVLCCommand"

Both commands are put into the background. It has been my experience that this isn't a problem for the sender to start before the receiver starts, as presumably it will block waiting for a receiver to connect to the sender port before transmission starts. Note that for the second command, I use a sed command to prefix "reciever" so that I can monitor errors that occur (and will occur if you have network setup problems or corrupt AVI files, or both). Word of warning: The position slider on the receiver GUI window does not work as you would expect it to. I have not yet found a solution, and would appreciate any comments as to a suitable fix.

Thursday, July 16, 2009

Emacs Blogger Integration

I find editing text outside of Emacs very cumbersome. Editing HTML directly inside Emacs or any other editor is also very cumbersome. What I think I need is a way to edit certain types of markup from within Emacs but save it into some blogging "backend" such as Blogger. What I have done so far is use the Mozex Firefox extension to edit text fields inside Blogger, and that is a big improvement, but it is still lacking: To see the rendered HTML, I have to switch between Firefox and Emacs, and I am still writing in HTML, versus a WYSIWYG view of the text. Some possibilities that I may eventually investigate are: If anyone has any experiences with those, or can offer other alternatives, I would like to know.

Friday, May 29, 2009

Overlap

I found myself interested in the underpinnings of Zen Buddhism. That eventually led to my reading of The Creed of Half Japan, by Arthur Lloyd, [1911]. In it, I found an interesting reference to "three modes of expression":
(64) In truth, there were, in germ, in the new Buddhism which was then coming into shape in the Indus valley, three modes of expression which must all be taken into account, if we would understand the Japanese Mahāyāna of to-day. They are not confined to Buddhism: they are found in Gnosticism, in Hinduism, in Christianity; they are, in fact, universals of religion. They may, for brevity's sake, be termed the Way, the Truth, and the Life; the appeal to the affections, the intellect, the spiritual imagination of Faith.
Eckhart Tolle said essentially the same thing (and I do not recall where and when), that each of those religions had such a mystical offshoot.