191 lines
5.9 KiB
Go
191 lines
5.9 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"image"
|
|
"image/png"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/nfnt/resize"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var faviconSizes = []int{16, 32, 48, 64, 72, 96, 128, 144, 152, 192, 196, 512}
|
|
var appleTouchSizes = []int{57, 60, 72, 76, 114, 120, 144, 152, 180}
|
|
var androidSizes = []int{36, 48, 72, 96, 144, 192, 196, 512}
|
|
|
|
// faviconCmd represents the favicon command
|
|
var faviconCmd = &cobra.Command{
|
|
Use: "favicon [input_image] [output_dir]",
|
|
Short: "Generate a complete favicon package from an image",
|
|
Long: `Generate a complete favicon package from a single image.
|
|
This creates all common favicon formats and sizes required for modern websites, including:
|
|
- PNG favicons in various sizes (16x16, 32x32, 48x48, etc.)
|
|
- Apple Touch Icons
|
|
- Android/PWA icons
|
|
- Web app manifest and browserconfig files
|
|
|
|
Example: dttt favicon logo.png ./favicons --name "My Awesome App" --short-name "MyApp"`,
|
|
Args: cobra.ExactArgs(2),
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
inputFile := args[0]
|
|
outputDir := args[1]
|
|
|
|
appName, _ := cmd.Flags().GetString("name")
|
|
shortName, _ := cmd.Flags().GetString("short-name")
|
|
|
|
generateFavicons(inputFile, outputDir, appName, shortName)
|
|
},
|
|
}
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(faviconCmd)
|
|
|
|
// Add flags for web manifest customization
|
|
faviconCmd.Flags().StringP("name", "n", "App", "Application name for the web manifest")
|
|
faviconCmd.Flags().StringP("short-name", "s", "App", "Short application name for the web manifest")
|
|
}
|
|
|
|
func generateFavicons(inputFile, outputDir, appName, shortName string) {
|
|
// Open and decode the input image
|
|
input, err := os.Open(inputFile)
|
|
if err != nil {
|
|
log.Fatal("Error opening input file:", err)
|
|
}
|
|
defer input.Close()
|
|
|
|
// Decode the input image
|
|
srcImg, _, err := image.Decode(input)
|
|
if err != nil {
|
|
log.Fatal("Error decoding input image:", err)
|
|
}
|
|
|
|
// Create output directory if it doesn't exist
|
|
if err := os.MkdirAll(outputDir, 0755); err != nil {
|
|
log.Fatal("Error creating output directory:", err)
|
|
}
|
|
|
|
// Generate standard favicons (PNG)
|
|
fmt.Println("Generating favicons...")
|
|
for _, size := range faviconSizes {
|
|
generateResizedPNG(srcImg, outputDir, fmt.Sprintf("favicon-%dx%d.png", size, size), size)
|
|
}
|
|
|
|
// Generate specific named favicons
|
|
generateResizedPNG(srcImg, outputDir, "favicon-16x16.png", 16)
|
|
generateResizedPNG(srcImg, outputDir, "favicon-32x32.png", 32)
|
|
generateResizedPNG(srcImg, outputDir, "favicon-48x48.png", 48)
|
|
generateResizedPNG(srcImg, outputDir, "favicon.png", 32) // Default favicon
|
|
|
|
// Generate Apple Touch Icons
|
|
fmt.Println("Generating Apple Touch Icons...")
|
|
for _, size := range appleTouchSizes {
|
|
generateResizedPNG(srcImg, outputDir, fmt.Sprintf("apple-touch-icon-%dx%d.png", size, size), size)
|
|
}
|
|
// Generate default Apple Touch Icon
|
|
generateResizedPNG(srcImg, outputDir, "apple-touch-icon.png", 180)
|
|
generateResizedPNG(srcImg, outputDir, "apple-touch-icon-precomposed.png", 180)
|
|
|
|
// Generate Android/PWA icons
|
|
fmt.Println("Generating Android/PWA icons...")
|
|
for _, size := range androidSizes {
|
|
generateResizedPNG(srcImg, outputDir, fmt.Sprintf("android-chrome-%dx%d.png", size, size), size)
|
|
}
|
|
|
|
// Generate web app manifest
|
|
fmt.Println("Generating web app manifest...")
|
|
generateWebManifest(outputDir, appName, shortName)
|
|
|
|
// Generate browserconfig
|
|
fmt.Println("Generating browserconfig...")
|
|
generateBrowserconfig(outputDir)
|
|
|
|
// Generate HTML include snippet
|
|
fmt.Println("Generating HTML include snippet...")
|
|
generateHTMLSnippet(outputDir)
|
|
|
|
fmt.Println("Note: No .ico file was generated; modern browsers support PNG favicons.")
|
|
fmt.Println("Favicon package generated successfully in", outputDir)
|
|
}
|
|
|
|
func generateResizedPNG(srcImg image.Image, outputDir, filename string, size int) {
|
|
resized := resize.Resize(uint(size), uint(size), srcImg, resize.Lanczos3)
|
|
|
|
outPath := filepath.Join(outputDir, filename)
|
|
outFile, err := os.Create(outPath)
|
|
if err != nil {
|
|
log.Printf("Error creating %s: %v", filename, err)
|
|
return
|
|
}
|
|
defer outFile.Close()
|
|
|
|
if err := png.Encode(outFile, resized); err != nil {
|
|
log.Printf("Error encoding %s: %v", filename, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func generateWebManifest(outputDir, appName, shortName string) {
|
|
manifest := fmt.Sprintf(`{
|
|
"name": "%s",
|
|
"short_name": "%s",
|
|
"icons": [
|
|
{
|
|
"src": "/android-chrome-192x192.png",
|
|
"sizes": "192x192",
|
|
"type": "image/png"
|
|
},
|
|
{
|
|
"src": "/android-chrome-512x512.png",
|
|
"sizes": "512x512",
|
|
"type": "image/png"
|
|
}
|
|
],
|
|
"theme_color": "#ffffff",
|
|
"background_color": "#ffffff",
|
|
"display": "standalone"
|
|
}`, appName, shortName)
|
|
|
|
err := os.WriteFile(filepath.Join(outputDir, "site.webmanifest"), []byte(manifest), 0644)
|
|
if err != nil {
|
|
log.Printf("Error writing site.webmanifest: %v", err)
|
|
}
|
|
}
|
|
|
|
func generateBrowserconfig(outputDir string) {
|
|
config := `<?xml version="1.0" encoding="utf-8"?>
|
|
<browserconfig>
|
|
<msapplication>
|
|
<tile>
|
|
<square70x70logo src="/favicon-72x72.png"/>
|
|
<square150x150logo src="/favicon-144x144.png"/>
|
|
<square310x310logo src="/favicon-192x192.png"/>
|
|
<TileColor>#ffffff</TileColor>
|
|
</tile>
|
|
</msapplication>
|
|
</browserconfig>`
|
|
|
|
err := os.WriteFile(filepath.Join(outputDir, "browserconfig.xml"), []byte(config), 0644)
|
|
if err != nil {
|
|
log.Printf("Error writing browserconfig.xml: %v", err)
|
|
}
|
|
}
|
|
|
|
func generateHTMLSnippet(outputDir string) {
|
|
snippet := `<!-- Favicon -->
|
|
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
|
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
|
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
|
<link rel="manifest" href="/site.webmanifest">
|
|
<meta name="msapplication-config" content="/browserconfig.xml">
|
|
<meta name="msapplication-TileColor" content="#ffffff">
|
|
<meta name="theme-color" content="#ffffff">`
|
|
|
|
err := os.WriteFile(filepath.Join(outputDir, "favicon-snippet.html"), []byte(snippet), 0644)
|
|
if err != nil {
|
|
log.Printf("Error writing favicon-snippet.html: %v", err)
|
|
}
|
|
}
|