writer.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. package ico
  2. import (
  3. "bufio"
  4. "bytes"
  5. "encoding/binary"
  6. "image"
  7. "image/draw"
  8. "image/png"
  9. "io"
  10. )
  11. type icondir struct {
  12. reserved uint16 //lint:ignore U1000 in spec but not used
  13. imageType uint16
  14. numImages uint16
  15. }
  16. type icondirentry struct {
  17. imageWidth uint8
  18. imageHeight uint8
  19. numColors uint8 //lint:ignore U1000 in spec but not used
  20. reserved uint8 //lint:ignore U1000 in spec but not used
  21. colorPlanes uint16
  22. bitsPerPixel uint16
  23. sizeInBytes uint32
  24. offset uint32
  25. }
  26. func newIcondir() icondir {
  27. var id icondir
  28. id.imageType = 1
  29. id.numImages = 1
  30. return id
  31. }
  32. func newIcondirentry() icondirentry {
  33. var ide icondirentry
  34. ide.colorPlanes = 1 // windows is supposed to not mind 0 or 1, but other icon files seem to have 1 here
  35. ide.bitsPerPixel = 32 // can be 24 for bitmap or 24/32 for png. Set to 32 for now
  36. ide.offset = 22 //6 icondir + 16 icondirentry, next image will be this image size + 16 icondirentry, etc
  37. return ide
  38. }
  39. func Encode(w io.Writer, im image.Image) error {
  40. b := im.Bounds()
  41. m := image.NewRGBA(b)
  42. draw.Draw(m, b, im, b.Min, draw.Src)
  43. id := newIcondir()
  44. ide := newIcondirentry()
  45. pngbb := new(bytes.Buffer)
  46. pngwriter := bufio.NewWriter(pngbb)
  47. png.Encode(pngwriter, m)
  48. pngwriter.Flush()
  49. ide.sizeInBytes = uint32(len(pngbb.Bytes()))
  50. bounds := m.Bounds()
  51. ide.imageWidth = uint8(bounds.Dx())
  52. ide.imageHeight = uint8(bounds.Dy())
  53. bb := new(bytes.Buffer)
  54. var e error
  55. binary.Write(bb, binary.LittleEndian, id)
  56. binary.Write(bb, binary.LittleEndian, ide)
  57. w.Write(bb.Bytes())
  58. w.Write(pngbb.Bytes())
  59. return e
  60. }