あああああああああああああああああああああああああああ
This commit is contained in:
parent
ec465535d7
commit
1375ab7a1a
5
Makefile
5
Makefile
|
@ -5,6 +5,9 @@ img_tag = local
|
|||
cory: clean
|
||||
go build -o ./cory ./_cmd/cory-bin
|
||||
|
||||
cory_win: clean
|
||||
go build -o ./cory.exe ./_cmd/cory-bin
|
||||
|
||||
docker:
|
||||
DOCKER_BUILDKIT=1 docker build -f server.Dockerfile -t $(img_user)/$(img_name):$(img_tag) .
|
||||
|
||||
|
@ -12,4 +15,4 @@ server-run: docker
|
|||
docker run -p 3333:3333 $(img_user)/$(img_name):$(img_tag) --serve
|
||||
|
||||
clean:
|
||||
rm -rf cory
|
||||
rm -rf cory cory.exe
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"git.tuxpa.in/a/nori/renderer"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
@ -57,7 +58,7 @@ func dump(filename string, output string) {
|
|||
}
|
||||
out := new(bytes.Buffer)
|
||||
printIf("rendering %d animation(s)\n", n.AnimationCount)
|
||||
animations, err := nori.RenderAnimations(n)
|
||||
animations, err := renderer.RenderAnimationsApng(n)
|
||||
if err != nil {
|
||||
log.Panicln("animation: %s", err)
|
||||
}
|
||||
|
@ -93,7 +94,7 @@ func serve() {
|
|||
if err := n.Decode(r.Body); err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
}
|
||||
frames, err := nori.RenderAnimations(n)
|
||||
frames, err := renderer.RenderAnimationsApng(n)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
}
|
||||
|
|
32
frame.go
32
frame.go
|
@ -81,23 +81,25 @@ func (f *Frame) Decode(rd io.Reader) error {
|
|||
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 {
|
||||
if f.Version >= 303 {
|
||||
var cast uint32
|
||||
if err := binary.Read(rd, end, &cast); 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
|
||||
// camp
|
||||
f.HasCamp = 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
6
go.mod
6
go.mod
|
@ -4,14 +4,16 @@ go 1.18
|
|||
|
||||
require (
|
||||
git.tuxpa.in/a/zlog v1.32.0
|
||||
github.com/go-chi/chi/v5 v5.0.7
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/phrozen/blend v0.0.0-20210220204729-f26b6cf7a28e
|
||||
gitlab.com/gfxlabs/gfximg v0.0.5
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/chai2010/webp v1.1.1 // indirect
|
||||
github.com/go-chi/chi/v5 v5.0.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
gitlab.com/gfxlabs/goutil v1.5.0 // indirect
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
|
||||
)
|
||||
|
|
13
go.sum
13
go.sum
|
@ -1,6 +1,10 @@
|
|||
git.tuxpa.in/a/zlog v1.32.0 h1:KKXbRF1x8kJDSzUoGz/pivo+4TVY6xT5sVtdFZ6traY=
|
||||
git.tuxpa.in/a/zlog v1.32.0/go.mod h1:vUa2Qhu6DLPLqmfRy99FiPqaY2eb6/KQjtMekW3UNnA=
|
||||
github.com/chai2010/webp v1.1.1 h1:jTRmEccAJ4MGrhFOrPMpNGIJ/eybIgwKpcACsrTEapk=
|
||||
github.com/chai2010/webp v1.1.1/go.mod h1:0XVwvZWdjjdxpUEIf7b9g9VkHFnInUSYujwqTLEuldU=
|
||||
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
|
||||
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
|
@ -14,8 +18,13 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||
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/go.mod h1:IAYZwCoqy3JFKwkKafragpfecp5Up6FFIzI7VvK2Zzo=
|
||||
gitlab.com/gfxlabs/goutil v1.5.0 h1:tYjMbDRtK93MPrWrZE4Ub67Ng8rYwTahtb+Bfpf0Spk=
|
||||
gitlab.com/gfxlabs/goutil v1.5.0/go.mod h1:NGvdG6oTLV2cEX4HKtewdzx/ZIvC+eAS7EbjKy4sXsA=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
|
16
image.go
16
image.go
|
@ -103,17 +103,19 @@ func (i *Image) Decode(rd io.Reader, palette *PaletteSection) error {
|
|||
return err
|
||||
}
|
||||
alpha := uint8(0xff)
|
||||
|
||||
if rgb[2] == 0x00 && rgb[1] == 0xff && rgb[0] == 0x00 {
|
||||
alpha = 0x00
|
||||
}
|
||||
if rgb[2] == 0xff && rgb[1] == 0x00 && rgb[0] == 0xff {
|
||||
alpha = 0x00
|
||||
}
|
||||
|
||||
col := &color.RGBA{
|
||||
rgb[0], rgb[1], rgb[2],
|
||||
rgb[2], rgb[1], rgb[0],
|
||||
alpha,
|
||||
}
|
||||
|
||||
if rgb[0] == 0x00 && rgb[1] == 0xff && rgb[2] == 0x00 {
|
||||
alpha = 0x00
|
||||
}
|
||||
if rgb[0] == 0xff && rgb[1] == 0x00 && rgb[2] == 0xff {
|
||||
alpha = 0x00
|
||||
}
|
||||
cf.Set(idx%int(i.Width), idx/int(i.Width), col)
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -18,7 +18,7 @@ func main() {
|
|||
log.Panicln("decode: %s", err)
|
||||
}
|
||||
// uses apng encoder/decoder from https://gitlab.com/gfxlabs/gfximg
|
||||
animations, err := n.RenderAnimations(n)
|
||||
animations, err := n.RenderAnimationsApng(n)
|
||||
if err != nil {
|
||||
log.Panicln("render: %s", err)
|
||||
}
|
||||
|
|
93
render.go
93
render.go
|
@ -2,47 +2,38 @@ package nori
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/draw"
|
||||
"strings"
|
||||
|
||||
"git.tuxpa.in/a/zlog/log"
|
||||
"github.com/disintegration/imaging"
|
||||
"github.com/phrozen/blend"
|
||||
"gitlab.com/gfxlabs/gfximg/apng"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
)
|
||||
|
||||
func RenderAnimations(n *Nori) ([]*apng.APNG, error) {
|
||||
apngs := make([]*apng.APNG, 0, len(n.Animations))
|
||||
for i := range n.Animations {
|
||||
a, err := RenderAnimation(n, i)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "no frame") {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
apngs = append(apngs, a)
|
||||
}
|
||||
return apngs, nil
|
||||
func copyImage(img image.Image) image.Image {
|
||||
copied := image.NewNRGBA(img.Bounds())
|
||||
draw.Draw(copied, img.Bounds(), img, img.Bounds().Min, draw.Over)
|
||||
return copied
|
||||
}
|
||||
|
||||
func RenderAnimation(n *Nori, num int) (*apng.APNG, error) {
|
||||
type RenderFunc = func(img image.Image, delay int)
|
||||
|
||||
func RenderAnimation(n *Nori, num int, f RenderFunc) error {
|
||||
g := n.Gawi
|
||||
a := &apng.APNG{
|
||||
Frames: make([]apng.Frame, 0, len(g.Images)),
|
||||
}
|
||||
if len(n.Animations[num].Frames) == 0 {
|
||||
return nil, fmt.Errorf("no frames found for animation")
|
||||
return fmt.Errorf("no frames found for animation")
|
||||
}
|
||||
images := make([]*image.NRGBA64, 0, len(n.Animations[num].Frames))
|
||||
images := make([]image.Image, 0, len(n.Animations[num].Frames))
|
||||
durations := make([]uint32, 0, len(n.Animations[num].Frames))
|
||||
for _, frame := range n.Animations[num].Frames {
|
||||
planes := frame.Planes
|
||||
var canvasRect image.Rectangle
|
||||
for i, 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))
|
||||
if int(plane.BitmapId) >= len(g.Images) {
|
||||
log.Printf("could not find bitmap %d, only have %d", plane.BitmapId, len(g.Images))
|
||||
}
|
||||
bitmap := n.Gawi.Images[plane.BitmapId]
|
||||
bitmap := g.Images[plane.BitmapId]
|
||||
pt := image.Pt(int(plane.PlaneX), int(plane.PlaneY)) // where to put the point
|
||||
rc := bitmap.Img.Bounds().Add(pt) // translate rectangle to put in the global canvas
|
||||
if i == 0 {
|
||||
|
@ -51,15 +42,24 @@ func RenderAnimation(n *Nori, num int) (*apng.APNG, error) {
|
|||
canvasRect = canvasRect.Union(rc)
|
||||
}
|
||||
}
|
||||
img := image.NewNRGBA64(canvasRect)
|
||||
img := image.NewNRGBA(canvasRect)
|
||||
for _, plane := range planes {
|
||||
bitmap := n.Gawi.Images[plane.BitmapId]
|
||||
bitmap := g.Images[plane.BitmapId]
|
||||
drawBitmap := bitmap.Img
|
||||
transparent := false
|
||||
//flipx
|
||||
if plane.RenderFlag&1 != 0 {
|
||||
if bitmap.Img == drawBitmap {
|
||||
drawBitmap = copyImage(bitmap.Img)
|
||||
}
|
||||
drawBitmap = imaging.FlipH(drawBitmap)
|
||||
}
|
||||
//flipy
|
||||
if plane.RenderFlag&2 != 0 {
|
||||
if bitmap.Img == drawBitmap {
|
||||
drawBitmap = copyImage(bitmap.Img)
|
||||
}
|
||||
drawBitmap = imaging.FlipV(drawBitmap)
|
||||
}
|
||||
// is transparent
|
||||
if plane.RenderFlag&0x20 != 0 {
|
||||
|
@ -67,36 +67,46 @@ func RenderAnimation(n *Nori, num int) (*apng.APNG, error) {
|
|||
}
|
||||
_ = transparent
|
||||
pt := image.Pt(int(plane.PlaneX), int(plane.PlaneY)) // where to put the point
|
||||
rc := bitmap.Img.Bounds().Add(pt)
|
||||
src := bitmap.Img
|
||||
rc := drawBitmap.Bounds().Add(pt)
|
||||
src := drawBitmap
|
||||
switch plane.Blend {
|
||||
case BlendMode_InvertMul, BlendMode_InvertMul5:
|
||||
img = imaging.Invert(img)
|
||||
fallthrough
|
||||
case BlendMode_Alpha:
|
||||
case BlendMode_Mul, BlendMode_Mul7:
|
||||
blend.BlendImage(img, bitmap.Img, blend.Multiply)
|
||||
blend.BlendImage(img, drawBitmap, 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)
|
||||
blend.BlendImage(img, drawBitmap, blend.Add)
|
||||
case BlendMode_None:
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown blend mode: %d", plane.Blend)
|
||||
return fmt.Errorf("unknown blend mode: %d", plane.Blend)
|
||||
}
|
||||
draw.Draw(
|
||||
|
||||
mask := (image.Image)(nil)
|
||||
if transparent {
|
||||
mask = &image.Uniform{C: color.RGBA{A: 160}}
|
||||
}
|
||||
|
||||
draw.DrawMask(
|
||||
img,
|
||||
rc,
|
||||
src,
|
||||
src.Bounds().Min,
|
||||
mask,
|
||||
src.Bounds().Min,
|
||||
draw.Over,
|
||||
)
|
||||
}
|
||||
images = append(images, img)
|
||||
durations = append(durations, frame.Duration)
|
||||
}
|
||||
or := images[0].Bounds()
|
||||
for _, realFrame := range images {
|
||||
or = realFrame.Bounds().Union(or)
|
||||
}
|
||||
if or.Size().X == 0 || or.Size().Y == 0 {
|
||||
return nil, fmt.Errorf("no frames found for animation")
|
||||
return fmt.Errorf("no frames found for animation")
|
||||
}
|
||||
for i, realFrame := range images {
|
||||
//log.Info().Int("frame", num).Interface("rect", or).Interface("frame", realFrame.Bounds()).Msg("")
|
||||
|
@ -112,11 +122,10 @@ func RenderAnimation(n *Nori, num int) (*apng.APNG, error) {
|
|||
fr := apng.Frame{
|
||||
Image: big,
|
||||
DelayDenominator: 1000,
|
||||
DelayNumerator: uint16(durations[i]),
|
||||
}
|
||||
if g.Images[i].Delay != 0 {
|
||||
fr.DelayNumerator = uint16(g.Images[i].Delay)
|
||||
}
|
||||
a.Frames = append(a.Frames, fr)
|
||||
f(big, int(fr.DelayNumerator))
|
||||
}
|
||||
return a, nil
|
||||
return nil
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package nori
|
||||
package nori_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"git.tuxpa.in/a/nori"
|
||||
"git.tuxpa.in/a/nori/renderer"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -11,7 +13,7 @@ import (
|
|||
)
|
||||
|
||||
func TestParseFile1(t *testing.T) {
|
||||
nori, err := FromFile("./render_test/test1.nri")
|
||||
nori, err := nori.FromFile("./render_test/test1.nri")
|
||||
if err != nil {
|
||||
t.Errorf("decode: %s", err)
|
||||
}
|
||||
|
@ -24,7 +26,7 @@ func TestParseFile1(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestParseFile2(t *testing.T) {
|
||||
nori, err := FromFile("./render_test/test2.nri")
|
||||
nori, err := nori.FromFile("./render_test/test2.nri")
|
||||
if err != nil {
|
||||
t.Errorf("decode: %s", err)
|
||||
}
|
||||
|
@ -35,8 +37,34 @@ func TestParseFile2(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestParseFile3(t *testing.T) {
|
||||
nori, err := nori.FromFile("./render_test/CharCreateNSelectUI.bac")
|
||||
if err != nil {
|
||||
t.Errorf("decode: %s", err)
|
||||
}
|
||||
t.Logf("\n nori: %+v\n gawi: %+v", nori, nori.Gawi)
|
||||
|
||||
err = writeApng(nori, "charcreate")
|
||||
if err != nil {
|
||||
t.Errorf("export: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseFile4(t *testing.T) {
|
||||
nori, err := nori.FromFile("./render_test/LoadingUI.bac")
|
||||
if err != nil {
|
||||
t.Errorf("decode: %s", err)
|
||||
}
|
||||
t.Logf("\n nori: %+v\n gawi: %+v", nori, nori.Gawi)
|
||||
|
||||
err = writeApng(nori, "LoadingUI")
|
||||
if err != nil {
|
||||
t.Errorf("export: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePalette(t *testing.T) {
|
||||
nori, err := FromFile("./render_test/palette.nri")
|
||||
nori, err := nori.FromFile("./render_test/palette.nri")
|
||||
if err != nil {
|
||||
t.Errorf("decode: %s", err)
|
||||
}
|
||||
|
@ -47,12 +75,12 @@ func TestParsePalette(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func writeApng(nori *Nori, name string) error {
|
||||
func writeApng(n *nori.Nori, name string) error {
|
||||
postfix := ".example"
|
||||
out := new(bytes.Buffer)
|
||||
os.MkdirAll(fmt.Sprintf("./render_test/%s%s", name, postfix), 0740)
|
||||
for i := range nori.Animations {
|
||||
a, err := RenderAnimation(nori, i)
|
||||
for i := range n.Animations {
|
||||
a, err := renderer.RenderAnimationApng(n, i)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "no frame") {
|
||||
continue
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,47 @@
|
|||
package renderer
|
||||
|
||||
import (
|
||||
"git.tuxpa.in/a/nori"
|
||||
"gitlab.com/gfxlabs/gfximg/apng"
|
||||
"image"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func newRenderApngFunc(a *apng.APNG) nori.RenderFunc {
|
||||
return func(img image.Image, delay int) {
|
||||
fr := apng.Frame{
|
||||
Image: img,
|
||||
DelayDenominator: 1000,
|
||||
}
|
||||
if delay != 0 {
|
||||
fr.DelayNumerator = uint16(delay)
|
||||
}
|
||||
a.Frames = append(a.Frames, fr)
|
||||
}
|
||||
}
|
||||
|
||||
func RenderAnimationsApng(n *nori.Nori) ([]*apng.APNG, error) {
|
||||
apngs := make([]*apng.APNG, 0, len(n.Animations))
|
||||
for i := range n.Animations {
|
||||
a, err := RenderAnimationApng(n, i)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "no frame") {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
apngs = append(apngs, a)
|
||||
}
|
||||
return apngs, nil
|
||||
}
|
||||
|
||||
func RenderAnimationApng(n *nori.Nori, i int) (*apng.APNG, error) {
|
||||
a := &apng.APNG{
|
||||
Frames: make([]apng.Frame, 0, len(n.Gawi.Images)),
|
||||
}
|
||||
err := nori.RenderAnimation(n, i, newRenderApngFunc(a))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return a, nil
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package renderer
|
||||
|
||||
import (
|
||||
"git.tuxpa.in/a/nori"
|
||||
"image"
|
||||
"image/color/palette"
|
||||
"image/draw"
|
||||
"image/gif"
|
||||
)
|
||||
|
||||
func newRenderGifFunc(gif *gif.GIF) nori.RenderFunc {
|
||||
return func(img image.Image, delay int) {
|
||||
i := image.NewPaletted(img.Bounds(), palette.Plan9)
|
||||
draw.Draw(i, img.Bounds(), img, img.Bounds().Min, draw.Over)
|
||||
|
||||
gif.Image = append(gif.Image, i)
|
||||
gif.Delay = append(gif.Delay, delay)
|
||||
}
|
||||
}
|
||||
|
||||
func RenderAnimationGif(n *nori.Nori, i int) (*gif.GIF, error) {
|
||||
gif := &gif.GIF{
|
||||
Image: make([]*image.Paletted, 0),
|
||||
Delay: make([]int, 0),
|
||||
LoopCount: 0,
|
||||
}
|
||||
err := nori.RenderAnimation(n, i, newRenderGifFunc(gif))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gif, nil
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package renderer_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"git.tuxpa.in/a/nori"
|
||||
"git.tuxpa.in/a/nori/renderer"
|
||||
"git.tuxpa.in/a/zlog/log"
|
||||
"image/gif"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMakeGif1(t *testing.T) {
|
||||
nori, err := nori.FromFile("../render_test/CharCreateNSelectUI.bac")
|
||||
if err != nil {
|
||||
t.Errorf("decode: %s", err)
|
||||
}
|
||||
t.Logf("\n nori: %+v\n gawi: %+v", nori, nori.Gawi)
|
||||
|
||||
err = writeGif(nori, "charcreate")
|
||||
if err != nil {
|
||||
t.Errorf("export: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeGif(n *nori.Nori, name string) error {
|
||||
postfix := ".example"
|
||||
out := new(bytes.Buffer)
|
||||
os.MkdirAll(fmt.Sprintf("../render_test/%s%s", name, postfix), 0740)
|
||||
for i := range n.Animations {
|
||||
g, err := renderer.RenderAnimationGif(n, i)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "no frame") {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
err = gif.EncodeAll(out, g)
|
||||
if err != nil {
|
||||
log.Errorf("EncodeAll failed for frame %d, skipping: %s", i, err)
|
||||
continue
|
||||
}
|
||||
err = os.WriteFile(fmt.Sprintf("../render_test/%s%s/animation_%d.gif", name, postfix, i), out.Bytes(), 0740)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out.Reset()
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -3,6 +3,7 @@ package utils
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"git.tuxpa.in/a/nori/renderer"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
|
@ -48,7 +49,7 @@ func TestParsePalette(t *testing.T) {
|
|||
|
||||
func writeZip(n *nori.Nori, name string) error {
|
||||
out := new(bytes.Buffer)
|
||||
frames, err := nori.RenderAnimations(n)
|
||||
frames, err := renderer.RenderAnimationsApng(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue