package gallery import ( "context" "math" "github.com/InfinityTools/go-binpack2d" ) type Gallery struct { GridWith int GridHeight int Images []Image } type Set struct { SM Gallery LG Gallery XLG Gallery } func (s *Service) GetGallerySet(ctx context.Context) (gallerySet Set, err error) { gallerySet.SM, err = s.GetGallery(ctx, 50) if err != nil { return } gallerySet.LG, err = s.GetGallery(ctx, 80) if err != nil { return } gallerySet.XLG, err = s.GetGallery(ctx, 120) if err != nil { return } 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(width, 999999) for len(imgs) > 0 { unused := make([]Image, 0, len(imgs)) for _, img := range imgs { adjustImageSize(&img, 200) rect, ok := packer.Insert(img.Width, img.Height, binpack2d.RULE_BEST_SHORT_SIDE_FIT) if !ok { unused = append(unused, img) continue } img.X = rect.X img.Y = rect.Y gallery.Images = append(gallery.Images, img) } imgs = unused } packer.ShrinkBin(false) gallery.GridHeight = packer.GetHeight() gallery.GridWith = packer.GetWidth() 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 *Image, area int) { // Calculate the original aspect ratio (W / H) aspectRatio := float64(img.Width) / float64(img.Height) // 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 img.Width = int(math.Round(newWidth)) img.Height = int(math.Round(newHeight)) }