svg_profiler 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +16 -3
- data/lib/svg_profiler.rb +3 -0
- data/lib/svg_profiler/base.rb +4 -0
- data/lib/svg_profiler/histogram.rb +48 -0
- data/lib/svg_profiler/inkscape.rb +21 -6
- metadata +50 -51
data/README.md
CHANGED
@@ -4,10 +4,8 @@ Profiles a Scalable Vector Graphics xml string.
|
|
4
4
|
|
5
5
|
## Setup
|
6
6
|
|
7
|
-
SVG Profiler depends on an open-source application called Inkscape.
|
8
|
-
|
9
7
|
```
|
10
|
-
brew install inkscape
|
8
|
+
brew install imagemagick inkscape
|
11
9
|
gem install svg_profiler
|
12
10
|
```
|
13
11
|
|
@@ -29,8 +27,23 @@ profile.height
|
|
29
27
|
|
30
28
|
profile.aspect
|
31
29
|
#=> 1.5
|
30
|
+
|
31
|
+
# The #colors method calculates the histogram for the SVG.
|
32
|
+
profile.colors
|
33
|
+
#=> { "#FF0000" => 0.7, "#FFFFFF" => 0.29, "#000000" => 0.01 }
|
34
|
+
```
|
35
|
+
|
36
|
+
You may find that the SVG is [antialiased](http://en.wikipedia.org/wiki/Spatial_anti-aliasing) before the histogram is calculated.
|
37
|
+
|
38
|
+
You can pass an optional threshold to the `#colors` method, to help cope with this:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
profile.colors(0.02)
|
42
|
+
#=> { "#FF0000" => 0.7070707070707071, "#FFFFFF" => 0.29292929292929293 }
|
32
43
|
```
|
33
44
|
|
45
|
+
The sum of the values in the hash will always add up to one.
|
46
|
+
|
34
47
|
## Contribution
|
35
48
|
|
36
49
|
If there's a metric you'd like to see implemented, please send a pull request or open an issue.
|
data/lib/svg_profiler.rb
CHANGED
data/lib/svg_profiler/base.rb
CHANGED
@@ -0,0 +1,48 @@
|
|
1
|
+
class SVGProfiler::Histogram
|
2
|
+
|
3
|
+
def self.for(png, threshold)
|
4
|
+
new(png).histogram(threshold)
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(png)
|
8
|
+
check_for_imagemagick
|
9
|
+
@image = Magick::Image.read(png.path).first
|
10
|
+
end
|
11
|
+
|
12
|
+
def histogram(threshold)
|
13
|
+
@image.quantize(8) # 00-FF is 8-bits.
|
14
|
+
|
15
|
+
histogram = @image.color_histogram
|
16
|
+
frequencies = histogram.inject({}) do |hash, (p, f)|
|
17
|
+
hash.merge(to_hex(p) => f)
|
18
|
+
end
|
19
|
+
|
20
|
+
ratios = normalize(frequencies)
|
21
|
+
ratios.reject! { |_, v| v < threshold }
|
22
|
+
|
23
|
+
# Re-normalize after thresholding.
|
24
|
+
normalize(ratios)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def check_for_imagemagick
|
29
|
+
unless system("which convert &>/dev/null")
|
30
|
+
raise DependencyError.new(
|
31
|
+
"Could not locate Imagemagick, try `brew install imagemagick'"
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_hex(pixel)
|
37
|
+
# The first two parameters are ignored by RMagick.
|
38
|
+
pixel.to_color(Magick::AllCompliance, false, 8, true)
|
39
|
+
end
|
40
|
+
|
41
|
+
def normalize(frequencies)
|
42
|
+
sum = frequencies.values.inject(:+)
|
43
|
+
frequencies.inject({}) do |hash, (k, v)|
|
44
|
+
hash.merge(k => v.to_f / sum)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -2,11 +2,7 @@ class SVGProfiler::Inkscape
|
|
2
2
|
|
3
3
|
def initialize(xml)
|
4
4
|
check_for_inkscape
|
5
|
-
|
6
|
-
input = Tempfile.new(["input", ".svg"])
|
7
|
-
input.write(xml.to_s)
|
8
|
-
input.close
|
9
|
-
@path = input.path
|
5
|
+
@xml = xml
|
10
6
|
end
|
11
7
|
|
12
8
|
def width
|
@@ -17,6 +13,15 @@ class SVGProfiler::Inkscape
|
|
17
13
|
exec("-H").to_i
|
18
14
|
end
|
19
15
|
|
16
|
+
def yield_png(&block)
|
17
|
+
tmp = Tempfile.new(["tmp", ".png"])
|
18
|
+
write_png(tmp.path)
|
19
|
+
yield tmp
|
20
|
+
ensure
|
21
|
+
tmp.close
|
22
|
+
tmp.unlink
|
23
|
+
end
|
24
|
+
|
20
25
|
private
|
21
26
|
def check_for_inkscape
|
22
27
|
unless system("which inkscape &>/dev/null")
|
@@ -27,7 +32,17 @@ class SVGProfiler::Inkscape
|
|
27
32
|
end
|
28
33
|
|
29
34
|
def exec(command)
|
30
|
-
|
35
|
+
input = Tempfile.new(["input", ".svg"])
|
36
|
+
input.write(@xml.to_s)
|
37
|
+
input.close
|
38
|
+
|
39
|
+
`inkscape -z #{command} #{input.path}`
|
40
|
+
ensure
|
41
|
+
input.unlink
|
42
|
+
end
|
43
|
+
|
44
|
+
def write_png(path)
|
45
|
+
exec("-e #{path}")
|
31
46
|
end
|
32
47
|
|
33
48
|
class DependencyError < StandardError; end
|
metadata
CHANGED
@@ -1,83 +1,82 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: svg_profiler
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
- 1
|
10
|
-
version: 1.0.1
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Chris Patuzzo
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
12
|
+
date: 2013-03-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rmagick
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
25
33
|
none: false
|
26
|
-
requirements:
|
27
|
-
- -
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
segments:
|
31
|
-
- 0
|
32
|
-
version: "0"
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
33
38
|
type: :development
|
34
|
-
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
35
46
|
description: Profiles a Scalable Vector Graphics xml string.
|
36
47
|
email: chris@patuzzo.co.uk
|
37
48
|
executables: []
|
38
|
-
|
39
49
|
extensions: []
|
40
|
-
|
41
50
|
extra_rdoc_files: []
|
42
|
-
|
43
|
-
files:
|
51
|
+
files:
|
44
52
|
- README.md
|
45
53
|
- lib/svg_profiler/base.rb
|
54
|
+
- lib/svg_profiler/histogram.rb
|
46
55
|
- lib/svg_profiler/inkscape.rb
|
47
56
|
- lib/svg_profiler.rb
|
48
|
-
has_rdoc: true
|
49
57
|
homepage: https://github.com/cpatuzzo/svg_profiler
|
50
58
|
licenses: []
|
51
|
-
|
52
59
|
post_install_message:
|
53
60
|
rdoc_options: []
|
54
|
-
|
55
|
-
require_paths:
|
61
|
+
require_paths:
|
56
62
|
- lib
|
57
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
64
|
none: false
|
59
|
-
requirements:
|
60
|
-
- -
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
|
63
|
-
|
64
|
-
- 0
|
65
|
-
version: "0"
|
66
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
70
|
none: false
|
68
|
-
requirements:
|
69
|
-
- -
|
70
|
-
- !ruby/object:Gem::Version
|
71
|
-
|
72
|
-
segments:
|
73
|
-
- 0
|
74
|
-
version: "0"
|
71
|
+
requirements:
|
72
|
+
- - ! '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
75
|
requirements: []
|
76
|
-
|
77
76
|
rubyforge_project:
|
78
|
-
rubygems_version: 1.
|
77
|
+
rubygems_version: 1.8.23
|
79
78
|
signing_key:
|
80
79
|
specification_version: 3
|
81
80
|
summary: SVG Profiler
|
82
81
|
test_files: []
|
83
|
-
|
82
|
+
has_rdoc:
|