Initial commit.
This commit is contained in:
commit
2b41abb11b
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 smariot
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
36
README.md
Normal file
36
README.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# Golang FFMPEG Animation Package
|
||||||
|
|
||||||
|
This package creates an image that can be drawn on, and provides an `EmitFrame()` method to pipe the image to [FFMPEG](https://ffmpeg.org/), and a `Close()` method to finish the animation.
|
||||||
|
|
||||||
|
The process of actually drawing frames of animation is left as an exercise for the reader.
|
||||||
|
|
||||||
|
The extension of the destination file determines the encoding format and parameters:
|
||||||
|
|
||||||
|
- `.gif`: Creates a looping indexed GIF animation.
|
||||||
|
|
||||||
|
Generating an optimal palette would require buffering the entire animation, so instead a fixed general purpose palette is used.
|
||||||
|
- `.png`/`.apng`: Creates a looping animated PNG image. Lossless and supports transparency.
|
||||||
|
|
||||||
|
This is the only supported format that is both completely lossless and supports transparency.
|
||||||
|
- `.mp4`: Creates an MP4 video using the `libx264rgb` codec with the `ultrafast` preset. Should be lossless, but doesn't support transparency.
|
||||||
|
|
||||||
|
The file will be quite large, and probably isn't something you'd want to distribute directly.
|
||||||
|
- `.mkv`: Identical to MP4, except with a Matroska container.
|
||||||
|
- `.webp`: Creates a looping WEBP animation. The RGB->YUV conversion is lossy, but is otherwise lossless and supports transparency.
|
||||||
|
- `.webm`: Creates a WEBM video. The RGB->YUV conversion is lossy, but is otherwise lossless and supports transparency.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get smariot.com/animate
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
You can find the documentation at https://pkg.go.dev/smariot.com/animate.
|
||||||
|
|
||||||
|
## Demo
|
||||||
|
|
||||||
|
The `cmd/demo` directory contains a simple program to demonstrate this package by generating the following image:
|
||||||
|
|
||||||
|

|
290
animate.go
Normal file
290
animate.go
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
// This package enables creating simple animations by drawing onto an image, using ffmpeg which could be in the system path.
|
||||||
|
|
||||||
|
package animate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmp"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"image/png"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Animation implements the [draw.Image] interface; you can draw to it and then invoke [EmitFrame].
|
||||||
|
//
|
||||||
|
// That said, some implementations might be optimized for known image types, in which case, passing a pointer to the
|
||||||
|
// [NRGBA] field might be more efficient.
|
||||||
|
type Animation struct {
|
||||||
|
image.NRGBA
|
||||||
|
|
||||||
|
// the first error where we encountered during writing
|
||||||
|
err error
|
||||||
|
|
||||||
|
// the pipe to ffmpeg's stdin, nil if the animation is closed
|
||||||
|
w io.WriteCloser
|
||||||
|
|
||||||
|
// the ffmpeg process, only applicable if w above is not nil
|
||||||
|
c *exec.Cmd
|
||||||
|
|
||||||
|
// the name of the file we're writing to,
|
||||||
|
// and where we'll move it to if nothing explodes
|
||||||
|
tmp, out string
|
||||||
|
|
||||||
|
// framerate
|
||||||
|
rate float64
|
||||||
|
|
||||||
|
// the current frame number
|
||||||
|
frame int
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmitFrame writes the image as it presently appears as a frame to the animation.
|
||||||
|
//
|
||||||
|
// If this is successful, then the frame counter is advanced. The frame buffer isn't cleared.
|
||||||
|
func (a *Animation) EmitFrame() error {
|
||||||
|
// if we've already encountered an error, return it
|
||||||
|
if a.err != nil {
|
||||||
|
return a.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the pipe is closed, then we can't write, obviously.
|
||||||
|
if a.w == nil {
|
||||||
|
return os.ErrClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to write the frame to the pipe,
|
||||||
|
// if if that fails, record the error and close the animation.
|
||||||
|
if _, err := a.w.Write(a.Pix); err != nil {
|
||||||
|
a.err = err
|
||||||
|
return a.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
a.frame++
|
||||||
|
|
||||||
|
// success!
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frame returns the current frame number, with the first frame being 0.
|
||||||
|
func (a *Animation) Frame() int {
|
||||||
|
return a.frame
|
||||||
|
}
|
||||||
|
|
||||||
|
// Elapsed returns the timestamp for the current frame, with first frame having a timestamp of 0.
|
||||||
|
func (a *Animation) Elapsed() time.Duration {
|
||||||
|
return time.Duration(float64(a.frame) * float64(time.Second) / a.rate)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close finishes writing the animation, and cleans up any resources.
|
||||||
|
func (a *Animation) Close() error {
|
||||||
|
// the pipe is open, shut everything down.
|
||||||
|
if a.w != nil {
|
||||||
|
// no longer needs to be finalized
|
||||||
|
runtime.SetFinalizer(a, nil)
|
||||||
|
|
||||||
|
// close the pipe and wait for ffmpeg to finish,
|
||||||
|
// setting a.err to the first error encountered.
|
||||||
|
a.err = cmp.Or(a.err, a.w.Close(), a.c.Wait())
|
||||||
|
a.w, a.c = nil, nil
|
||||||
|
|
||||||
|
// if there are no errors so far, attempt to move the file to the destination.
|
||||||
|
if a.err == nil {
|
||||||
|
a.err = os.Rename(a.tmp, a.out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there was an error, delete the temporary file we wrote.
|
||||||
|
if a.err != nil {
|
||||||
|
os.Remove(a.tmp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return any error we may have encountered.
|
||||||
|
return a.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func paletteToFile(palette color.Palette) (*os.File, error) {
|
||||||
|
r, w, err := os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer w.Close()
|
||||||
|
|
||||||
|
img := image.NewPaletted(image.Rect(0, 0, 16, 16), palette)
|
||||||
|
|
||||||
|
for i := 0; i < 256; i++ {
|
||||||
|
img.Pix[i] = uint8(min(i, len(palette)-1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// I'm not going to bother dealing with possible write errors,
|
||||||
|
// those would be because ffmpeg terminated unexpectedly,
|
||||||
|
// and has nothing to do with us.
|
||||||
|
png.Encode(w, img)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func finalize(a *Animation) {
|
||||||
|
err := a.Close()
|
||||||
|
log.Printf("animation was finalized without being closed; err=%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func new(r image.Rectangle, rate float64, palette color.Palette, out string, fmtArgs []string) (a *Animation, err error) {
|
||||||
|
tmp, err := os.CreateTemp(filepath.Dir(out), "."+strings.TrimSuffix(filepath.Base(out), filepath.Ext(out))+"*.tmp")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
// if things go wrong, delete the file we wrote.
|
||||||
|
if err != nil {
|
||||||
|
os.Remove(tmp.Name())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// we don't need the file open, we just want a safe place for ffmpeg to write to.
|
||||||
|
if err := tmp.Close(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var args []string
|
||||||
|
|
||||||
|
args = append(args,
|
||||||
|
"-hide_banner",
|
||||||
|
"-loglevel", "error",
|
||||||
|
"-f", "rawvideo",
|
||||||
|
"-pixel_format", "rgba",
|
||||||
|
"-video_size", fmt.Sprintf("%dx%d", r.Dx(), r.Dy()),
|
||||||
|
"-framerate", fmt.Sprint(rate),
|
||||||
|
"-i", "pipe:0",
|
||||||
|
)
|
||||||
|
|
||||||
|
var extraFiles []*os.File
|
||||||
|
|
||||||
|
if palette != nil {
|
||||||
|
f, err := paletteToFile(palette)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
args = append(args,
|
||||||
|
"-i", fmt.Sprintf("pipe:%d", len(extraFiles)+3),
|
||||||
|
"-filter_complex", "[0:v][1:v]paletteuse=dither=bayer",
|
||||||
|
)
|
||||||
|
|
||||||
|
extraFiles = append(extraFiles, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
args = append(args, fmtArgs...)
|
||||||
|
|
||||||
|
args = append(args, "-y", "file:"+tmp.Name())
|
||||||
|
|
||||||
|
cmd := exec.Command("ffmpeg", args...)
|
||||||
|
|
||||||
|
cmd.ExtraFiles = extraFiles
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
|
||||||
|
w, err := cmd.StdinPipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cmd.Start()
|
||||||
|
|
||||||
|
// close our copies of the file descriptors. The ffmpeg process, if it even started, has inherited them.
|
||||||
|
// and if it didn't, we'd needed to close them ourselves.
|
||||||
|
for _, f := range extraFiles {
|
||||||
|
f.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
animation := &Animation{
|
||||||
|
NRGBA: image.NRGBA{
|
||||||
|
Pix: make([]uint8, r.Dx()*r.Dy()*4),
|
||||||
|
Stride: r.Dx() * 4,
|
||||||
|
Rect: r,
|
||||||
|
},
|
||||||
|
w: w,
|
||||||
|
c: cmd,
|
||||||
|
tmp: tmp.Name(),
|
||||||
|
out: out,
|
||||||
|
rate: rate,
|
||||||
|
frame: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
// failing to close the animation will leave temporary files on the filesystem, possibly leave the ffmpeg process hanging,
|
||||||
|
// so let's try not to let that happen.
|
||||||
|
runtime.SetFinalizer(animation, finalize)
|
||||||
|
|
||||||
|
return animation, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// New begins a new animation at the given size and frame rate, to be written to the specified output file.
|
||||||
|
//
|
||||||
|
// The output filename must have one of the following extensions:
|
||||||
|
// - .gif (lossy, uses a default fixed palette)
|
||||||
|
// - .png / .apng (lossless)
|
||||||
|
// - .mp4 (lossless RGB, doesn't support transparency)
|
||||||
|
// - .mkv (lossless RGB, doesn't support transparency)
|
||||||
|
// - .webp (lossy YUV colorspace conversion, alpha supported)
|
||||||
|
// - .webm (lossy YUV colorspace conversion, alpha supported)
|
||||||
|
//
|
||||||
|
// Note that the output file won't be created immediately, the animation will be written to a temporary file and then renamed
|
||||||
|
// by the [Close] method if no errors are encountered.
|
||||||
|
func New(r image.Rectangle, rate float64, out string) (*Animation, error) {
|
||||||
|
switch ext := filepath.Ext(out); ext {
|
||||||
|
case ".gif":
|
||||||
|
return new(r, rate, defaultPalette, out, []string{
|
||||||
|
"-loop", "0",
|
||||||
|
"-f", "gif",
|
||||||
|
})
|
||||||
|
case ".png", ".apng":
|
||||||
|
return new(r, rate, nil, out, []string{
|
||||||
|
"-vcodec", "apng",
|
||||||
|
"-plays", "0",
|
||||||
|
"-f", "apng",
|
||||||
|
})
|
||||||
|
case ".mp4":
|
||||||
|
return new(r, rate, nil, out, []string{
|
||||||
|
"-vcodec", "libx264rgb",
|
||||||
|
"-preset", "ultrafast",
|
||||||
|
"-qp", "0",
|
||||||
|
"-f", "mp4",
|
||||||
|
})
|
||||||
|
case ".mkv":
|
||||||
|
return new(r, rate, nil, out, []string{
|
||||||
|
"-vcodec", "libx264rgb",
|
||||||
|
"-preset", "ultrafast",
|
||||||
|
"-qp", "0",
|
||||||
|
"-f", "matroska",
|
||||||
|
})
|
||||||
|
case ".webp":
|
||||||
|
return new(r, rate, nil, out, []string{
|
||||||
|
"-vcodec", "libwebp_anim",
|
||||||
|
"-lossless", "1",
|
||||||
|
"-loop", "0",
|
||||||
|
"-f", "webp",
|
||||||
|
})
|
||||||
|
case ".webm":
|
||||||
|
return new(r, rate, nil, out, []string{
|
||||||
|
"-vcodec", "vp9",
|
||||||
|
"-lossless", "1",
|
||||||
|
"-f", "webm",
|
||||||
|
})
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported extension: %q", ext)
|
||||||
|
}
|
||||||
|
}
|
124
cmd/demo/main.go
Normal file
124
cmd/demo/main.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
// Creates an animation of several renditions of "Munching Square".
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"image/draw"
|
||||||
|
"log"
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"smariot.com/animate"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
const (
|
||||||
|
gridSize = 32
|
||||||
|
pixelSize = 12
|
||||||
|
pixelRadius = pixelSize / 2.
|
||||||
|
subImageSize = gridSize * pixelSize
|
||||||
|
frameRate = 10
|
||||||
|
filename = "demo.webp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// create a single animation large enough to contain four sub-animations.
|
||||||
|
anim, err := animate.New(image.Rect(0, 0, subImageSize*2, subImageSize*2), frameRate, filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the sub images
|
||||||
|
// (note that b and d are swapped because I think it looks better visually, but as for logical progression, the letter order makes more sense)
|
||||||
|
a := anim.SubImage(image.Rect(0, 0, subImageSize, subImageSize)).(*image.NRGBA)
|
||||||
|
b := anim.SubImage(image.Rect(0, 0, subImageSize, subImageSize).Add(image.Pt(subImageSize, subImageSize))).(*image.NRGBA)
|
||||||
|
c := anim.SubImage(image.Rect(0, 0, subImageSize, subImageSize).Add(image.Pt(0, subImageSize))).(*image.NRGBA)
|
||||||
|
d := anim.SubImage(image.Rect(0, 0, subImageSize, subImageSize).Add(image.Pt(subImageSize, 0))).(*image.NRGBA)
|
||||||
|
|
||||||
|
// I don't want to deal with the sub images all having weird rectangles that don't start at (0, 0), so copy the rectangle from sub-image a for
|
||||||
|
// all of them.
|
||||||
|
b.Rect, c.Rect, d.Rect = a.Rect, a.Rect, a.Rect
|
||||||
|
|
||||||
|
// a pixel sized circle mask, used for the PDP-1 version.
|
||||||
|
// scaled by √2 so that the circles touch diagonally.
|
||||||
|
// need to use floor in the inset because the result is negative,
|
||||||
|
// and integers normally round toward zero.
|
||||||
|
dot := image.NewAlpha(image.Rect(0, 0, pixelSize, pixelSize).Inset(int(math.Floor(pixelRadius - pixelRadius*math.Sqrt2))))
|
||||||
|
|
||||||
|
for y := dot.Rect.Min.Y; y < dot.Rect.Max.Y; y++ {
|
||||||
|
for x := dot.Rect.Min.X; x < dot.Rect.Max.X; x++ {
|
||||||
|
dx := float64(x) + 0.5 - pixelRadius
|
||||||
|
dy := float64(y) + 0.5 - pixelRadius
|
||||||
|
a := uint8(max(0, min(1, pixelRadius*math.Sqrt2+0.5-math.Sqrt(dx*dx+dy*dy)))*255 + 0.5)
|
||||||
|
dot.SetAlpha(x, y, color.Alpha{A: a})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pixel := image.Rect(0, 0, pixelSize, pixelSize)
|
||||||
|
black := image.NewUniform(color.Black)
|
||||||
|
white := image.NewUniform(color.White)
|
||||||
|
|
||||||
|
for t := range gridSize {
|
||||||
|
// clear the frame.
|
||||||
|
draw.Draw(anim, anim.Rect, black, image.Point{}, draw.Src)
|
||||||
|
|
||||||
|
// the classing PDP-1 version.
|
||||||
|
for x := range gridSize {
|
||||||
|
y := x ^ t
|
||||||
|
draw.DrawMask(a, dot.Rect.Add(image.Pt(x*pixelSize, y*pixelSize)), white, image.Point{}, dot, dot.Rect.Min, draw.Over)
|
||||||
|
}
|
||||||
|
|
||||||
|
// an alternate version
|
||||||
|
for y := range gridSize {
|
||||||
|
for x := range gridSize {
|
||||||
|
if (x^y+t)%gridSize <= gridSize/2 {
|
||||||
|
draw.Draw(b, pixel.Add(image.Pt(x*pixelSize, y*pixelSize)), white, image.Point{}, draw.Src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// an alternate alternate version - with color!
|
||||||
|
for y := range gridSize {
|
||||||
|
for x := range gridSize {
|
||||||
|
r := uint8((x ^ y + t) % gridSize * 255 / gridSize)
|
||||||
|
g := uint8((x ^ y + t + gridSize/3) % gridSize * 255 / gridSize)
|
||||||
|
b := uint8((x ^ y + t + gridSize*2/3) % gridSize * 255 / gridSize)
|
||||||
|
|
||||||
|
draw.Draw(c, pixel.Add(image.Pt(x*pixelSize, y*pixelSize)), image.NewUniform(color.NRGBA{r, g, b, 255}), image.Point{}, draw.Src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for y := range subImageSize {
|
||||||
|
for x := range subImageSize {
|
||||||
|
// distance, as 0 in the center and 1 at the corners.
|
||||||
|
dx := float64(x) + 0.5 - subImageSize/2.
|
||||||
|
dy := float64(y) + 0.5 - subImageSize/2.
|
||||||
|
dist := math.Sqrt(dx*dx+dy*dy) / (math.Sqrt2 * subImageSize / 2.)
|
||||||
|
|
||||||
|
// distort time using a sine wave, based on distance and angle.
|
||||||
|
t := (t + int((math.Sin(math.Pi*2.*dist+math.Atan2(dy, dx))*.5+.5)*gridSize)) % gridSize
|
||||||
|
|
||||||
|
// re-quantize space, but also remember the original pixel position for drawing the pixel.
|
||||||
|
px, py := x, y
|
||||||
|
x, y := x/pixelSize, y/pixelSize
|
||||||
|
|
||||||
|
// for extra contrast with the RGB version, let's use CMY.
|
||||||
|
cyan := uint8((x ^ y + t) % gridSize * 255 / gridSize)
|
||||||
|
magenta := uint8((x ^ y + t + gridSize/3) % gridSize * 255 / gridSize)
|
||||||
|
yellow := uint8((x ^ y + t + gridSize*2/3) % gridSize * 255 / gridSize)
|
||||||
|
|
||||||
|
d.Set(px, py, color.NRGBA{255 - cyan, 255 - magenta, 255 - yellow, 255})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// emit the frame.
|
||||||
|
if err := anim.EmitFrame(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// and finally finish the animation by closing it.
|
||||||
|
if err := anim.Close(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
264
palette.go
Normal file
264
palette.go
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
package animate
|
||||||
|
|
||||||
|
import "image/color"
|
||||||
|
|
||||||
|
// Default palette to use for indexed images such as gif.
|
||||||
|
// Subject to change.
|
||||||
|
var defaultPalette = color.Palette{
|
||||||
|
color.RGBA{R: 0x0f, G: 0x08, B: 0x13, A: 0xff},
|
||||||
|
color.RGBA{R: 0x0f, G: 0x0d, B: 0x40, A: 0xff},
|
||||||
|
color.RGBA{R: 0x14, G: 0x12, B: 0x67, A: 0xff},
|
||||||
|
color.RGBA{R: 0x16, G: 0x16, B: 0x8c, A: 0xff},
|
||||||
|
color.RGBA{R: 0x16, G: 0x1e, B: 0x13, A: 0xff},
|
||||||
|
color.RGBA{R: 0x17, G: 0x19, B: 0xae, A: 0xff},
|
||||||
|
color.RGBA{R: 0x1a, G: 0x19, B: 0xd0, A: 0xff},
|
||||||
|
color.RGBA{R: 0x1a, G: 0x33, B: 0x16, A: 0xff},
|
||||||
|
color.RGBA{R: 0x1c, G: 0x28, B: 0x3e, A: 0xff},
|
||||||
|
color.RGBA{R: 0x1e, G: 0x31, B: 0x68, A: 0xff},
|
||||||
|
color.RGBA{R: 0x1f, G: 0x38, B: 0x94, A: 0xff},
|
||||||
|
color.RGBA{R: 0x1f, G: 0x3d, B: 0xc1, A: 0xff},
|
||||||
|
color.RGBA{R: 0x20, G: 0x1d, B: 0xf1, A: 0xff},
|
||||||
|
color.RGBA{R: 0x20, G: 0x47, B: 0x1a, A: 0xff},
|
||||||
|
color.RGBA{R: 0x21, G: 0x3d, B: 0x40, A: 0xff},
|
||||||
|
color.RGBA{R: 0x25, G: 0x54, B: 0x49, A: 0xff},
|
||||||
|
color.RGBA{R: 0x25, G: 0x5b, B: 0x21, A: 0xff},
|
||||||
|
color.RGBA{R: 0x26, G: 0x47, B: 0x66, A: 0xff},
|
||||||
|
color.RGBA{R: 0x27, G: 0x42, B: 0xef, A: 0xff},
|
||||||
|
color.RGBA{R: 0x28, G: 0x55, B: 0xae, A: 0xff},
|
||||||
|
color.RGBA{R: 0x28, G: 0x5d, B: 0x75, A: 0xff},
|
||||||
|
color.RGBA{R: 0x29, G: 0x4e, B: 0x8c, A: 0xff},
|
||||||
|
color.RGBA{R: 0x29, G: 0x6c, B: 0x1c, A: 0xff},
|
||||||
|
color.RGBA{R: 0x29, G: 0x7f, B: 0x21, A: 0xff},
|
||||||
|
color.RGBA{R: 0x2a, G: 0x5e, B: 0xf0, A: 0xff},
|
||||||
|
color.RGBA{R: 0x2c, G: 0x66, B: 0x9d, A: 0xff},
|
||||||
|
color.RGBA{R: 0x2c, G: 0x6c, B: 0xc9, A: 0xff},
|
||||||
|
color.RGBA{R: 0x2d, G: 0x0c, B: 0x29, A: 0xff},
|
||||||
|
color.RGBA{R: 0x2d, G: 0x74, B: 0x4a, A: 0xff},
|
||||||
|
color.RGBA{R: 0x2d, G: 0x86, B: 0xd5, A: 0xff},
|
||||||
|
color.RGBA{R: 0x2e, G: 0x68, B: 0x5c, A: 0xff},
|
||||||
|
color.RGBA{R: 0x2e, G: 0x74, B: 0xef, A: 0xff},
|
||||||
|
color.RGBA{R: 0x2e, G: 0x90, B: 0x23, A: 0xff},
|
||||||
|
color.RGBA{R: 0x2f, G: 0x73, B: 0x86, A: 0xff},
|
||||||
|
color.RGBA{R: 0x30, G: 0x54, B: 0xd0, A: 0xff},
|
||||||
|
color.RGBA{R: 0x30, G: 0x7c, B: 0xb0, A: 0xff},
|
||||||
|
color.RGBA{R: 0x30, G: 0xa1, B: 0x29, A: 0xff},
|
||||||
|
color.RGBA{R: 0x31, G: 0x82, B: 0x71, A: 0xff},
|
||||||
|
color.RGBA{R: 0x32, G: 0xb2, B: 0x27, A: 0xff},
|
||||||
|
color.RGBA{R: 0x33, G: 0x12, B: 0x54, A: 0xff},
|
||||||
|
color.RGBA{R: 0x33, G: 0x89, B: 0x98, A: 0xff},
|
||||||
|
color.RGBA{R: 0x34, G: 0x89, B: 0x52, A: 0xff},
|
||||||
|
color.RGBA{R: 0x35, G: 0x97, B: 0x7e, A: 0xff},
|
||||||
|
color.RGBA{R: 0x35, G: 0x9c, B: 0xed, A: 0xff},
|
||||||
|
color.RGBA{R: 0x36, G: 0xb0, B: 0x68, A: 0xff},
|
||||||
|
color.RGBA{R: 0x37, G: 0x9d, B: 0x5b, A: 0xff},
|
||||||
|
color.RGBA{R: 0x37, G: 0xc3, B: 0x29, A: 0xff},
|
||||||
|
color.RGBA{R: 0x38, G: 0xa8, B: 0xcb, A: 0xff},
|
||||||
|
color.RGBA{R: 0x38, G: 0xbc, B: 0xd5, A: 0xff},
|
||||||
|
color.RGBA{R: 0x39, G: 0x9d, B: 0xa4, A: 0xff},
|
||||||
|
color.RGBA{R: 0x39, G: 0xd2, B: 0x2a, A: 0xff},
|
||||||
|
color.RGBA{R: 0x39, G: 0xf0, B: 0x33, A: 0xff},
|
||||||
|
color.RGBA{R: 0x3a, G: 0xaa, B: 0x89, A: 0xff},
|
||||||
|
color.RGBA{R: 0x3a, G: 0xe1, B: 0x2a, A: 0xff},
|
||||||
|
color.RGBA{R: 0x3b, G: 0x17, B: 0x83, A: 0xff},
|
||||||
|
color.RGBA{R: 0x3d, G: 0xb3, B: 0xb1, A: 0xff},
|
||||||
|
color.RGBA{R: 0x3d, G: 0xc8, B: 0x83, A: 0xff},
|
||||||
|
color.RGBA{R: 0x3d, G: 0xcf, B: 0x61, A: 0xff},
|
||||||
|
color.RGBA{R: 0x3e, G: 0x19, B: 0xaf, A: 0xff},
|
||||||
|
color.RGBA{R: 0x3e, G: 0x93, B: 0xc1, A: 0xff},
|
||||||
|
color.RGBA{R: 0x3e, G: 0xe3, B: 0x63, A: 0xff},
|
||||||
|
color.RGBA{R: 0x3f, G: 0x11, B: 0x13, A: 0xff},
|
||||||
|
color.RGBA{R: 0x3f, G: 0x88, B: 0xf4, A: 0xff},
|
||||||
|
color.RGBA{R: 0x40, G: 0xbe, B: 0x9a, A: 0xff},
|
||||||
|
color.RGBA{R: 0x40, G: 0xcb, B: 0xc6, A: 0xff},
|
||||||
|
color.RGBA{R: 0x41, G: 0xbd, B: 0x5c, A: 0xff},
|
||||||
|
color.RGBA{R: 0x42, G: 0xb0, B: 0xf0, A: 0xff},
|
||||||
|
color.RGBA{R: 0x43, G: 0x20, B: 0xd4, A: 0xff},
|
||||||
|
color.RGBA{R: 0x43, G: 0xe7, B: 0xf2, A: 0xff},
|
||||||
|
color.RGBA{R: 0x44, G: 0x2c, B: 0x19, A: 0xff},
|
||||||
|
color.RGBA{R: 0x44, G: 0xe9, B: 0xae, A: 0xff},
|
||||||
|
color.RGBA{R: 0x44, G: 0xfc, B: 0x31, A: 0xff},
|
||||||
|
color.RGBA{R: 0x45, G: 0xd4, B: 0xab, A: 0xff},
|
||||||
|
color.RGBA{R: 0x45, G: 0xd5, B: 0xed, A: 0xff},
|
||||||
|
color.RGBA{R: 0x45, G: 0xed, B: 0x89, A: 0xff},
|
||||||
|
color.RGBA{R: 0x47, G: 0xda, B: 0x89, A: 0xff},
|
||||||
|
color.RGBA{R: 0x47, G: 0xe3, B: 0xcf, A: 0xff},
|
||||||
|
color.RGBA{R: 0x48, G: 0xc3, B: 0xf3, A: 0xff},
|
||||||
|
color.RGBA{R: 0x49, G: 0xf9, B: 0x72, A: 0xff},
|
||||||
|
color.RGBA{R: 0x4c, G: 0x33, B: 0x4a, A: 0xff},
|
||||||
|
color.RGBA{R: 0x4c, G: 0x38, B: 0x7a, A: 0xff},
|
||||||
|
color.RGBA{R: 0x4c, G: 0x3d, B: 0xae, A: 0xff},
|
||||||
|
color.RGBA{R: 0x4f, G: 0x13, B: 0x3d, A: 0xff},
|
||||||
|
color.RGBA{R: 0x4f, G: 0x45, B: 0x1e, A: 0xff},
|
||||||
|
color.RGBA{R: 0x50, G: 0x16, B: 0x68, A: 0xff},
|
||||||
|
color.RGBA{R: 0x50, G: 0xf8, B: 0xcd, A: 0xff},
|
||||||
|
color.RGBA{R: 0x50, G: 0xf8, B: 0xee, A: 0xff},
|
||||||
|
color.RGBA{R: 0x50, G: 0xfa, B: 0xa6, A: 0xff},
|
||||||
|
color.RGBA{R: 0x54, G: 0x22, B: 0xf1, A: 0xff},
|
||||||
|
color.RGBA{R: 0x58, G: 0x1a, B: 0x9e, A: 0xff},
|
||||||
|
color.RGBA{R: 0x58, G: 0x5c, B: 0x25, A: 0xff},
|
||||||
|
color.RGBA{R: 0x5b, G: 0x51, B: 0x51, A: 0xff},
|
||||||
|
color.RGBA{R: 0x5d, G: 0x4b, B: 0xf0, A: 0xff},
|
||||||
|
color.RGBA{R: 0x5f, G: 0x58, B: 0x80, A: 0xff},
|
||||||
|
color.RGBA{R: 0x61, G: 0x14, B: 0x17, A: 0xff},
|
||||||
|
color.RGBA{R: 0x61, G: 0x74, B: 0x26, A: 0xff},
|
||||||
|
color.RGBA{R: 0x62, G: 0x5e, B: 0xb2, A: 0xff},
|
||||||
|
color.RGBA{R: 0x63, G: 0x1d, B: 0xca, A: 0xff},
|
||||||
|
color.RGBA{R: 0x66, G: 0x72, B: 0x98, A: 0xff},
|
||||||
|
color.RGBA{R: 0x67, G: 0x68, B: 0xeb, A: 0xff},
|
||||||
|
color.RGBA{R: 0x67, G: 0x79, B: 0xcb, A: 0xff},
|
||||||
|
color.RGBA{R: 0x68, G: 0x71, B: 0x63, A: 0xff},
|
||||||
|
color.RGBA{R: 0x68, G: 0x8c, B: 0x28, A: 0xff},
|
||||||
|
color.RGBA{R: 0x69, G: 0x19, B: 0x83, A: 0xff},
|
||||||
|
color.RGBA{R: 0x69, G: 0x34, B: 0x21, A: 0xff},
|
||||||
|
color.RGBA{R: 0x6a, G: 0x47, B: 0xcb, A: 0xff},
|
||||||
|
color.RGBA{R: 0x6b, G: 0x42, B: 0x98, A: 0xff},
|
||||||
|
color.RGBA{R: 0x6d, G: 0x17, B: 0x5f, A: 0xff},
|
||||||
|
color.RGBA{R: 0x6d, G: 0x3c, B: 0x65, A: 0xff},
|
||||||
|
color.RGBA{R: 0x6d, G: 0xa5, B: 0x2e, A: 0xff},
|
||||||
|
color.RGBA{R: 0x72, G: 0x19, B: 0x3c, A: 0xff},
|
||||||
|
color.RGBA{R: 0x74, G: 0x88, B: 0x90, A: 0xff},
|
||||||
|
color.RGBA{R: 0x74, G: 0x8e, B: 0x64, A: 0xff},
|
||||||
|
color.RGBA{R: 0x76, G: 0x92, B: 0xea, A: 0xff},
|
||||||
|
color.RGBA{R: 0x78, G: 0x1d, B: 0xab, A: 0xff},
|
||||||
|
color.RGBA{R: 0x78, G: 0x23, B: 0xf0, A: 0xff},
|
||||||
|
color.RGBA{R: 0x7a, G: 0xbc, B: 0x2e, A: 0xff},
|
||||||
|
color.RGBA{R: 0x7b, G: 0x61, B: 0x27, A: 0xff},
|
||||||
|
color.RGBA{R: 0x7c, G: 0x9c, B: 0xc1, A: 0xff},
|
||||||
|
color.RGBA{R: 0x7d, G: 0xa9, B: 0x6c, A: 0xff},
|
||||||
|
color.RGBA{R: 0x7e, G: 0xd0, B: 0x35, A: 0xff},
|
||||||
|
color.RGBA{R: 0x7f, G: 0x46, B: 0x20, A: 0xff},
|
||||||
|
color.RGBA{R: 0x7f, G: 0xa2, B: 0x96, A: 0xff},
|
||||||
|
color.RGBA{R: 0x7f, G: 0xe5, B: 0x38, A: 0xff},
|
||||||
|
color.RGBA{R: 0x83, G: 0x1b, B: 0x19, A: 0xff},
|
||||||
|
color.RGBA{R: 0x83, G: 0x5b, B: 0x5c, A: 0xff},
|
||||||
|
color.RGBA{R: 0x85, G: 0xb4, B: 0xc8, A: 0xff},
|
||||||
|
color.RGBA{R: 0x86, G: 0x1d, B: 0x86, A: 0xff},
|
||||||
|
color.RGBA{R: 0x87, G: 0x81, B: 0xb6, A: 0xff},
|
||||||
|
color.RGBA{R: 0x88, G: 0x1f, B: 0xcf, A: 0xff},
|
||||||
|
color.RGBA{R: 0x88, G: 0x50, B: 0xeb, A: 0xff},
|
||||||
|
color.RGBA{R: 0x89, G: 0x3f, B: 0x4f, A: 0xff},
|
||||||
|
color.RGBA{R: 0x89, G: 0x78, B: 0x2a, A: 0xff},
|
||||||
|
color.RGBA{R: 0x89, G: 0xc3, B: 0x74, A: 0xff},
|
||||||
|
color.RGBA{R: 0x8a, G: 0x49, B: 0x86, A: 0xff},
|
||||||
|
color.RGBA{R: 0x8b, G: 0x64, B: 0xbc, A: 0xff},
|
||||||
|
color.RGBA{R: 0x8c, G: 0x46, B: 0xb7, A: 0xff},
|
||||||
|
color.RGBA{R: 0x8c, G: 0x76, B: 0xed, A: 0xff},
|
||||||
|
color.RGBA{R: 0x8d, G: 0x68, B: 0x89, A: 0xff},
|
||||||
|
color.RGBA{R: 0x8d, G: 0x93, B: 0x2f, A: 0xff},
|
||||||
|
color.RGBA{R: 0x8e, G: 0x1c, B: 0x63, A: 0xff},
|
||||||
|
color.RGBA{R: 0x8e, G: 0xf9, B: 0x37, A: 0xff},
|
||||||
|
color.RGBA{R: 0x8f, G: 0xcf, B: 0xc9, A: 0xff},
|
||||||
|
color.RGBA{R: 0x90, G: 0xaa, B: 0xee, A: 0xff},
|
||||||
|
color.RGBA{R: 0x90, G: 0xbd, B: 0xa0, A: 0xff},
|
||||||
|
color.RGBA{R: 0x90, G: 0xda, B: 0xa6, A: 0xff},
|
||||||
|
color.RGBA{R: 0x91, G: 0x19, B: 0x40, A: 0xff},
|
||||||
|
color.RGBA{R: 0x91, G: 0xdf, B: 0x7a, A: 0xff},
|
||||||
|
color.RGBA{R: 0x93, G: 0xc6, B: 0xee, A: 0xff},
|
||||||
|
color.RGBA{R: 0x93, G: 0xe2, B: 0xed, A: 0xff},
|
||||||
|
color.RGBA{R: 0x95, G: 0x78, B: 0x65, A: 0xff},
|
||||||
|
color.RGBA{R: 0x97, G: 0xac, B: 0x31, A: 0xff},
|
||||||
|
color.RGBA{R: 0x98, G: 0x1e, B: 0xa8, A: 0xff},
|
||||||
|
color.RGBA{R: 0x9b, G: 0x25, B: 0xf0, A: 0xff},
|
||||||
|
color.RGBA{R: 0x9c, G: 0x5d, B: 0x27, A: 0xff},
|
||||||
|
color.RGBA{R: 0xa0, G: 0x1d, B: 0x1e, A: 0xff},
|
||||||
|
color.RGBA{R: 0xa0, G: 0xf8, B: 0x80, A: 0xff},
|
||||||
|
color.RGBA{R: 0xa2, G: 0x42, B: 0x26, A: 0xff},
|
||||||
|
color.RGBA{R: 0xa3, G: 0x8c, B: 0xed, A: 0xff},
|
||||||
|
color.RGBA{R: 0xa5, G: 0x20, B: 0x81, A: 0xff},
|
||||||
|
color.RGBA{R: 0xa5, G: 0x89, B: 0x95, A: 0xff},
|
||||||
|
color.RGBA{R: 0xa5, G: 0x92, B: 0x6c, A: 0xff},
|
||||||
|
color.RGBA{R: 0xa5, G: 0xf8, B: 0xb2, A: 0xff},
|
||||||
|
color.RGBA{R: 0xa6, G: 0xf9, B: 0xe7, A: 0xff},
|
||||||
|
color.RGBA{R: 0xaa, G: 0x21, B: 0xcc, A: 0xff},
|
||||||
|
color.RGBA{R: 0xaa, G: 0x49, B: 0x67, A: 0xff},
|
||||||
|
color.RGBA{R: 0xaa, G: 0x81, B: 0x2d, A: 0xff},
|
||||||
|
color.RGBA{R: 0xaa, G: 0xc2, B: 0x36, A: 0xff},
|
||||||
|
color.RGBA{R: 0xab, G: 0x4e, B: 0x9c, A: 0xff},
|
||||||
|
color.RGBA{R: 0xab, G: 0x5c, B: 0xf0, A: 0xff},
|
||||||
|
color.RGBA{R: 0xab, G: 0xab, B: 0x74, A: 0xff},
|
||||||
|
color.RGBA{R: 0xac, G: 0x1e, B: 0x54, A: 0xff},
|
||||||
|
color.RGBA{R: 0xac, G: 0xd6, B: 0x34, A: 0xff},
|
||||||
|
color.RGBA{R: 0xac, G: 0xe9, B: 0x3a, A: 0xff},
|
||||||
|
color.RGBA{R: 0xad, G: 0x62, B: 0x5f, A: 0xff},
|
||||||
|
color.RGBA{R: 0xad, G: 0x71, B: 0xc8, A: 0xff},
|
||||||
|
color.RGBA{R: 0xad, G: 0x93, B: 0xc6, A: 0xff},
|
||||||
|
color.RGBA{R: 0xaf, G: 0x4d, B: 0xc9, A: 0xff},
|
||||||
|
color.RGBA{R: 0xaf, G: 0x6e, B: 0x97, A: 0xff},
|
||||||
|
color.RGBA{R: 0xb1, G: 0xa4, B: 0xa6, A: 0xff},
|
||||||
|
color.RGBA{R: 0xb3, G: 0x98, B: 0x2f, A: 0xff},
|
||||||
|
color.RGBA{R: 0xb3, G: 0xe6, B: 0xbf, A: 0xff},
|
||||||
|
color.RGBA{R: 0xb5, G: 0x6b, B: 0x2b, A: 0xff},
|
||||||
|
color.RGBA{R: 0xb7, G: 0x22, B: 0xa6, A: 0xff},
|
||||||
|
color.RGBA{R: 0xbb, G: 0x27, B: 0xef, A: 0xff},
|
||||||
|
color.RGBA{R: 0xbb, G: 0xae, B: 0x37, A: 0xff},
|
||||||
|
color.RGBA{R: 0xbc, G: 0x21, B: 0x24, A: 0xff},
|
||||||
|
color.RGBA{R: 0xbd, G: 0xb9, B: 0xbf, A: 0xff},
|
||||||
|
color.RGBA{R: 0xbd, G: 0xc9, B: 0x7b, A: 0xff},
|
||||||
|
color.RGBA{R: 0xbf, G: 0x4b, B: 0x27, A: 0xff},
|
||||||
|
color.RGBA{R: 0xc1, G: 0x21, B: 0x7d, A: 0xff},
|
||||||
|
color.RGBA{R: 0xc2, G: 0xb0, B: 0xe6, A: 0xff},
|
||||||
|
color.RGBA{R: 0xc2, G: 0xe3, B: 0x86, A: 0xff},
|
||||||
|
color.RGBA{R: 0xc3, G: 0xce, B: 0xea, A: 0xff},
|
||||||
|
color.RGBA{R: 0xc5, G: 0xce, B: 0xb1, A: 0xff},
|
||||||
|
color.RGBA{R: 0xc5, G: 0xfa, B: 0x3b, A: 0xff},
|
||||||
|
color.RGBA{R: 0xc6, G: 0x76, B: 0xee, A: 0xff},
|
||||||
|
color.RGBA{R: 0xc7, G: 0x79, B: 0x6b, A: 0xff},
|
||||||
|
color.RGBA{R: 0xc8, G: 0x23, B: 0x54, A: 0xff},
|
||||||
|
color.RGBA{R: 0xc8, G: 0xe6, B: 0xe9, A: 0xff},
|
||||||
|
color.RGBA{R: 0xc9, G: 0x96, B: 0xeb, A: 0xff},
|
||||||
|
color.RGBA{R: 0xca, G: 0x4e, B: 0x87, A: 0xff},
|
||||||
|
color.RGBA{R: 0xcd, G: 0x24, B: 0xc9, A: 0xff},
|
||||||
|
color.RGBA{R: 0xce, G: 0xb2, B: 0x87, A: 0xff},
|
||||||
|
color.RGBA{R: 0xcf, G: 0x53, B: 0x5f, A: 0xff},
|
||||||
|
color.RGBA{R: 0xcf, G: 0x56, B: 0xb7, A: 0xff},
|
||||||
|
color.RGBA{R: 0xcf, G: 0x84, B: 0x30, A: 0xff},
|
||||||
|
color.RGBA{R: 0xcf, G: 0x8f, B: 0xa8, A: 0xff},
|
||||||
|
color.RGBA{R: 0xd0, G: 0x53, B: 0xe8, A: 0xff},
|
||||||
|
color.RGBA{R: 0xd0, G: 0x94, B: 0x75, A: 0xff},
|
||||||
|
color.RGBA{R: 0xd1, G: 0xd1, B: 0x3c, A: 0xff},
|
||||||
|
color.RGBA{R: 0xd2, G: 0x7a, B: 0xc5, A: 0xff},
|
||||||
|
color.RGBA{R: 0xd3, G: 0x6f, B: 0x92, A: 0xff},
|
||||||
|
color.RGBA{R: 0xd4, G: 0xba, B: 0x36, A: 0xff},
|
||||||
|
color.RGBA{R: 0xd4, G: 0xe7, B: 0x3d, A: 0xff},
|
||||||
|
color.RGBA{R: 0xd5, G: 0x68, B: 0x2c, A: 0xff},
|
||||||
|
color.RGBA{R: 0xd6, G: 0x24, B: 0xa3, A: 0xff},
|
||||||
|
color.RGBA{R: 0xd6, G: 0x9e, B: 0x36, A: 0xff},
|
||||||
|
color.RGBA{R: 0xd7, G: 0x21, B: 0x22, A: 0xff},
|
||||||
|
color.RGBA{R: 0xd9, G: 0x24, B: 0xef, A: 0xff},
|
||||||
|
color.RGBA{R: 0xde, G: 0x49, B: 0x27, A: 0xff},
|
||||||
|
color.RGBA{R: 0xdf, G: 0x22, B: 0x7a, A: 0xff},
|
||||||
|
color.RGBA{R: 0xe4, G: 0x24, B: 0x4f, A: 0xff},
|
||||||
|
color.RGBA{R: 0xe6, G: 0xf5, B: 0xba, A: 0xff},
|
||||||
|
color.RGBA{R: 0xe6, G: 0xf7, B: 0x87, A: 0xff},
|
||||||
|
color.RGBA{R: 0xe9, G: 0xa5, B: 0xb5, A: 0xff},
|
||||||
|
color.RGBA{R: 0xeb, G: 0xf5, B: 0xea, A: 0xff},
|
||||||
|
color.RGBA{R: 0xec, G: 0xbc, B: 0xe9, A: 0xff},
|
||||||
|
color.RGBA{R: 0xed, G: 0xdb, B: 0x87, A: 0xff},
|
||||||
|
color.RGBA{R: 0xed, G: 0xdb, B: 0xbb, A: 0xff},
|
||||||
|
color.RGBA{R: 0xee, G: 0xbf, B: 0xb7, A: 0xff},
|
||||||
|
color.RGBA{R: 0xef, G: 0x50, B: 0x90, A: 0xff},
|
||||||
|
color.RGBA{R: 0xef, G: 0xa1, B: 0xeb, A: 0xff},
|
||||||
|
color.RGBA{R: 0xef, G: 0xc0, B: 0x81, A: 0xff},
|
||||||
|
color.RGBA{R: 0xef, G: 0xd8, B: 0xeb, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf0, G: 0x27, B: 0xc6, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf0, G: 0x5f, B: 0xed, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf0, G: 0x81, B: 0xea, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf0, G: 0x8d, B: 0xbe, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf0, G: 0xf7, B: 0x3c, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf1, G: 0x5d, B: 0x68, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf1, G: 0x77, B: 0x37, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf1, G: 0x81, B: 0x7e, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf2, G: 0x58, B: 0xc3, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf2, G: 0x90, B: 0x36, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf2, G: 0xa1, B: 0x7f, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf2, G: 0xab, B: 0x3a, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf2, G: 0xc5, B: 0x3b, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf3, G: 0x70, B: 0xa8, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf3, G: 0xde, B: 0x40, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf4, G: 0x26, B: 0x9d, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf4, G: 0x2b, B: 0xee, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf5, G: 0x26, B: 0x2a, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf5, G: 0x57, B: 0x2c, A: 0xff},
|
||||||
|
color.RGBA{R: 0xf7, G: 0x29, B: 0x69, A: 0xff},
|
||||||
|
color.RGBA{R: 0x00, G: 0x00, B: 0x00, A: 0x00},
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user