go-ico
| Language | Go |
|---|---|
| License | BSD 3-Clause |
| Repository | github.com/sergeymakinen/go-ico |
| Documentation | pkg.go.dev, cur subpackage |
| Depends on | github.com/sergeymakinen/go-bmp |
| Read / write | yes / yes, BMP and PNG entries, CUR read and write |
go-ico follows the style of the standard library’s image codecs: Decode returns the largest icon as an image.Image, DecodeAll returns every entry and DecodeConfig reads the size without decoding pixels. Importing the package registers the ico format, so image.Decode recognizes .ico files too.
Encode and EncodeAll write one or more images. 256x256 images are stored as 32-bit PNG and smaller ones as BMP, the layout Windows expects; images larger than 256x256 are rejected. The cur subpackage does the same for cursors and returns hotspots from DecodeAll.
Installation#
Shell
go get github.com/sergeymakinen/go-ico
Basic usage: convert ICO to PNG#
Go
package main
import (
"image/png"
"log"
"os"
"github.com/sergeymakinen/go-ico"
)
func main() {
f, err := os.Open("app.ico")
if err != nil {
log.Fatal(err)
}
defer f.Close()
img, err := ico.Decode(f) // the largest entry
if err != nil {
log.Fatal(err)
}
out, err := os.Create("app.png")
if err != nil {
log.Fatal(err)
}
defer out.Close()
if err := png.Encode(out, img); err != nil {
log.Fatal(err)
}
}
How to read every size in an ICO file#
Go
f, err := os.Open("app.ico")
if err != nil {
log.Fatal(err)
}
defer f.Close()
images, err := ico.DecodeAll(f)
if err != nil {
log.Fatal(err)
}
for i, img := range images {
b := img.Bounds()
fmt.Printf("%d: %d x %d\n", i, b.Dx(), b.Dy())
}
How to get the icon size without decoding#
Go
cfg, err := ico.DecodeConfig(f) // size of the largest entry
if err != nil {
log.Fatal(err)
}
fmt.Println(cfg.Width, cfg.Height)
How to create a multi-size ICO from PNG files#
Go
package main
import (
"image"
"image/png"
"log"
"os"
"github.com/sergeymakinen/go-ico"
)
func load(name string) image.Image {
f, err := os.Open(name)
if err != nil {
log.Fatal(err)
}
defer f.Close()
img, err := png.Decode(f)
if err != nil {
log.Fatal(err)
}
return img
}
func main() {
var images []image.Image
for _, name := range []string{"icon16.png", "icon32.png", "icon48.png", "icon256.png"} {
images = append(images, load(name))
}
out, err := os.Create("app.ico")
if err != nil {
log.Fatal(err)
}
defer out.Close()
if err := ico.EncodeAll(out, images); err != nil {
log.Fatal(err)
}
}
To resize one large image to each size first, use golang.org/x/image/draw (draw.CatmullRom.Scale).
How to read a cursor and its hotspot#
Go
import "github.com/sergeymakinen/go-ico/cur"
f, err := os.Open("pointer.cur")
if err != nil {
log.Fatal(err)
}
defer f.Close()
c, err := cur.DecodeAll(f)
if err != nil {
log.Fatal(err)
}
for i, img := range c.Cursor {
fmt.Printf("%v, hotspot %d,%d\n", img.Bounds().Size(), c.Hotspot[i].X, c.Hotspot[i].Y)
}
cur.Encode and cur.EncodeAll write cursors with the hotspot at 0,0.
Tips#
- With a blank import (
import _ "github.com/sergeymakinen/go-ico"),image.Decodeandimage.DecodeConfighandle ICO files alongside PNG, JPEG and GIF. - Errors are
ico.FormatError(not a valid ICO) orico.UnsupportedError(valid but uses a feature the package doesn’t implement).