2022-03-25 05:14:03 +00:00
|
|
|
package nori
|
|
|
|
|
|
|
|
import (
|
2022-12-19 09:09:29 +00:00
|
|
|
"bytes"
|
2022-03-25 05:14:03 +00:00
|
|
|
"encoding/binary"
|
|
|
|
"fmt"
|
|
|
|
"image"
|
|
|
|
"image/color"
|
|
|
|
"io"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Image struct {
|
2022-12-19 09:09:29 +00:00
|
|
|
Bpp uint32
|
|
|
|
Count uint32
|
|
|
|
SubImages []*SubImage
|
|
|
|
}
|
|
|
|
|
|
|
|
type SubImage struct {
|
2022-03-25 05:14:03 +00:00
|
|
|
Delay uint32
|
|
|
|
OffsetX int32
|
|
|
|
OffsetY int32
|
|
|
|
|
|
|
|
Width uint32
|
|
|
|
Height uint32
|
|
|
|
|
|
|
|
Size uint32
|
|
|
|
|
2022-03-25 07:33:23 +00:00
|
|
|
Img image.Image
|
2022-12-19 09:09:29 +00:00
|
|
|
rgb *image.RGBA64
|
2022-03-25 05:14:03 +00:00
|
|
|
}
|
|
|
|
|
2022-12-19 09:09:29 +00:00
|
|
|
func (i *SubImage) decode(rd io.Reader, img *Image, size int, g *GawiSection) error {
|
|
|
|
switch img.Bpp {
|
2022-03-25 05:14:03 +00:00
|
|
|
case 8:
|
2022-12-19 09:09:29 +00:00
|
|
|
if g.Palette == nil {
|
2022-03-25 06:00:01 +00:00
|
|
|
return fmt.Errorf("bpp = 8, but no palette")
|
|
|
|
}
|
2022-12-19 09:09:29 +00:00
|
|
|
for idx := 0; idx < int(size); idx++ {
|
2022-03-25 21:00:43 +00:00
|
|
|
b, err := readByte(rd)
|
2022-03-25 06:00:01 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-12-19 09:09:29 +00:00
|
|
|
col := g.Palette.Palette[b]
|
|
|
|
i.rgb.Set(idx%int(i.Width), idx/int(i.Width), col)
|
2022-03-25 06:00:01 +00:00
|
|
|
}
|
2022-03-25 05:14:03 +00:00
|
|
|
case 16:
|
|
|
|
var bgr uint16
|
2022-12-19 09:09:29 +00:00
|
|
|
for idx := 0; idx < int(size/2); idx++ {
|
2022-03-25 05:14:03 +00:00
|
|
|
if err := binary.Read(rd, end, &bgr); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
red := uint8(((0x7c00 & bgr) >> 10) * 255 / 31)
|
|
|
|
green := uint8(((0x3e0 & bgr) >> 5) * 255 / 31)
|
|
|
|
blue := uint8((0x1f & bgr) * 255 / 31)
|
2022-03-25 10:23:31 +00:00
|
|
|
alpha := uint8(0xff)
|
2022-03-25 19:38:46 +00:00
|
|
|
if red == 0xff && green == 0x00 && blue == 0xff {
|
2022-03-25 10:23:31 +00:00
|
|
|
alpha = 0x00
|
2022-03-25 05:14:03 +00:00
|
|
|
}
|
2022-03-25 10:28:36 +00:00
|
|
|
if red == 0x00 && blue == 0x00 && green == 0xff {
|
|
|
|
alpha = 0x00
|
|
|
|
}
|
2022-03-25 05:14:03 +00:00
|
|
|
col := &color.RGBA{
|
|
|
|
red, green, blue,
|
2022-03-25 10:23:31 +00:00
|
|
|
alpha,
|
2022-03-25 05:14:03 +00:00
|
|
|
}
|
2022-12-19 09:09:29 +00:00
|
|
|
i.rgb.Set(idx%int(i.Width), idx/int(i.Width), col)
|
2022-03-25 05:14:03 +00:00
|
|
|
}
|
|
|
|
case 24:
|
2022-12-19 09:09:29 +00:00
|
|
|
for idx := 0; idx < int(size/3); idx++ {
|
2022-03-25 05:14:03 +00:00
|
|
|
rgb := [3]byte{}
|
|
|
|
_, err := io.ReadFull(rd, rgb[:])
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-03-25 10:23:31 +00:00
|
|
|
alpha := uint8(0xff)
|
2022-03-25 10:28:36 +00:00
|
|
|
|
2022-03-26 06:52:59 +00:00
|
|
|
if rgb[2] == 0x00 && rgb[1] == 0xff && rgb[0] == 0x00 {
|
2022-03-25 10:28:36 +00:00
|
|
|
alpha = 0x00
|
|
|
|
}
|
2022-03-26 06:52:59 +00:00
|
|
|
if rgb[2] == 0xff && rgb[1] == 0x00 && rgb[0] == 0xff {
|
2022-03-25 10:23:31 +00:00
|
|
|
alpha = 0x00
|
2022-03-25 05:14:03 +00:00
|
|
|
}
|
2022-03-26 06:52:59 +00:00
|
|
|
|
|
|
|
col := &color.RGBA{
|
|
|
|
rgb[2], rgb[1], rgb[0],
|
|
|
|
alpha,
|
|
|
|
}
|
2022-12-19 09:09:29 +00:00
|
|
|
i.rgb.Set(idx%int(i.Width), idx/int(i.Width), col)
|
2022-03-25 05:14:03 +00:00
|
|
|
}
|
|
|
|
default:
|
2022-12-19 09:09:29 +00:00
|
|
|
return fmt.Errorf("unsupported bpp, %d", img.Bpp)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *SubImage) decodeCompressed(rd io.Reader, img *Image, g *GawiSection) error {
|
|
|
|
var u16 uint16
|
|
|
|
ob := new(bytes.Buffer)
|
|
|
|
for k := 0; k < int(i.Height); k++ {
|
|
|
|
pixelCount := 0
|
|
|
|
if err := binary.Read(rd, end, &u16); err != nil {
|
|
|
|
return fmt.Errorf("compressed size: %w", err)
|
|
|
|
}
|
|
|
|
want := make([]byte, int(u16)-2)
|
|
|
|
if _, err := io.ReadFull(rd, want); err != nil {
|
|
|
|
return fmt.Errorf("compressed want (%d): %w", u16, err)
|
|
|
|
}
|
|
|
|
buf := bytes.NewBuffer(want)
|
|
|
|
for buf.Len() > 0 {
|
|
|
|
var paddingSize, foregroundSize uint16
|
|
|
|
if err := binary.Read(buf, end, &paddingSize); err != nil {
|
|
|
|
return fmt.Errorf("padding size: %w", err)
|
|
|
|
}
|
|
|
|
if err := binary.Read(buf, end, &foregroundSize); err != nil {
|
|
|
|
return fmt.Errorf("foreground size: %w", err)
|
|
|
|
}
|
|
|
|
for x := 0; x < int(paddingSize); x++ {
|
|
|
|
switch img.Bpp {
|
|
|
|
case 8:
|
|
|
|
ob.Write([]byte{0})
|
|
|
|
case 16:
|
|
|
|
ob.Write([]byte{0x1f, 0x7c})
|
|
|
|
case 24:
|
|
|
|
ob.Write([]byte{0xff, 0, 0xff})
|
|
|
|
default:
|
|
|
|
ob.Write([]byte{0})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
foregroundBytes := make([]byte, int(foregroundSize)*(int(g.Bpp)/8))
|
|
|
|
if _, err := io.ReadFull(buf, foregroundBytes); err != nil {
|
|
|
|
return fmt.Errorf("foreground bytes: %w", err)
|
|
|
|
}
|
|
|
|
for y := 0; y < len(foregroundBytes); y++ {
|
|
|
|
ob.WriteByte(foregroundBytes[y])
|
|
|
|
}
|
|
|
|
pixelCount = pixelCount + int(paddingSize) + int(foregroundSize)
|
|
|
|
}
|
|
|
|
if pixelCount != int(i.Width) {
|
|
|
|
return fmt.Errorf("scanline has fewer pixels than the width (expected %d, got %d)", i.Width, pixelCount)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return i.decode(ob, img, ob.Len(), g)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *SubImage) Decode(rd io.Reader, img *Image, g *GawiSection) error {
|
|
|
|
cf := image.NewRGBA64(image.Rect(0, 0, int(i.Width), int(i.Height)))
|
|
|
|
i.rgb = cf
|
|
|
|
i.Img = i.rgb
|
|
|
|
if g.IsCompressed {
|
|
|
|
return i.decodeCompressed(rd, img, g)
|
|
|
|
}
|
|
|
|
return i.decode(rd, img, int(i.Size), g)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (img *Image) Decode(rd io.Reader, g *GawiSection) error {
|
|
|
|
if err := binary.Read(rd, end, &img.Count); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
img.SubImages = make([]*SubImage, 0, img.Count)
|
|
|
|
for k := 0; k < int(img.Count); k++ {
|
|
|
|
i := &SubImage{}
|
|
|
|
img.SubImages = append(img.SubImages, i)
|
|
|
|
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
|
|
|
|
}
|
|
|
|
if err := i.Decode(rd, img, g); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-03-25 05:14:03 +00:00
|
|
|
}
|
2022-12-19 09:09:29 +00:00
|
|
|
return nil
|
2022-03-25 05:14:03 +00:00
|
|
|
}
|