1
0

ico.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package vips
  2. /*
  3. #include "vips.h"
  4. */
  5. import "C"
  6. import (
  7. "bytes"
  8. "encoding/binary"
  9. "errors"
  10. "fmt"
  11. "unsafe"
  12. "github.com/imgproxy/imgproxy/v3/imagedata"
  13. "github.com/imgproxy/imgproxy/v3/imagemeta"
  14. "github.com/imgproxy/imgproxy/v3/imagetype"
  15. )
  16. func (img *Image) loadIco(data []byte, shrink int, scale float64, pages int) error {
  17. icoMeta, err := imagemeta.DecodeIcoMeta(bytes.NewReader(data))
  18. if err != nil {
  19. return err
  20. }
  21. offset := icoMeta.BestImageOffset()
  22. size := icoMeta.BestImageSize()
  23. internalData := data[offset : offset+size]
  24. var internalType imagetype.Type
  25. meta, err := imagemeta.DecodeMeta(bytes.NewReader(internalData))
  26. if err != nil {
  27. // Looks like it's BMP with an incomplete header
  28. if d, err := imagemeta.FixBmpHeader(internalData); err == nil {
  29. internalType = imagetype.BMP
  30. internalData = d
  31. } else {
  32. return err
  33. }
  34. } else {
  35. internalType = meta.Format()
  36. }
  37. if internalType == imagetype.ICO || !SupportsLoad(internalType) {
  38. return fmt.Errorf("Can't load %s from ICO", internalType)
  39. }
  40. imgdata := imagedata.ImageData{
  41. Type: internalType,
  42. Data: internalData,
  43. }
  44. return img.Load(&imgdata, shrink, scale, pages)
  45. }
  46. func (img *Image) saveAsIco() (*imagedata.ImageData, error) {
  47. if img.Width() > 256 || img.Height() > 256 {
  48. return nil, errors.New("Image dimensions is too big. Max dimension size for ICO is 256")
  49. }
  50. var ptr unsafe.Pointer
  51. imgsize := C.size_t(0)
  52. defer func() {
  53. C.g_free_go(&ptr)
  54. }()
  55. if C.vips_pngsave_go(img.VipsImage, &ptr, &imgsize, 0, 0, 256) != 0 {
  56. return nil, Error()
  57. }
  58. b := ptrToBytes(ptr, int(imgsize))
  59. buf := new(bytes.Buffer)
  60. buf.Grow(22 + int(imgsize))
  61. // ICONDIR header
  62. if _, err := buf.Write([]byte{0, 0, 1, 0, 1, 0}); err != nil {
  63. return nil, err
  64. }
  65. // ICONDIRENTRY
  66. if _, err := buf.Write([]byte{
  67. byte(img.Width() % 256),
  68. byte(img.Height() % 256),
  69. }); err != nil {
  70. return nil, err
  71. }
  72. // Number of colors. Not supported in our case
  73. if err := buf.WriteByte(0); err != nil {
  74. return nil, err
  75. }
  76. // Reserved
  77. if err := buf.WriteByte(0); err != nil {
  78. return nil, err
  79. }
  80. // Color planes. Always 1 in our case
  81. if _, err := buf.Write([]byte{1, 0}); err != nil {
  82. return nil, err
  83. }
  84. // Bits per pixel
  85. if img.HasAlpha() {
  86. if _, err := buf.Write([]byte{32, 0}); err != nil {
  87. return nil, err
  88. }
  89. } else {
  90. if _, err := buf.Write([]byte{24, 0}); err != nil {
  91. return nil, err
  92. }
  93. }
  94. // Image data size
  95. if err := binary.Write(buf, binary.LittleEndian, uint32(imgsize)); err != nil {
  96. return nil, err
  97. }
  98. // Image data offset. Always 22 in our case
  99. if _, err := buf.Write([]byte{22, 0, 0, 0}); err != nil {
  100. return nil, err
  101. }
  102. if _, err := buf.Write(b); err != nil {
  103. return nil, err
  104. }
  105. imgdata := imagedata.ImageData{
  106. Type: imagetype.ICO,
  107. Data: buf.Bytes(),
  108. }
  109. return &imgdata, nil
  110. }