Class: IsDark

Inherits:
Object
  • Object
show all
Defined in:
lib/is_dark.rb

Constant Summary collapse

BLUE_LUMINANCE_COEFFICIENT =
0.0722
GREEN_LUMINANCE_COEFFICIENT =
0.7152
HIGH_LUMINANCE_DIVIDER =
1.055
HIGH_LUMINANCE_POWER =
2.4
LOW_LUMINANCE_DIVIDER =
12.92
LUMINANCE_THRESHOLD =
0.05
MAXIMUM_COLOR_DEPTH =
255
MAX_COLOR_VALUE_MULTIPLIER =
655
MAX_COLOR_VALUE =
MAX_COLOR_VALUE_MULTIPLIER * MAXIMUM_COLOR_DEPTH
LINEAR_LUMINANCE_THRESHOLD =
(1 / (LOW_LUMINANCE_DIVIDER * 100.0)) * MAXIMUM_COLOR_DEPTH
NONLINEAR_TRANSFORM_DIVIDER =
1.055
NONLINEAR_TRANSFORM_OFFSET =
0.055
RED_LUMINANCE_COEFFICIENT =
0.2126

Class Method Summary collapse

Class Method Details

.color(hex) ⇒ Object



27
28
29
30
31
# File 'lib/is_dark.rb', line 27

def self.color(hex)
  @r, @g, @b = hex.match(/^#(..)(..)(..)$/).captures.map(&:hex)
  @colorset = MAXIMUM_COLOR_DEPTH
  is_dark
end

.draw_debug_files(image, x, y, oldx, oldy) ⇒ Object



97
98
99
100
101
102
103
104
105
# File 'lib/is_dark.rb', line 97

def self.draw_debug_files(image, x, y, oldx, oldy)
  return unless oldx && oldy

  gc = Magick::Draw.new
  gc.line(x, y, oldx, oldy)
  gc.stroke('black')
  gc.draw(image)
  image.write(@debug_file_path)
end

.is_dark(x = nil, y = nil, set_not_detected_light = true) ⇒ Object

detects a dark color based on luminance W3 standarts ( www.w3.org/TR/WCAG20/#relativeluminancedef )



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/is_dark.rb', line 108

def self.is_dark(x = nil, y = nil, set_not_detected_light = true)
  dark = false
  inverted = false
  pixel = [@r.to_f, @g.to_f, @b.to_f]
  return true if pixel == [0.00, 0.00, 0.00] #hardcoded exception
  # probably not detected pixel color by Imagick, will be considered as "white" if "set_not_detected_light = true"
  if set_not_detected_light && pixel[0] == 0.0 && pixel[1] == 0.0 && pixel[2] == 0.0
    pixel = [MAXIMUM_COLOR_DEPTH, MAXIMUM_COLOR_DEPTH, MAXIMUM_COLOR_DEPTH]
    inverted = true
  end
  calculated = []
  pixel.each do |color|
    color /= @colorset
    if color <= LINEAR_LUMINANCE_THRESHOLD
      color /= LOW_LUMINANCE_DIVIDER
    else
      color = ((color + NONLINEAR_TRANSFORM_OFFSET) / NONLINEAR_TRANSFORM_DIVIDER)**HIGH_LUMINANCE_POWER
    end
    calculated << color
  end
  l = RED_LUMINANCE_COEFFICIENT * calculated[0] +
      GREEN_LUMINANCE_COEFFICIENT * calculated[1] +
      BLUE_LUMINANCE_COEFFICIENT * calculated[2]
  dark = true if l <= LUMINANCE_THRESHOLD
  if @with_debug
    debug = { 'X': x, 'Y': y, 'R': @r, 'G': @g, 'B': @b, 'luminance value': l, 'is_dark': dark,
              'inverted to white': inverted }
    p debug
  end
  dark
end

.magick_area_from_blob(x, y, blob, height, width, percent = 80, range = (0..10), set_not_detected_light = true) ⇒ Object

(x, y) is the left corner of an element over a blob, height and width is the element’s size



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/is_dark.rb', line 48

def self.magick_area_from_blob(x, y, blob, height, width, percent = 80, range = (0..10), set_not_detected_light = true)
  @set_not_detected_light = set_not_detected_light
  image = Magick::Image.read(blob).first
  dark = false
  dots = []
  range.each do |xx|
    range.each do |yy|
      dots << { 'x': (x + width * xx / 10).to_i, 'y': (y + height * yy / 10).to_i }
    end
  end

  points = 0
  if @with_debug_file
    oldx = false
    oldy = false
  end
  p '====================================================================' if @with_debug
  dots.each do |dot|
    x = dot[:x].to_i
    y = dot[:y].to_i
    pix = image.pixel_color(x, y)
    l = magick_pixel(pix, x, y, set_not_detected_light)
    points += 1 if l
    next unless @with_debug_file

    draw_debug_files(image, x, y, oldx, oldy)
    oldy = y
    oldx = x
  end
  dark = true if points >= (dots.length / 100) * percent
  if @with_debug
    p '===================================================================='
    p "Total Points: #{dots.length}, dark points amount:#{points}"
    p "Is \"invert to white not detectd pixels\" option enabled?:#{set_not_detected_light}"
    p "Signature will be inverted if #{percent}% of dots will be dark"
    p "Is inverted?: #{dark}"
    p '===================================================================='
  end
  dark
end

.magick_pixel(pix, x = nil, y = nil, set_not_detected_light = true) ⇒ Object



33
34
35
36
37
38
39
# File 'lib/is_dark.rb', line 33

def self.magick_pixel(pix, x = nil, y = nil, set_not_detected_light = true)
  @r = pix.red.to_f
  @g = pix.green.to_f
  @b = pix.blue.to_f
  @colorset = MAX_COLOR_VALUE
  is_dark(x, y, set_not_detected_light)
end

.magick_pixel_from_blob(x, y, blob, _set_not_detected_light = true) ⇒ Object



41
42
43
44
45
# File 'lib/is_dark.rb', line 41

def self.magick_pixel_from_blob(x, y, blob, _set_not_detected_light = true)
  image = Magick::Image.read(blob).first
  pix = image.pixel_color(x, y)
  magick_pixel(pix, x, y)
end

.set_debug_data(show_info = false, draw_file = false) ⇒ Object



89
90
91
92
93
94
95
# File 'lib/is_dark.rb', line 89

def self.set_debug_data(show_info = false, draw_file = false)
  @with_debug = show_info
  return unless draw_file != false

  @with_debug_file = true
  @debug_file_path = draw_file
end