mirror of
https://github.com/celogeek/go-comic-converter.git
synced 2025-05-24 15:52:38 +02:00
reorg, and parallel processing
This commit is contained in:
parent
6e37d41edf
commit
8c1fd4cd79
@ -2,26 +2,14 @@ package comicconverter
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
|
"image/color"
|
||||||
"image/jpeg"
|
"image/jpeg"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"golang.org/x/image/draw"
|
"golang.org/x/image/draw"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ComicConverter struct {
|
func Load(file string) *image.Gray {
|
||||||
Options ComicConverterOptions
|
|
||||||
img *image.Gray
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
f, err := os.Open(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -35,32 +23,26 @@ func (c *ComicConverter) Load(file string) *ComicConverter {
|
|||||||
|
|
||||||
switch imgt := img.(type) {
|
switch imgt := img.(type) {
|
||||||
case *image.Gray:
|
case *image.Gray:
|
||||||
c.img = imgt
|
return imgt
|
||||||
default:
|
default:
|
||||||
newImg := image.NewGray(img.Bounds())
|
newImg := image.NewGray(img.Bounds())
|
||||||
draw.Draw(newImg, newImg.Bounds(), img, image.Point{}, draw.Src)
|
draw.Draw(newImg, newImg.Bounds(), img, image.Point{}, draw.Src)
|
||||||
c.img = newImg
|
return newImg
|
||||||
}
|
}
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ComicConverter) isBlank(x, y int) bool {
|
func isBlank(c color.Color) bool {
|
||||||
r, g, b, _ := c.img.At(x, y).RGBA()
|
r, g, b, _ := c.RGBA()
|
||||||
return r > 60000 && g > 60000 && b > 60000
|
return r > 60000 && g > 60000 && b > 60000
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ComicConverter) CropMarging() *ComicConverter {
|
func CropMarging(img *image.Gray) *image.Gray {
|
||||||
if c.img == nil {
|
imgArea := img.Bounds()
|
||||||
panic("load image first")
|
|
||||||
}
|
|
||||||
|
|
||||||
imgArea := c.img.Bounds()
|
|
||||||
|
|
||||||
LEFT:
|
LEFT:
|
||||||
for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
|
for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
|
||||||
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
|
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
|
||||||
if !c.isBlank(x, y) {
|
if !isBlank(img.At(x, y)) {
|
||||||
break LEFT
|
break LEFT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,7 +52,7 @@ LEFT:
|
|||||||
UP:
|
UP:
|
||||||
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
|
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
|
||||||
for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
|
for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
|
||||||
if !c.isBlank(x, y) {
|
if !isBlank(img.At(x, y)) {
|
||||||
break UP
|
break UP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,7 +62,7 @@ UP:
|
|||||||
RIGHT:
|
RIGHT:
|
||||||
for x := imgArea.Max.X - 1; x >= imgArea.Min.X; x-- {
|
for x := imgArea.Max.X - 1; x >= imgArea.Min.X; x-- {
|
||||||
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
|
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
|
||||||
if !c.isBlank(x, y) {
|
if !isBlank(img.At(x, y)) {
|
||||||
break RIGHT
|
break RIGHT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,40 +72,32 @@ RIGHT:
|
|||||||
BOTTOM:
|
BOTTOM:
|
||||||
for y := imgArea.Max.Y - 1; y >= imgArea.Min.Y; y-- {
|
for y := imgArea.Max.Y - 1; y >= imgArea.Min.Y; y-- {
|
||||||
for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
|
for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
|
||||||
if !c.isBlank(x, y) {
|
if !isBlank(img.At(x, y)) {
|
||||||
break BOTTOM
|
break BOTTOM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
imgArea.Max.Y--
|
imgArea.Max.Y--
|
||||||
}
|
}
|
||||||
|
|
||||||
newImg := image.NewGray(image.Rectangle{
|
return img.SubImage(imgArea).(*image.Gray)
|
||||||
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 = c.img.SubImage(imgArea).(*image.Gray)
|
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ComicConverter) Resize(w, h int) *ComicConverter {
|
func Resize(img *image.Gray, w, h int) *image.Gray {
|
||||||
if c.img == nil {
|
dim := img.Bounds()
|
||||||
panic("load image first")
|
|
||||||
}
|
|
||||||
|
|
||||||
dim := c.img.Bounds()
|
|
||||||
origWidth := dim.Dx()
|
origWidth := dim.Dx()
|
||||||
origHeight := dim.Dy()
|
origHeight := dim.Dy()
|
||||||
|
|
||||||
width, height := 1, 1
|
if origWidth == 0 || origHeight == 0 {
|
||||||
|
newImg := image.NewGray(image.Rectangle{
|
||||||
if origHeight > 0 && origWidth > 0 {
|
image.Point{0, 0},
|
||||||
width, height = origWidth*h/origHeight, origHeight*w/origWidth
|
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 {
|
if width > w {
|
||||||
width = w
|
width = w
|
||||||
}
|
}
|
||||||
@ -136,32 +110,24 @@ func (c *ComicConverter) Resize(w, h int) *ComicConverter {
|
|||||||
Max: image.Point{width, height},
|
Max: image.Point{width, height},
|
||||||
})
|
})
|
||||||
|
|
||||||
draw.BiLinear.Scale(newImg, newImg.Bounds(), c.img, c.img.Bounds(), draw.Src, nil)
|
draw.BiLinear.Scale(newImg, newImg.Bounds(), img, img.Bounds(), draw.Src, nil)
|
||||||
|
|
||||||
c.img = newImg
|
return newImg
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ComicConverter) Save(output string) *ComicConverter {
|
func Save(img *image.Gray, output string, quality int) {
|
||||||
if c.img == nil {
|
|
||||||
panic("load image first")
|
|
||||||
}
|
|
||||||
o, err := os.Create(output)
|
o, err := os.Create(output)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
defer o.Close()
|
defer o.Close()
|
||||||
|
|
||||||
quality := 75
|
if quality == 0 {
|
||||||
if c.Options.Quality > 0 {
|
quality = 75
|
||||||
quality = c.Options.Quality
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = jpeg.Encode(o, c.img, &jpeg.Options{Quality: quality})
|
err = jpeg.Encode(o, img, &jpeg.Options{Quality: quality})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
}
|
||||||
|
58
main.go
58
main.go
@ -3,20 +3,56 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
comicconverter "go-comic-converter/internal/comic-converter"
|
comicconverter "go-comic-converter/internal/comic-converter"
|
||||||
|
"io/fs"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
type Todo struct {
|
||||||
cv := comicconverter.
|
Input string
|
||||||
New(comicconverter.ComicConverterOptions{
|
Output string
|
||||||
Quality: 75,
|
}
|
||||||
})
|
|
||||||
|
|
||||||
for i := 1; i < 10; i++ {
|
func main() {
|
||||||
cv.
|
wg := &sync.WaitGroup{}
|
||||||
Load(fmt.Sprintf("/Users/vincent/Downloads/0000%d.jpg", i)).
|
todos := make(chan Todo, runtime.NumCPU())
|
||||||
CropMarging().
|
|
||||||
Resize(1860, 2480).
|
wg.Add(runtime.NumCPU())
|
||||||
Save(fmt.Sprintf("/Users/vincent/Downloads/0000%d_gray.jpg", i))
|
for i := 0; i < runtime.NumCPU(); i++ {
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
for todo := range todos {
|
||||||
|
fmt.Printf("Processing %s\n", todo.Input)
|
||||||
|
comicconverter.Save(
|
||||||
|
comicconverter.Resize(
|
||||||
|
comicconverter.CropMarging(
|
||||||
|
comicconverter.Load(todo.Input),
|
||||||
|
), 1860, 2480), todo.Output, 75,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dirname := "/Users/vincent/Downloads/Bleach T01 (Tite KUBO) [eBook officiel 1920]"
|
||||||
|
filepath.WalkDir(dirname, func(path string, d fs.DirEntry, err error) error {
|
||||||
|
if d.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
input := path
|
||||||
|
ext := filepath.Ext(path)
|
||||||
|
if strings.ToLower(ext) != ".jpg" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
output := fmt.Sprintf("%s_gray%s", input[0:len(input)-len(ext)], ext)
|
||||||
|
|
||||||
|
todos <- Todo{input, output}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
close(todos)
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user