-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
H3Cki
committed
Mar 22, 2023
1 parent
d0b534e
commit 9868d7d
Showing
35 changed files
with
1,431 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
*_crop* | ||
!*.go | ||
|
||
# Binaries for programs and plugins | ||
*.exe | ||
*.exe~ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
// Use IntelliSense to learn about possible attributes. | ||
// Hover to view descriptions of existing attributes. | ||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | ||
"version": "0.2.0", | ||
"configurations": [ | ||
{ | ||
"name": "CLI", | ||
"type": "go", | ||
"request": "launch", | ||
"mode": "auto", | ||
"program": "${workspaceFolder}/cmd", | ||
"console": "integratedTerminal", | ||
"args": ["i", "--suffix", "_c" , "../testdata/rect.png"] | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,286 @@ | ||
# croppingo | ||
# gocrop | ||
|
||
gocrop provides a CLI and an API for cropping transparent images. | ||
|
||
# Installation | ||
In order to use the API: | ||
``` | ||
go get github.com/H3Cki/gocrop | ||
``` | ||
|
||
In order to install the CLI: | ||
``` | ||
go install github.com/H3Cki/gocrop@latest | ||
``` | ||
|
||
# How it works | ||
All transparent pixels (or at least those with alpha value higher than the provided threshold) are discarded in all directions, left, top, right, bottom. If padding option was used the cropped image will be extended by the provided padding amount, equally in all directions. Examples (with hacky border to visualize the image size better, I suggest opening the image anyways): | ||
|
||
Original image: | ||
|
||
<kbd> | ||
<img src="https://hecki.codes/gocrop/circle.png"> | ||
</kbd> | ||
|
||
Cropped image: | ||
|
||
<kbd> | ||
<img src="https://hecki.codes/gocrop/circle_cropped.png"> | ||
</kbd> | ||
|
||
Cropped and padded image: | ||
|
||
<kbd> | ||
<img src="https://hecki.codes/gocrop/circle_cropped_padded.png"> | ||
</kbd> | ||
|
||
# CLI Examples | ||
|
||
### 1. Crop specific images and output them with `_cropped` suffix: | ||
|
||
Directory tree before: | ||
``` | ||
├─ img1.png | ||
├─ img2.png | ||
├─ img3.png | ||
``` | ||
|
||
Directory tree after: | ||
``` | ||
├─ img1.png | ||
├─ img1_cropped.png | ||
├─ img2.png | ||
├─ img2_cropped.png | ||
├─ img3.png | ||
``` | ||
|
||
```cli | ||
gocrop image --suffix _cropped img1.png img2.png | ||
``` | ||
|
||
### 2. Crop all images which file name matches a regex, in specific directories and all their subdirectories, output results into `images/cropped`: | ||
|
||
Directory tree before: | ||
``` | ||
dir1/ | ||
├─ img1.png | ||
├─ img2.gif | ||
dir2/ | ||
├─ img3.gif | ||
``` | ||
|
||
Directory tree after: | ||
``` | ||
dir1/ | ||
├─ img1.png | ||
├─ img2.gif | ||
dir2/ | ||
├─ img3.gif | ||
images/ | ||
├─ cropped/ | ||
│ ├─ img2.gif | ||
│ ├─ img3.gif | ||
``` | ||
|
||
```cli | ||
gocrop directory --out_dir images/cropped --regex ^.*gif.*$ --recursive dir1 dir2 | ||
``` | ||
|
||
# API Examples | ||
|
||
### 1. Cropping single image | ||
|
||
Directory tree before: | ||
``` | ||
images/ | ||
├─ test.png | ||
``` | ||
|
||
Directory tree after: | ||
``` | ||
images/ | ||
├─ test.png // image is overwritten | ||
``` | ||
|
||
|
||
```go | ||
import ( | ||
"fmt" | ||
|
||
"github.com/H3Cki/gocrop/gocrop" | ||
) | ||
|
||
func main() { | ||
// Load image, doing it this way assures the image is croppable | ||
// and it's format is supported | ||
croppable, err := gocrop.Load("images/test.png") | ||
if err != nil { | ||
fmt.Println(err) | ||
return | ||
} | ||
|
||
// Create cropper with no options (source image will be overwritten) | ||
cropper, _ := gocrop.NewCropper() | ||
if err != nil { | ||
fmt.Println(err) | ||
return | ||
} | ||
|
||
// Crop the image | ||
cropped, ok := cropper.Crop(croppable) | ||
// If ok is false we can skip saving the image because no changes were made | ||
if !ok { | ||
fmt.Println("cropping would make no difference to target image") | ||
return | ||
} | ||
|
||
// Encode and save the image at "images/test.png" | ||
err = cropper.Save(cropped) | ||
if err != nil { | ||
fmt.Println(err) | ||
return | ||
} | ||
} | ||
``` | ||
|
||
|
||
### 2. Cropping single image with 10-pixel padding and saving it in another directory | ||
|
||
Directory tree before: | ||
``` | ||
images/ | ||
├─ test.png | ||
``` | ||
|
||
Directory tree after: | ||
``` | ||
images/ | ||
├─ test.png | ||
cropped/ | ||
├─ test.png | ||
``` | ||
|
||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/H3Cki/gocrop/gocrop" | ||
) | ||
|
||
func main() { | ||
// Load image, doing it this way assures the image is croppable | ||
// and it's format is supported | ||
croppable, err := gocrop.Load("images/test.png") | ||
if err != nil { | ||
fmt.Println(err) | ||
return | ||
} | ||
|
||
// Create a cropper that saves the images in "images/cropped" directory (will be created if doesn't exist) and | ||
// applies a 10px padding to the cropped image. | ||
cropper, err := gocrop.NewCropper( | ||
gocrop.WithOutDir("images/cropped"), | ||
gocrop.WithPadding(10), | ||
) | ||
if err != nil { | ||
fmt.Println(err) | ||
return | ||
} | ||
|
||
// This time we used CropAndSave method for convenience. | ||
err = cropper.CropAndSave(croppable) | ||
if err != nil { | ||
fmt.Println(err) | ||
return | ||
} | ||
} | ||
``` | ||
|
||
|
||
### 3. Cropping all images in all subdirectories and saving them with _cropped suffix in their original directory | ||
|
||
Directory tree before: | ||
``` | ||
images/ | ||
├─ image1.png | ||
├─ avatars/ | ||
│ ├─ avatar1.png | ||
│ ├─ avatar2.png | ||
│ ├─ icons/ | ||
│ │ ├─ icon.png | ||
``` | ||
|
||
Directory tree after: | ||
``` | ||
images/ | ||
├─ image1.png | ||
├─ image1_cropped.png | ||
├─ avatars/ | ||
│ ├─ avatar1.png | ||
│ ├─ avatar1_cropped.png | ||
│ ├─ avatar2.png | ||
│ ├─ avatar2_cropped.png | ||
│ ├─ icons/ | ||
│ │ ├─ icon.png | ||
│ │ ├─ icon_cropped.png | ||
``` | ||
|
||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/H3Cki/gocrop/gocrop" | ||
) | ||
|
||
func main() { | ||
// Create a finder with recursive option to traverse all subdirectories | ||
finder, err := gocrop.NewFinder(gocrop.WithRecursive(true)) | ||
if err != nil { | ||
fmt.Println(err) | ||
return | ||
} | ||
|
||
directories := []string{"."} | ||
|
||
// Find all images in supported formats and wrap them in Croppable | ||
croppables, err := finder.Find(directories) | ||
if err != nil { | ||
fmt.Println(err) | ||
return | ||
} | ||
|
||
// Create a cropper with OutSuffix option that will append "_cropped" to the end of cropped images when saving them | ||
cropper, err := gocrop.NewCropper(gocrop.WithOutSuffix("_cropped")) | ||
if err != nil { | ||
fmt.Println(err) | ||
return | ||
} | ||
|
||
// Iterate over found croppables | ||
for _, croppable := range croppables { | ||
// Load the image (loads from croppable.Path and decodes it using croppable.Decode) | ||
if err := croppable.Load(); err != nil { | ||
continue | ||
} | ||
|
||
// Crop and save it | ||
if err := cropper.CropAndSave(croppable); err != nil { | ||
fmt.Printf("error cropping %s: %s\n", croppable.Path, err.Error()) | ||
} | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
module github.com/H3Cki/gocrop | ||
|
||
go 1.20 | ||
|
||
require ( | ||
github.com/stretchr/testify v1.8.2 | ||
github.com/urfave/cli/v2 v2.25.0 | ||
golang.org/x/image v0.6.0 | ||
) | ||
|
||
require ( | ||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect | ||
github.com/davecgh/go-spew v1.1.1 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
github.com/russross/blackfriday/v2 v2.1.0 // indirect | ||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect | ||
gopkg.in/yaml.v3 v3.0.1 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= | ||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
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/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 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= | ||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | ||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | ||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | ||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= | ||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= | ||
github.com/urfave/cli/v2 v2.25.0 h1:ykdZKuQey2zq0yin/l7JOm9Mh+pg72ngYMeB0ABn6q8= | ||
github.com/urfave/cli/v2 v2.25.0/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= | ||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= | ||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= | ||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= | ||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | ||
golang.org/x/image v0.6.0 h1:bR8b5okrPI3g/gyZakLZHeWxAR8Dn5CyxXv1hLH5g/4= | ||
golang.org/x/image v0.6.0/go.mod h1:MXLdDR43H7cDJq5GEGXEVeeNhPgi+YYEQ2pC1byI1x0= | ||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= | ||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= | ||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | ||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= | ||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= | ||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= | ||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= | ||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= | ||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= | ||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= | ||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= | ||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
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.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= |
Oops, something went wrong.