qttk 0.1.0
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.
- 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
|