2023-03-01 23:45:10 +02:00
|
|
|
//go:build js && wasm
|
|
|
|
|
// +build js,wasm
|
|
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"fmt"
|
|
|
|
|
"image"
|
|
|
|
|
"image/gif"
|
|
|
|
|
"log"
|
2023-03-03 05:57:35 +02:00
|
|
|
"math"
|
2023-03-01 23:45:10 +02:00
|
|
|
"syscall/js"
|
|
|
|
|
)
|
|
|
|
|
|
2023-03-03 05:57:35 +02:00
|
|
|
// taken from stdlib's image/image.go (SubImage) and modified to account for
|
|
|
|
|
// gif frame positions
|
|
|
|
|
func Crop(p *image.Paletted, selection image.Rectangle) *image.Paletted {
|
|
|
|
|
intersection := p.Rect.Intersect(selection)
|
2023-03-01 23:45:10 +02:00
|
|
|
|
2023-03-03 05:57:35 +02:00
|
|
|
if intersection.Empty() {
|
|
|
|
|
return &image.Paletted{
|
|
|
|
|
Palette: p.Palette,
|
|
|
|
|
}
|
2023-03-01 23:45:10 +02:00
|
|
|
}
|
|
|
|
|
|
2023-03-03 05:57:35 +02:00
|
|
|
i := p.PixOffset(intersection.Min.X, intersection.Min.Y)
|
|
|
|
|
xMin := int(math.Round(float64(intersection.Min.X) - (float64(selection.Min.X))))
|
|
|
|
|
yMin := int(math.Round(float64(intersection.Min.Y) - (float64(selection.Min.Y))))
|
|
|
|
|
xMax := xMin + (intersection.Dx())
|
|
|
|
|
yMax := yMin + (intersection.Dy())
|
|
|
|
|
bounds := image.Rect(xMin, yMin, xMax, yMax)
|
2023-03-01 23:45:10 +02:00
|
|
|
|
2023-03-03 05:57:35 +02:00
|
|
|
return &image.Paletted{
|
|
|
|
|
Pix: p.Pix[i:],
|
|
|
|
|
Stride: p.Stride,
|
|
|
|
|
Rect: bounds,
|
|
|
|
|
Palette: p.Palette,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func encodeGif(this js.Value, args []js.Value) interface{} {
|
|
|
|
|
rawGifBytes := args[0]
|
|
|
|
|
x := args[1].Int()
|
|
|
|
|
y := args[2].Int()
|
|
|
|
|
w := args[3].Int()
|
|
|
|
|
h := args[4].Int()
|
2023-03-01 23:45:10 +02:00
|
|
|
|
2023-03-03 05:57:35 +02:00
|
|
|
gifBytes := make([]byte, rawGifBytes.Length())
|
|
|
|
|
js.CopyBytesToGo(gifBytes, rawGifBytes)
|
|
|
|
|
gifIn, err := gif.DecodeAll(bytes.NewReader(gifBytes))
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println(err)
|
|
|
|
|
}
|
2023-03-01 23:45:10 +02:00
|
|
|
|
2023-03-03 05:57:35 +02:00
|
|
|
for i := 0; i < len(gifIn.Image); i++ {
|
|
|
|
|
frame := gifIn.Image[i]
|
|
|
|
|
selection := image.Rect(x, y, x+w, y+h)
|
|
|
|
|
gifIn.Image[i] = Crop(frame, selection)
|
2023-03-01 23:45:10 +02:00
|
|
|
}
|
|
|
|
|
|
2023-03-03 05:57:35 +02:00
|
|
|
outGif := gif.GIF{
|
|
|
|
|
Image: gifIn.Image,
|
|
|
|
|
Delay: gifIn.Delay,
|
|
|
|
|
LoopCount: gifIn.LoopCount,
|
|
|
|
|
Disposal: gifIn.Disposal,
|
|
|
|
|
BackgroundIndex: gifIn.BackgroundIndex,
|
2023-03-01 23:45:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
outBytes := new(bytes.Buffer)
|
2023-03-03 05:57:35 +02:00
|
|
|
err = gif.EncodeAll(outBytes, &outGif)
|
2023-03-01 23:45:10 +02:00
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-03 05:57:35 +02:00
|
|
|
return js.CopyBytesToJS(args[5], outBytes.Bytes())
|
2023-03-01 23:45:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
done := make(chan struct{}, 0)
|
|
|
|
|
js.Global().Set("encodeGif", js.FuncOf(encodeGif))
|
|
|
|
|
<-done
|
|
|
|
|
}
|