qttk 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +36 -0
- data/README.markdown +131 -0
- data/Rakefile +17 -0
- data/TODO.markdown +236 -0
- data/bin/qt +7 -0
- data/etc/gutenprint/gp-tool.rb +56 -0
- data/etc/gutenprint/gutenprint-filter.c +400 -0
- data/etc/gutenprint/gutenprint.rb +86 -0
- data/etc/gutenprint/stp-test +326 -0
- data/etc/images/3551599565_db282cf840_o.jpg +0 -0
- data/etc/images/4843122063_d582c569e9_o.jpg +0 -0
- data/etc/images/4843128953_83c1770907_o.jpg +0 -0
- data/lib/quadtone.rb +56 -0
- data/lib/quadtone/cgats.rb +137 -0
- data/lib/quadtone/cluster_calculator.rb +81 -0
- data/lib/quadtone/color.rb +83 -0
- data/lib/quadtone/color/cmyk.rb +112 -0
- data/lib/quadtone/color/device_n.rb +23 -0
- data/lib/quadtone/color/gray.rb +46 -0
- data/lib/quadtone/color/lab.rb +150 -0
- data/lib/quadtone/color/qtr.rb +71 -0
- data/lib/quadtone/color/rgb.rb +71 -0
- data/lib/quadtone/color/xyz.rb +80 -0
- data/lib/quadtone/curve.rb +138 -0
- data/lib/quadtone/curve_set.rb +196 -0
- data/lib/quadtone/descendants.rb +9 -0
- data/lib/quadtone/environment.rb +5 -0
- data/lib/quadtone/extensions/math.rb +11 -0
- data/lib/quadtone/extensions/pathname3.rb +11 -0
- data/lib/quadtone/printer.rb +106 -0
- data/lib/quadtone/profile.rb +217 -0
- data/lib/quadtone/quad_file.rb +59 -0
- data/lib/quadtone/renderer.rb +139 -0
- data/lib/quadtone/run.rb +10 -0
- data/lib/quadtone/sample.rb +32 -0
- data/lib/quadtone/separator.rb +36 -0
- data/lib/quadtone/target.rb +277 -0
- data/lib/quadtone/tool.rb +61 -0
- data/lib/quadtone/tools/add_printer.rb +73 -0
- data/lib/quadtone/tools/characterize.rb +43 -0
- data/lib/quadtone/tools/chart.rb +31 -0
- data/lib/quadtone/tools/check.rb +16 -0
- data/lib/quadtone/tools/dir.rb +15 -0
- data/lib/quadtone/tools/edit.rb +23 -0
- data/lib/quadtone/tools/init.rb +82 -0
- data/lib/quadtone/tools/install.rb +15 -0
- data/lib/quadtone/tools/linearize.rb +28 -0
- data/lib/quadtone/tools/list.rb +19 -0
- data/lib/quadtone/tools/print.rb +38 -0
- data/lib/quadtone/tools/printer_options.rb +40 -0
- data/lib/quadtone/tools/rename.rb +17 -0
- data/lib/quadtone/tools/render.rb +43 -0
- data/lib/quadtone/tools/rewrite.rb +15 -0
- data/lib/quadtone/tools/separate.rb +71 -0
- data/lib/quadtone/tools/show.rb +15 -0
- data/lib/quadtone/tools/test.rb +26 -0
- data/qttk.gemspec +34 -0
- metadata +215 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
module Quadtone
|
2
|
+
|
3
|
+
class ToolUsageError < Exception; end
|
4
|
+
|
5
|
+
class Tool
|
6
|
+
|
7
|
+
attr_accessor :profile
|
8
|
+
attr_accessor :verbose
|
9
|
+
|
10
|
+
def self.process_args(args)
|
11
|
+
begin
|
12
|
+
name = args.shift or raise ToolUsageError, "No subcommand specified"
|
13
|
+
klass_name = 'Quadtone::Tools::' + name.split('-').map { |p| p.capitalize }.join
|
14
|
+
begin
|
15
|
+
klass = Kernel.const_get(klass_name)
|
16
|
+
raise NameError unless klass.respond_to?(:process_args)
|
17
|
+
rescue NameError => e
|
18
|
+
raise ToolUsageError, "Unknown subcommand specified: #{name.inspect} (#{klass_name})"
|
19
|
+
end
|
20
|
+
tool = klass.new
|
21
|
+
tool.process_environment
|
22
|
+
tool.load_profile
|
23
|
+
while args.first && args.first[0] == '-'
|
24
|
+
option = args.shift
|
25
|
+
tool.parse_global_option(option, args) or tool.parse_option(option, args) or raise ToolUsageError, "Unknown option for #{name.inspect} tool: #{option}"
|
26
|
+
end
|
27
|
+
tool.run(*args)
|
28
|
+
rescue ToolUsageError => e
|
29
|
+
warn e
|
30
|
+
exit 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def process_environment
|
35
|
+
if (profile_name = ENV['PROFILE'])
|
36
|
+
@profile = Profile.load(profile_name)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_global_option(option, args)
|
41
|
+
case option
|
42
|
+
when '--verbose'
|
43
|
+
@verbose = true
|
44
|
+
when '--profile'
|
45
|
+
@profile = Profile.load(args.shift)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def parse_option(option, args)
|
50
|
+
# overridden by subclass
|
51
|
+
end
|
52
|
+
|
53
|
+
# subclass can override this to avoid requirement of profile being set
|
54
|
+
|
55
|
+
def load_profile
|
56
|
+
raise ToolUsageError, "No profile set" unless @profile
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Quadtone
|
2
|
+
|
3
|
+
module Tools
|
4
|
+
|
5
|
+
class AddPrinter < Tool
|
6
|
+
|
7
|
+
def load_profile
|
8
|
+
false
|
9
|
+
end
|
10
|
+
|
11
|
+
def run(printer)
|
12
|
+
|
13
|
+
#FIXME: move this into Printer class
|
14
|
+
|
15
|
+
unless %x{lpstat -v #{printer} 2>/dev/null}.empty?
|
16
|
+
raise ToolUsageError, "Printer #{printer.inspect} already exists"
|
17
|
+
end
|
18
|
+
|
19
|
+
curves_dir = Pathname.new('/Library/Printers/QTR/quadtone') + printer
|
20
|
+
cups_data_dir = Pathname.new(%x{cups-config --datadir}.chomp)
|
21
|
+
cups_serverbin_dir = Pathname.new(%x{cups-config --serverbin}.chomp)
|
22
|
+
|
23
|
+
model = printer.split(/[-_=]/).first
|
24
|
+
model_ppd = "C/#{model}.ppd.gz"
|
25
|
+
ppd_file = cups_data_dir + 'model' + model_ppd
|
26
|
+
|
27
|
+
raise "QuadToneRIP does not support printer model #{model.inspect}" unless ppd_file.exist?
|
28
|
+
|
29
|
+
uri = loc = nil
|
30
|
+
|
31
|
+
File.popen(cups_serverbin_dir + 'backend' + 'usb').readlines.each do |line|
|
32
|
+
#FIXME: Too fragile -- use 'lpinfo' to find all printers
|
33
|
+
if line =~ /(usb:.*EPSON.*#{Regexp.escape(model.sub(/^Quad/, ''))})/
|
34
|
+
uri = $1
|
35
|
+
loc = "USB Printer"
|
36
|
+
break
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
if uri.nil?
|
41
|
+
loop do
|
42
|
+
print "Enter IP address of IPP printer, or <return> to cancel: "
|
43
|
+
ipp = STDIN.gets.chomp
|
44
|
+
if ipp.empty?
|
45
|
+
warn "Install cancelled."
|
46
|
+
return
|
47
|
+
end
|
48
|
+
if ipp =~ /^\d+\.\d+\.\d+\.\d+$/
|
49
|
+
uri = "lpd://#{ipp}"
|
50
|
+
loc = "Network Printer IPP = #{ipp}"
|
51
|
+
break
|
52
|
+
end
|
53
|
+
warn "Invalid IPP number: #{ipp.inspect}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
warn "Creating printer #{printer.inspect}"
|
58
|
+
system('lpadmin',
|
59
|
+
'-p', printer,
|
60
|
+
'-E',
|
61
|
+
'-m', model_ppd,
|
62
|
+
'-L', loc,
|
63
|
+
'-v', uri)
|
64
|
+
raise "Failed to create printer" unless $? == 0
|
65
|
+
|
66
|
+
curves_dir.mkpath
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Quadtone
|
2
|
+
|
3
|
+
module Tools
|
4
|
+
|
5
|
+
class Characterize < Tool
|
6
|
+
|
7
|
+
attr_accessor :force
|
8
|
+
attr_accessor :remeasure
|
9
|
+
attr_accessor :channel
|
10
|
+
|
11
|
+
def parse_option(option, args)
|
12
|
+
case option
|
13
|
+
when '--force'
|
14
|
+
@force = true
|
15
|
+
when '--remeasure'
|
16
|
+
@remeasure = args.shift.to_i
|
17
|
+
when '--channel'
|
18
|
+
@channels = args.shift.split(',').map(&:to_sym)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def run(*args)
|
23
|
+
case (action = args.shift)
|
24
|
+
when 'build'
|
25
|
+
@profile.characterization_curveset.build_target
|
26
|
+
when 'print'
|
27
|
+
@profile.characterization_curveset.print_target
|
28
|
+
when 'measure'
|
29
|
+
@profile.characterization_curveset.measure_target(force: @force, remeasure: @remeasure, channels: @channels)
|
30
|
+
when 'process'
|
31
|
+
@profile.characterization_curveset.process_target
|
32
|
+
when 'chart'
|
33
|
+
@profile.characterization_curveset.chart_target
|
34
|
+
else
|
35
|
+
raise ToolUsageError, "Unknown action: #{action.inspect}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Quadtone
|
2
|
+
|
3
|
+
module Tools
|
4
|
+
|
5
|
+
class Chart < Tool
|
6
|
+
|
7
|
+
attr_accessor :open
|
8
|
+
attr_accessor :quick_look
|
9
|
+
|
10
|
+
def parse_option(option, args)
|
11
|
+
case option
|
12
|
+
when '--open'
|
13
|
+
@open = true
|
14
|
+
when '--quicklook'
|
15
|
+
@quicklook = true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
html_path = @profile.html_path
|
21
|
+
html_path.open('w') { |io| io.write(profile.to_html) }
|
22
|
+
;;warn "Saved HTML to #{html_path}"
|
23
|
+
system 'open', html_path if @open
|
24
|
+
system 'qlmanage', '-p', html_path if @quick_look
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Quadtone
|
2
|
+
|
3
|
+
module Tools
|
4
|
+
|
5
|
+
class Edit < Tool
|
6
|
+
|
7
|
+
def run
|
8
|
+
# editor = ENV['EDITOR'] or raise "Can't determine editor"
|
9
|
+
editor = 'subl'
|
10
|
+
Quadtone.run(editor,
|
11
|
+
'--wait',
|
12
|
+
@profile.qtr_profile_path)
|
13
|
+
@profile = Profile.load(@profile.qtr_profile_path)
|
14
|
+
@profile.check
|
15
|
+
@profile.save
|
16
|
+
@profile.show
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Quadtone
|
2
|
+
|
3
|
+
module Tools
|
4
|
+
|
5
|
+
class Init < Tool
|
6
|
+
|
7
|
+
def load_profile
|
8
|
+
false
|
9
|
+
end
|
10
|
+
|
11
|
+
def run(*args)
|
12
|
+
get_printer
|
13
|
+
get_printer_options
|
14
|
+
get_inks
|
15
|
+
get_medium
|
16
|
+
profile = Profile.new(printer: @printer, printer_options: @printer_options, inks: @inks, medium: @medium)
|
17
|
+
profile.save
|
18
|
+
;;warn "Created profile #{profile.name.inspect}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_printer
|
22
|
+
printers = CupsPrinter.get_all_printer_names.map { |n| Printer.new(n) }.select(&:quadtone?)
|
23
|
+
@printer = prompt('Printer', printers, printers[0]) { |p| p.name }
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_printer_options
|
27
|
+
@printer_options = {}
|
28
|
+
@printer.options.each do |name, option|
|
29
|
+
if Printer::ImportantOptions.include?(name)
|
30
|
+
choices = option.choices.map { |c| c.choice }
|
31
|
+
default = option.choices.find { |c| c.choice == option.default_choice }
|
32
|
+
@printer_options[name] = prompt(name, choices, default)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_medium
|
38
|
+
media = [
|
39
|
+
'Epson Velvet Fine Art',
|
40
|
+
'Epson Ultra Premium Presentation',
|
41
|
+
'Epson Premium Presentation',
|
42
|
+
'Epson Premium Luster',
|
43
|
+
'Hahnemuhle Bamboo',
|
44
|
+
'Southworth Antique Laid',
|
45
|
+
'Crane Museo',
|
46
|
+
]
|
47
|
+
@medium = prompt('Media', media, media[0])
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_inks
|
51
|
+
@inks = prompt('Inks', @printer.inks, @printer.inks.join(','))
|
52
|
+
@inks = [@inks] unless @inks.kind_of?(Array)
|
53
|
+
end
|
54
|
+
|
55
|
+
def prompt(label, values, default=nil, &block)
|
56
|
+
choices = {}
|
57
|
+
values.each_with_index { |value, i| choices[i + 1] = value }
|
58
|
+
STDERR.puts
|
59
|
+
STDERR.puts "#{label}:"
|
60
|
+
choices.each { |i, value| STDERR.puts '%2d. %s' % [i, block_given? ? yield(value) : value] }
|
61
|
+
STDERR.print "Choice" + (default ? " [#{block_given? ? yield(default) : default}]" : '') + "? "
|
62
|
+
selections = STDIN.gets.chomp
|
63
|
+
if selections.empty?
|
64
|
+
default
|
65
|
+
else
|
66
|
+
selections = selections.split(',').map(&:to_i)
|
67
|
+
case selections.length
|
68
|
+
when 0
|
69
|
+
default
|
70
|
+
when 1
|
71
|
+
choices[selections.first]
|
72
|
+
else
|
73
|
+
selections.map { |s| choices[s] }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Quadtone
|
2
|
+
|
3
|
+
module Tools
|
4
|
+
|
5
|
+
class Linearize < Tool
|
6
|
+
|
7
|
+
def run(*args)
|
8
|
+
case (action = args.shift)
|
9
|
+
when 'build'
|
10
|
+
@profile.linearization_curveset.build_target
|
11
|
+
when 'print'
|
12
|
+
@profile.linearization_curveset.print_target
|
13
|
+
when 'measure'
|
14
|
+
@profile.linearization_curveset.measure_target
|
15
|
+
when 'process'
|
16
|
+
@profile.linearization_curveset.process_target
|
17
|
+
when 'chart'
|
18
|
+
@profile.linearization_curveset.chart_target
|
19
|
+
else
|
20
|
+
raise ToolUsageError, "Unknown action: #{action.inspect}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Quadtone
|
2
|
+
|
3
|
+
module Tools
|
4
|
+
|
5
|
+
class Print < Tool
|
6
|
+
|
7
|
+
attr_accessor :calibrate
|
8
|
+
attr_accessor :printer_options
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super
|
12
|
+
@printer_options = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse_option(option, args)
|
16
|
+
case option
|
17
|
+
when '--calibrate'
|
18
|
+
@calibrate = true
|
19
|
+
when '--option', '--options'
|
20
|
+
@printer_options.merge!(
|
21
|
+
Hash[
|
22
|
+
args.shift.split(',').map { |o| o.split('=') }
|
23
|
+
]
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def run(*args)
|
29
|
+
args.map { |p| Pathname.new(p) }.each do |image_path|
|
30
|
+
@profile.print_file(image_path, calibrate: @calibrate, printer_options: @printer_options)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|