bconv 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +7 -0
  2. data/bin/bconv +194 -0
  3. data/data/bconv.glade +215 -0
  4. data/lib/bconv.rb +116 -0
  5. metadata +63 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0a2ee9a53ba762929e67f01c9250b8f5d41ff9ea
4
+ data.tar.gz: 848942f749535612beb4c00a0c21f800b40e0881
5
+ SHA512:
6
+ metadata.gz: cd24ae77b608b5466535fadf0e39be5ca0fc89bb151bede6e8bfb749ae85c2ae2db8f68f1b629bfd064882bfa092351fba7b8adb2026fc99938626dd6358987b
7
+ data.tar.gz: 9f64cc426f59bd05940d5ac5ea1340e0e782b8b5158d2249bf59dab4c229f5377b341512770d3807d5b1c5c7444b3d191d507c2b152b1772af1f818cd12d0a16
data/bin/bconv ADDED
@@ -0,0 +1,194 @@
1
+ #!/usr/bin/env ruby19
2
+ # encoding: UTF-8
3
+
4
+ #############################################################################
5
+ # Yet Another ImageMagic Frontend #
6
+ # (C) 2010-2011, Vasiliy Yeremeyev <vayerx@gmail.com> #
7
+ # #
8
+ # This program is free software: you can redistribute it and/or modify #
9
+ # it under the terms of the GNU General Public License as published by #
10
+ # the Free Software Foundation, either version 3 of the License, or #
11
+ # (at your option) any later version. #
12
+ # #
13
+ # This program is distributed in the hope that it will be useful, #
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of #
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
16
+ # GNU General Public License for more details. #
17
+ # #
18
+ # You should have received a copy of the GNU General Public License #
19
+ # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20
+ #############################################################################
21
+
22
+ # TODO humanist config interface (parseconfig -> /dev/null)
23
+ # TODO thinking of 'libglade2 -> raw gtk2'
24
+ # TODO humanist errors notification
25
+
26
+
27
+ require 'bconv'
28
+ require 'parseconfig'
29
+ require 'libglade2'
30
+
31
+ class ConverterGUI
32
+ MIN_RATIO = 65
33
+ MAX_RATIO = 100
34
+
35
+ def initialize(file_or_data)
36
+ @semaphore = Mutex.new
37
+ @counting_thread = nil
38
+ @source_files = []
39
+
40
+ @config_file = RUBY_PLATFORM =~ /linux|bsd|darwin|cygwin/i ? File.expand_path('~/.bconv.conf') : 'bconv.ini'
41
+ @config = ParseConfig.new(@config_file) rescue nil
42
+
43
+ @converter = Converter.new
44
+ @builder = Gtk::Builder.new
45
+ @builder << file_or_data
46
+ @builder.connect_signals { |name| method(name) }
47
+
48
+ %w[src_edit dest_edit size_edit ratio_scale run_button src_button dest_button
49
+ textview progress_bar status_bar main_window].each do |control|
50
+ instance_variable_set('@' + control, @builder[ control ])
51
+ end
52
+
53
+ @src_edit.text = @config['source'] rescue ''
54
+ @dest_edit.text = @config['destination'] rescue ''
55
+ @size_edit.text = @config['size'] rescue '1600x1200'
56
+
57
+ @ratio_scale.set_range(MIN_RATIO, MAX_RATIO)
58
+ ratio = @config['ratio'].to_i rescue 95
59
+ @ratio_scale.value = (ratio < MIN_RATIO ? MIN_RATIO : (ratio > MAX_RATIO ? MAX_RATIO : ratio))
60
+
61
+ @main_window.show
62
+
63
+ preload_dir(@src_edit.text) unless @src_edit.text.empty?
64
+ end
65
+
66
+ def run
67
+ Gtk.main
68
+ end
69
+
70
+ def on_src_button_clicked
71
+ dialog = Gtk::FileChooserDialog.new("Выбери исходную папку",
72
+ @main_window,
73
+ Gtk::FileChooser::ACTION_SELECT_FOLDER,
74
+ nil,
75
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
76
+ [Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_ACCEPT])
77
+
78
+ dialog.current_folder = @src_edit.text
79
+ if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
80
+ preload_dir(@src_edit.text = dialog.filename)
81
+ end
82
+ dialog.destroy
83
+ end
84
+
85
+ def preload_dir(dir)
86
+ @converter.preload_dir(dir) do |amount|
87
+ @status_bar.push(@status_bar.get_context_id(:init.to_s), "Найдено #{amount} файл(ов)") rescue nil
88
+ end
89
+ end
90
+
91
+ def on_dest_button_clicked
92
+ dialog = Gtk::FileChooserDialog.new("Выбери папку для результата",
93
+ @main_window,
94
+ Gtk::FileChooser::ACTION_SELECT_FOLDER,
95
+ nil,
96
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
97
+ [Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_ACCEPT])
98
+
99
+ dialog.current_folder = @dest_edit.text
100
+ if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
101
+ @dest_edit.text = dialog.filename
102
+ end
103
+ dialog.destroy
104
+ end
105
+
106
+ # Save configuration
107
+ def save_config
108
+ File.open(@config_file, 'w') do |f|
109
+ f << 'source=' << @src_edit.text << "\n"
110
+ f << 'destination=' << @dest_edit.text << "\n"
111
+ f << 'size=' << @size_edit.text << "\n"
112
+ f << 'ratio=' << @ratio_scale.value.to_i << "\n"
113
+ end
114
+ end
115
+
116
+ # Execute main job
117
+ def on_run_button_clicked
118
+ save_config
119
+
120
+ # check format of image size
121
+ img_size = @size_edit.text.gsub(/\s/, '')
122
+ begin
123
+ if img_size.index('%') || img_size.index('@')
124
+ raise img_size unless img_size.gsub!(/^(\d*)([%@])/, '\1\2')
125
+ else
126
+ raise img_size unless img_size.gsub!(/^(\d*)\w?(\d*)(\D?)$/, '\1x\2\3')
127
+ end
128
+ rescue
129
+ @textview.buffer.text = "Некорретный размер изображения '#{@size_edit.text}'"
130
+ return
131
+ end
132
+
133
+ ratio = @ratio_scale.value.to_i
134
+ if (ratio < 1 || ratio > 100)
135
+ @textview.buffer.text = "Недопустимый диапазон сжатия '#{ratio}'"
136
+ return
137
+ end
138
+
139
+ return unless check_directories(@src_edit.text, @dest_edit.text)
140
+
141
+ @textview.buffer.text = ""
142
+ @progress_bar.fraction = 0
143
+
144
+ lockUI
145
+ @converter.process(@src_edit.text, @dest_edit.text, img_size, ratio) { |file, step, done|
146
+ pulse_progress(file, step, done)
147
+ }
148
+ end
149
+
150
+ # Exit main loop
151
+ def on_main_window_destroy
152
+ @converter.stop
153
+ Gtk.main_quit
154
+ end
155
+
156
+ def lockUI
157
+ [ @run_button, @src_button, @dest_button ].each { |button| button.hide }
158
+ @progress_bar.show
159
+ end
160
+
161
+ def unlockUI
162
+ [ @run_button, @src_button, @dest_button ].each { |button| button.show }
163
+ @progress_bar.hide
164
+ end
165
+
166
+ # Check source/destination directories
167
+ def check_directories(src_dir, dest_dir)
168
+ # check source
169
+ if !FileTest.directory?(src_dir)
170
+ @textview.buffer.text = "#{src_dir} должно быть директорией"
171
+ return false
172
+ end
173
+
174
+ # check destination
175
+ Dir.mkdir(dest_dir, 0775) unless FileTest.exists?(dest_dir)
176
+ if !FileTest.directory?(dest_dir)
177
+ @textview.buffer.text = "#{dest_dir} должно быть директорией"
178
+ return false
179
+ end
180
+ true
181
+ end
182
+
183
+ def pulse_progress(file, step, done)
184
+ @semaphore.synchronize do
185
+ @textview.buffer.text = file + "\n" + @textview.buffer.text if file
186
+ @progress_bar.fraction += step if step
187
+ unlockUI if done
188
+ end
189
+ end
190
+ end
191
+
192
+ Encoding.default_external = 'UTF-8'
193
+ gui = ConverterGUI.new(File.read(File.expand_path('data/bconv.glade', File.dirname(__FILE__)+'/..')))
194
+ gui.run
data/data/bconv.glade ADDED
@@ -0,0 +1,215 @@
1
+ <?xml version="1.0"?>
2
+ <interface>
3
+ <requires lib="gtk+" version="2.16"/>
4
+ <!-- interface-naming-policy project-wide -->
5
+ <object class="GtkWindow" id="main_window">
6
+ <property name="width_request">700</property>
7
+ <property name="title" translatable="yes">&#x41F;&#x430;&#x43A;&#x435;&#x442;&#x43D;&#x43E;&#x435; &#x441;&#x436;&#x430;&#x442;&#x438;&#x435;</property>
8
+ <property name="window_position">center</property>
9
+ <signal name="destroy" handler="on_main_window_destroy"/>
10
+ <child>
11
+ <object class="GtkTable" id="table1">
12
+ <property name="visible">True</property>
13
+ <property name="n_rows">7</property>
14
+ <property name="n_columns">3</property>
15
+ <property name="column_spacing">2</property>
16
+ <property name="row_spacing">2</property>
17
+ <child>
18
+ <object class="GtkEntry" id="dest_edit">
19
+ <property name="visible">True</property>
20
+ <property name="can_focus">True</property>
21
+ <property name="tooltip_text" translatable="yes">&#x41A;&#x430;&#x442;&#x430;&#x43B;&#x43E;&#x433;, &#x43A;&#x443;&#x434;&#x430; &#x437;&#x430;&#x43F;&#x438;&#x441;&#x44B;&#x432;&#x430;&#x442;&#x44C; &#x43F;&#x43E;&#x436;&#x430;&#x442;&#x44B;&#x435; &#x444;&#x43E;&#x442;&#x43E;&#x433;&#x440;&#x430;&#x444;&#x438;&#x438;</property>
22
+ <property name="invisible_char">&#x25CF;</property>
23
+ </object>
24
+ <packing>
25
+ <property name="left_attach">1</property>
26
+ <property name="right_attach">2</property>
27
+ <property name="top_attach">1</property>
28
+ <property name="bottom_attach">2</property>
29
+ <property name="y_options"></property>
30
+ </packing>
31
+ </child>
32
+ <child>
33
+ <object class="GtkLabel" id="label1">
34
+ <property name="visible">True</property>
35
+ <property name="xpad">3</property>
36
+ <property name="ypad">3</property>
37
+ <property name="label" translatable="yes">&#x418;&#x441;&#x445;&#x43E;&#x434;&#x43D;&#x44B;&#x439; &#x43A;&#x430;&#x442;&#x430;&#x43B;&#x43E;&#x433;</property>
38
+ <property name="justify">right</property>
39
+ <property name="single_line_mode">True</property>
40
+ </object>
41
+ <packing>
42
+ <property name="x_options">GTK_FILL</property>
43
+ <property name="y_options"></property>
44
+ </packing>
45
+ </child>
46
+ <child>
47
+ <object class="GtkLabel" id="label2">
48
+ <property name="visible">True</property>
49
+ <property name="xpad">3</property>
50
+ <property name="ypad">3</property>
51
+ <property name="label" translatable="yes">&#x420;&#x435;&#x437;&#x443;&#x43B;&#x44C;&#x442;&#x438;&#x440;&#x443;&#x44E;&#x449;&#x438;&#x439; &#x43A;&#x430;&#x442;&#x430;&#x43B;&#x43E;&#x433;</property>
52
+ <property name="justify">right</property>
53
+ <property name="single_line_mode">True</property>
54
+ </object>
55
+ <packing>
56
+ <property name="top_attach">1</property>
57
+ <property name="bottom_attach">2</property>
58
+ <property name="x_options">GTK_FILL</property>
59
+ <property name="y_options"></property>
60
+ </packing>
61
+ </child>
62
+ <child>
63
+ <object class="GtkButton" id="dest_button">
64
+ <property name="label" translatable="yes">&#x412;&#x44B;&#x431;&#x440;&#x430;&#x442;&#x44C;...</property>
65
+ <property name="visible">True</property>
66
+ <property name="can_focus">True</property>
67
+ <property name="receives_default">True</property>
68
+ <signal name="clicked" handler="on_dest_button_clicked"/>
69
+ </object>
70
+ <packing>
71
+ <property name="left_attach">2</property>
72
+ <property name="right_attach">3</property>
73
+ <property name="top_attach">1</property>
74
+ <property name="bottom_attach">2</property>
75
+ <property name="x_options"></property>
76
+ <property name="y_options"></property>
77
+ </packing>
78
+ </child>
79
+ <child>
80
+ <object class="GtkButton" id="src_button">
81
+ <property name="label" translatable="yes">&#x412;&#x44B;&#x431;&#x440;&#x430;&#x442;&#x44C;...</property>
82
+ <property name="visible">True</property>
83
+ <property name="can_focus">True</property>
84
+ <property name="receives_default">True</property>
85
+ <signal name="clicked" handler="on_src_button_clicked"/>
86
+ </object>
87
+ <packing>
88
+ <property name="left_attach">2</property>
89
+ <property name="right_attach">3</property>
90
+ <property name="x_options"></property>
91
+ <property name="y_options"></property>
92
+ </packing>
93
+ </child>
94
+ <child>
95
+ <object class="GtkButton" id="run_button">
96
+ <property name="label" translatable="yes">&#x424;&#x438;&#x433;&#x430;&#x447;&#x438;&#x442;&#x44C;!</property>
97
+ <property name="visible">True</property>
98
+ <property name="can_focus">True</property>
99
+ <property name="receives_default">True</property>
100
+ <signal name="clicked" handler="on_run_button_clicked"/>
101
+ </object>
102
+ <packing>
103
+ <property name="right_attach">3</property>
104
+ <property name="top_attach">4</property>
105
+ <property name="bottom_attach">5</property>
106
+ <property name="x_options"></property>
107
+ <property name="y_options"></property>
108
+ </packing>
109
+ </child>
110
+ <child>
111
+ <object class="GtkLabel" id="label3">
112
+ <property name="visible">True</property>
113
+ <property name="xpad">3</property>
114
+ <property name="ypad">3</property>
115
+ <property name="label" translatable="yes">&#x421;&#x436;&#x430;&#x442;&#x438;&#x435;</property>
116
+ <property name="justify">right</property>
117
+ <property name="single_line_mode">True</property>
118
+ </object>
119
+ <packing>
120
+ <property name="top_attach">2</property>
121
+ <property name="bottom_attach">3</property>
122
+ <property name="x_options">GTK_FILL</property>
123
+ <property name="y_options"></property>
124
+ </packing>
125
+ </child>
126
+ <child>
127
+ <object class="GtkHScale" id="ratio_scale">
128
+ <property name="visible">True</property>
129
+ <property name="can_focus">True</property>
130
+ <property name="fill_level">100</property>
131
+ <property name="digits">0</property>
132
+ </object>
133
+ <packing>
134
+ <property name="left_attach">2</property>
135
+ <property name="right_attach">3</property>
136
+ <property name="top_attach">2</property>
137
+ <property name="bottom_attach">3</property>
138
+ <property name="y_options"></property>
139
+ </packing>
140
+ </child>
141
+ <child>
142
+ <object class="GtkEntry" id="size_edit">
143
+ <property name="visible">True</property>
144
+ <property name="can_focus">True</property>
145
+ <property name="tooltip_text" translatable="yes">&#x41C;&#x430;&#x43A;&#x441;&#x438;&#x43C;&#x430;&#x43B;&#x44C;&#x43D;&#x44B;&#x439; &#x440;&#x430;&#x437;&#x43C;&#x435;&#x440; &#x444;&#x43E;&#x442;&#x43E;&#x433;&#x440;&#x430;&#x444;&#x438;&#x438;: &#x428;&#x418;&#x420;&#x418;&#x41D;&#x410; x &#x412;&#x42B;&#x421;&#x41E;&#x422;&#x410; &#x438;&#x43B;&#x438; &#x41F;&#x420;&#x41E;&#x426;&#x415;&#x41D;&#x422;%</property>
146
+ <property name="invisible_char">&#x25CF;</property>
147
+ </object>
148
+ <packing>
149
+ <property name="left_attach">1</property>
150
+ <property name="right_attach">2</property>
151
+ <property name="top_attach">2</property>
152
+ <property name="bottom_attach">3</property>
153
+ <property name="y_options"></property>
154
+ </packing>
155
+ </child>
156
+ <child>
157
+ <object class="GtkProgressBar" id="progress_bar"/>
158
+ <packing>
159
+ <property name="right_attach">3</property>
160
+ <property name="top_attach">5</property>
161
+ <property name="bottom_attach">6</property>
162
+ <property name="y_options"></property>
163
+ </packing>
164
+ </child>
165
+ <child>
166
+ <object class="GtkStatusbar" id="status_bar">
167
+ <property name="visible">True</property>
168
+ <property name="spacing">2</property>
169
+ </object>
170
+ <packing>
171
+ <property name="right_attach">3</property>
172
+ <property name="top_attach">6</property>
173
+ <property name="bottom_attach">7</property>
174
+ <property name="y_options"></property>
175
+ </packing>
176
+ </child>
177
+ <child>
178
+ <object class="GtkEntry" id="src_edit">
179
+ <property name="visible">True</property>
180
+ <property name="can_focus">True</property>
181
+ <property name="tooltip_text" translatable="yes">&#x41A;&#x430;&#x442;&#x430;&#x43B;&#x43E;&#x433; &#x441; &#x438;&#x441;&#x445;&#x43E;&#x434;&#x43D;&#x44B;&#x43C;&#x438; &#x444;&#x43E;&#x442;&#x43E;&#x433;&#x440;&#x430;&#x444;&#x438;&#x44F;&#x43C;&#x438;</property>
182
+ <property name="invisible_char">&#x25CF;</property>
183
+ </object>
184
+ <packing>
185
+ <property name="left_attach">1</property>
186
+ <property name="right_attach">2</property>
187
+ <property name="y_options"></property>
188
+ </packing>
189
+ </child>
190
+ <child>
191
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
192
+ <property name="visible">True</property>
193
+ <property name="can_focus">True</property>
194
+ <property name="hscrollbar_policy">automatic</property>
195
+ <property name="vscrollbar_policy">automatic</property>
196
+ <child>
197
+ <object class="GtkTextView" id="textview">
198
+ <property name="visible">True</property>
199
+ <property name="can_focus">True</property>
200
+ <property name="editable">False</property>
201
+ <property name="cursor_visible">False</property>
202
+ <property name="accepts_tab">False</property>
203
+ </object>
204
+ </child>
205
+ </object>
206
+ <packing>
207
+ <property name="right_attach">3</property>
208
+ <property name="top_attach">3</property>
209
+ <property name="bottom_attach">4</property>
210
+ </packing>
211
+ </child>
212
+ </object>
213
+ </child>
214
+ </object>
215
+ </interface>
data/lib/bconv.rb ADDED
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env ruby
2
+ #############################################################################
3
+ # Yet Another ImageMagic Frontend #
4
+ # (C) 2010-2011, Vasiliy Yeremeyev <vayerx@gmail.com> #
5
+ # #
6
+ # This program is free software: you can redistribute it and/or modify #
7
+ # it under the terms of the GNU General Public License as published by #
8
+ # the Free Software Foundation, either version 3 of the License, or #
9
+ # (at your option) any later version. #
10
+ # #
11
+ # This program is distributed in the hope that it will be useful, #
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14
+ # GNU General Public License for more details. #
15
+ # #
16
+ # You should have received a copy of the GNU General Public License #
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>. #
18
+ #############################################################################
19
+
20
+ # TODO use 'rmagic' interface instead of Kernel.system
21
+
22
+
23
+ require 'enumerator'
24
+
25
+ def number_of_processors
26
+ raise "Can't determine 'number_of_processors' for '#{RUBY_PLATFORM}'" unless RUBY_PLATFORM =~ /linux/
27
+ %x[cat /proc/cpuinfo | grep processor | wc -l].to_i
28
+ end
29
+
30
+ class Converter
31
+ def initialize
32
+ @source_files = []
33
+ @launcher_thread = nil
34
+ @semaphore = Mutex.new
35
+ @jobs_slots = (number_of_processors * 1.25 + 1).to_i rescue 1
36
+ @jobs_slots = 1 if @jobs_slots < 1
37
+ end
38
+
39
+ # Asynchronously get directory listing
40
+ def preload_dir(dir, &block)
41
+ @counting_thread.terminate if @counting_thread
42
+ @counting_thread = Thread.new {
43
+ list_directory(dir)
44
+ block.call(@source_files.size) if block_given?
45
+ }
46
+ end
47
+
48
+ # Process directory
49
+ def process(src_dir, dest_dir, size, ratio, &progress)
50
+ @launcher_thread.join if @launcher_thread # supposed to be quick enough
51
+ @launcher_thread = Thread.new {
52
+ # get directory listing
53
+ if @counting_thread
54
+ @counting_thread.join
55
+ @counting_thread = nil
56
+ else
57
+ list_directory(src_dir)
58
+ end
59
+
60
+ unless @source_files.empty?
61
+ pulse_step = 1 / @source_files.size.to_f
62
+ @jobs=[]
63
+ @source_files.each_slice(((@source_files.size + @jobs_slots - 1) / @jobs_slots).to_i) do |files|
64
+ @jobs << Thread.new do
65
+ process_directory(src_dir, dest_dir, files, size, ratio, pulse_step, &progress)
66
+ end
67
+ end
68
+ else
69
+ progress.call(nil, nil, true)
70
+ end
71
+ }
72
+ end
73
+
74
+ # Terminate all running threads
75
+ def stop
76
+ @launcher_thread.terminate if @launcher_thread
77
+ @jobs.each { |thread| thread.terminate } if @jobs
78
+ @launcher_thread, @jobs = nil, nil
79
+ end
80
+
81
+ private
82
+
83
+ # Convert files
84
+ def process_directory(src_dir, dest_dir, source_files, size, ratio, pulse_step, &progress)
85
+ # rename files if destination is a source directory
86
+ file_rename =
87
+ if src_dir == dest_dir
88
+ Proc.new { |file| file.gsub(/(.*)(\.jpe?g)$/i, "\\1_#{size}\\2") }
89
+ else
90
+ Proc.new { |file| file }
91
+ end
92
+
93
+ # process files
94
+ size_opt = size && size.length != 0 ? "-resize #{size}" : ""
95
+ source_files.each do |file|
96
+ src_file = "#{src_dir}/#{file}".gsub(/([\s'()"])/, '\\\\\1')
97
+ dest_file = "#{dest_dir}/#{file_rename[file]}".gsub(/([\s'()"])/, '\\\\\1')
98
+ if src_file != dest_file
99
+ progress.call(file, nil, false)
100
+ system("convert -quality #{ratio} #{size_opt} #{src_file} #{dest_file}")
101
+ else
102
+ progress.call('SKIPPING ' + file, nil, false)
103
+ end
104
+ progress.call(nil, pulse_step, false)
105
+ end
106
+ ensure
107
+ @semaphore.synchronize {
108
+ progress.call(nil, nil, true) if (@jobs_slots -= 1) == 0
109
+ }
110
+ end
111
+
112
+ # Find JPEG files in a directory
113
+ def list_directory(dir)
114
+ @source_files = Dir.entries(dir).find_all { |file| /.*jpe?g$/i =~ file }
115
+ end
116
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bconv
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.6
5
+ platform: ruby
6
+ authors:
7
+ - Vasiliy Yeremeyev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: parseconfig
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.4
27
+ description: Yet another ImageMagick hardcore gui-frontend with multi-threading. Only
28
+ Russian language is supported.
29
+ email: vayerx@gmail.com
30
+ executables:
31
+ - bconv
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - lib/bconv.rb
36
+ - data/bconv.glade
37
+ - bin/bconv
38
+ homepage: http://github.com/vayerx/bconv
39
+ licenses:
40
+ - GPL-3
41
+ metadata: {}
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ~>
49
+ - !ruby/object:Gem::Version
50
+ version: 1.9.2
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements:
57
+ - libglade2, v2.6 or higher
58
+ rubyforge_project:
59
+ rubygems_version: 2.0.14
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: ImageMagick frontend for fast jpeg compression.
63
+ test_files: []