/* Extract and transform image into a compressed jpeg. */ package epubimageprocessor import ( "fmt" "image" "sync" epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image" epubimagefilters "github.com/celogeek/go-comic-converter/v2/internal/epub/imagefilters" epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options" epubprogress "github.com/celogeek/go-comic-converter/v2/internal/epub/progress" epubzip "github.com/celogeek/go-comic-converter/v2/internal/epub/zip" "github.com/disintegration/gift" ) type LoadedImage struct { Image *epubimage.Image ZipImage *epubzip.ZipImage } type LoadedImages []*LoadedImage func (l LoadedImages) Images() []*epubimage.Image { res := make([]*epubimage.Image, len(l)) for i, v := range l { res[i] = v.Image } return res } type EpubImageProcessor struct { *epuboptions.Options } func New(o *epuboptions.Options) *EpubImageProcessor { return &EpubImageProcessor{o} } // extract and convert images func (e *EpubImageProcessor) Load() (LoadedImages, error) { images := make(LoadedImages, 0) imageCount, imageInput, err := e.load() if err != nil { return nil, err } // dry run, skip convertion if e.Dry { for img := range imageInput { images = append(images, &LoadedImage{ Image: &epubimage.Image{ Id: img.Id, Path: img.Path, Name: img.Name, }, }) } return images, nil } imageOutput := make(chan *LoadedImage) // processing bar := epubprogress.New(epubprogress.Options{ Quiet: e.Quiet, Max: imageCount, Description: "Processing", CurrentJob: 1, TotalJob: 2, }) wg := &sync.WaitGroup{} for i := 0; i < e.WorkersRatio(50); i++ { wg.Add(1) go func() { defer wg.Done() for input := range imageInput { src := input.Image for part, dst := range e.transformImage(src, input.Id) { var raw image.Image if input.Id == 0 && part == 0 { raw = dst } img := &epubimage.Image{ Id: input.Id, Part: part, Raw: raw, Width: dst.Bounds().Dx(), Height: dst.Bounds().Dy(), IsCover: input.Id == 0 && part == 0, DoublePage: part == 0 && src.Bounds().Dx() > src.Bounds().Dy(), Path: input.Path, Name: input.Name, } imageOutput <- &LoadedImage{ Image: img, ZipImage: epubzip.CompressImage(fmt.Sprintf("OEBPS/%s", img.ImgPath()), dst, e.Image.Quality), } } } }() } go func() { wg.Wait() close(imageOutput) }() for output := range imageOutput { if output.Image.Part == 0 { bar.Add(1) } if e.Image.NoBlankPage && output.Image.Width == 1 && output.Image.Height == 1 { continue } images = append(images, output) } bar.Close() if len(images) == 0 { return nil, errNoImagesFound } return images, nil } // transform image into 1 or 3 images // only doublepage with autosplit has 3 versions func (e *EpubImageProcessor) transformImage(src image.Image, srcId int) []image.Image { var filters, splitFilter []gift.Filter var images []image.Image if e.Image.Crop.Enabled { f := epubimagefilters.AutoCrop( src, e.Image.Crop.Left, e.Image.Crop.Up, e.Image.Crop.Right, e.Image.Crop.Bottom, ) filters = append(filters, f) splitFilter = append(splitFilter, f) } if e.Image.AutoRotate && src.Bounds().Dx() > src.Bounds().Dy() { filters = append(filters, gift.Rotate90()) } if e.Image.Contrast != 0 { f := gift.Contrast(float32(e.Image.Contrast)) filters = append(filters, f) splitFilter = append(splitFilter, f) } if e.Image.Brightness != 0 { f := gift.Brightness(float32(e.Image.Brightness)) filters = append(filters, f) splitFilter = append(splitFilter, f) } filters = append(filters, epubimagefilters.Resize(e.Image.View.Width, e.Image.View.Height, 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 !e.Image.AutoSplitDoublePage { return images } // portrait, no need to split if src.Bounds().Dx() <= src.Bounds().Dy() { return images } // cover if e.Image.HasCover && srcId == 0 { return images } // convert double page for _, b := range []bool{e.Image.Manga, !e.Image.Manga} { g := gift.New(splitFilter...) g.Add( epubimagefilters.CropSplitDoublePage(b), epubimagefilters.Resize(e.Image.View.Width, e.Image.View.Height, gift.LanczosResampling), ) dst := image.NewGray(g.Bounds(src.Bounds())) g.Draw(dst, src) images = append(images, dst) } return images } // create a title page with the cover func (e *EpubImageProcessor) CoverTitleData(img image.Image, title string) *epubzip.ZipImage { // Create a blur version of the cover g := gift.New(epubimagefilters.CoverTitle(title)) dst := image.NewGray(g.Bounds(img.Bounds())) g.Draw(dst, img) return epubzip.CompressImage("OEBPS/Images/title.jpg", dst, e.Image.Quality) }