organized
|
@ -1,151 +1,38 @@
|
||||||
package nori
|
package nori
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Frame struct {
|
|
||||||
Duration uint32
|
|
||||||
PlaneCount uint32
|
|
||||||
Planes []*Plane
|
|
||||||
CoordinateCount uint32
|
|
||||||
Coordinates [][2]uint32
|
|
||||||
Unknown1 string
|
|
||||||
SoundEffect string
|
|
||||||
Unknown2 string
|
|
||||||
Camp CampSection
|
|
||||||
}
|
|
||||||
type CampSection struct {
|
|
||||||
Params [7]uint32
|
|
||||||
Array []byte
|
|
||||||
Extra string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Plane struct {
|
|
||||||
BitmapId uint32
|
|
||||||
PlaneX int32
|
|
||||||
PlaneY int32
|
|
||||||
Opacity uint32
|
|
||||||
Blend BlendMode
|
|
||||||
FlagParam uint32
|
|
||||||
RenderFlag uint32
|
|
||||||
}
|
|
||||||
type Animation struct {
|
type Animation struct {
|
||||||
Title [32]byte
|
Title [32]byte
|
||||||
|
|
||||||
// std::vector<uint32> frame_offsets
|
|
||||||
FrameCount uint32
|
FrameCount uint32
|
||||||
Frames []*Frame
|
Frames []*Frame
|
||||||
|
Version int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Animation) Decode(rd *bufio.Reader, version int) error {
|
func NewAnimation(version int) *Animation {
|
||||||
|
return &Animation{Version: version}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Animation) Decode(rd io.Reader) error {
|
||||||
if err := binary.Read(rd, end, a.Title[:]); err != nil {
|
if err := binary.Read(rd, end, a.Title[:]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := binary.Read(rd, end, &a.FrameCount); err != nil {
|
if err := binary.Read(rd, end, &a.FrameCount); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := rd.Discard(4 * int(a.FrameCount)); err != nil {
|
if err := discardN(rd, 4*int(a.FrameCount)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
a.Frames = make([]*Frame, int(a.FrameCount))
|
a.Frames = make([]*Frame, int(a.FrameCount))
|
||||||
for i := range a.Frames {
|
for i := range a.Frames {
|
||||||
cf := &Frame{}
|
a.Frames[i] = NewFrame(a.Version)
|
||||||
a.Frames[i] = cf
|
if err := a.Frames[i].Decode(rd); err != nil {
|
||||||
if err := binary.Read(rd, end, &cf.Duration); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := binary.Read(rd, end, &cf.PlaneCount); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cf.Planes = make([]*Plane, int(cf.PlaneCount))
|
|
||||||
for i := range cf.Planes {
|
|
||||||
cp := &Plane{}
|
|
||||||
cf.Planes[i] = cp
|
|
||||||
if err := binary.Read(rd, end, &cp.BitmapId); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := binary.Read(rd, end, &cp.PlaneX); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := binary.Read(rd, end, &cp.PlaneY); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := binary.Read(rd, end, &cp.Opacity); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := binary.Read(rd, end, &cp.RenderFlag); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := binary.Read(rd, end, &cp.Blend); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := binary.Read(rd, end, &cp.FlagParam); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if version != 300 {
|
|
||||||
if err := binary.Read(rd, end, &cf.CoordinateCount); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cf.Coordinates = make([][2]uint32, cf.CoordinateCount)
|
|
||||||
for i := range cf.Coordinates {
|
|
||||||
if err := binary.Read(rd, end, &cf.Coordinates[i][0]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := binary.Read(rd, end, &cf.Coordinates[i][1]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch version {
|
|
||||||
case 300, 301:
|
|
||||||
if _, err := rd.Discard(144); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case 302, 303:
|
|
||||||
if _, err := rd.Discard(96); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if version >= 302 {
|
|
||||||
// entry blocks
|
|
||||||
if _, err := rd.Discard(28 * 6); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// unknown1
|
|
||||||
if _, err := rd.Discard(44); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
//sound_effect
|
|
||||||
if _, err := rd.Discard(18); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// unknown2
|
|
||||||
if _, err := rd.Discard(18); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var cast uint32
|
|
||||||
if err := binary.Read(rd, end, &cast); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if version >= 303 && (cast > 0) {
|
|
||||||
cf.Camp = CampSection{}
|
|
||||||
if err := binary.Read(rd, end, cf.Camp.Params[:]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
sz := int(cf.Camp.Params[1]) * int(cf.Camp.Params[2])
|
|
||||||
cf.Camp.Array = make([]byte, sz)
|
|
||||||
if _, err := io.ReadFull(rd, cf.Camp.Array); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := rd.Discard(20); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package nori
|
package nori
|
||||||
|
|
||||||
|
import "encoding/binary"
|
||||||
|
|
||||||
type BlendMode uint32
|
type BlendMode uint32
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -16,3 +18,5 @@ var (
|
||||||
BlendMode_Mul7 BlendMode = 7
|
BlendMode_Mul7 BlendMode = 7
|
||||||
BlendMode_Add8 BlendMode = 8
|
BlendMode_Add8 BlendMode = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var end = binary.LittleEndian
|
|
@ -0,0 +1,26 @@
|
||||||
|
package nori
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func New() *Nori {
|
||||||
|
return &Nori{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromFile(fp string) (*Nori, error) {
|
||||||
|
file, err := os.Open(fp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
return Decode(bufio.NewReader(file))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Decode(r io.Reader) (*Nori, error) {
|
||||||
|
nori := New()
|
||||||
|
err := nori.Decode(r)
|
||||||
|
return nori, err
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
package nori
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Frame struct {
|
||||||
|
Duration uint32
|
||||||
|
PlaneCount uint32
|
||||||
|
Planes []*Plane
|
||||||
|
CoordinateCount uint32
|
||||||
|
Coordinates [][2]uint32
|
||||||
|
Unknown1 string
|
||||||
|
SoundEffect string
|
||||||
|
Unknown2 string
|
||||||
|
HasCamp bool
|
||||||
|
Camp struct {
|
||||||
|
Params [7]uint32
|
||||||
|
Array []byte
|
||||||
|
Extra string
|
||||||
|
}
|
||||||
|
|
||||||
|
Version int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFrame(version int) *Frame {
|
||||||
|
return &Frame{Version: version}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Frame) Decode(rd io.Reader) error {
|
||||||
|
if err := binary.Read(rd, end, &f.Duration); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(rd, end, &f.PlaneCount); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.Planes = make([]*Plane, int(f.PlaneCount))
|
||||||
|
for i := range f.Planes {
|
||||||
|
f.Planes[i] = &Plane{}
|
||||||
|
if err := f.Planes[i].Decode(rd); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if f.Version != 300 {
|
||||||
|
if err := binary.Read(rd, end, &f.CoordinateCount); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.Coordinates = make([][2]uint32, f.CoordinateCount)
|
||||||
|
for i := range f.Coordinates {
|
||||||
|
if err := binary.Read(rd, end, f.Coordinates[i][:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch f.Version {
|
||||||
|
case 300, 301:
|
||||||
|
if err := discardN(rd, 144); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case 302, 303:
|
||||||
|
if err := discardN(rd, 96); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if f.Version >= 302 {
|
||||||
|
// entry blocks
|
||||||
|
if err := discardN(rd, 28*6); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// unknown1
|
||||||
|
if err := discardN(rd, 44); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//sound_effect
|
||||||
|
if err := discardN(rd, 18); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// unknown2
|
||||||
|
if err := discardN(rd, 18); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var cast uint32
|
||||||
|
if err := binary.Read(rd, end, &cast); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// camp
|
||||||
|
f.HasCamp = (f.Version >= 303 && (cast > 0))
|
||||||
|
if f.HasCamp {
|
||||||
|
if err := binary.Read(rd, end, f.Camp.Params[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sz := int(f.Camp.Params[1]) * int(f.Camp.Params[2])
|
||||||
|
f.Camp.Array = make([]byte, sz)
|
||||||
|
if _, err := io.ReadFull(rd, f.Camp.Array); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := discardN(rd, 20); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package nori
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GawiSection struct {
|
||||||
|
Version uint32
|
||||||
|
Bpp uint32
|
||||||
|
IsCompressed bool
|
||||||
|
Params [4]uint32
|
||||||
|
BmpCount uint32
|
||||||
|
Size uint32
|
||||||
|
|
||||||
|
HasPalette bool
|
||||||
|
Palette *PaletteSection
|
||||||
|
Images []*Image
|
||||||
|
|
||||||
|
lastSignature [4]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GawiSection) Decode(rd io.Reader) error {
|
||||||
|
if _, err := io.ReadFull(rd, g.lastSignature[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if sig, target := string(g.lastSignature[:]), "GAWI"; sig != target {
|
||||||
|
return fmt.Errorf("bad sig: want %s, got %s", target, sig)
|
||||||
|
}
|
||||||
|
if err := binary.Read(rd, end, &g.Version); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if g.Version != 300 {
|
||||||
|
return fmt.Errorf("bad ver: want 300, got %d", g.Version)
|
||||||
|
}
|
||||||
|
if err := binary.Read(rd, end, &g.Bpp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
good := false
|
||||||
|
for _, v := range [3]uint32{8, 16, 24} {
|
||||||
|
if g.Bpp == v {
|
||||||
|
good = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !good {
|
||||||
|
return fmt.Errorf("bad bpp: %d", g.Bpp)
|
||||||
|
}
|
||||||
|
var container uint32
|
||||||
|
if err := binary.Read(rd, end, &container); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
g.IsCompressed = (container == 1)
|
||||||
|
if err := binary.Read(rd, end, &container); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
g.HasPalette = (container > 0)
|
||||||
|
|
||||||
|
if err := binary.Read(rd, end, g.Params[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(rd, end, &g.BmpCount); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(rd, end, &g.Size); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if g.HasPalette {
|
||||||
|
g.Palette = &PaletteSection{}
|
||||||
|
if err := g.Palette.Decode(rd); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := discardN(rd, 4*int(g.BmpCount)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
g.Images = make([]*Image, int(g.BmpCount))
|
||||||
|
for i := range g.Images {
|
||||||
|
g.Images[i] = &Image{Bpp: g.Bpp}
|
||||||
|
if err := g.Images[i].Decode(rd, g.Palette); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
package nori
|
package nori
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
|
@ -25,7 +24,37 @@ type Image struct {
|
||||||
Img image.Image
|
Img image.Image
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) Decode(rd *bufio.Reader, palette *PaletteSection) error {
|
func (i *Image) Decode(rd io.Reader, palette *PaletteSection) error {
|
||||||
|
if err := binary.Read(rd, end, &i.Count); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if i.Count != 1 {
|
||||||
|
return fmt.Errorf("img count should be 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(rd, end, &i.Size); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(rd, end, &i.Width); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(rd, end, &i.Height); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(rd, end, &i.Delay); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(rd, end, &i.OffsetX); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(rd, end, &i.OffsetY); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
cf := image.NewRGBA64(image.Rect(0, 0, int(i.Width), int(i.Height)))
|
cf := image.NewRGBA64(image.Rect(0, 0, int(i.Width), int(i.Height)))
|
||||||
i.Img = cf
|
i.Img = cf
|
||||||
switch i.Bpp {
|
switch i.Bpp {
|
||||||
|
@ -34,7 +63,7 @@ func (i *Image) Decode(rd *bufio.Reader, palette *PaletteSection) error {
|
||||||
return fmt.Errorf("bpp = 8, but no palette")
|
return fmt.Errorf("bpp = 8, but no palette")
|
||||||
}
|
}
|
||||||
for idx := 0; idx < int(i.Size); idx++ {
|
for idx := 0; idx < int(i.Size); idx++ {
|
||||||
b, err := rd.ReadByte()
|
b, err := readByte(rd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,10 @@
|
||||||
package nori
|
package nori
|
||||||
|
|
||||||
import "image/color"
|
import (
|
||||||
|
"encoding/binary"
|
||||||
type PaletteSection struct {
|
"fmt"
|
||||||
Version uint32
|
"io"
|
||||||
Params [4]uint32
|
)
|
||||||
Divided bool
|
|
||||||
DataLength uint32
|
|
||||||
Palette [256]color.Color
|
|
||||||
MainBound [2]uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type GawiSection struct {
|
|
||||||
Version uint32
|
|
||||||
Bpp uint32
|
|
||||||
IsCompressed bool
|
|
||||||
Params [4]uint32
|
|
||||||
BmpCount uint32
|
|
||||||
Size uint32
|
|
||||||
|
|
||||||
HasPalette bool
|
|
||||||
Palette *PaletteSection
|
|
||||||
// std::vector<uint32> bmp_offsets
|
|
||||||
Images []*Image
|
|
||||||
}
|
|
||||||
|
|
||||||
type Nori struct {
|
type Nori struct {
|
||||||
Version uint32
|
Version uint32
|
||||||
|
@ -34,7 +15,47 @@ type Nori struct {
|
||||||
|
|
||||||
Gawi *GawiSection
|
Gawi *GawiSection
|
||||||
Animations []*Animation
|
Animations []*Animation
|
||||||
AnimationByKey map[string]*Animation
|
//AnimationByKey map[string]*Animation
|
||||||
|
|
||||||
lastSignature [4]byte
|
lastSignature [4]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *Nori) Decode(r io.Reader) error {
|
||||||
|
rd := reflectReader(r)
|
||||||
|
n.Gawi = &GawiSection{}
|
||||||
|
if _, err := io.ReadFull(rd, n.lastSignature[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if sig, target := string(n.lastSignature[:]), "NORI"; sig != target {
|
||||||
|
return fmt.Errorf("expected header %s, got %s", target, sig)
|
||||||
|
}
|
||||||
|
if err := binary.Read(rd, end, &n.Version); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(rd, end, n.Params[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(rd, end, &n.AnimationCount); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(rd, end, &n.SizeNoGawi); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(rd, end, &n.TotalSize); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := n.Gawi.Decode(rd); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := discardN(rd, 4*int(n.AnimationCount)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
n.Animations = make([]*Animation, n.AnimationCount)
|
||||||
|
for i := range n.Animations {
|
||||||
|
n.Animations[i] = NewAnimation(int(n.Version))
|
||||||
|
if err := n.Animations[i].Decode(rd); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
package nori
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"image/color"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PaletteSection struct {
|
||||||
|
Version uint32
|
||||||
|
Params [4]uint32
|
||||||
|
Divided bool
|
||||||
|
DataLength uint32
|
||||||
|
Palette [256]color.Color
|
||||||
|
MainBound [2]uint32
|
||||||
|
|
||||||
|
lastSignature [4]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PaletteSection) Decode(rd io.Reader) error {
|
||||||
|
if _, err := io.ReadFull(rd, p.lastSignature[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if sig, target := string(p.lastSignature[:]), "PAL_"; sig != target {
|
||||||
|
return fmt.Errorf("bad sig: want %s, got %s", target, sig)
|
||||||
|
}
|
||||||
|
p.Palette = [256]color.Color{}
|
||||||
|
if err := binary.Read(rd, end, &p.Version); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(rd, end, p.Params[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var cast uint32
|
||||||
|
if err := binary.Read(rd, end, &cast); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.Divided = (cast > 0)
|
||||||
|
if err := binary.Read(rd, end, &p.DataLength); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i := 0; i < 256; i++ {
|
||||||
|
rgb := [3]byte{}
|
||||||
|
_, err := io.ReadFull(rd, rgb[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
alpha := uint8(0xff)
|
||||||
|
if rgb[0] == 0x00 && rgb[1] == 0xff && rgb[2] == 0x00 {
|
||||||
|
alpha = 0x00
|
||||||
|
}
|
||||||
|
if rgb[0] == 0xff && rgb[1] == 0x00 && rgb[2] == 0xff {
|
||||||
|
alpha = 0x00
|
||||||
|
}
|
||||||
|
p.Palette[i] = &color.RGBA{
|
||||||
|
rgb[0], rgb[1], rgb[2],
|
||||||
|
alpha,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.Divided {
|
||||||
|
if err := binary.Read(rd, end, p.MainBound[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package nori
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Plane struct {
|
||||||
|
BitmapId uint32
|
||||||
|
PlaneX int32
|
||||||
|
PlaneY int32
|
||||||
|
Opacity uint32
|
||||||
|
Blend BlendMode
|
||||||
|
FlagParam uint32
|
||||||
|
RenderFlag uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Plane) Decode(r io.Reader) error {
|
||||||
|
if err := binary.Read(r, end, &p.BitmapId); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(r, end, &p.PlaneX); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(r, end, &p.PlaneY); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(r, end, &p.Opacity); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(r, end, &p.RenderFlag); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(r, end, &p.Blend); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(r, end, &p.FlagParam); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,219 +0,0 @@
|
||||||
package nori
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
"image/color"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
var end = binary.LittleEndian
|
|
||||||
|
|
||||||
type Reader struct {
|
|
||||||
nori *Nori
|
|
||||||
|
|
||||||
r *bufio.Reader
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewReader(rd io.Reader) *Reader {
|
|
||||||
o := &Reader{
|
|
||||||
nori: &Nori{},
|
|
||||||
r: bufio.NewReader(rd),
|
|
||||||
}
|
|
||||||
return o
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Reader) Decode() (*Nori, error) {
|
|
||||||
if _, err := io.ReadFull(n, n.nori.lastSignature[:]); err != nil {
|
|
||||||
return n.nori, err
|
|
||||||
}
|
|
||||||
if sig, target := string(n.nori.lastSignature[:]), "NORI"; sig != target {
|
|
||||||
return n.nori, fmt.Errorf("expected header %s, got %s", target, sig)
|
|
||||||
}
|
|
||||||
if err := binary.Read(n, end, &n.nori.Version); err != nil {
|
|
||||||
return n.nori, err
|
|
||||||
}
|
|
||||||
if err := binary.Read(n, end, n.nori.Params[:]); err != nil {
|
|
||||||
return n.nori, err
|
|
||||||
}
|
|
||||||
if err := binary.Read(n, end, &n.nori.AnimationCount); err != nil {
|
|
||||||
return n.nori, err
|
|
||||||
}
|
|
||||||
if err := binary.Read(n, end, &n.nori.SizeNoGawi); err != nil {
|
|
||||||
return n.nori, err
|
|
||||||
}
|
|
||||||
if err := binary.Read(n, end, &n.nori.TotalSize); err != nil {
|
|
||||||
return n.nori, err
|
|
||||||
}
|
|
||||||
if err := n.decodeGawi(); err != nil {
|
|
||||||
return n.nori, err
|
|
||||||
}
|
|
||||||
return n.nori, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Reader) decodeGawi() error {
|
|
||||||
g := &GawiSection{}
|
|
||||||
n.nori.Gawi = g
|
|
||||||
if _, err := io.ReadFull(n, n.nori.lastSignature[:]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if sig, target := string(n.nori.lastSignature[:]), "GAWI"; sig != target {
|
|
||||||
return fmt.Errorf("bad sig: want %s, got %s", target, sig)
|
|
||||||
}
|
|
||||||
if err := binary.Read(n, end, &g.Version); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if g.Version != 300 {
|
|
||||||
return fmt.Errorf("bad ver: want 300, got %d", g.Version)
|
|
||||||
}
|
|
||||||
if err := binary.Read(n, end, &g.Bpp); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
good := false
|
|
||||||
for _, v := range [3]uint32{8, 16, 24} {
|
|
||||||
if g.Bpp == v {
|
|
||||||
good = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !good {
|
|
||||||
return fmt.Errorf("bad bpp: %d", g.Bpp)
|
|
||||||
}
|
|
||||||
var container uint32
|
|
||||||
if err := binary.Read(n, end, &container); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
g.IsCompressed = (container == 1)
|
|
||||||
if err := binary.Read(n, end, &container); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
g.HasPalette = (container > 0)
|
|
||||||
|
|
||||||
if err := binary.Read(n, end, g.Params[:]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := binary.Read(n, end, &g.BmpCount); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := binary.Read(n, end, &g.Size); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if g.HasPalette {
|
|
||||||
if err := n.decodePalette(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, err := n.r.Discard(4 * int(g.BmpCount)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
g.Images = make([]*Image, int(g.BmpCount))
|
|
||||||
for i := range g.Images {
|
|
||||||
g.Images[i] = &Image{Bpp: g.Bpp}
|
|
||||||
if err := n.decodeImage(g.Images[i]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, err := n.r.Discard(4 * int(n.nori.AnimationCount)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
n.nori.Animations = make([]*Animation, n.nori.AnimationCount)
|
|
||||||
for i := range n.nori.Animations {
|
|
||||||
n.nori.Animations[i] = &Animation{}
|
|
||||||
if err := n.nori.Animations[i].Decode(n.r, int(n.nori.Version)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Reader) decodePalette() error {
|
|
||||||
if _, err := io.ReadFull(n, n.nori.lastSignature[:]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if sig, target := string(n.nori.lastSignature[:]), "PAL_"; sig != target {
|
|
||||||
return fmt.Errorf("bad sig: want %s, got %s", target, sig)
|
|
||||||
}
|
|
||||||
cp := &PaletteSection{
|
|
||||||
Palette: [256]color.Color{},
|
|
||||||
}
|
|
||||||
n.nori.Gawi.Palette = cp
|
|
||||||
if err := binary.Read(n, end, &cp.Version); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := binary.Read(n, end, cp.Params[:]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var cast uint32
|
|
||||||
if err := binary.Read(n, end, &cast); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cp.Divided = (cast > 0)
|
|
||||||
if err := binary.Read(n, end, &cp.DataLength); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for i := 0; i < 256; i++ {
|
|
||||||
rgb := [3]byte{}
|
|
||||||
_, err := io.ReadFull(n, rgb[:])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
alpha := uint8(0xff)
|
|
||||||
if rgb[0] == 0x00 && rgb[1] == 0xff && rgb[2] == 0x00 {
|
|
||||||
alpha = 0x00
|
|
||||||
}
|
|
||||||
if rgb[0] == 0xff && rgb[1] == 0x00 && rgb[2] == 0xff {
|
|
||||||
alpha = 0x00
|
|
||||||
}
|
|
||||||
cp.Palette[i] = &color.RGBA{
|
|
||||||
rgb[0], rgb[1], rgb[2],
|
|
||||||
alpha,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if cp.Divided {
|
|
||||||
if err := binary.Read(n, end, cp.MainBound[:]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (n *Reader) decodeImage(img *Image) error {
|
|
||||||
if err := binary.Read(n, end, &img.Count); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if img.Count != 1 {
|
|
||||||
return fmt.Errorf("img count should be 1")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := binary.Read(n, end, &img.Size); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := binary.Read(n, end, &img.Width); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := binary.Read(n, end, &img.Height); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := binary.Read(n, end, &img.Delay); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := binary.Read(n, end, &img.OffsetX); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := binary.Read(n, end, &img.OffsetY); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := img.Decode(n.r, n.nori.Gawi.Palette); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Reader) Read(b []byte) (int, error) {
|
|
||||||
return n.r.Read(b)
|
|
||||||
}
|
|
|
@ -10,23 +10,7 @@ import (
|
||||||
"gitlab.com/gfxlabs/gfximg/apng"
|
"gitlab.com/gfxlabs/gfximg/apng"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (n *Nori) ShowAnimation() *apng.APNG {
|
func (n *Nori) RenderAnimation(num int) (*apng.APNG, error) {
|
||||||
g := n.Gawi
|
|
||||||
a := &apng.APNG{
|
|
||||||
Frames: make([]apng.Frame, 0, len(g.Images)),
|
|
||||||
}
|
|
||||||
for i := 0; i < len(g.Images); i++ {
|
|
||||||
fr := apng.Frame{
|
|
||||||
Image: g.Images[i].Img,
|
|
||||||
DelayNumerator: uint16(g.Images[i].Delay),
|
|
||||||
DelayDenominator: 1000,
|
|
||||||
}
|
|
||||||
a.Frames = append(a.Frames, fr)
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Nori) ExportAnimation(num int) (*apng.APNG, error) {
|
|
||||||
g := n.Gawi
|
g := n.Gawi
|
||||||
a := &apng.APNG{
|
a := &apng.APNG{
|
||||||
Frames: make([]apng.Frame, 0, len(g.Images)),
|
Frames: make([]apng.Frame, 0, len(g.Images)),
|
|
@ -11,11 +11,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseFile1(t *testing.T) {
|
func TestParseFile1(t *testing.T) {
|
||||||
rd, err := os.OpenFile("./nori_test/test1.nri", os.O_RDONLY, 0666)
|
nori, err := FromFile("./render_test/test1.nri")
|
||||||
if err != nil {
|
|
||||||
t.Errorf("open file: %s", err)
|
|
||||||
}
|
|
||||||
nori, err := NewReader(rd).Decode()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("decode: %s", err)
|
t.Errorf("decode: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -28,11 +24,7 @@ func TestParseFile1(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseFile2(t *testing.T) {
|
func TestParseFile2(t *testing.T) {
|
||||||
rd, err := os.OpenFile("./nori_test/test2.nri", os.O_RDONLY, 0666)
|
nori, err := FromFile("./render_test/test2.nri")
|
||||||
if err != nil {
|
|
||||||
t.Errorf("open file: %s", err)
|
|
||||||
}
|
|
||||||
nori, err := NewReader(rd).Decode()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("decode: %s", err)
|
t.Errorf("decode: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -44,11 +36,7 @@ func TestParseFile2(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParsePalette(t *testing.T) {
|
func TestParsePalette(t *testing.T) {
|
||||||
rd, err := os.OpenFile("./nori_test/palette.nri", os.O_RDONLY, 0666)
|
nori, err := FromFile("./render_test/palette.nri")
|
||||||
if err != nil {
|
|
||||||
t.Errorf("open file: %s", err)
|
|
||||||
}
|
|
||||||
nori, err := NewReader(rd).Decode()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("decode: %s", err)
|
t.Errorf("decode: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -62,9 +50,9 @@ func TestParsePalette(t *testing.T) {
|
||||||
func writeApng(nori *Nori, name string) error {
|
func writeApng(nori *Nori, name string) error {
|
||||||
postfix := ".example"
|
postfix := ".example"
|
||||||
out := new(bytes.Buffer)
|
out := new(bytes.Buffer)
|
||||||
os.MkdirAll(fmt.Sprintf("./nori_test/%s%s", name, postfix), 0740)
|
os.MkdirAll(fmt.Sprintf("./render_test/%s%s", name, postfix), 0740)
|
||||||
for i := range nori.Animations {
|
for i := range nori.Animations {
|
||||||
a, err := nori.ExportAnimation(i)
|
a, err := nori.RenderAnimation(i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "no frame") {
|
if strings.Contains(err.Error(), "no frame") {
|
||||||
continue
|
continue
|
||||||
|
@ -75,7 +63,7 @@ func writeApng(nori *Nori, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = os.WriteFile(fmt.Sprintf("./nori_test/%s%s/animation_%d.png", name, postfix, i), out.Bytes(), 0740)
|
err = os.WriteFile(fmt.Sprintf("./render_test/%s%s/animation_%d.png", name, postfix, i), out.Bytes(), 0740)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 609 B After Width: | Height: | Size: 609 B |
Before Width: | Height: | Size: 609 B After Width: | Height: | Size: 609 B |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |