mirror of
https://github.com/nxshock/colorcrop.git
synced 2025-07-02 00:23:44 +05:00
Upload code
This commit is contained in:
parent
b055be1d8e
commit
602c4b0993
6 changed files with 227 additions and 1 deletions
16
README.md
16
README.md
|
@ -1 +1,17 @@
|
|||
# colorcrop
|
||||
|
||||
Go library for cropping images by removing borders with specified color.
|
||||
|
||||
## Installation
|
||||
|
||||
`go get -u github.com/nxshock/colorcrop`
|
||||
|
||||
## Usage
|
||||
|
||||
Crop white borders with 50% of thresold:
|
||||
|
||||
`croppedImage := colorcrop.Crop(sourceImage, color.RGBA{255, 255, 255, 255}, 0.5)`
|
||||
|
||||
## Examples
|
||||
|
||||
See in "examples".
|
||||
|
|
67
colorcrop.go
Normal file
67
colorcrop.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
// Go library for cropping images by removing borders with specified color.
|
||||
package colorcrop
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
// Crop returns cropped image with default comparator.
|
||||
func Crop(img image.Image, color color.Color, thresold float64) image.Image {
|
||||
return CropWithComparator(img, color, thresold, CmpRGBComponentsDiff)
|
||||
}
|
||||
|
||||
// Crop returns cropped image with specified comparator.
|
||||
func CropWithComparator(img image.Image, color color.Color, thresold float64, comparator comparator) image.Image {
|
||||
return img.(interface {
|
||||
SubImage(r image.Rectangle) image.Image
|
||||
}).SubImage(cropRectanle(img, color, thresold, comparator))
|
||||
}
|
||||
|
||||
// cropRectanle returns rectangle of image without borders.
|
||||
func cropRectanle(img image.Image, color color.Color, thresold float64, comparator comparator) image.Rectangle {
|
||||
rectangle := img.Bounds()
|
||||
|
||||
TopLoop:
|
||||
for y := rectangle.Min.Y; y < rectangle.Max.Y; y++ {
|
||||
rectangle.Min.Y = y
|
||||
for x := rectangle.Min.X; x < rectangle.Max.X; x++ {
|
||||
if comparator(img.At(x, y), color) > thresold {
|
||||
break TopLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BottomLoop:
|
||||
for y := rectangle.Max.Y - 1; y >= rectangle.Min.Y; y-- {
|
||||
rectangle.Max.Y = y + 1
|
||||
for x := rectangle.Min.X; x < rectangle.Max.X; x++ {
|
||||
if comparator(img.At(x, y), color) > thresold {
|
||||
break BottomLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LeftLoop:
|
||||
for x := rectangle.Min.X; x < rectangle.Max.X; x++ {
|
||||
rectangle.Min.X = x
|
||||
for y := rectangle.Min.Y; y < rectangle.Max.Y; y++ {
|
||||
if comparator(img.At(x, y), color) > thresold {
|
||||
break LeftLoop
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RightLoop:
|
||||
for x := rectangle.Max.X - 1; x >= rectangle.Min.X; x-- {
|
||||
rectangle.Max.X = x + 1
|
||||
for y := rectangle.Min.Y; y < rectangle.Max.Y; y++ {
|
||||
if comparator(img.At(x, y), color) > thresold {
|
||||
break RightLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rectangle
|
||||
}
|
32
comparators.go
Normal file
32
comparators.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
package colorcrop
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"math"
|
||||
)
|
||||
|
||||
// comparator is a function that returns a difference between two colors in
|
||||
// range 0.0..1.0.
|
||||
type comparator func(color.Color, color.Color) float64
|
||||
|
||||
// CmpColorDifference returns difference of two colors
|
||||
func CmpSquareRGBComponentsDiff(color1 color.Color, color2 color.Color) float64 {
|
||||
const maxDiff = 113509.94967402637 // Difference between black and white colors
|
||||
|
||||
r1, g1, b1, _ := color1.RGBA()
|
||||
r2, g2, b2, _ := color2.RGBA()
|
||||
return math.Sqrt(math.Pow(float64(r2)-float64(r1), 2.0)+
|
||||
math.Pow(float64(g2)-float64(g1), 2.0)+
|
||||
math.Pow(float64(b2)-float64(b1), 2.0)) / maxDiff
|
||||
}
|
||||
|
||||
// CmpColorDifference returns difference of two colors.
|
||||
func CmpRGBComponentsDiff(color1 color.Color, color2 color.Color) float64 {
|
||||
const maxDiff = 765 // Difference between black and white colors
|
||||
|
||||
r1, g1, b1, _ := color1.RGBA()
|
||||
r2, g2, b2, _ := color2.RGBA()
|
||||
return math.Sqrt(math.Abs(float64(r2)-float64(r1))+
|
||||
math.Abs(float64(g2)-float64(g1))+
|
||||
math.Abs(float64(b2)-float64(b1))) / maxDiff
|
||||
}
|
41
comparators_test.go
Normal file
41
comparators_test.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
package colorcrop
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestColorComparators(t *testing.T) {
|
||||
type In struct {
|
||||
color1 color.Color
|
||||
color2 color.Color
|
||||
}
|
||||
|
||||
comparators := []comparator{CmpSquareRGBComponentsDiff, CmpRGBComponentsDiff}
|
||||
|
||||
tests := []struct {
|
||||
in In
|
||||
out float64
|
||||
commentary string
|
||||
}{
|
||||
{in: In{color.RGBA{0, 0, 0, 255}, color.RGBA{255, 255, 255, 255}},
|
||||
out: 1.00,
|
||||
commentary: "Difference between black and white colors"},
|
||||
{in: In{color.RGBA{255, 255, 255, 255}, color.RGBA{255, 255, 255, 255}},
|
||||
out: 0.00,
|
||||
commentary: "Difference between same colors"},
|
||||
{in: In{color.RGBA{255, 255, 255, 0}, color.RGBA{255, 255, 255, 255}},
|
||||
out: 0.00,
|
||||
commentary: "Difference between same colors with different transparency"},
|
||||
}
|
||||
|
||||
for _, comparator := range comparators {
|
||||
for _, test := range tests {
|
||||
if CmpSquareRGBComponentsDiff(test.in.color2, test.in.color1) != test.out {
|
||||
t.Errorf("%s: %s: expected %.2f, got %.2f", runtime.FuncForPC(reflect.ValueOf(comparator).Pointer()).Name(), test.commentary, test.out, CmpSquareRGBComponentsDiff(test.in.color2, test.in.color1))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
41
example/main.go
Normal file
41
example/main.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"image/png"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/nxshock/colorcrop"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
|
||||
// Read source image
|
||||
sourceFile, err := os.Open("img.png")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
defer sourceFile.Close()
|
||||
|
||||
sourceImage, err := png.Decode(sourceFile)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
// Crop image white border with 50% thresold
|
||||
croppedImage := colorcrop.Crop(sourceImage, color.RGBA{255, 255, 255, 255}, 0.5)
|
||||
|
||||
// Save cropped image
|
||||
croppedFile, err := os.Create("cropped.png")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
defer croppedFile.Close()
|
||||
|
||||
err = png.Encode(croppedFile, croppedImage)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
29
example_test.go
Normal file
29
example_test.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package colorcrop_test
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"image/png"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/nxshock/colorcrop"
|
||||
)
|
||||
|
||||
func Example() {
|
||||
log.SetFlags(0)
|
||||
|
||||
// Read source image
|
||||
sourceFile, _ := os.Open("img.png")
|
||||
defer sourceFile.Close()
|
||||
|
||||
sourceImage, _ := png.Decode(sourceFile)
|
||||
|
||||
// Crop image white border with 50% thresold
|
||||
croppedImage := colorcrop.Crop(sourceImage, color.RGBA{255, 255, 255, 255}, 0.5)
|
||||
|
||||
// Save cropped image
|
||||
croppedFile, _ := os.Create("cropped.png")
|
||||
defer croppedFile.Close()
|
||||
|
||||
png.Encode(croppedFile, croppedImage)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue