ico.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. package imagemeta
  2. import (
  3. "encoding/binary"
  4. "io"
  5. "github.com/imgproxy/imgproxy/v3/imagetype"
  6. )
  7. type IcoMeta struct {
  8. Meta
  9. offset int
  10. size int
  11. }
  12. func (m *IcoMeta) BestImageOffset() int {
  13. return m.offset
  14. }
  15. func (m *IcoMeta) BestImageSize() int {
  16. return m.size
  17. }
  18. func icoBestSize(r io.Reader) (width, height byte, offset uint32, size uint32, err error) {
  19. var tmp [16]byte
  20. if _, err = io.ReadFull(r, tmp[:6]); err != nil {
  21. return
  22. }
  23. count := binary.LittleEndian.Uint16(tmp[4:6])
  24. for i := uint16(0); i < count; i++ {
  25. if _, err = io.ReadFull(r, tmp[:]); err != nil {
  26. return
  27. }
  28. if tmp[0] > width || tmp[1] > height || tmp[0] == 0 || tmp[1] == 0 {
  29. width = tmp[0]
  30. height = tmp[1]
  31. size = binary.LittleEndian.Uint32(tmp[8:12])
  32. offset = binary.LittleEndian.Uint32(tmp[12:16])
  33. }
  34. }
  35. return
  36. }
  37. func BestIcoPage(r io.Reader) (int, int, error) {
  38. _, _, offset, size, err := icoBestSize(r)
  39. return int(offset), int(size), err
  40. }
  41. func DecodeIcoMeta(r io.Reader) (*IcoMeta, error) {
  42. bwidth, bheight, offset, size, err := icoBestSize(r)
  43. if err != nil {
  44. return nil, err
  45. }
  46. width := int(bwidth)
  47. height := int(bheight)
  48. if width == 0 {
  49. width = 256
  50. }
  51. if height == 0 {
  52. height = 256
  53. }
  54. return &IcoMeta{
  55. Meta: &meta{
  56. format: imagetype.ICO,
  57. width: width,
  58. height: height,
  59. },
  60. offset: int(offset),
  61. size: int(size),
  62. }, nil
  63. }
  64. func init() {
  65. RegisterFormat(
  66. "\x00\x00\x01\x00",
  67. func(r io.Reader) (Meta, error) { return DecodeIcoMeta(r) },
  68. )
  69. }