// 把多張 PNG 打包成 Windows .ico(PNG-in-ICO 格式,Vista+ 支援) // 用法:go run gen_ico.go // 範例:go run gen_ico.go icon.ico ../ 16,24,32,48,64,96,128,256 //go:build ignore package main import ( "bytes" "encoding/binary" "fmt" "os" "path/filepath" "strconv" "strings" ) type iconDir struct { Reserved uint16 Type uint16 Count uint16 } type iconDirEntry struct { Width uint8 Height uint8 ColorCount uint8 Reserved uint8 Planes uint16 BitCount uint16 SizeBytes uint32 Offset uint32 } func main() { if len(os.Args) < 4 { fmt.Fprintln(os.Stderr, "usage: gen_ico ") os.Exit(1) } outPath := os.Args[1] pngDir := os.Args[2] sizesCSV := os.Args[3] var sizes []int for _, s := range strings.Split(sizesCSV, ",") { n, err := strconv.Atoi(strings.TrimSpace(s)) if err != nil { fmt.Fprintln(os.Stderr, "bad size:", s) os.Exit(1) } sizes = append(sizes, n) } pngs := make([][]byte, len(sizes)) for i, s := range sizes { data, err := os.ReadFile(filepath.Join(pngDir, "icon-"+strconv.Itoa(s)+".png")) if err != nil { fmt.Fprintln(os.Stderr, "read", s, err) os.Exit(1) } pngs[i] = data } var buf bytes.Buffer binary.Write(&buf, binary.LittleEndian, iconDir{Reserved: 0, Type: 1, Count: uint16(len(sizes))}) headerSize := 6 + 16*len(sizes) offset := uint32(headerSize) for i, s := range sizes { w := uint8(s) h := uint8(s) if s >= 256 { w = 0 h = 0 } entry := iconDirEntry{ Width: w, Height: h, Planes: 1, BitCount: 32, SizeBytes: uint32(len(pngs[i])), Offset: offset, } binary.Write(&buf, binary.LittleEndian, entry) offset += uint32(len(pngs[i])) } for _, p := range pngs { buf.Write(p) } if err := os.WriteFile(outPath, buf.Bytes(), 0644); err != nil { fmt.Fprintln(os.Stderr, "write", err) os.Exit(1) } fmt.Println("wrote", outPath, "containing", len(sizes), "images") }