Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .github/dependabot.yml

This file was deleted.

13 changes: 0 additions & 13 deletions .github/workflows/auto-merge.yml

This file was deleted.

19 changes: 11 additions & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
name: Build/Test/Lint
on: [push, pull_request]
on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.18
uses: actions/setup-go@v2
- name: Set up Go 1.24
uses: actions/setup-go@v5
with:
go-version: 1.18
go-version: 1.24

- name: Check out source code
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Dependencies
run: make dep
Expand All @@ -23,6 +28,4 @@ jobs:
run: make test

- name: Lint
uses: golangci/golangci-lint-action@v2
with:
args: --enable-all
uses: golangci/golangci-lint-action@v6
12 changes: 7 additions & 5 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
linters:
enable-all: true
disable:
# Should eventually address, aiming for basic MVP ATM :)
- varnamelen
- gomnd
- goerr113
- exhaustivestruct
- wsl
- wrapcheck
- forbidigo
- testpackage
- dupl
- lll
- cyclop
- funlen
- mnd
- gosec
- depguard
- err113
- exhaustruct
- testifylint
25 changes: 14 additions & 11 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"errors"
"fmt"
"image"
"os"
Expand All @@ -9,34 +10,35 @@ import (
"github.com/theMagicalKarp/dithering/pkg"
)

func RunE(cmd *cobra.Command, args []string) error {
func RunE(cmd *cobra.Command, _ []string) error {
inFileName, err := cmd.Flags().GetString("in")
if err != nil {
return fmt.Errorf("Failed to read 'in' flag: %w", err)
return fmt.Errorf("failed to read 'in' flag: %w", err)
}

outFileName, err := cmd.Flags().GetString("out")
if err != nil {
return fmt.Errorf("Failed to read 'out' flag: %w", err)
return fmt.Errorf("failed to read 'out' flag: %w", err)
}

if inFileName == "" || outFileName == "" {
return fmt.Errorf("Please specify input/output files")
return errors.New("please specify input/output files")
}

factor, err := cmd.Flags().GetInt("factor")
if err != nil {
return fmt.Errorf("Failed to read 'factor' flag: %w", err)
return fmt.Errorf("failed to read 'factor' flag: %w", err)
}

if factor < 0 || factor > 255 {
return fmt.Errorf("Factor must be any value between 1-255")
return errors.New("factor must be any value between 1-255")
}

validOutEncodings := pkg.GetSupportedEncodings()

outFormat, err := cmd.Flags().GetString("out-format")
if err != nil {
return fmt.Errorf("Failed to read 'out-format' flag: %w", err)
return fmt.Errorf("failed to read 'out-format' flag: %w", err)
}

encodeFunc, ok := validOutEncodings[outFormat]
Expand All @@ -46,30 +48,31 @@ func RunE(cmd *cobra.Command, args []string) error {

inFile, err := os.Open(inFileName)
if err != nil {
return fmt.Errorf("Failed to read 'in' file: %w", err)
return fmt.Errorf("failed to read 'in' file: %w", err)
}
defer inFile.Close()

inImg, _, err := image.Decode(inFile)
if err != nil {
return fmt.Errorf("Failed to decode 'in' file: %w", err)
return fmt.Errorf("failed to decode 'in' file: %w", err)
}

grayScale := pkg.NewGreyScale(inImg.Bounds())
pkg.ReadGreyScale(inImg, grayScale)
pkg.ApplyDither(grayScale, factor)

outImg := image.NewNRGBA(inImg.Bounds())
pkg.WriteGrayScale(grayScale, outImg)

outFile, err := os.Create(outFileName)
if err != nil {
return fmt.Errorf("Failed to open 'out' file: %w", err)
return fmt.Errorf("failed to open 'out' file: %w", err)
}
defer outFile.Close()

err = encodeFunc(outFile, outImg)
if err != nil {
return fmt.Errorf("Failed to encode 'out' file: %w", err)
return fmt.Errorf("failed to encode 'out' file: %w", err)
}

return nil
Expand Down
17 changes: 10 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
module github.com/theMagicalKarp/dithering

go 1.18
go 1.24

require (
github.com/davecgh/go-spew v1.1.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/spf13/cobra v1.9.1
github.com/stretchr/testify v1.10.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/cobra v1.4.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/testify v1.7.1 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
github.com/spf13/pflag v1.0.6 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
29 changes: 14 additions & 15 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
5 changes: 3 additions & 2 deletions pkg/dithering.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ func quantize(value, factor int) (int, int) {

func ApplyDither(grayScale [][]int, factor int) {
var quantErr int

width := len(grayScale)
height := len(grayScale[0])

for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
for y := range height {
for x := range width {
grayScale[x][y], quantErr = quantize(grayScale[x][y], factor)

if x+1 >= width || y+1 >= height || x == 0 {
Expand Down
7 changes: 4 additions & 3 deletions pkg/dithering_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package pkg
package pkg_test

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/theMagicalKarp/dithering/pkg"
)

func TestApplyBasicDither(t *testing.T) {
Expand All @@ -27,7 +28,7 @@ func TestApplyBasicDither(t *testing.T) {
},
}

ApplyDither(img, 1)
pkg.ApplyDither(img, 1)

expected := [][]int{
{
Expand Down Expand Up @@ -71,7 +72,7 @@ func TestApplyBasicDitherWithFactor(t *testing.T) {
},
}

ApplyDither(img, 3)
pkg.ApplyDither(img, 3)

expected := [][]int{
{
Expand Down
12 changes: 6 additions & 6 deletions pkg/gray.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type WritableImage interface {

func NewGreyScale(bounds image.Rectangle) [][]int {
grayscale := make([][]int, bounds.Max.X)
for i := 0; i < bounds.Max.X; i++ {
for i := range bounds.Max.X {
grayscale[i] = make([]int, bounds.Max.Y)
}

Expand All @@ -32,18 +32,18 @@ func NewGreyScale(bounds image.Rectangle) [][]int {

func ReadGreyScale(src ReadableImage, dst [][]int) {
bounds := src.Bounds()
for x := 0; x < bounds.Max.X; x++ {
for y := 0; y < bounds.Max.Y; y++ {
for x := range bounds.Max.X {
for y := range bounds.Max.Y {
dst[x][y] = toGray(src.At(x, y))
}
}
}

func WriteGrayScale(src [][]int, dst WritableImage) {
bounds := dst.Bounds()
for x := 0; x < bounds.Max.X; x++ {
for y := 0; y < bounds.Max.Y; y++ {
dst.Set(x, y, color.Gray{intToUInt8(src[x][y])})
for x := range bounds.Max.X {
for y := range bounds.Max.Y {
dst.Set(x, y, color.Gray{IntToUInt8(src[x][y])})
}
}
}
18 changes: 10 additions & 8 deletions pkg/gray_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package pkg
package pkg_test

import (
"encoding/base64"
Expand All @@ -8,6 +8,7 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/theMagicalKarp/dithering/pkg"
)

func TestNewGreyScale(t *testing.T) {
Expand All @@ -23,7 +24,7 @@ func TestNewGreyScale(t *testing.T) {
{0, 0, 0, 0, 0},
}

assert.Equal(t, expected, NewGreyScale(bounds))
assert.Equal(t, expected, pkg.NewGreyScale(bounds))
}

func TestReadGreyScale(t *testing.T) {
Expand All @@ -32,7 +33,7 @@ func TestReadGreyScale(t *testing.T) {
const rawGopher = `iVBORw0KGgoAAAANSUhEUgAAAEsAAAA8CAAAAAALAhhPAAAFfUlEQVRYw62XeWwUVRzHf2+OPbo9d7tsWyiyaZti6eWGAhISoIGKECEKCAiJJkYTiUgTMYSIosYYBBIUIxoSPIINEBDi2VhwkQrVsj1ESgu9doHWdrul7ba73WNm3vOPtsseM9MdwvvrzTs+8/t95ze/33sI5BqiabU6m9En8oNjduLnAEDLUsQXFF8tQ5oxK3vmnNmDSMtrncks9Hhtt/qeWZapHb1ha3UqYSWVl2ZmpWgaXMXGohQAvmeop3bjTRtv6SgaK/Pb9/bFzUrYslbFAmHPp+3WhAYdr+7GN/YnpN46Opv55VDsJkoEpMrY/vO2BIYQ6LLvm0ThY3MzDzzeSJeeWNyTkgnIE5ePKsvKlcg/0T9QMzXalwXMlj54z4c0rh/mzEfr+FgWEz2w6uk8dkzFAgcARAgNp1ZYef8bH2AgvuStbc2/i6CiWGj98y2tw2l4FAXKkQBIf+exyRnteY83LfEwDQAYCoK+P6bxkZm/0966LxcAAILHB56kgD95PPxltuYcMtFTWw/FKkY/6Opf3GGd9ZF+Qp6mzJxzuRSractOmJrH1u8XTvWFHINNkLQLMR+XHXvfPPHw967raE1xxwtA36IMRfkAAG29/7mLuQcb2WOnsJReZGfpiHsSBX81cvMKywYZHhX5hFPtOqPGWZCXnhWGAu6lX91ElKXSalcLXu3UaOXVay57ZSe5f6Gpx7J2MXAsi7EqSp09b/MirKSyJfnfEEgeDjl8FgDAfvewP03zZ+AJ0m9aFRM8eEHBDRKjfcreDXnZdQuAxXpT2NRJ7xl3UkLBhuVGU16gZiGOgZmrSbRdqkILuL/yYoSXHHkl9KXgqNu3PB8oRg0geC5vFmLjad6mUyTKLmF3OtraWDIfACyXqmephaDABawfpi6tqqBZytfQMqOz6S09iWXhktrRaB8Xz4Yi/8gyABDm5NVe6qq/3VzPrcjELWrebVuyY2T7ar4zQyybUCtsQ5Es1FGaZVrRVQwAgHGW2ZCRZshI5bGQi7HesyE972pOSeMM0dSktlzxRdrlqb3Osa6CCS8IJoQQQgBAbTAa5l5epO34rJszibJI8rxLfGzcp1dRosutGeb2VDNgqYrwTiPNsLxXiPi3dz7LiS1WBRBDBOnqEjyy3aQb+/bLiJzz9dIkscVBBLxMfSEac7kO4Fpkngi0ruNBeSOal+u8jgOuqPz12nryMLCniEjtOOOmpt+KEIqsEdocJjYXwrh9OZqWJQyPCTo67LNS/TdxLAv6R5ZNK9npEjbYdT33gRo4o5oTqR34R+OmaSzDBWsAIPhuRcgyoteNi9gF0KzNYWVItPf2TLoXEg+7isNC7uJkgo1iQWOfRSP9NR11RtbZZ3OMG/VhL6jvx+J1m87+RCfJChAtEBQkSBX2PnSiihc/Twh3j0h7qdYQAoRVsRGmq7HU2QRbaxVGa1D6nIOqaIWRjyRZpHMQKWKpZM5feA+lzC4ZFultV8S6T0mzQGhQohi5I8iw+CsqBSxhFMuwyLgSwbghGb0AiIKkSDmGZVmJSiKihsiyOAUs70UkywooYP0bii9GdH4sfr1UNysd3fUyLLMQN+rsmo3grHl9VNJHbbwxoa47Vw5gupIqrZcjPh9R4Nye3nRDk199V+aetmvVtDRE8/+cbgAAgMIWGb3UA0MGLE9SCbWX670TDy1y98c3D27eppUjsZ6fql3jcd5rUe7+ZIlLNQny3Rd+E5Tct3WVhTM5RBCEdiEK0b6B+/ca2gYU393nFj/n1AygRQxPIUA043M42u85+z2SnssKrPl8Mx76NL3E6eXc3be7OD+H4WHbJkKI8AU8irbITQjZ+0hQcPEgId/Fn/pl9crKH02+5o2b9T/eMx7pKoskYgAAAABJRU5ErkJggg==`

src, err := png.Decode(base64.NewDecoder(base64.StdEncoding, strings.NewReader(rawGopher)))
assert.Nil(t, err)
assert.NoError(t, err)

expected := [][]int{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Expand Down Expand Up @@ -112,14 +113,15 @@ func TestReadGreyScale(t *testing.T) {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}

dst := NewGreyScale(image.Rect(0, 0, 75, 60))
ReadGreyScale(src, dst)
dst := pkg.NewGreyScale(image.Rect(0, 0, 75, 60))
pkg.ReadGreyScale(src, dst)

assert.Equal(t, expected, dst)
}

func TestWriteGrayScale(t *testing.T) {
t.Parallel()

src := [][]int{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Expand Down Expand Up @@ -199,10 +201,10 @@ func TestWriteGrayScale(t *testing.T) {
}
bounds := image.Rect(0, 0, 75, 60)
dst := image.NewNRGBA(bounds)
WriteGrayScale(src, dst)
pkg.WriteGrayScale(src, dst)

for x := 0; x < bounds.Max.X; x++ {
for y := 0; y < bounds.Max.Y; y++ {
for x := range bounds.Max.X {
for y := range bounds.Max.Y {
r, g, b, a := dst.At(x, y).RGBA()
assert.Equal(t, uint32(src[x][y])*257, r)
assert.Equal(t, uint32(src[x][y])*257, g)
Expand Down
3 changes: 2 additions & 1 deletion pkg/utils.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package pkg

func intToUInt8(value int) uint8 {
func IntToUInt8(value int) uint8 {
if value < 0 {
return 0
}

if value > 255 {
return 255
}
Expand Down
Loading
Loading