Class: Pixelart::Image
- Inherits:
-
Object
- Object
- Pixelart::Image
- Defined in:
- lib/pixelart/led.rb,
lib/pixelart/image.rb
Direct Known Subclasses
Constant Summary collapse
- CHARS =
todo/check: rename to default chars or such? why? why not?
'.@xo^~%*+=:'- PALETTE8BIT =
predefined palette8bit color maps
(grayscale to sepia/blue/false/etc.) - todo/check - keep "shortcut" convenience predefined map - why? why not? { sepia: Palette8bit::GRAYSCALE.zip( Palette8bit::SEPIA ).to_h, blue: Palette8bit::GRAYSCALE.zip( Palette8bit::BLUE ).to_h, false: Palette8bit::GRAYSCALE.zip( Palette8bit::FALSE ).to_h, }
Class Method Summary collapse
-
.parse(pixels, colors:, chars: CHARS) ⇒ Object
todo/check: support default chars encoding auto-of-the-box always or require user-defined chars to be passed in - why? why not?.
- .parse_colors(colors) ⇒ Object
-
.parse_pixels(pixels) ⇒ Object
helpers.
-
.read(path) ⇒ Object
convenience helper.
Instance Method Summary collapse
- #[](x, y) ⇒ Object
- #[]=(x, y, value) ⇒ Object
- #_change_colors!(img, color_map) ⇒ Object
- #_parse_color_map(color_map) ⇒ Object
-
#_parse_colors(colors) ⇒ Object
private helpers.
-
#change_colors(color_map) ⇒ Object
(also: #recolor)
add replace_colors alias too? - why? why not?.
- #change_palette8bit(palette) ⇒ Object (also: #change_palette256)
- #compose!(other, x = 0, y = 0) ⇒ Object (also: #paste!)
-
#grayscale ⇒ Object
filter / effects.
- #height ⇒ Object
-
#image ⇒ Object
return image ref - use a different name - why? why not? change to to_image - why? why not?.
-
#initialize(width, height, initial = Color::TRANSPARENT) ⇒ Image
constructor
A new instance of Image.
- #led(led = 8, spacing: 2, round_corner: false) ⇒ Object
- #pixels ⇒ Object
-
#save(path, constraints = {}) ⇒ Object
(also: #write)
(image) delegates todo/check: add some more??.
- #width ⇒ Object
- #zoom(zoom = 2) ⇒ Object (also: #scale)
Constructor Details
#initialize(width, height, initial = Color::TRANSPARENT) ⇒ Image
Returns a new instance of Image.
52 53 54 55 56 57 58 59 60 |
# File 'lib/pixelart/image.rb', line 52 def initialize( width, height, initial=Color::TRANSPARENT ) if initial.is_a?( ChunkyPNG::Image ) @img = initial else ## todo/check - initial - use parse_color here too e.g. allow "#fff" too etc. @img = ChunkyPNG::Image.new( width, height, initial ) end end |
Class Method Details
.parse(pixels, colors:, chars: CHARS) ⇒ Object
todo/check: support default chars encoding auto-of-the-box always
or require user-defined chars to be passed in - why? why not?
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/pixelart/image.rb', line 17 def self.parse( pixels, colors:, chars: CHARS ) has_keys = colors.is_a?(Hash) ## check if passed-in user-defined keys (via hash table)? colors = parse_colors( colors ) pixels = parse_pixels( pixels ) width = pixels.reduce(1) {|width,row| row.size > width ? row.size : width } height = pixels.size img = new( width, height ) pixels.each_with_index do |row,y| row.each_with_index do |color,x| pixel = if has_keys ## if passed-in user-defined keys check only the user-defined keys colors[color] else ## try map ascii art char (.@xo etc.) to color index (0,1,2) ## if no match found - fallback on assuming draw by number (0 1 2 etc.) encoding pos = chars.index( color ) if pos colors[ pos.to_s ] else ## assume nil (not found) colors[ color ] end end img[x,y] = pixel end # each row end # each data img end |
.parse_colors(colors) ⇒ Object
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/pixelart/image.rb', line 220 def self.parse_colors( colors ) if colors.is_a?( Array ) ## convenience shortcut ## note: always auto-add color 0 as pre-defined transparent - why? why not? h = { '0' => Color::TRANSPARENT } colors.each_with_index do |color, i| h[ (i+1).to_s ] = Color.parse( color ) end h else ## assume hash table with color map ## convert into ChunkyPNG::Color colors.map do |key,color| ## always convert key to string why? why not? use symbol? [ key.to_s, Color.parse( color ) ] end.to_h end end |
.parse_pixels(pixels) ⇒ Object
helpers
204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/pixelart/image.rb', line 204 def self.parse_pixels( pixels ) data = [] pixels.each_line do |line| line = line.strip next if line.start_with?( '#' ) || line.empty? ## note: allow comments and empty lines ## note: allow multiple spaces or tabs to separate pixel codes ## e.g. o o o o o o o o o o o o dg lg w w lg w lg lg dg dg w w lg dg o o o o o o o o o o o ## or data << line.split( /[ \t]+/) end data end |
.read(path) ⇒ Object
convenience helper
5 6 7 8 9 |
# File 'lib/pixelart/image.rb', line 5 def self.read( path ) ## convenience helper img_inner = ChunkyPNG::Image.from_file( path ) img = new( img_inner.width, img_inner.height, img_inner ) img end |
Instance Method Details
#[](x, y) ⇒ Object
187 |
# File 'lib/pixelart/image.rb', line 187 def []( x, y ) @img[x,y]; end |
#[]=(x, y, value) ⇒ Object
188 |
# File 'lib/pixelart/image.rb', line 188 def []=( x, y, value ) @img[x,y]=value; end |
#_change_colors!(img, color_map) ⇒ Object
151 152 153 154 155 156 157 158 159 |
# File 'lib/pixelart/image.rb', line 151 def _change_colors!( img, color_map ) img.width.times do |x| img.height.times do |y| color = img[x,y] new_color = color_map[color] img[x,y] = new_color if new_color end end end |
#_parse_color_map(color_map) ⇒ Object
145 146 147 148 149 |
# File 'lib/pixelart/image.rb', line 145 def _parse_color_map( color_map ) color_map.map do |k,v| [Color.parse(k), Color.parse(v)] end.to_h end |
#_parse_colors(colors) ⇒ Object
private helpers
141 142 143 |
# File 'lib/pixelart/image.rb', line 141 def _parse_colors( colors ) colors.map {|color| Color.parse( color ) } end |
#change_colors(color_map) ⇒ Object Also known as: recolor
add replace_colors alias too? - why? why not?
96 97 98 99 100 101 102 103 104 |
# File 'lib/pixelart/image.rb', line 96 def change_colors( color_map ) color_map = _parse_color_map( color_map ) img = @img.dup ## note: make a deep copy!!! _change_colors!( img, color_map ) ## wrap into Pixelart::Image - lets you use zoom() and such Image.new( img.width, img.height, img ) end |
#change_palette8bit(palette) ⇒ Object Also known as: change_palette256
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/pixelart/image.rb', line 118 def change_palette8bit( palette ) ## step 0: mapping from grayscale to new 8bit palette (256 colors) color_map = if palette.is_a?( String ) || palette.is_a?( Symbol ) PALETTE8BIT[ palette.to_sym ] ## todo/fix: check for missing/undefined palette not found - why? why not? else ## make sure we have colors all in Integer not names, hex, etc. palette = _parse_colors( palette ) Palette8bit::GRAYSCALE.zip( palette ).to_h end ## step 1: convert to grayscale (256 colors) img = @img.grayscale _change_colors!( img, color_map ) ## wrap into Pixelart::Image - lets you use zoom() and such Image.new( img.width, img.height, img ) end |
#compose!(other, x = 0, y = 0) ⇒ Object Also known as: paste!
178 179 180 |
# File 'lib/pixelart/image.rb', line 178 def compose!( other, x=0, y=0 ) @img.compose!( other.image, x, y ) ## note: "unwrap" inner image ref end |
#grayscale ⇒ Object
filter / effects
90 91 92 93 |
# File 'lib/pixelart/image.rb', line 90 def grayscale img = @img.grayscale Image.new( img.width, img.height, img ) end |
#height ⇒ Object
185 |
# File 'lib/pixelart/image.rb', line 185 def height() @img.height; end |
#image ⇒ Object
return image ref - use a different name - why? why not?
change to to_image - why? why not?
197 |
# File 'lib/pixelart/image.rb', line 197 def image() @img; end |
#led(led = 8, spacing: 2, round_corner: false) ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/pixelart/led.rb', line 5 def led( led=8, spacing: 2, round_corner: false ) width = @img.width*led + (@img.width-1)*spacing height = @img.height*led + (@img.height-1)*spacing puts " #{width}x#{height}" img = Image.new( width, height, Color::BLACK ) @img.width.times do |x| @img.height.times do |y| pixel = @img[x,y] pixel = Color::BLACK if pixel == Color::TRANSPARENT led.times do |n| led.times do |m| ## round a little - drop all four corners for now next if round_corner && [[0,0],[0,1],[1,0],[1,1],[0,2],[2,0], [0,led-1],[0,led-2],[1,led-1],[1,led-2],[0,led-3],[2,led-1], [led-1,0],[led-1,1],[led-2,0],[led-2,1],[led-1,2],[led-3,0], [led-1,led-1],[led-1,led-2],[led-2,led-1],[led-2,led-2],[led-1,led-3],[led-3,led-1], ].include?( [n,m] ) img[x*led+n + spacing*x, y*led+m + spacing*y] = pixel end end end end img end |
#pixels ⇒ Object
190 |
# File 'lib/pixelart/image.rb', line 190 def pixels() @img.pixels; end |
#save(path, constraints = {}) ⇒ Object Also known as: write
(image) delegates
todo/check: add some more??
167 168 169 170 171 172 173 174 |
# File 'lib/pixelart/image.rb', line 167 def save( path, constraints = {} ) # step 1: make sure outdir exits outdir = File.dirname( path ) FileUtils.mkdir_p( outdir ) unless Dir.exist?( outdir ) # step 2: save @img.save( path, constraints ) end |
#width ⇒ Object
184 |
# File 'lib/pixelart/image.rb', line 184 def width() @img.width; end |
#zoom(zoom = 2) ⇒ Object Also known as: scale
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/pixelart/image.rb', line 64 def zoom( zoom=2 ) ## create a new zoom factor x image (2x, 3x, etc.) img = Image.new( @img.width*zoom, @img.height*zoom ) @img.height.times do |y| @img.width.times do |x| pixel = @img[x,y] zoom.times do |n| zoom.times do |m| img[n+zoom*x,m+zoom*y] = pixel end end end # each x end # each y img end |