reorg, and parallel processing

This commit is contained in:
Celogeek 2022-12-26 11:53:47 +01:00
parent 6e37d41edf
commit 8c1fd4cd79
Signed by: celogeek
GPG Key ID: E6B7BDCFC446233A
2 changed files with 77 additions and 75 deletions

View File

@ -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
View File

@ -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()
} }