From 6295fefa02149a51facab78c0677a0a9f657f62f Mon Sep 17 00:00:00 2001 From: celogeek <65178+celogeek@users.noreply.github.com> Date: Thu, 27 Apr 2023 15:02:12 +0200 Subject: [PATCH] move image transformation to processing --- .../epub/imagefilters/epub_image_filters.go | 70 --------- .../imageprocessing/epub_image_processing.go | 140 ++++++++++++------ .../epub_image_processing_loader.go | 20 ++- 3 files changed, 108 insertions(+), 122 deletions(-) delete mode 100644 internal/epub/imagefilters/epub_image_filters.go diff --git a/internal/epub/imagefilters/epub_image_filters.go b/internal/epub/imagefilters/epub_image_filters.go deleted file mode 100644 index 807692a..0000000 --- a/internal/epub/imagefilters/epub_image_filters.go +++ /dev/null @@ -1,70 +0,0 @@ -package epubimagefilters - -import ( - "image" - - epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image" - "github.com/disintegration/gift" -) - -// create filter to apply to the source -func NewGift(img image.Image, options *epubimage.Options) *gift.GIFT { - g := gift.New() - g.SetParallelization(false) - - if options.Crop { - g.Add(AutoCrop( - img, - options.CropRatioLeft, - options.CropRatioUp, - options.CropRatioRight, - options.CropRatioBottom, - )) - } - if options.AutoRotate && img.Bounds().Dx() > img.Bounds().Dy() { - g.Add(gift.Rotate90()) - } - - if options.Contrast != 0 { - g.Add(gift.Contrast(float32(options.Contrast))) - } - - if options.Brightness != 0 { - g.Add(gift.Brightness(float32(options.Brightness))) - } - - g.Add( - Resize(options.ViewWidth, options.ViewHeight, gift.LanczosResampling), - Pixel(), - ) - return g -} - -// create filters to cut image into 2 equal pieces -func NewGiftSplitDoublePage(options *epubimage.Options) []*gift.GIFT { - gifts := make([]*gift.GIFT, 2) - - gifts[0] = gift.New( - CropSplitDoublePage(options.Manga), - ) - - gifts[1] = gift.New( - CropSplitDoublePage(!options.Manga), - ) - - for _, g := range gifts { - g.SetParallelization(false) - if options.Contrast != 0 { - g.Add(gift.Contrast(float32(options.Contrast))) - } - if options.Brightness != 0 { - g.Add(gift.Brightness(float32(options.Brightness))) - } - - g.Add( - Resize(options.ViewWidth, options.ViewHeight, gift.LanczosResampling), - ) - } - - return gifts -} diff --git a/internal/epub/imageprocessing/epub_image_processing.go b/internal/epub/imageprocessing/epub_image_processing.go index 301b825..d7ebfdf 100644 --- a/internal/epub/imageprocessing/epub_image_processing.go +++ b/internal/epub/imageprocessing/epub_image_processing.go @@ -61,7 +61,7 @@ func LoadImages(o *Options) ([]*epubimage.Image, error) { }) wg := &sync.WaitGroup{} - for i := 0; i < o.Workers; i++ { + for i := 0; i < o.WorkersRatio(50); i++ { wg.Add(1) go func() { defer wg.Done() @@ -69,52 +69,23 @@ func LoadImages(o *Options) ([]*epubimage.Image, error) { for img := range imageInput { src := img.Image - g := epubimagefilters.NewGift(src, o.Image) - // Convert image - dst := image.NewGray(g.Bounds(src.Bounds())) - g.Draw(dst, src) + for part, dst := range TransformImage(src, img.Id, o.Image) { + var raw image.Image + if img.Id == 0 && part == 0 { + raw = dst + } - var raw image.Image - if img.Id == 0 { - raw = dst - } - - imageOutput <- &epubimage.Image{ - Id: img.Id, - Part: 0, - Raw: raw, - Data: epubimagedata.New(img.Id, 0, dst, o.Image.Quality), - Width: dst.Bounds().Dx(), - Height: dst.Bounds().Dy(), - IsCover: img.Id == 0, - DoublePage: src.Bounds().Dx() > src.Bounds().Dy(), - Path: img.Path, - Name: img.Name, - } - - // Auto split double page - // Except for cover - // Only if the src image have width > height and is bigger than the view - if (!o.Image.HasCover || img.Id > 0) && - o.Image.AutoSplitDoublePage && - src.Bounds().Dx() > src.Bounds().Dy() { - gifts := epubimagefilters.NewGiftSplitDoublePage(o.Image) - for i, g := range gifts { - part := i + 1 - dst := image.NewGray(g.Bounds(src.Bounds())) - g.Draw(dst, src) - - imageOutput <- &epubimage.Image{ - Id: img.Id, - Part: part, - Data: epubimagedata.New(img.Id, part, dst, o.Image.Quality), - Width: dst.Bounds().Dx(), - Height: dst.Bounds().Dy(), - IsCover: false, - DoublePage: false, - Path: img.Path, - Name: img.Name, - } + imageOutput <- &epubimage.Image{ + Id: img.Id, + Part: part, + Raw: raw, + Data: epubimagedata.New(img.Id, part, dst, o.Image.Quality), + Width: dst.Bounds().Dx(), + Height: dst.Bounds().Dy(), + IsCover: img.Id == 0 && part == 0, + DoublePage: part == 0 && src.Bounds().Dx() > src.Bounds().Dy(), + Path: img.Path, + Name: img.Name, } } } @@ -153,3 +124,80 @@ func LoadCoverTitleData(img *epubimage.Image, title string, quality int) *epubim return epubimagedata.NewRaw("OEBPS/Images/title.jpg", dst, quality) } + +// transform image into 1 or 3 images +// only doublepage with autosplit has 3 versions +func TransformImage(src image.Image, srcId int, o *epubimage.Options) []image.Image { + var filters, splitFilter []gift.Filter + var images []image.Image + + if o.Crop { + f := epubimagefilters.AutoCrop( + src, + o.CropRatioLeft, + o.CropRatioUp, + o.CropRatioRight, + o.CropRatioBottom, + ) + filters = append(filters, f) + splitFilter = append(splitFilter, f) + } + + if o.AutoRotate && src.Bounds().Dx() > src.Bounds().Dy() { + filters = append(filters, gift.Rotate90()) + } + + if o.Contrast != 0 { + f := gift.Contrast(float32(o.Contrast)) + filters = append(filters, f) + splitFilter = append(splitFilter, f) + } + + if o.Brightness != 0 { + f := gift.Brightness(float32(o.Brightness)) + filters = append(filters, f) + splitFilter = append(splitFilter, f) + } + + filters = append(filters, + epubimagefilters.Resize(o.ViewWidth, o.ViewHeight, gift.LanczosResampling), + epubimagefilters.Pixel(), + ) + + // convert + { + g := gift.New(filters...) + dst := image.NewGray(g.Bounds(src.Bounds())) + g.Draw(dst, src) + images = append(images, dst) + } + + // auto split off + if !o.AutoSplitDoublePage { + return images + } + + // portrait, no need to split + if src.Bounds().Dx() <= src.Bounds().Dy() { + return images + } + + // cover + if o.HasCover && srcId == 0 { + return images + } + + // convert double page + for _, b := range []bool{o.Manga, !o.Manga} { + g := gift.New(splitFilter...) + g.Add( + epubimagefilters.CropSplitDoublePage(b), + epubimagefilters.Resize(o.ViewWidth, o.ViewHeight, gift.LanczosResampling), + ) + dst := image.NewGray(g.Bounds(src.Bounds())) + g.Draw(dst, src) + images = append(images, dst) + } + + return images +} diff --git a/internal/epub/imageprocessing/epub_image_processing_loader.go b/internal/epub/imageprocessing/epub_image_processing_loader.go index 3306fe0..f3a27c2 100644 --- a/internal/epub/imageprocessing/epub_image_processing_loader.go +++ b/internal/epub/imageprocessing/epub_image_processing_loader.go @@ -43,6 +43,14 @@ type Options struct { var errNoImagesFound = errors.New("no images found") +func (o *Options) WorkersRatio(pct int) (nbWorkers int) { + nbWorkers = o.Workers * pct / 100 + if nbWorkers < 1 { + nbWorkers = 1 + } + return +} + func (o *Options) Load() (totalImages int, output chan *tasks, err error) { fi, err := os.Stat(o.Input) if err != nil { @@ -112,8 +120,8 @@ func (o *Options) loadDir() (totalImages int, output chan *tasks, err error) { // read in parallel and get an image output = make(chan *tasks, o.Workers) wg := &sync.WaitGroup{} - wg.Add(o.Workers) - for j := 0; j < o.Workers; j++ { + for j := 0; j < o.WorkersRatio(50); j++ { + wg.Add(1) go func() { defer wg.Done() for job := range jobs { @@ -204,8 +212,8 @@ func (o *Options) loadCbz() (totalImages int, output chan *tasks, err error) { output = make(chan *tasks, o.Workers) wg := &sync.WaitGroup{} - wg.Add(o.Workers) - for j := 0; j < o.Workers; j++ { + for j := 0; j < o.WorkersRatio(50); j++ { + wg.Add(1) go func() { defer wg.Done() for job := range jobs { @@ -323,8 +331,8 @@ func (o *Options) loadCbr() (totalImages int, output chan *tasks, err error) { // send file to the queue output = make(chan *tasks, o.Workers) wg := &sync.WaitGroup{} - wg.Add(o.Workers) - for j := 0; j < o.Workers; j++ { + for j := 0; j < o.WorkersRatio(50); j++ { + wg.Add(1) go func() { defer wg.Done() for job := range jobs {