here u go
This commit is contained in:
parent
4057b3c3c6
commit
0f5e1f4c0a
|
@ -6,6 +6,7 @@ import (
|
||||||
"image/draw"
|
"image/draw"
|
||||||
|
|
||||||
"git.tuxpa.in/a/zlog/log"
|
"git.tuxpa.in/a/zlog/log"
|
||||||
|
"github.com/phrozen/blend"
|
||||||
"gitlab.com/gfxlabs/gfximg/apng"
|
"gitlab.com/gfxlabs/gfximg/apng"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -30,54 +31,89 @@ func (n *Nori) ExportAnimation() (*apng.APNG, error) {
|
||||||
a := &apng.APNG{
|
a := &apng.APNG{
|
||||||
Frames: make([]apng.Frame, 0, len(g.Images)),
|
Frames: make([]apng.Frame, 0, len(g.Images)),
|
||||||
}
|
}
|
||||||
|
images := make([]*image.NRGBA64, 0, len(n.Animations))
|
||||||
for i := 0; i < len(n.Animations); i++ {
|
for i := 0; i < len(n.Animations); i++ {
|
||||||
for _, v := range n.Animations[i].Frames {
|
if len(n.Animations[i].Frames) < 1 {
|
||||||
canvasRect := image.Rect(0, 0, 0, 0)
|
continue
|
||||||
for _, plane := range v.Planes {
|
|
||||||
if int(plane.BitmapId) >= len(n.Gawi.Images) {
|
|
||||||
log.Printf("could not find bitmap %d, only have %d", plane.BitmapId, len(n.Gawi.Images))
|
|
||||||
}
|
|
||||||
bitmap := n.Gawi.Images[plane.BitmapId]
|
|
||||||
canvasRect = canvasRect.Union(bitmap.Img.Bounds())
|
|
||||||
}
|
|
||||||
img := image.NewRGBA64(canvasRect)
|
|
||||||
for _, plane := range v.Planes {
|
|
||||||
bitmap := n.Gawi.Images[plane.BitmapId]
|
|
||||||
transparent := false
|
|
||||||
//flipx
|
|
||||||
if plane.RenderFlag&1 != 0 {
|
|
||||||
}
|
|
||||||
//flipy
|
|
||||||
if plane.RenderFlag&2 != 0 {
|
|
||||||
}
|
|
||||||
// is transparent
|
|
||||||
if plane.RenderFlag&0x20 != 0 {
|
|
||||||
transparent = true
|
|
||||||
}
|
|
||||||
_ = transparent
|
|
||||||
switch plane.Blend {
|
|
||||||
case BlendMode_Alpha:
|
|
||||||
case BlendMode_Mul, BlendMode_Mul7:
|
|
||||||
case BlendMode_Add, BlendMode_Add8:
|
|
||||||
case BlendMode_InvertMul, BlendMode_InvertMul5:
|
|
||||||
case BlendMode_None:
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unknown blend mode: %d", plane.Blend)
|
|
||||||
}
|
|
||||||
draw.Draw(img,
|
|
||||||
img.Rect,
|
|
||||||
bitmap.Img,
|
|
||||||
image.Point{X: int(plane.PlaneX),
|
|
||||||
Y: int(plane.PlaneY)}, draw.Over)
|
|
||||||
}
|
|
||||||
fr := apng.Frame{
|
|
||||||
Image: g.Images[i].Img,
|
|
||||||
DelayNumerator: uint16(g.Images[i].Delay),
|
|
||||||
DelayDenominator: 1000,
|
|
||||||
}
|
|
||||||
a.Frames = append(a.Frames, fr)
|
|
||||||
}
|
}
|
||||||
|
planes := n.Animations[i].Frames[0].Planes
|
||||||
|
var canvasRect image.Rectangle
|
||||||
|
for _, plane := range planes {
|
||||||
|
if int(plane.BitmapId) >= len(n.Gawi.Images) {
|
||||||
|
log.Printf("could not find bitmap %d, only have %d", plane.BitmapId, len(n.Gawi.Images))
|
||||||
|
}
|
||||||
|
bitmap := n.Gawi.Images[plane.BitmapId]
|
||||||
|
pt := image.Pt(int(plane.PlaneX), int(plane.PlaneY)) // where to put the point
|
||||||
|
rc := bitmap.Img.Bounds()
|
||||||
|
canvasRect = canvasRect.Union(rc.Add(pt))
|
||||||
|
}
|
||||||
|
img := image.NewNRGBA64(canvasRect)
|
||||||
|
for _, plane := range planes {
|
||||||
|
bitmap := n.Gawi.Images[plane.BitmapId]
|
||||||
|
transparent := false
|
||||||
|
//flipx
|
||||||
|
if plane.RenderFlag&1 != 0 {
|
||||||
|
}
|
||||||
|
//flipy
|
||||||
|
if plane.RenderFlag&2 != 0 {
|
||||||
|
}
|
||||||
|
// is transparent
|
||||||
|
if plane.RenderFlag&0x20 != 0 {
|
||||||
|
transparent = true
|
||||||
|
}
|
||||||
|
_ = transparent
|
||||||
|
pt := image.Pt(int(plane.PlaneX), int(plane.PlaneY)) // where to put the point
|
||||||
|
src := bitmap.Img
|
||||||
|
sr := src.Bounds()
|
||||||
|
r := image.Rectangle{pt, pt.Add(sr.Size())}
|
||||||
|
switch plane.Blend {
|
||||||
|
case BlendMode_Alpha:
|
||||||
|
case BlendMode_Mul, BlendMode_Mul7:
|
||||||
|
blend.BlendImage(img, bitmap.Img, blend.Multiply)
|
||||||
|
case BlendMode_Add, BlendMode_Add8:
|
||||||
|
blend.BlendImage(img, bitmap.Img, blend.Add)
|
||||||
|
case BlendMode_InvertMul, BlendMode_InvertMul5:
|
||||||
|
blend.BlendImage(img, bitmap.Img, blend.Multiply)
|
||||||
|
case BlendMode_None:
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown blend mode: %d", plane.Blend)
|
||||||
|
}
|
||||||
|
draw.Draw(img,
|
||||||
|
r,
|
||||||
|
src,
|
||||||
|
sr.Min,
|
||||||
|
draw.Over,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if len(planes) > 0 {
|
||||||
|
images = append(images, img)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
or := images[0].Bounds()
|
||||||
|
for _, realFrame := range images {
|
||||||
|
or = realFrame.Bounds().Union(or)
|
||||||
|
}
|
||||||
|
// TODO: this is bugged
|
||||||
|
for i, realFrame := range images {
|
||||||
|
big := image.NewNRGBA64(or)
|
||||||
|
draw.Draw(
|
||||||
|
big,
|
||||||
|
big.Rect,
|
||||||
|
realFrame,
|
||||||
|
realFrame.Bounds().Min,
|
||||||
|
draw.Src,
|
||||||
|
)
|
||||||
|
fr := apng.Frame{
|
||||||
|
Image: big,
|
||||||
|
DisposeOp: apng.DISPOSE_OP_PREVIOUS,
|
||||||
|
BlendOp: apng.BLEND_OP_OVER,
|
||||||
|
DelayDenominator: 1000,
|
||||||
|
}
|
||||||
|
if g.Images[i].Delay != 0 {
|
||||||
|
fr.DelayNumerator = uint16(g.Images[i].Delay)
|
||||||
|
}
|
||||||
|
a.Frames = append(a.Frames, fr)
|
||||||
}
|
}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,11 +51,13 @@ func (i *Image) Decode(rd *bufio.Reader, palette *PaletteSection) error {
|
||||||
red := uint8(((0x7c00 & bgr) >> 10) * 255 / 31)
|
red := uint8(((0x7c00 & bgr) >> 10) * 255 / 31)
|
||||||
green := uint8(((0x3e0 & bgr) >> 5) * 255 / 31)
|
green := uint8(((0x3e0 & bgr) >> 5) * 255 / 31)
|
||||||
blue := uint8((0x1f & bgr) * 255 / 31)
|
blue := uint8((0x1f & bgr) * 255 / 31)
|
||||||
if red != 0 && blue != 0 && green != 0 {
|
alpha := uint8(0xff)
|
||||||
|
if red == 0xff && blue == 0xff {
|
||||||
|
alpha = 0x00
|
||||||
}
|
}
|
||||||
col := &color.RGBA{
|
col := &color.RGBA{
|
||||||
red, green, blue,
|
red, green, blue,
|
||||||
0xff,
|
alpha,
|
||||||
}
|
}
|
||||||
cf.Set(idx%int(i.Width), idx/int(i.Width), col)
|
cf.Set(idx%int(i.Width), idx/int(i.Width), col)
|
||||||
}
|
}
|
||||||
|
@ -68,9 +70,13 @@ func (i *Image) Decode(rd *bufio.Reader, palette *PaletteSection) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
alpha := uint8(0xff)
|
||||||
col := &color.RGBA{
|
col := &color.RGBA{
|
||||||
rgb[0], rgb[1], rgb[2],
|
rgb[0], rgb[1], rgb[2],
|
||||||
0xff,
|
alpha,
|
||||||
|
}
|
||||||
|
if rgb[0] == 0xff && rgb[2] == 0xff {
|
||||||
|
alpha = 0x00
|
||||||
}
|
}
|
||||||
cf.Set(idx%int(i.Width), idx/int(i.Width), col)
|
cf.Set(idx%int(i.Width), idx/int(i.Width), col)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.tuxpa.in/a/zlog/log"
|
|
||||||
"gitlab.com/gfxlabs/gfximg/apng"
|
"gitlab.com/gfxlabs/gfximg/apng"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -59,14 +58,21 @@ func TestParsePalette(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("export: %s", err)
|
t.Errorf("export: %s", err)
|
||||||
}
|
}
|
||||||
writeApng(a, "./nori_test/palette.apng")
|
err = writeApng(a, "./nori_test/palette.apng")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("export: %s", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeApng(a *apng.APNG, fp string) {
|
func writeApng(a *apng.APNG, fp string) error {
|
||||||
out := new(bytes.Buffer)
|
out := new(bytes.Buffer)
|
||||||
err := apng.Encode(out, *a)
|
err := apng.Encode(out, *a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("fail to encode apng %s", err)
|
return err
|
||||||
}
|
}
|
||||||
os.WriteFile(fp, out.Bytes(), 0740)
|
err = os.WriteFile(fp, out.Bytes(), 0740)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 577 KiB |
Binary file not shown.
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 56 KiB |
Binary file not shown.
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 60 KiB |
1
go.mod
1
go.mod
|
@ -10,5 +10,6 @@ require (
|
||||||
require (
|
require (
|
||||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
|
github.com/phrozen/blend v0.0.0-20210220204729-f26b6cf7a28e // indirect
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
|
||||||
)
|
)
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -6,6 +6,8 @@ github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZb
|
||||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
|
github.com/phrozen/blend v0.0.0-20210220204729-f26b6cf7a28e h1:r8tWFp1HMiodzOwFtEVZ41Q0PuX/G5PWHZS14kAQMoI=
|
||||||
|
github.com/phrozen/blend v0.0.0-20210220204729-f26b6cf7a28e/go.mod h1:8LjAsvtcQgvNmMQZ/iSuduOKYgRA37KcsgPg8ZC6Krc=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
gitlab.com/gfxlabs/gfximg v0.0.5 h1:jtHE6In6axz0zGPy7YnLIZV9RFdcFEZzpdqoXb52K9s=
|
gitlab.com/gfxlabs/gfximg v0.0.5 h1:jtHE6In6axz0zGPy7YnLIZV9RFdcFEZzpdqoXb52K9s=
|
||||||
|
|
Loading…
Reference in New Issue