diff --git a/decode.go b/decode.go new file mode 100644 index 0000000..98fd790 --- /dev/null +++ b/decode.go @@ -0,0 +1,90 @@ +package gifenc + +import ( + "fmt" + "image" + "image/draw" + "image/gif" + "image/png" + "io" + "os" +) + +func (config Config) Decode(path string) error { + // Open the GIF + file, err := os.Open(path) + if err != nil { + return fmt.Errorf("error while opening file: %s", err) + } + + split(file, config.Width, config.Height, config.Output) + + return nil +} + +// Split the GIF into images +func split(file io.Reader, width int, height int, output Output) (err error) { + defer func() { + if recv := recover(); recv != nil { + err = fmt.Errorf("error while decoding file: %s", recv) + } + }() + + gif, err := gif.DecodeAll(file) + if err != nil { + return fmt.Errorf("error while decoding file: %s", err) + } + + x, y := getArea(gif) + if width == 0 { + width = x + } + if height == 0 { + height = y + } + + dst := image.NewRGBA(image.Rect(0, 0, width, height)) + draw.Draw(dst, dst.Bounds(), gif.Image[0], image.Point{}, draw.Src) + + for i, img := range gif.Image { + draw.Draw(dst, dst.Bounds(), img, image.Point{}, draw.Over) + + file, err := os.Create(fmt.Sprintf("%s%s%d%s", output.Path, output.Name, i, ".png")) + if err != nil { + return fmt.Errorf("error while creating image: %s", err) + } + + err = png.Encode(file, dst) + if err != nil { + return fmt.Errorf("error while creating image: %s", err) + } + + file.Close() + } + + return nil +} + +func getArea(gif *gif.GIF) (x, y int) { + var xLow int + var xHigh int + var yLow int + var yHigh int + + for _, img := range gif.Image { + if img.Rect.Min.X < xLow { + xLow = img.Rect.Min.X + } + if img.Rect.Min.Y < yLow { + yLow = img.Rect.Min.Y + } + if img.Rect.Max.X > xHigh { + xHigh = img.Rect.Max.X + } + if img.Rect.Max.Y > yHigh { + yHigh = img.Rect.Max.Y + } + } + + return xHigh - xLow, yHigh - yLow +} diff --git a/encode.go b/encode.go new file mode 100644 index 0000000..f5f9a5c --- /dev/null +++ b/encode.go @@ -0,0 +1,62 @@ +package gifenc + +import ( + "fmt" + "image" + "image/color/palette" + "image/draw" + "image/gif" + "image/png" + "os" +) + +func (config Config) Encode(path string) error { + files, err := os.ReadDir(path) + if err != nil { + return fmt.Errorf("error while opening dir: %s", err) + } + + var allFiles []string + for _, file := range files { + fmt.Print(file.Name()) + allFiles = append(allFiles, file.Name()) + } + + animated := gif.GIF{ + LoopCount: len(allFiles), + } + + for _, file := range allFiles { + reader, err := os.Open(path + file) + if err != nil { + return fmt.Errorf("error while opening file: %s", err) + } + defer reader.Close() + + img, err := png.Decode(reader) + if err != nil { + return fmt.Errorf("error while decoding image: %s", err) + } + bounds := img.Bounds() + drawer := draw.FloydSteinberg + + paletted := image.NewPaletted(bounds, palette.Plan9) + + drawer.Draw(paletted, img.Bounds(), img, image.Point{}) + animated.Image = append(animated.Image, paletted) + animated.Delay = append(animated.Delay, config.Delay) + } + + file, err := os.Create(config.Output.Name) + if err != nil { + return fmt.Errorf("error while creating file: %s", err) + } + defer file.Close() + + encodeErr := gif.EncodeAll(file, &animated) + if encodeErr != nil { + return fmt.Errorf("error while creating file: %s", err) + } + + return nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..65157a1 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/Nota30/gifenc + +go 1.21.6 diff --git a/types.go b/types.go new file mode 100644 index 0000000..95094de --- /dev/null +++ b/types.go @@ -0,0 +1,13 @@ +package gifenc + +type Output struct { + Name string `default:"img"` + Path string +} + +type Config struct { + Output Output + Delay int // encode delay + Width int // decode width + Height int // decode height +}