{"id":13657576,"url":"https://github.com/peterhellberg/gfx","last_synced_at":"2025-04-13T09:40:51.812Z","repository":{"id":57480871,"uuid":"165436171","full_name":"peterhellberg/gfx","owner":"peterhellberg","description":"Convenience package for dealing with graphics in my pixel drawing experiments.","archived":false,"fork":false,"pushed_at":"2024-07-17T09:40:59.000Z","size":892,"stargazers_count":145,"open_issues_count":1,"forks_count":5,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-27T01:11:11.431Z","etag":null,"topics":["blocks","drawing","gfx","go","graphics","matrix","noise","palettes","polygons","signed-distance-functions","simplex","vectors"],"latest_commit_sha":null,"homepage":"https://godoc.org/github.com/peterhellberg/gfx","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/peterhellberg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"ko_fi":"peterhellberg"}},"created_at":"2019-01-12T21:08:20.000Z","updated_at":"2025-02-09T10:03:36.000Z","dependencies_parsed_at":"2024-08-02T05:13:25.047Z","dependency_job_id":null,"html_url":"https://github.com/peterhellberg/gfx","commit_stats":{"total_commits":345,"total_committers":3,"mean_commits":115.0,"dds":0.005797101449275366,"last_synced_commit":"9885a9f73abe300ccee595aab7fc5b91e4e3de01"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterhellberg%2Fgfx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterhellberg%2Fgfx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterhellberg%2Fgfx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterhellberg%2Fgfx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/peterhellberg","download_url":"https://codeload.github.com/peterhellberg/gfx/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248693273,"owners_count":21146766,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blocks","drawing","gfx","go","graphics","matrix","noise","palettes","polygons","signed-distance-functions","simplex","vectors"],"created_at":"2024-08-02T05:00:45.491Z","updated_at":"2025-04-13T09:40:51.792Z","avatar_url":"https://github.com/peterhellberg.png","language":"Go","funding_links":["https://ko-fi.com/peterhellberg"],"categories":["Go"],"sub_categories":[],"readme":"# gfx\n\n[![Build status](https://github.com/peterhellberg/gfx/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/peterhellberg/gfx/actions/workflows/test.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/peterhellberg/gfx?style=flat)](https://goreportcard.com/report/github.com/peterhellberg/gfx)\n[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://pkg.go.dev/github.com/peterhellberg/gfx)\n[![License MIT](https://img.shields.io/badge/license-MIT-lightgrey.svg?style=flat)](https://github.com/peterhellberg/gfx#license-mit)\n\nConvenience package for dealing with graphics in my pixel drawing experiments.\n\n#### :warning: NO STABILITY GUARANTEES :warning:\n\n## Triangles\n\nTriangles can be drawn to an image using a `*gfx.DrawTarget`.\n\n![gfx-triangles](examples/gfx-example-triangles/gfx-example-triangles.png)\n\n[embedmd]:# (examples/gfx-example-triangles/gfx-example-triangles.go)\n```go\npackage main\n\nimport \"github.com/peterhellberg/gfx\"\n\nvar p = gfx.PaletteFamicube\n\nfunc main() {\n\tn := 50\n\tm := gfx.NewPaletted(900, 270, p, p.Color(n+7))\n\tt := gfx.NewDrawTarget(m)\n\n\tt.MakeTriangles(\u0026gfx.TrianglesData{\n\t\tvx(114, 16, n+1), vx(56, 142, n+2), vx(352, 142, n+3),\n\t\tvx(350, 142, n+4), vx(500, 50, n+5), vx(640, 236, n+6),\n\t\tvx(640, 70, n+8), vx(820, 160, n+9), vx(670, 236, n+10),\n\t}).Draw()\n\n\tgfx.SavePNG(\"gfx-example-triangles.png\", m)\n}\n\nfunc vx(x, y float64, n int) gfx.Vertex {\n\treturn gfx.Vertex{Position: gfx.V(x, y), Color: p.Color(n)}\n}\n```\n\n\n## Polygons\n\nA `gfx.Polygon` is represented by a list of vectors.\nThere is also `gfx.Polyline` which is a slice of polygons forming a line.\n\n![gfx-example-polygon](examples/gfx-example-polygon/gfx-example-polygon.png)\n\n[embedmd]:# (examples/gfx-example-polygon/gfx-example-polygon.go)\n```go\npackage main\n\nimport \"github.com/peterhellberg/gfx\"\n\nvar edg32 = gfx.PaletteEDG32\n\nfunc main() {\n\tm := gfx.NewNRGBA(gfx.IR(0, 0, 1024, 256))\n\tp := gfx.Polygon{\n\t\t{80, 40},\n\t\t{440, 60},\n\t\t{700, 200},\n\t\t{250, 230},\n\t\t{310, 140},\n\t}\n\n\tp.EachPixel(m, func(x, y int) {\n\t\tpv := gfx.IV(x, y)\n\t\tl := pv.To(p.Rect().Center()).Len()\n\n\t\tgfx.Mix(m, x, y, edg32.Color(int(l/18)%32))\n\t})\n\n\tfor n, v := range p {\n\t\tc := edg32.Color(n * 4)\n\n\t\tgfx.DrawCircle(m, v, 15, 8, gfx.ColorWithAlpha(c, 96))\n\t\tgfx.DrawCircle(m, v, 16, 1, c)\n\t}\n\n\tgfx.SavePNG(\"gfx-example-polygon.png\", m)\n}\n```\n\n\n## Blocks\n\nYou can draw (isometric) blocks using the `gfx.Blocks` and `gfx.Block` types.\n\n![gfx-example-blocks](examples/gfx-example-blocks/gfx-example-blocks.png)\n\n[embedmd]:# (examples/gfx-example-blocks/gfx-example-blocks.go)\n```go\npackage main\n\nimport \"github.com/peterhellberg/gfx\"\n\nfunc main() {\n\tvar (\n\t\tdst    = gfx.NewPaletted(898, 330, gfx.PaletteGo, gfx.PaletteGo[14])\n\t\trect   = gfx.BoundsToRect(dst.Bounds())\n\t\torigin = rect.Center().ScaledXY(gfx.V(1.5, -2.5)).Vec3(0.55)\n\t\tblocks gfx.Blocks\n\t)\n\n\tfor i, bc := range gfx.BlockColorsGo {\n\t\tvar (\n\t\t\tf    = float64(i) + 0.5\n\t\t\tv    = f * 11\n\t\t\tpos  = gfx.V3(290+(v*3), 8.5*v, 9*(f+2))\n\t\t\tsize = gfx.V3(90, 90, 90)\n\t\t)\n\n\t\tblocks.AddNewBlock(pos, size, bc)\n\t}\n\n\tblocks.Draw(dst, origin)\n\n\tgfx.SavePNG(\"gfx-example-blocks.png\", dst)\n}\n```\n\n## Signed Distance Functions\n\nThe `gfx.SignedDistance` type allows you to use basic [signed distance functions](http://jamie-wong.com/2016/07/15/ray-marching-signed-distance-functions/) (and operations) to produce some interesting graphics.\n\n![gfx-example-sdf](examples/gfx-example-sdf/gfx-example-sdf.png)\n\n[embedmd]:# (examples/gfx-example-sdf/gfx-example-sdf.go)\n```go\npackage main\n\nimport \"github.com/peterhellberg/gfx\"\n\nfunc main() {\n\tc := gfx.PaletteEDG36.Color\n\tm := gfx.NewImage(1024, 256, c(5))\n\n\tgfx.EachPixel(m.Bounds(), func(x, y int) {\n\t\tsd := gfx.SignedDistance{gfx.IV(x, y)}\n\n\t\tif d := sd.OpRepeat(gfx.V(128, 128), func(sd gfx.SignedDistance) float64 {\n\t\t\treturn sd.OpSubtraction(sd.Circle(50), sd.Line(gfx.V(0, 0), gfx.V(64, 64)))\n\t\t}); d \u003c 40 {\n\t\t\tm.Set(x, y, c(int(gfx.MathAbs(d/5))))\n\t\t}\n\t})\n\n\tgfx.SavePNG(\"gfx-example-sdf.png\", m)\n}\n```\n\n## Domain Coloring\n\nYou can use the `CmplxPhaseAt` method on a `gfx.Palette` to do [domain coloring](https://en.wikipedia.org/wiki/Domain_coloring).\n\n![gfx-example-domain-coloring](examples/gfx-example-domain-coloring/gfx-example-domain-coloring.png)\n\n[embedmd]:# (examples/gfx-example-domain-coloring/gfx-example-domain-coloring.go)\n```go\npackage main\n\nimport \"github.com/peterhellberg/gfx\"\n\nconst (\n\tw, h        = 1800, 540\n\tfovY        = 1.9\n\taspectRatio = float64(w) / float64(h)\n\tcenterReal  = 0\n\tcenterImag  = 0\n\tahc         = aspectRatio*fovY/2.0 + centerReal\n\thfc         = fovY/2.0 + centerImag\n)\n\nfunc pixelCoordinates(px, py int) gfx.Vec {\n\treturn gfx.V(\n\t\t((float64(px)/(w-1))*2-1)*ahc,\n\t\t((float64(h-py-1)/(h-1))*2-1)*hfc,\n\t)\n}\n\nfunc main() {\n\tvar (\n\t\tp  = gfx.PaletteEN4\n\t\tp0 = pixelCoordinates(0, 0)\n\t\tp1 = pixelCoordinates(w-1, h-1)\n\t\ty  = p0.Y\n\t\td  = gfx.V((p1.X-p0.X)/(w-1), (p1.Y-p0.Y)/(h-1))\n\t\tm  = gfx.NewImage(w, h)\n\t)\n\n\tfor py := 0; py \u003c h; py++ {\n\t\tx := p0.X\n\n\t\tfor px := 0; px \u003c w; px++ {\n\t\t\tcc := p.CmplxPhaseAt(gfx.CmplxCos(gfx.CmplxSin(0.42 / complex(y*x, x*x))))\n\n\t\t\tm.Set(px, py, cc)\n\n\t\t\tx += d.X\n\t\t}\n\n\t\ty += d.Y\n\t}\n\n\tgfx.SavePNG(\"gfx-example-domain-coloring.png\", m)\n}\n```\n\n## Animation\n\nThere is rudimentary support for making animations using `gfx.Animation`, the animations can then be encoded into GIF.\n\n![gfx-example-animation](examples/gfx-example-animation/gfx-example-animation.gif)\n\n[embedmd]:# (examples/gfx-example-animation/gfx-example-animation.go)\n```go\npackage main\n\nimport \"github.com/peterhellberg/gfx\"\n\nfunc main() {\n\ta := \u0026gfx.Animation{}\n\tp := gfx.PaletteEDG36\n\n\tvar fireflower = []uint8{\n\t\t0, 1, 1, 1, 1, 1, 1, 0,\n\t\t1, 1, 2, 2, 2, 2, 1, 1,\n\t\t1, 2, 3, 3, 3, 3, 2, 1,\n\t\t1, 1, 2, 2, 2, 2, 1, 1,\n\t\t0, 1, 1, 1, 1, 1, 1, 0,\n\t\t0, 0, 0, 4, 4, 0, 0, 0,\n\t\t0, 0, 0, 4, 4, 0, 0, 0,\n\t\t4, 4, 0, 4, 4, 0, 4, 4,\n\t\t0, 4, 0, 4, 4, 0, 4, 0,\n\t\t0, 4, 4, 4, 4, 4, 4, 0,\n\t\t0, 0, 4, 4, 4, 4, 0, 0,\n\t}\n\n\tfor i := 0; i \u003c len(p)-4; i++ {\n\t\tt := gfx.NewTile(p[i:i+4], 8, fireflower)\n\n\t\ta.AddPalettedImage(gfx.NewScaledPalettedImage(t, 20))\n\t}\n\n\ta.SaveGIF(\"gfx-example-animation.gif\")\n}\n```\n\n## Line drawing\n\n### DrawInt functions\n\nDrawing functions based on [TinyDraw](https://github.com/tinygo-org/tinydraw),\nwhich in turn is based on the [Adafruit GFX library](https://github.com/adafruit/Adafruit-GFX-Library).\n\n![gfx-example-draw-int](examples/gfx-example-draw-int/gfx-example-draw-int.png)\n\n[embedmd]:# (examples/gfx-example-draw-int/gfx-example-draw-int.go)\n```go\npackage main\n\nimport \"github.com/peterhellberg/gfx\"\n\nfunc main() {\n\tm := gfx.NewImage(160, 128, gfx.ColorTransparent)\n\n\tp := gfx.PaletteNight16\n\n\tgfx.DrawIntLine(m, 10, 10, 94, 10, p.Color(0))\n\tgfx.DrawIntLine(m, 94, 16, 10, 16, p.Color(1))\n\tgfx.DrawIntLine(m, 10, 20, 10, 118, p.Color(2))\n\tgfx.DrawIntLine(m, 16, 118, 16, 20, p.Color(4))\n\n\tgfx.DrawIntLine(m, 40, 40, 80, 80, p.Color(5))\n\tgfx.DrawIntLine(m, 40, 40, 80, 70, p.Color(6))\n\tgfx.DrawIntLine(m, 40, 40, 80, 60, p.Color(7))\n\tgfx.DrawIntLine(m, 40, 40, 80, 50, p.Color(8))\n\tgfx.DrawIntLine(m, 40, 40, 80, 40, p.Color(9))\n\n\tgfx.DrawIntLine(m, 100, 100, 40, 100, p.Color(10))\n\tgfx.DrawIntLine(m, 100, 100, 40, 90, p.Color(11))\n\tgfx.DrawIntLine(m, 100, 100, 40, 80, p.Color(12))\n\tgfx.DrawIntLine(m, 100, 100, 40, 70, p.Color(13))\n\tgfx.DrawIntLine(m, 100, 100, 40, 60, p.Color(14))\n\tgfx.DrawIntLine(m, 100, 100, 40, 50, p.Color(15))\n\n\tgfx.DrawIntRectangle(m, 30, 106, 120, 20, p.Color(14))\n\tgfx.DrawIntFilledRectangle(m, 34, 110, 112, 12, p.Color(8))\n\n\tgfx.DrawIntCircle(m, 120, 30, 20, p.Color(5))\n\tgfx.DrawIntFilledCircle(m, 120, 30, 16, p.Color(4))\n\n\tgfx.DrawIntTriangle(m, 120, 102, 100, 80, 152, 46, p.Color(9))\n\tgfx.DrawIntFilledTriangle(m, 119, 98, 105, 80, 144, 54, p.Color(6))\n\n\ts := gfx.NewScaledImage(m, 6)\n\n\tgfx.SavePNG(\"gfx-example-draw-int.png\", s)\n}\n```\n\n### Bresenham's line algorithm\n\n`gfx.DrawLineBresenham` draws a line using [Bresenham's line algorithm](http://en.wikipedia.org/wiki/Bresenham's_line_algorithm).\n\n![gfx-example-bresenham-line](examples/gfx-example-bresenham-line/gfx-example-bresenham-line.png)\n\n[embedmd]:# (examples/gfx-example-bresenham-line/gfx-example-bresenham-line.go)\n```go\npackage main\n\nimport \"github.com/peterhellberg/gfx\"\n\nvar (\n\tred   = gfx.BlockColorRed.Medium\n\tgreen = gfx.BlockColorGreen.Medium\n\tblue  = gfx.BlockColorBlue.Medium\n)\n\nfunc main() {\n\tm := gfx.NewImage(32, 16, gfx.ColorTransparent)\n\n\tgfx.DrawLineBresenham(m, gfx.V(2, 2), gfx.V(2, 14), red)\n\tgfx.DrawLineBresenham(m, gfx.V(6, 2), gfx.V(32, 2), green)\n\tgfx.DrawLineBresenham(m, gfx.V(6, 6), gfx.V(30, 14), blue)\n\n\ts := gfx.NewScaledImage(m, 16)\n\n\tgfx.SavePNG(\"gfx-example-bresenham-line.png\", s)\n}\n```\n\n## Geometry and Transformation\n\nThe (2D) geometry and transformation types are based on those found in \u003chttps://github.com/faiface/pixel\u003e (but indended for use without Pixel)\n\n### 2D types\n\n#### Vec\n\n`gfx.Vec` is a 2D vector type with X and Y components.\n\n#### Rect\n\n`gfx.Rect` is a 2D rectangle aligned with the axes of the coordinate system. It is defined by two `gfx.Vec`, Min and Max.\n\n#### Matrix\n\n`gfx.Matrix` is a 2x3 affine matrix that can be used for all kinds of spatial transforms, such as movement, scaling and rotations.\n\n![gfx-readme-examples-matrix](https://user-images.githubusercontent.com/565124/51478881-f8e69a00-1d8c-11e9-92c5-270c767dfc06.gif)\n\n[embedmd]:# (examples/gfx-example-matrix/gfx-example-matrix.go)\n```go\npackage main\n\nimport \"github.com/peterhellberg/gfx\"\n\nvar en4 = gfx.PaletteEN4\n\nfunc main() {\n\ta := \u0026gfx.Animation{Delay: 10}\n\n\tc := gfx.V(128, 128)\n\n\tp := gfx.Polygon{\n\t\t{50, 50},\n\t\t{50, 206},\n\t\t{128, 96},\n\t\t{206, 206},\n\t\t{206, 50},\n\t}\n\n\tfor d := 0.0; d \u003c 360; d += 2 {\n\t\tm := gfx.NewPaletted(256, 256, en4, en4.Color(3))\n\n\t\tmatrix := gfx.IM.RotatedDegrees(c, d)\n\n\t\tgfx.DrawPolygon(m, p.Project(matrix), 0, en4.Color(2))\n\t\tgfx.DrawPolygon(m, p.Project(matrix.Scaled(c, 0.5)), 0, en4.Color(1))\n\n\t\tgfx.DrawCircleFilled(m, c, 5, en4.Color(0))\n\n\t\ta.AddPalettedImage(m)\n\t}\n\n\ta.SaveGIF(\"/tmp/gfx-readme-examples-matrix.gif\")\n}\n```\n\n### 3D types\n\n#### Vec3\n\n`gfx.Vec3` is a 3D vector type with X, Y and Z components.\n\n#### Box\n\n`gfx.Box` is a 3D box. It is defined by two `gfx.Vec3`, Min and Max\n\n## Errors\n\nThe `gfx.Error` type is a string that implements the `error` interface.\n\n\u003e If you are using [Ebiten](https://github.com/hajimehoshi/ebiten) then you can return the provided `gfx.ErrDone` error to exit its run loop.\n\n## HTTP\n\nYou can use `gfx.GetPNG` to download and decode a PNG given an URL.\n\n## Log\n\nI find that it is fairly common for me to do some logging driven development\nwhen experimenting with graphical effects, so I've included `gfx.Log`,\n`gfx.Dump`, `gfx.Printf` and `gfx.Sprintf` in this package.\n\n## Math\n\nI have included a few functions that call functions in the `math` package.\n\nThere is also `gfx.Sign`, `gfx.Clamp` and `gfx.Lerp` functions for `float64`.\n\n## Cmplx\n\nI have included a few functions that call functions in the `cmplx` package.\n\n## Reading files\n\nIt is fairly common to read files in my experiments, so I've included `gfx.ReadFile` and `gfx.ReadJSON` in this package.\n\n## Resizing images\n\nYou can use `gfx.ResizeImage` to resize an image. (nearest neighbor, mainly useful for pixelated graphics)\n\n## Noise\n\nDifferent types of noise is often used in procedural generation.\n\n### SimplexNoise\n\nSimplexNoise is a speed-improved simplex noise algorithm for 2D, 3D and 4D.\n\n![gfx-example-simplex](examples/gfx-example-simplex/gfx-example-simplex.png)\n\n[embedmd]:# (examples/gfx-example-simplex/gfx-example-simplex.go)\n```go\npackage main\n\nimport \"github.com/peterhellberg/gfx\"\n\nfunc main() {\n\tsn := gfx.NewSimplexNoise(17)\n\n\tdst := gfx.NewImage(1024, 256)\n\n\tgfx.EachImageVec(dst, gfx.ZV, func(u gfx.Vec) {\n\t\tn := sn.Noise2D(u.X/900, u.Y/900)\n\t\tc := gfx.PaletteSplendor128.At(n / 2)\n\n\t\tgfx.SetVec(dst, u, c)\n\t})\n\n\tgfx.SavePNG(\"gfx-example-simplex.png\", dst)\n}\n```\n\n## Colors\n\nYou can construct new colors using `gfx.ColorRGBA`, `gfx.ColorNRGBA`, `gfx.ColorGray`, `gfx.ColorGray16` and `gfx.ColorWithAlpha`.\n\nThere is also a `gfx.LerpColors` function that performs linear interpolation between two colors.\n\n### Default colors\n\nThere are a few default colors in this package, convenient when you just want to experiment,\nfor more ambitious projects I suggest creating a `gfx.Palette` (or even use one of the included palettes).\n\n\n| Variable               | Color\n|------------------------|---------------------------------------------------------\n| `gfx.ColorBlack`       | ![gfx.ColorBlack](examples/gfx-colors/gfx-ColorBlack.png)\n| `gfx.ColorWhite`       | ![gfx.ColorWhite](examples/gfx-colors/gfx-ColorWhite.png)\n| `gfx.ColorTransparent` | ![gfx.ColorTransparent](examples/gfx-colors/gfx-ColorTransparent.png)\n| `gfx.ColorOpaque`      | ![gfx.ColorOpaque](examples/gfx-colors/gfx-ColorOpaque.png)\n| `gfx.ColorRed`         | ![gfx.ColorRed](examples/gfx-colors/gfx-ColorRed.png)\n| `gfx.ColorGreen`       | ![gfx.ColorGreen](examples/gfx-colors/gfx-ColorGreen.png)\n| `gfx.ColorBlue`        | ![gfx.ColorBlue](examples/gfx-colors/gfx-ColorBlue.png)\n| `gfx.ColorCyan`        | ![gfx.ColorCyan](examples/gfx-colors/gfx-ColorCyan.png)\n| `gfx.ColorMagenta`     | ![gfx.ColorMagenta](examples/gfx-colors/gfx-ColorMagenta.png)\n| `gfx.ColorYellow`      | ![gfx.ColorYellow](examples/gfx-colors/gfx-ColorYellow.png)\n\n### Block colors\n\nEach `gfx.BlockColor` consists of a `Dark`, `Medium` and `Light` shade of the same color.\n\n\n| Variable                     | Block Color\n|------------------------------|---------------------------------------------------------\n| `gfx.BlockColorYellow`       | ![gfx.BlockColorYellow](examples/gfx-colors/gfx-BlockColorYellow.png)\n| `gfx.BlockColorOrange`       | ![gfx.BlockColorOrange](examples/gfx-colors/gfx-BlockColorOrange.png)\n| `gfx.BlockColorBrown`        | ![gfx.BlockColorBrown](examples/gfx-colors/gfx-BlockColorBrown.png)\n| `gfx.BlockColorGreen`        | ![gfx.BlockColorGreen](examples/gfx-colors/gfx-BlockColorGreen.png)\n| `gfx.BlockColorBlue`         | ![gfx.BlockColorBlue](examples/gfx-colors/gfx-BlockColorBlue.png)\n| `gfx.BlockColorPurple`       | ![gfx.BlockColorPurple](examples/gfx-colors/gfx-BlockColorPurple.png)\n| `gfx.BlockColorRed`          | ![gfx.BlockColorRed](examples/gfx-colors/gfx-BlockColorRed.png)\n| `gfx.BlockColorWhite`        | ![gfx.BlockColorWhite](examples/gfx-colors/gfx-BlockColorWhite.png)\n| `gfx.BlockColorBlack`        | ![gfx.BlockColorBlack](examples/gfx-colors/gfx-BlockColorBlack.png)\n| `gfx.BlockColorGoGopherBlue` | ![gfx.BlockColorGoGopherBlue](examples/gfx-colors/gfx-BlockColorGoGopherBlue.png)\n| `gfx.BlockColorGoLightBlue`  | ![gfx.BlockColorGoLightBlue](examples/gfx-colors/gfx-BlockColorGoLightBlue.png)\n| `gfx.BlockColorGoAqua`       | ![gfx.BlockColorGoAqua](examples/gfx-colors/gfx-BlockColorGoAqua.png)\n| `gfx.BlockColorGoFuchsia`    | ![gfx.BlockColorGoFuchsia](examples/gfx-colors/gfx-BlockColorGoFuchsia.png)\n| `gfx.BlockColorGoBlack`      | ![gfx.BlockColorGoBlack](examples/gfx-colors/gfx-BlockColorGoBlack.png)\n| `gfx.BlockColorGoYellow`     | ![gfx.BlockColorGoYellow](examples/gfx-colors/gfx-BlockColorGoYellow.png)\n\n\n### Palettes\n\nThere are a number of palettes in the `gfx` package,\nmost of them are found in the [Lospec Palette List](https://lospec.com/palette-list/).\n\n\n| Variable                   | Colors | Lospec Palette\n|----------------------------|-------:| -----------------------------------------------------\n| `gfx.Palette1Bit`          |      2 | ![Palette1Bit](examples/gfx-palettes/gfx-Palette1Bit.png)\n| `gfx.Palette2BitGrayScale` |      4 | ![Palette2BitGrayScale](examples/gfx-palettes/gfx-Palette2BitGrayScale.png)\n| `gfx.PaletteEN4`           |      4 | ![PaletteEN4](examples/gfx-palettes/gfx-PaletteEN4.png)\n| `gfx.PaletteARQ4`          |      4 | ![PaletteARQ4](examples/gfx-palettes/gfx-PaletteARQ4.png)\n| `gfx.PaletteInk`           |      5 | ![PaletteInk](examples/gfx-palettes/gfx-PaletteInk.png)\n| `gfx.Palette3Bit`          |      8 | ![Palette3Bit](examples/gfx-palettes/gfx-Palette3Bit.png)\n| `gfx.PaletteEDG8`          |      8 | ![PaletteEDG8](examples/gfx-palettes/gfx-PaletteEDG8.png)\n| `gfx.PaletteAmmo8`         |      8 | ![PaletteAmmo8](examples/gfx-palettes/gfx-PaletteAmmo8.png)\n| `gfx.PaletteNYX8`          |      8 | ![PaletteNYX8](examples/gfx-palettes/gfx-PaletteNYX8.png)\n| `gfx.Palette15PDX`         |     15 | ![Palette15PDX](examples/gfx-palettes/gfx-Palette15PDX.png)\n| `gfx.PaletteCGA`           |     16 | ![PaletteCGA](examples/gfx-palettes/gfx-PaletteCGA.png)\n| `gfx.PalettePICO8`         |     16 | ![PalettePICO8](examples/gfx-palettes/gfx-PalettePICO8.png)\n| `gfx.PaletteNight16`       |     16 | ![PaletteNight16](examples/gfx-palettes/gfx-PaletteNight16.png)\n| `gfx.PaletteAAP16`         |     16 | ![PaletteAAP16](examples/gfx-palettes/gfx-PaletteAAP16.png)\n| `gfx.PaletteArne16`        |     16 | ![PaletteArne16](examples/gfx-palettes/gfx-PaletteArne16.png)\n| `gfx.PaletteEDG16`         |     16 | ![PaletteEDG16](examples/gfx-palettes/gfx-PaletteEDG16.png)\n| `gfx.Palette20PDX`         |     20 | ![Palette20PDX](examples/gfx-palettes/gfx-Palette20PDX.png)\n| `gfx.PaletteTango`         |     27 | ![PaletteTango](examples/gfx-palettes/gfx-PaletteTango.png)\n| `gfx.PaletteEDG32`         |     32 | ![PaletteEDG32](examples/gfx-palettes/gfx-PaletteEDG32.png)\n| `gfx.PaletteEDG36`         |     36 | ![PaletteEDG36](examples/gfx-palettes/gfx-PaletteEDG36.png)\n| `gfx.PaletteEDG64`         |     64 | ![PaletteEDG64](examples/gfx-palettes/gfx-PaletteEDG64.png)\n| `gfx.PaletteAAP64`         |     64 | ![PaletteAAP64](examples/gfx-palettes/gfx-PaletteAAP64.png)\n| `gfx.PaletteFamicube`      |     64 | ![PaletteFamicube](examples/gfx-palettes/gfx-PaletteFamicube.png)\n| `gfx.PaletteSplendor128`   |    128 | ![PaletteSplendor128](examples/gfx-palettes/gfx-PaletteSplendor128.png)\n\nThe palette images were generated like this:\n\n[embedmd]:# (examples/gfx-palettes/gfx-palettes.go)\n```go\npackage main\n\nimport \"github.com/peterhellberg/gfx\"\n\nfunc main() {\n\tfor size, paletteLookup := range gfx.PalettesByNumberOfColors {\n\t\tfor name, palette := range paletteLookup {\n\t\t\tdst := gfx.NewImage(size, 1)\n\n\t\t\tfor x, c := range palette {\n\t\t\t\tdst.Set(x, 0, c)\n\t\t\t}\n\n\t\t\tfilename := gfx.Sprintf(\"gfx-Palette%s.png\", name)\n\n\t\t\tgfx.SavePNG(filename, gfx.NewResizedImage(dst, 1120, 96))\n\t\t}\n\t}\n}\n```\n\n\n\u003cimg src=\"https://assets.c7.se/svg/viking-gopher.svg\" align=\"right\" width=\"30%\" height=\"300\"\u003e\n\n## License (MIT)\n\nCopyright (c) 2019-2024 [Peter Hellberg](https://c7.se)\n\n\u003e Permission is hereby granted, free of charge, to any person obtaining\n\u003e a copy of this software and associated documentation files (the\n\u003e \"Software\"), to deal in the Software without restriction, including\n\u003e without limitation the rights to use, copy, modify, merge, publish,\n\u003e distribute, sublicense, and/or sell copies of the Software, and to\n\u003e permit persons to whom the Software is furnished to do so, subject to\n\u003e the following conditions:\n\u003e\n\u003e The above copyright notice and this permission notice shall be\n\u003e included in all copies or substantial portions of the Software.\n\n\u003e THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n\u003e EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n\u003e MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n\u003e NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n\u003e LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n\u003e OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n\u003e WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeterhellberg%2Fgfx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpeterhellberg%2Fgfx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeterhellberg%2Fgfx/lists"}