pixelart 0.2.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ebe6ddb193d15d611f37461ebca0f7de77d9df6d14c0078eeb483fcdcaf505e
4
- data.tar.gz: 773ab34615671bb06b4e8b8e77096cc9e44588ec5c1b04662474e410a0382223
3
+ metadata.gz: bb520f7fc94b0b7d62336829d92929bbeb27600f0042ab3f68d81b6e5b26d2b3
4
+ data.tar.gz: ed4756f69b5f5d5ca696a1105aa348b5b86ab33653ff7c34d1b24f4dc75e244f
5
5
  SHA512:
6
- metadata.gz: 50f927ae70136c40e9d8bcac7c7c87641dc51427fbf5abaf2a88f1312327e83f59689b597b91e0d9003887a349b10fd20ce4be2ba7bf7baf1b9cebd2df2ee7b5
7
- data.tar.gz: 6afea4ef51112243f065b7071d26c4ae6a70b3c408015838ab01a02d38a3a53ff3f14f04c7cd9746520c6be10f4153eba8b6533e4a52726dc531a7d54e250c29
6
+ metadata.gz: caa3d9eeb12a4a59e4f6ec3191e432ae11d7cf44465e0b6722c69bda985af6caeea3a4390f773d4d535a38096f483c3d9467b03f63ed6547a168f79361db1991
7
+ data.tar.gz: d7f6d039eddc337b62ca22b338712a26423781b2a57703429469d376c02af0fef6aadd9182f4fb2cb755dc83f27c6bcbb97519ee528c01169ba8070534c7c377
data/Manifest.txt CHANGED
@@ -4,11 +4,15 @@ README.md
4
4
  Rakefile
5
5
  lib/pixelart.rb
6
6
  lib/pixelart/base.rb
7
+ lib/pixelart/blur.rb
7
8
  lib/pixelart/color.rb
9
+ lib/pixelart/composite.rb
8
10
  lib/pixelart/gradient.rb
9
11
  lib/pixelart/image.rb
10
12
  lib/pixelart/led.rb
11
13
  lib/pixelart/misc.rb
12
14
  lib/pixelart/palette.rb
13
15
  lib/pixelart/pixelator.rb
16
+ lib/pixelart/sketch.rb
17
+ lib/pixelart/spots.rb
14
18
  lib/pixelart/version.rb
data/Rakefile CHANGED
@@ -19,6 +19,7 @@ Hoe.spec 'pixelart' do
19
19
 
20
20
  self.extra_deps = [
21
21
  ['chunky_png'],
22
+ ['mini_magick'],
22
23
  ]
23
24
 
24
25
  self.licenses = ['Public Domain']
data/lib/pixelart/base.rb CHANGED
@@ -1,12 +1,24 @@
1
- ## 3rd party
1
+ ###############
2
+ # 3rd party
2
3
  require 'chunky_png'
3
4
 
5
+ # optional
6
+ # note: requires installed imagemagick command line installed for usage
7
+ require 'mini_magick'
8
+
9
+
10
+
4
11
  ## stdlib
5
12
  require 'pp'
6
13
  require 'time'
7
14
  require 'date'
8
15
  require 'fileutils'
9
16
 
17
+ require 'json'
18
+ require 'yaml'
19
+
20
+
21
+
10
22
 
11
23
  ## our own code
12
24
  require 'pixelart/version' # note: let version always go first
@@ -14,12 +26,32 @@ require 'pixelart/color'
14
26
  require 'pixelart/gradient'
15
27
  require 'pixelart/palette'
16
28
  require 'pixelart/image'
29
+ require 'pixelart/composite'
17
30
 
18
31
  require 'pixelart/pixelator'
19
32
 
20
33
  require 'pixelart/misc' ## misc helpers
21
34
 
22
- require 'pixelart/led' ## (special) effects / filters
35
+ #########################
36
+ # (special) effects / filters
37
+ require 'pixelart/led'
38
+ require 'pixelart/sketch'
39
+
40
+ ## (special) effects / filters that require imagemagick
41
+
42
+
43
+ ## todo/check - use a config block or such - why? why not?
44
+ module Pixelart
45
+ MAGICK_SCRIPT = './tmp/magick_script.txt'
46
+ MAGICK_INPUT = './tmp/magick_input.png'
47
+ MAGICK_OUTPUT = './tmp/magick_output.png'
48
+ end
49
+
50
+ require 'pixelart/spots'
51
+ require 'pixelart/blur'
52
+
53
+
54
+
23
55
 
24
56
 
25
57
 
@@ -33,6 +65,8 @@ module Pixelart
33
65
 
34
66
  Palette256Image = Palette8BitImage = Palette8bitImage =
35
67
  ImagePalette256 = ImagePalette8Bit = ImagePalette8bit
68
+
69
+ CompositeImage = ImageComposite
36
70
  end
37
71
 
38
72
 
@@ -0,0 +1,19 @@
1
+ module Pixelart
2
+
3
+ class Image
4
+
5
+ def blur( blur=2 )
6
+ @img.save( MAGICK_INPUT )
7
+
8
+ MiniMagick::Tool::Magick.new do |magick|
9
+ magick << MAGICK_INPUT
10
+ magick.blur( "#{blur}x#{blur}" )
11
+ magick << MAGICK_OUTPUT
12
+ end
13
+
14
+ Image.read( MAGICK_OUTPUT )
15
+ end
16
+
17
+ end # class Image
18
+ end # class Pixelart
19
+
@@ -0,0 +1,77 @@
1
+ module Pixelart
2
+
3
+ class ImageComposite < Image # check: (re)name to Collage, Sheet, Sprites, or such?
4
+
5
+ ## default tile width / height in pixel -- check: (re)name to sprite or such? why? why not?
6
+ TILE_WIDTH = 24
7
+ TILE_HEIGHT = 24
8
+
9
+
10
+ def initialize( *args, **kwargs )
11
+ @tile_width = kwargs[:width] || kwargs[:tile_width] || TILE_WIDTH
12
+ @tile_height = kwargs[:height] || kwargs[:tile_height] || TILE_HEIGHT
13
+
14
+ ## todo/fix: check type - args[0] is Image!!!
15
+ if args.size == 1 ## assume "copy" c'tor with passed in image
16
+ img = args[0] ## pass image through as-is
17
+
18
+ @tile_cols = img.width / @tile_width ## e.g. 2400/24 = 100
19
+ @tile_rows = img.height / @tile_height ## e.g. 2400/24 = 100
20
+ @tile_count = @tile_cols * @tile_rows ## ## 10000 = 100x100 (2400x2400 pixel)
21
+ elsif args.size == 2 || args.size == 0 ## cols, rows
22
+ ## todo/fix: check type - args[0] & args[1] is Integer!!!!!
23
+ ## todo/check - find a better name for cols/rows - why? why not?
24
+ @tile_cols = args[0] || 3
25
+ @tile_rows = args[1] || 3
26
+ @tile_count = 0 # (track) current index (of added images)
27
+
28
+ img = ChunkyPNG::Image.new( @tile_cols * @tile_width,
29
+ @tile_rows * @tile_height )
30
+ else
31
+ raise ArgumentError, "cols, rows or image arguments expected; got: #{args.inspect}"
32
+ end
33
+
34
+ puts " #{img.height}x#{img.width} (height x width)"
35
+
36
+ super( nil, nil, img )
37
+ end
38
+
39
+
40
+ def count() @tile_count; end
41
+ alias_method :size, :count ## add size alias (confusing if starting with 0?) - why? why not?
42
+
43
+ #####
44
+ # set / add tile
45
+
46
+ def add( image )
47
+ y, x = @tile_count.divmod( @tile_cols )
48
+
49
+ puts " [#{@tile_count}] @ (#{x}/#{y}) #{image.width}x#{image.height} (height x width)"
50
+
51
+ ## note: image.image - "unwrap" the "raw" ChunkyPNG::Image
52
+ @img.compose!( image.image, x*@tile_width, y*@tile_height )
53
+ @tile_count += 1
54
+ end
55
+ alias_method :<<, :add
56
+
57
+
58
+
59
+ ######
60
+ # get tile
61
+
62
+ def tile( index )
63
+ y, x = index.divmod( @tile_cols )
64
+ img = @img.crop( x*@tile_width, y*@tile_height, @tile_width, @tile_height )
65
+ Image.new( img.width, img.height, img ) ## wrap in pixelart image
66
+ end
67
+
68
+ def []( *args ) ## overload - why? why not?
69
+ if args.size == 1
70
+ index = args[0]
71
+ tile( index )
72
+ else
73
+ super ## e.g [x,y] --- get pixel
74
+ end
75
+ end
76
+ end # class ImageComposite
77
+ end # module Pixelart
@@ -50,6 +50,9 @@ end
50
50
 
51
51
 
52
52
  def initialize( width, height, initial=Color::TRANSPARENT )
53
+ ### todo/fix:
54
+ ## change params to *args only - why? why not?
55
+ ## make width/height optional if image passed in?
53
56
 
54
57
  if initial.is_a?( ChunkyPNG::Image )
55
58
  @img = initial
@@ -92,6 +95,13 @@ def grayscale
92
95
  Image.new( img.width, img.height, img )
93
96
  end
94
97
 
98
+ def mirror
99
+ img = @img.mirror
100
+ Image.new( img.width, img.height, img )
101
+ end
102
+ alias_method :flip_vertically, :mirror
103
+
104
+
95
105
  ## add replace_colors alias too? - why? why not?
96
106
  def change_colors( color_map )
97
107
  color_map = _parse_color_map( color_map )
@@ -76,7 +76,7 @@ class Pixelator # or use Minifier or such - rename - why? why not?
76
76
  alias_method :[], :pixel
77
77
 
78
78
 
79
- def can_pixelate?
79
+ def can_pixelate?( threshold: 50 )
80
80
  # check if any pixel has NOT a color with a 50% majority?
81
81
  count = 0
82
82
  @width.times do |x|
@@ -84,10 +84,13 @@ class Pixelator # or use Minifier or such - rename - why? why not?
84
84
  pixel = pixel( x, y )
85
85
  sum = pixel.values.sum
86
86
  color_count = pixel.values[0]
87
- if color_count < (sum/2)
87
+
88
+ threshold_count = sum / (100/threshold)
89
+ if color_count < threshold_count
88
90
  count += 1
91
+ puts "!! #{color_count} < #{threshold_count} (#{threshold}%)"
89
92
  ## todo/check: stor warn in a public errors or warns array - why? why not?
90
- puts "!! WARN #{count} - pixel (#{x}/#{y}) - no majority (50%) color:"
93
+ puts "!! WARN #{count} - pixel (#{x}/#{y}) - no majority (#{threshold}%) color:"
91
94
  pp pixel
92
95
  end
93
96
  end
@@ -111,7 +114,52 @@ class Pixelator # or use Minifier or such - rename - why? why not?
111
114
 
112
115
  Image.new( img.width, img.height, img ) ## wrap in Pixelart::Image - why? why not?
113
116
  end
117
+
118
+ def outline
119
+ ## create a two color outline (transparent and non-transparent color)
120
+ img = ChunkyPNG::Image.new( @width, @height )
121
+
122
+ @width.times do |x|
123
+ @height.times do |y|
124
+ pixel = pixel( x, y )
125
+ ## calculate pixel count for transparent and non-transparent parts
126
+ ## note:
127
+ ## also count all colors with alpha channel < 200 to transparent!!
128
+ transparent_count, color_count = pixel.reduce([0,0]) do |mem, (color,count)|
129
+ hsl = Color.to_hsl( color )
130
+ ## get alpha channel (transparency) for hsla
131
+ ## 0-255 max.
132
+ alpha = hsl[3]
133
+ if color == 0x00 || alpha < 200
134
+ mem[0] += count
135
+ else
136
+ mem[1] += count
137
+ end
138
+ mem
139
+ end
140
+
141
+ print "."
142
+ if transparent_count > 0 && color_count > 0
143
+ print "(#{x}/#{y}=>#{transparent_count}/#{color_count})"
144
+ end
145
+
146
+ ## todo/check:
147
+ ## warn if sum_transparent == sum_color
148
+ ## or within "threshold" e.g. below 55% or 58% or such - why? why not?
149
+ ## or add treshold as param to outline?
150
+ color = if transparent_count > color_count
151
+ 0x0
152
+ else
153
+ 0x0000ffff ## use blue for now
154
+ end
155
+
156
+ img[x,y] = color
157
+ end
158
+ end
159
+ print "\n"
160
+
161
+ Image.new( img.width, img.height, img ) ## wrap in Pixelart::Image - why? why not?
162
+ end
114
163
  end # class Pixelator
115
164
  end # module Pixelart
116
165
 
117
-
@@ -0,0 +1,69 @@
1
+ module Pixelart
2
+
3
+
4
+
5
+ class Image
6
+ def sketch( sketch=4, line: 1 )
7
+ # todo: line - find a better name eg. line_strenght/width or such?
8
+ width = @img.width*sketch + (@img.width+1)*line
9
+ height = @img.height*sketch + (@img.height+1)*line
10
+
11
+ puts " #{width}x#{height}"
12
+
13
+ img = Image.new( width, height, Color::WHITE )
14
+
15
+ @img.width.times do |x|
16
+ @img.height.times do |y|
17
+ pixel = @img[x,y]
18
+
19
+ ## get surrounding pixels - if "out-of-bound" use transparent (0)
20
+ left = x == 0 ? Color::TRANSPARENT : @img[x-1,y]
21
+ top = y == 0 ? Color::TRANSPARENT : @img[x ,y-1]
22
+
23
+ if pixel != left ## draw vertical line
24
+ (sketch+line*2).times do |n|
25
+ line.times do |m|
26
+ img[ x*sketch + line*x + m,
27
+ n + y*sketch + line*y] = Color::BLACK
28
+ end
29
+ end
30
+ end
31
+
32
+ if pixel != top ## draw horizontal line
33
+ (sketch+line*2).times do |n|
34
+ line.times do |m|
35
+ img[n + x*sketch + line*x,
36
+ y*sketch + line*y + m] = Color::BLACK
37
+ end
38
+ end
39
+ end
40
+
41
+
42
+ ## check special edge case for x and y to add "finish-up" right and bottom line
43
+ if x == @img.width-1 && pixel != Color::TRANSPARENT
44
+ ## draw vertical line
45
+ (sketch+line*2).times do |n|
46
+ line.times do |m|
47
+ img[ (x+1)*sketch + line*(x+1) + m,
48
+ n + y*sketch + line*y] = Color::BLACK
49
+ end
50
+ end
51
+ end
52
+
53
+ if y== @img.height-1 && pixel != Color::TRANSPARENT
54
+ ## draw horizontal line
55
+ (sketch+line*2).times do |n|
56
+ line.times do |m|
57
+ img[n + x*sketch + line*x,
58
+ (y+1)*sketch + line*(y+1) + m] = Color::BLACK
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ img
66
+ end
67
+ end # class Image
68
+ end # module Pixelart
69
+
@@ -0,0 +1,129 @@
1
+ module Pixelart
2
+
3
+ class Image
4
+
5
+
6
+ def spots( spot=10,
7
+ spacing: 0,
8
+ center: nil,
9
+ radius: nil,
10
+ background: nil,
11
+ lightness: nil,
12
+ odd: false )
13
+
14
+ width = @img.width
15
+ height = @img.height
16
+ ## puts " #{width}x#{height}"
17
+
18
+ min_center, max_center = center ? center : [0,0]
19
+ min_radius, max_radius = radius ? radius : [0,0]
20
+
21
+ background_color = background ? Color.parse( background ) : 0
22
+
23
+ min_lightness, max_lightness = lightness ? lightness : [0.0,0.0]
24
+
25
+ ## note: magick command line might get way too long, thus,
26
+ ## save commands to a script
27
+ script = String.new('')
28
+ script << "#{MAGICK_INPUT} \\\n"
29
+
30
+
31
+ width.times do |x|
32
+ height.times do |y|
33
+ color = @img[ x, y ]
34
+
35
+ if color == 0 ## transparent
36
+ if background ## change transparent to background
37
+ color = background_color
38
+ else
39
+ next ## skip transparent
40
+ end
41
+ end
42
+
43
+
44
+ if lightness
45
+ ## todo/check: make it work with alpha too
46
+ h,s,l = Color.to_hsl( color, include_alpha: false )
47
+
48
+ h = h % 360 ## make sure h(ue) is always positive!!!
49
+
50
+ ## note: rand() return between 0.0 and 1.0
51
+ l_diff = min_lightness +
52
+ (max_lightness-min_lightness)*rand()
53
+
54
+ lnew = [1.0, l+l_diff].min
55
+ lnew = [0.0, lnew].max
56
+
57
+ ## print " #{l}+#{l_diff}=#{lnew} "
58
+
59
+ color = Color.from_hsl( h,
60
+ [1.0, s].min,
61
+ lnew )
62
+ end
63
+
64
+ ## note: return hexstring with leading #
65
+ # e.g. 0 becomes #00000000
66
+ # and so on
67
+ color_hex = Color.to_hex( color, include_alpha: true )
68
+ script << "-fill '#{color_hex}' "
69
+
70
+ cx_offset,
71
+ cy_offset = if center ## randomize (offset off center +/-)
72
+ [(spot/2 + min_center) + rand( max_center-min_center ),
73
+ (spot/2 + min_center) + rand( max_center-min_center )]
74
+ else
75
+ [spot/2, ## center
76
+ spot/2]
77
+ end
78
+
79
+ cx = x*spot + x*spacing + cx_offset
80
+ cy = y*spot + y*spacing + cx_offset
81
+
82
+ px_offset = if radius ## randomize (radius +/-)
83
+ min_radius + rand( max_radius-min_radius )
84
+ else
85
+ spot/2
86
+ end
87
+ px = cx + px_offset
88
+ py = cy
89
+
90
+
91
+ if odd && (y % 2 == 1) ## add odd offset
92
+ cx += spot/2
93
+ px += spot/2
94
+ end
95
+
96
+ ## circle
97
+ ## give the center and any point on the perimeter (boundary)
98
+ script << "-draw 'circle #{cx},#{cy},#{px},#{py}' \\\n"
99
+ end
100
+ end
101
+
102
+ script << "-write #{MAGICK_OUTPUT}\n"
103
+
104
+
105
+ ## use an empty image (canvas) with transparent background
106
+ ## as magick input image
107
+ canvas = Image.new( width*spot+(width-1)*spacing,
108
+ height*spot+(height-1)*spacing )
109
+ canvas.save( MAGICK_INPUT )
110
+
111
+ ## note: save magick input first (see above) before save script
112
+ ## will (auto-)create missing directories in path (if missing)
113
+
114
+ File.open( MAGICK_SCRIPT, 'w:utf-8' ) do |f|
115
+ f.write( script )
116
+ end
117
+
118
+
119
+ MiniMagick::Tool::Magick.new do |magick|
120
+ magick.script( MAGICK_SCRIPT )
121
+ end
122
+
123
+ Image.read( MAGICK_OUTPUT )
124
+ end
125
+
126
+
127
+ end # class Image
128
+ end # class Pixelart
129
+
@@ -1,8 +1,8 @@
1
1
 
2
2
  module Pixelart
3
3
 
4
- MAJOR = 0
5
- MINOR = 2
4
+ MAJOR = 1
5
+ MINOR = 1
6
6
  PATCH = 0
7
7
  VERSION = [MAJOR,MINOR,PATCH].join('.')
8
8
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pixelart
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-08 00:00:00.000000000 Z
11
+ date: 2021-09-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chunky_png
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: mini_magick
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rdoc
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -74,13 +88,17 @@ files:
74
88
  - Rakefile
75
89
  - lib/pixelart.rb
76
90
  - lib/pixelart/base.rb
91
+ - lib/pixelart/blur.rb
77
92
  - lib/pixelart/color.rb
93
+ - lib/pixelart/composite.rb
78
94
  - lib/pixelart/gradient.rb
79
95
  - lib/pixelart/image.rb
80
96
  - lib/pixelart/led.rb
81
97
  - lib/pixelart/misc.rb
82
98
  - lib/pixelart/palette.rb
83
99
  - lib/pixelart/pixelator.rb
100
+ - lib/pixelart/sketch.rb
101
+ - lib/pixelart/spots.rb
84
102
  - lib/pixelart/version.rb
85
103
  homepage: https://github.com/rubycoco/pixel
86
104
  licenses: