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 35 return d.Data().(nbt.Compound), nil 36 } 37 38 func getDimensions(d nbt.Compound) image.Rectangle { 39 var width, height int 40 41 if w := d.Get("width"); w.TagID() == nbt.TagShort { 42 width = int(w.Data().(nbt.Short)) 43 } 44 45 if h := d.Get("height"); h.TagID() == nbt.TagShort { 46 height = int(h.Data().(nbt.Short)) 47 } 48 49 return image.Rectangle{ 50 image.Point{0, 0}, 51 image.Point{width, height}, 52 } 53 } 54 55 // Decode takes a reader for an uncompressed Minecraft map. 56 // 57 // Minecraft maps are gzip compressed, so the reader given to this func should 58 // be wrapped in gzip.NewReader. 59 func Decode(r io.Reader) (image.Image, error) { 60 d, err := readData(r) 61 if err != nil { 62 return nil, err 63 } 64 65 c := d.Get("colors") 66 if c.TagID() != nbt.TagByteArray { 67 return nil, nbt.WrongTag{ 68 Expecting: nbt.TagByteArray, 69 Got: c.TagID(), 70 } 71 } 72 73 rect := getDimensions(d) 74 75 return &image.Paletted{ 76 Pix: c.Data().(nbt.ByteArray).Bytes(), 77 Stride: rect.Max.X, 78 Rect: rect, 79 Palette: palette, 80 }, nil 81 } 82 83 // Config reader the configuration for an uncompressed Minecraft map. 84 // 85 // Minecraft maps are gzip compressed, so the reader given to this func should 86 // be wrapped in gzip.NewReader. 87 func Config(r io.Reader) (image.Config, error) { 88 d, err := readData(r) 89 if err != nil { 90 return image.Config{}, err 91 } 92 93 rect := getDimensions(d) 94 95 return image.Config{ 96 ColorModel: palette, 97 Width: int(rect.Max.X), 98 Height: int(rect.Max.Y), 99 }, nil 100 } 101