|
- package main
-
- import (
- "biukop.com/sfm/loan"
- "errors"
- log "github.com/sirupsen/logrus"
- "io/ioutil"
- "net/http"
- "os"
- "os/exec"
- "path/filepath"
- "strconv"
- "strings"
- )
-
- type uploadsOnDisk struct {
- Upload loan.Uploads
- }
-
- func (m *uploadsOnDisk) convertUploadsToPDF() (e error) {
- return convertUploadsToPDF(m.Upload)
- }
- func convertUploadsToPDF(ul loan.Uploads) (e error) {
- m := uploadsOnDisk{}
- m.Upload = ul
-
- if strings.Contains(strings.ToLower(ul.Format), "excel") ||
- strings.Contains(strings.ToLower(ul.Format), "spreadsheet") {
- e = m.convertExcelToPDF()
- return // excel is converted
- }
-
- if strings.Contains(strings.ToLower(ul.Format), "/pdf") {
- return // no need to convert
- }
-
- e = errors.New("don't know how to convert file to PDF")
- log.Error("don't know how to convert file to PDF", ul)
- return
- }
-
- func (m *uploadsOnDisk) convertUploadsToJpg() (e error) {
- return convertUploadsToJpg(m.Upload)
- }
-
- func convertUploadsToJpg(ul loan.Uploads) (e error) {
- m := uploadsOnDisk{}
- m.Upload = ul
-
- if strings.Contains(strings.ToLower(ul.Format), "excel") ||
- strings.Contains(strings.ToLower(ul.Format), "spreadsheet") {
- e = m.convertExcelToJpg()
- return // excel is converted
- }
- if strings.Contains(strings.ToLower(ul.Format), "/pdf") {
- e = m.convertPDFToJpg()
- return // excel is converted
- }
-
- e = errors.New("don't know how to convert file to image")
- log.Error("don't know how to convert file to image", ul)
- return
- }
-
- func (m *uploadsOnDisk) convertUploadsToThumb() (e error) {
- return convertUploadsToThumb(m.Upload)
- }
- func convertUploadsToThumb(ul loan.Uploads) (e error) {
- m := uploadsOnDisk{}
- m.Upload = ul
- if !fileExists(m.jpgPath()) {
- e = m.convertUploadsToJpg()
- if e != nil {
- return
- }
- }
-
- e = ConvertImageToThumbnail(m.jpgPath(), m.thumbPath(), 256)
- if e != nil {
- log.Error("cannot create thumbnail for uploads", m.Upload, e)
- return
- }
- return
- }
-
- func (m *uploadsOnDisk) filePath() string {
- return config.UploadsDir.FileDir + strconv.Itoa(int(m.Upload.Id)) + ".uploads"
- }
-
- func (m *uploadsOnDisk) jpgPath() string {
- return config.UploadsDir.JpgDir + strconv.Itoa(int(m.Upload.Id)) + ".jpg"
- }
-
- func (m *uploadsOnDisk) thumbPath() string {
- return config.UploadsDir.ThumbDir + strconv.Itoa(int(m.Upload.Id)) + ".webp"
- }
-
- func (m *uploadsOnDisk) pdfPath() string {
- return config.UploadsDir.PdfDir + strconv.Itoa(int(m.Upload.Id)) + ".pdf"
- }
- func (m *uploadsOnDisk) convertExcelToPDF() (e error) {
- if fileExists(m.pdfPath()) {
- log.Info("Skip conversion excel to PDF , already exists", m)
- return
- }
- return m.convertExcelTo("pdf")
- }
-
- func (m *uploadsOnDisk) convertExcelToJpg() (e error) {
- if fileExists(m.jpgPath()) {
- log.Info("Skip conversion excel to Jpg , already exists", m)
- return
- }
- return m.convertExcelTo("jpg")
- }
-
- func (m *uploadsOnDisk) convertExcelTo(format string) (e error) {
- if format != "pdf" && format != "jpg" {
- e = errors.New("unsupported format")
- return
- }
-
- dst := m.jpgPath()
- if format == "pdf" {
- dst = m.pdfPath()
- }
-
- dir, e := ioutil.TempDir(config.TempDir, "tmp-convert-xls-to-"+format+"-")
- if e != nil {
- log.Error("cannot create tmp dir for converting image", m.Upload, e)
- return
- }
- defer os.RemoveAll(dir)
-
- cmd := exec.Command("libreoffice", "--convert-to", format, "--outdir", dir, m.filePath())
- strCmd := cmd.String()
- log.Debug("command is ", strCmd)
- out, e := cmd.Output()
- if e != nil {
- log.Error("cannot converting Excel to "+format+":", m.Upload, e)
- return
- } else { // success
- log.Info("convert to "+format, m.Upload, " output: ", string(out))
- }
-
- _, name := filepath.Split(m.filePath())
-
- src := dir + string(os.PathSeparator) + fileNameWithoutExtTrimSuffix(name) + "." + format
- e = os.Rename(src, dst) // there should be only one jpg
-
- return
- }
-
- // first page to thumbnail
- // all page to single jpg
- func (m *uploadsOnDisk) convertPDFToJpg() (e error) {
-
- if fileExists(m.jpgPath()) {
- // no need to reconvert it again
- log.Info("PDF to JPG skipped it already exists ", m)
- return
- }
-
- dir, e := ioutil.TempDir(config.TempDir, "tmp-convert-pdf-to-jpg-")
- if e != nil {
- log.Error("cannot create tmp dir for converting image", m.Upload, e)
- return
- }
- defer os.RemoveAll(dir)
-
- // convert -density 3000 abc.pdf path/tmp/result.png
- // could be path/tmp/result-0, result-1, result-2, ... png
- target := dir + string(os.PathSeparator) + "result.jpg" //.jpg suffix is important
- cmd := exec.Command("convert", "-density", "300", m.filePath(), target)
- strCmd := cmd.String()
- log.Debug("command is ", strCmd)
- out, e := cmd.Output()
- if e != nil {
- log.Error("cannot create png file for PDF", m.Upload, e)
- return
- } else {
- log.Info("convert ", m.Upload, " output: ", string(out))
- }
-
- // montage -mode concatenate -tile 1x 30*png 30.jpg
- if fileExists(target) { // single file,
- e = os.Rename(target, m.jpgPath()) // there should be only one jpg
- _ = ConvertImageToThumbnail(target, m.thumbPath(), 256)
- } else { // multi-page, we have -0 -1 -2 -3 -4 files
- firstPage := dir + string(os.PathSeparator) + "result-0.jpg"
- _ = ConvertImageToThumbnail(firstPage, m.thumbPath(), 256)
-
- batch := dir + string(os.PathSeparator) + "result*jpg" // result* is important
- target = dir + string(os.PathSeparator) + "final.jpg" // .jpg suffix is important
- cmd = exec.Command("montage", "-mode", "concatenate", "-tile", "1x", batch, target)
-
- strCmd = cmd.String()
- log.Debug("command is ", strCmd)
- out, e = cmd.Output()
- if e != nil {
- return
- } else {
- log.Info("montage ", m, " output: ", string(out))
- }
- e = os.Rename(target, m.jpgPath()) // give combined file to target
- }
- return
- }
-
- func (m *uploadsOnDisk) GetFileType() (ret string, e error) {
- strMime, e := GetFileContentType(m.filePath())
- if e != nil {
- return
- }
-
- if strings.ToLower(strMime) == "application/pdf" {
- return "pdf", nil
- }
-
- if strings.ToLower(strMime) == "application/vnd.ms-excel" {
- return "excel", nil
- }
-
- if strings.ToLower(strMime) == "application/zip" &&
- strings.ToLower(m.Upload.Format) ==
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" {
- return "opensheet", nil
- }
-
- return "", nil
- }
-
- // tested, not accurate with xls, xlsx, it becomes zip and octstream sometime.
- func GetFileContentType(filename string) (contentType string, e error) {
- contentType = ""
- input, e := os.OpenFile(filename, os.O_RDONLY, 0755)
- // Only the first 512 bytes are used to sniff the content type.
- buffer := make([]byte, 512)
-
- _, e = input.Read(buffer)
- if e != nil {
- return
- }
-
- // Use the net/http package's handy DectectContentType function. Always returns a valid
- // content-type by returning "application/octet-stream" if no others seemed to match.
- contentType = http.DetectContentType(buffer)
- return
- }
-
- func ConvertImageToThumbnail(srcPath string, dstPath string, size int) (e error) {
- if fileExists(dstPath) {
- log.Info("skip converting thumbnail it exists", dstPath)
- return
- }
- if size <= 0 {
- size = 256
- }
- // convert -thumbnail 200 abc.png thumb.abc.png
- cmd := exec.Command("convert", "-thumbnail", strconv.Itoa(size), srcPath, dstPath)
- strCmd := cmd.String()
- log.Debug("create thumbnail: ", strCmd)
-
- out, e := cmd.Output()
- if e != nil {
- return
- } else { // success
- log.Info("success output: \n: ", string(out))
- }
- return
- }
-
- func fileNameWithoutExtTrimSuffix(fileName string) string {
- return strings.TrimSuffix(fileName, filepath.Ext(fileName))
- }
|