Created
November 17, 2024 08:17
-
-
Save iDevelopThings/acb68d32558ee5980832944c69737bfb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package icons_service | |
import ( | |
"context" | |
"fmt" | |
"image" | |
"image/png" | |
"io" | |
"net/http" | |
"os" | |
"path" | |
"time" | |
"github.com/fogleman/gg" | |
"github.com/schollz/progressbar/v3" | |
"github.com/wandb/parallel" | |
"golang.org/x/image/colornames" | |
"github.com/srwiley/oksvg" | |
"github.com/srwiley/rasterx" | |
"GoogleFontsPluginApi/logger" | |
"GoogleFontsPluginApi/util" | |
) | |
func downloadAllIcons(provider *IconProvider) error { | |
fmt.Println("Downloading icons\n\n") | |
startedAt := time.Now() | |
defer func() { logger.Debug("[downloadAllIcons]: %v", time.Since(startedAt)) }() | |
bar := progressbar.Default(int64(provider.Cache.Len()), "Downloading icons") | |
ctx := context.Background() | |
group := parallel.ErrGroup(parallel.Limited(ctx, 100)) | |
for k, i := range provider.Cache.KVIterator() { | |
icon := i | |
key := k | |
group.Go(func(ctx context.Context) error { | |
defer bar.Add(1) | |
p := path.Join("data", provider.Id, "icons", key+".svg") | |
if util.FileExists(p) { | |
return nil | |
} | |
// download the file from icon.Url | |
res, err := http.Get(icon.Url) | |
if err != nil { | |
return err | |
} | |
defer res.Body.Close() | |
if res.StatusCode != http.StatusOK { | |
return fmt.Errorf("failed to download icon %s: %s", icon.Name, res.Status) | |
} | |
if err := os.MkdirAll(path.Dir(p), os.ModePerm); err != nil { | |
return err | |
} | |
f, err := os.Create(p) | |
if err != nil { | |
return err | |
} | |
defer f.Close() | |
if _, err := io.Copy(f, res.Body); err != nil { | |
return err | |
} | |
return nil | |
}) | |
} | |
return group.Wait() | |
} | |
func CreateSheet(provider *IconProvider) error { | |
// download all icons | |
if err := downloadAllIcons(provider); err != nil { | |
return err | |
} | |
const ( | |
iconSize = 64 // Default size to scale each icon to in the sprite sheet | |
numColumns = 10 // Number of columns in the sprite sheet | |
) | |
iconPaths := []string{} | |
for k, _ := range provider.Cache.KVIterator() { | |
iconPaths = append(iconPaths, path.Join("data", provider.Id, "icons", k+".svg")) | |
} | |
// Calculate the size of the sprite sheet | |
numRows := (len(iconPaths) + numColumns - 1) / numColumns | |
sheetWidth := iconSize * numColumns | |
sheetHeight := iconSize * numRows | |
// Create a new sprite sheet | |
dc := gg.NewContext(sheetWidth, sheetHeight) | |
dc.SetRGBA(0, 0, 0, 0) // Transparent background | |
dc.Clear() | |
// Draw each icon onto the sprite sheet | |
for i, iconPath := range iconPaths { | |
file, err := os.Open(iconPath) | |
if err != nil { | |
panic(err) | |
} | |
defer file.Close() | |
dc.SetHexColor("#ffffff") | |
svgIcon, err := oksvg.ReadIconStream(file) | |
if err != nil { | |
panic(err) | |
} | |
// Get the original dimensions of the SVG | |
vbWidth := svgIcon.ViewBox.W | |
vbHeight := svgIcon.ViewBox.H | |
// Calculate the scale factor to fit the icon within the iconSize while maintaining aspect ratio | |
scaleX := float64(iconSize) / vbWidth | |
scaleY := float64(iconSize) / vbHeight | |
scale := min(scaleX, scaleY) | |
// Calculate the offset to center the icon within the iconSize | |
offsetX := (float64(iconSize) - (vbWidth * scale)) / 2 | |
offsetY := (float64(iconSize) - (vbHeight * scale)) / 2 | |
// Set the target dimensions for the SVG | |
svgIcon.SetTarget(offsetX, offsetY, vbWidth*scale, vbHeight*scale) | |
img := image.NewRGBA(image.Rect(0, 0, iconSize, iconSize)) | |
// Render the SVG to a raster image | |
rgba := gg.NewContextForRGBA(img) | |
raster := rasterx.NewDasher( | |
iconSize, | |
iconSize, | |
rasterx.NewScannerGV(iconSize, iconSize, img, img.Bounds()), | |
) | |
raster.SetColor(colornames.White) | |
for idx, svgp := range svgIcon.SVGPaths { | |
// svgp.SetLineColor(colornames.White) | |
svgp.SetFillColor(colornames.White) | |
svgIcon.SVGPaths[idx] = svgp | |
} | |
svgIcon.Draw(raster, 1.0) | |
col := i % numColumns | |
row := i / numColumns | |
x := float64(col * iconSize) | |
y := float64(row * iconSize) | |
dc.DrawImage(rgba.Image(), int(x), int(y)) | |
} | |
// Save the sprite sheet to a file | |
outFile, err := os.Create("sprite_sheet.png") | |
if err != nil { | |
panic(err) | |
} | |
defer outFile.Close() | |
err = png.Encode(outFile, dc.Image()) | |
if err != nil { | |
panic(err) | |
} | |
// create sprite sheet | |
return nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment