image_quality_check 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 +9 -0
- data/.rspec +1 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +145 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/config/locales/image_quality.de.yml +11 -0
- data/config/locales/image_quality.en.yml +10 -0
- data/db/migrate/20201008124025_create_image_quality_checks.rb +15 -0
- data/exe/image_quality_blur +60 -0
- data/image_quality_check.gemspec +28 -0
- data/lib/image_quality_check.rb +61 -0
- data/lib/image_quality_check/determine_quality.rb +76 -0
- data/lib/image_quality_check/dsl.rb +56 -0
- data/lib/image_quality_check/model.rb +34 -0
- data/lib/image_quality_check/version.rb +3 -0
- metadata +79 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b5fbfb17831bb894d3890c10197aff1573ca1f6fbdcf0308f5ec1975cfd35cc6
|
4
|
+
data.tar.gz: d5f5fdf1a2cb61f92566b26cc5954582a94116c056004a24323b93984307507d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 594ca886f91f517ef6b71fda2cbf350cb4c41991434c3071aaad6f9e63d0d48a71fb1acc08a01835f2e927dd9774cb19655a9d63c63b5829b82796f22e6f6304
|
7
|
+
data.tar.gz: 2b20142b04050a37d1b2655f6188ec69ac534f175acdf4234c4c07edc4760f3ec0b675f255afda053f080e836c852f93f69aa8c972441f80a58cabcff254bba4
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--require spec_helper
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2020 Stefan Wienert
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
# ImageQuality
|
2
|
+
|
3
|
+
Thin gem wrapper that uses ``imagemagick`` and ``python-opencv`` to help determine image quality.
|
4
|
+
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
System dependencies:
|
9
|
+
|
10
|
+
- Have imagemagick installed (Tool uses ``identify``).
|
11
|
+
- have python3 + OpenCV installed: Install OpenCV, e.g. on Ubuntu 18.04:
|
12
|
+
|
13
|
+
```
|
14
|
+
apt-get install python3-pywt python3-opencv
|
15
|
+
```
|
16
|
+
|
17
|
+
---
|
18
|
+
|
19
|
+
Add this line to your application's Gemfile:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
gem 'image_quality'
|
23
|
+
```
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
### Direct usage without model integration
|
28
|
+
|
29
|
+
```
|
30
|
+
result = ImageQualityCheck.analyze(path_to_file)
|
31
|
+
|
32
|
+
{
|
33
|
+
blur: {
|
34
|
+
LPScale: 100
|
35
|
+
}
|
36
|
+
face: null,
|
37
|
+
haseSmile: false,
|
38
|
+
width: 836,
|
39
|
+
format: 'jpeg',
|
40
|
+
height: 604,
|
41
|
+
quality: 90,
|
42
|
+
mime_type: 'image/jpeg',
|
43
|
+
}
|
44
|
+
```
|
45
|
+
|
46
|
+
This tool uses a shipped Python executable from https://github.com/pedrofrodenas/blur-Detection-Haar-Wavelet
|
47
|
+
|
48
|
+
The ``blur.LPScale`` gives you info if the image is blurry on a scale of 0..100
|
49
|
+
|
50
|
+
### DSL for defining rules for Models
|
51
|
+
|
52
|
+
**LIMITS**:
|
53
|
+
|
54
|
+
- currently only Paperclip attachment is implemented. Feel free to add other get-the-tmpfile adapter to ``ImageQualityCheck::DetermineQuality#read``
|
55
|
+
|
56
|
+
---
|
57
|
+
|
58
|
+
Create a initializer in your app:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
# config/initializers/image_quality.rb
|
62
|
+
|
63
|
+
# define your quality rules per attachment:
|
64
|
+
ImageQuality.define_rules_for Person, attachment: :photo do
|
65
|
+
# jpeg and png yields 100 score in this segment
|
66
|
+
preferred_formats_rule(jpeg: 100, png: 100)
|
67
|
+
|
68
|
+
# Sizes with w>400 and h>500 will give 100 score,
|
69
|
+
# otherwise linearly between 0 .. 100
|
70
|
+
preferred_size_rule(400, 500)
|
71
|
+
rule "Photo of a person" do |result, on_error|
|
72
|
+
if result[:blur].slice(:face, :hasSmile, :eyes).any?
|
73
|
+
# detector has either detected face, smile or eyes
|
74
|
+
100
|
75
|
+
else
|
76
|
+
on_error.call("No face found")
|
77
|
+
0
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
rule "Bluriness/Sharpness" do |result, on_error|
|
82
|
+
blur = result[:blur]
|
83
|
+
# overall picture is sharp (0...100)
|
84
|
+
if blur[:LPScale] > 70
|
85
|
+
100
|
86
|
+
else
|
87
|
+
# also including: you could check LPScale for eyes, face only
|
88
|
+
result = (blur[:LPScale] / 80 * 100).round
|
89
|
+
on_error.call("Contrast or focus is not optimal")
|
90
|
+
result
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
ImageQuality.define_rules_for Organisation, attachment: :logo do
|
96
|
+
preferred_formats_rule(png: 100, svg: 100, jpeg: 50, gif: 50)
|
97
|
+
preferred_size_rule(600, 400)
|
98
|
+
end
|
99
|
+
|
100
|
+
```
|
101
|
+
|
102
|
+
Then you can query for the quality rules to evaluate an attachment:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
ImageQuality.determine_quality(some_organisation, :logo) do |result|
|
106
|
+
```
|
107
|
+
|
108
|
+
### Using example Result model
|
109
|
+
|
110
|
+
There is an ActiveRecord example model included in this Gem to save the ImageQuality Results to the database. It uses json column so that (modern) mysql/psql are both supported without any conditionals.
|
111
|
+
|
112
|
+
Run:
|
113
|
+
|
114
|
+
```
|
115
|
+
bundle exec rake image_quality_check_engine:install:migrations
|
116
|
+
bin/rails db:migrate
|
117
|
+
```
|
118
|
+
|
119
|
+
Then you can use this class like so (Example):
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
# add to initializer:
|
123
|
+
require 'image_quality/model'
|
124
|
+
ImageQuality.determine_quality(some_organisation, :logo) do |result|
|
125
|
+
ImageQualityCheck::Result.create_for_result(some_organisation, column, result)
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
You also want to add a has_one relationship to the host models:
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
class Person < AR
|
133
|
+
has_one :image_quality_check_result, -> { where(attachable_column: :logo) }, as: :attachable, dependent: :destroy, class_name: "ImageQualityCheck::Result"
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
|
138
|
+
## Contributing
|
139
|
+
|
140
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/zealot128/image_quality.
|
141
|
+
|
142
|
+
|
143
|
+
## License
|
144
|
+
|
145
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "image_quality"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
---
|
2
|
+
de:
|
3
|
+
image_quality_check:
|
4
|
+
not_found: Kein Anhang/Bild gefunden
|
5
|
+
dsl:
|
6
|
+
no_qualities_defined_for: No qualities defined for [%{klass}, %{attachment}]
|
7
|
+
format: Format
|
8
|
+
format_ist_nutzen_sie: Format ist %{result_format} - Nutzen Sie %{formats_keys_map_upcase_jo}
|
9
|
+
gro_e: Größe
|
10
|
+
gro_e_ist_x_px_achten_sie: Größe ist %{result_width}x%{result_height}px - Achten
|
11
|
+
Sie auf eine Mindestgröße von min. %{expected_width}x%{expected_height}px
|
@@ -0,0 +1,10 @@
|
|
1
|
+
---
|
2
|
+
en:
|
3
|
+
image_quality_check:
|
4
|
+
not_found: "No attachment/photo found"
|
5
|
+
dsl:
|
6
|
+
no_qualities_defined_for: No qualities defined for [%{klass}, %{attachment}]
|
7
|
+
format: Format
|
8
|
+
format_ist_nutzen_sie: Format is %{result_format} - please prefer %{formats_keys_map_upcase_jo}
|
9
|
+
gro_e: Image dimension
|
10
|
+
gro_e_ist_x_px_achten_sie: Size is %{result_width}x%{result_height}px - Please use a minimum size of %{expected_width}x%{expected_height}px
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateImageQualityChecks < ActiveRecord::Migration[5.2]
|
2
|
+
def change
|
3
|
+
create_table :image_quality_check_results do |t|
|
4
|
+
t.string :attachable_type
|
5
|
+
t.string :attachable_id
|
6
|
+
t.string :attachable_column
|
7
|
+
t.json :result
|
8
|
+
t.integer :quality
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
t.index [:attachable_type, :attachable_id], name: 'index_image_quality_checks_on_attachable'
|
12
|
+
t.index [:attachable_type, :attachable_id, :attachable_column], unique: true, name: 'index_image_quality_checks_on_all'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
|
3
|
+
import sys
|
4
|
+
import json
|
5
|
+
import numpy as np
|
6
|
+
import cv2
|
7
|
+
|
8
|
+
null = None
|
9
|
+
|
10
|
+
img = cv2.imread(sys.argv[1], 0)
|
11
|
+
|
12
|
+
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
|
13
|
+
img = clahe.apply(img)
|
14
|
+
|
15
|
+
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
|
16
|
+
faces_detect = face_cascade.detectMultiScale(img, scaleFactor=1.5, minNeighbors=3)
|
17
|
+
|
18
|
+
for (x, y, w, h) in faces_detect:
|
19
|
+
# cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
|
20
|
+
face = img[y:y + h, x:x + w]
|
21
|
+
|
22
|
+
out = {}
|
23
|
+
|
24
|
+
if len(faces_detect) > 0:
|
25
|
+
out['face'] = {}
|
26
|
+
local = np.max(cv2.convertScaleAbs(cv2.Laplacian(face,3)))
|
27
|
+
laplace_face = cv2.Laplacian(face, cv2.CV_64F).var()
|
28
|
+
out['face']['FaceBlurScale'] = int(local / 255 * 100)
|
29
|
+
out['face']['FaceBlurLaplaceVar'] = laplace_face
|
30
|
+
else:
|
31
|
+
out['face'] = null
|
32
|
+
face = img
|
33
|
+
|
34
|
+
|
35
|
+
smile_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_smile.xml')
|
36
|
+
smile_detect = smile_cascade.detectMultiScale(face, minNeighbors=40, scaleFactor=1.14)
|
37
|
+
|
38
|
+
eye_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_eye.xml')
|
39
|
+
eye_detect = eye_cascade.detectMultiScale(face, minNeighbors=15)
|
40
|
+
|
41
|
+
out['hasSmile'] = len(smile_detect) > 0
|
42
|
+
|
43
|
+
if len(eye_detect) > 0:
|
44
|
+
for (x, y, w, h) in eye_detect:
|
45
|
+
eye = img[y:y + h, x:x + w]
|
46
|
+
local_laplace = np.max(cv2.convertScaleAbs(cv2.Laplacian(eye, 3)))
|
47
|
+
laplace_var = cv2.Laplacian(eye, cv2.CV_64F).var()
|
48
|
+
out['eyes'] = {
|
49
|
+
'LPScale': int(local_laplace / 255 * 100),
|
50
|
+
'LPVar': laplace_var
|
51
|
+
}
|
52
|
+
else:
|
53
|
+
out['eyes'] = null
|
54
|
+
|
55
|
+
laplace = cv2.Laplacian(img, cv2.CV_64F).var()
|
56
|
+
local_laplace = np.max(cv2.convertScaleAbs(cv2.Laplacian(img, 3)))
|
57
|
+
out['LPVar'] = laplace
|
58
|
+
out['LPScale'] = (local_laplace / 255 * 100)
|
59
|
+
|
60
|
+
print(json.dumps(out))
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative 'lib/image_quality_check/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "image_quality_check"
|
5
|
+
spec.version = ImageQualityCheck::VERSION
|
6
|
+
spec.authors = ["Stefan Wienert"]
|
7
|
+
spec.email = ["info@stefanwienert.de"]
|
8
|
+
|
9
|
+
spec.summary = %q{image quality}
|
10
|
+
spec.description = %q{image quality}
|
11
|
+
spec.homepage = "https://github.com/pludoni/image_quality_check"
|
12
|
+
spec.license = "MIT"
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
14
|
+
|
15
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
16
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
17
|
+
# spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
18
|
+
|
19
|
+
# Specify which files should be added to the gem when it is released.
|
20
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
21
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
22
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
23
|
+
end
|
24
|
+
spec.bindir = "exe"
|
25
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
|
+
spec.require_paths = ["lib"]
|
27
|
+
spec.add_runtime_dependency "i18n"
|
28
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require "image_quality_check/version"
|
2
|
+
require 'image_quality_check/dsl'
|
3
|
+
require 'image_quality_check/determine_quality'
|
4
|
+
require 'shellwords'
|
5
|
+
require 'json'
|
6
|
+
require 'open3'
|
7
|
+
|
8
|
+
module ImageQualityCheck
|
9
|
+
extend ImageQualityCheck::DSL
|
10
|
+
|
11
|
+
def self.determine_quality(model, attachment, &block)
|
12
|
+
ImageQualityCheck::DetermineQuality.run(model, attachment, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.analyze(path_to_image)
|
16
|
+
out = `convert #{Shellwords.escape path_to_image} json:`
|
17
|
+
# image magick gif delay bug invalid json
|
18
|
+
# https://github.com/ImageMagick/ImageMagick/issues/1624
|
19
|
+
out.gsub!(/("delay": "[^"]+")\n/m, "\\1,\n")
|
20
|
+
json = JSON.parse(out)['image']
|
21
|
+
background_is_transparent =
|
22
|
+
json.dig('channelDepth', 'alpha') &&
|
23
|
+
json['channelStatistics']['alpha']['min'] != json['channelStatistics']['alpha']['max']
|
24
|
+
{
|
25
|
+
format: json['format'].downcase,
|
26
|
+
mime_type: json['mimeType'],
|
27
|
+
background_is_transparent: background_is_transparent,
|
28
|
+
width: json.dig('geometry', 'width'),
|
29
|
+
height: json.dig('geometry', 'height'),
|
30
|
+
quality: json['quality'],
|
31
|
+
blur: blur_detect(path_to_image).map { |k, v| [ k.to_sym, v ] }.to_h
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.blur_detect(path_to_image)
|
36
|
+
script = File.join(File.dirname(__FILE__), '..', 'exe', 'image_quality_blur')
|
37
|
+
out, err, value = Open3.capture3("#{script} #{Shellwords.escape(path_to_image)}")
|
38
|
+
if value.success?
|
39
|
+
JSON.parse(out.gsub('NaN', '0'))
|
40
|
+
else
|
41
|
+
if out[/^\{/]
|
42
|
+
JSON.parse(out)
|
43
|
+
else
|
44
|
+
{
|
45
|
+
error: err.to_s,
|
46
|
+
out: out.to_s
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
if defined?(Rails)
|
54
|
+
class ImageQualityCheck::Engine < Rails::Engine
|
55
|
+
end
|
56
|
+
else
|
57
|
+
require 'i18n'
|
58
|
+
I18n.load_path << Dir[File.expand_path("config/locales") + "/*.yml"]
|
59
|
+
I18n.default_locale ||= :en
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'i18n'
|
2
|
+
|
3
|
+
class ImageQualityCheck::DetermineQuality
|
4
|
+
def self.run(model, column_name, tmp_file = nil, &block)
|
5
|
+
new(model, column_name, tmp_file).run(&block)
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(model, column_name, tmp_file = nil)
|
9
|
+
@model = model
|
10
|
+
@column_name = column_name
|
11
|
+
@column = model.send(column_name)
|
12
|
+
@messages = []
|
13
|
+
@tmp_file = tmp_file
|
14
|
+
end
|
15
|
+
|
16
|
+
def run(&block)
|
17
|
+
unless @tmp_file
|
18
|
+
@tmp_file = Tempfile.new(['image_quality'])
|
19
|
+
unless read!(@tmp_file)
|
20
|
+
result = {
|
21
|
+
quality: 0,
|
22
|
+
details: {},
|
23
|
+
messages: [{ name: I18n.t('image_quality_check.not_found'), quality: 0 }]
|
24
|
+
}
|
25
|
+
yield(result) if block_given?
|
26
|
+
return result
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
@analyse_result = ImageQualityCheck.analyze(@tmp_file.path)
|
31
|
+
result = {
|
32
|
+
quality: determine_quality,
|
33
|
+
details: @analyse_result,
|
34
|
+
messages: @messages,
|
35
|
+
}
|
36
|
+
yield(result) if block_given?
|
37
|
+
result
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def determine_quality
|
43
|
+
qualities = []
|
44
|
+
sum_of_weights = 0
|
45
|
+
ImageQualityCheck.rules_for(@model.class, @column_name).each do |qq|
|
46
|
+
error = nil
|
47
|
+
on_error = ->(msg) { error = msg }
|
48
|
+
result = instance_exec(@analyse_result, on_error, &qq[:block])
|
49
|
+
@messages << {
|
50
|
+
name: qq[:name],
|
51
|
+
quality: result,
|
52
|
+
message: error
|
53
|
+
}
|
54
|
+
if result
|
55
|
+
qualities << result * qq[:weight]
|
56
|
+
sum_of_weights += qq[:weight]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
(qualities.sum / sum_of_weights.to_f).round
|
61
|
+
end
|
62
|
+
|
63
|
+
def read!(tmp_file)
|
64
|
+
case @column.class.to_s
|
65
|
+
when "Paperclip::Attachment"
|
66
|
+
if !@column.path || !File.exist?(@column.path)
|
67
|
+
false
|
68
|
+
else
|
69
|
+
FileUtils.cp(@column.path, tmp_file.path)
|
70
|
+
true
|
71
|
+
end
|
72
|
+
else
|
73
|
+
raise NotImplementedError, @column.class
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'i18n'
|
2
|
+
# rubocop:disable Style/ClassVars,Metrics/BlockLength
|
3
|
+
module ImageQualityCheck::DSL
|
4
|
+
def define_rules_for(klass, attachment:, &block)
|
5
|
+
@rules ||= {}
|
6
|
+
@rules[[klass.to_s, attachment.to_s]] = block
|
7
|
+
end
|
8
|
+
|
9
|
+
def rules_for(klass, attachment)
|
10
|
+
rule = @rules[[klass.to_s, attachment.to_s]]
|
11
|
+
unless rule
|
12
|
+
raise NotImplemented, I18n.t("image_quality_check.dsl.no_qualities_defined_for", klass: (klass), attachment: (attachment))
|
13
|
+
end
|
14
|
+
@current_rule = []
|
15
|
+
class_exec(&rule)
|
16
|
+
@current_rule
|
17
|
+
end
|
18
|
+
|
19
|
+
def rule(name, weight: 1, &block)
|
20
|
+
@current_rule << { name: name, block: block, weight: weight }
|
21
|
+
end
|
22
|
+
|
23
|
+
def preferred_formats_rule(formats, weight: 1)
|
24
|
+
rule I18n.t("image_quality_check.dsl.format"), weight: weight do |result, on_error|
|
25
|
+
final_score = nil
|
26
|
+
formats.each do |f, score|
|
27
|
+
if result[:format].downcase.to_s == f.downcase.to_s
|
28
|
+
final_score ||= score
|
29
|
+
end
|
30
|
+
end
|
31
|
+
final_score ||= 0
|
32
|
+
if final_score < 100
|
33
|
+
message = I18n.t("image_quality_check.dsl.format_ist_nutzen_sie",
|
34
|
+
result_format: (result[:format]),
|
35
|
+
formats_keys_map_upcase_jo: (formats.keys.map(&:upcase).join(', ')))
|
36
|
+
on_error.call(message)
|
37
|
+
end
|
38
|
+
final_score
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def preferred_size_rule(expected_width, expected_height, weight: 2)
|
43
|
+
rule I18n.t("image_quality_check.dsl.gro_e"), weight: weight do |result, on_error|
|
44
|
+
if result[:width] >= expected_width && result[:height] >= expected_height
|
45
|
+
100
|
46
|
+
else
|
47
|
+
target = expected_width * expected_height
|
48
|
+
current = result[:width] * result[:height]
|
49
|
+
on_error.call(
|
50
|
+
I18n.t("image_quality_check.dsl.gro_e_ist_x_px_achten_sie", result_width: (result[:width]), result_height: (result[:height]), expected_width: (expected_width), expected_height: (expected_height))
|
51
|
+
)
|
52
|
+
[current / target.to_f * 100, 90].min.round
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
# == Schema Information
|
3
|
+
#
|
4
|
+
# Table name: image_quality_check_results
|
5
|
+
#
|
6
|
+
# id :bigint(8) not null, primary key
|
7
|
+
# attachable_column :string(255)
|
8
|
+
# attachable_type :string(255)
|
9
|
+
# quality :integer
|
10
|
+
# result :json
|
11
|
+
# created_at :datetime not null
|
12
|
+
# updated_at :datetime not null
|
13
|
+
# attachable_id :string(255)
|
14
|
+
#
|
15
|
+
# Indexes
|
16
|
+
#
|
17
|
+
# index_image_quality_checks_on_all (attachable_type,attachable_id,attachable_column) UNIQUE
|
18
|
+
# index_image_quality_checks_on_attachable (attachable_type,attachable_id)
|
19
|
+
#
|
20
|
+
|
21
|
+
class ImageQualityCheck::Result < ApplicationRecord
|
22
|
+
self.table_name = 'image_quality_check_results'
|
23
|
+
belongs_to :attachable, polymorphic: true
|
24
|
+
|
25
|
+
def self.create_for_result(attachable, column, result)
|
26
|
+
check = ImageQualityCheck::Result.where(attachable: attachable, attachable_column: column).first_or_initialize
|
27
|
+
check.quality = result[:quality]
|
28
|
+
check.result = {
|
29
|
+
details: result[:details],
|
30
|
+
messages: result[:messages],
|
31
|
+
}
|
32
|
+
check.save!
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: image_quality_check
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stefan Wienert
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-10-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: i18n
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: image quality
|
28
|
+
email:
|
29
|
+
- info@stefanwienert.de
|
30
|
+
executables:
|
31
|
+
- image_quality_blur
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- ".gitignore"
|
36
|
+
- ".rspec"
|
37
|
+
- Gemfile
|
38
|
+
- LICENSE.txt
|
39
|
+
- README.md
|
40
|
+
- Rakefile
|
41
|
+
- bin/console
|
42
|
+
- bin/setup
|
43
|
+
- config/locales/image_quality.de.yml
|
44
|
+
- config/locales/image_quality.en.yml
|
45
|
+
- db/migrate/20201008124025_create_image_quality_checks.rb
|
46
|
+
- exe/image_quality_blur
|
47
|
+
- image_quality_check.gemspec
|
48
|
+
- lib/image_quality_check.rb
|
49
|
+
- lib/image_quality_check/determine_quality.rb
|
50
|
+
- lib/image_quality_check/dsl.rb
|
51
|
+
- lib/image_quality_check/model.rb
|
52
|
+
- lib/image_quality_check/version.rb
|
53
|
+
homepage: https://github.com/pludoni/image_quality_check
|
54
|
+
licenses:
|
55
|
+
- MIT
|
56
|
+
metadata:
|
57
|
+
homepage_uri: https://github.com/pludoni/image_quality_check
|
58
|
+
source_code_uri: https://github.com/pludoni/image_quality_check
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options: []
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 2.3.0
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
requirements: []
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 2.7.6
|
76
|
+
signing_key:
|
77
|
+
specification_version: 4
|
78
|
+
summary: image quality
|
79
|
+
test_files: []
|