From 725ebb5f3b35ce7cacc0cc15be9bfa9bd8a88ec6 Mon Sep 17 00:00:00 2001 From: Anis Ahmad Date: Mon, 26 Mar 2018 03:42:59 +0600 Subject: [PATCH] Refactored - split functionalities into structs and interfaces --- img.go | 14 ++++++-- main.go | 83 +++++++---------------------------------------- pdf.go | 9 ++++++ source.go | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ util.go | 31 ++++++++---------- 5 files changed, 142 insertions(+), 91 deletions(-) create mode 100644 source.go diff --git a/img.go b/img.go index 36d7253..ae500e5 100644 --- a/img.go +++ b/img.go @@ -12,9 +12,16 @@ import ( var pageMargin [4]float64 var pageSize creator.PageSize -var sizeHasSet, merginHasSet = false, false +var sizeHasSet, marginHasSet = false, false + +type ImgSource struct { + source +} + +func (s ImgSource) MergeTo(c *creator.Creator) error { + return addImage(s.path, c, s.mime) +} -// func addImageToPdf(inputPath string, outputPath string, imagePath string, pageNum int, xPos float64, yPos float64, iwidth float64) error { func addImage(filePath string, c *creator.Creator, fileType string) error { debugInfo(fmt.Sprintf("Adding image: %s", filePath)) @@ -39,7 +46,7 @@ func addImage(filePath string, c *creator.Creator, fileType string) error { func setMargin(img *creator.Image, c *creator.Creator) { - if !merginHasSet { + if !marginHasSet { for i, m := range strings.Split(margin, ",") { floatVal, err := strconv.ParseFloat(m, 64) if err != nil { @@ -48,6 +55,7 @@ func setMargin(img *creator.Image, c *creator.Creator) { pageMargin[i] = floatVal * creator.PPI } + marginHasSet = true } c.SetPageMargins(pageMargin[0], pageMargin[1], pageMargin[2], pageMargin[3]) diff --git a/main.go b/main.go index 7f979e7..ca9949c 100644 --- a/main.go +++ b/main.go @@ -1,11 +1,8 @@ package main import ( - "errors" "fmt" "os" - "strconv" - "strings" flag "github.com/ogier/pflag" unicommon "github.com/unidoc/unidoc/common" @@ -18,8 +15,8 @@ var JPEGQuality int const ( DefaultSize = "IMG-SIZE" - DefaultMargin = "1,1,1,1" - VERSION = "1.0.1" + DefaultMargin = "0,0,0,0" + VERSION = "1.0.2" ) func init() { @@ -29,8 +26,8 @@ func init() { flag.BoolVar(&scaleW, "scale-width", false, "Scale Image to page width. Only if --size specified.") flag.BoolVar(&scaleH, "scale-height", false, "Scale Image to page height. Only if --size specified.") flag.IntVar(&JPEGQuality, "jpeg-quality", 100, "Optimize JPEG Quality.") - flag.BoolVarP(&verbose, "verbose", "v", false, "Display debug info.") - flag.BoolVarP(&version, "version", "V", false, "Display debug info.") + flag.BoolVarP(&verbose, "verbose", "v", false, "Display debug information.") + flag.BoolVarP(&version, "version", "V", false, "Display Version information.") flag.Usage = func() { fmt.Println("merge2pdf [options...] [...]") @@ -58,79 +55,23 @@ func main() { } outputPath := args[0] - inputPaths := []string{} - inputPages := [][]int{} + inputPaths := args[1:] - for _, arg := range flag.Args()[1:] { - //inputPaths = append(inputPaths, arg) - - fileInputParts := strings.Split(arg, "~") - inputPaths = append(inputPaths, fileInputParts[0]) - pages := []int{} - - if len(fileInputParts) > 1 { - for _, e := range strings.Split(fileInputParts[1], ",") { - pageNo, err := strconv.Atoi(strings.Trim(e, " \n")) - if err != nil { - fmt.Errorf("Invalid format! Example of a file input with page numbers: path/to/abc.pdf~1,2,3,5,6") - os.Exit(1) - } - pages = append(pages, pageNo) - } - } - - inputPages = append(inputPages, pages) - } - - // fmt.Println(inputPaths) - // fmt.Println(inputPages) - // os.Exit(1) - - err := mergePdf(inputPaths, inputPages, outputPath) - if err != nil { - fmt.Printf("Error: %v\n", err) - os.Exit(1) - } - - debugInfo(fmt.Sprintf("Complete, see output file: %s", outputPath)) -} - -func mergePdf(inputPaths []string, inputPages [][]int, outputPath string) error { c := creator.New() - for i, inputPath := range inputPaths { - - f, err := os.Open(inputPath) + for _, arg := range inputPaths { + err := NewSource(arg).MergeTo(c) if err != nil { - return err - } - defer f.Close() - - fileType, typeError := getFileType(f) - if typeError != nil { - return typeError - } - - if fileType == "directory" { - // @TODO : Read all files in directory - return errors.New(inputPath + " is a drectory.") - } else if fileType == "application/pdf" { - err = addPdfPages(f, inputPages[i], c) - } else if fileType[:6] == "image/" { - err = addImage(inputPath, c, fileType) - } else { - err = errors.New("Unsupported type:" + inputPath) - } - - if err != nil { - return err + fmt.Printf("Error: %s (%s) \n", err.Error(), arg) + os.Exit(1) } } err := c.WriteToFile(outputPath) if err != nil { - return err + fmt.Printf("Error: %s \n", err.Error()) } - return nil + debugInfo(fmt.Sprintf("Complete, see output file: %s", outputPath)) + os.Exit(0) } diff --git a/pdf.go b/pdf.go index 8a8122e..9d67d8d 100644 --- a/pdf.go +++ b/pdf.go @@ -10,6 +10,15 @@ import ( pdf "github.com/unidoc/unidoc/pdf/model" ) +type PDFSource struct { + source +} + +func (s PDFSource) MergeTo(c *creator.Creator) error { + f, _ := os.Open(s.path) + return addPdfPages(f, s.pages, c) +} + func getReader(rs io.ReadSeeker) (*pdf.PdfReader, error) { pdfReader, err := pdf.NewPdfReader(rs) diff --git a/source.go b/source.go new file mode 100644 index 0000000..09fbbcd --- /dev/null +++ b/source.go @@ -0,0 +1,96 @@ +package main + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "strconv" + "strings" + + "github.com/labstack/gommon/log" + "github.com/unidoc/unidoc/pdf/creator" +) + +type mergable interface { + MergeTo(c *creator.Creator) error +} + +type source struct { + path, sourceType, mime, ext string + pages []int +} + +// Initiate new source file from input argument +func NewSource(input string) mergable { + fileInputParts := strings.Split(input, "~") + + path := fileInputParts[0] + f, err := os.Open(fileInputParts[0]) + if err != nil { + log.Fatal("Cannot read source file:", fileInputParts[0]) + } + + defer f.Close() + + ext := filepath.Ext(f.Name()) + mime, err := getMimeType(f) + if err != nil { + log.Fatal("Error in getting mime type of file:", fileInputParts[0]) + } + + sourceType, err := getFileType(mime, ext) + if err != nil { + 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 + switch sourceType { + case "image": + m = ImgSource{source} + case "pdf": + m = PDFSource{source} + } + + return m +} + +func getFileType(mime, ext string) (string, error) { + pdfExts := []string{".pdf", ".PDF"} + imgExts := []string{".jpg", ".jpeg", ".gif", ".png", ".tiff", ".tif", ".JPG", ".JPEG", ".GIF", ".PNG", ".TIFF", ".TIF"} + + switch { + case mime == "application/pdf": + return "pdf", nil + case mime[:6] == "image/": + return "image", nil + case mime == "application/octet-stream" && in_array(ext, pdfExts): + return "pdf", nil + case mime == "application/octet-stream" && in_array(ext, imgExts): + return "image", nil + } + + return "error", errors.New("Could not detect file type.") +} + +func parsePageNums(pagesInput string) []int { + pages := []int{} + + for _, e := range strings.Split(pagesInput, ",") { + pageNo, err := strconv.Atoi(strings.Trim(e, " \n")) + if err != nil { + fmt.Errorf("Invalid format! Example of a file input with page numbers: path/to/abc.pdf~1,2,3,5,6") + os.Exit(1) + } + pages = append(pages, pageNo) + } + + return pages +} diff --git a/util.go b/util.go index 076b171..4cf819f 100644 --- a/util.go +++ b/util.go @@ -7,8 +7,11 @@ import ( "reflect" ) -func in_array(val interface{}, array interface{}) (exists bool, index int) { - exists = false +func in_array(val interface{}, array interface{}) bool { + return at_array(val, array) != -1 +} + +func at_array(val interface{}, array interface{}) (index int) { index = -1 switch reflect.TypeOf(array).Kind() { @@ -18,7 +21,6 @@ func in_array(val interface{}, array interface{}) (exists bool, index int) { for i := 0; i < s.Len(); i++ { if reflect.DeepEqual(val, s.Index(i).Interface()) == true { index = i - exists = true return } } @@ -27,22 +29,17 @@ func in_array(val interface{}, array interface{}) (exists bool, index int) { return } -func getFileType(file *os.File) (string, error) { +func getMimeType(file *os.File) (string, error) { // Only the first 512 bytes are used to sniff the content type. - if info, stateErr := file.Stat(); stateErr != nil { - return "error", stateErr - } else if info.IsDir() { - return "directory", nil - } else { - buffer := make([]byte, 512) - _, readError := file.Read(buffer) - if readError != nil { - return "error", readError - } - - // Always returns a valid content-type and "application/octet-stream" if no others seemed to match. - return http.DetectContentType(buffer), nil + buffer := make([]byte, 512) + _, readError := file.Read(buffer) + if readError != nil { + debugInfo("Read error for file: " + file.Name()) + return "error", readError } + + // Always returns a valid content-type and "application/octet-stream" if no others seemed to match. + return http.DetectContentType(buffer), nil } func debugInfo(message string) {