Compare commits

..

No commits in common. "8b04cbc38f219533779843f2703d8a85ff9947bb" and "e6051fda887e30ad4d41248a0a4623f57a776493" have entirely different histories.

10 changed files with 85 additions and 143 deletions

View File

@ -14,7 +14,6 @@ import (
"os"
"path/filepath"
"reflect"
"regexp"
"runtime"
"strings"
"time"
@ -101,7 +100,6 @@ func (c *Converter) InitParse() {
c.AddSection("Config")
c.AddStringParam(&c.Options.Profile, "profile", c.Options.Profile, fmt.Sprintf("Profile to use: \n%s", c.Options.AvailableProfiles()))
c.AddIntParam(&c.Options.Quality, "quality", c.Options.Quality, "Quality of the image")
c.AddBoolParam(&c.Options.Grayscale, "grayscale", c.Options.Grayscale, "Grayscale image. Ideal for eInk devices.")
c.AddBoolParam(&c.Options.Crop, "crop", c.Options.Crop, "Crop images")
c.AddIntParam(&c.Options.CropRatioLeft, "crop-ratio-left", c.Options.CropRatioLeft, "Crop ratio left: ratio of pixels allow to be non blank while cutting on the left.")
c.AddIntParam(&c.Options.CropRatioUp, "crop-ratio-up", c.Options.CropRatioUp, "Crop ratio up: ratio of pixels allow to be non blank while cutting on the top.")
@ -118,8 +116,6 @@ func (c *Converter) InitParse() {
c.AddIntParam(&c.Options.LimitMb, "limitmb", c.Options.LimitMb, "Limit size of the EPUB: Default nolimit (0), Minimum 20")
c.AddBoolParam(&c.Options.StripFirstDirectoryFromToc, "strip", c.Options.StripFirstDirectoryFromToc, "Strip first directory from the TOC if only 1")
c.AddIntParam(&c.Options.SortPathMode, "sort", c.Options.SortPathMode, "Sort path mode\n0 = alpha for path and file\n1 = alphanum for path and alpha for file\n2 = alphanum for path and file")
c.AddStringParam(&c.Options.ForegroundColor, "foreground-color", c.Options.ForegroundColor, "Foreground color in hexa format RGB. Black=000, White=FFF")
c.AddStringParam(&c.Options.BackgroundColor, "background-color", c.Options.BackgroundColor, "Background color in hexa format RGB. Black=000, White=FFF, Light Gray=DDD, Dark Gray=777")
c.AddSection("Default config")
c.AddBoolParam(&c.Options.Show, "show", false, "Show your default parameters")
@ -297,16 +293,6 @@ func (c *Converter) Validate() error {
return errors.New("sort should be 0, 1 or 2")
}
// Color
colorRegex := regexp.MustCompile("^[0-9A-F]{3}$")
if !colorRegex.MatchString(c.Options.ForegroundColor) {
return errors.New("foreground color must have color format in hexa: [0-9A-F]{3}")
}
if !colorRegex.MatchString(c.Options.BackgroundColor) {
return errors.New("background color must have color format in hexa: [0-9A-F]{3}")
}
return nil
}

View File

@ -23,7 +23,6 @@ type Options struct {
// Config
Profile string `yaml:"profile"`
Quality int `yaml:"quality"`
Grayscale bool `yaml:"grayscale"`
Crop bool `yaml:"crop"`
CropRatioLeft int `yaml:"crop_ratio_left"`
CropRatioUp int `yaml:"crop_ratio_up"`
@ -40,8 +39,6 @@ type Options struct {
LimitMb int `yaml:"limit_mb"`
StripFirstDirectoryFromToc bool `yaml:"strip_first_directory_from_toc"`
SortPathMode int `yaml:"sort_path_mode"`
ForegroundColor string `yaml:"foreground_color"`
BackgroundColor string `yaml:"background_color"`
// Default Config
Show bool `yaml:"-"`
@ -65,7 +62,6 @@ func New() *Options {
return &Options{
Profile: "",
Quality: 85,
Grayscale: true,
Crop: true,
CropRatioLeft: 1,
CropRatioUp: 1,
@ -81,34 +77,32 @@ func New() *Options {
LimitMb: 0,
StripFirstDirectoryFromToc: false,
SortPathMode: 1,
ForegroundColor: "000",
BackgroundColor: "FFF",
profiles: profiles.New(),
}
}
func (o *Options) Header() string {
return "Go Comic Converter\n\nOptions:"
return `Go Comic Converter
Options:`
}
func (o *Options) String() string {
var b strings.Builder
b.WriteString(o.Header())
for _, v := range []struct {
K string
V any
}{
{"Input", o.Input},
{"Output", o.Output},
{"Author", o.Author},
{"Title", o.Title},
{"Workers", o.Workers},
} {
b.WriteString(fmt.Sprintf("\n %-26s: %v", v.K, v.V))
}
b.WriteString(o.ShowConfig())
b.WriteRune('\n')
return b.String()
return fmt.Sprintf(`%s
Input : %s
Output : %s
Author : %s
Title : %s
Workers : %d%s
`,
o.Header(),
o.Input,
o.Output,
o.Author,
o.Title,
o.Workers,
o.ShowConfig(),
)
}
// Config file: ~/.go-comic-converter.yaml
@ -167,34 +161,40 @@ func (o *Options) ShowConfig() string {
sortpathmode = "path=alphanum, file=alphanum"
}
var b strings.Builder
for _, v := range []struct {
K string
V any
}{
{"Profile", profileDesc},
{"ViewRatio", fmt.Sprintf("1:%s", strings.TrimRight(fmt.Sprintf("%f", profiles.PerfectRatio), "0"))},
{"View", viewDesc},
{"Quality", o.Quality},
{"Grayscale", o.Grayscale},
{"Crop", o.Crop},
{"CropRatio", fmt.Sprintf("%d Left - %d Up - %d Right - %d Bottom", o.CropRatioLeft, o.CropRatioUp, o.CropRatioRight, o.CropRatioBottom)},
{"Brightness", o.Brightness},
{"Contrast", o.Contrast},
{"AutoRotate", o.AutoRotate},
{"AutoSplitDoublePage", o.AutoSplitDoublePage},
{"NoBlankImage", o.NoBlankImage},
{"Manga", o.Manga},
{"HasCover", o.HasCover},
{"LimitMb", limitmb},
{"StripFirstDirectoryFromToc", o.StripFirstDirectoryFromToc},
{"SortPathMode", sortpathmode},
{"Foreground Color", fmt.Sprintf("#%s", o.ForegroundColor)},
{"Background Color", fmt.Sprintf("#%s", o.BackgroundColor)},
} {
b.WriteString(fmt.Sprintf("\n %-26s: %v", v.K, v.V))
}
return b.String()
return fmt.Sprintf(`
Profile : %s
ViewRatio : 1:%s
View : %s
Quality : %d
Crop : %v
CropRatio : %d Left - %d Up - %d Right - %d Bottom
Brightness : %d
Contrast : %d
AutoRotate : %v
AutoSplitDoublePage : %v
NoBlankImage : %v
Manga : %v
HasCover : %v
LimitMb : %s
StripFirstDirectoryFromToc: %v
SortPathMode : %s`,
profileDesc,
strings.TrimRight(fmt.Sprintf("%f", profiles.PerfectRatio), "0"),
viewDesc,
o.Quality,
o.Crop,
o.CropRatioLeft, o.CropRatioUp, o.CropRatioRight, o.CropRatioBottom,
o.Brightness,
o.Contrast,
o.AutoRotate,
o.AutoSplitDoublePage,
o.NoBlankImage,
o.Manga,
o.HasCover,
limitmb,
o.StripFirstDirectoryFromToc,
sortpathmode,
)
}
// reset all settings to default value

View File

@ -16,7 +16,7 @@ type Profile struct {
}
// Recommended ratio of image for perfect rendering Portrait or Landscape.
const PerfectRatio = 1.6
const PerfectRatio = 1.5
// Compute best dimension based on device size
func (p Profile) PerfectDim() (int, int) {
@ -60,8 +60,6 @@ func New() Profiles {
{"KoF", "Kobo Forma", 1440, 1920},
{"KoS", "Kobo Sage", 1440, 1920},
{"KoE", "Kobo Elipsa", 1404, 1872},
// High Resolution for Tablette
{"HR", "High Resolution", 2400, 3840},
}
}

View File

@ -77,7 +77,7 @@ func (e *ePub) writeImage(wz *epubzip.EPUBZip, img *epubimage.Image, zipImg *zip
"Title": fmt.Sprintf("Image %d Part %d", img.Id, img.Part),
"ViewPort": fmt.Sprintf("width=%d,height=%d", e.Image.View.Width, e.Image.View.Height),
"ImagePath": img.ImgPath(),
"ImageStyle": img.ImgStyle(e.Image.View.Width, e.Image.View.Height, ""),
"ImageStyle": img.ImgStyle(e.Image.View.Width, e.Image.View.Height, e.Image.Manga),
})),
)
if err == nil {
@ -251,10 +251,6 @@ func (e *ePub) Write() error {
if totalParts > 1 {
title = fmt.Sprintf("%s [%d/%d]", title, i+1, totalParts)
}
titleAlign := "left:0"
if e.Image.Manga {
titleAlign = "right:0"
}
content := []zipContent{
{"META-INF/container.xml", epubtemplates.Container},
@ -273,7 +269,8 @@ func (e *ePub) Write() error {
})},
{"OEBPS/toc.xhtml", epubtemplates.Toc(title, e.StripFirstDirectoryFromToc, part.Images)},
{"OEBPS/Text/style.css", e.render(epubtemplates.Style, map[string]any{
"View": e.Image.View,
"PageWidth": e.Image.View.Width,
"PageHeight": e.Image.View.Height,
})},
{"OEBPS/Text/space_title.xhtml", e.render(epubtemplates.Blank, map[string]any{
"Title": "Blank Page Title",
@ -283,7 +280,7 @@ func (e *ePub) Write() error {
"Title": title,
"ViewPort": fmt.Sprintf("width=%d,height=%d", e.Image.View.Width, e.Image.View.Height),
"ImagePath": "Images/title.jpg",
"ImageStyle": part.Cover.ImgStyle(e.Image.View.Width, e.Image.View.Height, titleAlign),
"ImageStyle": part.Cover.ImgStyle(e.Image.View.Width, e.Image.View.Height, e.Image.Manga),
})},
}

View File

@ -19,7 +19,6 @@ type Image struct {
DoublePage bool
Path string
Name string
Position string
}
// key name of the blank plage after the image
@ -71,17 +70,24 @@ func (i *Image) EPUBImgPath() string {
//
// center by default.
// align to left or right if it's part of the splitted double page.
func (i *Image) ImgStyle(viewWidth, viewHeight int, align string) string {
func (i *Image) ImgStyle(viewWidth, viewHeight int, manga bool) string {
marginW, marginH := float64(viewWidth-i.Width)/2, float64(viewHeight-i.Height)/2
if align == "" {
switch i.Position {
case "rendition:page-spread-left":
align = "right:0"
case "rendition:page-spread-right":
left, top := marginW*100/float64(viewWidth), marginH*100/float64(viewHeight)
var align string
switch i.Part {
case 0:
align = fmt.Sprintf("left:%.2f%%", left)
case 1:
if manga {
align = "left:0"
} else {
align = "right:0"
}
case 2:
if manga {
align = "right:0"
} else {
align = "left:0"
default:
align = fmt.Sprintf("left:%.2f%%", marginW*100/float64(viewWidth))
}
}
@ -89,7 +95,7 @@ func (i *Image) ImgStyle(viewWidth, viewHeight int, align string) string {
"width:%dpx; height:%dpx; top:%.2f%%; %s;",
i.Width,
i.Height,
marginH*100/float64(viewHeight),
top,
align,
)
}

View File

@ -6,7 +6,6 @@ package epubimageprocessor
import (
"fmt"
"image"
"image/draw"
"os"
"sync"
@ -127,37 +126,6 @@ func (e *EPUBImageProcessor) Load() (images []*epubimage.Image, err error) {
return images, nil
}
func (e *EPUBImageProcessor) createImage(src image.Image, r image.Rectangle) draw.Image {
if e.Options.Image.GrayScale {
return image.NewGray(r)
}
switch t := src.(type) {
case *image.Gray:
return image.NewGray(r)
case *image.Gray16:
return image.NewGray16(r)
case *image.RGBA:
return image.NewRGBA(r)
case *image.RGBA64:
return image.NewRGBA64(r)
case *image.NRGBA:
return image.NewNRGBA(r)
case *image.NRGBA64:
return image.NewNRGBA64(r)
case *image.Alpha:
return image.NewAlpha(r)
case *image.Alpha16:
return image.NewAlpha16(r)
case *image.CMYK:
return image.NewCMYK(r)
case *image.Paletted:
return image.NewPaletted(r, t.Palette)
default:
return image.NewNRGBA64(r)
}
}
// 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 {
@ -209,7 +177,7 @@ func (e *EPUBImageProcessor) transformImage(src image.Image, srcId int) []image.
// convert
{
g := gift.New(filters...)
dst := e.createImage(src, g.Bounds(src.Bounds()))
dst := image.NewGray(g.Bounds(src.Bounds()))
g.Draw(dst, src)
images = append(images, dst)
}
@ -236,7 +204,7 @@ func (e *EPUBImageProcessor) transformImage(src image.Image, srcId int) []image.
epubimagefilters.CropSplitDoublePage(b),
epubimagefilters.Resize(e.Image.View.Width, e.Image.View.Height, gift.LanczosResampling),
)
dst := e.createImage(src, g.Bounds(src.Bounds()))
dst := image.NewGray(g.Bounds(src.Bounds()))
g.Draw(dst, src)
images = append(images, dst)
}
@ -245,11 +213,11 @@ func (e *EPUBImageProcessor) transformImage(src image.Image, srcId int) []image.
}
// create a title page with the cover
func (e *EPUBImageProcessor) CoverTitleData(src image.Image, title string) (*epubzip.ZipImage, error) {
func (e *EPUBImageProcessor) CoverTitleData(img image.Image, title string) (*epubzip.ZipImage, error) {
// Create a blur version of the cover
g := gift.New(epubimagefilters.CoverTitle(title))
dst := e.createImage(src, g.Bounds(src.Bounds()))
g.Draw(dst, src)
dst := image.NewGray(g.Bounds(img.Bounds()))
g.Draw(dst, img)
return epubzip.CompressImage("OEBPS/Images/title.jpg", dst, e.Image.Quality)
}

View File

@ -10,13 +10,8 @@ type Crop struct {
Left, Up, Right, Bottom int
}
type Color struct {
Foreground, Background string
}
type View struct {
Width, Height int
Color Color
}
type Image struct {
@ -30,7 +25,6 @@ type Image struct {
Manga bool
HasCover bool
View *View
GrayScale bool
}
type Options struct {

View File

@ -195,11 +195,9 @@ func getSpine(o *ContentOptions) []tag {
"",
})
}
// register position for style adjustment
img.Position = getSpread(img.DoublePage)
spine = append(spine, tag{
"itemref",
tagAttrs{"idref": img.PageKey(), "properties": img.Position},
tagAttrs{"idref": img.PageKey(), "properties": getSpread(img.DoublePage)},
"",
})
}

View File

@ -1,12 +1,12 @@
body {
color: #{{ .View.Color.Foreground }};
background: #{{ .View.Color.Background }};
color: #000;
background: #FFF;
top: 0;
left: 0;
margin: 0;
padding: 0;
width: {{ .View.Width }}px;
height: {{ .View.Height }}px;
width: {{ .PageWidth }}px;
height: {{ .PageHeight }}px;
text-align: center;
}

View File

@ -114,8 +114,6 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
DryVerbose: cmd.Options.DryVerbose,
Quiet: cmd.Options.Quiet,
Image: &epuboptions.Image{
Quality: cmd.Options.Quality,
GrayScale: cmd.Options.Grayscale,
Crop: &epuboptions.Crop{
Enabled: cmd.Options.Crop,
Left: cmd.Options.CropRatioLeft,
@ -123,6 +121,7 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
Right: cmd.Options.CropRatioRight,
Bottom: cmd.Options.CropRatioBottom,
},
Quality: cmd.Options.Quality,
Brightness: cmd.Options.Brightness,
Contrast: cmd.Options.Contrast,
AutoRotate: cmd.Options.AutoRotate,
@ -133,10 +132,6 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
View: &epuboptions.View{
Width: perfectWidth,
Height: perfectHeight,
Color: epuboptions.Color{
Foreground: cmd.Options.ForegroundColor,
Background: cmd.Options.BackgroundColor,
},
},
},
}).Write(); err != nil {