summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/epspdf/epspdftk.rb
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/scripts/epspdf/epspdftk.rb')
-rwxr-xr-xMaster/texmf-dist/scripts/epspdf/epspdftk.rb958
1 files changed, 958 insertions, 0 deletions
diff --git a/Master/texmf-dist/scripts/epspdf/epspdftk.rb b/Master/texmf-dist/scripts/epspdf/epspdftk.rb
new file mode 100755
index 00000000000..c09509c0c8f
--- /dev/null
+++ b/Master/texmf-dist/scripts/epspdf/epspdftk.rb
@@ -0,0 +1,958 @@
+#!/usr/bin/env ruby
+
+# epspdf conversion utility, GUI frontend
+
+#####
+# Copyright (C) 2006 Siep Kroonenberg
+# n dot s dot kroonenberg at rug dot nl
+#
+# This program is free software, licensed under the GNU GPL, >=2.0.
+# This software comes with absolutely NO WARRANTY. Use at your own risk!
+#####
+
+#$DEBUG=1
+
+# epspdfboot.rb: modify loadpath in a way which works both
+# with a full Ruby and with a custom subset ruby
+
+require __FILE__.sub( /epspdftk\.rbw?/, 'epspdfboot.rb' )
+
+##########################################
+
+# load conversion engine. epspdf also loads epspdfrc,
+# which detects platform and available converters.
+
+require 'epspdf'
+
+$VERBOSE = nil
+
+#require 'pp'
+
+if $DEBUG
+ puts ARCH
+ puts Config::CONFIG['arch']
+ puts "Ghostscript command #{$settings.gs_prog}" \
+ " and version #{$settings.gs_version}"
+ puts "Pdftops command #{$settings.pdftops_prog}" \
+ " and version #{$settings.pdftops_version}"
+end
+
+def viewable( p )
+ return nil unless p && p.path
+ return nil if p.type == 'other'
+ case ARCH
+ when 'osx'
+ return true
+ when 'w32'
+ return nil if p.type == 'epsPreview'
+ return open_with( File.extname( p.path ) )
+ else
+ return nil if p.type == 'epsPreview'
+ return true if p.type =~ /e?ps/ and ( not $settings.ps_viewer.empty? )
+ return true if p.type == 'pdf' and ( not $settings.pdf_viewer.empty? )
+ end # case ARCH
+ return nil
+end # viewable
+
+####################################
+
+# Tk and custom widgets
+
+require 'tk'
+require 'tkscrollbox'
+
+# For event field strings, which codify event details, see
+# the bind man page from the tk man pages (Ubuntu: tk8.x-doc package)
+
+####################################
+
+# combobox adapted from Takaaki Tateishi <ttate / jaist.ac.jp>
+# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/18167
+
+# literal content of an xbm file, created e.g. with the GIMP
+
+$DOWN_ARROW_IMG = <<STR
+#define dwnarrow.icn_width 15
+#define dwnarrow.icn_height 10
+static unsigned char dwnarrow.icn_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03,
+ 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00 };
+STR
+
+class TkACombobox < TkFrame
+
+ include TkComposite
+
+ attr_reader :scrollbox, :tframe
+ attr_accessor :entries, :is_valid
+
+ def initialize_composite( params = {} )
+
+ @entries = []
+ @is_valid = proc{ |s| true }
+ @entry = nil
+
+ # entry widget plus arrow for drop-down listbox
+
+ @entry = TkEntry.new( @frame,
+ 'width' => 30, 'bd' => 1, 'highlightthickness' => 0 )
+ image = TkBitmapImage.new( 'data' => $DOWN_ARROW_IMG )
+ @bt_arrow = TkButton.new( @frame, 'bd' => 1, 'image' => image,
+ 'highlightthickness' => 0, 'command' => proc{ cmd_scrollbox } )
+ @entry.pack( 'side' => 'left', 'fill' => 'x', 'expand' => 'yes' )
+ @bt_arrow.pack( 'side' => 'right' )
+
+ # drop-down listbox
+
+ @tframe = TkToplevel.new( @frame )
+ @tframe.overrideredirect( 1 ) # no window manager decorations
+ @tframe.transient
+ @tframe.withdraw
+ @scrollbox = TkScrollbox.new( @tframe, 'width' => 30, 'border' => 1 )
+ @scrollbox.pack( 'fill' => 'both', 'expand' => 'yes' )
+ @scrollbox.bind( 'Any-Leave', proc{ hide_scrollbox } )
+ # "%y", "%P": event field string; see bind manual from tk8.x-docs
+ @scrollbox.bind( 'Double-1', proc{ |y| select_this( y ) }, "%y" )
+ @scrollbox.bind( 'Return', proc{ |y| select_this( y ) }, "%y" )
+
+ @entry.bind( 'FocusOut', proc{ entry_proc } )
+ @entry.bind( 'Return', proc{ entry_proc } )
+ @entry.bind( 'Double-1', proc{ entry_proc } )
+
+ delegate( :width, @entry, @scrollbox )
+
+ configure params if params
+
+ end # initialize_composite
+
+ def cmd_scrollbox
+ case @tframe.state
+ when "withdrawn"
+ show_scrollbox( @entries )
+ else
+ hide_scrollbox
+ end
+ end
+
+ def show_scrollbox( entries = nil )
+ width = TkWinfo.width( @frame )
+ height = 5 * TkWinfo.height( @entry )
+ rootx = TkWinfo.rootx( @frame )
+ rooty = TkWinfo.rooty( @frame ).to_i + TkWinfo.height( @frame ).to_i
+ geometry = "#{width}x#{height}+#{rootx}+#{rooty}"
+ @tframe.geometry( geometry )
+ @tframe.deiconify
+ entries.each{ |entry| @scrollbox.insert( "end", entry ) } if entries
+ end
+
+ def hide_scrollbox
+ @tframe.withdraw
+ @scrollbox.delete( 0, "end" )
+ @entry.focus
+ end
+
+ def select_this( y )
+ i = @scrollbox.nearest( y )
+ s = @scrollbox.get( i )
+ @entry.delete( 0, 'end' )
+ @entry.insert( 0, s )
+ @is_valid.call( s ) # activates side effects
+ hide_scrollbox
+ end
+
+ def entry_proc
+ #puts @entry.value
+ if @is_valid.call( @entry.value )
+ @entries.unshift( @entry.value ).sort! \
+ unless @entries.index( @entry.value )
+ @tframe.withdraw unless @tframe.state == 'withdrawn'
+ else
+ Tk.bell
+ @entry.focus( true )
+ end
+ end
+
+ def get_entry
+ @entry.value
+ end
+
+ def set_entry( s )
+ @entry.delete( 0, 'end' )
+ @entry.insert( 'end', s ) if s
+ end
+
+end # TkACombobox
+
+####################################
+
+# checkboxes and radioboxes with built-in variables.
+# use string- rather than symbol keys when creating these widgets.
+
+def zero_one( v ) # For Tcl/Tk, everything is a string
+ case v
+ when /t(rue)?|y(es)?|1/i
+ '1'
+ when /f(alse)?|n(o)?|0/i
+ '0'
+ when 1
+ '1'
+ when 0
+ '0'
+ else
+ nil
+ end
+end
+
+class TkACheck < TkFrame
+
+ include TkComposite
+
+ def initialize_composite( params = {} )
+
+ Kernel::fail StandardError, "TkACheck doesn\'t allow \'variable\' key" \
+ if params.has_key?( 'variable' )
+
+ v = params.delete( 'value' )
+ @value = TkVariable.new( zero_one( v ) )
+
+ @ck = TkCheckButton.new( @frame, :variable => @value \
+ ).pack( :padx => 0, :pady => 0, :ipadx => 0, :ipady => 0 )
+
+ delegate( 'DEFAULT', @ck )
+
+ configure params unless params.empty?
+
+ end # initialize_composite
+
+ def value
+ @value.value
+ end
+
+ def value=( v )
+ @value.value = zero_one( v )
+ end
+
+end # TkACheck
+
+class TkRadios < TkFrame
+
+ include TkComposite
+
+ def initialize_composite( params = {} )
+
+ Kernel::fail StandardError, "TkRadios doesn\'t allow \'variable\' key" \
+ if params.has_key?( 'variable' )
+
+ @value = TkVariable.new( params.delete( 'value' ) )
+ @values = params.delete( 'values' )
+ @packing = params.delete( 'packing' )
+ @buttons = []
+
+ if ( @values.kind_of? Hash )
+ @values.each_key { |k|
+ @buttons << TkRadioButton.new( @frame,
+ :text => @values[k] || k,
+ :variable => @value,
+ :value => k
+ ).pack( @packing )
+ }
+ elsif ( @values.kind_of? Array )
+ @values.each { |k|
+ @buttons << TkRadioButton.new( @frame,
+ :text => k,
+ :variable => @value,
+ :value => k
+ ).pack( @packing )
+ }
+ else
+ Kernel::fail StandardError, "TkRadios requires a values array or hash"
+ end
+
+ delegate( 'DEFAULT', @frame )
+ delegate( 'command', *@buttons )
+ delegate( 'state', *@buttons )
+
+ configure( params ) unless params.empty?
+
+ end # initialize_composite
+
+ def value
+ @value.value
+ end
+
+ def value=( v )
+ @value.value = v
+ end
+
+ def get_button_state( v )
+ @buttons.each { |b|
+ if b.value == v
+ return b.cget( 'state' )
+ end
+ }
+ return nil
+ end
+
+ def set_button_state( v, s )
+ @buttons.each { |b|
+ if b.value == v
+ b.configure( 'state' => s )
+ @value.value = nil if s == 'disabled' and @value.value == v
+ end
+ }
+ end
+
+end # TkRadios
+
+$root = TkRoot.new { title "PostScript- and pdf conversions" }
+
+##################################
+
+# Initial tests: no gs => bail out; no viewers => warning
+
+if not $settings.gs_prog
+ Tk.messageBox(
+ :icon=>'error',
+ :type=>'ok',
+ :parent=>$root,
+ :message=>"No Ghostscript found; aborting..."
+ )
+ abort
+end
+
+if not $settings.pdf_viewer
+ Tk.messageBox( :icon=>'warning', :type=>'ok', :message =>
+ "No PostScript- or pdf viewer found" )
+elsif not $settings.ps_viewer
+ Tk.messageBox( :icon=>'warning', :type=>'ok', :message =>
+ "No PostScript viewer found" )
+end
+
+########################################
+
+$defaultDir = ENV['PWD']
+
+$defaultDir = ARGV[0] if ((ARGV.length > 0) and File.directory?(ARGV[0]))
+
+$source = PsPdf.new # currently loaded PsPdf object
+
+$tl_config = nil # configuration screen
+$tl_wait = nil # instead of a wait cursor or progress bar
+
+# widgets which are configured on the fly,
+# e.g. by ep_config, get a global name.
+# They don't really have to be declared early.
+
+# buttons and option widgets
+$view_button = nil
+$page_radio = nil
+$page_entry = nil
+$type_radio = nil
+$bbox_check = nil
+
+# widgets which display file info
+$source_dir_label = nil
+$source_name_label = nil
+$source_type_label = nil
+
+def set_widget_states
+ # states (normal/disabled) for various widgets.
+ # their values should already be mutually consistent.
+ # widgets concerned:
+ # view / save
+ # output format / bbox / single page / page no.
+
+ $view_button.configure( :state =>
+ ( viewable( $source ) ? 'normal' : 'disabled' ) )
+ $save_button.configure( :state =>
+ ( ( $source.type and $source.type != 'other' ) ? \
+ 'normal' : 'disabled' ) )
+
+ $type_radio.set_button_state( 'ps', ( \
+ ( $settings.pdftops_prog and $settings.use_pdftops and
+ ( $source.type =~ /ps|pdf/ ) ) ? \
+ 'normal' : 'disabled' ) )
+
+ $page_radio.set_button_state( 'all', 'normal' )
+ $page_radio.set_button_state( 'single', 'normal' )
+ $page_radio.set_button_state( 'all', 'disabled' ) if \
+ $type_radio.value == 'eps'
+ $page_radio.set_button_state( 'single', 'disabled' ) if \
+ $type_radio.value == 'ps'
+
+ $page_entry.configure( :state => \
+ ( $page_radio.value == 'all' ? 'disabled' : 'normal' ) )
+
+ $bbox_check.configure( :state => \
+ ( $page_radio.value == 'single' or $source.type =~ /eps/ ) \
+ ? 'normal' : 'disabled' )
+
+end # set_widget_states
+
+def load_file( path )
+ $source = PsPdf.new( 'file' => path )
+ # write info to labels
+ $source_dir_label.configure( :text => File.dirname( path ) )
+ $source_name_label.configure( :text => File.basename( path ) )
+ $source_type_label.configure( :text => $source.type )
+ $source.pdf_pages if ( $source.type == 'pdf' )
+ $source_npages_label.configure( :text => (
+ case $source.type
+ when 'pdf' then ( $source.npages ).to_s
+ when 'eps' then '1'
+ else ''
+ end
+ ) )
+ $page_entry.delete( 0, 'end' )
+ $page_entry.insert( 'end', '1' )
+ set_widget_states
+end
+
+# ipadx and ipady seem ineffective for frames
+
+FRM_PACK = {
+ :side => 'top',
+ :fill => 'x',
+ :expand => 1,
+ :padx => 4,
+ :pady => 4,
+ :anchor => 'w'
+}
+
+##################################
+
+# configuration screen (toplevel widget)
+
+$tl_config = nil
+
+def ep_config
+
+ if not $tl_config
+
+ $tl_config = TkToplevel.new( $root, :title => 'Configure epspdf' )
+
+ ### viewers frame
+
+ if ARCH == 'unix'
+ TkFrame.new( $tl_config ) { |frm|
+ frm.borderwidth 2
+ frm.relief 'groove'
+ TkLabel.new( frm, :text => 'VIEWERS'
+ ).pack( :side => 'top', :padx => 4, :anchor => 'w' )
+ TkFrame.new( frm ) { |fm|
+ TkLabel.new( fm, :text => 'Pdf viewer' ).grid(
+ :in => fm, :row => 0, :column => 0,
+ :sticky => 'w', :padx => 2 )
+ $pdf_vw_combo = TkACombobox.new( fm, :width => 30 )
+ $pdf_vw_combo.is_valid = lambda { |s| is_a_program( s ) }
+ $pdf_vw_combo.grid( :in => fm, :row => 0, :column => 1,
+ :pady => 2, :padx => 2, :sticky => 'e' )
+
+ TkLabel.new( fm, :text => 'PostScript viewer' ).grid(
+ :in => fm, :row => 1, :column => 0,
+ :sticky => 'w', :padx => 2 )
+ $ps_vw_combo = TkACombobox.new( fm, :width => 30 )
+ $ps_vw_combo.is_valid = lambda { |s| is_a_program( s ) }
+ $ps_vw_combo.grid( :in => fm, :row => 1, :column => 1,
+ :pady => 2, :padx => 2, :sticky => 'e' )
+ }.pack( :side => 'top', :anchor => 'w', :fill => 'x' )
+ }.pack( FRM_PACK )
+ end # if unix
+
+ ### postscript frame
+
+ TkFrame.new( $tl_config ){ |frm|
+ frm.borderwidth 2
+ frm.relief 'groove'
+ TkLabel.new( frm, :text => 'POSTSCRIPT CONVERSION'
+ ).pack( :side => 'top', :padx => 4, :anchor => 'w' )
+
+ if ARCH == 'w32' # others: assume pdftops on search path
+ TkLabel.new( frm, :text => "Find pdftops"
+ ).pack( :side => 'top', :anchor => 'w', :padx => 4 )
+
+ TkFrame.new( frm ) { |fm|
+ $pdftops_entry = TkEntry.new( fm, :width => 20
+ ).pack( 'side'=>'left', :padx => 4 )
+ TkButton.new( fm,
+ :text => 'Browse ...',
+ :command => lambda {
+ tryprog = Tk.getOpenFile(
+ :filetypes => [ [ 'Programs', [ '.exe' ] ] ],
+ :parent => fm
+ )
+ if tryprog and ( not tryprog.empty? )
+ if not xpdf_version( tryprog )
+ Tk.messageBox(
+ :icon => 'warning',
+ :type => 'ok',
+ :parent => fm,
+ :message => "pdftops missing or dysfunctional"
+ )
+ else
+ $pdftops_entry.delete( 0, 'end' )
+ $pdftops_entry.insert( 'end', tryprog )
+ end # ifthenelse xpdf_version
+ end # ifthenelse tryprog
+ } # command lambda
+ ).pack( :side => 'left' ) # TkButton
+ }.pack( :side => 'top', :pady => 4, :anchor => 'w' )
+ end # ARCH == 'w32'
+
+ $pdftops_check = TkACheck.new( frm,
+ 'text' => "Use pdftops if available"
+ ).pack( :side => 'top', :pady => 4, :anchor => 'w' )
+
+ }.pack( FRM_PACK ) # TkFrame |frm|
+
+ ### pdf frame
+
+ TkFrame.new( $tl_config ){ |frm|
+ frm.borderwidth 2
+ frm.relief 'groove'
+ TkLabel.new( frm, :text => 'PDF CONVERSION'
+ ).pack( :side => 'top', :padx => 4, :anchor => 'w' )
+
+ # internal packing
+ pack_pdf = {
+ :side => 'left', :padx => 2, :pady => 4, :anchor => 'w' }
+
+ TkLabel.new( frm, :text => 'Intended use'
+ ).pack( :side => 'top', :padx => 2, :pady => 0, :anchor => 'w' )
+ $pdf_target_radio = TkRadios.new( frm,
+ 'values' => PDF_TARGETS, 'packing' => pack_pdf
+ ).pack( :side => 'top', :anchor => 'w' )
+
+ # dummy widget for extra vertical space
+ TkLabel.new( frm, :text => ' ' ).pack
+
+ TkLabel.new( frm, :text => 'Pdf version'
+ ).pack( :side => 'top', :padx => 2, :pady => 0, :anchor => 'w' )
+
+ $pdf_version_radio = TkRadios.new( frm,
+ 'values' => PDF_VERSIONS, 'packing' => pack_pdf
+ ).pack( :side => 'top', :anchor => 'w' )
+
+ TkLabel.new( frm, :text => ' ' ).pack
+
+ TkLabel.new( frm, :text => 'Custom Ghostscript/ps2pdf parameters'
+ ).pack( :side => 'top', :padx => 2, :pady => 0, :anchor => 'w' )
+
+ $pdf_custom_entry = TkEntry.new( frm, :width => 50
+ ).pack( :side => 'top', :padx => 2, :pady => 2, :anchor => 'w' )
+
+ }.pack( FRM_PACK )
+
+ ### button frame
+
+ TkFrame.new( $tl_config ) { |frm|
+
+ TkButton.new( frm,
+ :text => 'Cancel',
+ :command => lambda {
+ $tl_config.withdraw
+ $root.focus
+ }
+ ).pack( :padx => 4, :side => 'left', :anchor => 'e' )
+
+ TkButton.new( frm,
+ :text => 'Done',
+ :command => lambda {
+ # copy settings from widgets to $settings
+ case ARCH
+ when 'unix' # viewers
+ $settings.accept_ps_viewer( $ps_vw_combo.get_entry )
+ $settings.accept_pdf_viewer( $pdf_vw_combo.get_entry )
+ when 'w32'
+ $settings.pdftops_prog = $pdftops_entry.get
+ end
+ $settings.use_pdftops = ( not $pdftops_check.value == '0' )
+ $settings.pdf_target = $pdf_target_radio.value
+ $settings.pdf_version = $pdf_version_radio.value
+ $settings.pdf_custom = $pdf_custom_entry.get
+ $settings.write_settings
+ $tl_config.withdraw
+ $root.focus
+ set_widget_states
+ } # lambda
+ ).pack( :side => 'left', :anchor => 'e' )
+
+ }.pack( :side => 'bottom', :padx => 4, :pady => 4, :anchor => 'e' )
+ else
+ $tl_config.deiconify
+ end # ifthenelse $tl_config
+
+ # copy data from $settings to widgets
+ if ARCH == 'unix'
+ $pdf_vw_combo.set_entry( $settings.pdf_viewer )
+ $pdf_vw_combo.entries = $settings.pdf_viewers[0..-1] # deep copy
+ $ps_vw_combo.set_entry( $settings.ps_viewer )
+ $ps_vw_combo.entries = $settings.ps_viewers[0..-1]
+ elsif ARCH == 'w32'
+ $pdftops_entry.delete( 0, 'end' )
+ $pdftops_entry.insert( 'end', $settings.pdftops_prog ) \
+ if $settings.pdftops_prog and not $settings.pdftops_prog.empty?
+ end # ifthenelse ARCH
+ $pdftops_check.value = $settings.use_pdftops ? '1' : '0'
+ $pdf_target_radio.value = $settings.pdf_target
+ $pdf_version_radio.value = $settings.pdf_version
+ $pdf_custom_entry.delete( 0, 'end' )
+ $pdf_custom_entry.insert( 'end', $settings.pdf_custom ) \
+ if not $settings.pdf_custom.empty?
+
+end # def ep_config
+
+###################################
+
+### makeshift help
+
+$tl_help = nil
+
+def ep_help
+ if not $tl_help
+ $tl_help = TkToplevel.new( $root, :title => 'Epspdftk help' )
+ TkFrame.new( $tl_help ) { |tf|
+ txt = TkText.new( tf,
+ 'width' => 80,
+ 'height' => 25
+ ) { |t|
+ TkScrollbar.new( tf,
+ 'command' => lambda{ |*args| t.yview( *args ) } ) { |sc|
+ t.yscrollcommand( lambda{ |first, last| sc.set first, last } )
+ }.pack( 'side' => 'right', 'fill' => 'y' )
+ }.pack( 'expand' => 'yes', 'fill' => 'both' )
+
+ txt.delete( '1.0', 'end' )
+
+ # LF ok for Win32 and Mac? Otherwise, split and join with $/
+
+ File.open( File.dirname( __FILE__ ) + '/epspdf.help', 'r' ) { |f|
+ $s = f.read
+ }
+
+ txt.insert( '1.0', $s )
+
+ }.pack( 'side' => 'top', 'fill' => 'x' )
+
+ TkButton.new( $tl_help,
+ :text => 'Cancel',
+ :command => lambda{
+ $tl_help.withdraw
+ $root.focus
+ }
+ ).pack( 'anchor' => 'e', 'padx' => 4, 'pady' => 4 )
+ else
+ $tl_help.deiconify
+ end # ifthenelse $tl_help
+
+end # def ep_help
+
+### some buttons
+
+TkFrame.new( $root ) { |frm|
+
+ TkButton.new( frm,
+ :text => "Configure",
+ :command => lambda { ep_config }
+ ).pack( :side => 'left', :padx => 4, :pady => 4 )
+
+ TkButton.new( frm,
+ :text => 'Help',
+ :command => lambda { ep_help }
+ ).pack( :side => 'right', :padx => 4, :pady => 4)
+
+}.pack( :side => 'top', :fill => 'x' ) # frm
+
+########################################
+
+### status info
+
+TkFrame.new( $root ){ |frm|
+ frm.borderwidth 2
+ frm.relief 'groove'
+
+ ### status info
+
+ TkFrame.new( frm ) { |fm|
+ TkLabel.new( fm,
+ :justify => 'left',
+ :text => 'Directory'
+ ).grid( :in => fm, :sticky => 'w', :row => 0, :column => 0 )
+ $source_dir_label = TkLabel.new( fm,
+ :justify => 'left'
+ ).grid( :in => fm, :sticky => 'w', :row => 0, :column => 1 )
+
+ TkLabel.new( fm,
+ :justify => 'left',
+ :text => 'File'
+ ).grid( :in => fm, :sticky => 'w', :row => 1, :column => 0 )
+ $source_name_label = TkLabel.new( frm,
+ :justify => 'left'
+ ).grid( :in => fm, :sticky => 'w', :row => 1, :column => 1 )
+
+ TkLabel.new( fm,
+ :justify => 'left',
+ :text => 'Type'
+ ).grid( :in => fm, :sticky => 'w', :row => 2, :column => 0 )
+ $source_type_label = TkLabel.new( fm,
+ :justify => 'left'
+ ).grid( :in => fm, :sticky => 'w', :row => 2, :column => 1 )
+
+ TkLabel.new( fm,
+ :justify => 'left',
+ :text => 'Pages'
+ ).grid( :in => fm, :sticky => 'w', :row => 3, :column => 0 )
+ $source_npages_label = TkLabel.new( fm,
+ :justify => 'left'
+ ).grid( :in => fm, :sticky => 'w', :row => 3, :column => 1 )
+
+ TkGrid.columnconfigure( fm, 0, :weight => 1, :minsize => 60, :pad =>4 )
+ TkGrid.columnconfigure( fm, 1, :weight => 3, :minsize => 60, :pad =>4 )
+ }.pack( :side => 'top', :anchor => 'w', :padx => 4 )
+
+}.pack( FRM_PACK )
+
+########################################
+
+### conversion options: see also $options, defined in epspdf.rb
+
+TkFrame.new( $root ) { |frm|
+
+ TkFrame.new( frm ) { |fm| # grayscaling, output format
+ TkFrame.new( fm ) { |f| # grayscaling
+ TkLabel.new( f, 'text' => 'Grayscaling'
+ ).pack( :side => 'top', :anchor => 'w' )
+
+ gray_options = {
+ 'gRAY' => 'Try harder to grayscale',
+ 'gray' => 'Try to grayscale',
+ 'color' => 'No color conversion'
+ }
+
+ $gray_radio = TkRadios.new( f,
+ 'values' => gray_options,
+ 'value' => 'color',
+ 'packing' => { 'side' => 'top', 'anchor' => 'w' }
+ ).pack( :side => 'bottom', :anchor => 'w' ) # $gray_radio
+ }.pack( :side => 'left', :padx => 4 ) # f: grayscaling
+
+ TkFrame.new( fm ) { |f| # output format
+ TkLabel.new( f, 'text' => 'Output format'
+ ).pack( :side => 'top', :anchor => 'w' )
+
+ $type_radio = TkRadios.new( f,
+ 'values' => [ 'pdf', 'eps', 'ps' ],
+ 'value' => 'pdf',
+ 'command' => lambda {
+ case 'value'
+ when 'eps'
+ $page_radio.value = 'single'
+ when 'ps'
+ $page_radio.value = 'all'
+ $bbox_check.value = '0'
+ end
+ set_widget_states
+ },
+ 'packing' => { 'side' => 'top', 'anchor' => 'w' }
+ ).pack( :side => 'bottom', :anchor => 'w' )
+ }.pack( :side => 'right', :padx => 4 ) # f: output format
+ }.pack( :side => 'top', :anchor => 'n', :fill => 'x' )
+
+ # dummy widget for extra vertical space
+ TkLabel.new( frm, :text => ' ' ).pack
+
+ $bbox_check = TkACheck.new( frm,
+ 'text' => 'Compute tight boundingbox',
+ 'value' => '0',
+ 'command' => lambda {
+ $page_radio.value = 'single' if 'value' == '1'
+ set_widget_states
+ }
+ ).pack( :side => 'top', :padx => 4, :anchor => 'w' )
+
+ TkLabel.new( frm, :text => ' ' ).pack
+
+ TkFrame.new( frm ) { |fm|
+ page_options = { 'all' => 'Convert all pages', 'single' => 'Page:' }
+ $page_radio = TkRadios.new( fm,
+ 'values' => page_options,
+ 'packing' => { 'side' => 'left', 'padx' => 4 },
+ 'value' => 'single',
+ 'command' => lambda {
+ $bbox_check.value = '0' if 'value' == 'all'
+ set_widget_states
+ }
+ ).pack( 'side' => 'left', :anchor => 'nw' )
+
+ $page_entry = TkEntry.new( fm,
+ :validate => 'focus',
+ :vcmd => [ lambda { |s|
+ ( s =~ /\d+/ ) and
+ ( s.to_i >= 1 ) and
+ ( $source.type != 'pdf' or s.to_i <= $source.npages )
+ }, "%P" ],
+ :invcmd => lambda { Tk.bell; $page_entry.focus },
+ :width => 5
+ ).pack( :side => 'left' )
+ $page_entry.delete( 0, 'end' )
+ $page_entry.insert( 'end', '1' )
+ }.pack( 'side' => 'left', :anchor => 'nw' )
+}.pack( FRM_PACK )
+
+########################################
+
+### view | open | save | done buttons
+
+TkFrame.new( $root ) { |frm|
+
+ $view_button = TkButton.new( frm,
+ :text => 'View',
+ :state => 'disabled',
+ :command => lambda {
+ # start a viewer
+ if ARCH == 'w32'
+ shell = Win32API.new("shell32", "ShellExecute",
+ ['l','p','p','p','p','l'], 'l')
+ shell.Call(0, 'open', $source.path, 0, 0, 1)
+ # shell.Call(0, 'open', $source.path, 0, 0, SW_SHOWNORMAL)
+ elsif ARCH == 'osx'
+ fork { exec "open -a Preview \"#{$source.path}\"" }
+ elsif viewable( $source )
+ viewer =
+ $source.type == 'pdf' ? $settings.pdf_viewer : $settings.ps_viewer
+ fork { exec "\"#{viewer}\" \"#{$source.path}\"" }
+ end
+ }
+ ).pack( :side=>'left', :anchor => 'w', :padx=>4, :pady=>4 )
+
+ TkFrame.new( frm ) { |fm|
+ TkButton.new( fm,
+ :text => 'Open..',
+ :command => lambda {
+ path = Tk.getOpenFile(
+ :initialdir => $defaultDir,
+ :filetypes => [
+ ['All files', '*'],
+ ['EPS', ['.eps']],
+ ['PDF', ['.pdf']],
+ ['PostScript', ['.ps']]
+ ],
+ :parent => $root
+ )
+ if path and ( not path.empty? )
+ load_file( path )
+ $defaultDir = File.expand_path( File.dirname( path ) )
+ end
+ }
+ ).pack( :side=>'left', :padx=>4, :pady=>4 )
+
+ $save_button = TkButton.new( fm,
+ :text => "Convert and save..",
+ :command => lambda {
+ $options.type = $type_radio.value
+ $options.page = \
+ ( ( $page_radio.value == 'single' ) ? $page_entry.value : nil )
+ $options.gray = ($gray_radio.value and $gray_radio.value != 'color' )
+ $options.gRAY = ($gray_radio.value and $gray_radio.value == 'gRAY' )
+ $options.bbox = ( ( $bbox_check.value == '1' ) \
+ and ( $page_radio.value == 'single' ) )
+ filetypes = case $options.type
+ when 'pdf' then [ ['Pdf', ['.pdf'] ] ]
+ when 'ps' then [ ['PostScript', ['.ps'] ] ]
+ when 'eps' then [ ['EPS (Encapsulated PostScript', ['.eps'] ] ]
+ end
+ path = nil
+ path = Tk.getSaveFile(
+ :filetypes => filetypes,
+ :parent => $root,
+ :initialdir => File.dirname( $source.path ),
+ :initialfile => File.basename( $source.path, ".*" ) +
+ '.' + $options.type,
+ :defaultextension => '.' + $options.type
+ )
+ return unless path && ! path.empty?
+ $defaultDir = File.expand_path( File.dirname( path ) )
+
+ # waitbox
+ if not $tl_wait
+ $tl_wait = TkToplevel.new( $root,
+ 'title' => 'Converting...',
+ 'geometry' =>
+ '+' + ( TkWinfo.rootx( $root ).to_i + 100 ).to_s +
+ '+' + ( TkWinfo.rooty( $root ).to_i + 100 ).to_s,
+ 'borderwidth' => 2,
+ 'relief' => 'solid'
+ )
+ $cnv_label = TkLabel.new( $tl_wait,
+ 'text' => 'converting...'
+ ).pack( 'side' => 'top' )
+ $tl_wait.overrideredirect( 1 )
+ end
+ $cnv_label.configure(
+ 'text' => "Converting #{$source.path} to \n #{path} ..."
+ )
+ $tl_wait.update
+ $tl_wait.deiconify
+ $tl_wait.raise
+ begin
+ result = $source.any_to_any( $options )
+ rescue EPCallError => exc
+ mess = "Wrong method call or conversion not supported" +
+ " or wrong page number"
+ write_log( mess + $/ +
+ exc.message + $/ + exc.backtrace.join( $/ ) )
+ Tk.messageBox(
+ 'icon' => 'error',
+ 'type' => 'ok',
+ 'parent' => $root,
+ 'message' => "#{mess}\nSee #{LOGFILE} for details."
+ )
+ rescue EPBBError => exc
+ mess = "Boundingbox problem" + $/ +
+ exc.message
+ write_log( mess + $/ + exc.backtrace.join( $/ ) )
+ Tk.messageBox(
+ 'icon' => 'error',
+ 'type' => 'ok',
+ 'parent' => $root,
+ 'message' => "#{mess}\nSee #{LOGFILE} for details."
+ )
+ rescue EPSystemError => exc
+ mess = "Problem with system call" + $/ +
+ exc.message
+ write_log( mess + $/ + exc.backtrace.join( $/ ) )
+ Tk.messageBox(
+ 'icon' => 'error',
+ 'type' => 'ok',
+ 'parent' => $root,
+ 'message' => "#{mess}\nSee #{LOGFILE} for details."
+ )
+ ensure
+ $tl_wait.withdraw
+ end
+ if result
+ ccp( result.path, path )
+ load_file( path )
+ Tk.messageBox(
+ 'icon' => 'info',
+ 'type' => 'ok',
+ 'parent' => $root,
+ 'message' => "Conversion completed"
+ )
+ end
+ }
+ ).pack( :side=>'left', :padx=>0, :pady=>4 )
+
+ TkButton.new( fm,
+ :text => "Done",
+ :command => lambda { $root.destroy }
+ ).pack( :side => 'left', :padx => 4, :pady => 4 )
+ }.pack( :side => 'right', :anchor => 'e' )
+}.pack( :side => 'bottom', :fill => 'x' )
+
+set_widget_states
+
+$root.raise
+
+Tk.mainloop
+cleantemp