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,196 @@
|
|
1
|
+
module Quadtone
|
2
|
+
|
3
|
+
class CurveSet
|
4
|
+
|
5
|
+
attr_accessor :profile
|
6
|
+
attr_accessor :channels
|
7
|
+
attr_accessor :type
|
8
|
+
attr_accessor :curves
|
9
|
+
|
10
|
+
def initialize(params={})
|
11
|
+
@curves = []
|
12
|
+
params.each { |key, value| send("#{key}=", value) }
|
13
|
+
raise "Profile must be specified" unless @profile
|
14
|
+
raise "Channels must be specified" unless @channels
|
15
|
+
raise "Type must be specified" unless @type
|
16
|
+
@target = Target.new(name: @type.to_s, channels: @channels, base_dir: @profile.dir_path, type: @type, ink_limits: @profile.ink_limits)
|
17
|
+
generate_scale
|
18
|
+
end
|
19
|
+
|
20
|
+
def build_target
|
21
|
+
@target.build
|
22
|
+
end
|
23
|
+
|
24
|
+
def print_target
|
25
|
+
@profile.print_file(@target.image_file, calibrate: (@type == :characterization), print: true)
|
26
|
+
end
|
27
|
+
|
28
|
+
def measure_target(options={})
|
29
|
+
@target.measure(options)
|
30
|
+
process_target
|
31
|
+
chart_target
|
32
|
+
end
|
33
|
+
|
34
|
+
def process_target
|
35
|
+
case @type
|
36
|
+
when :characterization
|
37
|
+
import_from_target
|
38
|
+
verify_increasing_values
|
39
|
+
set_common_white
|
40
|
+
# trim_to_limits
|
41
|
+
# @profile.ink_limits = Hash[
|
42
|
+
# @curves.map do |curve|
|
43
|
+
# [
|
44
|
+
# curve.channel,
|
45
|
+
# curve.samples.last.input.value
|
46
|
+
# ]
|
47
|
+
# end
|
48
|
+
# ]
|
49
|
+
# normalize_curves
|
50
|
+
@profile.ink_partitions = partitions
|
51
|
+
when :linearization, :test
|
52
|
+
import_from_target
|
53
|
+
if @type == :linearization
|
54
|
+
@profile.linearization = grayscale(21)
|
55
|
+
elsif @type == :test
|
56
|
+
@profile.grayscale = grayscale(21)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
@profile.save
|
60
|
+
@profile.install
|
61
|
+
end
|
62
|
+
|
63
|
+
def chart_target
|
64
|
+
import_from_target
|
65
|
+
out_file = (@profile.dir_path + @type.to_s).with_extname('.html')
|
66
|
+
out_file.open('w') { |io| io.write(to_html) }
|
67
|
+
;;warn "Saved chart to #{out_file.to_s.inspect}"
|
68
|
+
system('qlmanage', '-p', out_file.to_s)
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def import_from_target
|
74
|
+
@target.read
|
75
|
+
@curves.each do |curve|
|
76
|
+
curve.samples = @target.samples[curve.channel]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def generate_scale
|
81
|
+
@curves = @channels.map do |channel|
|
82
|
+
Curve.new(channel: channel, samples: [
|
83
|
+
Sample.new(input: Color::Gray.new(k: 0), output: Color::Lab.new(l: 100)),
|
84
|
+
Sample.new(input: Color::Gray.new(k: 1), output: Color::Lab.new(l: 0))
|
85
|
+
])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def channels
|
90
|
+
@curves.map(&:channel)
|
91
|
+
end
|
92
|
+
|
93
|
+
def verify_increasing_values
|
94
|
+
@curves.each { |c| c.verify_increasing_values }
|
95
|
+
end
|
96
|
+
|
97
|
+
def trim_to_limits
|
98
|
+
@curves.each { |c| c.trim_to_limit }
|
99
|
+
end
|
100
|
+
|
101
|
+
def normalize_curves
|
102
|
+
@curves.each { |c| c.normalize_inputs }
|
103
|
+
end
|
104
|
+
|
105
|
+
# find average shade of paper, and update each curve to have that average as its first value
|
106
|
+
|
107
|
+
def set_common_white
|
108
|
+
samples = samples_with_value(0)
|
109
|
+
outputs = samples.map(&:output)
|
110
|
+
average, error = Color::Lab.average(outputs)
|
111
|
+
raise "too much variance in white samples: average = #{average}, error = #{error}" if error >= 1
|
112
|
+
samples.each { |s| s.output = average }
|
113
|
+
end
|
114
|
+
|
115
|
+
def samples_with_value(value)
|
116
|
+
@curves.map { |c| c.samples.find { |s| s.input_value == value } }.compact.flatten
|
117
|
+
end
|
118
|
+
|
119
|
+
def partitions
|
120
|
+
partitions = {}
|
121
|
+
previous_curve = nil
|
122
|
+
@curves.sort_by(&:dmax).reverse.each do |curve|
|
123
|
+
;;warn "processing #{curve.channel}"
|
124
|
+
last_sample = curve.samples.last
|
125
|
+
if previous_curve
|
126
|
+
partitions[curve.channel] = previous_curve.input_for_output(last_sample.output.value) * partitions[previous_curve.channel]
|
127
|
+
;;warn "\t" + "value on previous curve for dmax #{last_sample.output.value} = #{partitions[curve.channel]}"
|
128
|
+
else
|
129
|
+
partitions[curve.channel] = last_sample.input.value
|
130
|
+
;;warn "\t" + "using absolute value of curve for dmax #{last_sample.output.value} = #{partitions[curve.channel]}"
|
131
|
+
end
|
132
|
+
previous_curve = curve
|
133
|
+
end
|
134
|
+
partitions
|
135
|
+
end
|
136
|
+
|
137
|
+
def grayscale(steps)
|
138
|
+
raise "Can't get gray scale of non-grayscale curveset" if @channels.length > 1
|
139
|
+
@curves.first.grayscale(steps)
|
140
|
+
end
|
141
|
+
|
142
|
+
def to_html
|
143
|
+
html = Builder::XmlMarkup.new(indent: 2)
|
144
|
+
html.div do
|
145
|
+
html.ul do
|
146
|
+
html.li("Channels: #{@channels.join(', ')}")
|
147
|
+
end
|
148
|
+
html.h3('Curve set:')
|
149
|
+
html.table(border: 1) do
|
150
|
+
html.tr do
|
151
|
+
[
|
152
|
+
'channel',
|
153
|
+
'ink limit',
|
154
|
+
'density: min',
|
155
|
+
'density: max',
|
156
|
+
'density: range',
|
157
|
+
].each { |s| html.th(s) }
|
158
|
+
end
|
159
|
+
@curves.each do |curve|
|
160
|
+
html.tr do
|
161
|
+
dmin, dmax = curve.dynamic_range
|
162
|
+
[
|
163
|
+
curve.channel.to_s,
|
164
|
+
curve.ink_limit.input,
|
165
|
+
'%.2f' % dmin,
|
166
|
+
'%.2f' % dmax,
|
167
|
+
'%.2f' % (dmax - dmin),
|
168
|
+
].each { |s| html.td(s) }
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
html << to_svg
|
173
|
+
end
|
174
|
+
html.target!
|
175
|
+
end
|
176
|
+
|
177
|
+
def to_svg(options={})
|
178
|
+
size = options[:size] || 500
|
179
|
+
svg = Builder::XmlMarkup.new(indent: 2)
|
180
|
+
svg.svg(xmlns: 'http://www.w3.org/2000/svg', version: '1.1') do
|
181
|
+
svg.g(width: size, height: size, transform: "translate(0,#{size}) scale(1,-1)") do
|
182
|
+
svg.g(stroke: 'blue') do
|
183
|
+
svg.rect(x: 0, y: 0, width: size, height: size, fill: 'none', :'stroke-width' => 1)
|
184
|
+
svg.line(x1: 0, y1: 0, x2: size, y2: size, :'stroke-width' => 0.5)
|
185
|
+
end
|
186
|
+
@curves.each do |curve|
|
187
|
+
curve.draw_svg(svg, options)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
svg.target!
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Quadtone
|
2
|
+
|
3
|
+
class Printer
|
4
|
+
|
5
|
+
ImportantOptions = %i{
|
6
|
+
MediaType
|
7
|
+
Resolution
|
8
|
+
ripBlack
|
9
|
+
ripSpeed
|
10
|
+
stpDither
|
11
|
+
}
|
12
|
+
|
13
|
+
attr_accessor :name
|
14
|
+
attr_accessor :options
|
15
|
+
attr_accessor :attributes
|
16
|
+
attr_accessor :inks
|
17
|
+
|
18
|
+
def initialize(name)
|
19
|
+
@name = name
|
20
|
+
@cups_ppd = CupsPPD.new(@name, nil)
|
21
|
+
@options = Hash[
|
22
|
+
@cups_ppd.options.map { |o| [o.delete(:keyword).to_sym, HashStruct.new(o)] }
|
23
|
+
]
|
24
|
+
@attributes = Hash[
|
25
|
+
@cups_ppd.attributes.map { |a| [a.delete(:name).to_sym, HashStruct.new(a)] }
|
26
|
+
]
|
27
|
+
@cups_printer = CupsPrinter.new(@name)
|
28
|
+
get_inks
|
29
|
+
end
|
30
|
+
|
31
|
+
def quadtone?
|
32
|
+
@attributes[:Manufacturer].value == 'QuadToneRIP'
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_inks
|
36
|
+
# FIXME: It would be nice to get this path programmatically.
|
37
|
+
ppd_file = Pathname.new("/etc/cups/ppd/#{@name}.ppd")
|
38
|
+
ppd_file.readlines.each do |line|
|
39
|
+
if line =~ /^\*%Inks\s*(.*?)\s*$/
|
40
|
+
@inks = $1.split(/,/).map(&:downcase).map(&:to_sym)
|
41
|
+
break
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def page_size(name=nil)
|
47
|
+
name ||= @cups_ppd.attribute('DefaultPageSize').first[:value]
|
48
|
+
page_size = @cups_ppd.page_size(name) or raise "Can't determine page size #{name.inspect}"
|
49
|
+
size = HashStruct.new(page_size)
|
50
|
+
# change 'length' to 'height', or else there are problems with Hash#length
|
51
|
+
size[:height] = size.delete(:length)
|
52
|
+
size = HashStruct.new(size)
|
53
|
+
size.imageable_width = size.margin.right - size.margin.left
|
54
|
+
size.imageable_height = size.margin.top - size.margin.bottom
|
55
|
+
size
|
56
|
+
end
|
57
|
+
|
58
|
+
def default_options
|
59
|
+
Hash[
|
60
|
+
@options.map do |name, option|
|
61
|
+
[name, option.default_choice]
|
62
|
+
end
|
63
|
+
]
|
64
|
+
end
|
65
|
+
|
66
|
+
def show_attributes
|
67
|
+
puts "Attributes:"
|
68
|
+
max_field_length = @attributes.keys.map(&:length).max
|
69
|
+
@attributes.sort_by { |name, info| name }.each do |name, attribute|
|
70
|
+
puts "\t" + "%#{max_field_length}s: %s%s" % [
|
71
|
+
name,
|
72
|
+
attribute.value.inspect,
|
73
|
+
attribute.spec.empty? ? '' : " [#{attribute.spec.inspect}]"
|
74
|
+
]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def show_options
|
79
|
+
puts "Options:"
|
80
|
+
max_field_length = @options.keys.map(&:length).max
|
81
|
+
@options.sort_by { |name, option| name }.each do |name, option|
|
82
|
+
puts "\t" + "%#{max_field_length}s: %s [%s]" % [
|
83
|
+
name,
|
84
|
+
option.default_choice.inspect,
|
85
|
+
(option.choices.map { |o| o.choice } - [option.default_choice]).map { |o| o.inspect }.join(', ')
|
86
|
+
]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def show_inks
|
91
|
+
puts "Inks:"
|
92
|
+
puts "\t" + @inks.map { |ink| ink.to_s.upcase }.join(', ')
|
93
|
+
end
|
94
|
+
|
95
|
+
def print_file(path, options)
|
96
|
+
warn "Printing #{path}"
|
97
|
+
warn "Options:"
|
98
|
+
options.each do |key, value|
|
99
|
+
warn "\t" + "%10s: %s" % [key, value]
|
100
|
+
end
|
101
|
+
@cups_printer.print_file(path, options)
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
module Quadtone
|
2
|
+
|
3
|
+
class Profile
|
4
|
+
|
5
|
+
attr_accessor :printer
|
6
|
+
attr_accessor :printer_options
|
7
|
+
attr_accessor :medium
|
8
|
+
attr_accessor :inks
|
9
|
+
attr_accessor :ink_partitions
|
10
|
+
attr_accessor :ink_limits
|
11
|
+
attr_accessor :linearization
|
12
|
+
attr_accessor :default_ink_limit
|
13
|
+
attr_accessor :gray_highlight
|
14
|
+
attr_accessor :gray_shadow
|
15
|
+
attr_accessor :gray_overlap
|
16
|
+
attr_accessor :gray_gamma
|
17
|
+
attr_accessor :characterization_curveset
|
18
|
+
attr_accessor :linearization_curveset
|
19
|
+
attr_accessor :test_curveset
|
20
|
+
|
21
|
+
ProfilesDir = BaseDir + 'profiles'
|
22
|
+
ProfileName = 'profile.txt'
|
23
|
+
|
24
|
+
def self.profile_names
|
25
|
+
Pathname.glob(ProfilesDir + '*').select { |p| p.directory? && p[0] != '.' }.map(&:basename)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.load(name)
|
29
|
+
profile = Profile.new
|
30
|
+
profile.load(name)
|
31
|
+
profile
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(params={})
|
35
|
+
@printer_options = nil
|
36
|
+
@default_ink_limit = 1.0
|
37
|
+
@ink_limits = {}
|
38
|
+
@ink_partitions = {}
|
39
|
+
@gray_highlight = 0.06
|
40
|
+
@gray_shadow = 0.06
|
41
|
+
@gray_overlap = 0.10
|
42
|
+
@gray_gamma = 1.0
|
43
|
+
params.each { |key, value| send("#{key}=", value) }
|
44
|
+
end
|
45
|
+
|
46
|
+
def name
|
47
|
+
[
|
48
|
+
@printer.name.gsub(/[^-A-Z0-9]/i, ''),
|
49
|
+
@medium.gsub(/[^-A-Z0-9]/i, ''),
|
50
|
+
].flatten.join('-')
|
51
|
+
end
|
52
|
+
|
53
|
+
def load(name)
|
54
|
+
inks_by_num = []
|
55
|
+
(ProfilesDir + name + ProfileName).readlines.each do |line|
|
56
|
+
line.chomp!
|
57
|
+
line.sub!(/#.*/, '')
|
58
|
+
line.strip!
|
59
|
+
next if line.empty?
|
60
|
+
key, value = line.split('=', 2)
|
61
|
+
case key
|
62
|
+
when 'PRINTER'
|
63
|
+
@printer = Printer.new(value)
|
64
|
+
when 'PRINTER_OPTIONS'
|
65
|
+
@printer_options = Hash[ value.split(',').map { |o| o.split('=') } ]
|
66
|
+
when 'MEDIUM'
|
67
|
+
@medium = value
|
68
|
+
when 'GRAPH_CURVE'
|
69
|
+
# ignore
|
70
|
+
when 'N_OF_INKS'
|
71
|
+
# ignore
|
72
|
+
when 'INKS'
|
73
|
+
@inks = value.split(',').map(&:downcase).map(&:to_sym)
|
74
|
+
when 'DEFAULT_INK_LIMIT'
|
75
|
+
@default_ink_limit = value.to_f / 100
|
76
|
+
when /^LIMIT_(.+)$/
|
77
|
+
@ink_limits[$1.downcase.to_sym] = value.to_f / 100
|
78
|
+
when 'N_OF_GRAY_PARTS'
|
79
|
+
# ignore
|
80
|
+
when /^GRAY_INK_(\d+)$/
|
81
|
+
i = $1.to_i - 1
|
82
|
+
inks_by_num[i] = value.downcase.to_sym
|
83
|
+
when /^GRAY_VAL_(\d+)$/
|
84
|
+
i = $1.to_i - 1
|
85
|
+
ink = inks_by_num[i]
|
86
|
+
@ink_partitions[ink] = value.to_f / 100
|
87
|
+
when 'GRAY_HIGHLIGHT'
|
88
|
+
@gray_highlight = value.to_f / 100
|
89
|
+
when 'GRAY_SHADOW'
|
90
|
+
@gray_shadow = value.to_f / 100
|
91
|
+
when 'GRAY_OVERLAP'
|
92
|
+
@gray_overlap = value.to_f / 100
|
93
|
+
when 'GRAY_GAMMA'
|
94
|
+
@gray_gamma = value.to_f
|
95
|
+
when 'LINEARIZE'
|
96
|
+
@linearization = value.gsub('"', '').split(/\s+/).map { |v| Color::Lab.new([v.to_f]) }
|
97
|
+
else
|
98
|
+
warn "Unknown key in QTR profile: #{key.inspect}"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
@characterization_curveset = CurveSet.new(channels: @inks, profile: self, type: :characterization)
|
102
|
+
@linearization_curveset = CurveSet.new(channels: [:k], profile: self, type: :linearization)
|
103
|
+
end
|
104
|
+
|
105
|
+
def save
|
106
|
+
qtr_profile_path.dirname.mkpath
|
107
|
+
qtr_profile_path.open('w') do |io|
|
108
|
+
io.puts "PRINTER=#{@printer.name}"
|
109
|
+
io.puts "PRINTER_OPTIONS=#{@printer_options.map { |k, v| [k, v].join('=') }.join(',')}" if @printer_options
|
110
|
+
io.puts "MEDIUM=#{@medium}"
|
111
|
+
io.puts "GRAPH_CURVE=YES"
|
112
|
+
io.puts "INKS=#{@inks.join(',')}"
|
113
|
+
io.puts "N_OF_INKS=#{@inks.length}"
|
114
|
+
io.puts "DEFAULT_INK_LIMIT=#{@default_ink_limit * 100}"
|
115
|
+
@ink_limits.each do |ink, limit|
|
116
|
+
io.puts "LIMIT_#{ink.upcase}=#{limit * 100}"
|
117
|
+
end
|
118
|
+
io.puts "N_OF_GRAY_PARTS=#{@ink_partitions.length}"
|
119
|
+
@ink_partitions.each_with_index do |partition, i|
|
120
|
+
ink, value = *partition
|
121
|
+
io.puts "GRAY_INK_#{i+1}=#{ink.upcase}"
|
122
|
+
io.puts "GRAY_VAL_#{i+1}=#{value * 100}"
|
123
|
+
end
|
124
|
+
io.puts "GRAY_HIGHLIGHT=#{@gray_highlight * 100}"
|
125
|
+
io.puts "GRAY_SHADOW=#{@gray_shadow * 100}"
|
126
|
+
io.puts "GRAY_OVERLAP=#{@gray_overlap * 100}"
|
127
|
+
io.puts "GRAY_GAMMA=#{@gray_gamma}"
|
128
|
+
io.puts "LINEARIZE=\"#{@linearization.map(&:l).join(' ')}\"" if @linearization
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def dir_path
|
133
|
+
ProfilesDir + name
|
134
|
+
end
|
135
|
+
|
136
|
+
def qtr_profile_path
|
137
|
+
dir_path + ProfileName
|
138
|
+
end
|
139
|
+
|
140
|
+
def quad_file_path
|
141
|
+
Pathname.new('/Library/Printers/QTR/quadtone') + @printer.name + "#{name}.quad"
|
142
|
+
end
|
143
|
+
|
144
|
+
def ink_limit(ink)
|
145
|
+
@ink_limits[ink] || @default_ink_limit
|
146
|
+
end
|
147
|
+
|
148
|
+
def install
|
149
|
+
# filename needs to match name of profile for quadprofile to install it properly,
|
150
|
+
# so temporarily make a symlink
|
151
|
+
tmp_file = Pathname.new('/tmp') + "#{name}.txt"
|
152
|
+
qtr_profile_path.symlink(tmp_file)
|
153
|
+
system('/Library/Printers/QTR/bin/quadprofile', tmp_file)
|
154
|
+
tmp_file.unlink
|
155
|
+
end
|
156
|
+
|
157
|
+
def print_file(input_path, options={})
|
158
|
+
options = HashStruct.new(options)
|
159
|
+
printer_options = @printer_options.dup
|
160
|
+
if options.printer_options
|
161
|
+
options.printer_options.each do |key, value|
|
162
|
+
printer_options[key.to_s] = value
|
163
|
+
end
|
164
|
+
end
|
165
|
+
if options.calibrate
|
166
|
+
printer_options['ColorModel'] = 'QTCAL'
|
167
|
+
else
|
168
|
+
printer_options['ripCurve1'] = name
|
169
|
+
end
|
170
|
+
@printer.print_file(input_path, printer_options)
|
171
|
+
end
|
172
|
+
|
173
|
+
def show
|
174
|
+
puts "Profile: #{name}"
|
175
|
+
puts "Printer: #{@printer.name}"
|
176
|
+
puts "Printer options:"
|
177
|
+
@printer_options.each do |key, value|
|
178
|
+
puts "\t" + "#{key}: #{value}"
|
179
|
+
end
|
180
|
+
puts "Medium: #{@medium}"
|
181
|
+
puts "Inks: #{@inks.join(', ')}"
|
182
|
+
puts "Default ink limit: #{@default_ink_limit}"
|
183
|
+
puts "Ink limits:"
|
184
|
+
@ink_limits.each do |ink, limit|
|
185
|
+
puts "\t" + "#{ink.upcase}: #{limit}"
|
186
|
+
end
|
187
|
+
puts "Gray settings:"
|
188
|
+
puts "\t" + "Highlight: #{@gray_highlight}"
|
189
|
+
puts "\t" + "Shadow: #{@gray_shadow}"
|
190
|
+
puts "\t" + "Overlap: #{@gray_overlap}"
|
191
|
+
puts "Gray gamma: #{@gray_gamma}"
|
192
|
+
puts "Ink partitions:"
|
193
|
+
@ink_partitions.each do |ink, value|
|
194
|
+
puts "\t" + "#{ink.upcase}: #{value}"
|
195
|
+
end
|
196
|
+
puts "Linearization: #{@linearization.join(', ')}" if @linearization
|
197
|
+
end
|
198
|
+
|
199
|
+
def to_html
|
200
|
+
html = Builder::XmlMarkup.new(indent: 2)
|
201
|
+
html.html do
|
202
|
+
html.head do
|
203
|
+
end
|
204
|
+
html.body do
|
205
|
+
html.h1("Profile: #{name}")
|
206
|
+
end
|
207
|
+
end
|
208
|
+
html.target!
|
209
|
+
end
|
210
|
+
|
211
|
+
def check
|
212
|
+
#FIXME: check values
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
end
|