feat(gallery): packing

This commit is contained in:
2026-05-31 15:48:18 +02:00
parent 9282f1f634
commit 8a72b96e66
12 changed files with 126 additions and 19 deletions
+74 -2
View File
@@ -3,11 +3,27 @@ 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 {
@@ -17,11 +33,67 @@ func (s *Service) GetImages(ctx context.Context) (imgs []images.Image, err error
for _, file := range files {
imagePath := path.Join(s.cfg.Path, file.Name())
img, err := s.img.GetImage(imagePath)
if err != nil {
slog.Warn("can not read image in gallery", "path", imagePath, "err", err)
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))
}