class Quadtone::CurveSet

Attributes

channels[RW]
curves[RW]
profile[RW]
type[RW]

Public Class Methods

new(params={}) click to toggle source
# File lib/quadtone/curve_set.rb, line 10
def initialize(params={})
  @curves = []
  params.each { |key, value| send("#{key}=", value) }
  raise "Profile must be specified" unless @profile
  raise "Channels must be specified" unless @channels
  raise "Type must be specified" unless @type
  @target = Target.new(name: @type.to_s, channels: @channels, base_dir: @profile.dir_path, type: @type, ink_limits: @profile.ink_limits)
  generate_scale
end

Public Instance Methods

build_target() click to toggle source
# File lib/quadtone/curve_set.rb, line 20
def build_target
  @target.build
end
chart_target() click to toggle source
# File lib/quadtone/curve_set.rb, line 63
def chart_target
  import_from_target
  out_file = (@profile.dir_path / @type.to_s).with_extname('.html')
  out_file.open('w') { |io| io.write(to_html) }
  ;;warn "Saved chart to #{out_file.to_s.inspect}"
  system('qlmanage', '-p', out_file.to_s)
end
measure_target(options={}) click to toggle source
# File lib/quadtone/curve_set.rb, line 28
def measure_target(options={})
  @target.measure(options)
  process_target
  chart_target
end
print_target() click to toggle source
process_target() click to toggle source
# File lib/quadtone/curve_set.rb, line 34
def process_target
  case @type
  when :characterization
    import_from_target
    verify_increasing_values
    set_common_white
    # trim_to_limits
    # @profile.ink_limits = Hash[
    #   @curves.map do |curve|
    #     [
    #       curve.channel,
    #       curve.samples.last.input.value
    #     ]
    #   end
    # ]
    # normalize_curves
    @profile.ink_partitions = partitions
  when :linearization, :test
    import_from_target
    if @type == :linearization
      @profile.linearization = grayscale(21)
    elsif @type == :test
      @profile.grayscale = grayscale(21)
    end
  end
  @profile.save
  @profile.install
end

Private Instance Methods

generate_scale() click to toggle source
# File lib/quadtone/curve_set.rb, line 80
def generate_scale
  @curves = @channels.map do |channel|
    Curve.new(channel: channel, samples: [
      Sample.new(input: Color::Gray.new(k: 0), output: Color::Lab.new(l: 100)),
      Sample.new(input: Color::Gray.new(k: 1), output: Color::Lab.new(l: 0))
    ])
  end
end
grayscale(steps) click to toggle source
# File lib/quadtone/curve_set.rb, line 137
def grayscale(steps)
  raise "Can't get gray scale of non-grayscale curveset" if @channels.length > 1
  @curves.first.grayscale(steps)
end
import_from_target() click to toggle source
# File lib/quadtone/curve_set.rb, line 73
def import_from_target
  @target.read
  @curves.each do |curve|
    curve.samples = @target.samples[curve.channel]
  end
end
normalize_curves() click to toggle source
# File lib/quadtone/curve_set.rb, line 101
def normalize_curves
  @curves.each { |c| c.normalize_inputs }
end
partitions() click to toggle source
# File lib/quadtone/curve_set.rb, line 119
def partitions
  partitions = {}
  previous_curve = nil
  @curves.sort_by(&:dmax).reverse.each do |curve|
    ;;warn "processing #{curve.channel}"
    last_sample = curve.samples.last
    if previous_curve
      partitions[curve.channel] = previous_curve.input_for_output(last_sample.output.value) * partitions[previous_curve.channel]
      ;;warn "\t" + "value on previous curve for dmax #{last_sample.output.value} = #{partitions[curve.channel]}"
    else
      partitions[curve.channel] = last_sample.input.value
      ;;warn "\t" + "using absolute value of curve for dmax #{last_sample.output.value} = #{partitions[curve.channel]}"
    end
    previous_curve = curve
  end
  partitions
end
samples_with_value(value) click to toggle source
# File lib/quadtone/curve_set.rb, line 115
def samples_with_value(value)
  @curves.map { |c| c.samples.find { |s| s.input_value == value } }.compact.flatten
end
set_common_white() click to toggle source

find average shade of paper, and update each curve to have that average as its first value

# File lib/quadtone/curve_set.rb, line 107
def set_common_white
  samples = samples_with_value(0)
  outputs = samples.map(&:output)
  average, error = Color::Lab.average(outputs)
  raise "too much variance in white samples: average = #{average}, error = #{error}" if error >= 1
  samples.each { |s| s.output = average }
end
to_html() click to toggle source
# File lib/quadtone/curve_set.rb, line 142
def to_html
  html = Builder::XmlMarkup.new(indent: 2)
  html.div do
    html.ul do
      html.li("Channels: #{@channels.join(', ')}")
    end
    html.h3('Curve set:')
    html.table(border: 1) do
      html.tr do
        [
          'channel',
          'ink limit',
          'density: min',
          'density: max',
          'density: range',
        ].each { |s| html.th(s) }
      end
      @curves.each do |curve|
        html.tr do
          dmin, dmax = curve.dynamic_range
          [
            curve.channel.to_s,
            curve.ink_limit.input,
            '%.2f' % dmin,
            '%.2f' % dmax,
            '%.2f' % (dmax - dmin),
          ].each { |s| html.td(s) }
        end
      end
    end
    html << to_svg
  end
  html.target!
end
to_svg(options={}) click to toggle source
# File lib/quadtone/curve_set.rb, line 177
def to_svg(options={})
  size = options[:size] || 500
  svg = Builder::XmlMarkup.new(indent: 2)
  svg.svg(xmlns: 'http://www.w3.org/2000/svg', version: '1.1') do
    svg.g(width: size, height: size, transform: "translate(0,#{size}) scale(1,-1)") do
      svg.g(stroke: 'blue') do
        svg.rect(x: 0, y: 0, width: size, height: size, fill: 'none', :'stroke-width' => 1)
        svg.line(x1: 0, y1: 0, x2: size, y2: size, :'stroke-width' => 0.5)
      end
      @curves.each do |curve|
        curve.draw_svg(svg, options)
      end
    end
  end
  svg.target!
end
trim_to_limits() click to toggle source
# File lib/quadtone/curve_set.rb, line 97
def trim_to_limits
  @curves.each { |c| c.trim_to_limit }
end
verify_increasing_values() click to toggle source
# File lib/quadtone/curve_set.rb, line 93
def verify_increasing_values
  @curves.each { |c| c.verify_increasing_values }
end