Add Combine option, issue #21

This commit is contained in:
Milan Nikolic
2026-06-24 04:37:38 +02:00
parent 0f6fbba1d7
commit 3c81595e08
4 changed files with 219 additions and 90 deletions
+60
View File
@@ -27,6 +27,8 @@ type Options struct {
Quality int Quality int
// Encoder speed/effort, format-specific: webp method 0-6, avif speed 0-10, jxl effort 1-10; -1 uses the format default // Encoder speed/effort, format-specific: webp method 0-6, avif speed 0-10, jxl effort 1-10; -1 uses the format default
Effort int Effort int
// Combine all inputs into a single archive
Combine bool
// Lossless enables lossless compression (webp, avif, jxl), ignores quality // Lossless enables lossless compression (webp, avif, jxl), ignores quality
Lossless bool Lossless bool
// Image width // Image width
@@ -89,6 +91,8 @@ type Converter struct {
Opts Options Opts Options
// Current working directory // Current working directory
Workdir string Workdir string
// Page name prefix, set per input when combining
prefix string
// Number of files // Number of files
Nfiles int Nfiles int
// Index of the current file // Index of the current file
@@ -499,6 +503,13 @@ func (c *Converter) Convert(fileName string, fileInfo os.FileInfo) error {
defer cancel() defer cancel()
c.OnCancel = cancel c.OnCancel = cancel
c.prefix = ""
var err error
c.Workdir, err = os.MkdirTemp(os.TempDir(), "cbc")
if err != nil {
return fmt.Errorf("%s: %w", fileName, err)
}
switch { switch {
case fileInfo.IsDir(): case fileInfo.IsDir():
@@ -523,3 +534,52 @@ func (c *Converter) Convert(fileName string, fileInfo os.FileInfo) error {
return nil return nil
} }
// Combine merges multiple comic books into a single archive.
func (c *Converter) Combine(files []File) error {
if len(files) == 0 {
return nil
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c.OnCancel = cancel
var err error
c.Workdir, err = os.MkdirTemp(os.TempDir(), "cbc")
if err != nil {
return fmt.Errorf("Combine: %w", err)
}
for i, file := range files {
c.CurrFile++
c.prefix = fmt.Sprintf("%04d_", i+1)
switch {
case file.Stat.IsDir():
err = c.convertDirectory(ctx, file.Path)
case isDocument(file.Path):
err = c.convertDocument(ctx, file.Path)
case isArchive(file.Path):
err = c.convertArchive(ctx, file.Path)
}
if err != nil {
return fmt.Errorf("%s: %w", file.Path, err)
}
}
out := c.Opts.OutFile
if out == "" {
out = baseNoExt(files[0].Path) + "-combined"
}
if err := c.archiveSave(out); err != nil {
return fmt.Errorf("Combine: %w", err)
}
c.OnCancel = nil
return nil
}
+16 -32
View File
@@ -26,13 +26,6 @@ import (
// convertDocument converts PDF/EPUB document to CBZ. // convertDocument converts PDF/EPUB document to CBZ.
func (c *Converter) convertDocument(ctx context.Context, fileName string) error { func (c *Converter) convertDocument(ctx context.Context, fileName string) error {
var err error
c.Workdir, err = os.MkdirTemp(os.TempDir(), "cbc")
if err != nil {
return fmt.Errorf("convertDocument: %w", err)
}
doc, err := fitz.New(fileName) doc, err := fitz.New(fileName)
if err != nil { if err != nil {
return fmt.Errorf("convertDocument: %w", err) return fmt.Errorf("convertDocument: %w", err)
@@ -77,13 +70,6 @@ func (c *Converter) convertDocument(ctx context.Context, fileName string) error
// convertArchive converts archive to CBZ. // convertArchive converts archive to CBZ.
func (c *Converter) convertArchive(ctx context.Context, fileName string) error { func (c *Converter) convertArchive(ctx context.Context, fileName string) error {
var err error
c.Workdir, err = os.MkdirTemp(os.TempDir(), "cbc")
if err != nil {
return fmt.Errorf("convertArchive: %w", err)
}
contents, err := c.archiveList(fileName) contents, err := c.archiveList(fileName)
if err != nil { if err != nil {
return fmt.Errorf("convertArchive: %w", err) return fmt.Errorf("convertArchive: %w", err)
@@ -137,7 +123,7 @@ func (c *Converter) convertArchive(ctx context.Context, fileName string) error {
if isImage(pathName) { if isImage(pathName) {
if c.Opts.NoConvert { if c.Opts.NoConvert {
if err = copyFile(bytes.NewReader(data), filepath.Join(c.Workdir, filepath.Base(pathName))); err != nil { if err = copyFile(bytes.NewReader(data), c.workPath(filepath.Base(pathName))); err != nil {
return fmt.Errorf("convertArchive: %w", err) return fmt.Errorf("convertArchive: %w", err)
} }
@@ -145,7 +131,7 @@ func (c *Converter) convertArchive(ctx context.Context, fileName string) error {
} }
if cover == pathName && c.Opts.NoCover { if cover == pathName && c.Opts.NoCover {
if err = copyFile(bytes.NewReader(data), filepath.Join(c.Workdir, filepath.Base(pathName))); err != nil { if err = copyFile(bytes.NewReader(data), c.workPath(filepath.Base(pathName))); err != nil {
return fmt.Errorf("convertArchive: %w", err) return fmt.Errorf("convertArchive: %w", err)
} }
@@ -159,7 +145,7 @@ func (c *Converter) convertArchive(ctx context.Context, fileName string) error {
} }
if c.Opts.NoRGB && !isGrayScale(img) { if c.Opts.NoRGB && !isGrayScale(img) {
if err = copyFile(bytes.NewReader(data), filepath.Join(c.Workdir, filepath.Base(pathName))); err != nil { if err = copyFile(bytes.NewReader(data), c.workPath(filepath.Base(pathName))); err != nil {
return fmt.Errorf("convertArchive: %w", err) return fmt.Errorf("convertArchive: %w", err)
} }
@@ -176,8 +162,8 @@ func (c *Converter) convertArchive(ctx context.Context, fileName string) error {
return nil return nil
} }
if !c.Opts.NoNonImage { if c.prefix == "" && !c.Opts.NoNonImage {
if err = copyFile(bytes.NewReader(data), filepath.Join(c.Workdir, filepath.Base(pathName))); err != nil { if err = copyFile(bytes.NewReader(data), c.workPath(filepath.Base(pathName))); err != nil {
return fmt.Errorf("convertArchive: %w", err) return fmt.Errorf("convertArchive: %w", err)
} }
} }
@@ -199,13 +185,6 @@ func (c *Converter) convertArchive(ctx context.Context, fileName string) error {
// convertDirectory converts directory to CBZ. // convertDirectory converts directory to CBZ.
func (c *Converter) convertDirectory(ctx context.Context, dirPath string) error { func (c *Converter) convertDirectory(ctx context.Context, dirPath string) error {
var err error
c.Workdir, err = os.MkdirTemp(os.TempDir(), "cbc")
if err != nil {
return fmt.Errorf("convertDirectory: %w", err)
}
contents, err := imagesFromPath(dirPath) contents, err := imagesFromPath(dirPath)
if err != nil { if err != nil {
return fmt.Errorf("convertDirectory: %w", err) return fmt.Errorf("convertDirectory: %w", err)
@@ -232,8 +211,8 @@ func (c *Converter) convertDirectory(ctx context.Context, dirPath string) error
return fmt.Errorf("convertDirectory: %w", err) return fmt.Errorf("convertDirectory: %w", err)
} }
if isNonImage(img) && !c.Opts.NoNonImage { if isNonImage(img) && c.prefix == "" && !c.Opts.NoNonImage {
if err = copyFile(file, filepath.Join(c.Workdir, filepath.Base(img))); err != nil { if err = copyFile(file, c.workPath(filepath.Base(img))); err != nil {
return fmt.Errorf("convertDirectory: %w", err) return fmt.Errorf("convertDirectory: %w", err)
} }
@@ -244,7 +223,7 @@ func (c *Converter) convertDirectory(ctx context.Context, dirPath string) error
continue continue
} else if isImage(img) { } else if isImage(img) {
if c.Opts.NoConvert { if c.Opts.NoConvert {
if err = copyFile(file, filepath.Join(c.Workdir, filepath.Base(img))); err != nil { if err = copyFile(file, c.workPath(filepath.Base(img))); err != nil {
return fmt.Errorf("convertDirectory: %w", err) return fmt.Errorf("convertDirectory: %w", err)
} }
@@ -262,7 +241,7 @@ func (c *Converter) convertDirectory(ctx context.Context, dirPath string) error
} }
if c.Opts.NoRGB && !isGrayScale(i) { if c.Opts.NoRGB && !isGrayScale(i) {
if err = copyFile(file, filepath.Join(c.Workdir, filepath.Base(img))); err != nil { if err = copyFile(file, c.workPath(filepath.Base(img))); err != nil {
return fmt.Errorf("convertDirectory: %w", err) return fmt.Errorf("convertDirectory: %w", err)
} }
@@ -293,6 +272,11 @@ func (c *Converter) convertDirectory(ctx context.Context, dirPath string) error
return nil return nil
} }
// workPath returns the path of name inside the workdir, with the combine prefix applied.
func (c *Converter) workPath(name string) string {
return filepath.Join(c.Workdir, c.prefix+name)
}
// imageConvert converts image.Image. // imageConvert converts image.Image.
func (c *Converter) imageConvert(ctx context.Context, img image.Image, index int, pathName string) error { func (c *Converter) imageConvert(ctx context.Context, img image.Image, index int, pathName string) error {
err := ctx.Err() err := ctx.Err()
@@ -312,9 +296,9 @@ func (c *Converter) imageConvert(ctx context.Context, img image.Image, index int
var fileName string var fileName string
if pathName != "" { if pathName != "" {
fileName = filepath.Join(c.Workdir, fmt.Sprintf("%s.%s", baseNoExt(pathName), ext)) fileName = c.workPath(fmt.Sprintf("%s.%s", baseNoExt(pathName), ext))
} else { } else {
fileName = filepath.Join(c.Workdir, fmt.Sprintf("%03d.%s", index, ext)) fileName = c.workPath(fmt.Sprintf("%03d.%s", index, ext))
} }
img = c.imageTransform(img) img = c.imageTransform(img)
+128 -56
View File
@@ -69,8 +69,6 @@ func main() {
iup.Open() iup.Open()
defer iup.Close() defer iup.Close()
iup.SetGlobal("UTF8MODE", "YES")
iup.SetGlobal("UTF8MODE_FILE", "YES")
iup.SetGlobal("AUTODARKMODE", "YES") iup.SetGlobal("AUTODARKMODE", "YES")
img, _ := png.Decode(bytes.NewReader(appLogo)) img, _ := png.Decode(bytes.NewReader(appLogo))
@@ -98,13 +96,7 @@ func main() {
dlg.SetCallback("THEMECHANGED_CB", iup.ThemeChangedFunc(func(ih iup.Ihandle, darkMode int) int { dlg.SetCallback("THEMECHANGED_CB", iup.ThemeChangedFunc(func(ih iup.Ihandle, darkMode int) int {
t := iup.GetHandle("Table") t := iup.GetHandle("Table")
if darkMode == 1 { tableRowColors(t, darkMode == 1)
t.SetAttribute("EVENROWCOLOR", "#3A3A3A")
t.SetAttribute("ODDROWCOLOR", "#2D2D2D")
} else {
t.SetAttribute("EVENROWCOLOR", "#F0F0F0")
t.SetAttribute("ODDROWCOLOR", "#FFFFFF")
}
t.SetAttribute("REDRAW", "YES") t.SetAttribute("REDRAW", "YES")
return iup.DEFAULT return iup.DEFAULT
@@ -162,6 +154,10 @@ func options() cbconvert.Options {
opts.Effort = -1 opts.Effort = -1
} }
opts.Lossless = iup.GetHandle("Lossless").GetAttribute("VALUE") == "ON" opts.Lossless = iup.GetHandle("Lossless").GetAttribute("VALUE") == "ON"
opts.Combine = iup.GetHandle("Combine").GetAttribute("VALUE") == "ON"
if opts.Combine {
opts.OutFile = iup.GetHandle("OutFile").GetAttribute("VALUE")
}
opts.Grayscale = iup.GetHandle("Grayscale").GetAttribute("VALUE") == "ON" opts.Grayscale = iup.GetHandle("Grayscale").GetAttribute("VALUE") == "ON"
opts.Brightness = iup.GetHandle("Brightness").GetInt("VALUE") opts.Brightness = iup.GetHandle("Brightness").GetInt("VALUE")
opts.Contrast = iup.GetHandle("Contrast").GetInt("VALUE") opts.Contrast = iup.GetHandle("Contrast").GetInt("VALUE")
@@ -244,6 +240,12 @@ func setActive() {
} else { } else {
iup.GetHandle("Fit").SetAttribute("ACTIVE", "NO") iup.GetHandle("Fit").SetAttribute("ACTIVE", "NO")
} }
if opts.Combine {
iup.GetHandle("VboxOutFile").SetAttribute("ACTIVE", "YES")
} else {
iup.GetHandle("VboxOutFile").SetAttribute("ACTIVE", "NO")
}
} }
func setEffort(format string) { func setEffort(format string) {
@@ -291,6 +293,16 @@ func layout() iup.Ihandle {
) )
} }
// tableRowColors sets the alternating row colors for dark or light mode.
func tableRowColors(t iup.Ihandle, dark bool) {
even, odd := "#F0F0F0", "#FFFFFF"
if dark {
even, odd = "#3A3A3A", "#2D2D2D"
}
t.SetAttribute("EVENROWCOLOR", even)
t.SetAttribute("ODDROWCOLOR", odd)
}
func list() iup.Ihandle { func list() iup.Ihandle {
t := iup.Table().SetHandle("Table") t := iup.Table().SetHandle("Table")
t.SetAttributes(map[string]string{ t.SetAttributes(map[string]string{
@@ -313,13 +325,7 @@ func list() iup.Ihandle {
"ALTERNATECOLOR": "YES", "ALTERNATECOLOR": "YES",
}) })
if iup.GetGlobal("DARKMODE") == "YES" && iup.GetGlobal("AUTODARKMODE") == "YES" { tableRowColors(t, iup.GetGlobal("DARKMODE") == "YES" && iup.GetGlobal("AUTODARKMODE") == "YES")
t.SetAttribute("EVENROWCOLOR", "#3A3A3A")
t.SetAttribute("ODDROWCOLOR", "#2D2D2D")
} else {
t.SetAttribute("EVENROWCOLOR", "#F0F0F0")
t.SetAttribute("ODDROWCOLOR", "#FFFFFF")
}
t.SetCallback("ENTERITEM_CB", iup.EnterItemFunc(func(ih iup.Ihandle, lin, col int) int { t.SetCallback("ENTERITEM_CB", iup.EnterItemFunc(func(ih iup.Ihandle, lin, col int) int {
index = lin - 1 index = lin - 1
@@ -489,34 +495,56 @@ func tabs() iup.Ihandle {
iup.Space().SetAttributes("EXPAND=HORIZONTAL"), iup.Space().SetAttributes("EXPAND=HORIZONTAL"),
).SetHandle("VboxInput").SetAttributes("NGAP=10") ).SetHandle("VboxInput").SetAttributes("NGAP=10")
vboxOutput := iup.Vbox( vboxOutput := iup.Hbox(
iup.Vbox( iup.Vbox(
iup.Label("Output Directory:"), iup.Vbox(
iup.Text().SetAttributes("VISIBLECOLUMNS=16, MINSIZE=100x").SetHandle("OutDir"). iup.Label("Output Directory:"),
SetCallback("VALUECHANGED_CB", iup.ValueChangedFunc(func(ih iup.Ihandle) int { iup.Text().SetAttributes("VISIBLECOLUMNS=16, MINSIZE=100x").SetHandle("OutDir").
setActive() SetCallback("VALUECHANGED_CB", iup.ValueChangedFunc(func(ih iup.Ihandle) int {
setActive()
return iup.DEFAULT return iup.DEFAULT
})), })),
iup.Space().SetAttribute("SIZE", "5x0"), iup.Space().SetAttribute("SIZE", "5x0"),
iup.Button("Browse...").SetAttributes("PADDING=DEFAULTBUTTONPADDING"). iup.Button("Browse...").SetAttributes("PADDING=DEFAULTBUTTONPADDING").
SetCallback("ACTION", iup.ActionFunc(onOutputDirectory)), SetCallback("ACTION", iup.ActionFunc(onOutputDirectory)),
), ),
iup.Vbox(
iup.Label("Add Suffix to Output File:"),
iup.Text().SetAttributes("VISIBLECOLUMNS=16, MINSIZE=100x").SetHandle("Suffix").
SetAttribute("TIP", "Add suffix to filename, i.e. filename_suffix.cbz"),
),
iup.Vbox(
iup.Label("Archive Format:"),
iup.List().SetAttributes(map[string]string{
"DROPDOWN": "YES",
"VALUE": "1",
"1": "ZIP",
"2": "TAR",
}).SetHandle("Archive"),
),
).SetAttributes("NGAP=10"),
iup.Space().SetAttribute("SIZE", "15"),
iup.Vbox( iup.Vbox(
iup.Label("Add Suffix to Output File:"), iup.Vbox(
iup.Text().SetAttributes("VISIBLECOLUMNS=16, MINSIZE=100x").SetHandle("Suffix"). iup.Toggle(" Combine into single file").SetHandle("Combine").
SetAttribute("TIP", "Add suffix to filename, i.e. filename_suffix.cbz"), SetAttributes(`TIP="Merge all listed files into one archive"`).
), SetCallback("VALUECHANGED_CB", iup.ValueChangedFunc(func(ih iup.Ihandle) int {
iup.Vbox( setActive()
iup.Label("Archive Format:"),
iup.List().SetAttributes(map[string]string{ return iup.DEFAULT
"DROPDOWN": "YES", })),
"VALUE": "1", ),
"1": "ZIP", iup.Vbox(
"2": "TAR", iup.Label("Output File:"),
}).SetHandle("Archive"), iup.Text().SetAttributes("VISIBLECOLUMNS=16, MINSIZE=100x").SetHandle("OutFile").
), SetAttribute("TIP", "Combined file name (default: first input + -combined)"),
).SetHandle("VboxOutput").SetAttributes("NGAP=10") iup.Space().SetAttribute("SIZE", "5x0"),
iup.Button("Browse...").SetAttributes("PADDING=DEFAULTBUTTONPADDING").
SetCallback("ACTION", iup.ActionFunc(onOutputFile)),
).SetHandle("VboxOutFile"),
).SetAttributes("NGAP=10"),
).SetHandle("VboxOutput")
vboxImage := iup.Hbox( vboxImage := iup.Hbox(
iup.Vbox( iup.Vbox(
@@ -1079,25 +1107,38 @@ func onConvert(ih iup.Ihandle) int {
return iup.DEFAULT return iup.DEFAULT
})) }))
convertErr := func(err error) {
if errors.Is(err, context.Canceled) {
if err := os.RemoveAll(conv.Workdir); err != nil {
fmt.Println(err)
}
return
}
iup.PostMessage(iup.GetHandle("dlg"), err.Error(), 0, 0)
fmt.Println(err)
if err := os.RemoveAll(conv.Workdir); err != nil {
fmt.Println(err)
}
}
go func(c *cbconvert.Converter) { go func(c *cbconvert.Converter) {
for _, file := range files { if c.Opts.Combine {
if err := c.Convert(file.Path, file.Stat); err != nil { if err := c.Combine(files); err != nil {
if errors.Is(err, context.Canceled) { convertErr(err)
if err := os.RemoveAll(c.Workdir); err != nil { }
fmt.Println(err) } else {
for _, file := range files {
if err := c.Convert(file.Path, file.Stat); err != nil {
convertErr(err)
if errors.Is(err, context.Canceled) {
break
} }
break continue
} }
iup.PostMessage(iup.GetHandle("dlg"), err.Error(), 0, 0)
fmt.Println(err)
if err := os.RemoveAll(c.Workdir); err != nil {
fmt.Println(err)
}
continue
} }
} }
@@ -1125,6 +1166,17 @@ func onOutputDirectory(ih iup.Ihandle) int {
return iup.DEFAULT return iup.DEFAULT
} }
func onOutputFile(ih iup.Ihandle) int {
name := saveDlg("Output File")
if name != "" {
iup.GetHandle("OutFile").SetAttribute("VALUE", filepath.Base(name))
iup.GetHandle("OutDir").SetAttribute("VALUE", filepath.Dir(name))
setActive()
}
return iup.DEFAULT
}
func onFilterChanged(ih iup.Ihandle) int { func onFilterChanged(ih iup.Ihandle) int {
switch ih.GetInt("VALUE") { switch ih.GetInt("VALUE") {
case 1: case 1:
@@ -1196,3 +1248,23 @@ func fileDlg(title string, multiple, directory bool) ([]string, error) {
return ret, nil return ret, nil
} }
func saveDlg(title string) string {
dlg := iup.FileDlg()
defer dlg.Destroy()
dlg.SetAttributes(map[string]string{
"DIALOGTYPE": "SAVE",
"EXTFILTER": "Comic Files|*.cbz;*.cbt|",
"FILTER": "*.cb*", // for Motif
"TITLE": title,
})
iup.Popup(dlg, iup.CENTERPARENT, iup.CENTERPARENT)
if dlg.GetInt("STATUS") == -1 {
return ""
}
return dlg.GetAttribute("VALUE")
}
+15 -2
View File
@@ -114,6 +114,17 @@ func main() {
} }
} }
if opts.Combine {
if err := conv.Combine(files); err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Fprintf(os.Stderr, "\r")
return
}
for _, file := range files { for _, file := range files {
switch { switch {
case opts.Meta: case opts.Meta:
@@ -169,6 +180,8 @@ func parseFlags() (cbconvert.Options, []string) {
convert.IntVar(&opts.Quality, "quality", 75, "Image quality") convert.IntVar(&opts.Quality, "quality", 75, "Image quality")
convert.IntVar(&opts.Effort, "effort", -1, "Encoder speed/effort, format-specific (webp method 0-6, avif speed 0-10, jxl effort 1-10), -1 uses the format default") convert.IntVar(&opts.Effort, "effort", -1, "Encoder speed/effort, format-specific (webp method 0-6, avif speed 0-10, jxl effort 1-10), -1 uses the format default")
convert.BoolVar(&opts.Lossless, "lossless", false, "Lossless compression (webp, avif, jxl), ignores quality") convert.BoolVar(&opts.Lossless, "lossless", false, "Lossless compression (webp, avif, jxl), ignores quality")
convert.BoolVar(&opts.Combine, "combine", false, "Combine all inputs into a single archive")
convert.StringVar(&opts.OutFile, "outfile", "", "Output file name for --combine (default: first input + -combined)")
convert.IntVar(&opts.Filter, "filter", 2, "0=NearestNeighbor, 1=Box, 2=Linear, 3=MitchellNetravali, 4=CatmullRom, 6=Gaussian, 7=Lanczos") convert.IntVar(&opts.Filter, "filter", 2, "0=NearestNeighbor, 1=Box, 2=Linear, 3=MitchellNetravali, 4=CatmullRom, 6=Gaussian, 7=Lanczos")
convert.BoolVar(&opts.NoCover, "no-cover", false, "Do not convert the cover image") convert.BoolVar(&opts.NoCover, "no-cover", false, "Do not convert the cover image")
convert.BoolVar(&opts.NoRGB, "no-rgb", false, "Do not convert images that have RGB colorspace") convert.BoolVar(&opts.NoRGB, "no-rgb", false, "Do not convert images that have RGB colorspace")
@@ -222,7 +235,7 @@ func parseFlags() (cbconvert.Options, []string) {
fmt.Fprintf(os.Stderr, "Usage: %s <command> [<flags>] [file1 dir1 ... fileOrDirN]\n\n", filepath.Base(os.Args[0])) fmt.Fprintf(os.Stderr, "Usage: %s <command> [<flags>] [file1 dir1 ... fileOrDirN]\n\n", filepath.Base(os.Args[0]))
fmt.Fprintf(os.Stderr, "\nCommands:\n") fmt.Fprintf(os.Stderr, "\nCommands:\n")
fmt.Fprintf(os.Stderr, "\n convert\n \tConvert archive or document\n\n") fmt.Fprintf(os.Stderr, "\n convert\n \tConvert archive or document\n\n")
order := []string{"width", "height", "fit", "format", "archive", "quality", "effort", "lossless", "filter", "no-cover", "no-rgb", order := []string{"width", "height", "fit", "format", "archive", "quality", "effort", "lossless", "combine", "outfile", "filter", "no-cover", "no-rgb",
"no-nonimage", "no-convert", "grayscale", "rotate", "brightness", "contrast", "suffix", "outdir", "size", "recursive", "quiet"} "no-nonimage", "no-convert", "grayscale", "rotate", "brightness", "contrast", "suffix", "outdir", "size", "recursive", "quiet"}
for _, name := range order { for _, name := range order {
f := convert.Lookup(name) f := convert.Lookup(name)
@@ -230,7 +243,7 @@ func parseFlags() (cbconvert.Options, []string) {
fmt.Fprintf(os.Stderr, "%v (default %q)\n", f.Usage, f.DefValue) fmt.Fprintf(os.Stderr, "%v (default %q)\n", f.Usage, f.DefValue)
} }
fmt.Fprintf(os.Stderr, "\n cover\n \tExtract cover\n\n") fmt.Fprintf(os.Stderr, "\n cover\n \tExtract cover\n\n")
order = []string{"width", "height", "fit", "format", "quality", "effort", "lossless", "filter", "outdir", "size", "recursive", "quiet"} order = []string{"width", "height", "fit", "format", "quality", "effort", "lossless", "combine", "outfile", "filter", "outdir", "size", "recursive", "quiet"}
for _, name := range order { for _, name := range order {
f := cover.Lookup(name) f := cover.Lookup(name)
fmt.Fprintf(os.Stderr, " --%s\n \t", f.Name) fmt.Fprintf(os.Stderr, " --%s\n \t", f.Name)