Skip to content

Commit

Permalink
refactoring to have settings and initialize
Browse files Browse the repository at this point in the history
  • Loading branch information
butteff committed Dec 30, 2024
1 parent 296d1e9 commit 8f89f5d
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 70 deletions.
32 changes: 17 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# is_dark Ruby Gem
Ruby Gem to detect a dark color over an area from a blob of a file or by a color hex code based on [luminance w3 standarts]( https://www.w3.org/TR/WCAG20/#relativeluminancedef "luminance w3 standarts")

https://github.com/user-attachments/assets/b5c46ae5-b608-4588-a497-b3bd3eb690ef
https://github.com/user-attachments/assets/430cd789-1b5d-42a0-ae6e-c8b5f1da694b

#### Can detect:
* is a hex color dark
Expand All @@ -14,7 +14,7 @@ An example practical aspect: it can be useful to understand will a black colored
#### How to Install:

Gemfile:
`gem 'is_dark', '~> 0.1.7'`
`gem 'is_dark', '~> 0.1.8'`

Install:
`gem install is_dark`
Expand All @@ -35,19 +35,21 @@ Install:
5. is Imagick area from a blob dark (by coordinates of a dot + width and height from the dot):
`IsDark.magick_area_from_blob(x, y, blob, height, width)` #standart default settings

#### More examples:
It also has kind of a development mode, when you can generate a debug outputs of all the generated dots based on provided coordinates. It can draw a test area over the file if you want, so you always can be sure, that you have valid coordinates on your tests.
- `IsDark.set_debug_data(true, false)` #with debug info outputs in logs

- `IsDark.set_debug_data(true, '/var/www/project/is_dark_debug_output.pdf')` #with a generated debug pdf file (has displayed area of the analytics). You can use other file formats for the info (jpg, png, gif)

- `IsDark.magick_area_from_blob(x, y, blob, height, width)` #standart default settings

- ` IsDark.magick_area_from_blob(x, y, blob, cf_height, cf_width, 60, (1..10))` #additional settings (percent of dark dots amount to mark an area as a dark, range of matrix to build dots 1..10 - means 10x10; 0..10 - will have 121 dots for the analytics)

Sometimes Imagick can't detect a pixel or it has no color, so it detects it as (RGB: 0,0,0), the gem has an option to consider pixels like this as "white", but if you need to disable this option add true or false at the end of the method:

- ` IsDark.magick_area_from_blob(x, y, blob, cf_height, cf_width, 60, (1..10), false)` #detection "as white" is disabled)
#### Settings:
It also has kind of a development mode, when you can generate a debug outputs of all the generated dots based on provided coordinates. It can draw a test area over the file if you want, so you always can be sure, that you have valid coordinates on your tests. You can also set some other values and calibrate results as you need.

```ruby
IsDark.configure({
percent: 70, #percent of dark dots under an area to mark all the area as dark
matrix: (0..10), #range of dots to analyse. (0..10) means matrix 10x10 or 100 dots to analyse
with_not_detected_as_white: true, # Sometimes Imagick can't detect a pixel or it has no color, so it detects it as (RGB: 0,0,0), the gem has an option to consider pixels like this as "white", but if you need to disable this option add true or false
with_debug: true, #show debug output
with_debug_file: true, #draw a tested area in a copy of your blob file
debug_file_path: debug_file_path #path of the file with a drawn area
})
```
You can use these settings and test it after with this command:
`IsDark.magick_area_from_blob(x, y, blob, height, width)`, so it will show a debug info with a generated file

#### Unit Tests:

Expand Down
2 changes: 1 addition & 1 deletion is_dark.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Gem::Specification.new do |s|
s.name = 'is_dark'
s.version = '0.1.7'
s.version = '0.1.8'
s.summary = 'Detects a dark background under an area or by a color code'
s.description = 'Detects a dark color based on luminance W3 standarts ' \
"( https://www.w3.org/TR/WCAG20/#relativeluminancedef ). \n\n " \
Expand Down
75 changes: 41 additions & 34 deletions lib/is_dark.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,107 +26,114 @@ class IsDark
NONLINEAR_TRANSFORM_DIVIDER = 1.055
NONLINEAR_TRANSFORM_OFFSET = 0.055
RED_LUMINANCE_COEFFICIENT = 0.2126
DEFAULT_PERCENT_OF_DOTS = 80
DEFAULT_MATRIX_RANGE = (0..10).freeze
DEFAULT_DEBUG_FILE_PATH = '/tmp/is_dark_debug_file.pdf'

@r = 0
@g = 0
@b = 0
@colorset = MAXIMUM_COLOR_DEPTH
@percent = DEFAULT_PERCENT_OF_DOTS
@matrix = DEFAULT_MATRIX_RANGE
@with_not_detected_as_white = true
@with_debug = false
@with_debug_file = false
@debug_file_path = '/tmp/is_dark_debug_file.pdf'
@debug_file_path = DEFAULT_DEBUG_FILE_PATH

def initialize(settings)
configure(settings) unless settings.nil?
end

def self.configure(settings)
@percent = settings[:percent] || DEFAULT_PERCENT_OF_DOTS
@matrix = settings[:matrix] || DEFAULT_MATRIX_RANGE
@with_not_detected_as_white = settings[:with_not_detected_as_white] || true
@with_debug = settings[:with_debug] || false
@with_debug_file = settings[:with_debug_file] || false
@debug_file_path = settings[:debug_file_path] || DEFAULT_DEBUG_FILE_PATH
end

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

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

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

# (x, y) is the left corner of an element over a blob, height and width is the element's size
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
def self.magick_area_from_blob(x, y, blob, height, width)
image = Magick::Image.read(blob).first
dark = false
dots = []
range.each do |xx|
range.each do |yy|
@matrix.each do |xx|
@matrix.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
old_x = false
old_y = false
end
p '====================================================================' if @with_debug
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)
l = magick_pixel(pix, x, y)
points += 1 if l
next unless @with_debug_file

draw_debug_files(image, x, y, oldx, oldy)
oldy = y
oldx = x
draw_debug_files(image, x, y, old_x, old_y)
old_y = y
old_x = x
end
dark = true if points >= (dots.length / 100) * percent
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 \"invert to white not detectd pixels\" option enabled?:#{@with_not_detected_as_white}"
p "Signature will be inverted if #{@percent}% of dots will be dark"
p "Is inverted?: #{dark}"
p "have a look on #{@debug_file_path} file to see your tested area of a blob"
p '=================================================================================='
end
dark
end

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

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

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

# detects a dark color based on luminance W3 standarts ( https://www.w3.org/TR/WCAG20/#relativeluminancedef )
def self.dark?(x = nil, y = nil, set_not_detected_light = true)
def self.dark?(x = nil, y = nil)
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
if @with_not_detected_as_white && 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
Expand Down
36 changes: 16 additions & 20 deletions spec/lib/is_dark_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,7 @@
y = 120 # coordinate of a left corner of the area's rectangle Y
cf_height = 64 # height of the area's rectangle
cf_width = 128 # height of the area's rectangle
percent = 70 # percent of detected dark pixels to invert
matrix = (1..10) # matrix of dots. Range of matrix to build dots 1..10 - means 10x10
# Sometimes Imagick can't detect a pixel or it has no color, so it detects it as (RGB: 0,0,0), the gem has an
# option to consider pixels like this as "white", but if you need to disable this option add true or false.
with_not_detected = false
expect(IsDark.magick_area_from_blob(x, y, TEST_FILE_PATH, cf_height, cf_width, percent, matrix,
with_not_detected)).to eq(false)
expect(IsDark.magick_area_from_blob(x, y, TEST_FILE_PATH, cf_height, cf_width)).to eq(false)
end
end

Expand All @@ -104,13 +98,7 @@
y = 120 # coordinate of a left corner of the area's rectangle Y
cf_height = 64 # height of the area's rectangle
cf_width = 128 # height of the area's rectangle
percent = 70 # percent of detected dark pixels to invert
matrix = (1..10) # matrix of dots. Range of matrix to build dots 1..10 - means 10x10
# Sometimes Imagick can't detect a pixel or it has no color, so it detects it as (RGB: 0,0,0), the gem has
# an option to consider pixels like this as "white", but if you need to disable this option add true or false.
with_not_detected = false
expect(IsDark.magick_area_from_blob(x, y, TEST_FILE_PATH, cf_height, cf_width, percent, matrix,
with_not_detected)).to eq(false)
expect(IsDark.magick_area_from_blob(x, y, TEST_FILE_PATH, cf_height, cf_width)).to eq(false)
end
end

Expand All @@ -120,14 +108,22 @@
y = 120 # coordinate of a left corner of the area's rectangle Y
cf_height = 64 # height of the area's rectangle
cf_width = 128 # height of the area's rectangle
percent = 70 # percent of detected dark pixels to invert
percent = 70 # percent of detected dark pixels to mark as dark
matrix = (1..10) # matrix of dots. Range of matrix to build dots 1..10 - means 10x10
# Sometimes Imagick can't detect a pixel or it has no color, so it detects it as (RGB: 0,0,0), the gem has
# an option to consider pixels like this as "white", but if you need to disable this option add true or false.
with_not_detected = false
IsDark.set_debug_data(true, './is_dark_debug_output.pdf')
expect(IsDark.magick_area_from_blob(x, y, TEST_FILE_PATH, cf_height, cf_width, percent, matrix,
with_not_detected)).to eq(false)
# an option to consider pixels like this as "white", but if you need to disable this option add true or false:
not_detected = false
# generated file with lines through dots of the matrix over a tested area:
debug_file_path = './is_dark_debug_file.pdf'
IsDark.configure({
percent: percent,
matrix: matrix,
with_not_detected_as_white: not_detected,
with_debug: true,
with_debug_file: true,
debug_file_path: debug_file_path
})
expect(IsDark.magick_area_from_blob(x, y, TEST_FILE_PATH, cf_height, cf_width)).to eq(false)
end
end
end
Expand Down

0 comments on commit 8f89f5d

Please sign in to comment.