foggy-mirror 1.0.1 → 1.2.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/CHANGELOG.md +7 -0
- data/Gemfile.lock +18 -18
- data/README.md +13 -11
- data/bin/cli +7 -0
- data/foggy-mirror.gemspec +2 -2
- data/lib/foggy-mirror/adapters/vips.rb +25 -4
- data/lib/foggy-mirror/blob.rb +9 -0
- data/lib/foggy-mirror/cli.rb +27 -5
- data/lib/foggy-mirror/color.rb +75 -0
- data/lib/foggy-mirror/exporter.rb +2 -2
- data/lib/foggy-mirror/exporters/css.rb +4 -1
- data/lib/foggy-mirror/exporters/svg.rb +35 -2
- data/lib/foggy-mirror/processor.rb +30 -22
- data/lib/foggy-mirror/version.rb +1 -1
- data/lib/foggy-mirror.rb +2 -2
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb318a75bf83a7eaa2e49ce6bad117aa28b994525ad3f2fd5917d132d9fdf9c4
|
4
|
+
data.tar.gz: 4a426b98c5eb87c053493eeea40bd138908c609681aefbab48c2b784c668231e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5980f61abdffaff14d23b7496aa1604f8735c389df2a995e39fdefb5f3646956d8190d25d4d99e740f2894a901ec9822042ee00d53667bb2fe64dbaa662b1b02
|
7
|
+
data.tar.gz: 492eb518d3102e18cdb7d43053a40a077a5bf89395ee17bccbe45afd0fe973974d1d04ca4a43ab8819aa6eadff200d9d8aaab9b5e83c0fbab612f8b8b6bca4f3
|
data/CHANGELOG.md
ADDED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
foggy-mirror (1.0
|
4
|
+
foggy-mirror (1.2.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -11,31 +11,31 @@ GEM
|
|
11
11
|
diff-lcs (1.5.0)
|
12
12
|
ffi (1.15.5)
|
13
13
|
method_source (1.0.0)
|
14
|
-
nokogiri (1.
|
14
|
+
nokogiri (1.14.2-x86_64-darwin)
|
15
15
|
racc (~> 1.4)
|
16
|
-
nokogiri (1.
|
16
|
+
nokogiri (1.14.2-x86_64-linux)
|
17
17
|
racc (~> 1.4)
|
18
|
-
pry (0.
|
18
|
+
pry (0.14.2)
|
19
19
|
coderay (~> 1.1)
|
20
20
|
method_source (~> 1.0)
|
21
|
-
pry-byebug (3.
|
21
|
+
pry-byebug (3.10.1)
|
22
22
|
byebug (~> 11.0)
|
23
|
-
pry (
|
24
|
-
racc (1.6.
|
23
|
+
pry (>= 0.13, < 0.15)
|
24
|
+
racc (1.6.2)
|
25
25
|
rake (13.0.6)
|
26
|
-
rspec (3.
|
27
|
-
rspec-core (~> 3.
|
28
|
-
rspec-expectations (~> 3.
|
29
|
-
rspec-mocks (~> 3.
|
30
|
-
rspec-core (3.
|
31
|
-
rspec-support (~> 3.
|
32
|
-
rspec-expectations (3.
|
26
|
+
rspec (3.12.0)
|
27
|
+
rspec-core (~> 3.12.0)
|
28
|
+
rspec-expectations (~> 3.12.0)
|
29
|
+
rspec-mocks (~> 3.12.0)
|
30
|
+
rspec-core (3.12.1)
|
31
|
+
rspec-support (~> 3.12.0)
|
32
|
+
rspec-expectations (3.12.2)
|
33
33
|
diff-lcs (>= 1.2.0, < 2.0)
|
34
|
-
rspec-support (~> 3.
|
35
|
-
rspec-mocks (3.
|
34
|
+
rspec-support (~> 3.12.0)
|
35
|
+
rspec-mocks (3.12.4)
|
36
36
|
diff-lcs (>= 1.2.0, < 2.0)
|
37
|
-
rspec-support (~> 3.
|
38
|
-
rspec-support (3.
|
37
|
+
rspec-support (~> 3.12.0)
|
38
|
+
rspec-support (3.12.0)
|
39
39
|
ruby-vips (2.1.4)
|
40
40
|
ffi (~> 1.12)
|
41
41
|
|
data/README.md
CHANGED
@@ -5,17 +5,13 @@
|
|
5
5
|
[](https://beezwax.net/)
|
6
6
|
|
7
7
|
foggy-mirror is a small Ruby tool that creates faux blurry versions of raster
|
8
|
-
images using
|
9
|
-
|
8
|
+
images using SVG or CSS, either through radial gradients or SVG blur filters,
|
9
|
+
with very minimal file sizes (usually under 1KB).
|
10
10
|
|
11
11
|
This is useful as a poor man's replacement for CSS's `backdrop-filter: blur()`,
|
12
12
|
as that CSS feature isn't fully supported by browsers, and sometimes you want
|
13
|
-
an element with a "frosted glass" effect
|
14
|
-
|
15
|
-
Using gradients we can achieve very smooth and infinitely scalable graphics at
|
16
|
-
very low file size (e.g. the example SVG below is only 814 bytes after gzip).
|
17
|
-
If you need a less blurry version of the original picture, then a regular blur
|
18
|
-
effect saved to JPEG/WebP may be a better value proposition.
|
13
|
+
an element with a "frosted glass" effect (also known as glassmorphism) on top
|
14
|
+
of a crispy background.
|
19
15
|
|
20
16
|
Need Ruby/Rails consulting? Contact us at [Beezwax.net](https://beezwax.net/)
|
21
17
|
|
@@ -25,9 +21,13 @@ Original raster image:
|
|
25
21
|
|
26
22
|

|
27
23
|
|
28
|
-
SVG:
|
24
|
+
SVG with blur filter:
|
25
|
+
|
26
|
+
<img src="/img/unsplash.gradients.svg" alt="foggy-mirror SVG using gradients" width="500" height="500" />
|
27
|
+
|
28
|
+
SVG with radial gradients:
|
29
29
|
|
30
|
-
<img src="/img/unsplash.svg" alt="foggy-mirror SVG" width="500" height="500" />
|
30
|
+
<img src="/img/unsplash.filter.svg" alt="foggy-mirror SVG using blur filter" width="500" height="500" />
|
31
31
|
|
32
32
|
## Installation
|
33
33
|
|
@@ -93,7 +93,9 @@ For a full list of options use `-h`:
|
|
93
93
|
```
|
94
94
|
$ foggy-mirror -h
|
95
95
|
Usage: foggy-mirror [options] [--] image_file ...
|
96
|
-
--
|
96
|
+
--format=FORMAT Which format output to generate, default: svg
|
97
|
+
--strategy=STRATEGY Which strategy to use for SVG output, default: embedded_image
|
98
|
+
--res=RESOLUTION The output resolution (how many radial gradients per dimension, default: 5)
|
97
99
|
--overlap=OVERLAP How much to overlap radial gradients
|
98
100
|
--dist=DISTRIBUTION Distribution strategy for radial gradients
|
99
101
|
--random-offset=OFFSET Upper limit for how much to randomly offset each radial gradient
|
data/bin/cli
ADDED
data/foggy-mirror.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.authors = ["Pedro Carbajal"]
|
9
9
|
spec.email = ["pedro_c@beezwax.net"]
|
10
10
|
|
11
|
-
spec.summary = "Tool to create
|
12
|
-
spec.description = "foggy-mirror takes a raster image and outputs a blurred version of it using
|
11
|
+
spec.summary = "Tool to create math-based tiny blurry versions of raster images"
|
12
|
+
spec.description = "foggy-mirror takes a raster image and outputs a blurred version of it using SVG or CSS"
|
13
13
|
spec.homepage = "https://github.com/beezwax/foggy-mirror"
|
14
14
|
spec.required_ruby_version = ">= 2.4.0"
|
15
15
|
|
@@ -5,20 +5,41 @@ rescue LoadError
|
|
5
5
|
raise LoadError, "Couldn't load 'vips' library, do you have ruby-vips in your Gemfile?"
|
6
6
|
end
|
7
7
|
|
8
|
+
require 'base64'
|
9
|
+
|
8
10
|
module FoggyMirror
|
9
11
|
class Vips
|
10
|
-
include Utils
|
11
|
-
|
12
12
|
def initialize(path)
|
13
13
|
@path = path
|
14
14
|
end
|
15
15
|
|
16
16
|
def dominant_color
|
17
|
-
|
17
|
+
color_avg(load_image(DEFAULT_RESOLUTION))
|
18
18
|
end
|
19
19
|
|
20
20
|
def color_samples(res)
|
21
|
-
square_image(res).to_a.flatten(1)
|
21
|
+
square_image(res).to_a.flatten(1)
|
22
|
+
end
|
23
|
+
|
24
|
+
# format and options are passed to Vips' #write_to_buffer.
|
25
|
+
#
|
26
|
+
# We use .gif as the default format as it's by far the most size-efficient
|
27
|
+
# format for very small images. E.g. a 5x5 GIF is around 171 bytes, while
|
28
|
+
# an equivalent PNG would be around 2780 bytes, and JPEG would be larger
|
29
|
+
# still.
|
30
|
+
#
|
31
|
+
def data_uri(res, format: '.gif', options: {})
|
32
|
+
image_type = if format.downcase.match?(/\.jpe?g/)
|
33
|
+
'jpeg'
|
34
|
+
else
|
35
|
+
format.downcase.match(/\.(png|gif)/)[1]
|
36
|
+
end
|
37
|
+
|
38
|
+
raise(ArgumentError, 'Unsupported image format') unless image_type
|
39
|
+
|
40
|
+
base64 = Base64.strict_encode64(square_image(res).write_to_buffer(format, **options)).chomp
|
41
|
+
|
42
|
+
"data:image/#{image_type};base64,#{base64}"
|
22
43
|
end
|
23
44
|
|
24
45
|
private
|
data/lib/foggy-mirror/cli.rb
CHANGED
@@ -5,6 +5,10 @@ module FoggyMirror
|
|
5
5
|
class CLI
|
6
6
|
DEFAULT_EXTENSION = '.foggy.svg'
|
7
7
|
|
8
|
+
DEFAULT_FORMAT = :svg
|
9
|
+
|
10
|
+
FORMATS = %i[svg css]
|
11
|
+
|
8
12
|
def initialize(args = ARGV)
|
9
13
|
@args = args.dup
|
10
14
|
end
|
@@ -12,6 +16,8 @@ module FoggyMirror
|
|
12
16
|
def run
|
13
17
|
@options = {}
|
14
18
|
@extension = DEFAULT_EXTENSION
|
19
|
+
@format = DEFAULT_FORMAT
|
20
|
+
@strategy = SVG::STRATEGIES.first
|
15
21
|
@stdout = false
|
16
22
|
@target_dir = nil
|
17
23
|
|
@@ -22,11 +28,19 @@ module FoggyMirror
|
|
22
28
|
@args.each do |path|
|
23
29
|
p = Processor.new(path, **@options)
|
24
30
|
|
25
|
-
|
26
|
-
|
27
|
-
|
31
|
+
output = case @format
|
32
|
+
when :svg
|
33
|
+
p.to_svg(strategy: @strategy)
|
34
|
+
when :css
|
35
|
+
@stdout = true
|
36
|
+
p.to_css
|
37
|
+
end
|
38
|
+
|
39
|
+
if @stdout
|
40
|
+
puts output
|
28
41
|
else
|
29
|
-
|
42
|
+
foggy_file = File.join(@target_dir || File.dirname(path), File.basename(path, '.*') + @extension)
|
43
|
+
IO.write(foggy_file, output)
|
30
44
|
end
|
31
45
|
end
|
32
46
|
end
|
@@ -38,6 +52,14 @@ module FoggyMirror
|
|
38
52
|
OptionParser.new do |opts|
|
39
53
|
opts.banner = 'Usage: foggy-mirror [options] [--] image_file ...'
|
40
54
|
|
55
|
+
opts.on('--format=FORMAT', FORMATS, "Which format output to generate, default: #{DEFAULT_FORMAT}") do |f|
|
56
|
+
@format = f
|
57
|
+
end
|
58
|
+
|
59
|
+
opts.on('--strategy=STRATEGY', SVG::STRATEGIES, "Which strategy to use for SVG output, default: #{SVG::STRATEGIES.first}") do |s|
|
60
|
+
@strategy = s
|
61
|
+
end
|
62
|
+
|
41
63
|
opts.on('--res=RESOLUTION', Integer, "The output resolution (how many radial gradients per dimension, default: #{DEFAULT_RESOLUTION})") do |r|
|
42
64
|
@options[:resolution] = r
|
43
65
|
end
|
@@ -46,7 +68,7 @@ module FoggyMirror
|
|
46
68
|
@options[:overlap] = o
|
47
69
|
end
|
48
70
|
|
49
|
-
opts.on('--dist=DISTRIBUTION', %w[shuffle spiral_in spiral_out scan scan_reverse], 'Distribution strategy for radial gradients') do |d|
|
71
|
+
opts.on('--dist=DISTRIBUTION', %w[shuffle spiral_in spiral_out scan scan_reverse brightness brightness_reverse], 'Distribution strategy for radial gradients') do |d|
|
50
72
|
@options[:distribution] = d.to_s
|
51
73
|
end
|
52
74
|
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FoggyMirror
|
4
|
+
class Color
|
5
|
+
RGB_WEIGHTS = [0.299, 0.587, 0.114].freeze
|
6
|
+
|
7
|
+
PADDED_RGB_HEX = '%06x'
|
8
|
+
|
9
|
+
def initialize(color)
|
10
|
+
if color.kind_of?(String)
|
11
|
+
color = color[/[A-Z0-9]{6}/i].to_i(16)
|
12
|
+
elsif color.kind_of?(Array)
|
13
|
+
color = (color[0] << 16) + (color[1] << 8) + color[2]
|
14
|
+
end
|
15
|
+
|
16
|
+
color = color.to_i
|
17
|
+
|
18
|
+
if color > 0xFFFFFF || color < 0
|
19
|
+
raise ArgumentError, "out of range color value (#{color < 0 ? '-' : ''}0x#{color.abs.to_s(16).upcase})"
|
20
|
+
end
|
21
|
+
|
22
|
+
@value = color.to_i
|
23
|
+
end
|
24
|
+
|
25
|
+
def brightness(weights: RGB_WEIGHTS)
|
26
|
+
Math.sqrt(
|
27
|
+
weights[0] * red ** 2 +
|
28
|
+
weights[1] * green ** 2 +
|
29
|
+
weights[2] * blue ** 2
|
30
|
+
).to_i
|
31
|
+
end
|
32
|
+
|
33
|
+
def red
|
34
|
+
(@value & 0xFF0000) >> 16
|
35
|
+
end
|
36
|
+
|
37
|
+
def green
|
38
|
+
(@value & 0x00FF00) >> 8
|
39
|
+
end
|
40
|
+
|
41
|
+
def blue
|
42
|
+
@value & 0x0000FF
|
43
|
+
end
|
44
|
+
|
45
|
+
def ==(oth)
|
46
|
+
oth.to_i == @value
|
47
|
+
end
|
48
|
+
alias_method :eql?, :==
|
49
|
+
|
50
|
+
def hash
|
51
|
+
@value.hash
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_s(prefix: '#', shorthand: true)
|
55
|
+
if shorthand
|
56
|
+
return 'red' if @value == 0xFF0000
|
57
|
+
|
58
|
+
if (@value & 0xF0F0F0) == (@value & 0x0F0F0F) << 4
|
59
|
+
hex = to_s(prefix: '', shorthand: false)
|
60
|
+
return prefix.to_s + hex[0] + hex[2] + hex[4]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
prefix.to_s + (PADDED_RGB_HEX % @value).upcase
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_i
|
68
|
+
@value
|
69
|
+
end
|
70
|
+
|
71
|
+
def inspect
|
72
|
+
"#<#{self.class.name} #{to_s}>"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -6,14 +6,14 @@ module FoggyMirror
|
|
6
6
|
class Exporter
|
7
7
|
extend Forwardable
|
8
8
|
|
9
|
-
def_delegators :@processor, :base_color, :resolution, :blobs
|
9
|
+
def_delegators :@processor, :base_color, :resolution, :blobs, :data_uri
|
10
10
|
|
11
11
|
def initialize(processor)
|
12
12
|
@processor = processor
|
13
13
|
end
|
14
14
|
|
15
15
|
def render
|
16
|
-
raise
|
16
|
+
raise NoMethodError
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
@@ -2,6 +2,9 @@
|
|
2
2
|
|
3
3
|
module FoggyMirror
|
4
4
|
class CSS < Exporter
|
5
|
+
# If hash is true it returns a Ruby Hash with the CSS properties instead of
|
6
|
+
# a CSS-ready string
|
7
|
+
#
|
5
8
|
def render(hash: false)
|
6
9
|
if hash
|
7
10
|
return {
|
@@ -18,7 +21,7 @@ module FoggyMirror
|
|
18
21
|
def radial_gradients
|
19
22
|
blobs.map do |b|
|
20
23
|
x, y, r = [b.x, b.y, b.r].map { |c| (c * 100).round(1) }
|
21
|
-
"radial-gradient(circle at #{x}% #{y}%, #{b.color} 0%, #{b.color}00 #{r}%)"
|
24
|
+
"radial-gradient(circle at #{x}% #{y}%, #{b.color} 0%, #{b.color.to_s(shorthand: false)}00 #{r}%)"
|
22
25
|
end
|
23
26
|
end
|
24
27
|
end
|
@@ -8,12 +8,28 @@ module FoggyMirror
|
|
8
8
|
|
9
9
|
VIEWBOX_SIZE = 1000
|
10
10
|
|
11
|
-
|
11
|
+
STRATEGIES = %i[embedded_image gradients]
|
12
|
+
|
13
|
+
def render(strategy: STRATEGIES.first)
|
14
|
+
strategy = STRATEGIES.first if strategy.nil?
|
15
|
+
|
16
|
+
unless STRATEGIES.include?(strategy.to_sym)
|
17
|
+
raise ArgumentError, "Invalid SVG rendering strategy `#{strategy}'"
|
18
|
+
end
|
19
|
+
|
20
|
+
send("render_#{strategy}")
|
21
|
+
end
|
22
|
+
|
23
|
+
def render_gradients
|
12
24
|
"#{header}<defs>#{radial_gradients.join}</defs>#{circles.join}</svg>"
|
13
25
|
end
|
14
26
|
|
27
|
+
def render_embedded_image
|
28
|
+
"#{header}#{blur_filter}#{embedded_image}</svg>"
|
29
|
+
end
|
30
|
+
|
15
31
|
def header
|
16
|
-
%{#{XML_HEADER}<svg viewBox="0 0 #{VIEWBOX_SIZE} #{VIEWBOX_SIZE}" xmlns="http://www.w3.org/2000/svg" version="1.1" style="background-color:#{base_color}">}
|
32
|
+
%{#{XML_HEADER}<svg width="#{VIEWBOX_SIZE}" height="#{VIEWBOX_SIZE}" preserveAspectRatio="none" viewBox="0 0 #{VIEWBOX_SIZE} #{VIEWBOX_SIZE}" xmlns="http://www.w3.org/2000/svg" version="1.1" style="background-color:#{base_color}">}
|
17
33
|
end
|
18
34
|
|
19
35
|
def radial_gradients
|
@@ -37,5 +53,22 @@ module FoggyMirror
|
|
37
53
|
Hash[blobs.map(&:color).uniq.map { |c| [c, id.dup].tap { id.succ! } }]
|
38
54
|
end
|
39
55
|
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def blur_filter
|
60
|
+
<<~FILTER.lines.map(&:strip).join
|
61
|
+
<filter id="b" color-interpolation-filters="sRGB">
|
62
|
+
<feGaussianBlur in="SourceGraphic" stdDeviation="30"/>
|
63
|
+
<feComponentTransfer>
|
64
|
+
<feFuncA type="discrete" tableValues="1 1"/>
|
65
|
+
</feComponentTransfer>
|
66
|
+
</filter>
|
67
|
+
FILTER
|
68
|
+
end
|
69
|
+
|
70
|
+
def embedded_image
|
71
|
+
%{<image href="#{data_uri}" width="#{VIEWBOX_SIZE}" height="#{VIEWBOX_SIZE}" filter="url(#b)"/>}
|
72
|
+
end
|
40
73
|
end
|
41
74
|
end
|
@@ -17,18 +17,14 @@ module FoggyMirror
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def base_color
|
20
|
-
@base_color ||= adapter.dominant_color
|
21
|
-
end
|
22
|
-
|
23
|
-
def color_samples
|
24
|
-
@color_samples ||= adapter.color_samples(resolution)
|
20
|
+
@base_color ||= Color.new(adapter.dominant_color)
|
25
21
|
end
|
26
22
|
|
27
23
|
def to_css(hash: false)
|
28
24
|
CSS.new(self).render(hash: hash)
|
29
25
|
end
|
30
26
|
|
31
|
-
def to_svg
|
27
|
+
def to_svg(strategy: nil)
|
32
28
|
SVG.new(self).render
|
33
29
|
end
|
34
30
|
|
@@ -57,30 +53,25 @@ module FoggyMirror
|
|
57
53
|
spiral_in(blobs).reverse
|
58
54
|
when 'scan_reverse'
|
59
55
|
blobs.reverse
|
56
|
+
when 'brightness'
|
57
|
+
blobs.sort_by { |b| b.color.brightness }
|
58
|
+
when 'brightness_reverse'
|
59
|
+
blobs.sort_by { |b| 255 - b.color.brightness }
|
60
60
|
else
|
61
61
|
blobs
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
matrix = array.each_slice(Math.sqrt(array.size).to_i).to_a
|
69
|
-
|
70
|
-
actions = [
|
71
|
-
-> { matrix.shift }, # top
|
72
|
-
-> { matrix.map { |f| f.pop } }, # right
|
73
|
-
-> { matrix.pop.reverse }, # bottom
|
74
|
-
-> { matrix.map { |f| f.shift }.reverse } # left
|
75
|
-
]
|
76
|
-
|
77
|
-
peel = actions.cycle
|
65
|
+
def data_uri
|
66
|
+
@data_uri ||= adapter.data_uri(resolution)
|
67
|
+
end
|
78
68
|
|
79
|
-
|
80
|
-
|
81
|
-
end
|
69
|
+
def color_samples
|
70
|
+
@color_samples ||= adapter.color_samples(resolution)
|
82
71
|
end
|
83
72
|
|
73
|
+
private
|
74
|
+
|
84
75
|
def default_adapter
|
85
76
|
require 'vips'
|
86
77
|
Vips
|
@@ -97,5 +88,22 @@ module FoggyMirror
|
|
97
88
|
|
98
89
|
raise Error, "`adapter' must be an adapter class or an adapter name (#{ADAPTERS.keys.join(', ')})"
|
99
90
|
end
|
91
|
+
|
92
|
+
def spiral_in(array)
|
93
|
+
matrix = array.each_slice(Math.sqrt(array.size).to_i).to_a
|
94
|
+
|
95
|
+
actions = [
|
96
|
+
-> { matrix.shift }, # top
|
97
|
+
-> { matrix.map { |f| f.pop } }, # right
|
98
|
+
-> { matrix.pop.reverse }, # bottom
|
99
|
+
-> { matrix.map { |f| f.shift }.reverse } # left
|
100
|
+
]
|
101
|
+
|
102
|
+
peel = actions.cycle
|
103
|
+
|
104
|
+
[].tap do |r|
|
105
|
+
r.concat(peel.next.call) until matrix.empty?
|
106
|
+
end
|
107
|
+
end
|
100
108
|
end
|
101
109
|
end
|
data/lib/foggy-mirror/version.rb
CHANGED
data/lib/foggy-mirror.rb
CHANGED
@@ -12,9 +12,9 @@ module FoggyMirror
|
|
12
12
|
magick: -> { FoggyMirror::ImageMagick }
|
13
13
|
}.freeze
|
14
14
|
|
15
|
-
Blob = Struct.new(:x, :y, :r, :color, keyword_init: true)
|
16
|
-
|
17
15
|
autoload :Processor, 'foggy-mirror/processor'
|
16
|
+
autoload :Color, 'foggy-mirror/color'
|
17
|
+
autoload :Blob, 'foggy-mirror/blob'
|
18
18
|
autoload :CLI, 'foggy-mirror/cli'
|
19
19
|
autoload :Utils, 'foggy-mirror/utils'
|
20
20
|
autoload :ImageMagick, 'foggy-mirror/adapters/image_magick'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foggy-mirror
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pedro Carbajal
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-03-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-vips
|
@@ -81,7 +81,7 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
description: foggy-mirror takes a raster image and outputs a blurred version of it
|
84
|
-
using
|
84
|
+
using SVG or CSS
|
85
85
|
email:
|
86
86
|
- pedro_c@beezwax.net
|
87
87
|
executables:
|
@@ -92,11 +92,13 @@ files:
|
|
92
92
|
- ".github/workflows/main.yml"
|
93
93
|
- ".gitignore"
|
94
94
|
- ".rspec"
|
95
|
+
- CHANGELOG.md
|
95
96
|
- Gemfile
|
96
97
|
- Gemfile.lock
|
97
98
|
- LICENSE.txt
|
98
99
|
- README.md
|
99
100
|
- Rakefile
|
101
|
+
- bin/cli
|
100
102
|
- bin/console
|
101
103
|
- bin/setup
|
102
104
|
- exe/foggy-mirror
|
@@ -104,7 +106,9 @@ files:
|
|
104
106
|
- lib/foggy-mirror.rb
|
105
107
|
- lib/foggy-mirror/adapters/image_magick.rb
|
106
108
|
- lib/foggy-mirror/adapters/vips.rb
|
109
|
+
- lib/foggy-mirror/blob.rb
|
107
110
|
- lib/foggy-mirror/cli.rb
|
111
|
+
- lib/foggy-mirror/color.rb
|
108
112
|
- lib/foggy-mirror/exporter.rb
|
109
113
|
- lib/foggy-mirror/exporters/css.rb
|
110
114
|
- lib/foggy-mirror/exporters/svg.rb
|
@@ -134,5 +138,5 @@ requirements: []
|
|
134
138
|
rubygems_version: 3.3.3
|
135
139
|
signing_key:
|
136
140
|
specification_version: 4
|
137
|
-
summary: Tool to create
|
141
|
+
summary: Tool to create math-based tiny blurry versions of raster images
|
138
142
|
test_files: []
|