pixelart 1.3.2 → 1.3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Manifest.txt +1 -3
- data/README.md +6 -0
- data/Rakefile +2 -1
- data/lib/pixelart/base.rb +13 -34
- data/lib/pixelart/convert.rb +54 -0
- data/lib/pixelart/image.rb +55 -5
- data/lib/pixelart/version.rb +1 -1
- data/lib/pixelart.rb +10 -0
- metadata +20 -8
- data/lib/pixelart/color.rb +0 -131
- data/lib/pixelart/gradient.rb +0 -106
- data/lib/pixelart/palette.rb +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43bc0ad17527099593a49e143036c875bf93fc61873d551252a19376490734fd
|
4
|
+
data.tar.gz: c57fdb4d5241915767f4480a698f3f362d25c53f99805050b8c8dd4c2ca9ec27
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 742db57f909288c2a19105244951f676c99723544be749e60544d3576f326f323ec00bcdf0ea9fbeef0e6a6a0d55771f5ad06a7e5fe1a32814b6f509bc472be4
|
7
|
+
data.tar.gz: 2b7d05f9e4ab9a4f4348b3fb7b7f1f5b36ee884b4db3bae901479c84c4dac0207f67f56ba140319a45bd1704c9af14075ef7dfc3ef20897476dfc5bf242a509c
|
data/Manifest.txt
CHANGED
@@ -6,14 +6,12 @@ lib/pixelart.rb
|
|
6
6
|
lib/pixelart/base.rb
|
7
7
|
lib/pixelart/blur.rb
|
8
8
|
lib/pixelart/circle.rb
|
9
|
-
lib/pixelart/color.rb
|
10
9
|
lib/pixelart/composite.rb
|
10
|
+
lib/pixelart/convert.rb
|
11
11
|
lib/pixelart/generator.rb
|
12
|
-
lib/pixelart/gradient.rb
|
13
12
|
lib/pixelart/image.rb
|
14
13
|
lib/pixelart/led.rb
|
15
14
|
lib/pixelart/misc.rb
|
16
|
-
lib/pixelart/palette.rb
|
17
15
|
lib/pixelart/pixelator.rb
|
18
16
|
lib/pixelart/sample.rb
|
19
17
|
lib/pixelart/silhouette.rb
|
data/README.md
CHANGED
@@ -288,3 +288,9 @@ Just install the gem:
|
|
288
288
|
|
289
289
|
The scripts are dedicated to the public domain.
|
290
290
|
Use it as you please with no restrictions whatsoever.
|
291
|
+
|
292
|
+
|
293
|
+
|
294
|
+
## Questions? Comments?
|
295
|
+
|
296
|
+
Post them on the [D.I.Y. Punk (Pixel) Art reddit](https://old.reddit.com/r/DIYPunkArt). Thanks.
|
data/Rakefile
CHANGED
data/lib/pixelart/base.rb
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
require 'cocos'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
|
5
|
+
###
|
6
|
+
# base module
|
7
|
+
require 'pixelart/colors'
|
8
|
+
|
9
|
+
|
10
|
+
|
1
11
|
###############
|
2
12
|
# 3rd party
|
3
13
|
require 'chunky_png'
|
@@ -7,27 +17,9 @@ require 'chunky_png'
|
|
7
17
|
require 'mini_magick'
|
8
18
|
|
9
19
|
|
10
|
-
# bonus / prologue / convenience 3rd party
|
11
|
-
require 'csvreader'
|
12
|
-
|
13
|
-
|
14
|
-
## stdlib
|
15
|
-
require 'pp'
|
16
|
-
require 'time'
|
17
|
-
require 'date'
|
18
|
-
require 'fileutils'
|
19
|
-
|
20
|
-
require 'json'
|
21
|
-
require 'yaml'
|
22
|
-
|
23
|
-
|
24
|
-
|
25
20
|
|
26
21
|
## our own code
|
27
22
|
require 'pixelart/version' # note: let version always go first
|
28
|
-
require 'pixelart/color'
|
29
|
-
require 'pixelart/gradient'
|
30
|
-
require 'pixelart/palette'
|
31
23
|
require 'pixelart/image'
|
32
24
|
require 'pixelart/composite'
|
33
25
|
|
@@ -71,22 +63,9 @@ require 'pixelart/blur'
|
|
71
63
|
|
72
64
|
|
73
65
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
##########
|
79
|
-
# add some spelling convenience variants
|
80
|
-
PixelArt = Pixelart
|
81
|
-
|
82
|
-
module Pixelart
|
83
|
-
Palette256 = Palette8Bit = Palette8bit
|
84
|
-
|
85
|
-
Palette256Image = Palette8BitImage = Palette8bitImage =
|
86
|
-
ImagePalette256 = ImagePalette8Bit = ImagePalette8bit
|
87
|
-
|
88
|
-
CompositeImage = ImageComposite
|
89
|
-
end
|
66
|
+
###
|
67
|
+
# mover helpers / utils
|
68
|
+
require 'pixelart/convert'
|
90
69
|
|
91
70
|
|
92
71
|
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Pixelart
|
2
|
+
|
3
|
+
class Image
|
4
|
+
|
5
|
+
|
6
|
+
## helper to convert (all) image in directory
|
7
|
+
## chech: move to ImageUtils.convert or such - why? why not?
|
8
|
+
##
|
9
|
+
## what about the name e.g. rename to convert_dir or
|
10
|
+
## batch_convert such - why? why not?
|
11
|
+
def self.convert( dir, from: 'jpg',
|
12
|
+
to: 'png',
|
13
|
+
outdir: nil,
|
14
|
+
overwrite: true )
|
15
|
+
|
16
|
+
outdir = dir if outdir.nil?
|
17
|
+
|
18
|
+
files = Dir.glob( "#{dir}/*.#{from}" )
|
19
|
+
puts "==> found #{files.size} image(s) to convert from #{from} to #{to} (overwrite mode set to: #{overwrite})"
|
20
|
+
|
21
|
+
files.each_with_index do |file,i|
|
22
|
+
dirname = File.dirname( file )
|
23
|
+
extname = File.extname( file )
|
24
|
+
basename = File.basename( file, extname )
|
25
|
+
|
26
|
+
## skip convert if target / dest file already exists
|
27
|
+
next if overwrite == false && File.exist?( "#{outdir}/#{basename}.#{to}" )
|
28
|
+
|
29
|
+
## note: make sure outdir exists (magic will not create it??)
|
30
|
+
FileUtils.mkdir_p( outdir ) unless Dir.exist?( outdir )
|
31
|
+
|
32
|
+
cmd = "magick convert #{dirname}/#{basename}.#{from} #{outdir}/#{basename}.#{to}"
|
33
|
+
|
34
|
+
puts " [#{i+1}/#{files.size}] - #{cmd}"
|
35
|
+
## todo/fix: check return value!!! magick comand not available (in path) and so on!!!
|
36
|
+
system( cmd )
|
37
|
+
|
38
|
+
if from == 'gif'
|
39
|
+
## assume multi-images for gif
|
40
|
+
## save image-0.png to image.png
|
41
|
+
path0 = "#{outdir}/#{basename}-0.#{to}"
|
42
|
+
path = "#{outdir}/#{basename}.#{to}"
|
43
|
+
|
44
|
+
puts " saving #{path0} to #{path}..."
|
45
|
+
|
46
|
+
blob = File.open( path0, 'rb' ) { |f| f.read }
|
47
|
+
File.open( path, 'wb' ) { |f| f.write( blob ) }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
end # class Image
|
54
|
+
end # class Pixelart
|
data/lib/pixelart/image.rb
CHANGED
@@ -2,12 +2,42 @@ module Pixelart
|
|
2
2
|
|
3
3
|
class Image
|
4
4
|
|
5
|
+
|
6
|
+
## keep track of all (inherited) subclasses via inherited hook
|
7
|
+
##
|
8
|
+
## change/rename to descendants - why? why not?
|
9
|
+
##
|
10
|
+
## note about rails (activesupport?)
|
11
|
+
## If you use rails >= 3, you have two options in place.
|
12
|
+
## Use .descendants if you want more than one level depth of children classes,
|
13
|
+
## or use .subclasses for the first level of child classes.
|
14
|
+
|
15
|
+
def self.subclasses
|
16
|
+
@subclasses ||= []
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.inherited( subclass )
|
20
|
+
subclasses << subclass
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
|
5
27
|
def self.read( path ) ## convenience helper
|
6
28
|
img_inner = ChunkyPNG::Image.from_file( path )
|
7
29
|
img = new( img_inner.width, img_inner.height, img_inner )
|
8
30
|
img
|
9
31
|
end
|
10
32
|
|
33
|
+
def self.parse_base64( str )
|
34
|
+
blob = Base64.decode64( str )
|
35
|
+
img_inner = ChunkyPNG::Image.from_blob( blob )
|
36
|
+
img = new( img_inner.width, img_inner.height, img_inner )
|
37
|
+
img
|
38
|
+
end
|
39
|
+
|
40
|
+
|
11
41
|
|
12
42
|
|
13
43
|
CHARS = '.@xo^~%*+=:' ## todo/check: rename to default chars or such? why? why not?
|
@@ -95,6 +125,16 @@ def crop( x, y, crop_width, crop_height )
|
|
95
125
|
end
|
96
126
|
|
97
127
|
|
128
|
+
## shift image n-pixels to the left (NOT changing width/height)
|
129
|
+
def left( left )
|
130
|
+
img = Image.new( width, height )
|
131
|
+
img.compose!( crop( 0, 0, width-left, height ), left, 0 )
|
132
|
+
img
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
|
137
|
+
|
98
138
|
|
99
139
|
#######################
|
100
140
|
## filter / effects
|
@@ -106,19 +146,29 @@ end
|
|
106
146
|
alias_method :greyscale, :grayscale
|
107
147
|
|
108
148
|
|
109
|
-
|
110
|
-
|
111
|
-
|
149
|
+
######################
|
150
|
+
# flip horizontally on x-axis (top-to-bottom/bottom-to-top)
|
151
|
+
# e.g. pixels on the top will now be pixels on the bottom
|
152
|
+
def flip_horizontally
|
153
|
+
img = @img.flip_horizontally
|
112
154
|
Image.new( img.width, img.height, img )
|
113
155
|
end
|
114
|
-
|
156
|
+
## keep flop? alias - why? why not?
|
157
|
+
## note: chunky_png use flip alias for flip_horizontally!!!!
|
158
|
+
alias_method :flop, :flip_horizontally
|
159
|
+
|
115
160
|
|
161
|
+
###
|
162
|
+
# flip vertially on y-axis (right-to-left/left-to-right)
|
163
|
+
# e.g. pixels on the left will now be pixels on the right
|
116
164
|
def mirror
|
117
165
|
img = @img.mirror
|
118
166
|
Image.new( img.width, img.height, img )
|
119
167
|
end
|
120
168
|
alias_method :flip_vertically, :mirror
|
121
|
-
alias_method :
|
169
|
+
alias_method :flip, :mirror ## note: chunky_png use flip alias for flip_horizontally (top-to-bottom)!!!!
|
170
|
+
alias_method :phlip, :mirror ## philip the intern ("hand-phlip one-by-one")
|
171
|
+
alias_method :hand_phlip, :mirror
|
122
172
|
|
123
173
|
|
124
174
|
def rotate_counter_clockwise # 90 degrees
|
data/lib/pixelart/version.rb
CHANGED
data/lib/pixelart.rb
CHANGED
@@ -9,4 +9,14 @@ require 'pixelart/base' # aka "strict(er)" version
|
|
9
9
|
include Pixelart
|
10
10
|
|
11
11
|
|
12
|
+
##########
|
13
|
+
# add some spelling convenience variants
|
14
|
+
|
15
|
+
|
16
|
+
module Pixelart
|
17
|
+
Palette256Image = Palette8BitImage = Palette8bitImage =
|
18
|
+
ImagePalette256 = ImagePalette8Bit = ImagePalette8bit
|
19
|
+
|
20
|
+
CompositeImage = ImageComposite
|
21
|
+
end
|
12
22
|
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pixelart
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gerald Bauer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-08-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: cocos
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: pixelart-colors
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -39,7 +39,21 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: chunky_png
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: mini_magick
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
59
|
- - ">="
|
@@ -104,14 +118,12 @@ files:
|
|
104
118
|
- lib/pixelart/base.rb
|
105
119
|
- lib/pixelart/blur.rb
|
106
120
|
- lib/pixelart/circle.rb
|
107
|
-
- lib/pixelart/color.rb
|
108
121
|
- lib/pixelart/composite.rb
|
122
|
+
- lib/pixelart/convert.rb
|
109
123
|
- lib/pixelart/generator.rb
|
110
|
-
- lib/pixelart/gradient.rb
|
111
124
|
- lib/pixelart/image.rb
|
112
125
|
- lib/pixelart/led.rb
|
113
126
|
- lib/pixelart/misc.rb
|
114
|
-
- lib/pixelart/palette.rb
|
115
127
|
- lib/pixelart/pixelator.rb
|
116
128
|
- lib/pixelart/sample.rb
|
117
129
|
- lib/pixelart/silhouette.rb
|
data/lib/pixelart/color.rb
DELETED
@@ -1,131 +0,0 @@
|
|
1
|
-
module Pixelart
|
2
|
-
|
3
|
-
|
4
|
-
class Color
|
5
|
-
TRANSPARENT = 0 # rgba( 0, 0, 0, 0)
|
6
|
-
BLACK = 0xff # rgba( 0, 0, 0,255)
|
7
|
-
WHITE = 0xffffffff # rgba(255,255,255,255)
|
8
|
-
|
9
|
-
|
10
|
-
def self.parse( color )
|
11
|
-
if color.is_a?( Integer ) ## e.g. assumes ChunkyPNG::Color.rgb() or such
|
12
|
-
color ## pass through as is 1:1
|
13
|
-
elsif color.is_a?( Array ) ## assume array of hsl(a) e. g. [180, 0.86, 0.88]
|
14
|
-
from_hsl( *color )
|
15
|
-
elsif color.is_a?( String )
|
16
|
-
if color.downcase == 'transparent' ## special case for builtin colors
|
17
|
-
TRANSPARENT
|
18
|
-
else
|
19
|
-
## note: return an Integer !!! (not a Color class or such!!! )
|
20
|
-
from_hex( color )
|
21
|
-
end
|
22
|
-
else
|
23
|
-
raise ArgumentError, "unknown color format; cannot parse - expected rgb hex string e.g. d3d3d3"
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.from_hex( hex )
|
28
|
-
## Creates a color by converting it from a string in hex notation.
|
29
|
-
##
|
30
|
-
## It supports colors with (#rrggbbaa) or without (#rrggbb)
|
31
|
-
## alpha channel as well as the 3-digit short format (#rgb)
|
32
|
-
## for those without. Color strings may include
|
33
|
-
## the prefix "0x" or "#"".
|
34
|
-
ChunkyPNG::Color.from_hex( hex )
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.from_hsl( hue, saturation, lightness, alpha=255)
|
38
|
-
ChunkyPNG::Color.from_hsl( hue,
|
39
|
-
saturation,
|
40
|
-
lightness,
|
41
|
-
alpha )
|
42
|
-
end
|
43
|
-
|
44
|
-
|
45
|
-
def self.to_hex( color, include_alpha: true )
|
46
|
-
ChunkyPNG::Color.to_hex( color, include_alpha )
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.to_hsl( color, include_alpha: true )
|
50
|
-
# Returns an array with the separate HSL components of a color.
|
51
|
-
ChunkyPNG::Color.to_hsl( color, include_alpha )
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.r( color ) ChunkyPNG::Color.r( color ); end
|
55
|
-
def self.g( color ) ChunkyPNG::Color.g( color ); end
|
56
|
-
def self.b( color ) ChunkyPNG::Color.b( color ); end
|
57
|
-
|
58
|
-
def self.rgb( r, g, b ) ChunkyPNG::Color.rgb( r, g, b); end
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
## known built-in color names
|
63
|
-
def self.build_names
|
64
|
-
names = {
|
65
|
-
'#00000000' => 'TRANSPARENT',
|
66
|
-
'#000000ff' => 'BLACK',
|
67
|
-
'#ffffffff' => 'WHITE',
|
68
|
-
}
|
69
|
-
|
70
|
-
## auto-add grayscale 1 to 254
|
71
|
-
(1..254).each do |n|
|
72
|
-
hex = "#" + ('%02x' % n)*3
|
73
|
-
hex << "ff" ## add alpha channel (255)
|
74
|
-
names[ hex ] = "8-BIT GRAYSCALE ##{n}"
|
75
|
-
end
|
76
|
-
|
77
|
-
names
|
78
|
-
end
|
79
|
-
|
80
|
-
NAMES = build_names
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
def self.format( color )
|
85
|
-
rgb = [r(color),
|
86
|
-
g(color),
|
87
|
-
b(color)]
|
88
|
-
|
89
|
-
# rgb in hex (string format)
|
90
|
-
# note: do NOT include alpha channel for now - why? why not?
|
91
|
-
hex = "#" + rgb.map{|num| '%02x' % num }.join
|
92
|
-
|
93
|
-
hsl = to_hsl( color )
|
94
|
-
## get alpha channel (transparency) for hsla
|
95
|
-
alpha = hsl[3]
|
96
|
-
|
97
|
-
|
98
|
-
buf = ''
|
99
|
-
buf << hex
|
100
|
-
buf << " / "
|
101
|
-
buf << "rgb("
|
102
|
-
buf << "%3d " % rgb[0]
|
103
|
-
buf << "%3d " % rgb[1]
|
104
|
-
buf << "%3d)" % rgb[2]
|
105
|
-
buf << " - "
|
106
|
-
buf << "hsl("
|
107
|
-
buf << "%3d° " % (hsl[0] % 360)
|
108
|
-
buf << "%3d%% " % (hsl[1]*100+0.5).to_i
|
109
|
-
buf << "%3d%%)" % (hsl[2]*100+0.5).to_i
|
110
|
-
|
111
|
-
if alpha != 255
|
112
|
-
buf << " - α(%3d%%)" % (alpha*100/255+0.5).to_i
|
113
|
-
else
|
114
|
-
buf << " " ## add empty for 255 (full opacity)
|
115
|
-
end
|
116
|
-
|
117
|
-
## note: add alpha channel to hex
|
118
|
-
alpha_hex = '%02x' % alpha
|
119
|
-
name = NAMES[ hex+alpha_hex ]
|
120
|
-
buf << " - #{name}" if name
|
121
|
-
|
122
|
-
buf
|
123
|
-
end
|
124
|
-
class << self
|
125
|
-
alias_method :fmt, :format
|
126
|
-
end
|
127
|
-
|
128
|
-
end # class Color
|
129
|
-
end # module Pixelart
|
130
|
-
|
131
|
-
|
data/lib/pixelart/gradient.rb
DELETED
@@ -1,106 +0,0 @@
|
|
1
|
-
|
2
|
-
## inspired / helped by
|
3
|
-
## https://en.wikipedia.org/wiki/List_of_software_palettes#Color_gradient_palettes
|
4
|
-
## https://github.com/mistic100/tinygradient
|
5
|
-
## https://mistic100.github.io/tinygradient/
|
6
|
-
## https://bsouthga.dev/posts/color-gradients-with-python
|
7
|
-
|
8
|
-
|
9
|
-
module Pixelart
|
10
|
-
|
11
|
-
class Gradient
|
12
|
-
|
13
|
-
def initialize( *stops )
|
14
|
-
## note: convert stop colors to rgb triplets e.g.
|
15
|
-
## from #ffffff to [255,255,255]
|
16
|
-
## #000000 to [0,0,0] etc.
|
17
|
-
@stops = stops.map do |stop|
|
18
|
-
stop = Color.parse( stop )
|
19
|
-
[Color.r(stop), Color.g(stop), Color.b(stop)]
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
|
24
|
-
def colors( steps )
|
25
|
-
segments = @stops.size - 1
|
26
|
-
|
27
|
-
## note: gradient will include start (first)
|
28
|
-
## AND stop color (last) - stop color is NOT excluded for now!!
|
29
|
-
if segments == 1
|
30
|
-
start = @stops[0]
|
31
|
-
stop = @stops[1]
|
32
|
-
|
33
|
-
gradient = linear_gradient( start, stop, steps,
|
34
|
-
include_stop: true )
|
35
|
-
else
|
36
|
-
steps_per_segment, mod = steps.divmod( segments )
|
37
|
-
raise ArgumentError, "steps (#{steps}) must be divisible by # of segments (#{segments}); expected mod of 0 but got #{mod}" if mod != 0
|
38
|
-
|
39
|
-
gradient = []
|
40
|
-
segments.times do |segment|
|
41
|
-
start = @stops[segment]
|
42
|
-
stop = @stops[segment+1]
|
43
|
-
include_stop = (segment == segments-1) ## note: only include stop if last segment!!
|
44
|
-
|
45
|
-
# print " segment #{segment+1}/#{segments} #{steps_per_segment} color(s) - "
|
46
|
-
# print " start: #{start.inspect} "
|
47
|
-
# print include_stop ? 'include' : 'exclude'
|
48
|
-
# print " stop: #{stop.inspect}"
|
49
|
-
# print "\n"
|
50
|
-
|
51
|
-
gradient += linear_gradient( start, stop, steps_per_segment,
|
52
|
-
include_stop: include_stop )
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
## convert to color (Integer)
|
57
|
-
gradient.map do |color|
|
58
|
-
Color.rgb( *color )
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
def interpolate( start, stop, steps, n )
|
65
|
-
## note: n - expected to start with 1,2,3,etc.
|
66
|
-
color = []
|
67
|
-
3.times do |i|
|
68
|
-
stepize = Float(stop[i] - start[i]) / Float(steps-1)
|
69
|
-
value = stepize * n
|
70
|
-
## convert back to Integer from Float
|
71
|
-
## add 0.5 for rounding up (starting with 0.5) - why? why not?
|
72
|
-
value = (value+0.5).to_i
|
73
|
-
value = start[i] + value
|
74
|
-
|
75
|
-
color << value
|
76
|
-
end
|
77
|
-
color
|
78
|
-
end
|
79
|
-
|
80
|
-
|
81
|
-
def linear_gradient( start, stop, steps,
|
82
|
-
include_stop: true )
|
83
|
-
|
84
|
-
gradient = [start] ## auto-add start color (first color in gradient)
|
85
|
-
|
86
|
-
if include_stop
|
87
|
-
1.upto( steps-2 ).each do |n| ## sub two (-2), that is, start and stop color
|
88
|
-
gradient << interpolate( start, stop, steps, n )
|
89
|
-
end
|
90
|
-
# note: use original passed in stop color (should match calculated)
|
91
|
-
gradient << stop
|
92
|
-
else
|
93
|
-
1.upto( steps-1 ).each do |n| ## sub one (-1), that is, start color only
|
94
|
-
## note: add one (+1) to steps because stop color gets excluded (not included)!!
|
95
|
-
gradient << interpolate( start, stop, steps+1, n )
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
gradient
|
100
|
-
end
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
end # class Gradient
|
105
|
-
end # module Pixelart
|
106
|
-
|
data/lib/pixelart/palette.rb
DELETED
@@ -1,72 +0,0 @@
|
|
1
|
-
module Pixelart
|
2
|
-
|
3
|
-
|
4
|
-
class Palette8bit # or use Palette256 alias?
|
5
|
-
|
6
|
-
|
7
|
-
## auto-add grayscale 0 to 255
|
8
|
-
## e.g. rgb(0,0,0)
|
9
|
-
## rgb(1,1,1)
|
10
|
-
## rgb(2,2,2)
|
11
|
-
## ...
|
12
|
-
## rgb(255,255,255)
|
13
|
-
GRAYSCALE = (0..255).map { |n| Color.rgb( n, n, n ) }
|
14
|
-
|
15
|
-
|
16
|
-
## 8x32 gradient color stops
|
17
|
-
## see https://en.wikipedia.org/wiki/List_of_software_palettes#Color_gradient_palettes
|
18
|
-
|
19
|
-
SEPIA_STOPS = [
|
20
|
-
['080400', '262117'],
|
21
|
-
['272218', '453E2F'],
|
22
|
-
['463F30', '645C48'],
|
23
|
-
['655D48', '837A60'],
|
24
|
-
|
25
|
-
['847A60', 'A29778'],
|
26
|
-
['A39878', 'C1B590'],
|
27
|
-
['C2B691', 'E0D2A8'],
|
28
|
-
['E1D3A9', 'FEEFBF'],
|
29
|
-
]
|
30
|
-
|
31
|
-
BLUE_STOPS = [
|
32
|
-
['000000', '001F3E'],
|
33
|
-
['002040', '003F7E'],
|
34
|
-
['004080', '005FBD'],
|
35
|
-
['0060BF', '007FFD'],
|
36
|
-
|
37
|
-
['0080FF', '009FFF'],
|
38
|
-
['00A0FF', '00BFFF'],
|
39
|
-
['00C0FF', '00DFFF'],
|
40
|
-
['00E0FF', '00FEFF'],
|
41
|
-
]
|
42
|
-
|
43
|
-
FALSE_STOPS = [
|
44
|
-
['FF00FF', '6400FF'],
|
45
|
-
['5F00FF', '003CFF'],
|
46
|
-
['0041FF', '00DCFF'],
|
47
|
-
['00E1FF', '00FF82'],
|
48
|
-
|
49
|
-
['00FF7D', '1EFF00'],
|
50
|
-
['23FF00', 'BEFF00'],
|
51
|
-
['C3FF00', 'FFA000'],
|
52
|
-
['FF9B00', 'FF0000'],
|
53
|
-
]
|
54
|
-
|
55
|
-
|
56
|
-
def self.build_palette( gradients )
|
57
|
-
colors_per_gradient, mod = 256.divmod( gradients.size )
|
58
|
-
raise ArgumentError, "8bit palette - 256 must be divisible by # of gradients (#{gradients.size}; expected mod of 0 but got #{mod}" if mod != 0
|
59
|
-
|
60
|
-
colors = []
|
61
|
-
gradients.each do |stops|
|
62
|
-
colors += Gradient.new( *stops ).colors( colors_per_gradient )
|
63
|
-
end
|
64
|
-
colors
|
65
|
-
end
|
66
|
-
|
67
|
-
SEPIA = build_palette( SEPIA_STOPS )
|
68
|
-
BLUE = build_palette( BLUE_STOPS )
|
69
|
-
FALSE = build_palette( FALSE_STOPS )
|
70
|
-
end # class Palette8bit
|
71
|
-
end # module Pixelart
|
72
|
-
|