image_paradise 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of image_paradise might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/LICENSE.md +38 -0
- data/README.md +179 -0
- data/USAGE.md +10 -0
- data/bin/black_white +10 -0
- data/bin/display_text_from_this_image +7 -0
- data/bin/image_paradise +7 -0
- data/bin/image_paradise_shell +7 -0
- data/bin/image_to_ascii +54 -0
- data/bin/image_to_pdf +7 -0
- data/bin/make_this_image_transparent +7 -0
- data/bin/rotate_left +7 -0
- data/bin/rotate_right +7 -0
- data/doc/README.gen +162 -0
- data/doc/TODO_FOR_THE_GTK_GUI.md +1 -0
- data/image_paradise.gemspec +50 -0
- data/lib/image_paradise.rb +5 -0
- data/lib/image_paradise/base/base.rb +91 -0
- data/lib/image_paradise/black_white.rb +89 -0
- data/lib/image_paradise/confree_generator/class.rb +614 -0
- data/lib/image_paradise/confree_generator/constants.rb +61 -0
- data/lib/image_paradise/confree_generator/gui/gtk_confree_generator.rb +752 -0
- data/lib/image_paradise/confree_generator/gui/insert_button.rb +78 -0
- data/lib/image_paradise/confree_generator/reset.rb +61 -0
- data/lib/image_paradise/confree_generator/shared/shared.rb +100 -0
- data/lib/image_paradise/constants.rb +43 -0
- data/lib/image_paradise/constants/image_file_types.rb +21 -0
- data/lib/image_paradise/create_animated_gif.rb +47 -0
- data/lib/image_paradise/crop/crop.rb +302 -0
- data/lib/image_paradise/gm_support.rb +34 -0
- data/lib/image_paradise/graphs.rb +36 -0
- data/lib/image_paradise/graphs/accumulator_bar.rb +29 -0
- data/lib/image_paradise/graphs/area.rb +64 -0
- data/lib/image_paradise/graphs/bar.rb +117 -0
- data/lib/image_paradise/graphs/bar_conversion.rb +53 -0
- data/lib/image_paradise/graphs/base.rb +1392 -0
- data/lib/image_paradise/graphs/bezier.rb +45 -0
- data/lib/image_paradise/graphs/bullet.rb +115 -0
- data/lib/image_paradise/graphs/deprecated.rb +42 -0
- data/lib/image_paradise/graphs/dot.rb +129 -0
- data/lib/image_paradise/graphs/line.rb +328 -0
- data/lib/image_paradise/graphs/mini/bar.rb +42 -0
- data/lib/image_paradise/graphs/mini/legend.rb +109 -0
- data/lib/image_paradise/graphs/mini/pie.rb +42 -0
- data/lib/image_paradise/graphs/mini/side_bar.rb +41 -0
- data/lib/image_paradise/graphs/net.rb +133 -0
- data/lib/image_paradise/graphs/photo_bar.rb +106 -0
- data/lib/image_paradise/graphs/pie.rb +139 -0
- data/lib/image_paradise/graphs/scatter.rb +264 -0
- data/lib/image_paradise/graphs/scene.rb +216 -0
- data/lib/image_paradise/graphs/side_bar.rb +144 -0
- data/lib/image_paradise/graphs/side_stacked_bar.rb +116 -0
- data/lib/image_paradise/graphs/spider.rb +163 -0
- data/lib/image_paradise/graphs/stacked_area.rb +73 -0
- data/lib/image_paradise/graphs/stacked_bar.rb +68 -0
- data/lib/image_paradise/graphs/stacked_mixin.rb +30 -0
- data/lib/image_paradise/graphs/themes.rb +117 -0
- data/lib/image_paradise/graphviz/README.md +2 -0
- data/lib/image_paradise/graphviz/generate_graphviz_image.rb +274 -0
- data/lib/image_paradise/gui/gtk/control_panel.rb +126 -0
- data/lib/image_paradise/identify.rb +145 -0
- data/lib/image_paradise/image_border.rb +231 -0
- data/lib/image_paradise/image_manipulations.rb +320 -0
- data/lib/image_paradise/image_paradise.rb +150 -0
- data/lib/image_paradise/image_to_ascii/image_to_ascii.rb +187 -0
- data/lib/image_paradise/image_to_pdf/image_to_pdf.rb +99 -0
- data/lib/image_paradise/label/README.md +2 -0
- data/lib/image_paradise/label/simple_label.rb +206 -0
- data/lib/image_paradise/optimizer.rb +483 -0
- data/lib/image_paradise/project/project.rb +29 -0
- data/lib/image_paradise/random_text_to_image.rb +363 -0
- data/lib/image_paradise/requires/common_base_requires.rb +17 -0
- data/lib/image_paradise/requires/require_colours.rb +9 -0
- data/lib/image_paradise/requires/require_gtk_components.rb +8 -0
- data/lib/image_paradise/requires/require_image_to_ascii.rb +7 -0
- data/lib/image_paradise/requires/require_the_image_paradise_project.rb +24 -0
- data/lib/image_paradise/requires/require_toplevel_methods.rb +21 -0
- data/lib/image_paradise/rotate/README.md +2 -0
- data/lib/image_paradise/rotate/rotate.rb +98 -0
- data/lib/image_paradise/shell/interactive.rb +156 -0
- data/lib/image_paradise/svg/README.md +5 -0
- data/lib/image_paradise/svg/circle.rb +106 -0
- data/lib/image_paradise/svg/feature.rb +48 -0
- data/lib/image_paradise/svg/rectangle.rb +154 -0
- data/lib/image_paradise/svg/svg.rb +102 -0
- data/lib/image_paradise/to_gif.rb +91 -0
- data/lib/image_paradise/to_jpg.rb +90 -0
- data/lib/image_paradise/toplevel_methods/add_black_border_to_this_image.rb +56 -0
- data/lib/image_paradise/toplevel_methods/crop.rb +28 -0
- data/lib/image_paradise/toplevel_methods/e.rb +16 -0
- data/lib/image_paradise/toplevel_methods/esystem.rb +19 -0
- data/lib/image_paradise/toplevel_methods/extract_text_from_this_image.rb +56 -0
- data/lib/image_paradise/toplevel_methods/file_related_code.rb +25 -0
- data/lib/image_paradise/toplevel_methods/flip_image_left_right.rb +32 -0
- data/lib/image_paradise/toplevel_methods/greyscale_this_image.rb +59 -0
- data/lib/image_paradise/toplevel_methods/help.rb +30 -0
- data/lib/image_paradise/toplevel_methods/make_this_image_transparent.rb +30 -0
- data/lib/image_paradise/toplevel_methods/menu.rb +92 -0
- data/lib/image_paradise/toplevel_methods/merge_these_images.rb +49 -0
- data/lib/image_paradise/toplevel_methods/mirror_image.rb +28 -0
- data/lib/image_paradise/toplevel_methods/misc.rb +31 -0
- data/lib/image_paradise/toplevel_methods/png_to_svg.rb +34 -0
- data/lib/image_paradise/toplevel_methods/roebe.rb +17 -0
- data/lib/image_paradise/toplevel_methods/to_png.rb +105 -0
- data/lib/image_paradise/toplevel_methods/wallpaper.rb +37 -0
- data/lib/image_paradise/toplevel_methods/write_this_text.rb +76 -0
- data/lib/image_paradise/version/version.rb +19 -0
- data/test/16x16_red_square_image_for_testing.png +0 -0
- data/test/testing_confree_generator.rb +8 -0
- data/test/testing_crop.rb +19 -0
- data/test/testing_image_magick_commands.rb +39 -0
- data/test/testing_image_paradise.rb +49 -0
- data/test/testing_the_svg_component.html +261 -0
- data/test/testing_the_svg_component.rb +106 -0
- metadata +217 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
- We need to add a pdf-to-png converter.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# =========================================================================== #
|
|
2
|
+
# Gemspec for Project ImageParadise.
|
|
3
|
+
# =========================================================================== #
|
|
4
|
+
require 'image_paradise/version/version.rb'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new { |s|
|
|
7
|
+
|
|
8
|
+
s.name = 'image_paradise'
|
|
9
|
+
s.version = ImageParadise::VERSION
|
|
10
|
+
s.date = Time.now.strftime('%Y-%m-%d')
|
|
11
|
+
|
|
12
|
+
DESCRIPTION = <<-EOF
|
|
13
|
+
|
|
14
|
+
This project, called image_paradise, allows you to manipulate images,
|
|
15
|
+
primarily by using ImageMagick.
|
|
16
|
+
|
|
17
|
+
For a more complete overview, have a look at the documentation, but
|
|
18
|
+
just to give an overview - it is possible to animate .gif files,
|
|
19
|
+
make use of gruff, or batch-generate automatically created
|
|
20
|
+
image files through confree_generator (if you have cfdg
|
|
21
|
+
installed). Images can be cropped through the toplevel method
|
|
22
|
+
ImageParadise.crop(). class Optimizer can be used to optimize .jpg
|
|
23
|
+
and .png files, if pngquant is installed.
|
|
24
|
+
|
|
25
|
+
EOF
|
|
26
|
+
|
|
27
|
+
s.summary = DESCRIPTION
|
|
28
|
+
s.description = DESCRIPTION
|
|
29
|
+
|
|
30
|
+
s.extra_rdoc_files = %w()
|
|
31
|
+
|
|
32
|
+
s.authors = ['Robert A. Heiler']
|
|
33
|
+
s.email = 'shevegen@gmail.com'
|
|
34
|
+
s.files = Dir['**/*']
|
|
35
|
+
s.license = 'GPL-2.0'
|
|
36
|
+
s.executables = Dir['bin/*'].map { |f| File.basename(f) }
|
|
37
|
+
s.homepage = 'https://rubygems.org/gems/image_paradise'
|
|
38
|
+
|
|
39
|
+
s.required_ruby_version = '>= '+RUBY_VERSION
|
|
40
|
+
s.required_rubygems_version = '>= '+Gem::VERSION
|
|
41
|
+
s.rubygems_version = '>= '+Gem::VERSION
|
|
42
|
+
|
|
43
|
+
# ========================================================================= #
|
|
44
|
+
# Dependencies for the project:
|
|
45
|
+
# ========================================================================= #
|
|
46
|
+
s.add_dependency 'colours'
|
|
47
|
+
s.add_dependency 'opn'
|
|
48
|
+
s.add_dependency 'save_file'
|
|
49
|
+
|
|
50
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/ruby -w
|
|
2
|
+
# Encoding: UTF-8
|
|
3
|
+
# frozen_string_literal: true
|
|
4
|
+
# =========================================================================== #
|
|
5
|
+
# require 'image_paradise/base/base.rb'
|
|
6
|
+
# < ::ImageParadise::Base
|
|
7
|
+
# =========================================================================== #
|
|
8
|
+
require 'image_paradise/requires/common_base_requires.rb'
|
|
9
|
+
require 'image_paradise/constants.rb'
|
|
10
|
+
require 'image_paradise/toplevel_methods/esystem.rb'
|
|
11
|
+
require 'image_paradise/toplevel_methods/file_related_code.rb'
|
|
12
|
+
require 'image_paradise/toplevel_methods/roebe.rb'
|
|
13
|
+
|
|
14
|
+
module ImageParadise
|
|
15
|
+
|
|
16
|
+
class Base # === ImageParadise::Base
|
|
17
|
+
|
|
18
|
+
include Colours
|
|
19
|
+
|
|
20
|
+
# ========================================================================= #
|
|
21
|
+
# === initialize
|
|
22
|
+
# ========================================================================= #
|
|
23
|
+
def initialize
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# ========================================================================= #
|
|
27
|
+
# === reset
|
|
28
|
+
# ========================================================================= #
|
|
29
|
+
def reset
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# ========================================================================= #
|
|
33
|
+
# === today
|
|
34
|
+
# ========================================================================= #
|
|
35
|
+
def today
|
|
36
|
+
"#{Time.now.strftime('%d.%m.%Y')}_#{Time.now.strftime('%H:%M:%S.%L')}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# ========================================================================= #
|
|
40
|
+
# === rds
|
|
41
|
+
# ========================================================================= #
|
|
42
|
+
def rds(i)
|
|
43
|
+
i.squeeze('/')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# ========================================================================= #
|
|
47
|
+
# === chdir
|
|
48
|
+
# ========================================================================= #
|
|
49
|
+
def chdir(i)
|
|
50
|
+
Dir.chdir(i)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# ========================================================================= #
|
|
54
|
+
# === mkdir
|
|
55
|
+
# ========================================================================= #
|
|
56
|
+
def mkdir(i)
|
|
57
|
+
FileUtils.mkdir_p(i) unless File.directory? i
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# ========================================================================= #
|
|
61
|
+
# === register_sigint
|
|
62
|
+
# ========================================================================= #
|
|
63
|
+
def register_sigint
|
|
64
|
+
Signal.trap('SIGINT') {
|
|
65
|
+
e 'Exiting now, as requested.'
|
|
66
|
+
exit
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# ========================================================================= #
|
|
71
|
+
# === write_what_into
|
|
72
|
+
# ========================================================================= #
|
|
73
|
+
def write_what_into(what, into)
|
|
74
|
+
SaveFile.write_what_into(what, into)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# ========================================================================= #
|
|
78
|
+
# === esystem
|
|
79
|
+
# ========================================================================= #
|
|
80
|
+
def esystem(i)
|
|
81
|
+
::ImageParadise.esystem(i)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# ========================================================================= #
|
|
85
|
+
# === is_on_roebe?
|
|
86
|
+
# ========================================================================= #
|
|
87
|
+
def is_on_roebe?
|
|
88
|
+
::ImageParadise.is_on_roebe?
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
end; end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/ruby -w
|
|
2
|
+
# Encoding: UTF-8
|
|
3
|
+
# frozen_string_literal: true
|
|
4
|
+
# =========================================================================== #
|
|
5
|
+
# === ImageParadise::BlackWhite
|
|
6
|
+
#
|
|
7
|
+
# This class can turn an image into a black-white image.
|
|
8
|
+
#
|
|
9
|
+
# Usage example:
|
|
10
|
+
# ImageParadise::BlackWhite.new
|
|
11
|
+
# =========================================================================== #
|
|
12
|
+
# require 'image_paradise/black_white.rb'
|
|
13
|
+
# =========================================================================== #
|
|
14
|
+
require 'image_paradise/base/base.rb'
|
|
15
|
+
|
|
16
|
+
module ImageParadise
|
|
17
|
+
|
|
18
|
+
class BlackWhite < ::ImageParadise::Base # === ImageParadise::BlackWhite
|
|
19
|
+
|
|
20
|
+
# ========================================================================= #
|
|
21
|
+
# === initialize
|
|
22
|
+
# ========================================================================= #
|
|
23
|
+
def initialize(
|
|
24
|
+
i = nil,
|
|
25
|
+
run_already = true
|
|
26
|
+
)
|
|
27
|
+
reset
|
|
28
|
+
set_input(i)
|
|
29
|
+
run if run_already
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# ========================================================================= #
|
|
33
|
+
# === reset (reset tag)
|
|
34
|
+
# ========================================================================= #
|
|
35
|
+
def reset
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# ========================================================================= #
|
|
39
|
+
# === set_input
|
|
40
|
+
# ========================================================================= #
|
|
41
|
+
def set_input(i = ARGV)
|
|
42
|
+
i = [i] unless i.is_a? Array
|
|
43
|
+
@input = i
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# ========================================================================= #
|
|
47
|
+
# === input?
|
|
48
|
+
# ========================================================================= #
|
|
49
|
+
def input?
|
|
50
|
+
@input
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# ========================================================================= #
|
|
54
|
+
# === run (run tag)
|
|
55
|
+
# ========================================================================= #
|
|
56
|
+
def run
|
|
57
|
+
input?.each {|filename|
|
|
58
|
+
_ = 'convert '+filename+' -colorspace Gray OUTPUT_'+filename
|
|
59
|
+
Esystem.esystem(_)
|
|
60
|
+
}
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# ========================================================================= #
|
|
64
|
+
# === []
|
|
65
|
+
# ========================================================================= #
|
|
66
|
+
def self.[](i = '')
|
|
67
|
+
self.new(i)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# =========================================================================== #
|
|
73
|
+
# === ImageParadise.black_white
|
|
74
|
+
# =========================================================================== #
|
|
75
|
+
def self.black_white(i = ARGV)
|
|
76
|
+
if i.is_a? Array
|
|
77
|
+
i.each {|entry|
|
|
78
|
+
ImageParadise.black_white(entry)
|
|
79
|
+
}
|
|
80
|
+
else
|
|
81
|
+
ImageParadise::BlackWhite.new(i)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
if __FILE__ == $PROGRAM_NAME
|
|
88
|
+
ImageParadise::BlackWhite.new(ARGV)
|
|
89
|
+
end # black_white
|
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
#!/usr/bin/ruby -w
|
|
2
|
+
# Encoding: UTF-8
|
|
3
|
+
# frozen_string_literal: true
|
|
4
|
+
# =========================================================================== #
|
|
5
|
+
# === ImageParadise::ConfreeGenerator
|
|
6
|
+
#
|
|
7
|
+
# The task of this class is to generate a .cfdg file or more than one.
|
|
8
|
+
#
|
|
9
|
+
# Usage examples:
|
|
10
|
+
#
|
|
11
|
+
# ImageParadise::ConfreeGenerator.new(ARGV)
|
|
12
|
+
#
|
|
13
|
+
# =========================================================================== #
|
|
14
|
+
# require 'image_paradise/confree_generator/class.rb'
|
|
15
|
+
# ImageParadise.confreegenerator
|
|
16
|
+
# =========================================================================== #
|
|
17
|
+
require 'image_paradise/base/base.rb'
|
|
18
|
+
require 'image_paradise/confree_generator/reset.rb'
|
|
19
|
+
require 'image_paradise/confree_generator/shared/shared.rb'
|
|
20
|
+
|
|
21
|
+
module ImageParadise
|
|
22
|
+
|
|
23
|
+
class ConfreeGenerator < ::ImageParadise::Base # === ImageParadise::ConfreeGenerator
|
|
24
|
+
|
|
25
|
+
begin
|
|
26
|
+
require 'web_object/toplevel_methods/standalone_drag_and_drop_this_image.rb'
|
|
27
|
+
rescue LoadError; end
|
|
28
|
+
|
|
29
|
+
begin
|
|
30
|
+
require 'html_tags' # For .html generation.
|
|
31
|
+
include HtmlTags
|
|
32
|
+
rescue LoadError; end
|
|
33
|
+
|
|
34
|
+
include ImageParadise::ConfreeGenerator::Shared # This one is part of shared/shared.rb
|
|
35
|
+
|
|
36
|
+
attr_accessor :n_confree_files # How many confree files we will process.
|
|
37
|
+
|
|
38
|
+
# ========================================================================= #
|
|
39
|
+
# === initialize
|
|
40
|
+
# ========================================================================= #
|
|
41
|
+
def initialize(
|
|
42
|
+
i = nil,
|
|
43
|
+
run_already = true
|
|
44
|
+
)
|
|
45
|
+
register_sigint
|
|
46
|
+
reset
|
|
47
|
+
set_input(i)
|
|
48
|
+
if block_given?
|
|
49
|
+
yielded = yield
|
|
50
|
+
case yielded
|
|
51
|
+
# ===================================================================== #
|
|
52
|
+
# === :do_not_open_via_the_browser
|
|
53
|
+
# ===================================================================== #
|
|
54
|
+
when :do_not_open_via_the_browser
|
|
55
|
+
@try_to_open_the_generated_image_in_the_browser = false
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
run if run_already
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# ========================================================================= #
|
|
62
|
+
# === name_of_output_file?
|
|
63
|
+
# ========================================================================= #
|
|
64
|
+
def name_of_output_file?
|
|
65
|
+
ConfreeGenerator::NAME_OF_OUTPUT_FILE
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# ========================================================================= #
|
|
69
|
+
# === set_location_of_output_file
|
|
70
|
+
#
|
|
71
|
+
# This tells us where we store the output file.
|
|
72
|
+
# ========================================================================= #
|
|
73
|
+
def set_location_of_output_file(
|
|
74
|
+
i = DIRECTORY_WITH_CFDG_IMAGES+name_of_output_file?
|
|
75
|
+
)
|
|
76
|
+
i = DIRECTORY_WITH_CFDG_IMAGES+name_of_output_file? if i.nil?
|
|
77
|
+
i = Dir.pwd+'/'+i unless i.include? '/'
|
|
78
|
+
@location_of_output_file = i
|
|
79
|
+
end; alias set_output_location set_location_of_output_file # === set_output_location
|
|
80
|
+
alias set_output set_location_of_output_file # === set_output
|
|
81
|
+
|
|
82
|
+
# ========================================================================= #
|
|
83
|
+
# === br
|
|
84
|
+
# ========================================================================= #
|
|
85
|
+
def br
|
|
86
|
+
HtmlTags.br
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# ========================================================================= #
|
|
90
|
+
# === random_name
|
|
91
|
+
#
|
|
92
|
+
# This method will return a string which consists of the input-string
|
|
93
|
+
# and 8 more random characters. We assume that for 8 random characters,
|
|
94
|
+
# there will be no double names.
|
|
95
|
+
#
|
|
96
|
+
# The result of this method is, for instance:
|
|
97
|
+
# "tube_map_jblhelce.png"
|
|
98
|
+
# ========================================================================= #
|
|
99
|
+
def random_name(i)
|
|
100
|
+
copy = i.to_s.dup
|
|
101
|
+
alphabet = ALPHABET # Build up the alphabet.
|
|
102
|
+
copy.gsub!(/\.cfdg/,'') # Don't like file ending here.
|
|
103
|
+
copy = File.basename(copy).dup
|
|
104
|
+
copy << '_'
|
|
105
|
+
10.times { copy << alphabet.sample }
|
|
106
|
+
return copy
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# ========================================================================= #
|
|
110
|
+
# === eparse
|
|
111
|
+
# ========================================================================= #
|
|
112
|
+
def eparse(i)
|
|
113
|
+
Colours.eparse(i)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# ========================================================================= #
|
|
117
|
+
# === toggle_generate_image
|
|
118
|
+
#
|
|
119
|
+
# This toggle switches between when we want to generate the image,
|
|
120
|
+
# and when we don't.
|
|
121
|
+
# ========================================================================= #
|
|
122
|
+
def toggle_generate_image
|
|
123
|
+
if generate_the_image?
|
|
124
|
+
e 'Setting to false - dont create images.'
|
|
125
|
+
else
|
|
126
|
+
e 'Setting to true - do create images.'
|
|
127
|
+
end
|
|
128
|
+
@generate_the_image = ! @generate_the_image
|
|
129
|
+
end; alias change_flag toggle_generate_image # === change_flag
|
|
130
|
+
|
|
131
|
+
# ========================================================================= #
|
|
132
|
+
# === generate_the_image?
|
|
133
|
+
# ========================================================================= #
|
|
134
|
+
def generate_the_image?
|
|
135
|
+
@generate_the_image
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# ========================================================================= #
|
|
139
|
+
# === show_welcome_message
|
|
140
|
+
# ========================================================================= #
|
|
141
|
+
def show_welcome_message
|
|
142
|
+
opnn; efancy ' => Starting the Confreegenerator now.'
|
|
143
|
+
opnn; e 'Welcome!'
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# ========================================================================= #
|
|
147
|
+
# === check_whether_cfdg_is_installed
|
|
148
|
+
# ========================================================================= #
|
|
149
|
+
def check_whether_cfdg_is_installed
|
|
150
|
+
_ = `cfdg 2>&1` # => "sh: cfdg: command not found\n"
|
|
151
|
+
if _.include? 'cfdg: command not found'
|
|
152
|
+
e 'Note that you do not seem to have cfdg installed.'
|
|
153
|
+
e 'We will still continue nonetheless.'
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# ========================================================================= #
|
|
158
|
+
# === start_gui (gui tag)
|
|
159
|
+
#
|
|
160
|
+
# This method will start the GUI component.
|
|
161
|
+
# ========================================================================= #
|
|
162
|
+
def start_gui
|
|
163
|
+
require 'confreegenerator/gui/gtk_confree_generator.rb'
|
|
164
|
+
@gtk_confreegenerator = GtkConfreeGenerator.new
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# ========================================================================= #
|
|
168
|
+
# === check_input_given (menu tag)
|
|
169
|
+
#
|
|
170
|
+
# Usage examples:
|
|
171
|
+
#
|
|
172
|
+
# confgen change_flag
|
|
173
|
+
#
|
|
174
|
+
# Regular use:
|
|
175
|
+
#
|
|
176
|
+
# rfree $CFDG/spiral_star.cfdg
|
|
177
|
+
# rfree $CFDG/star.cfdg
|
|
178
|
+
#
|
|
179
|
+
# ========================================================================= #
|
|
180
|
+
def menu
|
|
181
|
+
_ = @input.shift # Return the first element and also remove it.
|
|
182
|
+
case _ # case tag
|
|
183
|
+
# ======================================================================= #
|
|
184
|
+
# === confree_generator --batch
|
|
185
|
+
# ======================================================================= #
|
|
186
|
+
when /^-?-?batch$/,
|
|
187
|
+
'batchmode','b','2'
|
|
188
|
+
run_in_batch_mode
|
|
189
|
+
# ======================================================================= #
|
|
190
|
+
# === confree_generator --html
|
|
191
|
+
# ======================================================================= #
|
|
192
|
+
when /^-?-?html$/i,
|
|
193
|
+
/^-?-?html(_|-)?gallery$/i,
|
|
194
|
+
'gallery','default','4'
|
|
195
|
+
create_html_gallery # Always create the html gallery.
|
|
196
|
+
# ======================================================================= #
|
|
197
|
+
# === confree_generator --gui
|
|
198
|
+
# ======================================================================= #
|
|
199
|
+
when /^-?-?gui$/i,'startgui','start_gui','3'
|
|
200
|
+
start_gui
|
|
201
|
+
# ======================================================================= #
|
|
202
|
+
# === confree_generator --toggle
|
|
203
|
+
# ======================================================================= #
|
|
204
|
+
when '--toggle','change','change_flag','c','flag','f','fl',
|
|
205
|
+
'fla','generate_image','toggle','1'
|
|
206
|
+
toggle_generate_image
|
|
207
|
+
# ======================================================================= #
|
|
208
|
+
# === confree_generator --gallery_only
|
|
209
|
+
# ======================================================================= #
|
|
210
|
+
when '--gallery_only','gallery_only'
|
|
211
|
+
@create_image = false # We skip creating the images anew.
|
|
212
|
+
create_html_gallery
|
|
213
|
+
# ======================================================================= #
|
|
214
|
+
# === confree_generator --help
|
|
215
|
+
# ======================================================================= #
|
|
216
|
+
when 'HELP','help','--help'
|
|
217
|
+
show_help; exit
|
|
218
|
+
else # else tag
|
|
219
|
+
set_input(_)
|
|
220
|
+
show_welcome_message
|
|
221
|
+
create_html_gallery if @create_html_gallery
|
|
222
|
+
end
|
|
223
|
+
end; alias check_input_given menu # === check_input_given
|
|
224
|
+
|
|
225
|
+
# ======================================================================= #
|
|
226
|
+
# === set_width_then_height
|
|
227
|
+
#
|
|
228
|
+
# This method will first set the width, then the height.
|
|
229
|
+
# ======================================================================= #
|
|
230
|
+
def set_width_then_height(
|
|
231
|
+
width = 55,
|
|
232
|
+
height = nil
|
|
233
|
+
)
|
|
234
|
+
height = width if height.nil?
|
|
235
|
+
set_width(width)
|
|
236
|
+
set_height(height)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# ========================================================================= #
|
|
240
|
+
# === append_to_html_file
|
|
241
|
+
#
|
|
242
|
+
# Use this method to append into a html file.
|
|
243
|
+
# ========================================================================= #
|
|
244
|
+
def append_to_html_file(i = nil)
|
|
245
|
+
append_what_into(i, html_file?) if i
|
|
246
|
+
end; alias my_append append_to_html_file # === my_append
|
|
247
|
+
|
|
248
|
+
# ========================================================================= #
|
|
249
|
+
# === html_file?
|
|
250
|
+
# ========================================================================= #
|
|
251
|
+
def html_file?
|
|
252
|
+
@html_file
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# ========================================================================= #
|
|
256
|
+
# === start_batch_processing (batch tag)
|
|
257
|
+
# ========================================================================= #
|
|
258
|
+
def start_batch_processing
|
|
259
|
+
@file_listing = get_all_cfdg_files
|
|
260
|
+
# Let's order it randomly:
|
|
261
|
+
@file_listing = @file_listing.sort_by { rand }
|
|
262
|
+
# Obtain how many we have:
|
|
263
|
+
@n_confree_files = @file_listing.size
|
|
264
|
+
set_input @file_listing
|
|
265
|
+
@input.each {|entry|
|
|
266
|
+
_ = TEMP_IMAGES+random_name(entry)+'.png'
|
|
267
|
+
e _
|
|
268
|
+
set_output_location(_)
|
|
269
|
+
create_image_from_cfdg(entry)
|
|
270
|
+
}
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# ========================================================================= #
|
|
274
|
+
# === run_in_batch_mode
|
|
275
|
+
# ========================================================================= #
|
|
276
|
+
def run_in_batch_mode
|
|
277
|
+
@batch_mode = true
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
# ========================================================================= #
|
|
281
|
+
# === create_html_gallery (html tag, img tag, gallery tag)
|
|
282
|
+
#
|
|
283
|
+
# Run this method here to create the HTML gallery.
|
|
284
|
+
#
|
|
285
|
+
# To invoke this method from the commandline, try:
|
|
286
|
+
#
|
|
287
|
+
# confree_generator --html
|
|
288
|
+
#
|
|
289
|
+
# ========================================================================= #
|
|
290
|
+
def create_html_gallery
|
|
291
|
+
::ImageParadise.remove_file(html_file?) # Always ensure that the html_file was removed.
|
|
292
|
+
opnn; e "We will save into `#{sfile(html_file?)}`."
|
|
293
|
+
mkdir(File.dirname(html_file?))
|
|
294
|
+
_ = '<html>'.dup
|
|
295
|
+
_ << '<title>'+html_file?+' CFDG Image Collection'+'</title>'
|
|
296
|
+
_ << HtmlTags.body
|
|
297
|
+
# ======================================================================= #
|
|
298
|
+
# After here, we have added <html>, <title> and <body>
|
|
299
|
+
# ======================================================================= #
|
|
300
|
+
append_to_html_file(_)
|
|
301
|
+
img_counter = 0
|
|
302
|
+
if @create_image
|
|
303
|
+
these_files = get_all_cfdg_files
|
|
304
|
+
else
|
|
305
|
+
these_files = Dir[save_files_where?+'*.png']
|
|
306
|
+
end
|
|
307
|
+
be_verbose = @create_image
|
|
308
|
+
# ======================================================================= #
|
|
309
|
+
# Next, we add all the images that we found:
|
|
310
|
+
# ======================================================================= #
|
|
311
|
+
these_files.each {|cfdg_file|
|
|
312
|
+
if @create_image
|
|
313
|
+
_ = TEMP_IMAGES+random_name(cfdg_file)+'.png'
|
|
314
|
+
else
|
|
315
|
+
_ = cfdg_file
|
|
316
|
+
end
|
|
317
|
+
set_output_location(_)
|
|
318
|
+
if @create_image
|
|
319
|
+
opnn; e 'Now processing file `'+sfile(cfdg_file)+'` into `'+sfile(_)+'`.'
|
|
320
|
+
end
|
|
321
|
+
img_counter += 1 # at which img pos are we?
|
|
322
|
+
@n_confree_files += 1
|
|
323
|
+
tmp_var = img_counter % 9
|
|
324
|
+
set_width_then_height(320) # This is the same size for both.
|
|
325
|
+
create_image_from_cfdg_file(cfdg_file, true) if @create_image
|
|
326
|
+
# ===================================================================== #
|
|
327
|
+
# Next we will create the file, but we will store it into a html table.
|
|
328
|
+
# Data points 1,2,3 - 4,5,6 -7,8,9 come into a table.
|
|
329
|
+
# ===================================================================== #
|
|
330
|
+
case tmp_var # case tag
|
|
331
|
+
when 0
|
|
332
|
+
my_append(TD+N)
|
|
333
|
+
write_entry( i.sub(/\/Users\/x\/DATA\/IMG/,'$IMG'),
|
|
334
|
+
img_counter, be_verbose )
|
|
335
|
+
my_append(ctd)
|
|
336
|
+
my_append(ctr+N+N)
|
|
337
|
+
my_append(ctable+N+N)
|
|
338
|
+
# Reset the img_counter every 9 iteration.
|
|
339
|
+
img_counter = 0
|
|
340
|
+
when 1
|
|
341
|
+
my_append(TABLE+TR+TD+N)
|
|
342
|
+
write_entry(cfdg_file, img_counter, be_verbose)
|
|
343
|
+
my_append(ctd)
|
|
344
|
+
when 3,6
|
|
345
|
+
_ = td+cfdg_file+img_counter.to_s+ctd+
|
|
346
|
+
ctr+N+N+tr
|
|
347
|
+
my_append(_)
|
|
348
|
+
else # bei 2,4,5,7,8
|
|
349
|
+
my_append(TD+N)
|
|
350
|
+
write_entry(cfdg_file, img_counter, be_verbose)
|
|
351
|
+
my_append(ctd)
|
|
352
|
+
end
|
|
353
|
+
}
|
|
354
|
+
# ======================================================================= #
|
|
355
|
+
# Last but not least, we close the table.
|
|
356
|
+
# ======================================================================= #
|
|
357
|
+
my_append(ctr)
|
|
358
|
+
my_append(ctable)
|
|
359
|
+
my_append(br+'Find more examples ')
|
|
360
|
+
my_append('<a href="http://chriscoyne.com/gallery/view.php"><b>here</b></a>')
|
|
361
|
+
my_append(br+' '+@n_confree_files.to_s+' images files should be listed here.'+N)
|
|
362
|
+
my_append(br+cbody+chtml)
|
|
363
|
+
opnn; e "Finished appending into `#{sfile(html_file?)}`."
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
# ========================================================================= #
|
|
367
|
+
# === save_files_where?
|
|
368
|
+
# ========================================================================= #
|
|
369
|
+
def save_files_where?
|
|
370
|
+
TEMP_IMAGES
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
# ========================================================================= #
|
|
374
|
+
# === opnn
|
|
375
|
+
# ========================================================================= #
|
|
376
|
+
def opnn
|
|
377
|
+
Opn.opn(namespace: NAMESPACE)
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# ========================================================================= #
|
|
381
|
+
# === show_help (help tag)
|
|
382
|
+
#
|
|
383
|
+
# To invoke this help menu, do:
|
|
384
|
+
#
|
|
385
|
+
# congen HELP
|
|
386
|
+
#
|
|
387
|
+
# ========================================================================= #
|
|
388
|
+
def show_help
|
|
389
|
+
e
|
|
390
|
+
e ::Colours::YEL+'Currently this script has this usage:'+::Colours.rev
|
|
391
|
+
e
|
|
392
|
+
eparse ' confreegen name_of_cfdg_file.cfdg'
|
|
393
|
+
e
|
|
394
|
+
eparse ' toggle # Toggle whether we want to create the image or not.'
|
|
395
|
+
eparse ' batch # run everything in batch mode (batch processing)'
|
|
396
|
+
eparse ' gallery_only # generate only the gallery'
|
|
397
|
+
eparse ' html # create a html gallery'
|
|
398
|
+
eparse ' gui # start the GUI component of this project'
|
|
399
|
+
e
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
# ========================================================================= #
|
|
403
|
+
# === write_entry
|
|
404
|
+
#
|
|
405
|
+
# A helper method to log stuff into the html file. We use the project
|
|
406
|
+
# HtmlTags for the html here.
|
|
407
|
+
# ========================================================================= #
|
|
408
|
+
def write_entry(
|
|
409
|
+
i, counter = 0, be_verbose = true
|
|
410
|
+
)
|
|
411
|
+
my_append(
|
|
412
|
+
HtmlTags.comment(counter.to_s)
|
|
413
|
+
)
|
|
414
|
+
my_append(
|
|
415
|
+
span('The CFDG-File Name is:','','','font-size:0.95em')+br+N
|
|
416
|
+
) if be_verbose
|
|
417
|
+
my_append(
|
|
418
|
+
b(i)+br+N
|
|
419
|
+
)
|
|
420
|
+
# ======================================================================= #
|
|
421
|
+
# Add the <img> tag here.
|
|
422
|
+
# ======================================================================= #
|
|
423
|
+
id_for_this_image_file = File.basename(@location_of_output_file).
|
|
424
|
+
sub(/#{File.extname(@location_of_output_file)}$/,'')
|
|
425
|
+
my_append(
|
|
426
|
+
N+N+img( # <- This will actually call HtmlTags.img().
|
|
427
|
+
@location_of_output_file,
|
|
428
|
+
'','','margin:5px; border:1px solid black;'
|
|
429
|
+
)+
|
|
430
|
+
WebObject.standalone_drag_and_drop_this_image(id_for_this_image_file)+
|
|
431
|
+
N # img tag here.
|
|
432
|
+
)
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
# ========================================================================= #
|
|
436
|
+
# === process_input (process tag)
|
|
437
|
+
#
|
|
438
|
+
# This method will process the .cfdg file at hand.
|
|
439
|
+
# ========================================================================= #
|
|
440
|
+
def process_input(
|
|
441
|
+
i = @input
|
|
442
|
+
)
|
|
443
|
+
if @batch_mode # Run all images here.
|
|
444
|
+
start_batch_processing
|
|
445
|
+
else
|
|
446
|
+
unless i.empty?
|
|
447
|
+
e ' => Processing the given input next.'
|
|
448
|
+
i.each_with_index {|entry, index| index += 1
|
|
449
|
+
opnn; e ("#{index})").rjust(4)+' '+entry
|
|
450
|
+
create_image_from_cfdg(entry)
|
|
451
|
+
}
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
# ========================================================================= #
|
|
457
|
+
# === create_image_from_cfdg (system tag)
|
|
458
|
+
#
|
|
459
|
+
# This is the method that will shell out to "cfdg" and actually create
|
|
460
|
+
# the image in question. Additionally, we may also optimize the
|
|
461
|
+
# generated .png file, via "pngquant", to minimize the size.
|
|
462
|
+
# ========================================================================= #
|
|
463
|
+
def create_image_from_cfdg(
|
|
464
|
+
i,
|
|
465
|
+
generate_the_image = @generate_the_image
|
|
466
|
+
)
|
|
467
|
+
if File.exist? i
|
|
468
|
+
scan_this_file_for_width_and_height_values(i)
|
|
469
|
+
end
|
|
470
|
+
_ = 'cfdg '+i.to_s
|
|
471
|
+
_ << ' -b 1' # This means border size. For now this is hardcoded.
|
|
472
|
+
_ << ' -w '+@height.to_s
|
|
473
|
+
_ << ' -h '+@width.to_s
|
|
474
|
+
# _ << '-a 10'
|
|
475
|
+
_ << ' '+@location_of_output_file
|
|
476
|
+
e _
|
|
477
|
+
if generate_the_image
|
|
478
|
+
system(_)
|
|
479
|
+
# ===================================================================== #
|
|
480
|
+
# === Optimize via pngquant
|
|
481
|
+
# ===================================================================== #
|
|
482
|
+
if OPTIMIZE_PNG_FILES
|
|
483
|
+
# =================================================================== #
|
|
484
|
+
# Do a bit of clean-up first:
|
|
485
|
+
# =================================================================== #
|
|
486
|
+
# _ = 'output-fs8.png'
|
|
487
|
+
# File.delete(_) if File.exist? _
|
|
488
|
+
# =================================================================== #
|
|
489
|
+
# Optimize the generated .png file.
|
|
490
|
+
# =================================================================== #
|
|
491
|
+
optimize_string = 'pngquant '+@location_of_output_file
|
|
492
|
+
e "Next running #{sfancy('pngquant')} to reduce the size "\
|
|
493
|
+
"of the .png file at hand."
|
|
494
|
+
e
|
|
495
|
+
e sfancy(" #{optimize_string}")
|
|
496
|
+
e
|
|
497
|
+
system(optimize_string)
|
|
498
|
+
end
|
|
499
|
+
if @try_to_open_the_generated_image_in_the_browser
|
|
500
|
+
if File.exist? @location_of_output_file
|
|
501
|
+
require 'open_in_browser'
|
|
502
|
+
OpenInBrowser[@location_of_output_file]
|
|
503
|
+
end
|
|
504
|
+
end
|
|
505
|
+
end
|
|
506
|
+
end; alias create_image_from_cfdg_file create_image_from_cfdg # === create_image_from_cfdg_file
|
|
507
|
+
|
|
508
|
+
# ========================================================================= #
|
|
509
|
+
# === scan_this_file_for_width_and_height_values
|
|
510
|
+
# ========================================================================= #
|
|
511
|
+
def scan_this_file_for_width_and_height_values(i)
|
|
512
|
+
File.readlines(i).each {|line|
|
|
513
|
+
if line.include? ' WIDTH: '
|
|
514
|
+
# =================================================================== #
|
|
515
|
+
# Set the width next:
|
|
516
|
+
# =================================================================== #
|
|
517
|
+
set_width(line.delete('#:').strip.sub(/WIDTH/,''))
|
|
518
|
+
elsif line.include? ' HEIGHT: '
|
|
519
|
+
# =================================================================== #
|
|
520
|
+
# Set the height next:
|
|
521
|
+
# =================================================================== #
|
|
522
|
+
set_height(line.delete('#:').strip.sub(/HEIGHT/,''))
|
|
523
|
+
end
|
|
524
|
+
}
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
# ========================================================================= #
|
|
528
|
+
# === set_height
|
|
529
|
+
# ========================================================================= #
|
|
530
|
+
def set_height(i)
|
|
531
|
+
if i.is_a? String
|
|
532
|
+
i = i.dup if i.frozen?
|
|
533
|
+
i.strip!
|
|
534
|
+
end
|
|
535
|
+
@height = i.to_i
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
# ========================================================================= #
|
|
539
|
+
# === set_width
|
|
540
|
+
# ========================================================================= #
|
|
541
|
+
def set_width(i)
|
|
542
|
+
if i.is_a? String
|
|
543
|
+
i = i.dup if i.frozen?
|
|
544
|
+
i.strip!
|
|
545
|
+
end
|
|
546
|
+
@width = i.to_i
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
# ========================================================================= #
|
|
550
|
+
# === set_input
|
|
551
|
+
#
|
|
552
|
+
# Whenever this is called, we immediately run sanitize_input.
|
|
553
|
+
# ========================================================================= #
|
|
554
|
+
def set_input(i = '')
|
|
555
|
+
unless i.is_a? Array # We want an array here.
|
|
556
|
+
i = [i.to_s]
|
|
557
|
+
end
|
|
558
|
+
@input = i # <- This is typically a .cfdg file such as "moon_explorations.cfdg"
|
|
559
|
+
sanitize_input
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
# ========================================================================= #
|
|
563
|
+
# === sanitize_input (sanitize tag)
|
|
564
|
+
# ========================================================================= #
|
|
565
|
+
def sanitize_input
|
|
566
|
+
@input.map! {|entry|
|
|
567
|
+
entry = get_random_cfdg_file if entry == 'RANDOM' # Turn RANDOM into something meaningful here.
|
|
568
|
+
entry = entry.dup if entry.frozen?
|
|
569
|
+
unless entry.end_with? '.cfdg'
|
|
570
|
+
entry << '.cfdg'
|
|
571
|
+
end
|
|
572
|
+
unless File.exist? entry
|
|
573
|
+
try_this_target = "#{HARDCODED_PATH_TO_THE_CFDG_IMAGES_DIRECTORY}#{entry}"
|
|
574
|
+
if File.exist?(try_this_target)
|
|
575
|
+
entry = try_this_target
|
|
576
|
+
end
|
|
577
|
+
end
|
|
578
|
+
entry
|
|
579
|
+
}
|
|
580
|
+
@input.flatten!
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
# ========================================================================= #
|
|
584
|
+
# === run (run tag)
|
|
585
|
+
# ========================================================================= #
|
|
586
|
+
def run
|
|
587
|
+
check_whether_cfdg_is_installed
|
|
588
|
+
check_input_given
|
|
589
|
+
process_input
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
# =========================================================================== #
|
|
595
|
+
# === ImageParadise.confreegenerator
|
|
596
|
+
# =========================================================================== #
|
|
597
|
+
def self.confreegenerator(
|
|
598
|
+
i = ARGV
|
|
599
|
+
)
|
|
600
|
+
::ImageParadise::ConfreeGenerator.new(i)
|
|
601
|
+
end
|
|
602
|
+
|
|
603
|
+
# =========================================================================== #
|
|
604
|
+
# === ImageParadise.batch_generate_the_cfdg_files
|
|
605
|
+
# =========================================================================== #
|
|
606
|
+
def self.batch_generate_the_cfdg_files
|
|
607
|
+
::ImageParadise::ConfreeGenerator.new('--batch')
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
if __FILE__ == $PROGRAM_NAME
|
|
613
|
+
ImageParadise::ConfreeGenerator.new(ARGV)
|
|
614
|
+
end # confree_generator
|