diff --git a/README.md b/README.md index 68964a1..4db152b 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,11 @@ merge2pdf output.pdf input1.pdf~1 input2.pdf input3.pdf~2,3,4 # Merge multiple Images merge2pdf output.pdf image1.jpg image2.jpg path/to/other.png ... -# Mixing up PDF, PDF Pages and Images -merge2pdf output.pdf doc1.pdf~1,2 image1.jpg image2.png path/to/other.pdf ... +# Merge all Images/PDFs of one or multiple directory +merge2pdf output.pdf path/to/a/dir path/to/another ... + +# Mixing up PDF, PDF Pages, Images and directories +merge2pdf output.pdf doc1.pdf~1,2 image1.jpg path/to/dir path/to/other.pdf ... ``` ### Fine tuning Image pages @@ -65,17 +68,23 @@ To see details of options, ```bash merge2pdf -h ``` +### Notes + +- `--size`, `--margin`, `--scale-width`, `--scale-height` will only effect images. +- PDF pages will inherit size and margin of source PDF +- _Some_ `.tiff` files (e,g, compression level 4) may not work properly +- Directory inputs will be searched for image/PDF files on first level only. Subdirectories will be skipped. ### Roadmap ✅ Merge multiple PDFs without loosing quality ✅ Merge multiple PDFs with **selective pages** ✅ Adding Images -✅ Mixing up Images and PDFs -◻️ Merge all (Image and PDF) files from directory +✅ Mixing up Images and PDFs +✅️ Merge all (Image and PDF) files from directory ✅ Option to Resize Images to reduce filesize ◻️ Option to Greyscale Images to reduce filesize -◻️ Option to set files and pages as JSON config to make usages from other app more convenient +◻️ Option to set files and pages as JSON config to make usages from other app more convenient ### Contribute diff --git a/dir.go b/dir.go new file mode 100644 index 0000000..c3464e0 --- /dev/null +++ b/dir.go @@ -0,0 +1,40 @@ +package main + +import ( + "fmt" + "io/ioutil" + "path/filepath" + + "github.com/unidoc/unidoc/pdf/creator" +) + +type DirSource struct { + path string + files []Mergeable +} + +func (s DirSource) MergeTo(c *creator.Creator) error { + debugInfo(fmt.Sprintf("Adding Directory: %s", s.path)) + var err error + + for _, mergeableFile := range s.files { + err = mergeableFile.MergeTo(c) + if err != nil { + break + } + } + + return err +} + +func (s *DirSource) scanMergeables() { + filesInDir, _ := ioutil.ReadDir(s.path) + + for _, file := range filesInDir { + if file.IsDir() { + continue + } + + s.files = append(s.files, getMergeableFile(filepath.Join(s.path, file.Name()), []int{})) + } +} diff --git a/main.go b/main.go index ca9949c..4762666 100644 --- a/main.go +++ b/main.go @@ -31,8 +31,8 @@ func init() { flag.Usage = func() { fmt.Println("merge2pdf [options...] [...]") - fmt.Println(" should be a PDF file and can be PDF or image files. PDF files can have specific page numbers to merge.") - fmt.Println("Example: merge2pdf output.pdf input1.pdf input_pages.pdf~1,2,3 input3.jpg /path/to/input.png ...") + fmt.Println(" should be a PDF file and can be PDF, image or directory. PDF files can have specific page numbers to merge.") + fmt.Println("Example: merge2pdf output.pdf input1.pdf input_pages.pdf~1,2,3 input3.jpg /path/to/dir ...") flag.PrintDefaults() } } diff --git a/source.go b/source.go index 09fbbcd..c794388 100644 --- a/source.go +++ b/source.go @@ -12,7 +12,7 @@ import ( "github.com/unidoc/unidoc/pdf/creator" ) -type mergable interface { +type Mergeable interface { MergeTo(c *creator.Creator) error } @@ -22,13 +22,42 @@ type source struct { } // Initiate new source file from input argument -func NewSource(input string) mergable { +func NewSource(input string) Mergeable { fileInputParts := strings.Split(input, "~") path := fileInputParts[0] - f, err := os.Open(fileInputParts[0]) + var inputSource Mergeable + + info, err := os.Stat(path) if err != nil { - log.Fatal("Cannot read source file:", fileInputParts[0]) + log.Fatal("Error:", err.Error()) + } + + switch mode := info.Mode(); { + case mode.IsDir(): + inputSource = getMergeableDir(path) + case mode.IsRegular(): + pages := []int{} + if len(fileInputParts) > 1 { + pages = parsePageNums(fileInputParts[1]) + } + inputSource = getMergeableFile(path, pages) + } + + return inputSource +} + +func getMergeableDir(path string) Mergeable { + dir := DirSource{path: path} + dir.scanMergeables() + + return dir +} + +func getMergeableFile(path string, pages []int) Mergeable { + f, err := os.Open(path) + if err != nil { + log.Fatal("Cannot read source file:", path) } defer f.Close() @@ -36,7 +65,7 @@ func NewSource(input string) mergable { ext := filepath.Ext(f.Name()) mime, err := getMimeType(f) if err != nil { - log.Fatal("Error in getting mime type of file:", fileInputParts[0]) + log.Fatal("Error in getting mime type of file:", path) } sourceType, err := getFileType(mime, ext) @@ -44,14 +73,9 @@ func NewSource(input string) mergable { log.Fatal("Error : %s (%s)", err.Error(), path) } - pages := []int{} - if len(fileInputParts) > 1 { - pages = parsePageNums(fileInputParts[1]) - } - source := source{path, sourceType, mime, ext, pages} - var m mergable + var m Mergeable switch sourceType { case "image": m = ImgSource{source} @@ -77,7 +101,7 @@ func getFileType(mime, ext string) (string, error) { return "image", nil } - return "error", errors.New("Could not detect file type.") + return "error", errors.New("File type not acceptable. ") } func parsePageNums(pagesInput string) []int {