Merge branch 'simplify-options'

This commit is contained in:
Celogeek 2024-12-24 11:25:27 +01:00
commit 45677c6b7b
Signed by: celogeek
GPG Key ID: 850295F3747870DD
11 changed files with 224 additions and 358 deletions

2
.gitignore vendored
View File

@ -1,2 +1,4 @@
.vscode
.idea
.DS_Store
/tmp/

12
go.mod
View File

@ -8,11 +8,11 @@ require (
github.com/fogleman/gg v1.3.0
github.com/gofrs/uuid v4.4.0+incompatible
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
github.com/nwaples/rardecode/v2 v2.0.0-beta.3
github.com/nwaples/rardecode/v2 v2.0.1
github.com/raff/pdfreader v0.0.0-20220308062436-033e8ac577f0
github.com/schollz/progressbar/v3 v3.16.1
github.com/schollz/progressbar/v3 v3.17.1
github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e
golang.org/x/image v0.21.0
golang.org/x/image v0.23.0
gopkg.in/yaml.v3 v3.0.1
)
@ -22,7 +22,7 @@ require (
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/rivo/uniseg v0.4.7 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/term v0.25.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/term v0.27.0 // indirect
)

24
go.sum
View File

@ -24,28 +24,28 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/nwaples/rardecode/v2 v2.0.0-beta.3 h1:evQTW0IjM2GAL5AaPHiQrT+laWohkt5zHKA3yCsGQGU=
github.com/nwaples/rardecode/v2 v2.0.0-beta.3/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY=
github.com/nwaples/rardecode/v2 v2.0.1 h1:3MN6/R+Y4c7e+21U3yhWuUcf72sYmcmr6jtiuAVSH1A=
github.com/nwaples/rardecode/v2 v2.0.1/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/raff/pdfreader v0.0.0-20220308062436-033e8ac577f0 h1:fuFvfwIc+cpySYurvDNTs5LIHXP9Cj3reVRplj9Whv4=
github.com/raff/pdfreader v0.0.0-20220308062436-033e8ac577f0/go.mod h1:Ql3QqeGiYGlPOtYz+F/L7J27spqDcdH9LhDHOrrdsD4=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/schollz/progressbar/v3 v3.16.1 h1:RnF1neWZFzLCoGx8yp1yF7SDl4AzNDI5y4I0aUJRrZQ=
github.com/schollz/progressbar/v3 v3.16.1/go.mod h1:I2ILR76gz5VXqYMIY/LdLecvMHDPVcQm3W/MSKi1TME=
github.com/schollz/progressbar/v3 v3.17.1 h1:bI1MTaoQO+v5kzklBjYNRQLoVpe0zbyRZNK6DFkVC5U=
github.com/schollz/progressbar/v3 v3.17.1/go.mod h1:RzqpnsPQNjUyIgdglUjRLgD7sVnxN1wpmBMV+UiEbL4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e h1:IWllFTiDjjLIf2oeKxpIUmtiDV5sn71VgeQgg6vcE7k=
github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e/go.mod h1:d7u6HkTYKSv5m6MCKkOQlHwaShTMl3HjqSGW3XtVhXM=
golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s=
golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68=
golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -105,35 +105,35 @@ func (c *Converter) InitParse() {
c.AddSection("Config")
c.AddStringParam(&c.Options.Profile, "profile", c.Options.Profile, "Profile to use: \n"+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.AddIntParam(&c.Options.GrayscaleMode, "grayscale-mode", c.Options.GrayscaleMode, "Grayscale Mode\n0 = normal\n1 = average\n2 = luminance")
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.")
c.AddIntParam(&c.Options.CropRatioRight, "crop-ratio-right", c.Options.CropRatioRight, "Crop ratio right: ratio of pixels allow to be non blank while cutting on the right.")
c.AddIntParam(&c.Options.CropRatioBottom, "crop-ratio-bottom", c.Options.CropRatioBottom, "Crop ratio bottom: ratio of pixels allow to be non blank while cutting on the bottom.")
c.AddIntParam(&c.Options.CropLimit, "crop-limit", c.Options.CropLimit, "Crop limit: maximum number of cropping in percentage allowed. 0 mean unlimited.")
c.AddBoolParam(&c.Options.CropSkipIfLimitReached, "crop-skip-if-limit-reached", c.Options.CropSkipIfLimitReached, "Crop skip if limit reached.")
c.AddIntParam(&c.Options.Brightness, "brightness", c.Options.Brightness, "Brightness readjustment: between -100 and 100, > 0 lighter, < 0 darker")
c.AddIntParam(&c.Options.Contrast, "contrast", c.Options.Contrast, "Contrast readjustment: between -100 and 100, > 0 more contrast, < 0 less contrast")
c.AddBoolParam(&c.Options.AutoContrast, "autocontrast", c.Options.AutoContrast, "Improve contrast automatically")
c.AddBoolParam(&c.Options.AutoRotate, "autorotate", c.Options.AutoRotate, "Auto Rotate page when width > height")
c.AddBoolParam(&c.Options.AutoSplitDoublePage, "autosplitdoublepage", c.Options.AutoSplitDoublePage, "Auto Split double page when width > height")
c.AddBoolParam(&c.Options.KeepDoublePageIfSplit, "keepdoublepageifsplit", c.Options.KeepDoublePageIfSplit, "Keep the double page if split")
c.AddBoolParam(&c.Options.KeepSplitDoublePageAspect, "keepsplitdoublepageaspect", c.Options.KeepSplitDoublePageAspect, "Keep aspect of split part of a double page (best for landscape rendering)")
c.AddBoolParam(&c.Options.NoBlankImage, "noblankimage", c.Options.NoBlankImage, "Remove blank image")
c.AddBoolParam(&c.Options.Manga, "manga", c.Options.Manga, "Manga mode (right to left)")
c.AddBoolParam(&c.Options.HasCover, "hascover", c.Options.HasCover, "Has cover. Indicate if your comic have a cover. The first page will be used as a cover and include after the title.")
c.AddIntParam(&c.Options.Image.Quality, "quality", c.Options.Image.Quality, "Quality of the image")
c.AddBoolParam(&c.Options.Image.GrayScale, "grayscale", c.Options.Image.GrayScale, "Grayscale image. Ideal for eInk devices.")
c.AddIntParam(&c.Options.Image.GrayScaleMode, "grayscale-mode", c.Options.Image.GrayScaleMode, "Grayscale Mode\n0 = normal\n1 = average\n2 = luminance")
c.AddBoolParam(&c.Options.Image.Crop.Enabled, "crop", c.Options.Image.Crop.Enabled, "Crop images")
c.AddIntParam(&c.Options.Image.Crop.Left, "crop-ratio-left", c.Options.Image.Crop.Left, "Crop ratio left: ratio of pixels allow to be non blank while cutting on the left.")
c.AddIntParam(&c.Options.Image.Crop.Up, "crop-ratio-up", c.Options.Image.Crop.Up, "Crop ratio up: ratio of pixels allow to be non blank while cutting on the top.")
c.AddIntParam(&c.Options.Image.Crop.Right, "crop-ratio-right", c.Options.Image.Crop.Right, "Crop ratio right: ratio of pixels allow to be non blank while cutting on the right.")
c.AddIntParam(&c.Options.Image.Crop.Bottom, "crop-ratio-bottom", c.Options.Image.Crop.Bottom, "Crop ratio bottom: ratio of pixels allow to be non blank while cutting on the bottom.")
c.AddIntParam(&c.Options.Image.Crop.Limit, "crop-limit", c.Options.Image.Crop.Limit, "Crop limit: maximum number of cropping in percentage allowed. 0 mean unlimited.")
c.AddBoolParam(&c.Options.Image.Crop.SkipIfLimitReached, "crop-skip-if-limit-reached", c.Options.Image.Crop.SkipIfLimitReached, "Crop skip if limit reached.")
c.AddIntParam(&c.Options.Image.Brightness, "brightness", c.Options.Image.Brightness, "Brightness readjustment: between -100 and 100, > 0 lighter, < 0 darker")
c.AddIntParam(&c.Options.Image.Contrast, "contrast", c.Options.Image.Contrast, "Contrast readjustment: between -100 and 100, > 0 more contrast, < 0 less contrast")
c.AddBoolParam(&c.Options.Image.AutoContrast, "autocontrast", c.Options.Image.AutoContrast, "Improve contrast automatically")
c.AddBoolParam(&c.Options.Image.AutoRotate, "autorotate", c.Options.Image.AutoRotate, "Auto Rotate page when width > height")
c.AddBoolParam(&c.Options.Image.AutoSplitDoublePage, "autosplitdoublepage", c.Options.Image.AutoSplitDoublePage, "Auto Split double page when width > height")
c.AddBoolParam(&c.Options.Image.KeepDoublePageIfSplit, "keepdoublepageifsplit", c.Options.Image.KeepDoublePageIfSplit, "Keep the double page if split")
c.AddBoolParam(&c.Options.Image.KeepSplitDoublePageAspect, "keepsplitdoublepageaspect", c.Options.Image.KeepSplitDoublePageAspect, "Keep aspect of split part of a double page (best for landscape rendering)")
c.AddBoolParam(&c.Options.Image.NoBlankImage, "noblankimage", c.Options.Image.NoBlankImage, "Remove blank image")
c.AddBoolParam(&c.Options.Image.Manga, "manga", c.Options.Image.Manga, "Manga mode (right to left)")
c.AddBoolParam(&c.Options.Image.HasCover, "hascover", c.Options.Image.HasCover, "Has cover. Indicate if your comic have a cover. The first page will be used as a cover and include after the title.")
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 = alphanumeric for path and alpha for file\n2 = alphanumeric for path and file")
c.AddStringParam(&c.Options.ForegroundColor, "foreground-color", c.Options.ForegroundColor, "Foreground color in hexadecimal format RGB. Black=000, White=FFF")
c.AddStringParam(&c.Options.BackgroundColor, "background-color", c.Options.BackgroundColor, "Background color in hexadecimal format RGB. Black=000, White=FFF, Light Gray=DDD, Dark Gray=777")
c.AddBoolParam(&c.Options.NoResize, "noresize", c.Options.NoResize, "Do not reduce image size if exceed device size")
c.AddStringParam(&c.Options.Format, "format", c.Options.Format, "Format of output images: jpeg (lossy), png (lossless)")
c.AddFloatParam(&c.Options.AspectRatio, "aspect-ratio", c.Options.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.PortraitOnly, "portrait-only", c.Options.PortraitOnly, "Portrait only: force orientation to portrait only.")
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.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")
c.AddSection("Default config")
@ -150,7 +150,7 @@ func (c *Converter) InitParse() {
c.AddBoolParam(&c.Options.GoodQuality, "goodquality", false, "Max quality: grayscale jpg q90")
c.AddSection("Compatibility")
c.AddBoolParam(&c.Options.AppleBookCompatibility, "applebookcompatibility", c.Options.AppleBookCompatibility, "Apple book compatibility")
c.AddBoolParam(&c.Options.Image.AppleBookCompatibility, "applebookcompatibility", c.Options.Image.AppleBookCompatibility, "Apple book compatibility")
c.AddSection("Other")
c.AddIntParam(&c.Options.Workers, "workers", runtime.NumCPU(), "Number of workers")
@ -228,57 +228,59 @@ func (c *Converter) isZeroValue(f *flag.Flag, value string) (ok bool, err error)
// Parse all parameters
func (c *Converter) Parse() {
_ = c.Cmd.Parse(os.Args[1:])
if err := c.Cmd.Parse(os.Args[1:]); err != nil {
utils.Fatalf("cannot parse command line options: %v", err)
}
if c.Options.Help {
c.Cmd.Usage()
os.Exit(0)
}
if c.Options.Auto {
c.Options.AutoContrast = true
c.Options.AutoRotate = true
c.Options.AutoSplitDoublePage = true
c.Options.Image.AutoContrast = true
c.Options.Image.AutoRotate = true
c.Options.Image.AutoSplitDoublePage = true
}
if c.Options.MaxQuality {
c.Options.Format = "png"
c.Options.Grayscale = false
c.Options.NoResize = true
c.Options.Image.Format = "png"
c.Options.Image.GrayScale = false
c.Options.Image.Resize = false
} else if c.Options.BestQuality {
c.Options.Format = "jpeg"
c.Options.Quality = 100
c.Options.Grayscale = false
c.Options.NoResize = true
c.Options.Image.Format = "jpeg"
c.Options.Image.Quality = 100
c.Options.Image.GrayScale = false
c.Options.Image.Resize = false
} else if c.Options.GreatQuality {
c.Options.Format = "jpeg"
c.Options.Quality = 90
c.Options.Grayscale = true
c.Options.NoResize = true
c.Options.Image.Format = "jpeg"
c.Options.Image.Quality = 90
c.Options.Image.GrayScale = true
c.Options.Image.Resize = false
} else if c.Options.GoodQuality {
c.Options.Format = "jpeg"
c.Options.Quality = 90
c.Options.Grayscale = true
c.Options.NoResize = false
c.Options.Image.Format = "jpeg"
c.Options.Image.Quality = 90
c.Options.Image.GrayScale = true
c.Options.Image.Resize = true
}
if c.Options.NoFilter {
c.Options.Crop = false
c.Options.Brightness = 0
c.Options.Contrast = 0
c.Options.AutoContrast = false
c.Options.AutoRotate = false
c.Options.NoBlankImage = false
c.Options.NoResize = true
c.Options.Image.Crop.Enabled = false
c.Options.Image.Brightness = 0
c.Options.Image.Contrast = 0
c.Options.Image.AutoContrast = false
c.Options.Image.AutoRotate = false
c.Options.Image.NoBlankImage = false
c.Options.Image.Resize = false
}
if c.Options.AppleBookCompatibility {
c.Options.AutoSplitDoublePage = true
c.Options.KeepDoublePageIfSplit = false
c.Options.KeepSplitDoublePageAspect = true
if c.Options.Image.AppleBookCompatibility {
c.Options.Image.AutoSplitDoublePage = true
c.Options.Image.KeepDoublePageIfSplit = false
c.Options.Image.KeepSplitDoublePageAspect = true
}
if c.Options.PortraitOnly {
c.Options.KeepSplitDoublePageAspect = false
if c.Options.Image.View.PortraitOnly {
c.Options.Image.KeepSplitDoublePageAspect = false
}
}
@ -352,12 +354,12 @@ func (c *Converter) Validate() error {
}
// Brightness
if c.Options.Brightness < -100 || c.Options.Brightness > 100 {
if c.Options.Image.Brightness < -100 || c.Options.Image.Brightness > 100 {
return errors.New("brightness should be between -100 and 100")
}
// Contrast
if c.Options.Contrast < -100 || c.Options.Contrast > 100 {
if c.Options.Image.Contrast < -100 || c.Options.Image.Contrast > 100 {
return errors.New("contrast should be between -100 and 100")
}
@ -368,21 +370,21 @@ func (c *Converter) Validate() error {
// Color
colorRegex := regexp.MustCompile("^[0-9A-F]{3}$")
if !colorRegex.MatchString(c.Options.ForegroundColor) {
if !colorRegex.MatchString(c.Options.Image.View.Color.Foreground) {
return errors.New("foreground color must have color format in hexadecimal: [0-9A-F]{3}")
}
if !colorRegex.MatchString(c.Options.BackgroundColor) {
if !colorRegex.MatchString(c.Options.Image.View.Color.Background) {
return errors.New("background color must have color format in hexadecimal: [0-9A-F]{3}")
}
// Format
if !(c.Options.Format == "jpeg" || c.Options.Format == "png") {
if !(c.Options.Image.Format == "jpeg" || c.Options.Image.Format == "png") {
return errors.New("format should be jpeg or png")
}
// Aspect Ratio
if c.Options.AspectRatio < 0 && c.Options.AspectRatio != -1 {
if c.Options.Image.View.AspectRatio < 0 && c.Options.Image.View.AspectRatio != -1 {
return errors.New("aspect ratio should be -1, 0 or > 0")
}
@ -392,12 +394,12 @@ func (c *Converter) Validate() error {
}
// Grayscale Mode
if c.Options.GrayscaleMode < 0 || c.Options.GrayscaleMode > 2 {
if c.Options.Image.GrayScaleMode < 0 || c.Options.Image.GrayScaleMode > 2 {
return errors.New("grayscale mode should be 0, 1 or 2")
}
// crop
if c.Options.CropLimit < 0 || c.Options.CropLimit > 100 {
if c.Options.Image.Crop.Limit < 0 || c.Options.Image.Crop.Limit > 100 {
return errors.New("crop limit should be between 0 and 100")
}

View File

@ -2,7 +2,6 @@
package converter
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
@ -10,71 +9,32 @@ import (
"gopkg.in/yaml.v3"
"github.com/celogeek/go-comic-converter/v2/internal/pkg/epuboptions"
"github.com/celogeek/go-comic-converter/v2/internal/pkg/utils"
)
type Options struct {
// Output
Input string `yaml:"-"`
Output string `yaml:"-"`
Author string `yaml:"-"`
Title string `yaml:"-"`
epuboptions.EPUBOptions
// Config
Profile string `yaml:"profile"`
Quality int `yaml:"quality"`
Grayscale bool `yaml:"grayscale"`
GrayscaleMode int `yaml:"grayscale_mode"` // 0 = normal, 1 = average, 2 = luminance
Crop bool `yaml:"crop"`
CropRatioLeft int `yaml:"crop_ratio_left"`
CropRatioUp int `yaml:"crop_ratio_up"`
CropRatioRight int `yaml:"crop_ratio_right"`
CropRatioBottom int `yaml:"crop_ratio_bottom"`
CropLimit int `yaml:"crop_limit"`
CropSkipIfLimitReached bool `yaml:"crop_skip_if_limit_reached"`
Brightness int `yaml:"brightness"`
Contrast int `yaml:"contrast"`
AutoContrast bool `yaml:"auto_contrast"`
AutoRotate bool `yaml:"auto_rotate"`
AutoSplitDoublePage bool `yaml:"auto_split_double_page"`
KeepDoublePageIfSplit bool `yaml:"keep_double_page_if_split"`
KeepSplitDoublePageAspect bool `yaml:"keep_split_double_page_aspect"`
NoBlankImage bool `yaml:"no_blank_image"`
Manga bool `yaml:"manga"`
HasCover bool `yaml:"has_cover"`
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"`
NoResize bool `yaml:"noresize"`
Format string `yaml:"format"`
AspectRatio float64 `yaml:"aspect_ratio"`
PortraitOnly bool `yaml:"portrait_only"`
AppleBookCompatibility bool `yaml:"apple_book_compatibility"`
TitlePage int `yaml:"title_page"`
Profile string `yaml:"profile" json:"profile"`
// Default Config
Show bool `yaml:"-"`
Save bool `yaml:"-"`
Reset bool `yaml:"-"`
Show bool `yaml:"-" json:"-"`
Save bool `yaml:"-" json:"-"`
Reset bool `yaml:"-" json:"-"`
// Shortcut
Auto bool `yaml:"-"`
NoFilter bool `yaml:"-"`
MaxQuality bool `yaml:"-"`
BestQuality bool `yaml:"-"`
GreatQuality bool `yaml:"-"`
GoodQuality bool `yaml:"-"`
Auto bool `yaml:"-" json:"-"`
NoFilter bool `yaml:"-" json:"-"`
MaxQuality bool `yaml:"-" json:"-"`
BestQuality bool `yaml:"-" json:"-"`
GreatQuality bool `yaml:"-" json:"-"`
GoodQuality bool `yaml:"-" json:"-"`
// Other
Workers int `yaml:"-"`
Dry bool `yaml:"-"`
DryVerbose bool `yaml:"-"`
Quiet bool `yaml:"-"`
Json bool `yaml:"-"`
Version bool `yaml:"-"`
Help bool `yaml:"-"`
Version bool `yaml:"-" json:"-"`
Help bool `yaml:"-" json:"-"`
// Internal
profiles Profiles
@ -84,22 +44,33 @@ type Options struct {
func NewOptions() *Options {
return &Options{
Profile: "SR",
EPUBOptions: epuboptions.EPUBOptions{
Image: epuboptions.Image{
Quality: 85,
Grayscale: true,
Crop: true,
CropRatioLeft: 1,
CropRatioUp: 1,
CropRatioRight: 1,
CropRatioBottom: 3,
GrayScale: true,
Crop: epuboptions.Crop{
Enabled: true,
Left: 1,
Up: 1,
Right: 1,
Bottom: 3,
},
NoBlankImage: true,
HasCover: true,
KeepDoublePageIfSplit: true,
KeepSplitDoublePageAspect: true,
SortPathMode: 1,
ForegroundColor: "000",
BackgroundColor: "FFF",
View: epuboptions.View{
Color: epuboptions.Color{
Foreground: "000",
Background: "FFF",
},
},
Resize: true,
Format: "jpeg",
},
TitlePage: 1,
SortPathMode: 1,
},
profiles: NewProfiles(),
}
}
@ -128,69 +99,6 @@ func (o *Options) String() string {
return b.String()
}
func (o *Options) MarshalJSON() ([]byte, error) {
out := map[string]any{
"input": o.Input,
"output": o.Output,
"author": o.Author,
"title": o.Title,
"workers": o.Workers,
"profile": o.GetProfile(),
"format": o.Format,
"grayscale": o.Grayscale,
"crop": o.Crop,
"autocontrast": o.AutoContrast,
"autorotate": o.AutoRotate,
"noblankimage": o.NoBlankImage,
"manga": o.Manga,
"hascover": o.HasCover,
"stripfirstdirectoryfromtoc": o.StripFirstDirectoryFromToc,
"sortpathmode": o.SortPathMode,
"foregroundcolor": o.ForegroundColor,
"backgroundcolor": o.BackgroundColor,
"resize": !o.NoResize,
"aspectratio": o.AspectRatio,
"portraitonly": o.PortraitOnly,
"titlepage": o.TitlePage,
}
if o.Format == "jpeg" {
out["quality"] = o.Quality
}
if o.Grayscale {
out["grayscale_mode"] = o.GrayscaleMode
}
if o.Crop {
out["crop_ratio"] = map[string]any{
"left": o.CropRatioLeft,
"right": o.CropRatioRight,
"up": o.CropRatioUp,
"bottom": o.CropRatioBottom,
}
out["crop_limit"] = o.CropLimit
out["crop_skip_if_limit_reached"] = o.CropSkipIfLimitReached
}
if o.Brightness != 0 {
out["brightness"] = o.Brightness
}
if o.Contrast != 0 {
out["contrast"] = o.Contrast
}
if o.PortraitOnly || !o.AppleBookCompatibility {
out["autosplitdoublepage"] = o.AutoSplitDoublePage
if o.AutoSplitDoublePage {
out["keepdoublepageifsplit"] = o.KeepDoublePageIfSplit
out["keepsplitdoublepageaspect"] = o.KeepSplitDoublePageAspect
}
}
if o.LimitMb != 0 {
out["limitmb"] = o.LimitMb
}
if !o.PortraitOnly {
out["applebookcompatibility"] = o.AppleBookCompatibility
}
return json.Marshal(out)
}
// FileName Config file: ~/.go-comic-converter.yaml
func (o *Options) FileName() string {
home, _ := os.UserHomeDir()
@ -233,9 +141,9 @@ func (o *Options) ShowConfig() string {
}
aspectRatio := "auto"
if o.AspectRatio > 0 {
aspectRatio = "1:" + utils.FloatToString(o.AspectRatio, 2)
} else if o.AspectRatio < 0 {
if o.Image.View.AspectRatio > 0 {
aspectRatio = "1:" + utils.FloatToString(o.Image.View.AspectRatio, 2)
} else if o.Image.View.AspectRatio < 0 {
if profile != nil {
aspectRatio = "1:" + utils.FloatToString(float64(profile.Height)/float64(profile.Width), 2) + " (device)"
} else {
@ -254,7 +162,7 @@ func (o *Options) ShowConfig() string {
}
grayscaleMode := "normal"
switch o.GrayscaleMode {
switch o.Image.GrayScaleMode {
case 1:
grayscaleMode = "average"
case 2:
@ -268,39 +176,39 @@ func (o *Options) ShowConfig() string {
Condition bool
}{
{"Profile", profileDesc, true},
{"Format", o.Format, true},
{"Quality", o.Quality, o.Format == "jpeg"},
{"Grayscale", o.Grayscale, true},
{"Grayscale mode", grayscaleMode, o.Grayscale},
{"Crop", o.Crop, true},
{"Format", o.Image.Format, true},
{"Quality", o.Image.Quality, o.Image.Format == "jpeg"},
{"Grayscale", o.Image.GrayScale, true},
{"Grayscale mode", grayscaleMode, o.Image.GrayScale},
{"Crop", o.Image.Crop.Enabled, true},
{"Crop ratio",
utils.IntToString(o.CropRatioLeft) + " Left - " +
utils.IntToString(o.CropRatioUp) + " Up - " +
utils.IntToString(o.CropRatioRight) + " Right - " +
utils.IntToString(o.CropRatioBottom) + " Bottom - " +
"Limit " + utils.IntToString(o.CropLimit) + "% - " +
"Skip " + utils.BoolToString(o.CropSkipIfLimitReached),
o.Crop},
{"Brightness", o.Brightness, o.Brightness != 0},
{"Contrast", o.Contrast, o.Contrast != 0},
{"Auto contrast", o.AutoContrast, true},
{"Auto rotate", o.AutoRotate, true},
{"Auto split double page", o.AutoSplitDoublePage, o.PortraitOnly || !o.AppleBookCompatibility},
{"Keep double page if split", o.KeepDoublePageIfSplit, (o.PortraitOnly || !o.AppleBookCompatibility) && o.AutoSplitDoublePage},
{"Keep split double page aspect", o.KeepSplitDoublePageAspect, (o.PortraitOnly || !o.AppleBookCompatibility) && o.AutoSplitDoublePage},
{"No blank image", o.NoBlankImage, true},
{"Manga", o.Manga, true},
{"Has cover", o.HasCover, true},
utils.IntToString(o.Image.Crop.Left) + " Left - " +
utils.IntToString(o.Image.Crop.Up) + " Up - " +
utils.IntToString(o.Image.Crop.Right) + " Right - " +
utils.IntToString(o.Image.Crop.Bottom) + " Bottom - " +
"Limit " + utils.IntToString(o.Image.Crop.Limit) + "% - " +
"Skip " + utils.BoolToString(o.Image.Crop.SkipIfLimitReached),
o.Image.Crop.Enabled},
{"Brightness", o.Image.Brightness, o.Image.Brightness != 0},
{"Contrast", o.Image.Contrast, o.Image.Contrast != 0},
{"Auto contrast", o.Image.AutoContrast, true},
{"Auto rotate", o.Image.AutoRotate, true},
{"Auto split double page", o.Image.AutoSplitDoublePage, o.Image.View.PortraitOnly || !o.Image.AppleBookCompatibility},
{"Keep double page if split", o.Image.KeepDoublePageIfSplit, (o.Image.View.PortraitOnly || !o.Image.AppleBookCompatibility) && o.Image.AutoSplitDoublePage},
{"Keep split double page aspect", o.Image.KeepSplitDoublePageAspect, (o.Image.View.PortraitOnly || !o.Image.AppleBookCompatibility) && o.Image.AutoSplitDoublePage},
{"No blank image", o.Image.NoBlankImage, true},
{"Manga", o.Image.Manga, true},
{"Has cover", o.Image.HasCover, true},
{"Limit", utils.IntToString(o.LimitMb) + " Mb", o.LimitMb != 0},
{"Strip first directory from toc", o.StripFirstDirectoryFromToc, true},
{"Sort path mode", sortpathmode, true},
{"Foreground color", "#" + o.ForegroundColor, true},
{"Background color", "#" + o.BackgroundColor, true},
{"Resize", !o.NoResize, true},
{"Foreground color", "#" + o.Image.View.Color.Foreground, true},
{"Background color", "#" + o.Image.View.Color.Background, true},
{"Resize", o.Image.Resize, true},
{"Aspect ratio", aspectRatio, true},
{"Portrait only", o.PortraitOnly, true},
{"Portrait only", o.Image.View.PortraitOnly, true},
{"Title page", titlePage, true},
{"Apple book compatibility", o.AppleBookCompatibility, !o.PortraitOnly},
{"Apple book compatibility", o.Image.AppleBookCompatibility, !o.Image.View.PortraitOnly},
} {
if v.Condition {
b.WriteString(fmt.Sprintf("\n %-32s: %v", v.Key, v.Value))

View File

@ -1,5 +1,6 @@
package epuboptions
type Color struct {
Foreground, Background string
Foreground string `yaml:"foreground" json:"foreground"`
Background string `yaml:"background" json:"background"`
}

View File

@ -1,8 +1,11 @@
package epuboptions
type Crop struct {
Enabled bool
Left, Up, Right, Bottom int
Limit int
SkipIfLimitReached bool
Enabled bool `yaml:"enabled" json:"enabled"`
Left int `yaml:"left" json:"left"`
Up int `yaml:"up" json:"up"`
Right int `yaml:"right" json:"right"`
Bottom int `yaml:"bottom" json:"bottom"`
Limit int `yaml:"limit" json:"limit"`
SkipIfLimitReached bool `yaml:"skip_if_limit_reached" json:"skip_if_limit_reached"`
}

View File

@ -2,20 +2,25 @@
package epuboptions
type EPUBOptions struct {
Input string
Output string
Title string
TitlePage int
Author string
LimitMb int
StripFirstDirectoryFromToc bool
Dry bool
DryVerbose bool
SortPathMode int
Quiet bool
Json bool
Workers int
Image Image
// Output
Input string `yaml:"-" json:"input"`
Output string `yaml:"-" json:"output"`
Author string `yaml:"-" json:"author"`
Title string `yaml:"-" json:"title"`
//Config
TitlePage int `yaml:"title_page" json:"title_page"`
LimitMb int `yaml:"limit_mb" json:"limit_mb"`
StripFirstDirectoryFromToc bool `yaml:"strip_first_directory" json:"strip_first_directory"`
SortPathMode int `yaml:"sort_path_mode" json:"sort_path_mode"`
Image Image `yaml:"image" json:"image"`
// Other
Dry bool `yaml:"-" json:"dry"`
DryVerbose bool `yaml:"-" json:"dry_verbose"`
Quiet bool `yaml:"-" json:"-"`
Json bool `yaml:"-" json:"-"`
Workers int `yaml:"-" json:"workers"`
}
func (o EPUBOptions) WorkersRatio(pct int) (nbWorkers int) {

View File

@ -1,24 +1,24 @@
package epuboptions
type Image struct {
Crop Crop
Quality int
Brightness int
Contrast int
AutoContrast bool
AutoRotate bool
AutoSplitDoublePage bool
KeepDoublePageIfSplit bool
KeepSplitDoublePageAspect bool
NoBlankImage bool
Manga bool
HasCover bool
View View
GrayScale bool
GrayScaleMode int
Resize bool
Format string
AppleBookCompatibility bool
Crop Crop `yaml:"crop" json:"crop"`
Quality int `yaml:"quality" json:"quality"`
Brightness int `yaml:"brightness" json:"brightness"`
Contrast int `yaml:"contrast" json:"contrast"`
AutoContrast bool `yaml:"auto_contrast" json:"auto_contrast"`
AutoRotate bool `yaml:"auto_rotate" json:"auto_rotate"`
AutoSplitDoublePage bool `yaml:"auto_split_double_page" json:"auto_split_double_page"`
KeepDoublePageIfSplit bool `yaml:"keep_double_page_if_split" json:"keep_double_page_if_split"`
KeepSplitDoublePageAspect bool `yaml:"keep_split_double_page_aspect" json:"keep_split_double_page_aspect"`
NoBlankImage bool `yaml:"no_blank_image" json:"no_blank_image"`
Manga bool `yaml:"manga" json:"manga"`
HasCover bool `yaml:"has_cover" json:"has_cover"`
View View `yaml:"view" json:"view"`
GrayScale bool `yaml:"grayscale" json:"grayscale"`
GrayScaleMode int `yaml:"grayscale_mode" json:"gray_scale_mode"` // 0 = normal, 1 = average, 2 = luminance
Resize bool `yaml:"resize" json:"resize"`
Format string `yaml:"format" json:"format"`
AppleBookCompatibility bool `yaml:"apple_book_compatibility" json:"apple_book_compatibility"`
}
func (i Image) MediaType() string {

View File

@ -5,10 +5,11 @@ import (
)
type View struct {
Width, Height int
AspectRatio float64
PortraitOnly bool
Color Color
Width int `yaml:"-" json:"width"`
Height int `yaml:"-" json:"height"`
AspectRatio float64 `yaml:"aspect_ratio" json:"aspect_ratio"`
PortraitOnly bool `yaml:"portrait_only" json:"portrait_only"`
Color Color `yaml:"color" json:"color"`
}
func (v View) Dimension() string {

76
main.go
View File

@ -16,7 +16,6 @@ import (
"github.com/celogeek/go-comic-converter/v2/internal/pkg/converter"
"github.com/celogeek/go-comic-converter/v2/internal/pkg/epub"
"github.com/celogeek/go-comic-converter/v2/internal/pkg/epuboptions"
"github.com/celogeek/go-comic-converter/v2/internal/pkg/utils"
)
@ -54,9 +53,12 @@ func version() {
Repository: "go-comic-converter",
}
v, err := githubTag.Fetch()
if err != nil || len(v.Versions) < 1 {
if err != nil {
utils.Fatalln("failed to fetch the latest version")
}
if len(v.Versions) < 1 {
utils.Fatalln("no versions found")
}
latestVersion := v.Versions[0]
utils.Printf(`go-comic-converter
@ -103,16 +105,6 @@ func reset(cmd *converter.Converter) {
cmd.Options.ShowConfig(),
cmd.Options.FileName(),
)
if err := cmd.Options.ResetConfig(); err != nil {
cmd.Fatal(err)
}
utils.Printf(
"%s%s\n\nReset default to %s\n",
cmd.Options.Header(),
cmd.Options.ShowConfig(),
cmd.Options.FileName(),
)
}
func generate(cmd *converter.Converter) {
@ -120,6 +112,11 @@ func generate(cmd *converter.Converter) {
cmd.Fatal(err)
}
if profile := cmd.Options.GetProfile(); profile != nil {
cmd.Options.Image.View.Width = profile.Width
cmd.Options.Image.View.Height = profile.Height
}
if cmd.Options.Json {
_ = json.NewEncoder(os.Stdout).Encode(map[string]any{
"type": "options", "data": cmd.Options,
@ -128,60 +125,7 @@ func generate(cmd *converter.Converter) {
utils.Println(cmd.Options)
}
profile := cmd.Options.GetProfile()
if err := epub.New(epuboptions.EPUBOptions{
Input: cmd.Options.Input,
Output: cmd.Options.Output,
LimitMb: cmd.Options.LimitMb,
Title: cmd.Options.Title,
TitlePage: cmd.Options.TitlePage,
Author: cmd.Options.Author,
StripFirstDirectoryFromToc: cmd.Options.StripFirstDirectoryFromToc,
SortPathMode: cmd.Options.SortPathMode,
Workers: cmd.Options.Workers,
Dry: cmd.Options.Dry,
DryVerbose: cmd.Options.DryVerbose,
Quiet: cmd.Options.Quiet,
Json: cmd.Options.Json,
Image: epuboptions.Image{
Crop: epuboptions.Crop{
Enabled: cmd.Options.Crop,
Left: cmd.Options.CropRatioLeft,
Up: cmd.Options.CropRatioUp,
Right: cmd.Options.CropRatioRight,
Bottom: cmd.Options.CropRatioBottom,
Limit: cmd.Options.CropLimit,
SkipIfLimitReached: cmd.Options.CropSkipIfLimitReached,
},
Quality: cmd.Options.Quality,
Brightness: cmd.Options.Brightness,
Contrast: cmd.Options.Contrast,
AutoContrast: cmd.Options.AutoContrast,
AutoRotate: cmd.Options.AutoRotate,
AutoSplitDoublePage: cmd.Options.AutoSplitDoublePage,
KeepDoublePageIfSplit: cmd.Options.KeepDoublePageIfSplit,
KeepSplitDoublePageAspect: cmd.Options.KeepSplitDoublePageAspect,
NoBlankImage: cmd.Options.NoBlankImage,
Manga: cmd.Options.Manga,
HasCover: cmd.Options.HasCover,
View: epuboptions.View{
Width: profile.Width,
Height: profile.Height,
AspectRatio: cmd.Options.AspectRatio,
PortraitOnly: cmd.Options.PortraitOnly,
Color: epuboptions.Color{
Foreground: cmd.Options.ForegroundColor,
Background: cmd.Options.BackgroundColor,
},
},
GrayScale: cmd.Options.Grayscale,
GrayScaleMode: cmd.Options.GrayscaleMode,
Resize: !cmd.Options.NoResize,
Format: cmd.Options.Format,
AppleBookCompatibility: cmd.Options.AppleBookCompatibility,
},
}).Write(); err != nil {
if err := epub.New(cmd.Options.EPUBOptions).Write(); err != nil {
utils.Fatalf("Error: %v\n", err)
}
if !cmd.Options.Dry {