diff --git a/internal/pkg/converter/converter.go b/internal/pkg/converter/converter.go index c0703c8..50e85ac 100644 --- a/internal/pkg/converter/converter.go +++ b/internal/pkg/converter/converter.go @@ -15,6 +15,7 @@ import ( "reflect" "regexp" "runtime" + "slices" "strings" "time" @@ -131,7 +132,7 @@ func (c *Converter) InitParse() { c.AddStringParam(&c.Options.Image.View.Color.Foreground, "foreground-color", c.Options.Image.View.Color.Foreground, "Foreground color in hexadecimal format RGB. Black=000, White=FFF") c.AddStringParam(&c.Options.Image.View.Color.Background, "background-color", c.Options.Image.View.Color.Background, "Background color in hexadecimal format RGB. Black=000, White=FFF, Light Gray=DDD, Dark Gray=777") c.AddBoolParam(&c.Options.Image.Resize, "resize", c.Options.Image.Resize, "Reduce image size if exceed device size") - c.AddStringParam(&c.Options.Image.Format, "format", c.Options.Image.Format, "Format of output images: jpeg (lossy), png (lossless)") + c.AddStringParam(&c.Options.Image.Format, "format", c.Options.Image.Format, "Format of output images: jpeg (lossy), png (lossless), copy (no processing)") c.AddFloatParam(&c.Options.Image.View.AspectRatio, "aspect-ratio", c.Options.Image.View.AspectRatio, "Aspect ratio (height/width) of the output\n -1 = same as device\n 0 = same as source\n1.6 = amazon advice for kindle") c.AddBoolParam(&c.Options.Image.View.PortraitOnly, "portrait-only", c.Options.Image.View.PortraitOnly, "Portrait only: force orientation to portrait only.") c.AddIntParam(&c.Options.TitlePage, "titlepage", c.Options.TitlePage, "Title page\n0 = never\n1 = always\n2 = only if epub is split") @@ -379,8 +380,8 @@ func (c *Converter) Validate() error { } // Format - if !(c.Options.Image.Format == "jpeg" || c.Options.Image.Format == "png") { - return errors.New("format should be jpeg or png") + if !slices.Contains([]string{"jpeg", "png", "copy"}, c.Options.Image.Format) { + return errors.New("format should be jpeg, png or copy") } // Aspect Ratio diff --git a/internal/pkg/epubimage/epub_image.go b/internal/pkg/epubimage/epub_image.go index 578e933..eb61663 100644 --- a/internal/pkg/epubimage/epub_image.go +++ b/internal/pkg/epubimage/epub_image.go @@ -73,6 +73,11 @@ func (i EPUBImage) EPUBImgPath() string { return "OEBPS/" + i.ImgPath() } +// MediaType of the epub image +func (i EPUBImage) MediaType() string { + return "image/" + i.Format +} + // ImgStyle style to apply to the image. // // center by default. diff --git a/internal/pkg/epubimagepassthrough/passthrough.go b/internal/pkg/epubimagepassthrough/passthrough.go new file mode 100644 index 0000000..93a5297 --- /dev/null +++ b/internal/pkg/epubimagepassthrough/passthrough.go @@ -0,0 +1,432 @@ +package epubimagepassthrough + +import ( + "archive/zip" + "bytes" + "errors" + "fmt" + "image" + "image/jpeg" + "image/png" + "io" + "io/fs" + "os" + "path/filepath" + "sort" + "strings" + + "github.com/nwaples/rardecode/v2" + + "github.com/celogeek/go-comic-converter/v3/internal/pkg/epubimage" + "github.com/celogeek/go-comic-converter/v3/internal/pkg/epubimageprocessor" + "github.com/celogeek/go-comic-converter/v3/internal/pkg/epubprogress" + "github.com/celogeek/go-comic-converter/v3/internal/pkg/epubzip" + "github.com/celogeek/go-comic-converter/v3/internal/pkg/sortpath" + "github.com/celogeek/go-comic-converter/v3/pkg/epuboptions" +) + +type ePUBImagePassthrough struct { + epuboptions.EPUBOptions +} + +func (e ePUBImagePassthrough) Load() (images []epubimage.EPUBImage, err error) { + fi, err := os.Stat(e.Input) + if err != nil { + return + } + + if fi.IsDir() { + return e.loadDir() + } else { + switch ext := strings.ToLower(filepath.Ext(e.Input)); ext { + case ".cbz", ".zip": + return e.loadCbz() + case ".cbr", ".rar": + return e.loadCbr() + default: + return nil, fmt.Errorf("unknown file format (%s): support .cbz, .zip, .cbr, .rar", ext) + } + } +} + +func (e ePUBImagePassthrough) CoverTitleData(o epubimageprocessor.CoverTitleDataOptions) (epubzip.Image, error) { + return epubimageprocessor.New(e.EPUBOptions).CoverTitleData(o) +} + +var errNoImagesFound = errors.New("no images found") + +func New(o epuboptions.EPUBOptions) epubimageprocessor.EPUBImageProcessor { + return ePUBImagePassthrough{o} +} + +func (e ePUBImagePassthrough) loadDir() (images []epubimage.EPUBImage, err error) { + imagesPath := make([]string, 0) + + input := filepath.Clean(e.Input) + err = filepath.WalkDir(input, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + if !d.IsDir() && e.isSupportedImage(path) { + imagesPath = append(imagesPath, path) + } + + return nil + }) + + if err != nil { + return + } + + if len(imagesPath) == 0 { + err = errNoImagesFound + return + } + + sort.Sort(sortpath.By(imagesPath, e.SortPathMode)) + + var imgStorage epubzip.StorageImageWriter + imgStorage, err = epubzip.NewStorageImageWriter(e.ImgStorage(), e.Image.Format) + if err != nil { + return + } + defer imgStorage.Close() + + // processing + bar := epubprogress.New(epubprogress.Options{ + Quiet: e.Quiet, + Json: e.Json, + Max: len(imagesPath), + Description: "Copying", + CurrentJob: 1, + TotalJob: 2, + }) + defer bar.Close() + + for i, imgPath := range imagesPath { + + var img epubimage.EPUBImage + img, err = e.copyRawDataToStorage( + imgStorage, + func() ([]byte, error) { + f, err := os.Open(imgPath) + if err != nil { + return nil, err + } + defer f.Close() + return io.ReadAll(f) + }, + i, + input, + imgPath, + ) + if err != nil { + return + } + + images = append(images, img) + _ = bar.Add(1) + } + + if len(images) == 0 { + err = errNoImagesFound + } + + return + +} + +func (e ePUBImagePassthrough) loadCbz() (images []epubimage.EPUBImage, err error) { + images = make([]epubimage.EPUBImage, 0) + + input := filepath.Clean(e.Input) + r, err := zip.OpenReader(input) + if err != nil { + return + } + defer r.Close() + + imagesZip := make([]*zip.File, 0) + for _, f := range r.File { + if !f.FileInfo().IsDir() && e.isSupportedImage(f.Name) { + imagesZip = append(imagesZip, f) + } + } + + if len(imagesZip) == 0 { + err = errNoImagesFound + return + } + + var names []string + for _, img := range imagesZip { + names = append(names, img.Name) + } + + sort.Sort(sortpath.By(names, e.SortPathMode)) + + indexedNames := make(map[string]int) + for i, name := range names { + indexedNames[name] = i + } + + var imgStorage epubzip.StorageImageWriter + imgStorage, err = epubzip.NewStorageImageWriter(e.ImgStorage(), e.Image.Format) + if err != nil { + return + } + defer imgStorage.Close() + + // processing + bar := epubprogress.New(epubprogress.Options{ + Quiet: e.Quiet, + Json: e.Json, + Max: len(imagesZip), + Description: "Copying", + CurrentJob: 1, + TotalJob: 2, + }) + defer bar.Close() + + for _, imgZip := range imagesZip { + if _, ok := indexedNames[imgZip.Name]; !ok { + continue + } + + var img epubimage.EPUBImage + img, err = e.copyRawDataToStorage( + imgStorage, + func() ([]byte, error) { + f, err := imgZip.Open() + if err != nil { + return nil, err + } + defer f.Close() + + return io.ReadAll(f) + }, + indexedNames[imgZip.Name], + "", + imgZip.Name, + ) + + if err != nil { + return + } + + images = append(images, img) + _ = bar.Add(1) + } + + if len(images) == 0 { + err = errNoImagesFound + } + + return +} + +func (e ePUBImagePassthrough) loadCbr() (images []epubimage.EPUBImage, err error) { + images = make([]epubimage.EPUBImage, 0) + + var isSolid bool + files, err := rardecode.List(e.Input) + if err != nil { + return + } + + names := make([]string, 0) + for _, f := range files { + if !f.IsDir && e.isSupportedImage(f.Name) { + if f.Solid { + isSolid = true + } + names = append(names, f.Name) + } + } + + if len(names) == 0 { + err = errNoImagesFound + return + } + + sort.Sort(sortpath.By(names, e.SortPathMode)) + + indexedNames := make(map[string]int) + for i, name := range names { + indexedNames[name] = i + } + + var imgStorage epubzip.StorageImageWriter + imgStorage, err = epubzip.NewStorageImageWriter(e.ImgStorage(), e.Image.Format) + if err != nil { + return + } + defer imgStorage.Close() + + // processing + bar := epubprogress.New(epubprogress.Options{ + Quiet: e.Quiet, + Json: e.Json, + Max: len(names), + Description: "Copying", + CurrentJob: 1, + TotalJob: 2, + }) + defer bar.Close() + + if isSolid { + var r *rardecode.ReadCloser + r, err = rardecode.OpenReader(e.Input) + if err != nil { + return + } + defer r.Close() + + for { + f, rerr := r.Next() + if rerr != nil { + if rerr == io.EOF { + break + } + err = rerr + return + } + + if _, ok := indexedNames[f.Name]; !ok { + continue + } + + var img epubimage.EPUBImage + img, err = e.copyRawDataToStorage( + imgStorage, + func() ([]byte, error) { + return io.ReadAll(r) + }, + indexedNames[f.Name], + "", + f.Name, + ) + + if err != nil { + return + } + + images = append(images, img) + _ = bar.Add(1) + } + } else { + for _, file := range files { + if i, ok := indexedNames[file.Name]; ok { + var img epubimage.EPUBImage + img, err = e.copyRawDataToStorage( + imgStorage, + func() ([]byte, error) { + f, err := file.Open() + if err != nil { + return nil, err + } + defer f.Close() + return io.ReadAll(f) + }, + i, + "", + file.Name, + ) + + if err != nil { + return + } + + images = append(images, img) + _ = bar.Add(1) + } + } + } + + if len(images) == 0 { + err = errNoImagesFound + } + + return +} + +func (e ePUBImagePassthrough) isSupportedImage(path string) bool { + switch strings.ToLower(filepath.Ext(path)) { + case ".jpg", ".jpeg", ".png": + { + return !strings.HasPrefix(filepath.Base(path), ".") + } + } + return false +} + +func (e ePUBImagePassthrough) copyRawDataToStorage( + imgStorage epubzip.StorageImageWriter, + getData func() ([]byte, error), + id int, + dirname string, + filename string, +) (img epubimage.EPUBImage, err error) { + var uncompressedData []byte + uncompressedData, err = getData() + if err != nil { + return + } + + p, fn := filepath.Split(filepath.Clean(filename)) + if p == dirname { + p = "" + } else { + p = p[len(dirname)+1:] + } + + var ( + format string + decodeConfig func(r io.Reader) (image.Config, error) + decode func(r io.Reader) (image.Image, error) + ) + + switch filepath.Ext(fn) { + case ".png": + format = "png" + decodeConfig = png.DecodeConfig + decode = png.Decode + case ".jpg", ".jpeg": + format = "jpeg" + decodeConfig = jpeg.DecodeConfig + decode = jpeg.Decode + } + + var config image.Config + config, err = decodeConfig(bytes.NewReader(uncompressedData)) + if err != nil { + return + } + + var rawImage image.Image + if id == 0 { + rawImage, err = decode(bytes.NewReader(uncompressedData)) + if err != nil { + return + } + } + + img = epubimage.EPUBImage{ + Id: id, + Part: 0, + Raw: rawImage, + Width: config.Width, + Height: config.Height, + IsBlank: false, + DoublePage: config.Width > config.Height, + Path: p, + Name: fn, + Format: format, + OriginalAspectRatio: float64(config.Height) / float64(config.Width), + } + + err = imgStorage.AddRaw(img.EPUBImgPath(), uncompressedData) + + return +} diff --git a/internal/pkg/epubimageprocessor/loader.go b/internal/pkg/epubimageprocessor/loader.go index a120385..d6848fb 100644 --- a/internal/pkg/epubimageprocessor/loader.go +++ b/internal/pkg/epubimageprocessor/loader.go @@ -43,7 +43,7 @@ type task struct { var errNoImagesFound = errors.New("no images found") // only accept jpg, png and webp as source file -func (e EPUBImageProcessor) isSupportedImage(path string) bool { +func (e ePUBImageProcessor) isSupportedImage(path string) bool { switch strings.ToLower(filepath.Ext(path)) { case ".jpg", ".jpeg", ".png", ".webp", ".tiff": { @@ -53,8 +53,8 @@ func (e EPUBImageProcessor) isSupportedImage(path string) bool { return false } -// Load images from input -func (e EPUBImageProcessor) load() (totalImages int, output chan task, err error) { +// load images from input +func (e ePUBImageProcessor) load() (totalImages int, output chan task, err error) { fi, err := os.Stat(e.Input) if err != nil { return @@ -78,7 +78,7 @@ func (e EPUBImageProcessor) load() (totalImages int, output chan task, err error } } -func (e EPUBImageProcessor) corruptedImage(path, name string) image.Image { +func (e ePUBImageProcessor) corruptedImage(path, name string) image.Image { var w, h float64 = 1200, 1920 f, _ := truetype.Parse(gomonobold.TTF) face := truetype.NewFace(f, &truetype.Options{Size: 64, DPI: 72}) @@ -102,7 +102,7 @@ func (e EPUBImageProcessor) corruptedImage(path, name string) image.Image { } // load a directory of images -func (e EPUBImageProcessor) loadDir() (totalImages int, output chan task, err error) { +func (e ePUBImageProcessor) loadDir() (totalImages int, output chan task, err error) { images := make([]string, 0) input := filepath.Clean(e.Input) @@ -191,7 +191,7 @@ func (e EPUBImageProcessor) loadDir() (totalImages int, output chan task, err er } // load a zip file that include images -func (e EPUBImageProcessor) loadCbz() (totalImages int, output chan task, err error) { +func (e ePUBImageProcessor) loadCbz() (totalImages int, output chan task, err error) { r, err := zip.OpenReader(e.Input) if err != nil { return @@ -277,7 +277,7 @@ func (e EPUBImageProcessor) loadCbz() (totalImages int, output chan task, err er } // load a rar file that include images -func (e EPUBImageProcessor) loadCbr() (totalImages int, output chan task, err error) { +func (e ePUBImageProcessor) loadCbr() (totalImages int, output chan task, err error) { var isSolid bool files, err := rardecode.List(e.Input) if err != nil { @@ -393,7 +393,7 @@ func (e EPUBImageProcessor) loadCbr() (totalImages int, output chan task, err er } // extract image from a pdf -func (e EPUBImageProcessor) loadPdf() (totalImages int, output chan task, err error) { +func (e ePUBImageProcessor) loadPdf() (totalImages int, output chan task, err error) { pdf := pdfread.Load(e.Input) if pdf == nil { err = fmt.Errorf("can't read pdf") diff --git a/internal/pkg/epubimageprocessor/processor.go b/internal/pkg/epubimageprocessor/processor.go index bb2c368..ad2adf6 100644 --- a/internal/pkg/epubimageprocessor/processor.go +++ b/internal/pkg/epubimageprocessor/processor.go @@ -17,16 +17,21 @@ import ( "github.com/celogeek/go-comic-converter/v3/pkg/epuboptions" ) -type EPUBImageProcessor struct { +type EPUBImageProcessor interface { + Load() (images []epubimage.EPUBImage, err error) + CoverTitleData(o CoverTitleDataOptions) (epubzip.Image, error) +} + +type ePUBImageProcessor struct { epuboptions.EPUBOptions } func New(o epuboptions.EPUBOptions) EPUBImageProcessor { - return EPUBImageProcessor{o} + return ePUBImageProcessor{o} } // Load extract and convert images -func (e EPUBImageProcessor) Load() (images []epubimage.EPUBImage, err error) { +func (e ePUBImageProcessor) Load() (images []epubimage.EPUBImage, err error) { images = make([]epubimage.EPUBImage, 0) imageCount, imageInput, err := e.load() if err != nil { @@ -136,7 +141,7 @@ func (e EPUBImageProcessor) Load() (images []epubimage.EPUBImage, err error) { return images, nil } -func (e EPUBImageProcessor) createImage(src image.Image, r image.Rectangle) draw.Image { +func (e ePUBImageProcessor) createImage(src image.Image, r image.Rectangle) draw.Image { if e.EPUBOptions.Image.GrayScale { return image.NewGray(r) } @@ -169,7 +174,7 @@ func (e EPUBImageProcessor) createImage(src image.Image, r image.Rectangle) draw // transform image into 1 or 3 images // only doublepage with autosplit has 3 versions -func (e EPUBImageProcessor) transformImage(input task, part int, right bool) epubimage.EPUBImage { +func (e ePUBImageProcessor) transformImage(input task, part int, right bool) epubimage.EPUBImage { g := gift.New() src := input.Image srcBounds := src.Bounds() @@ -286,7 +291,7 @@ type CoverTitleDataOptions struct { BorderSize int } -func (e EPUBImageProcessor) Cover16LevelOfGray(bounds image.Rectangle) draw.Image { +func (e ePUBImageProcessor) cover16LevelOfGray(bounds image.Rectangle) draw.Image { return image.NewPaletted(bounds, color.Palette{ color.Gray{}, color.Gray{Y: 0x11}, @@ -308,20 +313,20 @@ func (e EPUBImageProcessor) Cover16LevelOfGray(bounds image.Rectangle) draw.Imag } // CoverTitleData create a title page with the cover -func (e EPUBImageProcessor) CoverTitleData(o CoverTitleDataOptions) (epubzip.Image, error) { +func (e ePUBImageProcessor) CoverTitleData(o CoverTitleDataOptions) (epubzip.Image, error) { // Create a blur version of the cover g := gift.New(epubimagefilters.CoverTitle(o.Text, o.Align, o.PctWidth, o.PctMargin, o.MaxFontSize, o.BorderSize)) var dst draw.Image if o.Name == "cover" && e.Image.GrayScale { - dst = e.Cover16LevelOfGray(o.Src.Bounds()) + dst = e.cover16LevelOfGray(o.Src.Bounds()) } else { dst = e.createImage(o.Src, g.Bounds(o.Src.Bounds())) } g.Draw(dst, o.Src) return epubzip.CompressImage( - "OEBPS/Images/"+o.Name+"."+e.Image.Format, - e.Image.Format, + "OEBPS/Images/"+o.Name+".jpeg", + "jpeg", dst, e.Image.Quality, ) diff --git a/internal/pkg/epubtemplates/content.go b/internal/pkg/epubtemplates/content.go index 7de258d..abd87f9 100644 --- a/internal/pkg/epubtemplates/content.go +++ b/internal/pkg/epubtemplates/content.go @@ -144,7 +144,7 @@ func (o Content) getManifest() []tag { var imageTags, pageTags, spaceTags []tag addTag := func(img epubimage.EPUBImage, withSpace bool) { imageTags = append(imageTags, - tag{"item", tagAttrs{"id": img.ImgKey(), "href": img.ImgPath(), "media-type": o.ImageOptions.MediaType()}, ""}, + tag{"item", tagAttrs{"id": img.ImgKey(), "href": img.ImgPath(), "media-type": img.MediaType()}, ""}, ) pageTags = append(pageTags, tag{"item", tagAttrs{"id": img.PageKey(), "href": img.PagePath(), "media-type": "application/xhtml+xml"}, ""}, @@ -160,13 +160,13 @@ func (o Content) getManifest() []tag { {"item", tagAttrs{"id": "toc", "href": "toc.xhtml", "properties": "nav", "media-type": "application/xhtml+xml"}, ""}, {"item", tagAttrs{"id": "css", "href": "Text/style.css", "media-type": "text/css"}, ""}, {"item", tagAttrs{"id": "page_cover", "href": "Text/cover.xhtml", "media-type": "application/xhtml+xml"}, ""}, - {"item", tagAttrs{"id": "img_cover", "href": "Images/cover." + o.ImageOptions.Format, "media-type": o.ImageOptions.MediaType()}, ""}, + {"item", tagAttrs{"id": "img_cover", "href": "Images/cover.jpeg", "media-type": "image/jpeg"}, ""}, } if o.HasTitlePage { items = append(items, tag{"item", tagAttrs{"id": "page_title", "href": "Text/title.xhtml", "media-type": "application/xhtml+xml"}, ""}, - tag{"item", tagAttrs{"id": "img_title", "href": "Images/title." + o.ImageOptions.Format, "media-type": o.ImageOptions.MediaType()}, ""}, + tag{"item", tagAttrs{"id": "img_title", "href": "Images/title.jpeg", "media-type": "image/jpeg"}, ""}, ) if !o.ImageOptions.View.PortraitOnly { diff --git a/internal/pkg/epubzip/image.go b/internal/pkg/epubzip/image.go index df87c4f..af479a6 100644 --- a/internal/pkg/epubzip/image.go +++ b/internal/pkg/epubzip/image.go @@ -66,3 +66,39 @@ func CompressImage(filename string, format string, img image.Image, quality int) cdata.Bytes(), }, nil } + +func CompressRaw(filename string, uncompressedData []byte) (Image, error) { + var ( + cdata bytes.Buffer + err error + ) + wcdata, err := flate.NewWriter(&cdata, flate.BestCompression) + if err != nil { + return Image{}, err + } + + _, err = wcdata.Write(uncompressedData) + if err != nil { + return Image{}, err + } + + err = wcdata.Close() + if err != nil { + return Image{}, err + } + + t := time.Now() + //goland:noinspection GoDeprecation + return Image{ + &zip.FileHeader{ + Name: filename, + CompressedSize64: uint64(cdata.Len()), + UncompressedSize64: uint64(len(uncompressedData)), + CRC32: crc32.Checksum(uncompressedData, crc32.IEEETable), + Method: zip.Deflate, + ModifiedTime: uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11), + ModifiedDate: uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9), + }, + cdata.Bytes(), + }, nil +} diff --git a/internal/pkg/epubzip/storage_image_writer.go b/internal/pkg/epubzip/storage_image_writer.go index ccec171..e19b3f2 100644 --- a/internal/pkg/epubzip/storage_image_writer.go +++ b/internal/pkg/epubzip/storage_image_writer.go @@ -50,3 +50,24 @@ func (e StorageImageWriter) Add(filename string, img image.Image, quality int) e return nil } + +func (e StorageImageWriter) AddRaw(filename string, uncompressedData []byte) error { + zipImage, err := CompressRaw(filename, uncompressedData) + + if err != nil { + return err + } + + e.mut.Lock() + defer e.mut.Unlock() + fh, err := e.fz.CreateRaw(zipImage.Header) + if err != nil { + return err + } + _, err = fh.Write(zipImage.Data) + if err != nil { + return err + } + + return nil +} diff --git a/pkg/epub/epub.go b/pkg/epub/epub.go index debba78..1861b1c 100644 --- a/pkg/epub/epub.go +++ b/pkg/epub/epub.go @@ -15,6 +15,7 @@ import ( "github.com/gofrs/uuid" "github.com/celogeek/go-comic-converter/v3/internal/pkg/epubimage" + "github.com/celogeek/go-comic-converter/v3/internal/pkg/epubimagepassthrough" "github.com/celogeek/go-comic-converter/v3/internal/pkg/epubimageprocessor" "github.com/celogeek/go-comic-converter/v3/internal/pkg/epubprogress" "github.com/celogeek/go-comic-converter/v3/internal/pkg/epubtemplates" @@ -52,13 +53,20 @@ func New(options epuboptions.EPUBOptions) EPUB { "zoom": func(s int, z float32) int { return int(float32(s) * z) }, }) + var imageProcessor epubimageprocessor.EPUBImageProcessor + if options.Image.Format == "copy" { + imageProcessor = epubimagepassthrough.New(options) + } else { + imageProcessor = epubimageprocessor.New(options) + } + return epub{ EPUBOptions: options, UID: uid.String(), Publisher: "GO Comic Converter", UpdatedAt: time.Now().UTC().Format("2006-01-02T15:04:05Z"), templateProcessor: tmpl, - imageProcessor: epubimageprocessor.New(options), + imageProcessor: imageProcessor, } } @@ -115,7 +123,7 @@ func (e epub) writeCoverImage(wz epubzip.EPUBZip, img epubimage.EPUBImage, part, []byte(e.render(epubtemplates.Text, map[string]any{ "Title": title, "ViewPort": e.Image.View.Port(), - "ImagePath": "Images/cover." + e.Image.Format, + "ImagePath": "Images/cover.jpeg", "ImageStyle": img.ImgStyle(e.Image.View.Width, e.Image.View.Height, ""), })), ); err != nil { @@ -172,7 +180,7 @@ func (e epub) writeTitleImage(wz epubzip.EPUBZip, img epubimage.EPUBImage, title []byte(e.render(epubtemplates.Text, map[string]any{ "Title": title, "ViewPort": e.Image.View.Port(), - "ImagePath": "Images/title." + e.Image.Format, + "ImagePath": "Images/title.jpeg", "ImageStyle": img.ImgStyle(e.Image.View.Width, e.Image.View.Height, titleAlign), })), ); err != nil { diff --git a/pkg/epuboptions/image.go b/pkg/epuboptions/image.go index 1e78d1d..dc3f382 100644 --- a/pkg/epuboptions/image.go +++ b/pkg/epuboptions/image.go @@ -20,7 +20,3 @@ type Image struct { Format string `yaml:"format" json:"format"` AppleBookCompatibility bool `yaml:"apple_book_compatibility" json:"apple_book_compatibility"` } - -func (i Image) MediaType() string { - return "image/" + i.Format -}