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 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.
@@ -1,4 +1,7 @@
1
1
  require "tempfile"
2
2
 
3
+ require "rmagick"
4
+
3
5
  require "svg_profiler/base"
4
6
  require "svg_profiler/inkscape"
7
+ require "svg_profiler/histogram"
@@ -20,4 +20,8 @@ class SVGProfiler
20
20
  width.to_f / height
21
21
  end
22
22
 
23
+ def colors(threshold = 0)
24
+ @inkscape.yield_png { |png| Histogram.for(png, threshold) }
25
+ end
26
+
23
27
  end
@@ -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
- `inkscape -z #{command} #@path`
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
- hash: 21
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
- date: 2013-03-09 00:00:00 +00:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
22
- name: rspec
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
- requirement: &id001 !ruby/object:Gem::Requirement
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
- hash: 3
30
- segments:
31
- - 0
32
- version: "0"
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
33
38
  type: :development
34
- version_requirements: *id001
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
- hash: 3
63
- segments:
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
- hash: 3
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.6.2
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: