From 7a9796000ec7dceec428055785e940ea28034ce7 Mon Sep 17 00:00:00 2001 From: celogeek <65178+celogeek@users.noreply.github.com> Date: Sun, 25 Dec 2022 19:26:02 +0100 Subject: [PATCH] move to internal --- internal/comic-converter/core.go | 165 +++++++++++++++++++++++++++++++ main.go | 113 ++------------------- 2 files changed, 175 insertions(+), 103 deletions(-) create mode 100644 internal/comic-converter/core.go diff --git a/internal/comic-converter/core.go b/internal/comic-converter/core.go new file mode 100644 index 0000000..8232679 --- /dev/null +++ b/internal/comic-converter/core.go @@ -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 +} diff --git a/main.go b/main.go index b6e04d9..696f89e 100644 --- a/main.go +++ b/main.go @@ -1,111 +1,18 @@ package main import ( - "fmt" - "image" - "image/jpeg" - "os" - - "golang.org/x/image/draw" + comicconverter "go-comic-converter/internal/comic-converter" ) -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() { - f, err := os.Open("/Users/vincent/Downloads/00001.jpg") - if err != nil { - panic(err) - } - defer f.Close() - img, _, err := image.Decode(f) - if err != nil { - panic(err) - } - - 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) - } + comicconverter. + New(comicconverter.ComicConverterOptions{ + Quality: 90, + }). + Load("/Users/vincent/Downloads/00001.jpg"). + GrayScale(). + CropMarging(). + Resize(1860, 2480). + Save("/Users/vincent/Downloads/00001_gray.jpg") }