gradient 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/README.md +49 -3
- data/Rakefile +2 -2
- data/gradient.gemspec +2 -1
- data/lib/gradient.rb +2 -1
- data/lib/gradient/map.rb +48 -1
- data/lib/gradient/svg.rb +118 -0
- data/lib/gradient/version.rb +1 -1
- metadata +19 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 16b46fdf7f784862a6e05230f8717e4485c5794c
|
4
|
+
data.tar.gz: c677d43ca0e4cb0a3df7e28811ec9a442b8b7dce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 040beeb18b21d234a733d1790d37f8c0508255cc6f44dcaa5dfaad1a08445736a0ffb0b771beb633b349c808b69e71bb8535788d82b4ef8497c9eadfcd06fa5c
|
7
|
+
data.tar.gz: a6b6060794a681c72d6609af073c0b2f2fde4ec9c247de2c6f65f07ac60bfcabbf449a6810d08257d28aaf6d1a7e52edb39bddaf71c8ce90d3525f92da0251dc
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
# Gradient
|
2
|
+
[](https://badge.fury.io/rb/gradient)
|
3
|
+
[](https://travis-ci.org/zeeraw/gradient)
|
4
|
+
|
2
5
|
Library for dealing with color gradients in ruby
|
3
6
|
|
4
7
|
## Usage
|
@@ -40,8 +43,28 @@ printer.radial(shape: :circle)
|
|
40
43
|
# => "radial-gradient(circle, rgba(30,87,153,1.0) 0%, rgba(41,137,216,0.02) 49%, rgba(37,131,209,0.0) 50%, rgba(32,124,202,0.02) 51%, rgba(125,185,232,1.0) 100%)"
|
41
44
|
```
|
42
45
|
|
43
|
-
###
|
44
|
-
|
46
|
+
### Serialize & deserialize gradients
|
47
|
+
To store your gradients in something like a document database,
|
48
|
+
you're able to convert a gradient to primitives using `Gradient::Map#serialize`.
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
Gradient::Map.new(
|
52
|
+
Gradient::Point.new(0, Color::RGB.new(221, 189, 82), 1.0),
|
53
|
+
Gradient::Point.new(1, Color::RGB.new(89, 12, 72), 0.3)
|
54
|
+
).serialize
|
55
|
+
# => [[0, "rgb", [221, 189, 82], 1.0], [1, "rgb", [89, 12, 72], 0.3]]
|
56
|
+
|
57
|
+
```
|
58
|
+
|
59
|
+
You can easily turn them back in to ruby objects by using `Gradient::Map.deserialize`.
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
Gradient::Map.deserialize([[0, "rgb", [221, 189, 82], 1.0], [1, "rgb", [89, 12, 72], 0.3]])
|
63
|
+
# => #<Gradient Map #<Point 0 #ddbd52ff> #<Point 100 #590c484d>>
|
64
|
+
```
|
65
|
+
|
66
|
+
### Import Adobe Photoshop gradient (`.grd`) files
|
67
|
+
For many artists, a preferred way of creating gradients is through Photoshop.
|
45
68
|
You are able to parse `.grd` files and turn them in to a hash of `Gradient::Map` objects.
|
46
69
|
|
47
70
|
```ruby
|
@@ -51,6 +74,17 @@ Gradient::GRD.read("./kiwi.grd")
|
|
51
74
|
# }
|
52
75
|
```
|
53
76
|
|
77
|
+
### Import SVG gradients
|
78
|
+
SVG images can contain multiple gradients, and these can be extracted in the same
|
79
|
+
way as for [`.grd`](#import-adobe-photoshop-gradient-grd-files) files.
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
Gradient::SVG.read("./lemon-lime.svg")
|
83
|
+
# => {
|
84
|
+
# "Lemon-Lime"=> #<Gradient Map #<Point 0.0 #ffff00ff> #<Point 20.0 #ffff00ff> #<Point 50.0 #00ff00ff> #<Point 80.0 #ffff00ff> #<Point 100.0 #ffff00ff>>}"
|
85
|
+
# }
|
86
|
+
```
|
87
|
+
|
54
88
|
### Separate point vectors for opacity and color
|
55
89
|
You're able to control the point vectors for color and opacity separately by using a point merger.
|
56
90
|
|
@@ -74,6 +108,18 @@ gradient = Gradient::Map.new(points)
|
|
74
108
|
# => #<Gradient Map #<Point 0 #1e5799ff> #<Point 49.0 #2989d805> #<Point 50.0 #2583d100> #<Point 51.0 #207cca05> #<Point 100 #7db9e8ff>>
|
75
109
|
```
|
76
110
|
|
111
|
+
### Interpolation
|
112
|
+
One can find the color and opacity at an arbitrary location using the `#at` method, which returns a new `Gradient::Point`.
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
map = Gradient::Map.new(
|
116
|
+
Gradient::Point.new(0, Color::RGB.new(0, 128, 255), 1.0),
|
117
|
+
Gradient::Point.new(1, Color::RGB.new(255, 128, 0), 0.0)
|
118
|
+
)
|
119
|
+
map.at(0.5)
|
120
|
+
# => #<Point 50.0 #80808080>
|
121
|
+
```
|
122
|
+
|
77
123
|
## Installation
|
78
124
|
Add this line to your application's Gemfile:
|
79
125
|
|
@@ -98,7 +144,7 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
98
144
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
99
145
|
|
100
146
|
## Contributing
|
101
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/zeeraw/gradient. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
147
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/zeeraw/gradient. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
102
148
|
|
103
149
|
## License
|
104
150
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
CHANGED
data/gradient.gemspec
CHANGED
@@ -20,7 +20,8 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
22
|
spec.add_dependency "color", "~> 1.8"
|
23
|
-
spec.
|
23
|
+
spec.add_dependency 'nokogiri', '~> 1.6'
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
24
25
|
spec.add_development_dependency "rake", "~> 10.0"
|
25
26
|
spec.add_development_dependency "rspec"
|
26
27
|
spec.add_development_dependency "pry"
|
data/lib/gradient.rb
CHANGED
data/lib/gradient/map.rb
CHANGED
@@ -18,6 +18,26 @@ module Gradient
|
|
18
18
|
"#<Gradient Map #{points.map(&:inspect).join(" ")}>"
|
19
19
|
end
|
20
20
|
|
21
|
+
def range
|
22
|
+
@range ||=
|
23
|
+
begin
|
24
|
+
ends = [:first, :last]
|
25
|
+
.map { |method| points.send(method) }
|
26
|
+
.map(&:location)
|
27
|
+
Range.new(*ends)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def at(location, opts = {})
|
32
|
+
if range.include? location then
|
33
|
+
if 0 == (i = points.find_index { |p| p.location >= location }) then
|
34
|
+
points[0].dup
|
35
|
+
else
|
36
|
+
interpolate_points(points[i-1], points[i], location)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
21
41
|
def to_css(**args)
|
22
42
|
@css_printer ||= Gradient::CSSPrinter.new(self)
|
23
43
|
@css_printer.css(**args)
|
@@ -31,5 +51,32 @@ module Gradient
|
|
31
51
|
serialize
|
32
52
|
end
|
33
53
|
|
54
|
+
private
|
55
|
+
|
56
|
+
def interpolate_points(point_left, point_right, location)
|
57
|
+
points = [point_left, point_right]
|
58
|
+
color_left, color_right = points.map(&:color)
|
59
|
+
location_left, location_right = points.map(&:location)
|
60
|
+
separation = location_right - location_left
|
61
|
+
if separation == 0.0 then
|
62
|
+
point_right.dup
|
63
|
+
else
|
64
|
+
weight = (location - location_left)/separation
|
65
|
+
r, g, b = [:r, :g, :b].map do |channel|
|
66
|
+
interpolate_floats(color_left.send(channel),
|
67
|
+
color_right.send(channel),
|
68
|
+
weight)
|
69
|
+
end
|
70
|
+
color = Color::RGB.from_fraction(r, g, b)
|
71
|
+
opacity = interpolate_floats(point_left.opacity,
|
72
|
+
point_right.opacity,
|
73
|
+
weight)
|
74
|
+
Point.new(location, color, opacity)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def interpolate_floats(x0, x1, weight)
|
79
|
+
x0 * (1.0 - weight) + x1 * weight
|
80
|
+
end
|
34
81
|
end
|
35
|
-
end
|
82
|
+
end
|
data/lib/gradient/svg.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'scanf'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module Gradient
|
5
|
+
|
6
|
+
class SVGError < StandardError ; end
|
7
|
+
|
8
|
+
class SVG
|
9
|
+
|
10
|
+
attr_reader :maps
|
11
|
+
|
12
|
+
class << self
|
13
|
+
|
14
|
+
def parse(string_buffer)
|
15
|
+
new.tap do |parser|
|
16
|
+
parser.parse(string_buffer)
|
17
|
+
end.maps
|
18
|
+
end
|
19
|
+
|
20
|
+
def read(file)
|
21
|
+
new.tap do |parser|
|
22
|
+
File.open(file, 'r') do |file|
|
23
|
+
parser.parse(file.read)
|
24
|
+
end
|
25
|
+
end.maps
|
26
|
+
end
|
27
|
+
|
28
|
+
def open(file)
|
29
|
+
read(file)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize
|
35
|
+
@maps = {}
|
36
|
+
end
|
37
|
+
|
38
|
+
SVGNS = 'http://www.w3.org/2000/svg'
|
39
|
+
|
40
|
+
def parse(buffer)
|
41
|
+
xml = Nokogiri::XML(buffer)
|
42
|
+
(
|
43
|
+
xml.xpath('//linearGradient') +
|
44
|
+
xml.xpath('//xmlns:linearGradient', 'xmlns' => SVGNS)
|
45
|
+
).each do |linear_gradient|
|
46
|
+
unless (id = linear_gradient['id']) then
|
47
|
+
raise SVGError, 'linearGradient has no id'
|
48
|
+
end
|
49
|
+
unless (map = parse_linear_gradient(linear_gradient)).points.empty?
|
50
|
+
@maps[id] = map
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private def parse_linear_gradient(linear_gradient)
|
56
|
+
map = Gradient::Map.new
|
57
|
+
linear_gradient.children.each do |node|
|
58
|
+
next unless node.name == 'stop'
|
59
|
+
map.points << parse_stop(node)
|
60
|
+
end
|
61
|
+
map
|
62
|
+
end
|
63
|
+
|
64
|
+
private def parse_stop(stop)
|
65
|
+
unless (offset = stop['offset']) then
|
66
|
+
raise SVGError, 'stop has no offset'
|
67
|
+
end
|
68
|
+
location = parse_location(offset)
|
69
|
+
if (style = stop['style']) then
|
70
|
+
point_from_style(location, style)
|
71
|
+
else
|
72
|
+
point_from_stop(location, stop)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
private def point_from_style(location, style)
|
77
|
+
stop = Hash[ style.split(/;/).map { |item| item.split(/:/) } ]
|
78
|
+
point_from_stop(location, stop)
|
79
|
+
end
|
80
|
+
|
81
|
+
private def point_from_stop(location, stop)
|
82
|
+
unless (stop_color = stop['stop-color']) then
|
83
|
+
raise SVGError, 'stop has no stop-color'
|
84
|
+
end
|
85
|
+
color, opacity = parse_stop_color(stop_color)
|
86
|
+
if (stop_opacity = stop['stop-opacity']) then
|
87
|
+
opacity = parse_stop_opacity(stop_opacity)
|
88
|
+
end
|
89
|
+
Gradient::Point.new(location, color, opacity)
|
90
|
+
end
|
91
|
+
|
92
|
+
private def parse_location(offset)
|
93
|
+
unless (location = offset.scanf('%f%%')).count == 1 then
|
94
|
+
raise SVGError, "failed parse of offset #{offset}"
|
95
|
+
end
|
96
|
+
location.first / 100.0
|
97
|
+
end
|
98
|
+
|
99
|
+
private def parse_stop_color(stop_color)
|
100
|
+
parts =
|
101
|
+
if (r, g, b = stop_color.scanf('rgb(%d,%d,%d)')).count == 3 then
|
102
|
+
[Color::RGB.new(r, g, b), 1.0]
|
103
|
+
elsif (r, g, b, a = stop_color.scanf('rgba(%d,%d,%d,%f)')).count == 4 then
|
104
|
+
[Color::RGB.new(r, g, b), a]
|
105
|
+
elsif (color = Color::RGB.by_css(stop_color)) then
|
106
|
+
[color, 1.0]
|
107
|
+
end
|
108
|
+
unless parts then
|
109
|
+
raise SVGError, "failed parse of stop-color #{stop_color}"
|
110
|
+
end
|
111
|
+
parts
|
112
|
+
end
|
113
|
+
|
114
|
+
private def parse_stop_opacity(stop_opacity)
|
115
|
+
stop_opacity.scanf('%f').first
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/lib/gradient/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gradient
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Philip Vieira
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: color
|
@@ -24,20 +24,34 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: nokogiri
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: bundler
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - "~>"
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
47
|
+
version: '1.7'
|
34
48
|
type: :development
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1.
|
54
|
+
version: '1.7'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rake
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -119,6 +133,7 @@ files:
|
|
119
133
|
- lib/gradient/opacity_point.rb
|
120
134
|
- lib/gradient/point.rb
|
121
135
|
- lib/gradient/point_merger.rb
|
136
|
+
- lib/gradient/svg.rb
|
122
137
|
- lib/gradient/version.rb
|
123
138
|
homepage: https://github.com/zeeraw/gradient
|
124
139
|
licenses:
|