mirror of
https://github.com/celogeek/go-comic-converter.git
synced 2025-05-24 15:52:38 +02:00
154 lines
2.8 KiB
Go
154 lines
2.8 KiB
Go
package comicconverter
|
|
|
|
import (
|
|
"bytes"
|
|
"image"
|
|
"image/color"
|
|
"image/jpeg"
|
|
"io"
|
|
"os"
|
|
|
|
"golang.org/x/image/draw"
|
|
)
|
|
|
|
func Load(file string) *image.Gray {
|
|
f, err := os.Open(file)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer f.Close()
|
|
|
|
img, _, err := image.Decode(f)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
switch imgt := img.(type) {
|
|
case *image.Gray:
|
|
return imgt
|
|
default:
|
|
newImg := image.NewGray(img.Bounds())
|
|
draw.Draw(newImg, newImg.Bounds(), img, image.Point{}, draw.Src)
|
|
return newImg
|
|
}
|
|
}
|
|
|
|
func isBlank(c color.Color) bool {
|
|
r, g, b, _ := c.RGBA()
|
|
return r > 60000 && g > 60000 && b > 60000
|
|
}
|
|
|
|
func CropMarging(img *image.Gray) *image.Gray {
|
|
imgArea := img.Bounds()
|
|
|
|
LEFT:
|
|
for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
|
|
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
|
|
if !isBlank(img.At(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 !isBlank(img.At(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 !isBlank(img.At(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 !isBlank(img.At(x, y)) {
|
|
break BOTTOM
|
|
}
|
|
}
|
|
imgArea.Max.Y--
|
|
}
|
|
|
|
return img.SubImage(imgArea).(*image.Gray)
|
|
}
|
|
|
|
func Resize(img *image.Gray, w, h int) *image.Gray {
|
|
dim := img.Bounds()
|
|
origWidth := dim.Dx()
|
|
origHeight := dim.Dy()
|
|
|
|
if origWidth == 0 || origHeight == 0 {
|
|
newImg := image.NewGray(image.Rectangle{
|
|
image.Point{0, 0},
|
|
image.Point{w, h},
|
|
})
|
|
draw.Draw(newImg, newImg.Bounds(), image.NewUniform(color.White), newImg.Bounds().Min, draw.Src)
|
|
return newImg
|
|
}
|
|
|
|
width, height := origWidth*h/origHeight, origHeight*w/origWidth
|
|
|
|
if width > w {
|
|
width = w
|
|
}
|
|
if height > h {
|
|
height = h
|
|
}
|
|
|
|
newImg := image.NewGray(image.Rectangle{
|
|
Min: image.Point{0, 0},
|
|
Max: image.Point{width, height},
|
|
})
|
|
|
|
draw.BiLinear.Scale(newImg, newImg.Bounds(), img, img.Bounds(), draw.Src, nil)
|
|
|
|
return newImg
|
|
}
|
|
|
|
func Get(img *image.Gray, quality int) io.Reader {
|
|
b := bytes.NewBuffer([]byte{})
|
|
err := jpeg.Encode(b, img, &jpeg.Options{Quality: quality})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return b
|
|
}
|
|
|
|
func Save(img *image.Gray, output string, quality int) {
|
|
o, err := os.Create(output)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer o.Close()
|
|
|
|
if quality == 0 {
|
|
quality = 75
|
|
}
|
|
|
|
err = jpeg.Encode(o, img, &jpeg.Options{Quality: quality})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func Convert(path string, crop bool, w, h int, quality int) (io.Reader, int, int) {
|
|
img := Load(path)
|
|
if crop {
|
|
img = CropMarging(img)
|
|
}
|
|
img = Resize(img, w, h)
|
|
return Get(img, quality), img.Bounds().Dx(), img.Bounds().Dy()
|
|
}
|