Updated 2011-07-04 22:27:49 by RLE

A Tcl/Tk based-GUI to ImageMagick's Identify Command

Man, I would really like to see a native Tcl implementation of identify. Should be easy.

This is a Tcl/Tk based-GUI to ImageMagick's identify command. This was really my first 'large' Tcl/Tk application, so I would love to see input on how to improve the code and style. This program lets you browse to a file or a directory, and outputs identify's data as tagged XML based upon the options checked.
 #!/usr/local/ActiveTcl/bin/wish -f
 #
 # idimage.tcl --
 #
 #    This file is a Tcl/Tk based GUI for ImageMagick's identify utility.
 #
 # RCS:
 #
 #    $RCSfile: 4277,v $
 #    $Date: 2006-11-12 19:00:35 $
 #    $Revision: 1.5 $
 
 package require Tclx
 package require xmlgen
 namespace import ::xmlgen::*
 
 set run_time [clock format [clock scan now] -format {%D %T} ]
 
 # Specify the identify format flag descriptions and flag values. See 
 # http://www.imagemagick.org/script/command-line-options.php#format 
 # for -format flag descriptions and values.
 set format(File_Size) %b
 set format(Comment) %c
 set format(Directory) %d
 set format(Filename_Extension) %e
 set format(Filename) %f
 set format(Unique_Colors) %k
 set format(Label) %l
 set format(Magick) %m
 set format(Number_of_Scenes) %n
 set format(Output_Filename) %o
 set format(Page_Number) %p
 set format(Quantum_Depth) %q
 set format(Scene_Number) %s
 set format(Top_of_Filename) %t
 set format(Temporary_Filename) %u
 set format(X_Y_Resolution) "%x %y"
 set format(Geometry) %wx%h
 set format(Signature) %#
 
 # Declare tags used for XML output
 declaretag Images
 declaretag Image
 declaretag Input_Filename
 
 # Iterate through format flags and declare tags
 foreach format_element [array names format] {
   declaretag $format_element
 }
 
 # Set a title for the window
 wm title . "Tcl/Tk Identify"
 
 # Construct a frame which holds the menubar
 frame .mbar -relief raised -bd 2
 pack .mbar -side top -fill x
 
 #######################################
 #
 # Configure the menubar
 #
 #######################################
 
 # Top-level menu items: File, Options
 menubutton .mbar.file -text File -menu .mbar.file.menu -underline 0
 menubutton .mbar.options -text Options -menu .mbar.options.menu -underline 0
 pack .mbar.file .mbar.options -side left
 
 # File menu
 menu .mbar.file.menu -tearoff 0
 .mbar.file.menu add command -label Open -underline 0 -accelerator "Ctrl+O" \
         -command "file_dialog"
 
 .mbar.file.menu add command -label "Identify All" -underline 9 -accelerator \
         "Ctrl+A" -command "dir_dialog"
 .mbar.file.menu add command -label Quit -underline 0 -accelerator "Ctrl+Q" \
         -command exit 
 
 # Keyboard shortcuts for file menu options
 bind all <Control-o> {file_dialog}
 bind all <Control-a> {dir_dialog}
 bind all <Control-q> {exit}
 
 # Options menu
 menu .mbar.options.menu -tearoff 1
 
 # Populate the options menu
 foreach format_element [array names format] {
 
   # Substitute " " for "_" for display in options menu
   regsub -all "_" $format_element " " gui_format_element
 
   .mbar.options.menu add checkbutton -label "$gui_format_element" -variable \
           $format_element
 }
 
 
 #######################################
 #
 # Text widget to display output
 #
 #######################################
 
 text .text -relief flat -bd 2 -yscrollcommand ".scroll set" -font \
         -adobe-courier-medium-r-*-*-12-*-*-*-*-*-*-*
 
 # Enable gridding in the text widget
 .text configure -setgrid 1
 
 scrollbar .scroll -command ".text yview"
 pack .scroll -side right -fill y
 # Pack the text widget so it fills both axes and will expand to fill screen
 pack .text -side left -fill both -expand 1
 
 
 # Procedure: file_dialog --
 #
 # Produce a dialog box that will allow the user open an individual file.
 #
 # Arguments:
 #    None
 #
 # Results:
 #    Passes a file name to the identify_file procedure.
 
 proc file_dialog {} {
 
   # This is used as an attribute value for the Images tag
   global run_time
 
   set types {
     {{All Files}        {*}}
   }
 
   set file [tk_getOpenFile -filetypes $types]
 
   if {$file != ""} {
   
     # Clear contents of text area
     .text delete 0.0 end
 
     set id_out [identify_file $file]
     set xml_out [Images date=$run_time $id_out]
     .text insert end $xml_out
   }
 }
 
 
 # Procedure: identify_file --
 #
 # Execute identify using the user designated options and show the results in
 # the text widget.
 #
 # Arguments:
 #    Name of file to identify.
 #
 # Results:
 #    Identify results written to text widget.
 
 proc identify_file {thisfile} {
 
   set flags [identify_options]
 
   set result [catch {exec identify -format "$flags" $thisfile} msg]
 
   if {$result==0} {
     set id_out [Image $msg]
     return $id_out
   } else {
     
     # An error has occurred, so inform user and continue
     .text insert end "An exception has occurred:\n$msg"
   }
 
 }
 
 
 # Procedure: identify_options --
 # 
 # Creates a string of -format flags based upon what the user checks in the
 # Options menu.
 #
 # Arguments:
 #    None
 #
 # Results:
 #    A string of -format flags and additional formatting elements.
 
 proc identify_options {} {
 
   # Make format array available to this proc
   global format
 
   # Input filename is the default flag
   set flags " [Input_Filename {%i}]\n"
 
   foreach format_element [array names format] {
 
     global $format_element
     set format_element_checked $$format_element
 
     regsub -all "_" $format_element " " gui_format_element
 
     if [expr $format_element_checked] {
       append flags [$format_element $format($format_element)]\n
     }
   }
 
   return $flags
 }
 
 
 # Procedure: dir_dialog --
 # 
 # Open a directory chooser dialog box
 #
 # Arguments:
 #    None
 #
 # Results:
 #    A directory name passed to the identify_all procedure.
 
 proc dir_dialog {} {
   
   set dir [tk_chooseDirectory -mustexist 1]
 
   if {$dir != ""} {
 
     # Clear contents of text area
     .text delete 0.0 end
 
     # Readdir puts the names of all files in the target dir in a list.
     set files [readdir $dir]
     identify_all $dir $files
   }
 }
 
 
 # Procedure: identify_all --
 # 
 # 
 #
 # Arguments:
 #    A directory name.
 #
 # Results:
 #    Pass each filename within the target directory to the identify_file
 #    procedure.
 
 proc identify_all {dir files} {
 
   # This is used as an attribute value for the Images tag
   global run_time
 
   # Identify each file and append results to id_out
   foreach file $files {
     append id_out [identify_file $dir/$file]
   }
 
   set xml_out [Images date=$run_time $id_out]
   .text insert end $xml_out  
 }