convertor struct

This commit is contained in:
Milan Nikolic
2015-11-05 09:54:21 +01:00
parent bc8520d825
commit d77d2c0ce7

View File

@@ -72,6 +72,14 @@ var filters = map[int]imaging.ResampleFilter{
Lanczos: imaging.Lanczos, Lanczos: imaging.Lanczos,
} }
var (
bar *pb.ProgressBar
wg sync.WaitGroup
)
// Limits go routines to number of CPUs + 1
var throttle = make(chan int, runtime.NumCPU()+1)
// Options // Options
type Options struct { type Options struct {
ToPNG bool // encode images to PNG instead of JPEG ToPNG bool // encode images to PNG instead of JPEG
@@ -99,66 +107,65 @@ type Options struct {
Quiet bool // hide console output Quiet bool // hide console output
} }
// Globals // Convertor struct
var ( type Convertor struct {
opts Options Opts Options // Options struct
workdir string Workdir string // Current working directory
nfiles int Nfiles int // Number of files
current int Current int // Index of current file
bar *pb.ProgressBar }
wg sync.WaitGroup
)
// Command line arguments // NewConvertor returns new convertor
var arguments []string func NewConvertor(o Options) *Convertor {
c := &Convertor{}
// Limits go routines to number of CPUs + 1 c.Opts = o
var throttle = make(chan int, runtime.NumCPU()+1) return c
}
// Converts image // Converts image
func convertImage(img image.Image, index int, pathName string) { func (c *Convertor) convertImage(img image.Image, index int, pathName string) {
defer wg.Done() defer wg.Done()
var ext string = "jpg" var ext string = "jpg"
if opts.ToPNG { if c.Opts.ToPNG {
ext = "png" ext = "png"
} else if opts.ToBMP { } else if c.Opts.ToBMP {
ext = "bmp" ext = "bmp"
} else if opts.ToGIF { } else if c.Opts.ToGIF {
ext = "gif" ext = "gif"
} else if opts.ToTIFF { } else if c.Opts.ToTIFF {
ext = "tiff" ext = "tiff"
} }
var filename string var filename string
if pathName != "" { if pathName != "" {
filename = filepath.Join(workdir, fmt.Sprintf("%s.%s", getBasename(pathName), ext)) filename = filepath.Join(c.Workdir, fmt.Sprintf("%s.%s", c.getBasename(pathName), ext))
} else { } else {
filename = filepath.Join(workdir, fmt.Sprintf("%03d.%s", index, ext)) filename = filepath.Join(c.Workdir, fmt.Sprintf("%03d.%s", index, ext))
} }
if opts.ToPNG { if c.Opts.ToPNG {
// convert image to PNG // convert image to PNG
if opts.Grayscale { if c.Opts.Grayscale {
encodeImageMagick(img, filename) c.encodeImageMagick(img, filename)
} else { } else {
encodeImage(img, filename) c.encodeImage(img, filename)
} }
} else if opts.ToBMP { } else if c.Opts.ToBMP {
// convert image to 4-Bit BMP (16 colors) // convert image to 4-Bit BMP (16 colors)
encodeImageMagick(img, filename) c.encodeImageMagick(img, filename)
} else if opts.ToGIF { } else if c.Opts.ToGIF {
// convert image to GIF // convert image to GIF
encodeImageMagick(img, filename) c.encodeImageMagick(img, filename)
} else if opts.ToTIFF { } else if c.Opts.ToTIFF {
// convert image to TIFF // convert image to TIFF
encodeImage(img, filename) c.encodeImage(img, filename)
} else { } else {
// convert image to JPEG (default) // convert image to JPEG (default)
if opts.Grayscale { if c.Opts.Grayscale {
encodeImageMagick(img, filename) c.encodeImageMagick(img, filename)
} else { } else {
encodeImage(img, filename) c.encodeImage(img, filename)
} }
} }
@@ -166,19 +173,19 @@ func convertImage(img image.Image, index int, pathName string) {
} }
// Transforms image (resize, rotate, flip, brightness, contrast) // Transforms image (resize, rotate, flip, brightness, contrast)
func transformImage(img image.Image) image.Image { func (c *Convertor) transformImage(img image.Image) image.Image {
var i image.Image = img var i image.Image = img
if opts.Width > 0 || opts.Height > 0 { if c.Opts.Width > 0 || c.Opts.Height > 0 {
if opts.Fit { if c.Opts.Fit {
i = imaging.Fit(i, opts.Width, opts.Height, filters[opts.Filter]) i = imaging.Fit(i, c.Opts.Width, c.Opts.Height, filters[c.Opts.Filter])
} else { } else {
i = imaging.Resize(i, opts.Width, opts.Height, filters[opts.Filter]) i = imaging.Resize(i, c.Opts.Width, c.Opts.Height, filters[c.Opts.Filter])
} }
} }
if opts.Rotate > 0 { if c.Opts.Rotate > 0 {
switch opts.Rotate { switch c.Opts.Rotate {
case 90: case 90:
i = imaging.Rotate90(i) i = imaging.Rotate90(i)
case 180: case 180:
@@ -188,8 +195,8 @@ func transformImage(img image.Image) image.Image {
} }
} }
if opts.Flip != "none" { if c.Opts.Flip != "none" {
switch opts.Flip { switch c.Opts.Flip {
case "horizontal": case "horizontal":
i = imaging.FlipH(i) i = imaging.FlipH(i)
case "vertical": case "vertical":
@@ -197,20 +204,20 @@ func transformImage(img image.Image) image.Image {
} }
} }
if opts.Brightness != 0 { if c.Opts.Brightness != 0 {
i = imaging.AdjustBrightness(i, opts.Brightness) i = imaging.AdjustBrightness(i, c.Opts.Brightness)
} }
if opts.Contrast != 0 { if c.Opts.Contrast != 0 {
i = imaging.AdjustContrast(i, opts.Contrast) i = imaging.AdjustContrast(i, c.Opts.Contrast)
} }
return i return i
} }
// Converts PDF/EPUB/XPS document to CBZ // Converts PDF/EPUB/XPS document to CBZ
func convertDocument(file string) { func (c *Convertor) convertDocument(file string) {
workdir, _ = ioutil.TempDir(os.TempDir(), "cbc") c.Workdir, _ = ioutil.TempDir(os.TempDir(), "cbc")
doc, err := fitz.NewDocument(file) doc, err := fitz.NewDocument(file)
if err != nil { if err != nil {
@@ -220,39 +227,39 @@ func convertDocument(file string) {
npages := doc.Pages() npages := doc.Pages()
if !opts.Quiet { if !c.Opts.Quiet {
bar = pb.New(npages) bar = pb.New(npages)
bar.ShowTimeLeft = false bar.ShowTimeLeft = false
bar.Prefix(fmt.Sprintf("Converting %d of %d: ", current, nfiles)) bar.Prefix(fmt.Sprintf("Converting %d of %d: ", c.Current, c.Nfiles))
bar.Start() bar.Start()
} }
for n := 0; n < npages; n++ { for n := 0; n < npages; n++ {
if !opts.Quiet { if !c.Opts.Quiet {
bar.Increment() bar.Increment()
} }
img, err := doc.Image(n) img, err := doc.Image(n)
if err == nil { if err == nil {
img = transformImage(img) img = c.transformImage(img)
} }
if img != nil { if img != nil {
throttle <- 1 throttle <- 1
wg.Add(1) wg.Add(1)
go convertImage(img, n, "") go c.convertImage(img, n, "")
} }
} }
wg.Wait() wg.Wait()
} }
// Converts archive to CBZ // Converts archive to CBZ
func convertArchive(file string) { func (c *Convertor) convertArchive(file string) {
workdir, _ = ioutil.TempDir(os.TempDir(), "cbc") c.Workdir, _ = ioutil.TempDir(os.TempDir(), "cbc")
ncontents := len(listArchive(file)) ncontents := len(c.listArchive(file))
archive, err := unarr.NewArchive(file) archive, err := unarr.NewArchive(file)
if err != nil { if err != nil {
@@ -260,10 +267,10 @@ func convertArchive(file string) {
} }
defer archive.Close() defer archive.Close()
if !opts.Quiet { if !c.Opts.Quiet {
bar = pb.New(ncontents) bar = pb.New(ncontents)
bar.ShowTimeLeft = false bar.ShowTimeLeft = false
bar.Prefix(fmt.Sprintf("Converting %d of %d: ", current, nfiles)) bar.Prefix(fmt.Sprintf("Converting %d of %d: ", c.Current, c.Nfiles))
bar.Start() bar.Start()
} }
@@ -278,7 +285,7 @@ func convertArchive(file string) {
} }
} }
if !opts.Quiet { if !c.Opts.Quiet {
bar.Increment() bar.Increment()
} }
@@ -299,28 +306,28 @@ func convertArchive(file string) {
continue continue
} }
if isImage(pathname) { if c.isImage(pathname) {
img, err := decodeImage(bytes.NewReader(buf), pathname) img, err := c.decodeImage(bytes.NewReader(buf), 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
} }
i := transformImage(img) i := c.transformImage(img)
if !opts.RGB && !isGrayScale(i) { if !c.Opts.RGB && !c.isGrayScale(i) {
encodeImage(i, filepath.Join(workdir, filepath.Base(pathname))) c.encodeImage(i, filepath.Join(c.Workdir, filepath.Base(pathname)))
continue continue
} }
if i != nil { if i != nil {
throttle <- 1 throttle <- 1
wg.Add(1) wg.Add(1)
go convertImage(i, 0, pathname) go c.convertImage(i, 0, pathname)
} }
} else { } else {
if opts.NonImage { if c.Opts.NonImage {
copyFile(bytes.NewReader(buf), filepath.Join(workdir, filepath.Base(pathname))) c.copyFile(bytes.NewReader(buf), filepath.Join(c.Workdir, filepath.Base(pathname)))
} }
} }
} }
@@ -328,20 +335,20 @@ func convertArchive(file string) {
} }
// Converts directory to CBZ // Converts directory to CBZ
func convertDirectory(path string) { func (c *Convertor) convertDirectory(path string) {
workdir, _ = ioutil.TempDir(os.TempDir(), "cbc") c.Workdir, _ = ioutil.TempDir(os.TempDir(), "cbc")
images := getImages(path) images := c.getImages(path)
if !opts.Quiet { if !c.Opts.Quiet {
bar = pb.New(nfiles) bar = pb.New(c.Nfiles)
bar.ShowTimeLeft = false bar.ShowTimeLeft = false
bar.Prefix(fmt.Sprintf("Converting %d of %d: ", current, nfiles)) bar.Prefix(fmt.Sprintf("Converting %d of %d: ", c.Current, c.Nfiles))
bar.Start() bar.Start()
} }
for index, img := range images { for index, img := range images {
if opts.Quiet { if c.Opts.Quiet {
bar.Increment() bar.Increment()
} }
@@ -351,16 +358,16 @@ func convertDirectory(path string) {
continue continue
} }
i, err := decodeImage(f, img) i, err := c.decodeImage(f, img)
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
} }
i = transformImage(i) i = c.transformImage(i)
if !opts.RGB && !isGrayScale(i) { if !c.Opts.RGB && !c.isGrayScale(i) {
encodeImage(i, filepath.Join(workdir, filepath.Base(img))) c.encodeImage(i, filepath.Join(c.Workdir, filepath.Base(img)))
continue continue
} }
@@ -369,17 +376,17 @@ func convertDirectory(path string) {
if i != nil { if i != nil {
throttle <- 1 throttle <- 1
wg.Add(1) wg.Add(1)
go convertImage(i, index, img) go c.convertImage(i, index, img)
} }
} }
wg.Wait() wg.Wait()
} }
// Saves workdir to CBZ archive // Saves workdir to CBZ archive
func saveArchive(file string) { func (c *Convertor) saveArchive(file string) {
defer os.RemoveAll(workdir) defer os.RemoveAll(c.Workdir)
zipname := filepath.Join(opts.Outdir, fmt.Sprintf("%s%s.cbz", getBasename(file), opts.Suffix)) zipname := filepath.Join(c.Opts.Outdir, fmt.Sprintf("%s%s.cbz", c.getBasename(file), c.Opts.Suffix))
zipfile, err := os.Create(zipname) zipfile, err := os.Create(zipname)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Error Create: %v\n", err.Error()) fmt.Fprintf(os.Stderr, "Error Create: %v\n", err.Error())
@@ -388,21 +395,21 @@ func saveArchive(file string) {
defer zipfile.Close() defer zipfile.Close()
z := zip.NewWriter(zipfile) z := zip.NewWriter(zipfile)
files, _ := ioutil.ReadDir(workdir) files, _ := ioutil.ReadDir(c.Workdir)
if !opts.Quiet { if !c.Opts.Quiet {
bar = pb.New(len(files)) bar = pb.New(len(files))
bar.ShowTimeLeft = false bar.ShowTimeLeft = false
bar.Prefix(fmt.Sprintf("Compressing %d of %d: ", current, nfiles)) bar.Prefix(fmt.Sprintf("Compressing %d of %d: ", c.Current, c.Nfiles))
bar.Start() bar.Start()
} }
for _, file := range files { for _, file := range files {
if !opts.Quiet { if !c.Opts.Quiet {
bar.Increment() bar.Increment()
} }
r, err := ioutil.ReadFile(filepath.Join(workdir, file.Name())) r, err := ioutil.ReadFile(filepath.Join(c.Workdir, file.Name()))
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Error ReadFile: %v\n", err.Error()) fmt.Fprintf(os.Stderr, "Error ReadFile: %v\n", err.Error())
continue continue
@@ -419,7 +426,7 @@ func saveArchive(file string) {
} }
// Decodes image from reader // Decodes image from reader
func decodeImage(reader io.Reader, filename string) (i image.Image, err error) { func (c *Convertor) decodeImage(reader io.Reader, filename string) (i image.Image, err error) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "Recovered in decodeImage %s: %v\n", filename, r) fmt.Fprintf(os.Stderr, "Recovered in decodeImage %s: %v\n", filename, r)
@@ -431,7 +438,7 @@ func decodeImage(reader io.Reader, filename string) (i image.Image, err error) {
} }
// Encode image to file // Encode image to file
func encodeImage(i image.Image, filename string) (err error) { func (c *Convertor) encodeImage(i image.Image, filename string) (err error) {
f, err := os.Create(filename) f, err := os.Create(filename)
if err != nil { if err != nil {
return return
@@ -446,7 +453,7 @@ func encodeImage(i image.Image, filename string) (err error) {
case ".gif": case ".gif":
err = gif.Encode(f, i, nil) err = gif.Encode(f, i, nil)
default: default:
err = jpeg.Encode(f, i, &jpeg.Options{opts.Quality}) err = jpeg.Encode(f, i, &jpeg.Options{c.Opts.Quality})
} }
f.Close() f.Close()
@@ -454,14 +461,14 @@ func encodeImage(i image.Image, filename string) (err error) {
} }
// Encode image to file (ImageMagick) // Encode image to file (ImageMagick)
func encodeImageMagick(i image.Image, filename string) (err error) { func (c *Convertor) encodeImageMagick(i image.Image, filename string) (err error) {
imagick.Initialize() imagick.Initialize()
mw := imagick.NewMagickWand() mw := imagick.NewMagickWand()
defer mw.Destroy() defer mw.Destroy()
b := new(bytes.Buffer) b := new(bytes.Buffer)
jpeg.Encode(b, i, &jpeg.Options{opts.Quality}) jpeg.Encode(b, i, &jpeg.Options{c.Opts.Quality})
err = mw.ReadImageBlob(b.Bytes()) err = mw.ReadImageBlob(b.Bytes())
if err != nil { if err != nil {
@@ -469,7 +476,7 @@ func encodeImageMagick(i image.Image, filename string) (err error) {
return return
} }
if opts.Grayscale { if c.Opts.Grayscale {
c := mw.GetImageColors() c := mw.GetImageColors()
mw.QuantizeImage(c, imagick.COLORSPACE_GRAY, 8, true, true) mw.QuantizeImage(c, imagick.COLORSPACE_GRAY, 8, true, true)
} }
@@ -487,7 +494,7 @@ func encodeImageMagick(i image.Image, filename string) (err error) {
defer w.Destroy() defer w.Destroy()
cs := mw.GetImageColorspace() cs := mw.GetImageColorspace()
if opts.Grayscale { if c.Opts.Grayscale {
cs = imagick.COLORSPACE_GRAY cs = imagick.COLORSPACE_GRAY
} }
@@ -508,7 +515,7 @@ func encodeImageMagick(i image.Image, filename string) (err error) {
} }
// Lists contents of archive // Lists contents of archive
func listArchive(file string) []string { func (c *Convertor) listArchive(file string) []string {
var contents []string var contents []string
archive, err := unarr.NewArchive(file) archive, err := unarr.NewArchive(file)
if err != nil { if err != nil {
@@ -535,17 +542,17 @@ func listArchive(file string) []string {
} }
// Extracts cover from archive // Extracts cover from archive
func coverArchive(file string) (image.Image, error) { func (c *Convertor) coverArchive(file string) (image.Image, error) {
var images []string var images []string
contents := listArchive(file) contents := c.listArchive(file)
for _, c := range contents { for _, ct := range contents {
if isImage(c) { if c.isImage(ct) {
images = append(images, c) images = append(images, ct)
} }
} }
cover := getCover(images) cover := c.getCover(images)
archive, err := unarr.NewArchive(file) archive, err := unarr.NewArchive(file)
if err != nil { if err != nil {
@@ -572,7 +579,7 @@ func coverArchive(file string) (image.Image, error) {
return nil, errors.New("Error Read") return nil, errors.New("Error Read")
} }
img, err := decodeImage(bytes.NewReader(buf), cover) img, err := c.decodeImage(bytes.NewReader(buf), cover)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -581,7 +588,7 @@ func coverArchive(file string) (image.Image, error) {
} }
// Extracts cover from document // Extracts cover from document
func coverDocument(file string) (image.Image, error) { func (c *Convertor) coverDocument(file string) (image.Image, error) {
doc, err := fitz.NewDocument(file) doc, err := fitz.NewDocument(file)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -600,9 +607,9 @@ func coverDocument(file string) (image.Image, error) {
} }
// Extracts cover from directory // Extracts cover from directory
func coverDirectory(dir string) (image.Image, error) { func (c *Convertor) coverDirectory(dir string) (image.Image, error) {
images := getImages(dir) images := c.getImages(dir)
cover := getCover(images) cover := c.getCover(images)
p, err := os.Open(cover) p, err := os.Open(cover)
if err != nil { if err != nil {
@@ -610,7 +617,7 @@ func coverDirectory(dir string) (image.Image, error) {
} }
defer p.Close() defer p.Close()
img, err := decodeImage(p, cover) img, err := c.decodeImage(p, cover)
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())
return nil, err return nil, err
@@ -624,13 +631,13 @@ func coverDirectory(dir string) (image.Image, error) {
} }
// Returns list of found comic files // Returns list of found comic files
func getFiles() []string { func (c *Convertor) GetFiles(args []string) []string {
var files []string var files []string
walkFiles := func(fp string, f os.FileInfo, err error) error { walkFiles := func(fp string, f os.FileInfo, err error) error {
if !f.IsDir() { if !f.IsDir() {
if isArchive(fp) || isDocument(fp) { if c.isArchive(fp) || c.isDocument(fp) {
if isSize(f.Size()) { if c.isSize(f.Size()) {
files = append(files, fp) files = append(files, fp)
} }
} }
@@ -638,7 +645,7 @@ func getFiles() []string {
return nil return nil
} }
for _, arg := range arguments { for _, arg := range args {
path, _ := filepath.Abs(arg) path, _ := filepath.Abs(arg)
stat, err := os.Stat(path) stat, err := os.Stat(path)
if err != nil { if err != nil {
@@ -647,19 +654,19 @@ func getFiles() []string {
} }
if !stat.IsDir() { if !stat.IsDir() {
if isArchive(path) || isDocument(path) { if c.isArchive(path) || c.isDocument(path) {
if isSize(stat.Size()) { if c.isSize(stat.Size()) {
files = append(files, path) files = append(files, path)
} }
} }
} else { } else {
if opts.Recursive { if c.Opts.Recursive {
filepath.Walk(path, walkFiles) filepath.Walk(path, walkFiles)
} else { } else {
fs, _ := ioutil.ReadDir(path) fs, _ := ioutil.ReadDir(path)
for _, f := range fs { for _, f := range fs {
if isArchive(f.Name()) || isArchive(f.Name()) { if c.isArchive(f.Name()) || c.isArchive(f.Name()) {
if isSize(f.Size()) { if c.isSize(f.Size()) {
files = append(files, filepath.Join(path, f.Name())) files = append(files, filepath.Join(path, f.Name()))
} }
} }
@@ -673,16 +680,17 @@ func getFiles() []string {
} }
} }
c.Nfiles = len(files)
return files return files
} }
// Returns list of found image files for given directory // Returns list of found image files for given directory
func getImages(path string) []string { func (c *Convertor) getImages(path string) []string {
var images []string var images []string
walkFiles := func(fp string, f os.FileInfo, err error) error { walkFiles := func(fp string, f os.FileInfo, err error) error {
if !f.IsDir() && f.Mode()&os.ModeType == 0 { if !f.IsDir() && f.Mode()&os.ModeType == 0 {
if f.Size() > 0 && isImage(fp) { if f.Size() > 0 && c.isImage(fp) {
images = append(images, fp) images = append(images, fp)
} }
} }
@@ -697,7 +705,7 @@ func getImages(path string) []string {
} }
if !stat.IsDir() && stat.Mode()&os.ModeType == 0 { if !stat.IsDir() && stat.Mode()&os.ModeType == 0 {
if isImage(f) { if c.isImage(f) {
images = append(images, f) images = append(images, f)
} }
} else { } else {
@@ -708,7 +716,7 @@ func getImages(path string) []string {
} }
// Returns the filename that is the most likely to be the cover // Returns the filename that is the most likely to be the cover
func getCover(images []string) string { func (c *Convertor) getCover(images []string) string {
if len(images) == 0 { if len(images) == 0 {
return "" return ""
} }
@@ -724,7 +732,7 @@ func getCover(images []string) string {
} }
// Checks if file is archive // Checks if file is archive
func isArchive(f string) bool { func (c *Convertor) isArchive(f string) bool {
var types = []string{".rar", ".zip", ".7z", ".gz", var types = []string{".rar", ".zip", ".7z", ".gz",
".bz2", ".cbr", ".cbz", ".cb7", ".cbt"} ".bz2", ".cbr", ".cbz", ".cb7", ".cbt"}
for _, t := range types { for _, t := range types {
@@ -736,7 +744,7 @@ func isArchive(f string) bool {
} }
// Checks if file is document // Checks if file is document
func isDocument(f string) bool { func (c *Convertor) isDocument(f string) bool {
var types = []string{".pdf", ".epub", ".xps"} var types = []string{".pdf", ".epub", ".xps"}
for _, t := range types { for _, t := range types {
if strings.ToLower(filepath.Ext(f)) == t { if strings.ToLower(filepath.Ext(f)) == t {
@@ -747,7 +755,7 @@ func isDocument(f string) bool {
} }
// Checks if file is image // Checks if file is image
func isImage(f string) bool { func (c *Convertor) isImage(f string) bool {
var types = []string{".jpg", ".jpeg", ".jpe", ".png", var types = []string{".jpg", ".jpeg", ".jpe", ".png",
".gif", ".bmp", ".tiff", ".tif", ".webp"} ".gif", ".bmp", ".tiff", ".tif", ".webp"}
for _, t := range types { for _, t := range types {
@@ -759,9 +767,9 @@ func isImage(f string) bool {
} }
// Checks size of file // Checks size of file
func isSize(size int64) bool { func (c *Convertor) isSize(size int64) bool {
if opts.Size > 0 { if c.Opts.Size > 0 {
if size < opts.Size*(1024*1024) { if size < c.Opts.Size*(1024*1024) {
return false return false
} }
} }
@@ -769,7 +777,7 @@ func isSize(size int64) bool {
} }
// Checks if image is grayscale // Checks if image is grayscale
func isGrayScale(img image.Image) bool { func (c *Convertor) isGrayScale(img image.Image) bool {
model := img.ColorModel() model := img.ColorModel()
if model == color.GrayModel || model == color.Gray16Model { if model == color.GrayModel || model == color.Gray16Model {
return true return true
@@ -778,7 +786,7 @@ func isGrayScale(img image.Image) bool {
} }
// Copies reader to file // Copies reader to file
func copyFile(reader io.Reader, filename string) error { func (c *Convertor) copyFile(reader io.Reader, filename string) error {
os.MkdirAll(filepath.Dir(filename), 0755) os.MkdirAll(filepath.Dir(filename), 0755)
file, err := os.Create(filename) file, err := os.Create(filename)
@@ -796,22 +804,24 @@ func copyFile(reader io.Reader, filename string) error {
} }
// Returns basename without extension // Returns basename without extension
func getBasename(file string) string { func (c *Convertor) getBasename(file string) string {
basename := strings.TrimSuffix(filepath.Base(file), filepath.Ext(file)) basename := strings.TrimSuffix(filepath.Base(file), filepath.Ext(file))
basename = strings.TrimSuffix(basename, ".tar") basename = strings.TrimSuffix(basename, ".tar")
return basename return basename
} }
// Extracts cover // Extracts cover
func extractCover(file string, info os.FileInfo) { func (c *Convertor) ExtractCover(file string, info os.FileInfo) {
var err error var err error
var cover image.Image var cover image.Image
c.Current += 1
if info.IsDir() { if info.IsDir() {
cover, err = coverDirectory(file) cover, err = c.coverDirectory(file)
} else if isDocument(file) { } else if c.isDocument(file) {
cover, err = coverDocument(file) cover, err = c.coverDocument(file)
} else { } else {
cover, err = coverArchive(file) cover, err = c.coverArchive(file)
} }
if err != nil { if err != nil {
@@ -819,15 +829,15 @@ func extractCover(file string, info os.FileInfo) {
return return
} }
if opts.Width > 0 || opts.Height > 0 { if c.Opts.Width > 0 || c.Opts.Height > 0 {
if opts.Fit { if c.Opts.Fit {
cover = imaging.Fit(cover, opts.Width, opts.Height, filters[opts.Filter]) cover = imaging.Fit(cover, c.Opts.Width, c.Opts.Height, filters[c.Opts.Filter])
} else { } else {
cover = imaging.Resize(cover, opts.Width, opts.Height, filters[opts.Filter]) cover = imaging.Resize(cover, c.Opts.Width, c.Opts.Height, filters[c.Opts.Filter])
} }
} }
filename := filepath.Join(opts.Outdir, fmt.Sprintf("%s.jpg", getBasename(file))) filename := filepath.Join(c.Opts.Outdir, fmt.Sprintf("%s.jpg", c.getBasename(file)))
f, err := os.Create(filename) f, err := os.Create(filename)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Error Create: %v\n", err.Error()) fmt.Fprintf(os.Stderr, "Error Create: %v\n", err.Error())
@@ -835,19 +845,21 @@ func extractCover(file string, info os.FileInfo) {
} }
defer f.Close() defer f.Close()
jpeg.Encode(f, cover, &jpeg.Options{opts.Quality}) jpeg.Encode(f, cover, &jpeg.Options{c.Opts.Quality})
} }
// Extracts thumbnail // Extracts thumbnail
func extractThumbnail(file string, info os.FileInfo) { func (c *Convertor) ExtractThumbnail(file string, info os.FileInfo) {
var err error var err error
var cover image.Image var cover image.Image
c.Current += 1
if info.IsDir() { if info.IsDir() {
cover, err = coverDirectory(file) cover, err = c.coverDirectory(file)
} else if isDocument(file) { } else if c.isDocument(file) {
cover, err = coverDocument(file) cover, err = c.coverDocument(file)
} else { } else {
cover, err = coverArchive(file) cover, err = c.coverArchive(file)
} }
if err != nil { if err != nil {
@@ -855,14 +867,14 @@ func extractThumbnail(file string, info os.FileInfo) {
return return
} }
if opts.Width > 0 || opts.Height > 0 { if c.Opts.Width > 0 || c.Opts.Height > 0 {
if opts.Fit { if c.Opts.Fit {
cover = imaging.Fit(cover, opts.Width, opts.Height, filters[opts.Filter]) cover = imaging.Fit(cover, c.Opts.Width, c.Opts.Height, filters[c.Opts.Filter])
} else { } else {
cover = imaging.Resize(cover, opts.Width, opts.Height, filters[opts.Filter]) cover = imaging.Resize(cover, c.Opts.Width, c.Opts.Height, filters[c.Opts.Filter])
} }
} else { } else {
cover = imaging.Resize(cover, 256, 0, filters[opts.Filter]) cover = imaging.Resize(cover, 256, 0, filters[c.Opts.Filter])
} }
imagick.Initialize() imagick.Initialize()
@@ -879,7 +891,7 @@ func extractThumbnail(file string, info os.FileInfo) {
} }
fileuri := "file://" + file fileuri := "file://" + file
filename := filepath.Join(opts.Outdir, fmt.Sprintf("%x.png", md5.Sum([]byte(fileuri)))) filename := filepath.Join(c.Opts.Outdir, fmt.Sprintf("%x.png", md5.Sum([]byte(fileuri))))
mw.SetImageFormat("PNG") mw.SetImageFormat("PNG")
mw.SetImageProperty("Software", "cbconvert") mw.SetImageProperty("Software", "cbconvert")
@@ -893,22 +905,25 @@ func extractThumbnail(file string, info os.FileInfo) {
} }
// Converts comic book // Converts comic book
func convertComic(file string, info os.FileInfo) { func (c *Convertor) ConvertComic(file string, info os.FileInfo) {
c.Current += 1
if info.IsDir() { if info.IsDir() {
convertDirectory(file) c.convertDirectory(file)
saveArchive(file) c.saveArchive(file)
} else if isDocument(file) { } else if c.isDocument(file) {
convertDocument(file) c.convertDocument(file)
saveArchive(file) c.saveArchive(file)
} else { } else {
convertArchive(file) c.convertArchive(file)
saveArchive(file) c.saveArchive(file)
} }
} }
// Parses command line flags // Parses command line flags
func parseFlags() { func parseFlags() (Options, []string) {
opts = Options{} opts := Options{}
var args []string
kingpin.Version("CBconvert 0.4.0") kingpin.Version("CBconvert 0.4.0")
kingpin.CommandLine.Help = "Comic Book convert tool." kingpin.CommandLine.Help = "Comic Book convert tool."
kingpin.UsageTemplate(kingpin.CompactUsageTemplate) kingpin.UsageTemplate(kingpin.CompactUsageTemplate)
@@ -919,7 +934,7 @@ func parseFlags() {
kingpin.Flag("quiet", "Hide console output").BoolVar(&opts.Quiet) kingpin.Flag("quiet", "Hide console output").BoolVar(&opts.Quiet)
convert := kingpin.Command("convert", "Convert archive or document (default command)").Default() convert := kingpin.Command("convert", "Convert archive or document (default command)").Default()
convert.Arg("args", "filename or directory").Required().ExistingFilesOrDirsVar(&arguments) convert.Arg("args", "filename or directory").Required().ExistingFilesOrDirsVar(&args)
convert.Flag("width", "Image width").Default(strconv.Itoa(0)).IntVar(&opts.Width) convert.Flag("width", "Image width").Default(strconv.Itoa(0)).IntVar(&opts.Width)
convert.Flag("height", "Image height").Default(strconv.Itoa(0)).IntVar(&opts.Height) convert.Flag("height", "Image height").Default(strconv.Itoa(0)).IntVar(&opts.Height)
convert.Flag("fit", "Best fit for required width and height").BoolVar(&opts.Fit) convert.Flag("fit", "Best fit for required width and height").BoolVar(&opts.Fit)
@@ -939,7 +954,7 @@ func parseFlags() {
convert.Flag("suffix", "Add suffix to file basename").StringVar(&opts.Suffix) convert.Flag("suffix", "Add suffix to file basename").StringVar(&opts.Suffix)
cover := kingpin.Command("cover", "Extract cover") cover := kingpin.Command("cover", "Extract cover")
cover.Arg("args", "filename or directory").Required().ExistingFilesOrDirsVar(&arguments) cover.Arg("args", "filename or directory").Required().ExistingFilesOrDirsVar(&args)
cover.Flag("width", "Image width").Default(strconv.Itoa(0)).IntVar(&opts.Width) cover.Flag("width", "Image width").Default(strconv.Itoa(0)).IntVar(&opts.Width)
cover.Flag("height", "Image height").Default(strconv.Itoa(0)).IntVar(&opts.Height) cover.Flag("height", "Image height").Default(strconv.Itoa(0)).IntVar(&opts.Height)
cover.Flag("fit", "Best fit for required width and height").BoolVar(&opts.Fit) cover.Flag("fit", "Best fit for required width and height").BoolVar(&opts.Fit)
@@ -947,7 +962,7 @@ func parseFlags() {
cover.Flag("filter", "0=NearestNeighbor, 1=Box, 2=Linear, 3=MitchellNetravali, 4=CatmullRom, 6=Gaussian, 7=Lanczos").Default(strconv.Itoa(Linear)).IntVar(&opts.Filter) cover.Flag("filter", "0=NearestNeighbor, 1=Box, 2=Linear, 3=MitchellNetravali, 4=CatmullRom, 6=Gaussian, 7=Lanczos").Default(strconv.Itoa(Linear)).IntVar(&opts.Filter)
thumbnail := kingpin.Command("thumbnail", "Extract cover thumbnail (freedesktop spec.)") thumbnail := kingpin.Command("thumbnail", "Extract cover thumbnail (freedesktop spec.)")
thumbnail.Arg("args", "filename or directory").Required().ExistingFilesOrDirsVar(&arguments) thumbnail.Arg("args", "filename or directory").Required().ExistingFilesOrDirsVar(&args)
thumbnail.Flag("width", "Image width").Default(strconv.Itoa(0)).IntVar(&opts.Width) thumbnail.Flag("width", "Image width").Default(strconv.Itoa(0)).IntVar(&opts.Width)
thumbnail.Flag("height", "Image height").Default(strconv.Itoa(0)).IntVar(&opts.Height) thumbnail.Flag("height", "Image height").Default(strconv.Itoa(0)).IntVar(&opts.Height)
thumbnail.Flag("fit", "Best fit for required width and height").BoolVar(&opts.Fit) thumbnail.Flag("fit", "Best fit for required width and height").BoolVar(&opts.Fit)
@@ -959,17 +974,20 @@ func parseFlags() {
case "thumbnail": case "thumbnail":
opts.Thumbnail = true opts.Thumbnail = true
} }
return opts, args
} }
func main() { func main() {
parseFlags() opts, args := parseFlags()
conv := NewConvertor(opts)
c := make(chan os.Signal, 3) c := make(chan os.Signal, 3)
signal.Notify(c, os.Interrupt, syscall.SIGHUP, syscall.SIGTERM) signal.Notify(c, os.Interrupt, syscall.SIGHUP, syscall.SIGTERM)
go func() { go func() {
for _ = range c { for _ = range c {
fmt.Fprintf(os.Stderr, "Aborting\n") fmt.Fprintf(os.Stderr, "Aborting\n")
os.RemoveAll(workdir) os.RemoveAll(conv.Workdir)
os.Exit(1) os.Exit(1)
} }
}() }()
@@ -978,20 +996,17 @@ func main() {
os.MkdirAll(opts.Outdir, 0777) os.MkdirAll(opts.Outdir, 0777)
} }
files := getFiles() files := conv.GetFiles(args)
nfiles = len(files)
if opts.Cover || opts.Thumbnail { if opts.Cover || opts.Thumbnail {
if !opts.Quiet { if !opts.Quiet {
bar = pb.New(nfiles) bar = pb.New(conv.Nfiles)
bar.ShowTimeLeft = false bar.ShowTimeLeft = false
bar.Start() bar.Start()
} }
} }
for n, file := range files { for _, file := range files {
current = n + 1
stat, err := os.Stat(file) stat, err := os.Stat(file)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Error Stat: %v\n", err.Error()) fmt.Fprintf(os.Stderr, "Error Stat: %v\n", err.Error())
@@ -999,19 +1014,19 @@ func main() {
} }
if opts.Cover { if opts.Cover {
extractCover(file, stat) conv.ExtractCover(file, stat)
if !opts.Quiet { if !opts.Quiet {
bar.Increment() bar.Increment()
} }
continue continue
} else if opts.Thumbnail { } else if opts.Thumbnail {
extractThumbnail(file, stat) conv.ExtractThumbnail(file, stat)
if !opts.Quiet { if !opts.Quiet {
bar.Increment() bar.Increment()
} }
continue continue
} }
convertComic(file, stat) conv.ConvertComic(file, stat)
} }
} }