diff --git a/README.md b/README.md index 6583a45..d525b97 100644 --- a/README.md +++ b/README.md @@ -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.9'` +`gem 'is_dark', '~> 0.2.0'` Install: `gem install is_dark` @@ -23,36 +23,51 @@ Install: 1. Declare a lib: `require 'is_dark'` +2. Make an instance: +`is_dark = IsDark.new` + 2. Is Hex color dark: -`IsDark.color('#ffffff') => false` +`is_dark.color('#ffffff') => false` 3. is Imagick pixel dark: -`IsDark.magick_pixel(pix)` +`is_dark.magick_pixel(pix)` 4. is Imagick pixel from a blob dark by coordinates: -`IsDark.magick_pixel_from_blob(x, y, blob)` +`is_dark.magick_pixel_from_blob(x, y, blob)` 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 +`is_dark.magick_area_from_blob(x, y, blob, height, width)` #standart default settings #### 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. +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 during your tests. You can also set some other values and calibrate results as you need. You can just initialize an instance with these settings or update an existed one: ```ruby -IsDark.configure({ +params = { 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 -}) + debug_file_path: debug_file_path, #path of the file with a drawn area + luminance: 0.05 # all pixels are dark if their luminance is lower, that this value +} +is_dark = IsDark.new(params) #to generate new Instance +#or +is_dark.configure(params) #to update existed instance + ``` + 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 +`is_dark.magick_area_from_blob(x, y, blob, height, width)`, so it will show a debug info with a generated file like in the video at the top of this documentation. + +###### Deep Settings: + +You can calibrate it more deep, change constants for it inside lib/is_dark.rb file, but the most powerful parameter to calibrate in case of a not valid dark area detection is about luminance value, it is open to change this value from settings params, it is already described in the message above. #### Unit Tests: - `rspec` #rspec tests with a generated debug file -- `rake test` #minitest based unit tests (low amount of tests) +#### Old versions: + +Old versions of the gem are about static methods only, you can find old documentation about it all in [README_old.md file]( https://github.com/butteff/is_dark_ruby_gem/blob/main/README_old.md "README_old.md file") \ No newline at end of file diff --git a/README_old.md b/README_old.md new file mode 100644 index 0000000..6583a45 --- /dev/null +++ b/README_old.md @@ -0,0 +1,58 @@ +# 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/430cd789-1b5d-42a0-ae6e-c8b5f1da694b + +#### Can detect: +* is a hex color dark +* is an Imagick pixel dark +* is an Imagick pixel from a blob dark +* is an area in a blob over a dark background (uses Imagick for it too). +. +An example practical aspect: it can be useful to understand will a black colored text be visible or not over an area. + +#### How to Install: + +Gemfile: +`gem 'is_dark', '~> 0.1.9'` + +Install: +`gem install is_dark` + +#### How to use: +1. Declare a lib: +`require 'is_dark'` + +2. Is Hex color dark: +`IsDark.color('#ffffff') => false` + +3. is Imagick pixel dark: +`IsDark.magick_pixel(pix)` + +4. is Imagick pixel from a blob dark by coordinates: +`IsDark.magick_pixel_from_blob(x, y, blob)` + +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 + +#### 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: + +- `rspec` #rspec tests with a generated debug file + +- `rake test` #minitest based unit tests (low amount of tests) diff --git a/Rakefile b/Rakefile deleted file mode 100644 index d0c6390..0000000 --- a/Rakefile +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -require 'rake/testtask' - -Rake::TestTask.new do |t| - t.libs << 'test' -end - -desc 'Run tests' -task default: :test diff --git a/is_dark.gemspec b/is_dark.gemspec index d516fba..e98e5f7 100644 --- a/is_dark.gemspec +++ b/is_dark.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = 'is_dark' - s.version = '0.1.9' + s.version = '0.2.0' 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 " \ diff --git a/lib/is_dark.rb b/lib/is_dark.rb index 1118780..d701963 100644 --- a/lib/is_dark.rb +++ b/lib/is_dark.rb @@ -36,27 +36,33 @@ class IsDark @colorset = MAXIMUM_COLOR_DEPTH @percent = DEFAULT_PERCENT_OF_DOTS @matrix = DEFAULT_MATRIX_RANGE + @luminance = LUMINANCE_THRESHOLD @with_not_detected_as_white = true @with_debug = false @with_debug_file = false @debug_file_path = DEFAULT_DEBUG_FILE_PATH - def self.configure(settings) + def initialize(settings = {}) + configure(settings) + end + + def configure(settings = {}) @percent = settings[:percent] || DEFAULT_PERCENT_OF_DOTS @matrix = settings[:matrix] || DEFAULT_MATRIX_RANGE + @luminance = settings[:luminance] || LUMINANCE_THRESHOLD @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) + def 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) + def magick_pixel(pix, x = nil, y = nil) @r = pix.red.to_f @g = pix.green.to_f @b = pix.blue.to_f @@ -64,14 +70,14 @@ def self.magick_pixel(pix, x = nil, y = nil) dark?(x, y) end - def self.magick_pixel_from_blob(x, y, blob) + def 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) + def magick_area_from_blob(x, y, blob, height, width) image = Magick::Image.read(blob).first dark = false dots = [] @@ -104,15 +110,16 @@ def self.magick_area_from_blob(x, y, blob, height, width) p '==================================================================================' p "Total Points: #{dots.length}, dark points amount:#{points}" 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 "Percent of dark dots in the matrix: #{@percent}%" + p "Luminance value is: #{@luminance}" + p "Is Area Dark?: #{dark}" p "have a look on #{@debug_file_path} file to see your tested area of a blob" p '==================================================================================' end dark end - def self.draw_debug_files(image, x, y, old_x, old_y) + def draw_debug_files(image, x, y, old_x, old_y) return unless old_x && old_y gc = Magick::Draw.new @@ -123,7 +130,7 @@ def self.draw_debug_files(image, x, y, old_x, old_y) end # detects a dark color based on luminance W3 standarts ( https://www.w3.org/TR/WCAG20/#relativeluminancedef ) - def self.dark?(x = nil, y = nil) + def dark?(x = nil, y = nil) dark = false inverted = false pixel = [@r.to_f, @g.to_f, @b.to_f] @@ -146,7 +153,7 @@ def self.dark?(x = nil, y = nil) l = (RED_LUMINANCE_COEFFICIENT * calculated[0]) + (GREEN_LUMINANCE_COEFFICIENT * calculated[1]) + (BLUE_LUMINANCE_COEFFICIENT * calculated[2]) - dark = true if l <= LUMINANCE_THRESHOLD + dark = true if l <= @luminance if @with_debug debug = { X: x, Y: y, R: @r, G: @g, B: @b, 'luminance value': l, dark?: dark, 'inverted to white': inverted } diff --git a/spec/lib/is_dark_spec.rb b/spec/lib/is_dark_spec.rb index c2ef0fc..8998e29 100644 --- a/spec/lib/is_dark_spec.rb +++ b/spec/lib/is_dark_spec.rb @@ -10,37 +10,45 @@ describe '.color' do context 'dark colors tests' do it 'this color #000000 is dark, returns true' do - expect(IsDark.color('#000000')).to eq(true) + is_dark = IsDark.new + expect(is_dark.color('#000000')).to eq(true) end it 'this color #111111 is dark, returns true' do - expect(IsDark.color('#111111')).to eq(true) + is_dark = IsDark.new + expect(is_dark.color('#111111')).to eq(true) end it 'this color #102694 is dark, returns true' do - expect(IsDark.color('#102694')).to eq(true) + is_dark = IsDark.new + expect(is_dark.color('#102694')).to eq(true) end it 'this color #ff2e17 is dark, returns true' do - expect(IsDark.color('#800f03')).to eq(true) + is_dark = IsDark.new + expect(is_dark.color('#800f03')).to eq(true) end end context 'not dark colors tests' do it 'this color is not dark, returns false' do - expect(IsDark.color('#444444')).to eq(false) + is_dark = IsDark.new + expect(is_dark.color('#444444')).to eq(false) end it 'this color is not dark, returns false' do - expect(IsDark.color('#888888')).to eq(false) + is_dark = IsDark.new + expect(is_dark.color('#888888')).to eq(false) end it 'this color is not dark, returns false' do - expect(IsDark.color('#ffffff')).to eq(false) + is_dark = IsDark.new + expect(is_dark.color('#ffffff')).to eq(false) end it 'this color is not dark, returns false' do - expect(IsDark.color('#fff6b2')).to eq(false) + is_dark = IsDark.new + expect(is_dark.color('#fff6b2')).to eq(false) end end end @@ -50,7 +58,8 @@ it 'this pixel is dark, returns true' do x = 120 y = 120 - expect(IsDark.magick_pixel_from_blob(x, y, TEST_FILE_PATH)).to eq(true) + is_dark = IsDark.new + expect(is_dark.magick_pixel_from_blob(x, y, TEST_FILE_PATH)).to eq(true) end end @@ -58,7 +67,8 @@ it 'this pixel is not dark, returns false' do x = 720 y = 120 - expect(IsDark.magick_pixel_from_blob(x, y, TEST_FILE_PATH)).to eq(false) + is_dark = IsDark.new + expect(is_dark.magick_pixel_from_blob(x, y, TEST_FILE_PATH)).to eq(false) end end end @@ -68,7 +78,8 @@ it 'this pixel is dark, returns true' do image = Magick::Image.read(TEST_FILE_PATH).first pix = image.pixel_color(80, 320) - expect(IsDark.magick_pixel(pix)).to eq(true) + is_dark = IsDark.new + expect(is_dark.magick_pixel(pix)).to eq(true) end end @@ -76,7 +87,8 @@ it 'this pixel is not dark, returns false' do image = Magick::Image.read(TEST_FILE_PATH).first pix = image.pixel_color(720, 120) - expect(IsDark.magick_pixel(pix)).to eq(false) + is_dark = IsDark.new + expect(is_dark.magick_pixel(pix)).to eq(false) end end end @@ -88,7 +100,8 @@ 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 - expect(IsDark.magick_area_from_blob(x, y, TEST_FILE_PATH, cf_height, cf_width)).to eq(false) + is_dark = IsDark.new + expect(is_dark.magick_area_from_blob(x, y, TEST_FILE_PATH, cf_height, cf_width)).to eq(false) end end @@ -98,7 +111,8 @@ 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 - expect(IsDark.magick_area_from_blob(x, y, TEST_FILE_PATH, cf_height, cf_width)).to eq(false) + is_dark = IsDark.new + expect(is_dark.magick_area_from_blob(x, y, TEST_FILE_PATH, cf_height, cf_width)).to eq(false) end end @@ -108,22 +122,16 @@ 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 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: - 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) + params = { + 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, + with_not_detected_as_white: true, # to mark not detected pixels as white + with_debug: true, # to show debug output + with_debug_file: true, # to generate debug file to show a tested area + debug_file_path: './is_dark_debug_file.pdf' # to show file path + } + is_dark = IsDark.new(params) + expect(is_dark.magick_area_from_blob(x, y, TEST_FILE_PATH, cf_height, cf_width)).to eq(false) end end end diff --git a/test/test_is_dark.rb b/test/test_is_dark.rb deleted file mode 100644 index a80c6c2..0000000 --- a/test/test_is_dark.rb +++ /dev/null @@ -1,50 +0,0 @@ -# frozen_string_literal: true - -require 'minitest/autorun' -require 'is_dark' - -class HolaTest < Minitest::Test - # dark colors - - def test_is_dark_hex_code_000000 - assert_equal true, - IsDark.color('#000000') - end - - def test_is_dark_hex_code_111111 - assert_equal true, - IsDark.color('#111111') - end - - def test_is_dark_hex_code_102694 - assert_equal true, - IsDark.color('#102694') - end - - def test_is_dark_hex_code_ff2e17 - assert_equal true, - IsDark.color('#800f03') - end - - # not dark colors - - def test_is_dark_hex_code_444444 - assert_equal false, - IsDark.color('#444444') - end - - def test_is_dark_hex_code_888888 - assert_equal false, - IsDark.color('#888888') - end - - def test_is_dark_hex_code_ffffff - assert_equal false, - IsDark.color('#ffffff') - end - - def test_is_dark_hex_code_fff6b2 - assert_equal false, - IsDark.color('#fff6b2') - end -end