mirror of
https://github.com/celogeek/go-comic-converter.git
synced 2025-05-24 15:52:38 +02:00
move to internal
This commit is contained in:
parent
892c0ca320
commit
7a9796000e
165
internal/comic-converter/core.go
Normal file
165
internal/comic-converter/core.go
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
package comicconverter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"image/jpeg"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/image/draw"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ComicConverter struct {
|
||||||
|
Options ComicConverterOptions
|
||||||
|
img image.Image
|
||||||
|
grayImg *image.Gray16
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.img = img
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ComicConverter) GrayScale() *ComicConverter {
|
||||||
|
if c.img == nil {
|
||||||
|
panic("load image first")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.grayImg = image.NewGray16(c.img.Bounds())
|
||||||
|
|
||||||
|
draw.Draw(c.grayImg, c.grayImg.Bounds(), c.img, image.Point{}, draw.Src)
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ComicConverter) CropMarging() *ComicConverter {
|
||||||
|
if c.grayImg == nil {
|
||||||
|
panic("grayscale first")
|
||||||
|
}
|
||||||
|
|
||||||
|
imgArea := c.grayImg.Bounds()
|
||||||
|
colorLimit := color.Gray16{60000}
|
||||||
|
|
||||||
|
LEFT:
|
||||||
|
for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
|
||||||
|
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
|
||||||
|
if c.grayImg.Gray16At(x, y).Y < colorLimit.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.grayImg.Gray16At(x, y).Y < colorLimit.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.grayImg.Gray16At(x, y).Y < colorLimit.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.grayImg.Gray16At(x, y).Y < colorLimit.Y {
|
||||||
|
break BOTTOM
|
||||||
|
}
|
||||||
|
}
|
||||||
|
imgArea.Max.Y--
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("CROP", imgArea)
|
||||||
|
|
||||||
|
c.grayImg = c.grayImg.SubImage(imgArea).(*image.Gray16)
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ComicConverter) Resize(w, h int) *ComicConverter {
|
||||||
|
if c.grayImg == nil {
|
||||||
|
panic("grayscale first")
|
||||||
|
}
|
||||||
|
|
||||||
|
dim := c.grayImg.Bounds()
|
||||||
|
origWidth := dim.Dx()
|
||||||
|
origHeight := dim.Dy()
|
||||||
|
|
||||||
|
width, heigth := origWidth*h/origHeight, origHeight*w/origWidth
|
||||||
|
|
||||||
|
fmt.Println("W:", origWidth, width, h)
|
||||||
|
fmt.Println("H:", origHeight, heigth, w)
|
||||||
|
if width > origWidth {
|
||||||
|
width = origWidth
|
||||||
|
} else if heigth > origHeight {
|
||||||
|
heigth = origHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
imgGray := image.NewGray16(image.Rectangle{
|
||||||
|
Min: image.Point{0, 0},
|
||||||
|
Max: image.Point{width, heigth},
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println("RESIZE", imgGray.Bounds())
|
||||||
|
|
||||||
|
draw.BiLinear.Scale(imgGray, imgGray.Bounds(), c.grayImg, c.grayImg.Bounds(), draw.Src, nil)
|
||||||
|
|
||||||
|
c.grayImg = imgGray
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ComicConverter) Save(output string) *ComicConverter {
|
||||||
|
if c.grayImg == nil {
|
||||||
|
panic("grayscale 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.grayImg, &jpeg.Options{Quality: quality})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
113
main.go
113
main.go
@ -1,111 +1,18 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
comicconverter "go-comic-converter/internal/comic-converter"
|
||||||
"image"
|
|
||||||
"image/jpeg"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"golang.org/x/image/draw"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type KindleSpec struct {
|
|
||||||
Width int
|
|
||||||
Height int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KindleSpec) Bounds() image.Rectangle {
|
|
||||||
return image.Rectangle{
|
|
||||||
Min: image.Point{0, 0},
|
|
||||||
Max: image.Point{k.Width, k.Height},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KindleSpec) ConvertGray16(img image.Image) image.Image {
|
|
||||||
r := detectMarging(img)
|
|
||||||
width, heigth := r.Dx()*k.Height/r.Dy(), r.Dy()*k.Width/r.Dx()
|
|
||||||
if width > k.Width {
|
|
||||||
width = k.Width
|
|
||||||
} else {
|
|
||||||
heigth = k.Height
|
|
||||||
}
|
|
||||||
|
|
||||||
imgGray := image.NewGray16(image.Rectangle{
|
|
||||||
Min: image.Point{0, 0},
|
|
||||||
Max: image.Point{width, heigth},
|
|
||||||
})
|
|
||||||
|
|
||||||
draw.BiLinear.Scale(imgGray, imgGray.Bounds(), img, r, draw.Src, nil)
|
|
||||||
|
|
||||||
return imgGray
|
|
||||||
}
|
|
||||||
|
|
||||||
var KindleScribe = &KindleSpec{1860, 2480}
|
|
||||||
|
|
||||||
func lineIsBlank(img image.Image, y int) bool {
|
|
||||||
for x := 0; x < img.Bounds().Max.X; x++ {
|
|
||||||
r, _, _, _ := img.At(x, y).RGBA()
|
|
||||||
if r < 0xfff {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func colIsBlank(img image.Image, x int) bool {
|
|
||||||
for y := 0; y < img.Bounds().Max.Y; y++ {
|
|
||||||
r, _, _, _ := img.At(x, y).RGBA()
|
|
||||||
if r < 0xfff { // allow a light gray, white = 0xffff
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func detectMarging(img image.Image) image.Rectangle {
|
|
||||||
rect := img.Bounds()
|
|
||||||
|
|
||||||
var xmin, xmax = rect.Min.X, rect.Max.X - 1
|
|
||||||
var ymin, ymax = rect.Min.Y, rect.Max.Y - 1
|
|
||||||
|
|
||||||
for ; ymin < ymax && lineIsBlank(img, ymin); ymin++ {
|
|
||||||
rect.Min.Y++
|
|
||||||
}
|
|
||||||
for ; ymin < ymax && lineIsBlank(img, ymax); ymax-- {
|
|
||||||
rect.Max.Y--
|
|
||||||
}
|
|
||||||
for ; xmin < xmax && colIsBlank(img, xmin); xmin++ {
|
|
||||||
rect.Min.X++
|
|
||||||
}
|
|
||||||
for ; xmin < xmax && colIsBlank(img, xmax); xmax-- {
|
|
||||||
rect.Max.X--
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(rect)
|
|
||||||
return rect
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
f, err := os.Open("/Users/vincent/Downloads/00001.jpg")
|
comicconverter.
|
||||||
if err != nil {
|
New(comicconverter.ComicConverterOptions{
|
||||||
panic(err)
|
Quality: 90,
|
||||||
}
|
}).
|
||||||
defer f.Close()
|
Load("/Users/vincent/Downloads/00001.jpg").
|
||||||
img, _, err := image.Decode(f)
|
GrayScale().
|
||||||
if err != nil {
|
CropMarging().
|
||||||
panic(err)
|
Resize(1860, 2480).
|
||||||
}
|
Save("/Users/vincent/Downloads/00001_gray.jpg")
|
||||||
|
|
||||||
imgGray := KindleScribe.ConvertGray16(img)
|
|
||||||
|
|
||||||
o, err := os.Create("/Users/vincent/Downloads/00001_gray.jpg")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer o.Close()
|
|
||||||
err = jpeg.Encode(o, imgGray, &jpeg.Options{Quality: 90})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user