123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- // Copyright 2016 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package iconvg
- import (
- "image/color"
- "math"
- )
- // buffer holds an encoded IconVG graphic.
- //
- // The decodeXxx methods return the decoded value and an integer n, the number
- // of bytes that value was encoded in. They return n == 0 if an error occurred.
- //
- // The encodeXxx methods append to the buffer, modifying the slice in place.
- type buffer []byte
- func (b buffer) decodeNatural() (u uint32, n int) {
- if len(b) < 1 {
- return 0, 0
- }
- x := b[0]
- if x&0x01 == 0 {
- return uint32(x) >> 1, 1
- }
- if x&0x02 == 0 {
- if len(b) >= 2 {
- y := uint16(b[0]) | uint16(b[1])<<8
- return uint32(y) >> 2, 2
- }
- return 0, 0
- }
- if len(b) >= 4 {
- y := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
- return y >> 2, 4
- }
- return 0, 0
- }
- // decodeNaturalFFV1 is like decodeNatural but for File Format Version 1. See
- // https://github.com/google/iconvg/issues/33
- func (b buffer) decodeNaturalFFV1() (u uint32, n int) {
- if len(b) < 1 {
- return 0, 0
- }
- x := b[0]
- if x&0x01 != 0 {
- return uint32(x) >> 1, 1
- }
- if x&0x02 != 0 {
- if len(b) >= 2 {
- y := uint16(b[0]) | uint16(b[1])<<8
- return uint32(y) >> 2, 2
- }
- return 0, 0
- }
- if len(b) >= 4 {
- y := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
- return y >> 2, 4
- }
- return 0, 0
- }
- func (b buffer) decodeReal() (f float32, n int) {
- switch u, n := b.decodeNatural(); n {
- case 0:
- return 0, n
- case 1:
- return float32(u), n
- case 2:
- return float32(u), n
- default:
- return math.Float32frombits(u << 2), n
- }
- }
- func (b buffer) decodeCoordinate() (f float32, n int) {
- switch u, n := b.decodeNatural(); n {
- case 0:
- return 0, n
- case 1:
- return float32(int32(u) - 64), n
- case 2:
- return float32(int32(u)-64*128) / 64, n
- default:
- return math.Float32frombits(u << 2), n
- }
- }
- func (b buffer) decodeZeroToOne() (f float32, n int) {
- switch u, n := b.decodeNatural(); n {
- case 0:
- return 0, n
- case 1:
- return float32(u) / 120, n
- case 2:
- return float32(u) / 15120, n
- default:
- return math.Float32frombits(u << 2), n
- }
- }
- func (b buffer) decodeColor1() (c Color, n int) {
- if len(b) < 1 {
- return Color{}, 0
- }
- return decodeColor1(b[0]), 1
- }
- func (b buffer) decodeColor2() (c Color, n int) {
- if len(b) < 2 {
- return Color{}, 0
- }
- return RGBAColor(color.RGBA{
- R: 0x11 * (b[0] >> 4),
- G: 0x11 * (b[0] & 0x0f),
- B: 0x11 * (b[1] >> 4),
- A: 0x11 * (b[1] & 0x0f),
- }), 2
- }
- func (b buffer) decodeColor3Direct() (c Color, n int) {
- if len(b) < 3 {
- return Color{}, 0
- }
- return RGBAColor(color.RGBA{
- R: b[0],
- G: b[1],
- B: b[2],
- A: 0xff,
- }), 3
- }
- func (b buffer) decodeColor4() (c Color, n int) {
- if len(b) < 4 {
- return Color{}, 0
- }
- return RGBAColor(color.RGBA{
- R: b[0],
- G: b[1],
- B: b[2],
- A: b[3],
- }), 4
- }
- func (b buffer) decodeColor3Indirect() (c Color, n int) {
- if len(b) < 3 {
- return Color{}, 0
- }
- return BlendColor(b[0], b[1], b[2]), 3
- }
- func (b *buffer) encodeNatural(u uint32) {
- if u < 1<<7 {
- u = (u << 1)
- *b = append(*b, uint8(u))
- return
- }
- if u < 1<<14 {
- u = (u << 2) | 1
- *b = append(*b, uint8(u), uint8(u>>8))
- return
- }
- u = (u << 2) | 3
- *b = append(*b, uint8(u), uint8(u>>8), uint8(u>>16), uint8(u>>24))
- }
- // encodeNaturalFFV1 is like encodeNatural but for File Format Version 1. See
- // https://github.com/google/iconvg/issues/33
- func (b *buffer) encodeNaturalFFV1(u uint32) {
- if u < 1<<7 {
- u = (u << 1) | 0x01
- *b = append(*b, uint8(u))
- return
- }
- if u < 1<<14 {
- u = (u << 2) | 0x02
- *b = append(*b, uint8(u), uint8(u>>8))
- return
- }
- u = (u << 2)
- *b = append(*b, uint8(u), uint8(u>>8), uint8(u>>16), uint8(u>>24))
- }
- func (b *buffer) encodeReal(f float32) int {
- if u := uint32(f); float32(u) == f && u < 1<<14 {
- if u < 1<<7 {
- u = (u << 1)
- *b = append(*b, uint8(u))
- return 1
- }
- u = (u << 2) | 1
- *b = append(*b, uint8(u), uint8(u>>8))
- return 2
- }
- b.encode4ByteReal(f)
- return 4
- }
- func (b *buffer) encode4ByteReal(f float32) {
- u := math.Float32bits(f)
- // Round the fractional bits (the low 23 bits) to the nearest multiple of
- // 4, being careful not to overflow into the upper bits.
- v := u & 0x007fffff
- if v < 0x007ffffe {
- v += 2
- }
- u = (u & 0xff800000) | v
- // A 4 byte encoding has the low two bits set.
- u |= 0x03
- *b = append(*b, uint8(u), uint8(u>>8), uint8(u>>16), uint8(u>>24))
- }
- // encode4ByteRealFFV1 is like encode4ByteReal but for File Format Version 1.
- // See https://github.com/google/iconvg/issues/33
- func (b *buffer) encode4ByteRealFFV1(f float32) {
- u := math.Float32bits(f)
- // Round the fractional bits (the low 23 bits) to the nearest multiple of
- // 4, being careful not to overflow into the upper bits.
- v := u & 0x007fffff
- if v < 0x007ffffe {
- v += 2
- }
- u = (u & 0xff800000) | v
- // A 4 byte encoding has the low two bits unset.
- u &= 0xfffffffc
- *b = append(*b, uint8(u), uint8(u>>8), uint8(u>>16), uint8(u>>24))
- }
- func (b *buffer) encodeCoordinate(f float32) int {
- if i := int32(f); -64 <= i && i < +64 && float32(i) == f {
- u := uint32(i + 64)
- u = (u << 1)
- *b = append(*b, uint8(u))
- return 1
- }
- if i := int32(f * 64); -128*64 <= i && i < +128*64 && float32(i) == f*64 {
- u := uint32(i + 128*64)
- u = (u << 2) | 1
- *b = append(*b, uint8(u), uint8(u>>8))
- return 2
- }
- b.encode4ByteReal(f)
- return 4
- }
- // encodeCoordinateFFV1 is like encodeCoordinate but for File Format Version 1.
- // See https://github.com/google/iconvg/issues/33
- func (b *buffer) encodeCoordinateFFV1(f float32) int {
- if i := int32(f); -64 <= i && i < +64 && float32(i) == f {
- u := uint32(i + 64)
- u = (u << 1) | 0x01
- *b = append(*b, uint8(u))
- return 1
- }
- if i := int32(f * 64); -128*64 <= i && i < +128*64 && float32(i) == f*64 {
- u := uint32(i + 128*64)
- u = (u << 2) | 0x02
- *b = append(*b, uint8(u), uint8(u>>8))
- return 2
- }
- b.encode4ByteRealFFV1(f)
- return 4
- }
- func (b *buffer) encodeCoordinatePairFFV1(f [2]float32) int {
- n0 := b.encodeCoordinateFFV1(f[0])
- n1 := b.encodeCoordinateFFV1(f[1])
- return n0 + n1
- }
- func (b *buffer) encodeAngle(f float32) int {
- // Normalize f to the range [0, 1).
- g := float64(f)
- g -= math.Floor(g)
- return b.encodeZeroToOne(float32(g))
- }
- func (b *buffer) encodeZeroToOne(f float32) int {
- if u := uint32(f * 15120); float32(u) == f*15120 && u < 15120 {
- if u%126 == 0 {
- u = ((u / 126) << 1)
- *b = append(*b, uint8(u))
- return 1
- }
- u = (u << 2) | 1
- *b = append(*b, uint8(u), uint8(u>>8))
- return 2
- }
- b.encode4ByteReal(f)
- return 4
- }
- func (b *buffer) encodeColor1(c Color) {
- if x, ok := encodeColor1(c); ok {
- *b = append(*b, x)
- return
- }
- // Default to opaque black.
- *b = append(*b, 0x00)
- }
- func (b *buffer) encodeColor2(c Color) {
- if x, ok := encodeColor2(c); ok {
- *b = append(*b, x[0], x[1])
- return
- }
- // Default to opaque black.
- *b = append(*b, 0x00, 0x0f)
- }
- func (b *buffer) encodeColor3Direct(c Color) {
- if x, ok := encodeColor3Direct(c); ok {
- *b = append(*b, x[0], x[1], x[2])
- return
- }
- // Default to opaque black.
- *b = append(*b, 0x00, 0x00, 0x00)
- }
- func (b *buffer) encodeColor4(c Color) {
- if x, ok := encodeColor4(c); ok {
- *b = append(*b, x[0], x[1], x[2], x[3])
- return
- }
- // Default to opaque black.
- *b = append(*b, 0x00, 0x00, 0x00, 0xff)
- }
- func (b *buffer) encodeColor3Indirect(c Color) {
- if x, ok := encodeColor3Indirect(c); ok {
- *b = append(*b, x[0], x[1], x[2])
- return
- }
- // Default to opaque black.
- *b = append(*b, 0x00, 0x00, 0x00)
- }
|