Class: SnesUtils::Png2Snes
- Inherits:
-
Object
- Object
- SnesUtils::Png2Snes
- Defined in:
- lib/png2snes/png2snes.rb
Constant Summary collapse
- CHAR_SIZE =
8
Instance Method Summary collapse
- #extract_bitplanes(sprite) ⇒ Object
- #extract_sprites ⇒ Object
- #fill_palette ⇒ Object
-
#initialize(file_path, bpp: 4, alpha: nil, mode7: false, m7_palette_offset: nil) ⇒ Png2Snes
constructor
A new instance of Png2Snes.
- #mode_7_pal_size ⇒ Object
- #pixel_indices ⇒ Object
- #pixels_to_bgr5 ⇒ Object
- #unshift_alpha(alpha) ⇒ Object
- #write(hex, file_path) ⇒ Object
- #write_image ⇒ Object
- #write_image_m06 ⇒ Object
- #write_image_m7 ⇒ Object
- #write_palette ⇒ Object
Constructor Details
#initialize(file_path, bpp: 4, alpha: nil, mode7: false, m7_palette_offset: nil) ⇒ Png2Snes
Returns a new instance of Png2Snes.
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 |
# File 'lib/png2snes/png2snes.rb', line 5 def initialize(file_path, bpp:4, alpha:nil, mode7: false, m7_palette_offset: nil) @file_path = file_path @file_dir = File.dirname(@file_path) @file_name = File.basename(@file_path, File.extname(@file_path)) @image = ChunkyPNG::Image.from_file(@file_path) @mode7 = mode7 raise ArgumentError, 'Image width and height must be a multiple of sprite size' if (@image.width % CHAR_SIZE != 0) or (@image.height % CHAR_SIZE != 0) @pixels = pixels_to_bgr5 @palette = @pixels.uniq if @mode7 raise ArgumentError, 'mode 7 palette offset must be multiple of 16' if m7_palette_offset % 16 != 0 raise ArgumentError, 'mode 7 palette offset must be less than 112' if m7_palette_offset > 112 @m7_palette_offset = m7_palette_offset unshift_alpha(alpha) if alpha fill_palette else raise ArgumentError, 'BPP must be 2, 4, or 8' unless [2, 4, 8].include? bpp @bpp = bpp unshift_alpha(alpha) if alpha fill_palette end end |
Instance Method Details
#extract_bitplanes(sprite) ⇒ Object
101 102 103 104 105 106 107 108 |
# File 'lib/png2snes/png2snes.rb', line 101 def extract_bitplanes sprite bitplanes = [] (0..@bpp-1).each do |plane| bitplanes.push sprite.map { |p| p[plane] } end bitplanes end |
#extract_sprites ⇒ Object
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/png2snes/png2snes.rb', line 77 def extract_sprites pixel_idx = pixel_indices sprite_per_row = @image.width / CHAR_SIZE sprite_per_col = @image.height / CHAR_SIZE sprite_per_sheet = sprite_per_row * sprite_per_col sprites = [] (0..sprite_per_sheet-1).each do |s| sprite = [] (0..CHAR_SIZE-1).each do |r| offset = (s/sprite_per_row)*sprite_per_row * CHAR_SIZE**2 + s % sprite_per_row * CHAR_SIZE if @mode7 sprite += @pixels[offset + r*sprite_per_row*CHAR_SIZE, CHAR_SIZE] else sprite += pixel_idx[offset + r*sprite_per_row*CHAR_SIZE, CHAR_SIZE] end end sprites.push(sprite) end sprites end |
#fill_palette ⇒ Object
48 49 50 51 52 53 54 |
# File 'lib/png2snes/png2snes.rb', line 48 def fill_palette target_size = @mode7 ? mode_7_pal_size : 2**@bpp missing_colors = target_size - @palette.count raise ArgumentError, "Palette size too large for target BPP (#{@palette.count})" if missing_colors < 0 @palette += [0] * missing_colors end |
#mode_7_pal_size ⇒ Object
56 57 58 |
# File 'lib/png2snes/png2snes.rb', line 56 def mode_7_pal_size 128 - @m7_palette_offset end |
#pixel_indices ⇒ Object
71 72 73 74 75 |
# File 'lib/png2snes/png2snes.rb', line 71 def pixel_indices pix_idx = @pixels.map { |p| @palette.index(p) } pix_idx_bin = pix_idx.map { |i| "%0#{@bpp}b" % i } pix_idx_bin.map { |i| i.reverse } end |
#pixels_to_bgr5 ⇒ Object
34 35 36 37 38 39 40 41 42 |
# File 'lib/png2snes/png2snes.rb', line 34 def pixels_to_bgr5 @image.pixels.map do |c| r = ((c >> 24) & 0xff) >> 3 g = ((c >> 16) & 0xff) >> 3 b = ((c >> 8) & 0xff) >> 3 r | (g << 5) | (b << 10) end end |
#unshift_alpha(alpha) ⇒ Object
44 45 46 |
# File 'lib/png2snes/png2snes.rb', line 44 def unshift_alpha(alpha) @palette.unshift(alpha) end |
#write(hex, file_path) ⇒ Object
60 61 62 63 64 |
# File 'lib/png2snes/png2snes.rb', line 60 def write hex, file_path File.open(file_path, 'w+b') do |file| file.write([hex.join].pack('H*')) end end |
#write_image ⇒ Object
110 111 112 |
# File 'lib/png2snes/png2snes.rb', line 110 def write_image @mode7 ? write_image_m7 : write_image_m06 end |
#write_image_m06 ⇒ Object
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/png2snes/png2snes.rb', line 114 def write_image_m06 sprite_per_row = @image.width / CHAR_SIZE sprites = extract_sprites sprites_bitplanes = sprites.map { |s| extract_bitplanes s } image_bits = "" sprites_bitplanes.each do |sprite_bitplanes| sprite_bitplane_pairs = sprite_bitplanes.each_slice(2).to_a bitplane_bits = "" sprite_bitplane_pairs.each do |bitplane| (0..CHAR_SIZE-1).each do |r| offset = r*CHAR_SIZE bitplane_bits += bitplane[0][offset, CHAR_SIZE].join + bitplane[1][offset, CHAR_SIZE].join end end image_bits += bitplane_bits end image_hex = image_bits.scan(/.{8}/).map { |b| "%02x" % b.to_i(2) } write image_hex, File.("#{@file_name}.tiles", @file_dir) end |
#write_image_m7 ⇒ Object
138 139 140 141 142 143 144 |
# File 'lib/png2snes/png2snes.rb', line 138 def write_image_m7 sprites = extract_sprites indices = sprites.flatten.map { |color| "%02x" % (@palette.index(color) + @m7_palette_offset) } write indices, File.("#{@file_name}.tiles", @file_dir) end |
#write_palette ⇒ Object
66 67 68 69 |
# File 'lib/png2snes/png2snes.rb', line 66 def write_palette palette_hex = @palette.map { |c| ('%04x' % c).scan(/.{2}/).reverse.join } write palette_hex, File.("#{@file_name}.pal", @file_dir) end |