pixelart 0.2.0 → 1.1.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 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: