Skip to content

Instantly share code, notes, and snippets.

@peterhellberg
Last active April 17, 2020 11:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peterhellberg/c2c30bef0cd9c9e03ba295f505b74b4d to your computer and use it in GitHub Desktop.
Save peterhellberg/c2c30bef0cd9c9e03ba295f505b74b4d to your computer and use it in GitHub Desktop.
Initial version of a parser for ACNL pattern files
package acnl
import (
"bytes"
"encoding/binary"
"image"
"image/color"
"io"
"io/ioutil"
)
// Pattern data layout (identical to binary QR code contents):
//
// 0x 00 - 0x 29 ( 42) = Pattern Title
// 0x 2A - 0x 2B ( 2) = User ID
// 0x 2C - 0x 3F ( 20) = User Name
// 0x 40 - 0x 41 ( 2) = Town ID
// 0x 42 - 0x 55 ( 20) = Town Name
// 0x 56 - 0x 57 ( 2) = Unknown (values are usually random - changing seems to have no effect)
// 0x 58 - 0x 66 ( 15) = Color code indexes
// 0x 67 ( 1) = Unknown (value is usually random - changing seems to have no effect)
// 0x 68 ( 1) = Ten? (seems to always be 0x0A or 0x00)
// 0x 69 ( 1) = Pattern type (see below)
// 0x 6A - 0x 6B ( 2) = Zero? (seems to always be 0x0000)
// 0x 6C - 0x26B (512) = Pattern Data 1 (mandatory)
// 0x26C - 0x46B (512) = Pattern Data 2 (optional)
// 0x46C - 0x66B (512) = Pattern Data 3 (optional)
// 0x66C - 0x86B (512) = Pattern Data 4 (optional)
// 0x86C - 0x86F ( 4) = Zero padding (optional)
//
// Pattern types:
// 0x00 = fullsleeve dress (pro)
// 0x01 = halfsleeve dress (pro)
// 0x02 = sleeveless dress (pro)
// 0x03 = Longsleeve shirt (pro)
// 0x04 = Midsleeve shirt (pro)
// 0x07 = Plain pattern (hat)
// 0x08 = Standee (pro)
// 0x09 = Plain pattern (easel)
//
type Pattern struct {
Title [42]byte
UserID uint16
UserName [20]byte
TownID uint16
TownName [20]byte
Hash uint16
ColorIndexes [15]uint8
Unknown uint8
Ten uint8
Type PatternType
Padding uint16
Data1 [512]uint8
Data2 [512]uint8
Data3 [512]uint8
Data4 [512]uint8
ZeroPadding [4]byte
}
// PatternType of the pattern
type PatternType uint8
// The various types of patterns
var (
DressLongSleeves PatternType = 0
DressShortSleeves PatternType = 1
DressSleveless PatternType = 2
ShirtLongSleeves PatternType = 3
ShirtShortSleeves PatternType = 4
ShirtSleeveless PatternType = 5
HatWithHorns PatternType = 6
HatWithoutHorns PatternType = 7
Standee PatternType = 8
NormalPattern PatternType = 9
)
// ReadBytes containing the bytes from an .acnl file
func ReadBytes(b []byte) (Pattern, error) {
return Read(bytes.NewReader(b))
}
// Read and .acnl file
func Read(r io.Reader) (Pattern, error) {
var p Pattern
b, err := ioutil.ReadAll(io.LimitReader(r, 2160))
if err != nil {
return Pattern{}, err
}
if len(b) == 620 {
b = append(b, make([]byte, 1540)...)
}
return p, binary.Read(bytes.NewReader(b), binary.LittleEndian, &p)
}
// Read the bytes for the pattern
func (p Pattern) Read(b []byte) (int, error) {
var buf bytes.Buffer
if err := binary.Write(&buf, binary.LittleEndian, &p); err != nil {
return 0, err
}
if p.Size() == 32 {
return copy(b, buf.Next(620)), io.EOF
}
return copy(b, buf.Bytes()), io.EOF
}
// TitleString of the pattern
func (p Pattern) TitleString() string {
return string(bytes.ReplaceAll(p.Title[:], []byte{0x0}, nil))
}
// UserNameString of the pattern
func (p Pattern) UserNameString() string {
return string(bytes.ReplaceAll(p.UserName[:], []byte{0x0}, nil))
}
// Size of the pattern
func (p Pattern) Size() int {
if p.Type < HatWithHorns {
return 64
}
return 32
}
// Bounds of the pattern
func (p Pattern) Bounds() image.Rectangle {
s := p.Size()
return image.Rect(0, 0, s, s)
}
// ColorModel of the pattern
func (p Pattern) ColorModel() color.Model {
return color.RGBAModel
}
// At returns the color at x and y
func (p Pattern) At(x, y int) color.Color {
var i uint8
switch {
case x >= 0 && x < 32 && y >= 0 && y < 32:
i = idx(x+32*y, p.Data1)
case x >= 0 && x < 32 && y >= 32 && y < 64:
i = idx(x+32*(y-32), p.Data2)
case x >= 32 && x < 64 && y >= 0 && y < 32:
i = idx(x-32+32*y, p.Data3)
case x >= 32 && x < 64 && y >= 32 && y < 64:
i = idx(x-32+32*(y-32), p.Data4)
}
if i == 15 {
return color.Transparent
}
return colorFromIndex(p.ColorIndexes[i])
}
func idx(n int, d [512]byte) uint8 {
o := n / 2
if n == o+o {
return d[o] & 0b00001111
}
return d[o] & 0b11110000 >> 4
}
func colorFromIndex(i uint8) color.RGBA {
switch i {
case 0x00:
return color.RGBA{0xFF, 0xEF, 0xFF, 0xFF}
case 0x01:
return color.RGBA{0xFF, 0x9A, 0xAD, 0xFF}
case 0x02:
return color.RGBA{0xEF, 0x55, 0x9C, 0xFF}
case 0x03:
return color.RGBA{0xFF, 0x65, 0xAD, 0xFF}
case 0x04:
return color.RGBA{0xFF, 0x00, 0x63, 0xFF}
case 0x05:
return color.RGBA{0xBD, 0x45, 0x73, 0xFF}
case 0x06:
return color.RGBA{0xCE, 0x00, 0x52, 0xFF}
case 0x07:
return color.RGBA{0x9C, 0x00, 0x31, 0xFF}
case 0x08:
return color.RGBA{0x52, 0x20, 0x31, 0xFF}
case 0x10:
return color.RGBA{0xFF, 0xBA, 0xCE, 0xFF}
case 0x11:
return color.RGBA{0xFF, 0x75, 0x73, 0xFF}
case 0x12:
return color.RGBA{0xDE, 0x30, 0x10, 0xFF}
case 0x13:
return color.RGBA{0xFF, 0x55, 0x42, 0xFF}
case 0x14:
return color.RGBA{0xFF, 0x00, 0x00, 0xFF}
case 0x15:
return color.RGBA{0xCE, 0x65, 0x63, 0xFF}
case 0x16:
return color.RGBA{0xBD, 0x45, 0x42, 0xFF}
case 0x17:
return color.RGBA{0xBD, 0x00, 0x00, 0xFF}
case 0x18:
return color.RGBA{0x8C, 0x20, 0x21, 0xFF}
case 0x20:
return color.RGBA{0xDE, 0xCF, 0xBD, 0xFF}
case 0x21:
return color.RGBA{0xFF, 0xCF, 0x63, 0xFF}
case 0x22:
return color.RGBA{0xDE, 0x65, 0x21, 0xFF}
case 0x23:
return color.RGBA{0xFF, 0xAA, 0x21, 0xFF}
case 0x24:
return color.RGBA{0xFF, 0x65, 0x00, 0xFF}
case 0x25:
return color.RGBA{0xBD, 0x8A, 0x52, 0xFF}
case 0x26:
return color.RGBA{0xDE, 0x45, 0x00, 0xFF}
case 0x27:
return color.RGBA{0xBD, 0x45, 0x00, 0xFF}
case 0x28:
return color.RGBA{0x63, 0x30, 0x10, 0xFF}
case 0x30:
return color.RGBA{0xFF, 0xEF, 0xDE, 0xFF}
case 0x31:
return color.RGBA{0xFF, 0xDF, 0xCE, 0xFF}
case 0x32:
return color.RGBA{0xFF, 0xCF, 0xAD, 0xFF}
case 0x33:
return color.RGBA{0xFF, 0xBA, 0x8C, 0xFF}
case 0x34:
return color.RGBA{0xFF, 0xAA, 0x8C, 0xFF}
case 0x35:
return color.RGBA{0xDE, 0x8A, 0x63, 0xFF}
case 0x36:
return color.RGBA{0xBD, 0x65, 0x42, 0xFF}
case 0x37:
return color.RGBA{0x9C, 0x55, 0x31, 0xFF}
case 0x38:
return color.RGBA{0x8C, 0x45, 0x21, 0xFF}
case 0x40:
return color.RGBA{0xFF, 0xCF, 0xFF, 0xFF}
case 0x41:
return color.RGBA{0xEF, 0x8A, 0xFF, 0xFF}
case 0x42:
return color.RGBA{0xCE, 0x65, 0xDE, 0xFF}
case 0x43:
return color.RGBA{0xBD, 0x8A, 0xCE, 0xFF}
case 0x44:
return color.RGBA{0xCE, 0x00, 0xFF, 0xFF}
case 0x45:
return color.RGBA{0x9C, 0x65, 0x9C, 0xFF}
case 0x46:
return color.RGBA{0x8C, 0x00, 0xAD, 0xFF}
case 0x47:
return color.RGBA{0x52, 0x00, 0x73, 0xFF}
case 0x48:
return color.RGBA{0x31, 0x00, 0x42, 0xFF}
case 0x50:
return color.RGBA{0xFF, 0xBA, 0xFF, 0xFF}
case 0x51:
return color.RGBA{0xFF, 0x9A, 0xFF, 0xFF}
case 0x52:
return color.RGBA{0xDE, 0x20, 0xBD, 0xFF}
case 0x53:
return color.RGBA{0xFF, 0x55, 0xEF, 0xFF}
case 0x54:
return color.RGBA{0xFF, 0x00, 0xCE, 0xFF}
case 0x55:
return color.RGBA{0x8C, 0x55, 0x73, 0xFF}
case 0x56:
return color.RGBA{0xBD, 0x00, 0x9C, 0xFF}
case 0x57:
return color.RGBA{0x8C, 0x00, 0x63, 0xFF}
case 0x58:
return color.RGBA{0x52, 0x00, 0x42, 0xFF}
case 0x60:
return color.RGBA{0xDE, 0xBA, 0x9C, 0xFF}
case 0x61:
return color.RGBA{0xCE, 0xAA, 0x73, 0xFF}
case 0x62:
return color.RGBA{0x73, 0x45, 0x31, 0xFF}
case 0x63:
return color.RGBA{0xAD, 0x75, 0x42, 0xFF}
case 0x64:
return color.RGBA{0x9C, 0x30, 0x00, 0xFF}
case 0x65:
return color.RGBA{0x73, 0x30, 0x21, 0xFF}
case 0x66:
return color.RGBA{0x52, 0x20, 0x00, 0xFF}
case 0x67:
return color.RGBA{0x31, 0x10, 0x00, 0xFF}
case 0x68:
return color.RGBA{0x21, 0x10, 0x00, 0xFF}
case 0x70:
return color.RGBA{0xFF, 0xFF, 0xCE, 0xFF}
case 0x71:
return color.RGBA{0xFF, 0xFF, 0x73, 0xFF}
case 0x72:
return color.RGBA{0xDE, 0xDF, 0x21, 0xFF}
case 0x73:
return color.RGBA{0xFF, 0xFF, 0x00, 0xFF}
case 0x74:
return color.RGBA{0xFF, 0xDF, 0x00, 0xFF}
case 0x75:
return color.RGBA{0xCE, 0xAA, 0x00, 0xFF}
case 0x76:
return color.RGBA{0x9C, 0x9A, 0x00, 0xFF}
case 0x77:
return color.RGBA{0x8C, 0x75, 0x00, 0xFF}
case 0x78:
return color.RGBA{0x52, 0x55, 0x00, 0xFF}
case 0x80:
return color.RGBA{0xDE, 0xBA, 0xFF, 0xFF}
case 0x81:
return color.RGBA{0xBD, 0x9A, 0xEF, 0xFF}
case 0x82:
return color.RGBA{0x63, 0x30, 0xCE, 0xFF}
case 0x83:
return color.RGBA{0x9C, 0x55, 0xFF, 0xFF}
case 0x84:
return color.RGBA{0x63, 0x00, 0xFF, 0xFF}
case 0x85:
return color.RGBA{0x52, 0x45, 0x8C, 0xFF}
case 0x86:
return color.RGBA{0x42, 0x00, 0x9C, 0xFF}
case 0x87:
return color.RGBA{0x21, 0x00, 0x63, 0xFF}
case 0x88:
return color.RGBA{0x21, 0x10, 0x31, 0xFF}
case 0x90:
return color.RGBA{0xBD, 0xBA, 0xFF, 0xFF}
case 0x91:
return color.RGBA{0x8C, 0x9A, 0xFF, 0xFF}
case 0x92:
return color.RGBA{0x31, 0x30, 0xAD, 0xFF}
case 0x93:
return color.RGBA{0x31, 0x55, 0xEF, 0xFF}
case 0x94:
return color.RGBA{0x00, 0x00, 0xFF, 0xFF}
case 0x95:
return color.RGBA{0x31, 0x30, 0x8C, 0xFF}
case 0x96:
return color.RGBA{0x00, 0x00, 0xAD, 0xFF}
case 0x97:
return color.RGBA{0x10, 0x10, 0x63, 0xFF}
case 0x98:
return color.RGBA{0x00, 0x00, 0x21, 0xFF}
case 0xA0:
return color.RGBA{0x9C, 0xEF, 0xBD, 0xFF}
case 0xA1:
return color.RGBA{0x63, 0xCF, 0x73, 0xFF}
case 0xA2:
return color.RGBA{0x21, 0x65, 0x10, 0xFF}
case 0xA3:
return color.RGBA{0x42, 0xAA, 0x31, 0xFF}
case 0xA4:
return color.RGBA{0x00, 0x8A, 0x31, 0xFF}
case 0xA5:
return color.RGBA{0x52, 0x75, 0x52, 0xFF}
case 0xA6:
return color.RGBA{0x21, 0x55, 0x00, 0xFF}
case 0xA7:
return color.RGBA{0x10, 0x30, 0x21, 0xFF}
case 0xA8:
return color.RGBA{0x00, 0x20, 0x10, 0xFF}
case 0xB0:
return color.RGBA{0xDE, 0xFF, 0xBD, 0xFF}
case 0xB1:
return color.RGBA{0xCE, 0xFF, 0x8C, 0xFF}
case 0xB2:
return color.RGBA{0x8C, 0xAA, 0x52, 0xFF}
case 0xB3:
return color.RGBA{0xAD, 0xDF, 0x8C, 0xFF}
case 0xB4:
return color.RGBA{0x8C, 0xFF, 0x00, 0xFF}
case 0xB5:
return color.RGBA{0xAD, 0xBA, 0x9C, 0xFF}
case 0xB6:
return color.RGBA{0x63, 0xBA, 0x00, 0xFF}
case 0xB7:
return color.RGBA{0x52, 0x9A, 0x00, 0xFF}
case 0xB8:
return color.RGBA{0x31, 0x65, 0x00, 0xFF}
case 0xC0:
return color.RGBA{0xBD, 0xDF, 0xFF, 0xFF}
case 0xC1:
return color.RGBA{0x73, 0xCF, 0xFF, 0xFF}
case 0xC2:
return color.RGBA{0x31, 0x55, 0x9C, 0xFF}
case 0xC3:
return color.RGBA{0x63, 0x9A, 0xFF, 0xFF}
case 0xC4:
return color.RGBA{0x10, 0x75, 0xFF, 0xFF}
case 0xC5:
return color.RGBA{0x42, 0x75, 0xAD, 0xFF}
case 0xC6:
return color.RGBA{0x21, 0x45, 0x73, 0xFF}
case 0xC7:
return color.RGBA{0x00, 0x20, 0x73, 0xFF}
case 0xC8:
return color.RGBA{0x00, 0x10, 0x42, 0xFF}
case 0xD0:
return color.RGBA{0xAD, 0xFF, 0xFF, 0xFF}
case 0xD1:
return color.RGBA{0x52, 0xFF, 0xFF, 0xFF}
case 0xD2:
return color.RGBA{0x00, 0x8A, 0xBD, 0xFF}
case 0xD3:
return color.RGBA{0x52, 0xBA, 0xCE, 0xFF}
case 0xD4:
return color.RGBA{0x00, 0xCF, 0xFF, 0xFF}
case 0xD5:
return color.RGBA{0x42, 0x9A, 0xAD, 0xFF}
case 0xD6:
return color.RGBA{0x00, 0x65, 0x8C, 0xFF}
case 0xD7:
return color.RGBA{0x00, 0x45, 0x52, 0xFF}
case 0xD8:
return color.RGBA{0x00, 0x20, 0x31, 0xFF}
case 0xE0:
return color.RGBA{0xCE, 0xFF, 0xEF, 0xFF}
case 0xE1:
return color.RGBA{0xAD, 0xEF, 0xDE, 0xFF}
case 0xE2:
return color.RGBA{0x31, 0xCF, 0xAD, 0xFF}
case 0xE3:
return color.RGBA{0x52, 0xEF, 0xBD, 0xFF}
case 0xE4:
return color.RGBA{0x00, 0xFF, 0xCE, 0xFF}
case 0xE5:
return color.RGBA{0x73, 0xAA, 0xAD, 0xFF}
case 0xE6:
return color.RGBA{0x00, 0xAA, 0x9C, 0xFF}
case 0xE7:
return color.RGBA{0x00, 0x8A, 0x73, 0xFF}
case 0xE8:
return color.RGBA{0x00, 0x45, 0x31, 0xFF}
case 0xF0:
return color.RGBA{0xAD, 0xFF, 0xAD, 0xFF}
case 0xF1:
return color.RGBA{0x73, 0xFF, 0x73, 0xFF}
case 0xF2:
return color.RGBA{0x63, 0xDF, 0x42, 0xFF}
case 0xF3:
return color.RGBA{0x00, 0xFF, 0x00, 0xFF}
case 0xF4:
return color.RGBA{0x21, 0xDF, 0x21, 0xFF}
case 0xF5:
return color.RGBA{0x52, 0xBA, 0x52, 0xFF}
case 0xF6:
return color.RGBA{0x00, 0xBA, 0x00, 0xFF}
case 0xF7:
return color.RGBA{0x00, 0x8A, 0x00, 0xFF}
case 0xF8:
return color.RGBA{0x21, 0x45, 0x21, 0xFF}
case 0x0F:
return color.RGBA{0xFF, 0xFF, 0xFF, 0xFF}
case 0x1F:
return color.RGBA{0xEC, 0xEC, 0xEC, 0xFF}
case 0x2F:
return color.RGBA{0xDA, 0xDA, 0xDA, 0xFF}
case 0x3F:
return color.RGBA{0xC8, 0xC8, 0xC8, 0xFF}
case 0x4F:
return color.RGBA{0xB6, 0xB6, 0xB6, 0xFF}
case 0x5F:
return color.RGBA{0xA3, 0xA3, 0xA3, 0xFF}
case 0x6F:
return color.RGBA{0x91, 0x91, 0x91, 0xFF}
case 0x7F:
return color.RGBA{0x7F, 0x7F, 0x7F, 0xFF}
case 0x8F:
return color.RGBA{0x6D, 0x6D, 0x6D, 0xFF}
case 0x9F:
return color.RGBA{0x5B, 0x5B, 0x5B, 0xFF}
case 0xAF:
return color.RGBA{0x48, 0x48, 0x48, 0xFF}
case 0xBF:
return color.RGBA{0x36, 0x36, 0x36, 0xFF}
case 0xCF:
return color.RGBA{0x24, 0x24, 0x24, 0xFF}
case 0xDF:
return color.RGBA{0x12, 0x12, 0x12, 0xFF}
case 0xEF:
return color.RGBA{0x00, 0x00, 0x00, 0xFF}
default:
return color.RGBA{0, 0, 0, 0}
}
}
@peterhellberg
Copy link
Author

Nibbles table

@peterhellberg
Copy link
Author

peterhellberg commented Apr 15, 2020

Example pattern

acnl.Pattern{
	Title:[42]uint8{0x41, 0x0, 0x73, 0x0, 0x74, 0x0, 0x72, 0x0, 0x6f, 0x0, 0x6e, 0x0, 0x61, 0x0, 0x75, 0x0, 0x74, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
	UserID:0x0, 
	UserName:[20]uint8{0x4b, 0x0, 0x69, 0x0, 0x6d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
	TownID:0x0, 
	TownName:[20]uint8{0x53, 0x0, 0x6b, 0x0, 0xe5, 0x0, 0x6e, 0x0, 0x65, 0x0, 0x6c, 0x0, 0x61, 0x0, 0x6e, 0x0, 0x64, 0x0, 0x0, 0x0}, 	Hash:0x3119, 
	ColorIndexes:[15]uint8{0x88, 0xcf, 0xbf, 0x9f, 0x8f, 0x7f, 0x6f, 0x5f, 0xb5, 0x20, 0x98, 0xaf, 0xe5, 0x4f, 0x60}, 
	Unknown:0xcc, 
	Ten:0xa, 
	Type:0x9, 
	Padding:0x0, 
	Data1:[512]uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb2, 0x3b, 0x43, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x21, 0x3b, 0x3b, 0x53, 0x55, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf, 0x11, 0x0, 0x0, 0x21, 0x32, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x10, 0xb2, 0x5b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf, 0x0, 0x0, 0x0, 0x0, 0xa0, 0x0, 0x3b, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf, 0x0, 0xb0, 0x2, 0x20, 0x4b, 0x10, 0xba, 0x43, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x10, 0x41, 0x3, 0x11, 0xe5, 0xa, 0x0, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x10, 0x1, 0x0, 0x1, 0x32, 0x53, 0xa, 0xb2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf, 0xa0, 0x14, 0x20, 0x13, 0x0, 0x0, 0x20, 0x0, 0x21, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf, 0x0, 0x0, 0x34, 0x24, 0x1, 0x21, 0x20, 0x1, 0x0, 0x20, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0xa0, 0x34, 0x11, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x21, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0xa0, 0xb3, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x23, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x52, 0x44, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x10, 0x1, 0x0, 0x0, 0x0, 0x10, 0x54, 0x44, 0xff, 0xff, 0xff, 0xff, 0x0, 0x10, 0x1, 0x10, 0x12, 0x0, 0x0, 0x0, 0xb0, 0x43, 0x46, 0x55, 0xff, 0xff, 0xff, 0xff, 0x0, 0x12, 0x23, 0x0, 0xbb, 0x3b, 0x3b, 0x34, 0xbb, 0x53, 0xc5, 0x77, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x34, 0x1, 0x0, 0x42, 0x44, 0x54, 0x54, 0x54, 0x65, 0x77, 0xf5, 0xff, 0xff, 0xff, 0x0, 0xb0, 0x44, 0x23, 0x32, 0xa1, 0x30, 0x85, 0xee, 0x56, 0xc5, 0x47, 0xf6, 0xff, 0xff, 0xf, 0x0, 0xb0, 0x44, 0x44, 0x53, 0xb4, 0xbb, 0x54, 0xe8, 0x56, 0x55, 0x67, 0x55, 0xff, 0xff, 0xf, 0x21, 0x0, 0xc5, 0x44, 0x7c, 0x77, 0x87, 0x77, 0x88, 0x57, 0x55, 0x76, 0x66, 0xff, 0xff, 0x21, 0x31, 0x12, 0x33, 0x43, 0x73, 0x77, 0xd7, 0x7d, 0x76, 0x55, 0x65, 0x75, 0x77, 0xff, 0x1f, 0x1, 0x30, 0x41, 0x4c, 0x2b, 0x3a, 0x77, 0x67, 0x85, 0x78, 0x68, 0x6b, 0x65, 0xd8, 0xf5, 0xf, 0x1, 0xb0, 0xb1, 0x65, 0x3b, 0x52, 0x77, 0x77, 0x65, 0x88, 0xdd, 0x65, 0x67, 0x96, 0xf8, 0x20, 0x2, 0x31, 0x2, 0x30, 0xb2, 0x63, 0x76, 0x77, 0xe8, 0x8e, 0x98, 0x89, 0x8d, 0x97, 0x59, 0xb0, 0x2, 0xb0, 0xb3, 0x3b, 0x24, 0x5b, 0xc6, 0x35, 0xe3, 0x6e, 0x77, 0x67, 0x66, 0xe9, 0x89, 0xb0, 0x2, 0x10, 0xbb, 0x2b, 0x24, 0x74, 0xc6, 0x36, 0x8b, 0x43, 0xc7, 0x5d, 0x66, 0xee, 0x86, 0x20, 0xb3, 0x3b, 0xa2, 0xba, 0x4, 0xcb, 0xcc, 0xb8, 0xe3, 0x6b, 0xcd, 0x89, 0x65, 0x68, 0x83, 0x10, 0x42, 0x34, 0x1, 0x65, 0x3, 0x40, 0x77, 0x8, 0xe4, 0x6b, 0x77, 0xe9, 0x51, 0x57, 0x83, 0x0, 0x31, 0x34, 0x20, 0x65, 0xa3, 0xa0, 0x84, 0xb8, 0x82, 0x73, 0x9c, 0x99, 0xc4, 0x78, 0x9e, 0x0, 0x32, 0x33, 0xb0, 0x24, 0xb, 0x1, 0xc2, 0x39, 0x20, 0x73, 0x99, 0x9d, 0x48, 0x9e, 0xd9, 0x0, 0x32, 0x34, 0x20, 0x33, 0x44, 0x65, 0x5b, 0x47, 0x5b, 0x63, 0xdd, 0x4c, 0x37, 0x95, 0xd9, 0x2b, 0x5b, 0xb4, 0x21, 0x44, 0x34, 0x63, 0x68, 0x68, 0xb3, 0x30, 0x43, 0x54, 0x67, 0x67, 0x99}, 
	Data2:[512]uint8{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
	Data3:[512]uint8{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
	Data4:[512]uint8{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
	ZeroPadding:[4]uint8{0x0, 0x0, 0x0, 0x0},
}

astronaut

Palette

astronaut-palette

Code that read an .acnl, prints out the parsed struct in Go format, and saves a PNG:

package main

import (
	"fmt"
	"image/png"
	"os"

	"github.com/peterhellberg/acnl"
)

func main() {
	if len(os.Args) < 2 {
		fmt.Println("missing filename as first argument")
		os.Exit(1)
	}

	fn := os.Args[1]

	f, err := os.Open(fn)
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(1)
	}
	defer f.Close()

	p, err := acnl.Read(f)
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(1)
	}

	fmt.Printf("%#v\n", p)

	if len(os.Args) == 3 {
		w, err := os.Create(os.Args[2])
		if err != nil {
			fmt.Println("Error:", err)
			os.Exit(1)
		}
		defer w.Close()

		if err := png.Encode(w, p); err != nil {
			fmt.Println("Error:", err)
			os.Exit(1)
		}
	}
}

@peterhellberg
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment