package app import ( "fmt" "image" "image/draw" "image/gif" "log" "unsafe" "github.com/gabriel-vasile/mimetype" "github.com/veandco/go-sdl2/img" "github.com/veandco/go-sdl2/sdl" ) type ViewerImageFrame struct { Surface *sdl.Surface Duration int } type ViewerImage struct { Frames []ViewerImageFrame Width int32 Height int32 } func loadViewerImageDefault(fileInfo *FileInfo) (*ViewerImage, error) { data := fileInfo.OpenRW() if data == nil { return nil, fmt.Errorf("failed to open file: %s", fileInfo.Name) } defer data.Close() surface, err := img.LoadRW(data, false) if err != nil { return nil, err } return &ViewerImage{Frames: []ViewerImageFrame{{Surface: surface, Duration: 99999}}, Width: surface.W, Height: surface.H}, nil } func loadViewerImageGif(fileInfo *FileInfo) (*ViewerImage, error) { file, err := fileInfo.Open() if err != nil { return nil, err } defer file.Close() gifData, err := gif.DecodeAll(file) if err != nil { return nil, err } bounds := gifData.Image[0].Bounds() rgbaFrameImage := image.NewRGBA(bounds) var frames = make([]ViewerImageFrame, len(gifData.Image)) for i, frameImage := range gifData.Image { draw.Draw(rgbaFrameImage, bounds, frameImage, bounds.Min, draw.Src) surface, err := sdl.CreateRGBSurfaceWithFormatFrom( unsafe.Pointer(&rgbaFrameImage.Pix[0]), int32(bounds.Dx()), int32(bounds.Dy()), 32, int32(rgbaFrameImage.Stride), sdl.PIXELFORMAT_ABGR8888, ) if err != nil { return nil, err } copiedSurface, err := surface.Convert(surface.Format, 0) if err != nil { return nil, err } surface.Free() frames[i] = ViewerImageFrame{Surface: copiedSurface, Duration: gifData.Delay[i] * 10} } return &ViewerImage{Frames: frames, Width: int32(gifData.Config.Width), Height: int32(gifData.Config.Height)}, nil } func (v *ViewerImage) Free() { for _, frame := range v.Frames { frame.Surface.Free() } } func (v *Viewer) RenderViewerImage() { fileInfo := v.File() if fileInfo == nil { v.SetError(errNoFiles) return } log.Printf(">> render viewer image %s", fileInfo.Name) file, err := fileInfo.Open() if err != nil { v.SetError(err) return } defer file.Close() fileMimeType, err := mimetype.DetectReader(file) if err != nil { v.SetError(err) return } fileExt := fileMimeType.Extension() log.Printf(" - detected %s (%s) file", fileExt, fileMimeType.String()) var image *ViewerImage switch fileExt { case ".gif": image, err = loadViewerImageGif(fileInfo) default: image, err = loadViewerImageDefault(fileInfo) } if err != nil { v.SetError(err) return } v.Image = image }