mirror of
https://github.com/gen2brain/cbconvert
synced 2025-10-14 02:28:51 +02:00
Add support for CBT
This commit is contained in:
10
README.md
10
README.md
@@ -9,7 +9,7 @@ It can convert comics to different formats to fit your various devices.
|
||||
### Features
|
||||
|
||||
* reads RAR, ZIP, 7Z, CBR, CBZ, CB7, CBT, PDF, EPUB, and plain directory
|
||||
* always saves processed comics in CBZ (ZIP) archive format
|
||||
* saves processed comics in CBZ (ZIP) archive format or CBT (TAR)
|
||||
* images can be converted to JPEG, PNG, TIFF, WEBP, AVIF, or 4-Bit BMP (16 colors) file format
|
||||
* rotate, flip, adjust brightness/contrast, adjust levels (Photoshop-like) or grayscale images
|
||||
* resize algorithms (NearestNeighbor, Box, Linear, MitchellNetravali, CatmullRom, Gaussian, Lanczos)
|
||||
@@ -32,7 +32,7 @@ Copy cbconvert cli binary to your PATH and create file ~/.local/share/thumbnaile
|
||||
[Thumbnailer Entry]
|
||||
TryExec=cbconvert
|
||||
Exec=cbconvert thumbnail --quiet --width %s --outfile %o %i
|
||||
MimeType=application/pdf;application/x-pdf;image/pdf;application/x-cbz;application/x-cbr;application/x-cb7;application/x-cbt;application/epub+zip;application/vnd.comicbook-rar;application/vnd.comicbook+zip;
|
||||
MimeType=application/pdf;application/x-cb7;application/x-cbt;application/epub+zip;application/vnd.comicbook-rar;application/vnd.comicbook+zip;
|
||||
```
|
||||
|
||||
This is what it looks like in the PCManFM file manager:
|
||||
@@ -59,6 +59,8 @@ This is what it looks like in the PCManFM file manager:
|
||||
Best fit for required width and height (default "false")
|
||||
--format
|
||||
Image format, valid values are jpeg, png, tiff, bmp, webp, avif (default "jpeg")
|
||||
--archive
|
||||
Archive format, valid values are zip, tar (default "zip")
|
||||
--quality
|
||||
Image quality (default "75")
|
||||
--lossless
|
||||
@@ -156,9 +158,9 @@ This is what it looks like in the PCManFM file manager:
|
||||
--cover
|
||||
Print cover name (default "false")
|
||||
--comment
|
||||
Print comment (default "false")
|
||||
Print zip comment (default "false")
|
||||
--comment-body
|
||||
Set comment (default "")
|
||||
Set zip comment (default "")
|
||||
|
||||
```
|
||||
|
||||
|
90
cbconvert.go
90
cbconvert.go
@@ -1,6 +1,7 @@
|
||||
package cbconvert
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"context"
|
||||
@@ -68,6 +69,8 @@ var filters = map[int]imaging.ResampleFilter{
|
||||
type Options struct {
|
||||
// Image format, valid values are jpeg, png, tiff, bmp, webp, avif
|
||||
Format string
|
||||
// Archive format, valid values are zip, tar
|
||||
Archive string
|
||||
// JPEG image quality
|
||||
Quality int
|
||||
// Lossless compression (avif)
|
||||
@@ -701,6 +704,17 @@ func (c *Convertor) imEncode(i image.Image, fileName string) error {
|
||||
|
||||
// archiveSave saves workdir to CBZ archive.
|
||||
func (c *Convertor) archiveSave(fileName string) error {
|
||||
if c.Opts.Archive == "zip" {
|
||||
return c.archiveSaveZip(fileName)
|
||||
} else if c.Opts.Archive == "tar" {
|
||||
return c.archiveSaveTar(fileName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// archiveSaveZip saves workdir to CBZ archive.
|
||||
func (c *Convertor) archiveSaveZip(fileName string) error {
|
||||
if c.OnCompress != nil {
|
||||
c.OnCompress()
|
||||
}
|
||||
@@ -709,50 +723,108 @@ func (c *Convertor) archiveSave(fileName string) error {
|
||||
|
||||
zipFile, err := os.Create(zipName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("archiveSave: %w", err)
|
||||
return fmt.Errorf("archiveSaveZip: %w", err)
|
||||
}
|
||||
|
||||
z := zip.NewWriter(zipFile)
|
||||
|
||||
files, err := os.ReadDir(c.Workdir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("archiveSave: %w", err)
|
||||
return fmt.Errorf("archiveSaveZip: %w", err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
r, err := os.ReadFile(filepath.Join(c.Workdir, file.Name()))
|
||||
if err != nil {
|
||||
return fmt.Errorf("archiveSave: %w", err)
|
||||
return fmt.Errorf("archiveSaveZip: %w", err)
|
||||
}
|
||||
|
||||
info, err := file.Info()
|
||||
if err != nil {
|
||||
return fmt.Errorf("archiveSave: %w", err)
|
||||
return fmt.Errorf("archiveSaveZip: %w", err)
|
||||
}
|
||||
|
||||
zipInfo, err := zip.FileInfoHeader(info)
|
||||
if err != nil {
|
||||
return fmt.Errorf("archiveSave: %w", err)
|
||||
return fmt.Errorf("archiveSaveZip: %w", err)
|
||||
}
|
||||
|
||||
zipInfo.Method = zip.Deflate
|
||||
w, err := z.CreateHeader(zipInfo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("archiveSave: %w", err)
|
||||
return fmt.Errorf("archiveSaveZip: %w", err)
|
||||
}
|
||||
|
||||
_, err = w.Write(r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("archiveSave: %w", err)
|
||||
return fmt.Errorf("archiveSaveZip: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = z.Close(); err != nil {
|
||||
return fmt.Errorf("archiveSave: %w", err)
|
||||
return fmt.Errorf("archiveSaveZip: %w", err)
|
||||
}
|
||||
|
||||
if err = zipFile.Close(); err != nil {
|
||||
return fmt.Errorf("archiveSave: %w", err)
|
||||
return fmt.Errorf("archiveSaveZip: %w", err)
|
||||
}
|
||||
|
||||
return os.RemoveAll(c.Workdir)
|
||||
}
|
||||
|
||||
// archiveSaveTar saves workdir to CBT archive.
|
||||
func (c *Convertor) archiveSaveTar(fileName string) error {
|
||||
if c.OnCompress != nil {
|
||||
c.OnCompress()
|
||||
}
|
||||
|
||||
tarName := filepath.Join(c.Opts.Outdir, fmt.Sprintf("%s%s.cbt", c.baseNoExt(fileName), c.Opts.Suffix))
|
||||
|
||||
tarFile, err := os.Create(tarName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("archiveSaveTar: %w", err)
|
||||
}
|
||||
|
||||
tw := tar.NewWriter(tarFile)
|
||||
|
||||
files, err := os.ReadDir(c.Workdir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("archiveSaveTar: %w", err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
r, err := os.ReadFile(filepath.Join(c.Workdir, file.Name()))
|
||||
if err != nil {
|
||||
return fmt.Errorf("archiveSaveTar: %w", err)
|
||||
}
|
||||
|
||||
info, err := file.Info()
|
||||
if err != nil {
|
||||
return fmt.Errorf("archiveSaveTar: %w", err)
|
||||
}
|
||||
|
||||
header, err := tar.FileInfoHeader(info, info.Name())
|
||||
if err != nil {
|
||||
return fmt.Errorf("archiveSaveTar: %w", err)
|
||||
}
|
||||
|
||||
err = tw.WriteHeader(header)
|
||||
if err != nil {
|
||||
return fmt.Errorf("archiveSaveTar: %w", err)
|
||||
}
|
||||
|
||||
_, err = tw.Write(r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("archiveSaveTar: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = tw.Close(); err != nil {
|
||||
return fmt.Errorf("archiveSaveTar: %w", err)
|
||||
}
|
||||
|
||||
if err = tarFile.Close(); err != nil {
|
||||
return fmt.Errorf("archiveSaveTar: %w", err)
|
||||
}
|
||||
|
||||
return os.RemoveAll(c.Workdir)
|
||||
|
@@ -135,6 +135,7 @@ func parseFlags() (cbconvert.Options, []string) {
|
||||
convert.IntVar(&opts.Height, "height", 0, "Image height")
|
||||
convert.BoolVar(&opts.Fit, "fit", false, "Best fit for required width and height")
|
||||
convert.StringVar(&opts.Format, "format", "jpeg", "Image format, valid values are jpeg, png, tiff, bmp, webp, avif")
|
||||
convert.StringVar(&opts.Archive, "archive", "zip", "Archive format, valid values are zip, tar")
|
||||
convert.IntVar(&opts.Quality, "quality", 75, "Image quality")
|
||||
convert.BoolVar(&opts.Lossless, "lossless", false, "Lossless compression (avif)")
|
||||
convert.IntVar(&opts.Filter, "filter", 2, "0=NearestNeighbor, 1=Box, 2=Linear, 3=MitchellNetravali, 4=CatmullRom, 6=Gaussian, 7=Lanczos")
|
||||
@@ -186,8 +187,8 @@ func parseFlags() (cbconvert.Options, []string) {
|
||||
meta := flag.NewFlagSet("meta", flag.ExitOnError)
|
||||
meta.SortFlags = false
|
||||
meta.BoolVar(&opts.Cover, "cover", false, "Print cover name")
|
||||
meta.BoolVar(&opts.Comment, "comment", false, "Print comment")
|
||||
meta.StringVar(&opts.CommentBody, "comment-body", "", "Set comment")
|
||||
meta.BoolVar(&opts.Comment, "comment", false, "Print zip comment")
|
||||
meta.StringVar(&opts.CommentBody, "comment-body", "", "Set zip comment")
|
||||
|
||||
convert.Usage = func() {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "Usage: %s <command> [<flags>] [file1 dir1 ... fileOrDirN]\n\n", filepath.Base(os.Args[0]))
|
||||
|
Reference in New Issue
Block a user