100 lines
2.1 KiB
Go
100 lines
2.1 KiB
Go
package gallery
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"math"
|
|
"path"
|
|
|
|
"git.schreifuchs.ch/schreifuchs/schreifuchs.ch/internal/components/images"
|
|
"github.com/InfinityTools/go-binpack2d"
|
|
)
|
|
|
|
type Gallery struct {
|
|
GridWith int
|
|
GridHeight int
|
|
Images []Image
|
|
}
|
|
|
|
type Image struct {
|
|
UID string
|
|
X int
|
|
Y int
|
|
Width int
|
|
Height int
|
|
}
|
|
|
|
func (s *Service) GetImages(ctx context.Context) (imgs []images.Image, err error) {
|
|
files, err := s.fs.ReadDir(s.cfg.Path)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
for _, file := range files {
|
|
imagePath := path.Join(s.cfg.Path, file.Name())
|
|
img, err := s.img.GetImage(imagePath)
|
|
if err != nil || img.Image == nil {
|
|
continue
|
|
}
|
|
imgs = append(imgs, img)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (s *Service) GetGallery(ctx context.Context, width int) (gallery Gallery, err error) {
|
|
imgs, err := s.GetImages(ctx)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
packer := binpack2d.Create(50, 999999)
|
|
|
|
for len(imgs) > 0 {
|
|
unused := make([]images.Image, 0, len(imgs))
|
|
for _, img := range imgs {
|
|
width, height := adjustImageSize(img, 200)
|
|
rect, ok := packer.Insert(width, height, binpack2d.RULE_BEST_AREA_FIT)
|
|
if !ok {
|
|
unused = append(unused, img)
|
|
continue
|
|
}
|
|
uid, err := img.UID()
|
|
if err != nil {
|
|
return gallery, err
|
|
}
|
|
gallery.Images = append(gallery.Images, Image{
|
|
UID: uid,
|
|
X: rect.X,
|
|
Y: rect.Y,
|
|
Width: width,
|
|
Height: height,
|
|
})
|
|
}
|
|
imgs = unused
|
|
}
|
|
|
|
packer.ShrinkBin(false)
|
|
|
|
gallery.GridHeight = packer.GetHeight()
|
|
gallery.GridWith = packer.GetWidth()
|
|
|
|
slog.Info("serving gallery", "g", gallery)
|
|
|
|
return
|
|
}
|
|
|
|
// adjustImageSize adjusts the image size so that the aspect ratio stays the same
|
|
// but the image area is the given parameter.
|
|
func adjustImageSize(img images.Image, area int) (width, height int) {
|
|
// Calculate the original aspect ratio (W / H)
|
|
aspectRatio := float64(img.Bounds().Dx()) / float64(img.Bounds().Dy())
|
|
|
|
// Calculate new height and width using the derived formulas
|
|
newHeight := math.Sqrt(float64(area) / aspectRatio)
|
|
newWidth := newHeight * aspectRatio
|
|
|
|
// Round to the nearest integer to minimize precision loss
|
|
return int(math.Round(newWidth)), int(math.Round(newHeight))
|
|
}
|