qttk 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/Gemfile +6 -0
  4. data/Gemfile.lock +36 -0
  5. data/README.markdown +131 -0
  6. data/Rakefile +17 -0
  7. data/TODO.markdown +236 -0
  8. data/bin/qt +7 -0
  9. data/etc/gutenprint/gp-tool.rb +56 -0
  10. data/etc/gutenprint/gutenprint-filter.c +400 -0
  11. data/etc/gutenprint/gutenprint.rb +86 -0
  12. data/etc/gutenprint/stp-test +326 -0
  13. data/etc/images/3551599565_db282cf840_o.jpg +0 -0
  14. data/etc/images/4843122063_d582c569e9_o.jpg +0 -0
  15. data/etc/images/4843128953_83c1770907_o.jpg +0 -0
  16. data/lib/quadtone.rb +56 -0
  17. data/lib/quadtone/cgats.rb +137 -0
  18. data/lib/quadtone/cluster_calculator.rb +81 -0
  19. data/lib/quadtone/color.rb +83 -0
  20. data/lib/quadtone/color/cmyk.rb +112 -0
  21. data/lib/quadtone/color/device_n.rb +23 -0
  22. data/lib/quadtone/color/gray.rb +46 -0
  23. data/lib/quadtone/color/lab.rb +150 -0
  24. data/lib/quadtone/color/qtr.rb +71 -0
  25. data/lib/quadtone/color/rgb.rb +71 -0
  26. data/lib/quadtone/color/xyz.rb +80 -0
  27. data/lib/quadtone/curve.rb +138 -0
  28. data/lib/quadtone/curve_set.rb +196 -0
  29. data/lib/quadtone/descendants.rb +9 -0
  30. data/lib/quadtone/environment.rb +5 -0
  31. data/lib/quadtone/extensions/math.rb +11 -0
  32. data/lib/quadtone/extensions/pathname3.rb +11 -0
  33. data/lib/quadtone/printer.rb +106 -0
  34. data/lib/quadtone/profile.rb +217 -0
  35. data/lib/quadtone/quad_file.rb +59 -0
  36. data/lib/quadtone/renderer.rb +139 -0
  37. data/lib/quadtone/run.rb +10 -0
  38. data/lib/quadtone/sample.rb +32 -0
  39. data/lib/quadtone/separator.rb +36 -0
  40. data/lib/quadtone/target.rb +277 -0
  41. data/lib/quadtone/tool.rb +61 -0
  42. data/lib/quadtone/tools/add_printer.rb +73 -0
  43. data/lib/quadtone/tools/characterize.rb +43 -0
  44. data/lib/quadtone/tools/chart.rb +31 -0
  45. data/lib/quadtone/tools/check.rb +16 -0
  46. data/lib/quadtone/tools/dir.rb +15 -0
  47. data/lib/quadtone/tools/edit.rb +23 -0
  48. data/lib/quadtone/tools/init.rb +82 -0
  49. data/lib/quadtone/tools/install.rb +15 -0
  50. data/lib/quadtone/tools/linearize.rb +28 -0
  51. data/lib/quadtone/tools/list.rb +19 -0
  52. data/lib/quadtone/tools/print.rb +38 -0
  53. data/lib/quadtone/tools/printer_options.rb +40 -0
  54. data/lib/quadtone/tools/rename.rb +17 -0
  55. data/lib/quadtone/tools/render.rb +43 -0
  56. data/lib/quadtone/tools/rewrite.rb +15 -0
  57. data/lib/quadtone/tools/separate.rb +71 -0
  58. data/lib/quadtone/tools/show.rb +15 -0
  59. data/lib/quadtone/tools/test.rb +26 -0
  60. data/qttk.gemspec +34 -0
  61. 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,16 @@
1
+ module Quadtone
2
+
3
+ module Tools
4
+
5
+ class Check < Tool
6
+
7
+ def run
8
+ @profile.check
9
+ ;;warn "Profile checks out okay."
10
+ end
11
+
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,15 @@
1
+ module Quadtone
2
+
3
+ module Tools
4
+
5
+ class Dir < Tool
6
+
7
+ def run
8
+ puts @profile.dir_path
9
+ end
10
+
11
+ end
12
+
13
+ end
14
+
15
+ 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,15 @@
1
+ module Quadtone
2
+
3
+ module Tools
4
+
5
+ class Install < Tool
6
+
7
+ def run
8
+ @profile.install
9
+ end
10
+
11
+ end
12
+
13
+ end
14
+
15
+ 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,19 @@
1
+ module Quadtone
2
+
3
+ module Tools
4
+
5
+ class List < Tool
6
+
7
+ def load_profile
8
+ false
9
+ end
10
+
11
+ def run
12
+ Profile.profile_names.each { |name| puts name }
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+
19
+ 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