Merge branch '32-add-limts-to-crop-page'

This commit is contained in:
Celogeek 2024-04-28 21:37:39 +02:00
commit 897efdc1d1
Signed by: celogeek
SSH Key Fingerprint: SHA256:njNJLzoLQdbV9PC6ehcruRb0QnEgxABoCYZ+0+aUIYc
18 changed files with 208 additions and 115 deletions

8
go.mod
View File

@ -22,8 +22,8 @@ require (
github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/go-version v1.6.0 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/rivo/uniseg v0.4.7 // indirect github.com/rivo/uniseg v0.4.7 // indirect
github.com/stretchr/testify v1.8.4 // indirect github.com/stretchr/testify v1.9.0 // indirect
golang.org/x/net v0.21.0 // indirect golang.org/x/net v0.24.0 // indirect
golang.org/x/sys v0.17.0 // indirect golang.org/x/sys v0.19.0 // indirect
golang.org/x/term v0.17.0 // indirect golang.org/x/term v0.19.0 // indirect
) )

14
go.sum
View File

@ -35,19 +35,21 @@ github.com/schollz/progressbar/v3 v3.14.2 h1:EducH6uNLIWsr560zSV1KrTeUb/wZGAHqyM
github.com/schollz/progressbar/v3 v3.14.2/go.mod h1:aQAZQnhF4JGFtRJiw/eobaXpsqpVQAftEQ+hLGXaRc4= github.com/schollz/progressbar/v3 v3.14.2/go.mod h1:aQAZQnhF4JGFtRJiw/eobaXpsqpVQAftEQ+hLGXaRc4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 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 h1:IWllFTiDjjLIf2oeKxpIUmtiDV5sn71VgeQgg6vcE7k=
github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e/go.mod h1:d7u6HkTYKSv5m6MCKkOQlHwaShTMl3HjqSGW3XtVhXM= github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e/go.mod h1:d7u6HkTYKSv5m6MCKkOQlHwaShTMl3HjqSGW3XtVhXM=
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -19,6 +19,7 @@ import (
"time" "time"
"github.com/celogeek/go-comic-converter/v2/internal/converter/options" "github.com/celogeek/go-comic-converter/v2/internal/converter/options"
"github.com/celogeek/go-comic-converter/v2/internal/utils"
) )
type Converter struct { type Converter struct {
@ -44,17 +45,17 @@ func New() *Converter {
var cmdOutput strings.Builder var cmdOutput strings.Builder
cmd.SetOutput(&cmdOutput) cmd.SetOutput(&cmdOutput)
cmd.Usage = func() { cmd.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", filepath.Base(os.Args[0])) utils.Printf("Usage of %s:\n", filepath.Base(os.Args[0]))
for _, o := range conv.order { for _, o := range conv.order {
switch v := o.(type) { switch v := o.(type) {
case converterOrderSection: case converterOrderSection:
fmt.Fprintf(os.Stderr, "\n%s:\n", o.Value()) utils.Printf("\n%s:\n", o.Value())
case converterOrderName: case converterOrderName:
fmt.Fprintln(os.Stderr, conv.Usage(v.isString, cmd.Lookup(v.Value()))) utils.Println(conv.Usage(v.isString, cmd.Lookup(v.Value())))
} }
} }
if cmdOutput.Len() > 0 { if cmdOutput.Len() > 0 {
fmt.Fprintf(os.Stderr, "\nError: %s", cmdOutput.String()) utils.Printf("\nError: %s", cmdOutput.String())
} }
} }
@ -113,6 +114,8 @@ func (c *Converter) InitParse() {
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.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.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.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.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.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.AutoContrast, "autocontrast", c.Options.AutoContrast, "Improve contrast automatically")
@ -162,7 +165,7 @@ func (c *Converter) InitParse() {
// Usage Customize version of FlagSet.PrintDefaults // Usage Customize version of FlagSet.PrintDefaults
func (c *Converter) Usage(isString bool, f *flag.Flag) string { func (c *Converter) Usage(isString bool, f *flag.Flag) string {
var b strings.Builder var b strings.Builder
fmt.Fprintf(&b, " -%s", f.Name) // Two spaces before -; see next two comments. b.WriteString(" -" + f.Name)
name, usage := flag.UnquoteUsage(f) name, usage := flag.UnquoteUsage(f)
if len(name) > 0 { if len(name) > 0 {
b.WriteString(" ") b.WriteString(" ")
@ -174,9 +177,9 @@ func (c *Converter) Usage(isString bool, f *flag.Flag) string {
c.isZeroValueErrs = append(c.isZeroValueErrs, err) c.isZeroValueErrs = append(c.isZeroValueErrs, err)
} else if !isZero { } else if !isZero {
if isString { if isString {
fmt.Fprintf(&b, " (default %q)", f.DefValue) b.WriteString(fmt.Sprintf(" (default %q)", f.DefValue))
} else { } else {
fmt.Fprintf(&b, " (default %v)", f.DefValue) b.WriteString(fmt.Sprintf(" (default %v)", f.DefValue))
} }
} }
@ -225,7 +228,7 @@ func (c *Converter) isZeroValue(f *flag.Flag, value string) (ok bool, err error)
// Parse all parameters // Parse all parameters
func (c *Converter) Parse() { func (c *Converter) Parse() {
c.Cmd.Parse(os.Args[1:]) _ = c.Cmd.Parse(os.Args[1:])
if c.Options.Help { if c.Options.Help {
c.Cmd.Usage() c.Cmd.Usage()
os.Exit(0) os.Exit(0)
@ -388,13 +391,18 @@ func (c *Converter) Validate() error {
return errors.New("grayscale mode should be 0, 1 or 2") return errors.New("grayscale mode should be 0, 1 or 2")
} }
// crop
if c.Options.CropLimit < 0 || c.Options.CropLimit > 100 {
return errors.New("crop limit should be between 0 and 100")
}
return nil return nil
} }
// Fatal Helper to show usage, err and exit 1 // Fatal Helper to show usage, err and exit 1
func (c *Converter) Fatal(err error) { func (c *Converter) Fatal(err error) {
c.Cmd.Usage() c.Cmd.Usage()
fmt.Fprintf(os.Stderr, "\nError: %s\n", err) utils.Printf("\nError: %s\n", err)
os.Exit(1) os.Exit(1)
} }
@ -405,7 +413,7 @@ func (c *Converter) Stats() {
runtime.ReadMemStats(&mem) runtime.ReadMemStats(&mem)
if c.Options.Json { if c.Options.Json {
json.NewEncoder(os.Stdout).Encode(map[string]any{ _ = json.NewEncoder(os.Stdout).Encode(map[string]any{
"type": "stats", "type": "stats",
"data": map[string]any{ "data": map[string]any{
"elapse_ms": elapse.Milliseconds(), "elapse_ms": elapse.Milliseconds(),
@ -413,8 +421,7 @@ func (c *Converter) Stats() {
}, },
}) })
} else { } else {
fmt.Fprintf( utils.Printf(
os.Stderr,
"Completed in %s, Memory usage %d Mb\n", "Completed in %s, Memory usage %d Mb\n",
elapse, elapse,
mem.Sys/1024/1024, mem.Sys/1024/1024,

View File

@ -8,8 +8,9 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/celogeek/go-comic-converter/v2/internal/converter/profiles"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"github.com/celogeek/go-comic-converter/v2/internal/converter/profiles"
) )
type Options struct { type Options struct {
@ -29,6 +30,8 @@ type Options struct {
CropRatioUp int `yaml:"crop_ratio_up"` CropRatioUp int `yaml:"crop_ratio_up"`
CropRatioRight int `yaml:"crop_ratio_right"` CropRatioRight int `yaml:"crop_ratio_right"`
CropRatioBottom int `yaml:"crop_ratio_bottom"` CropRatioBottom int `yaml:"crop_ratio_bottom"`
CropLimit int `yaml:"crop_limit"`
CropSkipIfLimitReached bool `yaml:"crop_skip_if_limit_reached"`
Brightness int `yaml:"brightness"` Brightness int `yaml:"brightness"`
Contrast int `yaml:"contrast"` Contrast int `yaml:"contrast"`
AutoContrast bool `yaml:"auto_contrast"` AutoContrast bool `yaml:"auto_contrast"`
@ -79,23 +82,25 @@ type Options struct {
// New Initialize default options. // New Initialize default options.
func New() *Options { func New() *Options {
return &Options{ return &Options{
Profile: "SR", Profile: "SR",
Quality: 85, Quality: 85,
Grayscale: true, Grayscale: true,
Crop: true, Crop: true,
CropRatioLeft: 1, CropRatioLeft: 1,
CropRatioUp: 1, CropRatioUp: 1,
CropRatioRight: 1, CropRatioRight: 1,
CropRatioBottom: 3, CropRatioBottom: 3,
NoBlankImage: true, CropLimit: 10,
HasCover: true, CropSkipIfLimitReached: true,
KeepDoublePageIfSplit: true, NoBlankImage: true,
SortPathMode: 1, HasCover: true,
ForegroundColor: "000", KeepDoublePageIfSplit: true,
BackgroundColor: "FFF", SortPathMode: 1,
Format: "jpeg", ForegroundColor: "000",
TitlePage: 1, BackgroundColor: "FFF",
profiles: profiles.New(), Format: "jpeg",
TitlePage: 1,
profiles: profiles.New(),
} }
} }
@ -161,6 +166,8 @@ func (o *Options) MarshalJSON() ([]byte, error) {
"up": o.CropRatioUp, "up": o.CropRatioUp,
"bottom": o.CropRatioBottom, "bottom": o.CropRatioBottom,
} }
out["crop_limit"] = o.CropLimit
out["crop_skip_if_limit_reached"] = o.CropSkipIfLimitReached
} }
if o.Brightness != 0 { if o.Brightness != 0 {
out["brightness"] = o.Brightness out["brightness"] = o.Brightness
@ -195,7 +202,9 @@ func (o *Options) LoadConfig() error {
if err != nil { if err != nil {
return nil return nil
} }
defer f.Close() defer func(f *os.File) {
_ = f.Close()
}(f)
err = yaml.NewDecoder(f).Decode(o) err = yaml.NewDecoder(f).Decode(o)
if err != nil && err.Error() != "EOF" { if err != nil && err.Error() != "EOF" {
return err return err
@ -232,7 +241,11 @@ func (o *Options) ShowConfig() string {
if o.AspectRatio > 0 { if o.AspectRatio > 0 {
aspectRatio = fmt.Sprintf("1:%.02f", o.AspectRatio) aspectRatio = fmt.Sprintf("1:%.02f", o.AspectRatio)
} else if o.AspectRatio < 0 { } else if o.AspectRatio < 0 {
aspectRatio = fmt.Sprintf("1:%0.2f (device)", float64(profile.Height)/float64(profile.Width)) if profile != nil {
aspectRatio = fmt.Sprintf("1:%0.2f (device)", float64(profile.Height)/float64(profile.Width))
} else {
aspectRatio = "1:?? (device)"
}
} }
titlePage := "" titlePage := ""
@ -265,7 +278,7 @@ func (o *Options) ShowConfig() string {
{"Grayscale", o.Grayscale, true}, {"Grayscale", o.Grayscale, true},
{"Grayscale mode", grayscaleMode, o.Grayscale}, {"Grayscale mode", grayscaleMode, o.Grayscale},
{"Crop", o.Crop, true}, {"Crop", o.Crop, true},
{"Crop ratio", fmt.Sprintf("%d Left - %d Up - %d Right - %d Bottom", o.CropRatioLeft, o.CropRatioUp, o.CropRatioRight, o.CropRatioBottom), o.Crop}, {"Crop ratio", fmt.Sprintf("%d Left - %d Up - %d Right - %d Bottom - Limit %d%% - Skip %v", o.CropRatioLeft, o.CropRatioUp, o.CropRatioRight, o.CropRatioBottom, o.CropLimit, o.CropSkipIfLimitReached), o.Crop},
{"Brightness", o.Brightness, o.Brightness != 0}, {"Brightness", o.Brightness, o.Brightness != 0},
{"Contrast", o.Contrast, o.Contrast != 0}, {"Contrast", o.Contrast, o.Contrast != 0},
{"Auto contrast", o.AutoContrast, true}, {"Auto contrast", o.AutoContrast, true},
@ -295,7 +308,9 @@ func (o *Options) ShowConfig() string {
// ResetConfig reset all settings to default value // ResetConfig reset all settings to default value
func (o *Options) ResetConfig() error { func (o *Options) ResetConfig() error {
New().SaveConfig() if err := New().SaveConfig(); err != nil {
return err
}
return o.LoadConfig() return o.LoadConfig()
} }
@ -305,7 +320,9 @@ func (o *Options) SaveConfig() error {
if err != nil { if err != nil {
return err return err
} }
defer f.Close() defer func(f *os.File) {
_ = f.Close()
}(f)
return yaml.NewEncoder(f).Encode(o) return yaml.NewEncoder(f).Encode(o)
} }

View File

@ -5,7 +5,6 @@ import (
"archive/zip" "archive/zip"
"fmt" "fmt"
"math" "math"
"os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"sort" "sort"
@ -13,6 +12,8 @@ import (
"text/template" "text/template"
"time" "time"
"github.com/gofrs/uuid"
epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image" epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image"
epubimageprocessor "github.com/celogeek/go-comic-converter/v2/internal/epub/imageprocessor" epubimageprocessor "github.com/celogeek/go-comic-converter/v2/internal/epub/imageprocessor"
epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options" epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options"
@ -20,7 +21,7 @@ import (
epubtemplates "github.com/celogeek/go-comic-converter/v2/internal/epub/templates" epubtemplates "github.com/celogeek/go-comic-converter/v2/internal/epub/templates"
epubtree "github.com/celogeek/go-comic-converter/v2/internal/epub/tree" epubtree "github.com/celogeek/go-comic-converter/v2/internal/epub/tree"
epubzip "github.com/celogeek/go-comic-converter/v2/internal/epub/zip" epubzip "github.com/celogeek/go-comic-converter/v2/internal/epub/zip"
"github.com/gofrs/uuid" "github.com/celogeek/go-comic-converter/v2/internal/utils"
) )
type EPub struct { type EPub struct {
@ -338,7 +339,9 @@ func (e *EPub) writePart(path string, currentPart, totalParts int, part *epubPar
if err != nil { if err != nil {
return err return err
} }
defer wz.Close() defer func(wz *epubzip.EPUBZip) {
_ = wz.Close()
}(wz)
title := e.Title title := e.Title
if totalParts > 1 { if totalParts > 1 {
@ -418,18 +421,18 @@ func (e *EPub) Write() error {
if e.Dry { if e.Dry {
p := epubParts[0] p := epubParts[0]
fmt.Fprintf(os.Stderr, "TOC:\n - %s\n%s\n", e.Title, e.getTree(p.Images, true)) utils.Printf("TOC:\n - %s\n%s\n", e.Title, e.getTree(p.Images, true))
if e.DryVerbose { if e.DryVerbose {
if e.Image.HasCover { if e.Image.HasCover {
fmt.Fprintf(os.Stderr, "Cover:\n%s\n", e.getTree([]*epubimage.Image{p.Cover}, false)) utils.Printf("Cover:\n%s\n", e.getTree([]*epubimage.Image{p.Cover}, false))
} }
fmt.Fprintf(os.Stderr, "Files:\n%s\n", e.getTree(p.Images, false)) utils.Printf("Files:\n%s\n", e.getTree(p.Images, false))
} }
return nil return nil
} }
defer func() { defer func() {
imgStorage.Close() _ = imgStorage.Close()
imgStorage.Remove() _ = imgStorage.Remove()
}() }()
totalParts := len(epubParts) totalParts := len(epubParts)
@ -465,11 +468,11 @@ func (e *EPub) Write() error {
return err return err
} }
bar.Add(1) _ = bar.Add(1)
} }
bar.Close() _ = bar.Close()
if !e.Json { if !e.Json {
fmt.Fprintln(os.Stderr) utils.Println()
} }
// display corrupted images // display corrupted images
@ -477,17 +480,17 @@ func (e *EPub) Write() error {
for pId, part := range epubParts { for pId, part := range epubParts {
if pId == 0 && e.Image.HasCover && part.Cover.Error != nil { if pId == 0 && e.Image.HasCover && part.Cover.Error != nil {
hasError = true hasError = true
fmt.Fprintf(os.Stderr, "Error on image %s: %v\n", filepath.Join(part.Cover.Path, part.Cover.Name), part.Cover.Error) utils.Printf("Error on image %s: %v\n", filepath.Join(part.Cover.Path, part.Cover.Name), part.Cover.Error)
} }
for _, img := range part.Images { for _, img := range part.Images {
if img.Part == 0 && img.Error != nil { if img.Part == 0 && img.Error != nil {
hasError = true hasError = true
fmt.Fprintf(os.Stderr, "Error on image %s: %v\n", filepath.Join(img.Path, img.Name), img.Error) utils.Printf("Error on image %s: %v\n", filepath.Join(img.Path, img.Name), img.Error)
} }
} }
} }
if hasError { if hasError {
fmt.Fprintln(os.Stderr) utils.Println()
} }
return nil return nil

View File

@ -8,9 +8,9 @@ import (
) )
// AutoCrop Lookup for margin and crop // AutoCrop Lookup for margin and crop
func AutoCrop(img image.Image, bounds image.Rectangle, cutRatioLeft, cutRatioUp, cutRatioRight, cutRatioBottom int) gift.Filter { func AutoCrop(img image.Image, bounds image.Rectangle, cutRatioLeft, cutRatioUp, cutRatioRight, cutRatioBottom int, limit int, skipIfLimitReached bool) gift.Filter {
return gift.Crop( return gift.Crop(
findMargin(img, bounds, cutRatioOptions{cutRatioLeft, cutRatioUp, cutRatioRight, cutRatioBottom}), findMargin(img, bounds, cutRatioOptions{cutRatioLeft, cutRatioUp, cutRatioRight, cutRatioBottom}, limit, skipIfLimitReached),
) )
} }
@ -25,11 +25,13 @@ type cutRatioOptions struct {
Left, Up, Right, Bottom int Left, Up, Right, Bottom int
} }
func findMargin(img image.Image, bounds image.Rectangle, cutRatio cutRatioOptions) image.Rectangle { func findMargin(img image.Image, bounds image.Rectangle, cutRatio cutRatioOptions, limit int, skipIfLimitReached bool) image.Rectangle {
imgArea := bounds imgArea := bounds
maxCropX, maxCropY := imgArea.Dx()*limit/100, imgArea.Dy()*limit/100
LEFT: LEFT:
for x := imgArea.Min.X; x < imgArea.Max.X; x++ { for x, maxCrop := imgArea.Min.X, maxCropX; x < imgArea.Max.X && (limit == 0 || maxCrop > 0); x, maxCrop = x+1, maxCrop-1 {
allowNonBlank := imgArea.Dy() * cutRatio.Left / 100 allowNonBlank := imgArea.Dy() * cutRatio.Left / 100
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ { for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
if !colorIsBlank(img.At(x, y)) { if !colorIsBlank(img.At(x, y)) {
@ -40,10 +42,13 @@ LEFT:
} }
} }
imgArea.Min.X++ imgArea.Min.X++
if limit > 0 && maxCrop == 1 && skipIfLimitReached {
return bounds
}
} }
UP: UP:
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ { for y, maxCrop := imgArea.Min.Y, maxCropY; y < imgArea.Max.Y && (limit == 0 || maxCrop > 0); y, maxCrop = y+1, maxCrop-1 {
allowNonBlank := imgArea.Dx() * cutRatio.Up / 100 allowNonBlank := imgArea.Dx() * cutRatio.Up / 100
for x := imgArea.Min.X; x < imgArea.Max.X; x++ { for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
if !colorIsBlank(img.At(x, y)) { if !colorIsBlank(img.At(x, y)) {
@ -54,10 +59,13 @@ UP:
} }
} }
imgArea.Min.Y++ imgArea.Min.Y++
if limit > 0 && maxCrop == 1 && skipIfLimitReached {
return bounds
}
} }
RIGHT: RIGHT:
for x := imgArea.Max.X - 1; x >= imgArea.Min.X; x-- { for x, maxCrop := imgArea.Max.X-1, maxCropX; x >= imgArea.Min.X && (limit == 0 || maxCrop > 0); x, maxCrop = x-1, maxCrop-1 {
allowNonBlank := imgArea.Dy() * cutRatio.Right / 100 allowNonBlank := imgArea.Dy() * cutRatio.Right / 100
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ { for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
if !colorIsBlank(img.At(x, y)) { if !colorIsBlank(img.At(x, y)) {
@ -68,10 +76,13 @@ RIGHT:
} }
} }
imgArea.Max.X-- imgArea.Max.X--
if limit > 0 && maxCrop == 1 && skipIfLimitReached {
return bounds
}
} }
BOTTOM: BOTTOM:
for y := imgArea.Max.Y - 1; y >= imgArea.Min.Y; y-- { for y, maxCrop := imgArea.Max.Y-1, maxCropY; y >= imgArea.Min.Y && (limit == 0 || maxCrop > 0); y, maxCrop = y-1, maxCrop-1 {
allowNonBlank := imgArea.Dx() * cutRatio.Bottom / 100 allowNonBlank := imgArea.Dx() * cutRatio.Bottom / 100
for x := imgArea.Min.X; x < imgArea.Max.X; x++ { for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
if !colorIsBlank(img.At(x, y)) { if !colorIsBlank(img.At(x, y)) {
@ -82,6 +93,9 @@ BOTTOM:
} }
} }
imgArea.Max.Y-- imgArea.Max.Y--
if limit > 0 && maxCrop == 1 && skipIfLimitReached {
return bounds
}
} }
return imgArea return imgArea

View File

@ -94,5 +94,5 @@ func (p *coverTitle) Draw(dst draw.Image, src image.Image, _ *gift.Options) {
textLeft = textArea.Min.X textLeft = textArea.Min.X
} }
textTop := textArea.Min.Y + textArea.Dy()/2 + textHeight/4 textTop := textArea.Min.Y + textArea.Dy()/2 + textHeight/4
c.DrawString(p.title, freetype.Pt(textLeft, textTop)) _, _ = c.DrawString(p.title, freetype.Pt(textLeft, textTop))
} }

View File

@ -9,12 +9,14 @@ import (
"os" "os"
"sync" "sync"
"github.com/disintegration/gift"
epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image" epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image"
epubimagefilters "github.com/celogeek/go-comic-converter/v2/internal/epub/imagefilters" epubimagefilters "github.com/celogeek/go-comic-converter/v2/internal/epub/imagefilters"
epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options" epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options"
epubprogress "github.com/celogeek/go-comic-converter/v2/internal/epub/progress" epubprogress "github.com/celogeek/go-comic-converter/v2/internal/epub/progress"
epubzip "github.com/celogeek/go-comic-converter/v2/internal/epub/zip" epubzip "github.com/celogeek/go-comic-converter/v2/internal/epub/zip"
"github.com/disintegration/gift" "github.com/celogeek/go-comic-converter/v2/internal/utils"
) )
type EPUBImageProcessor struct { type EPUBImageProcessor struct {
@ -62,7 +64,7 @@ func (e *EPUBImageProcessor) Load() (images []*epubimage.Image, err error) {
imgStorage, err := epubzip.NewStorageImageWriter(e.ImgStorage(), e.Image.Format) imgStorage, err := epubzip.NewStorageImageWriter(e.ImgStorage(), e.Image.Format)
if err != nil { if err != nil {
bar.Close() _ = bar.Close()
return nil, err return nil, err
} }
@ -82,8 +84,8 @@ func (e *EPUBImageProcessor) Load() (images []*epubimage.Image, err error) {
if !(img.DoublePage && input.Id > 0 && if !(img.DoublePage && input.Id > 0 &&
e.Options.Image.AutoSplitDoublePage && !e.Options.Image.KeepDoublePageIfSplit) { e.Options.Image.AutoSplitDoublePage && !e.Options.Image.KeepDoublePageIfSplit) {
if err = imgStorage.Add(img.EPUBImgPath(), img.Raw, e.Image.Quality); err != nil { if err = imgStorage.Add(img.EPUBImgPath(), img.Raw, e.Image.Quality); err != nil {
bar.Close() _ = bar.Close()
fmt.Fprintf(os.Stderr, "error with %s: %s", input.Name, err) utils.Printf("error with %s: %s", input.Name, err)
os.Exit(1) os.Exit(1)
} }
// do not keep raw image except for cover // do not keep raw image except for cover
@ -103,8 +105,8 @@ func (e *EPUBImageProcessor) Load() (images []*epubimage.Image, err error) {
for i, b := range []bool{e.Image.Manga, !e.Image.Manga} { for i, b := range []bool{e.Image.Manga, !e.Image.Manga} {
img = e.transformImage(input, i+1, b) img = e.transformImage(input, i+1, b)
if err = imgStorage.Add(img.EPUBImgPath(), img.Raw, e.Image.Quality); err != nil { if err = imgStorage.Add(img.EPUBImgPath(), img.Raw, e.Image.Quality); err != nil {
bar.Close() _ = bar.Close()
fmt.Fprintf(os.Stderr, "error with %s: %s", input.Name, err) utils.Printf("error with %s: %s", input.Name, err)
os.Exit(1) os.Exit(1)
} }
img.Raw = nil img.Raw = nil
@ -116,20 +118,20 @@ func (e *EPUBImageProcessor) Load() (images []*epubimage.Image, err error) {
go func() { go func() {
wg.Wait() wg.Wait()
imgStorage.Close() _ = imgStorage.Close()
close(imageOutput) close(imageOutput)
}() }()
for img := range imageOutput { for img := range imageOutput {
if img.Part == 0 { if img.Part == 0 {
bar.Add(1) _ = bar.Add(1)
} }
if e.Image.NoBlankImage && img.IsBlank { if e.Image.NoBlankImage && img.IsBlank {
continue continue
} }
images = append(images, img) images = append(images, img)
} }
bar.Close() _ = bar.Close()
if len(images) == 0 { if len(images) == 0 {
return nil, errNoImagesFound return nil, errNoImagesFound
@ -189,6 +191,8 @@ func (e *EPUBImageProcessor) transformImage(input *task, part int, right bool) *
e.Image.Crop.Up, e.Image.Crop.Up,
e.Image.Crop.Right, e.Image.Crop.Right,
e.Image.Crop.Bottom, e.Image.Crop.Bottom,
e.Image.Crop.Limit,
e.Image.Crop.SkipIfLimitReached,
) )
// detect if blank image // detect if blank image

View File

@ -20,12 +20,14 @@ import (
"golang.org/x/image/font/gofont/gomonobold" "golang.org/x/image/font/gofont/gomonobold"
_ "golang.org/x/image/webp" _ "golang.org/x/image/webp"
"github.com/celogeek/go-comic-converter/v2/internal/sortpath"
"github.com/fogleman/gg" "github.com/fogleman/gg"
"github.com/golang/freetype/truetype" "github.com/golang/freetype/truetype"
"github.com/nwaples/rardecode/v2" "github.com/nwaples/rardecode/v2"
pdfimage "github.com/raff/pdfreader/image" pdfimage "github.com/raff/pdfreader/image"
"github.com/raff/pdfreader/pdfread" "github.com/raff/pdfreader/pdfread"
"github.com/celogeek/go-comic-converter/v2/internal/sortpath"
"github.com/celogeek/go-comic-converter/v2/internal/utils"
) )
type task struct { type task struct {
@ -153,7 +155,7 @@ func (e *EPUBImageProcessor) loadDir() (totalImages int, output chan *task, err
f, err = os.Open(job.Path) f, err = os.Open(job.Path)
if err == nil { if err == nil {
img, _, err = image.Decode(f) img, _, err = image.Decode(f)
f.Close() _ = f.Close()
} }
} }
@ -203,7 +205,7 @@ func (e *EPUBImageProcessor) loadCbz() (totalImages int, output chan *task, err
totalImages = len(images) totalImages = len(images)
if totalImages == 0 { if totalImages == 0 {
r.Close() _ = r.Close()
err = errNoImagesFound err = errNoImagesFound
return return
} }
@ -246,7 +248,7 @@ func (e *EPUBImageProcessor) loadCbz() (totalImages int, output chan *task, err
if err == nil { if err == nil {
img, _, err = image.Decode(f) img, _, err = image.Decode(f)
} }
f.Close() _ = f.Close()
} }
p, fn := filepath.Split(filepath.Clean(job.F.Name)) p, fn := filepath.Split(filepath.Clean(job.F.Name))
@ -267,7 +269,7 @@ func (e *EPUBImageProcessor) loadCbz() (totalImages int, output chan *task, err
go func() { go func() {
wg.Wait() wg.Wait()
close(output) close(output)
r.Close() _ = r.Close()
}() }()
return return
} }
@ -315,24 +317,26 @@ func (e *EPUBImageProcessor) loadCbr() (totalImages int, output chan *task, err
if isSolid && !e.Dry { if isSolid && !e.Dry {
r, rerr := rardecode.OpenReader(e.Input) r, rerr := rardecode.OpenReader(e.Input)
if rerr != nil { if rerr != nil {
fmt.Fprintf(os.Stderr, "\nerror processing image %s: %s\n", e.Input, rerr) utils.Printf("\nerror processing image %s: %s\n", e.Input, rerr)
os.Exit(1) os.Exit(1)
} }
defer r.Close() defer func(r *rardecode.ReadCloser) {
_ = r.Close()
}(r)
for { for {
f, rerr := r.Next() f, rerr := r.Next()
if rerr != nil { if rerr != nil {
if rerr == io.EOF { if rerr == io.EOF {
break break
} }
fmt.Fprintf(os.Stderr, "\nerror processing image %s: %s\n", f.Name, rerr) utils.Printf("\nerror processing image %s: %s\n", f.Name, rerr)
os.Exit(1) os.Exit(1)
} }
if i, ok := indexedNames[f.Name]; ok { if i, ok := indexedNames[f.Name]; ok {
var b bytes.Buffer var b bytes.Buffer
_, rerr = io.Copy(&b, r) _, rerr = io.Copy(&b, r)
if rerr != nil { if rerr != nil {
fmt.Fprintf(os.Stderr, "\nerror processing image %s: %s\n", f.Name, rerr) utils.Printf("\nerror processing image %s: %s\n", f.Name, rerr)
os.Exit(1) os.Exit(1)
} }
jobs <- &job{i, f.Name, func() (io.ReadCloser, error) { jobs <- &job{i, f.Name, func() (io.ReadCloser, error) {
@ -365,7 +369,7 @@ func (e *EPUBImageProcessor) loadCbr() (totalImages int, output chan *task, err
if err == nil { if err == nil {
img, _, err = image.Decode(f) img, _, err = image.Decode(f)
} }
f.Close() _ = f.Close()
} }
p, fn := filepath.Split(filepath.Clean(job.Name)) p, fn := filepath.Split(filepath.Clean(job.Name))

View File

@ -6,6 +6,8 @@ import "fmt"
type Crop struct { type Crop struct {
Enabled bool Enabled bool
Left, Up, Right, Bottom int Left, Up, Right, Bottom int
Limit int
SkipIfLimitReached bool
} }
type Color struct { type Color struct {

View File

@ -7,6 +7,8 @@ import (
"time" "time"
"github.com/schollz/progressbar/v3" "github.com/schollz/progressbar/v3"
"github.com/celogeek/go-comic-converter/v2/internal/utils"
) )
type Options struct { type Options struct {
@ -38,7 +40,7 @@ func New(o Options) EpubProgress {
progressbar.OptionSetWriter(os.Stderr), progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionThrottle(65*time.Millisecond), progressbar.OptionThrottle(65*time.Millisecond),
progressbar.OptionOnCompletion(func() { progressbar.OptionOnCompletion(func() {
fmt.Fprint(os.Stderr, "\n") utils.Println()
}), }),
progressbar.OptionSetDescription(fmt.Sprintf(fmtDesc, o.CurrentJob, o.TotalJob, o.Description)), progressbar.OptionSetDescription(fmt.Sprintf(fmtDesc, o.CurrentJob, o.TotalJob, o.Description)),
progressbar.OptionSetWidth(60), progressbar.OptionSetWidth(60),

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/beevik/etree" "github.com/beevik/etree"
epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image" epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image"
epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options" epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options"
) )

View File

@ -5,6 +5,7 @@ import (
"strings" "strings"
"github.com/beevik/etree" "github.com/beevik/etree"
epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image" epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image"
) )

View File

@ -39,6 +39,7 @@ func (e *EPUBZip) Close() error {
// This will be valid with epubcheck tools. // This will be valid with epubcheck tools.
func (e *EPUBZip) WriteMagic() error { func (e *EPUBZip) WriteMagic() error {
t := time.Now().UTC() t := time.Now().UTC()
//goland:noinspection GoDeprecation
fh := &zip.FileHeader{ fh := &zip.FileHeader{
Name: "mimetype", Name: "mimetype",
Method: zip.Store, Method: zip.Store,

View File

@ -52,6 +52,7 @@ func CompressImage(filename string, format string, img image.Image, quality int)
} }
t := time.Now() t := time.Now()
//goland:noinspection GoDeprecation
return &ZipImage{ return &ZipImage{
&zip.FileHeader{ &zip.FileHeader{
Name: filename, Name: filename,

View File

@ -25,7 +25,7 @@ func NewStorageImageWriter(filename string, format string) (*StorageImageWriter,
func (e *StorageImageWriter) Close() error { func (e *StorageImageWriter) Close() error {
if err := e.fz.Close(); err != nil { if err := e.fz.Close(); err != nil {
e.fh.Close() _ = e.fh.Close()
return err return err
} }
return e.fh.Close() return e.fh.Close()

14
internal/utils/utils.go Normal file
View File

@ -0,0 +1,14 @@
package utils
import (
"fmt"
"os"
)
func Printf(format string, a ...interface{}) {
_, _ = fmt.Fprintf(os.Stderr, format, a...)
}
func Println(a ...interface{}) {
_, _ = fmt.Fprintln(os.Stderr, a...)
}

74
main.go
View File

@ -9,14 +9,15 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt"
"os" "os"
"runtime/debug" "runtime/debug"
"github.com/tcnksm/go-latest"
"github.com/celogeek/go-comic-converter/v2/internal/converter" "github.com/celogeek/go-comic-converter/v2/internal/converter"
"github.com/celogeek/go-comic-converter/v2/internal/epub" "github.com/celogeek/go-comic-converter/v2/internal/epub"
epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options" epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options"
"github.com/tcnksm/go-latest" "github.com/celogeek/go-comic-converter/v2/internal/utils"
) )
func main() { func main() {
@ -30,7 +31,7 @@ func main() {
if cmd.Options.Version { if cmd.Options.Version {
bi, ok := debug.ReadBuildInfo() bi, ok := debug.ReadBuildInfo()
if !ok { if !ok {
fmt.Fprintln(os.Stderr, "failed to fetch current version") utils.Println("failed to fetch current version")
os.Exit(1) os.Exit(1)
} }
@ -40,12 +41,12 @@ func main() {
} }
v, err := githubTag.Fetch() v, err := githubTag.Fetch()
if err != nil || len(v.Versions) < 1 { if err != nil || len(v.Versions) < 1 {
fmt.Fprintln(os.Stderr, "failed to fetch the latest version") utils.Println("failed to fetch the latest version")
os.Exit(1) os.Exit(1)
} }
latestVersion := v.Versions[0] latestVersion := v.Versions[0]
fmt.Fprintf(os.Stderr, `go-comic-converter utils.Printf(`go-comic-converter
Path : %s Path : %s
Sum : %s Sum : %s
Version : %s Version : %s
@ -65,9 +66,10 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
} }
if cmd.Options.Save { if cmd.Options.Save {
cmd.Options.SaveConfig() if err := cmd.Options.SaveConfig(); err != nil {
fmt.Fprintf( cmd.Fatal(err)
os.Stderr, }
utils.Printf(
"%s%s\n\nSaving to %s\n", "%s%s\n\nSaving to %s\n",
cmd.Options.Header(), cmd.Options.Header(),
cmd.Options.ShowConfig(), cmd.Options.ShowConfig(),
@ -77,14 +79,15 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
} }
if cmd.Options.Show { if cmd.Options.Show {
fmt.Fprintln(os.Stderr, cmd.Options.Header(), cmd.Options.ShowConfig()) utils.Println(cmd.Options.Header(), cmd.Options.ShowConfig())
return return
} }
if cmd.Options.Reset { if cmd.Options.Reset {
cmd.Options.ResetConfig() if err := cmd.Options.ResetConfig(); err != nil {
fmt.Fprintf( cmd.Fatal(err)
os.Stderr, }
utils.Printf(
"%s%s\n\nReset default to %s\n", "%s%s\n\nReset default to %s\n",
cmd.Options.Header(), cmd.Options.Header(),
cmd.Options.ShowConfig(), cmd.Options.ShowConfig(),
@ -98,11 +101,11 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
} }
if cmd.Options.Json { if cmd.Options.Json {
json.NewEncoder(os.Stdout).Encode(map[string]any{ _ = json.NewEncoder(os.Stdout).Encode(map[string]any{
"type": "options", "data": cmd.Options, "type": "options", "data": cmd.Options,
}) })
} else { } else {
fmt.Fprintln(os.Stderr, cmd.Options) utils.Println(cmd.Options)
} }
profile := cmd.Options.GetProfile() profile := cmd.Options.GetProfile()
@ -122,18 +125,35 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
Quiet: cmd.Options.Quiet, Quiet: cmd.Options.Quiet,
Json: cmd.Options.Json, Json: cmd.Options.Json,
Image: &epuboptions.Image{ 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}, Crop: &epuboptions.Crop{
Quality: cmd.Options.Quality, Enabled: cmd.Options.Crop,
Brightness: cmd.Options.Brightness, Left: cmd.Options.CropRatioLeft,
Contrast: cmd.Options.Contrast, Up: cmd.Options.CropRatioUp,
AutoContrast: cmd.Options.AutoContrast, Right: cmd.Options.CropRatioRight,
AutoRotate: cmd.Options.AutoRotate, Bottom: cmd.Options.CropRatioBottom,
AutoSplitDoublePage: cmd.Options.AutoSplitDoublePage, Limit: cmd.Options.CropLimit,
KeepDoublePageIfSplit: cmd.Options.KeepDoublePageIfSplit, SkipIfLimitReached: cmd.Options.CropSkipIfLimitReached,
NoBlankImage: cmd.Options.NoBlankImage, },
Manga: cmd.Options.Manga, Quality: cmd.Options.Quality,
HasCover: cmd.Options.HasCover, Brightness: cmd.Options.Brightness,
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}}, Contrast: cmd.Options.Contrast,
AutoContrast: cmd.Options.AutoContrast,
AutoRotate: cmd.Options.AutoRotate,
AutoSplitDoublePage: cmd.Options.AutoSplitDoublePage,
KeepDoublePageIfSplit: cmd.Options.KeepDoublePageIfSplit,
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, GrayScale: cmd.Options.Grayscale,
GrayScaleMode: cmd.Options.GrayscaleMode, GrayScaleMode: cmd.Options.GrayscaleMode,
Resize: !cmd.Options.NoResize, Resize: !cmd.Options.NoResize,
@ -141,7 +161,7 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
AppleBookCompatibility: cmd.Options.AppleBookCompatibility, AppleBookCompatibility: cmd.Options.AppleBookCompatibility,
}, },
}).Write(); err != nil { }).Write(); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err) utils.Printf("Error: %v\n", err)
os.Exit(1) os.Exit(1)
} }
if !cmd.Options.Dry { if !cmd.Options.Dry {