class Pixelart::Image
Constants
- CHARS
- PALETTE8BIT
predefined palette8bit color maps
(grayscale to sepia/blue/false/etc.) - todo/check - keep "shortcut" convenience predefined map - why? why not?
Public Class Methods
new( width, height, initial=Color::TRANSPARENT )
click to toggle source
# File lib/pixelart/image.rb, line 52 def initialize( width, height, initial=Color::TRANSPARENT ) ### todo/fix: ## change params to *args only - why? why not? ## make width/height optional if image passed in? 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
parse( pixels, colors:, chars: CHARS )
click to toggle source
todo/check: support default chars encoding auto-of-the-box always
or require user-defined chars to be passed in - why? why not?
# 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 )
click to toggle source
# File lib/pixelart/image.rb, line 230 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 )
click to toggle source
helpers
# File lib/pixelart/image.rb, line 214 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 )
click to toggle source
# 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
Public Instance Methods
[]( x, y )
click to toggle source
# File lib/pixelart/image.rb, line 197 def []( x, y ) @img[x,y]; end
[]=( x, y, value )
click to toggle source
# File lib/pixelart/image.rb, line 198 def []=( x, y, value ) @img[x,y]=value; end
_change_colors!( img, color_map )
click to toggle source
# File lib/pixelart/image.rb, line 161 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 )
click to toggle source
# File lib/pixelart/image.rb, line 155 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 )
click to toggle source
private helpers
# File lib/pixelart/image.rb, line 151 def _parse_colors( colors ) colors.map {|color| Color.parse( color ) } end
change_colors( color_map )
click to toggle source
add replace_colors alias too? - why? why not?
# File lib/pixelart/image.rb, line 106 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
Also aliased as: recolor
change_palette8bit( palette )
click to toggle source
# File lib/pixelart/image.rb, line 128 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
Also aliased as: change_palette256
compose!( other, x=0, y=0 )
click to toggle source
# File lib/pixelart/image.rb, line 188 def compose!( other, x=0, y=0 ) @img.compose!( other.image, x, y ) ## note: "unwrap" inner image ref end
Also aliased as: paste!
grayscale()
click to toggle source
filter / effects
# File lib/pixelart/image.rb, line 93 def grayscale img = @img.grayscale Image.new( img.width, img.height, img ) end
height()
click to toggle source
# File lib/pixelart/image.rb, line 195 def height() @img.height; end
image()
click to toggle source
return image ref - use a different name - why? why not?
change to to_image - why? why not?
# File lib/pixelart/image.rb, line 207 def image() @img; end
led( led=8, spacing: 2, round_corner: false )
click to toggle source
# 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
mirror()
click to toggle source
# File lib/pixelart/image.rb, line 98 def mirror img = @img.mirror Image.new( img.width, img.height, img ) end
Also aliased as: flip_vertically
pixels()
click to toggle source
# File lib/pixelart/image.rb, line 200 def pixels() @img.pixels; end
save( path, constraints = {} )
click to toggle source
(image) delegates
todo/check: add some more??
# File lib/pixelart/image.rb, line 177 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
Also aliased as: write
width()
click to toggle source
# File lib/pixelart/image.rb, line 194 def width() @img.width; end
zoom( zoom=2 )
click to toggle source
# File lib/pixelart/image.rb, line 67 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
Also aliased as: scale