mirror of
https://github.com/celogeek/go-comic-converter.git
synced 2025-05-24 07:42:37 +02:00
174 lines
3.0 KiB
Go
174 lines
3.0 KiB
Go
package comicconverter
|
|
|
|
import (
|
|
"image"
|
|
"image/jpeg"
|
|
"os"
|
|
|
|
"golang.org/x/image/draw"
|
|
)
|
|
|
|
type ComicConverter struct {
|
|
Options ComicConverterOptions
|
|
img image.Image
|
|
}
|
|
|
|
type ComicConverterOptions struct {
|
|
Quality int
|
|
}
|
|
|
|
func New(opt ComicConverterOptions) *ComicConverter {
|
|
return &ComicConverter{Options: opt}
|
|
}
|
|
|
|
func (c *ComicConverter) Load(file string) *ComicConverter {
|
|
f, err := os.Open(file)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer f.Close()
|
|
|
|
img, _, err := image.Decode(f)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
newImg := image.NewRGBA(img.Bounds())
|
|
draw.Draw(newImg, newImg.Bounds(), img, image.Point{}, draw.Src)
|
|
|
|
c.img = newImg
|
|
|
|
return c
|
|
}
|
|
|
|
func (c *ComicConverter) GrayScale() *ComicConverter {
|
|
if c.img == nil {
|
|
panic("load image first")
|
|
}
|
|
|
|
newImg := image.NewGray(c.img.Bounds())
|
|
|
|
draw.Draw(newImg, newImg.Bounds(), c.img, image.Point{}, draw.Src)
|
|
|
|
c.img = newImg
|
|
|
|
return c
|
|
}
|
|
|
|
func (c *ComicConverter) isBlank(x, y int) bool {
|
|
r, g, b, _ := c.img.At(x, y).RGBA()
|
|
return r > 60000 && g > 60000 && b > 60000
|
|
}
|
|
|
|
func (c *ComicConverter) CropMarging() *ComicConverter {
|
|
if c.img == nil {
|
|
panic("load image first")
|
|
}
|
|
|
|
imgArea := c.img.Bounds()
|
|
|
|
LEFT:
|
|
for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
|
|
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
|
|
if !c.isBlank(x, y) {
|
|
break LEFT
|
|
}
|
|
}
|
|
imgArea.Min.X++
|
|
}
|
|
|
|
UP:
|
|
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
|
|
for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
|
|
if !c.isBlank(x, y) {
|
|
break UP
|
|
}
|
|
}
|
|
imgArea.Min.Y++
|
|
}
|
|
|
|
RIGHT:
|
|
for x := imgArea.Max.X - 1; x >= imgArea.Min.X; x-- {
|
|
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
|
|
if !c.isBlank(x, y) {
|
|
break RIGHT
|
|
}
|
|
}
|
|
imgArea.Max.X--
|
|
}
|
|
|
|
BOTTOM:
|
|
for y := imgArea.Max.Y - 1; y >= imgArea.Min.Y; y-- {
|
|
for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
|
|
if !c.isBlank(x, y) {
|
|
break BOTTOM
|
|
}
|
|
}
|
|
imgArea.Max.Y--
|
|
}
|
|
|
|
newImg := image.NewRGBA(image.Rectangle{
|
|
Min: image.Point{0, 0},
|
|
Max: image.Point{imgArea.Dx(), imgArea.Dy()},
|
|
})
|
|
|
|
draw.Draw(newImg, newImg.Bounds(), c.img, imgArea.Min, draw.Src)
|
|
|
|
c.img = newImg
|
|
|
|
return c
|
|
}
|
|
|
|
func (c *ComicConverter) Resize(w, h int) *ComicConverter {
|
|
if c.img == nil {
|
|
panic("load image first")
|
|
}
|
|
|
|
dim := c.img.Bounds()
|
|
origWidth := dim.Dx()
|
|
origHeight := dim.Dy()
|
|
|
|
width, heigth := origWidth*h/origHeight, origHeight*w/origWidth
|
|
|
|
if width > w {
|
|
width = w
|
|
}
|
|
if heigth > h {
|
|
heigth = h
|
|
}
|
|
|
|
newImg := image.NewRGBA(image.Rectangle{
|
|
Min: image.Point{0, 0},
|
|
Max: image.Point{width, heigth},
|
|
})
|
|
|
|
draw.BiLinear.Scale(newImg, newImg.Bounds(), c.img, c.img.Bounds(), draw.Src, nil)
|
|
|
|
c.img = newImg
|
|
|
|
return c
|
|
}
|
|
|
|
func (c *ComicConverter) Save(output string) *ComicConverter {
|
|
if c.img == nil {
|
|
panic("load image first")
|
|
}
|
|
o, err := os.Create(output)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer o.Close()
|
|
|
|
quality := 75
|
|
if c.Options.Quality > 0 {
|
|
quality = c.Options.Quality
|
|
}
|
|
|
|
err = jpeg.Encode(o, c.img, &jpeg.Options{Quality: quality})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return c
|
|
}
|