buffer.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. // Copyright 2016 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package iconvg
  5. import (
  6. "image/color"
  7. "math"
  8. )
  9. // buffer holds an encoded IconVG graphic.
  10. //
  11. // The decodeXxx methods return the decoded value and an integer n, the number
  12. // of bytes that value was encoded in. They return n == 0 if an error occurred.
  13. //
  14. // The encodeXxx methods append to the buffer, modifying the slice in place.
  15. type buffer []byte
  16. func (b buffer) decodeNatural() (u uint32, n int) {
  17. if len(b) < 1 {
  18. return 0, 0
  19. }
  20. x := b[0]
  21. if x&0x01 == 0 {
  22. return uint32(x) >> 1, 1
  23. }
  24. if x&0x02 == 0 {
  25. if len(b) >= 2 {
  26. y := uint16(b[0]) | uint16(b[1])<<8
  27. return uint32(y) >> 2, 2
  28. }
  29. return 0, 0
  30. }
  31. if len(b) >= 4 {
  32. y := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
  33. return y >> 2, 4
  34. }
  35. return 0, 0
  36. }
  37. // decodeNaturalFFV1 is like decodeNatural but for File Format Version 1. See
  38. // https://github.com/google/iconvg/issues/33
  39. func (b buffer) decodeNaturalFFV1() (u uint32, n int) {
  40. if len(b) < 1 {
  41. return 0, 0
  42. }
  43. x := b[0]
  44. if x&0x01 != 0 {
  45. return uint32(x) >> 1, 1
  46. }
  47. if x&0x02 != 0 {
  48. if len(b) >= 2 {
  49. y := uint16(b[0]) | uint16(b[1])<<8
  50. return uint32(y) >> 2, 2
  51. }
  52. return 0, 0
  53. }
  54. if len(b) >= 4 {
  55. y := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
  56. return y >> 2, 4
  57. }
  58. return 0, 0
  59. }
  60. func (b buffer) decodeReal() (f float32, n int) {
  61. switch u, n := b.decodeNatural(); n {
  62. case 0:
  63. return 0, n
  64. case 1:
  65. return float32(u), n
  66. case 2:
  67. return float32(u), n
  68. default:
  69. return math.Float32frombits(u << 2), n
  70. }
  71. }
  72. func (b buffer) decodeCoordinate() (f float32, n int) {
  73. switch u, n := b.decodeNatural(); n {
  74. case 0:
  75. return 0, n
  76. case 1:
  77. return float32(int32(u) - 64), n
  78. case 2:
  79. return float32(int32(u)-64*128) / 64, n
  80. default:
  81. return math.Float32frombits(u << 2), n
  82. }
  83. }
  84. func (b buffer) decodeZeroToOne() (f float32, n int) {
  85. switch u, n := b.decodeNatural(); n {
  86. case 0:
  87. return 0, n
  88. case 1:
  89. return float32(u) / 120, n
  90. case 2:
  91. return float32(u) / 15120, n
  92. default:
  93. return math.Float32frombits(u << 2), n
  94. }
  95. }
  96. func (b buffer) decodeColor1() (c Color, n int) {
  97. if len(b) < 1 {
  98. return Color{}, 0
  99. }
  100. return decodeColor1(b[0]), 1
  101. }
  102. func (b buffer) decodeColor2() (c Color, n int) {
  103. if len(b) < 2 {
  104. return Color{}, 0
  105. }
  106. return RGBAColor(color.RGBA{
  107. R: 0x11 * (b[0] >> 4),
  108. G: 0x11 * (b[0] & 0x0f),
  109. B: 0x11 * (b[1] >> 4),
  110. A: 0x11 * (b[1] & 0x0f),
  111. }), 2
  112. }
  113. func (b buffer) decodeColor3Direct() (c Color, n int) {
  114. if len(b) < 3 {
  115. return Color{}, 0
  116. }
  117. return RGBAColor(color.RGBA{
  118. R: b[0],
  119. G: b[1],
  120. B: b[2],
  121. A: 0xff,
  122. }), 3
  123. }
  124. func (b buffer) decodeColor4() (c Color, n int) {
  125. if len(b) < 4 {
  126. return Color{}, 0
  127. }
  128. return RGBAColor(color.RGBA{
  129. R: b[0],
  130. G: b[1],
  131. B: b[2],
  132. A: b[3],
  133. }), 4
  134. }
  135. func (b buffer) decodeColor3Indirect() (c Color, n int) {
  136. if len(b) < 3 {
  137. return Color{}, 0
  138. }
  139. return BlendColor(b[0], b[1], b[2]), 3
  140. }
  141. func (b *buffer) encodeNatural(u uint32) {
  142. if u < 1<<7 {
  143. u = (u << 1)
  144. *b = append(*b, uint8(u))
  145. return
  146. }
  147. if u < 1<<14 {
  148. u = (u << 2) | 1
  149. *b = append(*b, uint8(u), uint8(u>>8))
  150. return
  151. }
  152. u = (u << 2) | 3
  153. *b = append(*b, uint8(u), uint8(u>>8), uint8(u>>16), uint8(u>>24))
  154. }
  155. // encodeNaturalFFV1 is like encodeNatural but for File Format Version 1. See
  156. // https://github.com/google/iconvg/issues/33
  157. func (b *buffer) encodeNaturalFFV1(u uint32) {
  158. if u < 1<<7 {
  159. u = (u << 1) | 0x01
  160. *b = append(*b, uint8(u))
  161. return
  162. }
  163. if u < 1<<14 {
  164. u = (u << 2) | 0x02
  165. *b = append(*b, uint8(u), uint8(u>>8))
  166. return
  167. }
  168. u = (u << 2)
  169. *b = append(*b, uint8(u), uint8(u>>8), uint8(u>>16), uint8(u>>24))
  170. }
  171. func (b *buffer) encodeReal(f float32) int {
  172. if u := uint32(f); float32(u) == f && u < 1<<14 {
  173. if u < 1<<7 {
  174. u = (u << 1)
  175. *b = append(*b, uint8(u))
  176. return 1
  177. }
  178. u = (u << 2) | 1
  179. *b = append(*b, uint8(u), uint8(u>>8))
  180. return 2
  181. }
  182. b.encode4ByteReal(f)
  183. return 4
  184. }
  185. func (b *buffer) encode4ByteReal(f float32) {
  186. u := math.Float32bits(f)
  187. // Round the fractional bits (the low 23 bits) to the nearest multiple of
  188. // 4, being careful not to overflow into the upper bits.
  189. v := u & 0x007fffff
  190. if v < 0x007ffffe {
  191. v += 2
  192. }
  193. u = (u & 0xff800000) | v
  194. // A 4 byte encoding has the low two bits set.
  195. u |= 0x03
  196. *b = append(*b, uint8(u), uint8(u>>8), uint8(u>>16), uint8(u>>24))
  197. }
  198. // encode4ByteRealFFV1 is like encode4ByteReal but for File Format Version 1.
  199. // See https://github.com/google/iconvg/issues/33
  200. func (b *buffer) encode4ByteRealFFV1(f float32) {
  201. u := math.Float32bits(f)
  202. // Round the fractional bits (the low 23 bits) to the nearest multiple of
  203. // 4, being careful not to overflow into the upper bits.
  204. v := u & 0x007fffff
  205. if v < 0x007ffffe {
  206. v += 2
  207. }
  208. u = (u & 0xff800000) | v
  209. // A 4 byte encoding has the low two bits unset.
  210. u &= 0xfffffffc
  211. *b = append(*b, uint8(u), uint8(u>>8), uint8(u>>16), uint8(u>>24))
  212. }
  213. func (b *buffer) encodeCoordinate(f float32) int {
  214. if i := int32(f); -64 <= i && i < +64 && float32(i) == f {
  215. u := uint32(i + 64)
  216. u = (u << 1)
  217. *b = append(*b, uint8(u))
  218. return 1
  219. }
  220. if i := int32(f * 64); -128*64 <= i && i < +128*64 && float32(i) == f*64 {
  221. u := uint32(i + 128*64)
  222. u = (u << 2) | 1
  223. *b = append(*b, uint8(u), uint8(u>>8))
  224. return 2
  225. }
  226. b.encode4ByteReal(f)
  227. return 4
  228. }
  229. // encodeCoordinateFFV1 is like encodeCoordinate but for File Format Version 1.
  230. // See https://github.com/google/iconvg/issues/33
  231. func (b *buffer) encodeCoordinateFFV1(f float32) int {
  232. if i := int32(f); -64 <= i && i < +64 && float32(i) == f {
  233. u := uint32(i + 64)
  234. u = (u << 1) | 0x01
  235. *b = append(*b, uint8(u))
  236. return 1
  237. }
  238. if i := int32(f * 64); -128*64 <= i && i < +128*64 && float32(i) == f*64 {
  239. u := uint32(i + 128*64)
  240. u = (u << 2) | 0x02
  241. *b = append(*b, uint8(u), uint8(u>>8))
  242. return 2
  243. }
  244. b.encode4ByteRealFFV1(f)
  245. return 4
  246. }
  247. func (b *buffer) encodeCoordinatePairFFV1(f [2]float32) int {
  248. n0 := b.encodeCoordinateFFV1(f[0])
  249. n1 := b.encodeCoordinateFFV1(f[1])
  250. return n0 + n1
  251. }
  252. func (b *buffer) encodeAngle(f float32) int {
  253. // Normalize f to the range [0, 1).
  254. g := float64(f)
  255. g -= math.Floor(g)
  256. return b.encodeZeroToOne(float32(g))
  257. }
  258. func (b *buffer) encodeZeroToOne(f float32) int {
  259. if u := uint32(f * 15120); float32(u) == f*15120 && u < 15120 {
  260. if u%126 == 0 {
  261. u = ((u / 126) << 1)
  262. *b = append(*b, uint8(u))
  263. return 1
  264. }
  265. u = (u << 2) | 1
  266. *b = append(*b, uint8(u), uint8(u>>8))
  267. return 2
  268. }
  269. b.encode4ByteReal(f)
  270. return 4
  271. }
  272. func (b *buffer) encodeColor1(c Color) {
  273. if x, ok := encodeColor1(c); ok {
  274. *b = append(*b, x)
  275. return
  276. }
  277. // Default to opaque black.
  278. *b = append(*b, 0x00)
  279. }
  280. func (b *buffer) encodeColor2(c Color) {
  281. if x, ok := encodeColor2(c); ok {
  282. *b = append(*b, x[0], x[1])
  283. return
  284. }
  285. // Default to opaque black.
  286. *b = append(*b, 0x00, 0x0f)
  287. }
  288. func (b *buffer) encodeColor3Direct(c Color) {
  289. if x, ok := encodeColor3Direct(c); ok {
  290. *b = append(*b, x[0], x[1], x[2])
  291. return
  292. }
  293. // Default to opaque black.
  294. *b = append(*b, 0x00, 0x00, 0x00)
  295. }
  296. func (b *buffer) encodeColor4(c Color) {
  297. if x, ok := encodeColor4(c); ok {
  298. *b = append(*b, x[0], x[1], x[2], x[3])
  299. return
  300. }
  301. // Default to opaque black.
  302. *b = append(*b, 0x00, 0x00, 0x00, 0xff)
  303. }
  304. func (b *buffer) encodeColor3Indirect(c Color) {
  305. if x, ok := encodeColor3Indirect(c); ok {
  306. *b = append(*b, x[0], x[1], x[2])
  307. return
  308. }
  309. // Default to opaque black.
  310. *b = append(*b, 0x00, 0x00, 0x00)
  311. }