1 package maps // import "vimagination.zapto.org/minecraft/maps" 2 3 import ( 4 "image" 5 "io" 6 7 "vimagination.zapto.org/minecraft/nbt" 8 ) 9 10 func init() { 11 image.RegisterFormat("minecraftmap", "\x0a\x00\x00\x0a\x00\x04data", Decode, Config) 12 } 13 14 func readData(r io.Reader) (nbt.Compound, error) { 15 t, err := nbt.Decode(r) 16 if err != nil { 17 return nil, err 18 } 19 20 if t.TagID() != nbt.TagCompound { 21 return nil, nbt.WrongTag{ 22 Expecting: nbt.TagCompound, 23 Got: t.TagID(), 24 } 25 } 26 27 d := t.Data().(nbt.Compound).Get("data") 28 if d.TagID() != nbt.TagCompound { 29 return nil, nbt.WrongTag{ 30 Expecting: nbt.TagCompound, 31 Got: d.TagID(), 32 } 33 } 34 return d.Data().(nbt.Compound), nil 35 } 36 37 func getDimensions(d nbt.Compound) image.Rectangle { 38 var width, height int 39 w := d.Get("width") 40 if w.TagID() == nbt.TagShort { 41 width = int(w.Data().(nbt.Short)) 42 } 43 h := d.Get("height") 44 if h.TagID() == nbt.TagShort { 45 height = int(h.Data().(nbt.Short)) 46 } 47 return image.Rectangle{ 48 image.Point{0, 0}, 49 image.Point{width, height}, 50 } 51 } 52 53 // Decode takes a reader for an uncompressed Minecraft map. 54 // 55 // Minecraft maps are gzip compressed, so the reader given to this func should 56 // be wrapped in gzip.NewReader. 57 func Decode(r io.Reader) (image.Image, error) { 58 d, err := readData(r) 59 if err != nil { 60 return nil, err 61 } 62 63 c := d.Get("colors") 64 if c.TagID() != nbt.TagByteArray { 65 return nil, nbt.WrongTag{ 66 Expecting: nbt.TagByteArray, 67 Got: c.TagID(), 68 } 69 } 70 71 rect := getDimensions(d) 72 73 return &image.Paletted{ 74 Pix: c.Data().(nbt.ByteArray).Bytes(), 75 Stride: rect.Max.X, 76 Rect: rect, 77 Palette: palette, 78 }, nil 79 } 80 81 // Config reader the configuration for an uncompressed Minecraft map. 82 // 83 // Minecraft maps are gzip compressed, so the reader given to this func should 84 // be wrapped in gzip.NewReader. 85 func Config(r io.Reader) (image.Config, error) { 86 d, err := readData(r) 87 if err != nil { 88 return image.Config{}, err 89 } 90 rect := getDimensions(d) 91 return image.Config{ 92 ColorModel: palette, 93 Width: int(rect.Max.X), 94 Height: int(rect.Max.Y), 95 }, nil 96 } 97