Upload code

This commit is contained in:
nxshock 2017-06-23 19:18:15 +05:00
parent b055be1d8e
commit 602c4b0993
6 changed files with 227 additions and 1 deletions

View file

@ -1 +1,17 @@
# colorcrop # 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
View 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
View 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
View 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
View 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
View 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)
}