mirror of
https://github.com/gen2brain/cbconvert
synced 2025-10-14 10:38:51 +02:00
use unarr instead of libarchive
This commit is contained in:
16
README.md
16
README.md
@@ -26,9 +26,9 @@ Download
|
|||||||
Compile
|
Compile
|
||||||
-------
|
-------
|
||||||
|
|
||||||
Install poppler, poppler-glib, cairo, libarchive and imagemagick dev packages:
|
Install poppler, poppler-glib, cairo and imagemagick dev packages:
|
||||||
|
|
||||||
apt-get install libpoppler-glib-dev libcairo2-dev libarchive-dev libmagickcore-dev libmagickwand-dev
|
apt-get install libpoppler-glib-dev libcairo2-dev libmagickcore-dev libmagickwand-dev
|
||||||
|
|
||||||
Install go package:
|
Install go package:
|
||||||
|
|
||||||
@@ -38,9 +38,9 @@ Install go package:
|
|||||||
Dependencies
|
Dependencies
|
||||||
------------
|
------------
|
||||||
|
|
||||||
go get github.com/MStoykov/go-libarchive
|
|
||||||
go get github.com/cheggaaa/go-poppler
|
go get github.com/cheggaaa/go-poppler
|
||||||
go get github.com/cheggaaa/pb
|
go get github.com/cheggaaa/pb
|
||||||
|
go get github.com/gen2brain/go-unarr
|
||||||
go get github.com/gographics/imagick/imagick
|
go get github.com/gographics/imagick/imagick
|
||||||
go get github.com/hotei/bmp
|
go get github.com/hotei/bmp
|
||||||
go get github.com/nfnt/resize
|
go get github.com/nfnt/resize
|
||||||
@@ -80,14 +80,16 @@ Using
|
|||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
Rescale images to 1200px for all supported files found in directory with size larger then 60MB:
|
||||||
|
|
||||||
cbconvert --recursive --width 1200 --size 60 /media/comics/Thorgal/
|
cbconvert --recursive --width 1200 --size 60 /media/comics/Thorgal/
|
||||||
|
|
||||||
Rescale images to 1200px for all supported files found in directory with size larger then 60MB.
|
Convert all images in archive to 4bit BMP image and save result in ~/comics directory:
|
||||||
|
|
||||||
cbconvert --bmp --outdir ~/comics /media/comics/Garfield/Garfield_01.cbz
|
cbconvert --bmp --outdir ~/comics /media/comics/Garfield/Garfield_01.cbz
|
||||||
|
|
||||||
Convert all images in archive to 4bit BMP image and save result in ~/comics directory. [BMP](http://en.wikipedia.org/wiki/BMP_file_format) format is uncompressed, for black&white pages very good choice. Archive size can be smaller 2-3x and file will be readable by comic readers.
|
[BMP](http://en.wikipedia.org/wiki/BMP_file_format) format is uncompressed, for black&white pages very good choice. Archive size can be smaller 2-3x and file will be readable by comic readers.
|
||||||
|
|
||||||
|
Generate thumbnails by freedesktop specification in ~/.thumbnails/normal directory, Lanczos3 algorithm is used for resizing:
|
||||||
|
|
||||||
cbconvert --interpolation=5 --outdir ~/.thumbnails/normal --thumbnail /media/comics/GrooTheWanderer/
|
cbconvert --interpolation=5 --outdir ~/.thumbnails/normal --thumbnail /media/comics/GrooTheWanderer/
|
||||||
|
|
||||||
Generate thumbnails by freedesktop specification in ~/.thumbnails/normal directory, Lanczos3 algorithm is used for resizing.
|
|
||||||
|
136
cbconvert.go
136
cbconvert.go
@@ -39,9 +39,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/MStoykov/go-libarchive"
|
|
||||||
"github.com/cheggaaa/go-poppler"
|
"github.com/cheggaaa/go-poppler"
|
||||||
"github.com/cheggaaa/pb"
|
"github.com/cheggaaa/pb"
|
||||||
|
"github.com/gen2brain/go-unarr"
|
||||||
"github.com/gographics/imagick/imagick"
|
"github.com/gographics/imagick/imagick"
|
||||||
_ "github.com/hotei/bmp"
|
_ "github.com/hotei/bmp"
|
||||||
"github.com/nfnt/resize"
|
"github.com/nfnt/resize"
|
||||||
@@ -199,69 +199,63 @@ func convertPDF(file string) {
|
|||||||
func convertArchive(file string) {
|
func convertArchive(file string) {
|
||||||
workdir, _ = ioutil.TempDir(os.TempDir(), "cbc")
|
workdir, _ = ioutil.TempDir(os.TempDir(), "cbc")
|
||||||
|
|
||||||
f, err := os.Open(file)
|
ncontents := len(listArchive(file))
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Error Open: %v\n", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
reader, err := archive.NewReader(f)
|
archive, err := unarr.NewArchive(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error NewReader: %v\n", err.Error())
|
fmt.Fprintf(os.Stderr, "Error NewReader: %v\n", err.Error())
|
||||||
}
|
}
|
||||||
defer reader.Free()
|
defer archive.Close()
|
||||||
defer reader.Close()
|
|
||||||
|
|
||||||
var bar *pb.ProgressBar
|
var bar *pb.ProgressBar
|
||||||
if !opts.Quiet {
|
if !opts.Quiet {
|
||||||
s, _ := f.Stat()
|
bar = pb.New(ncontents)
|
||||||
bar = pb.New(int(s.Size()))
|
|
||||||
bar.SetUnits(pb.U_BYTES)
|
|
||||||
bar.ShowTimeLeft = false
|
bar.ShowTimeLeft = false
|
||||||
bar.Prefix(fmt.Sprintf("Converting %d of %d: ", current, nfiles))
|
bar.Prefix(fmt.Sprintf("Converting %d of %d: ", current, nfiles))
|
||||||
bar.Start()
|
bar.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
entry, err := reader.Next()
|
err := archive.Entry()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == archive.ErrArchiveEOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(os.Stderr, "Error Next: %v\n", err.Error())
|
fmt.Fprintf(os.Stderr, "Error Entry: %v\n", err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stat := entry.Stat()
|
|
||||||
if stat.Mode()&os.ModeType != 0 || stat.IsDir() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !opts.Quiet {
|
if !opts.Quiet {
|
||||||
size := reader.Size()
|
bar.Increment()
|
||||||
bar.Set(size)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pathname := entry.PathName()
|
size := archive.Size()
|
||||||
|
pathname := archive.Name()
|
||||||
|
|
||||||
|
buf := make([]byte, size)
|
||||||
|
for size > 0 {
|
||||||
|
n, err := archive.Read(buf)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
size -= n
|
||||||
|
}
|
||||||
|
|
||||||
|
if size > 0 {
|
||||||
|
fmt.Printf("Error Read\n")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if isImage(pathname) {
|
if isImage(pathname) {
|
||||||
buf := new(bytes.Buffer)
|
img, err := decodeImage(bytes.NewReader(buf), pathname)
|
||||||
_, err := buf.ReadFrom(reader)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Error ReadFrom: %v\n", err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
img, err := decodeImage(bytes.NewReader(buf.Bytes()), pathname)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error Decode: %v\n", err.Error())
|
fmt.Fprintf(os.Stderr, "Error Decode: %v\n", err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.NoRGB && !isGrayScale(img) {
|
if opts.NoRGB && !isGrayScale(img) {
|
||||||
copyFile(bytes.NewReader(buf.Bytes()), filepath.Join(workdir, filepath.Base(pathname)))
|
copyFile(bytes.NewReader(buf), filepath.Join(workdir, filepath.Base(pathname)))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +265,7 @@ func convertArchive(file string) {
|
|||||||
go convertImage(img, 0, pathname)
|
go convertImage(img, 0, pathname)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
copyFile(reader, filepath.Join(workdir, filepath.Base(pathname)))
|
copyFile(bytes.NewReader(buf), filepath.Join(workdir, filepath.Base(pathname)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
@@ -368,64 +362,72 @@ func saveArchive(file string) {
|
|||||||
z.Close()
|
z.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unpacks archive to directory
|
// Lists contents of archive
|
||||||
func unpackArchive(file string, dir string) {
|
func listArchive(file string) []string {
|
||||||
f, err := os.Open(file)
|
var contents []string
|
||||||
if err != nil {
|
archive, err := unarr.NewArchive(file)
|
||||||
fmt.Fprintf(os.Stderr, "Error Open: %v\n", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
reader, err := archive.NewReader(f)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error NewReader: %v\n", err.Error())
|
fmt.Fprintf(os.Stderr, "Error NewReader: %v\n", err.Error())
|
||||||
return
|
|
||||||
}
|
}
|
||||||
defer reader.Free()
|
defer archive.Close()
|
||||||
defer reader.Close()
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
entry, err := reader.Next()
|
err := archive.Entry()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == archive.ErrArchiveEOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error Entry: %v\n", err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if entry.Stat().Mode()&os.ModeType == 0 {
|
pathname := archive.Name()
|
||||||
err = copyFile(reader, filepath.Join(dir, entry.PathName()))
|
contents = append(contents, pathname)
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err.Error())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return contents
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extracts cover from archive
|
// Extracts cover from archive
|
||||||
func coverArchive(file string) (image.Image, error) {
|
func coverArchive(file string) (image.Image, error) {
|
||||||
tmpdir, _ := ioutil.TempDir(os.TempDir(), "cbc")
|
var images []string
|
||||||
defer os.RemoveAll(tmpdir)
|
|
||||||
|
|
||||||
unpackArchive(file, tmpdir)
|
contents := listArchive(file)
|
||||||
|
for _, c := range contents {
|
||||||
images := getImages(tmpdir)
|
if isImage(c) {
|
||||||
if len(images) == 0 {
|
images = append(images, c)
|
||||||
return nil, errors.New("No images")
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cover := getCover(images)
|
cover := getCover(images)
|
||||||
|
|
||||||
p, err := os.Open(cover)
|
archive, err := unarr.NewArchive(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer p.Close()
|
defer archive.Close()
|
||||||
|
|
||||||
img, err := decodeImage(p, cover)
|
err = archive.EntryFor(cover)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
size := archive.Size()
|
||||||
|
buf := make([]byte, size)
|
||||||
|
for size > 0 {
|
||||||
|
n, err := archive.Read(buf)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
size -= n
|
||||||
|
}
|
||||||
|
|
||||||
|
if size > 0 {
|
||||||
|
return nil, errors.New("Error Read")
|
||||||
|
}
|
||||||
|
|
||||||
|
img, err := decodeImage(bytes.NewReader(buf), cover)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -759,7 +761,7 @@ func convertComic(file string, info os.FileInfo) {
|
|||||||
// Parses command line flags
|
// Parses command line flags
|
||||||
func parseFlags() {
|
func parseFlags() {
|
||||||
opts = options{}
|
opts = options{}
|
||||||
kingpin.Version("CBconvert 0.1.0")
|
kingpin.Version("CBconvert 0.2.0")
|
||||||
kingpin.CommandLine.Help = "Comic Book convert tool."
|
kingpin.CommandLine.Help = "Comic Book convert tool."
|
||||||
kingpin.Flag("png", "encode images to PNG instead of JPEG").Short('p').BoolVar(&opts.ToPNG)
|
kingpin.Flag("png", "encode images to PNG instead of JPEG").Short('p').BoolVar(&opts.ToPNG)
|
||||||
kingpin.Flag("bmp", "encode images to 4-Bit BMP instead of JPEG").Short('b').BoolVar(&opts.ToBMP)
|
kingpin.Flag("bmp", "encode images to 4-Bit BMP instead of JPEG").Short('b').BoolVar(&opts.ToBMP)
|
||||||
|
Reference in New Issue
Block a user