gradient 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/gradient.svg)](https://badge.fury.io/rb/gradient)
|
3
|
+
[![Build Status](https://travis-ci.org/zeeraw/gradient.svg?branch=master)](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:
|