forked from tangled.org/core
Monorepo for Tangled — https://tangled.org
at master 1.9 kB view raw
1package ico 2 3import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "image" 8 "image/png" 9) 10 11type IconDir struct { 12 Reserved uint16 // must be 0 13 Type uint16 // 1 for ICO, 2 for CUR 14 Count uint16 // number of images 15} 16 17type IconDirEntry struct { 18 Width uint8 // 0 means 256 19 Height uint8 // 0 means 256 20 ColorCount uint8 21 Reserved uint8 // must be 0 22 ColorPlanes uint16 // 0 or 1 23 BitsPerPixel uint16 24 SizeInBytes uint32 25 Offset uint32 26} 27 28func ImageToIco(img image.Image) ([]byte, error) { 29 // encode image as png 30 var pngBuf bytes.Buffer 31 if err := png.Encode(&pngBuf, img); err != nil { 32 return nil, fmt.Errorf("failed to encode PNG: %w", err) 33 } 34 pngData := pngBuf.Bytes() 35 36 // get image dimensions 37 bounds := img.Bounds() 38 width := bounds.Dx() 39 height := bounds.Dy() 40 41 // prepare output buffer 42 var icoBuf bytes.Buffer 43 44 iconDir := IconDir{ 45 Reserved: 0, 46 Type: 1, // ICO format 47 Count: 1, // One image 48 } 49 50 w := uint8(width) 51 h := uint8(height) 52 53 // width/height of 256 should be stored as 0 54 if width == 256 { 55 w = 0 56 } 57 if height == 256 { 58 h = 0 59 } 60 61 iconDirEntry := IconDirEntry{ 62 Width: w, 63 Height: h, 64 ColorCount: 0, // 0 for PNG (32-bit) 65 Reserved: 0, 66 ColorPlanes: 1, 67 BitsPerPixel: 32, // PNG with alpha 68 SizeInBytes: uint32(len(pngData)), 69 Offset: 6 + 16, // Size of ICONDIR + ICONDIRENTRY 70 } 71 72 // write IconDir 73 if err := binary.Write(&icoBuf, binary.LittleEndian, iconDir); err != nil { 74 return nil, fmt.Errorf("failed to write ICONDIR: %w", err) 75 } 76 77 // write IconDirEntry 78 if err := binary.Write(&icoBuf, binary.LittleEndian, iconDirEntry); err != nil { 79 return nil, fmt.Errorf("failed to write ICONDIRENTRY: %w", err) 80 } 81 82 // write PNG data directly 83 if _, err := icoBuf.Write(pngData); err != nil { 84 return nil, fmt.Errorf("failed to write PNG data: %w", err) 85 } 86 87 return icoBuf.Bytes(), nil 88}