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)) }