diff --git a/converter/converter.go b/converter/converter.go index e3aa2ba..8cd57d3 100644 --- a/converter/converter.go +++ b/converter/converter.go @@ -2,40 +2,29 @@ package converter import ( "context" + "fmt" "os" "path/filepath" "runtime" + "strings" "time" + "gitea.tecamino.com/paadi/html2pdf/models" "github.com/chromedp/cdproto/page" "github.com/chromedp/chromedp" ) +// html to pdf converter structure for type Converter struct { chromePath string + ctx context.Context + cancel context.CancelFunc } +// NewConverter starts a new converter instance with a chrome headless shell executable func NewConverter(chromePath string) *Converter { - return &Converter{chromePath: chromePath} -} - -func (c *Converter) Convert(imputFile, outputFile string) error { - - chromePath := c.getChromePath() - htmlURL := "file://" - - switch runtime.GOOS { - case "windows": - htmlURL += "/" - } - - // Convert to absolute path - absPath, err := filepath.Abs(imputFile) - if err != nil { - return err - } - - htmlURL += filepath.ToSlash(absPath) + c := &Converter{chromePath: chromePath} + chromePath = c.getChromePath() opts := append(chromedp.DefaultExecAllocatorOptions[:], chromedp.ExecPath(chromePath), @@ -44,38 +33,65 @@ func (c *Converter) Convert(imputFile, outputFile string) error { chromedp.DisableGPU, ) - allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...) - defer cancel() - ctx, cancel := chromedp.NewContext(allocCtx) - defer cancel() + var allocCtx context.Context + allocCtx, c.cancel = chromedp.NewExecAllocator(context.Background(), opts...) + c.ctx, c.cancel = chromedp.NewContext(allocCtx) + return c +} - ctx, cancel = context.WithTimeout(ctx, 60*time.Second) - defer cancel() +// Convert converts all given input files +func (c *Converter) Convert(files ...models.File) error { + for _, f := range files { + if f.Input == "" || filepath.Ext(f.Input) != ".html" { + return fmt.Errorf("no .html input file path provided: %s", f.Input) + } else if f.Output == "" || filepath.Ext(f.Output) != ".pdf" { + return fmt.Errorf("no .pdf output file path provided: %s", f.Output) + } - var pdf []byte - err = chromedp.Run(ctx, - chromedp.Navigate(htmlURL), - chromedp.WaitReady("body", chromedp.ByQuery), - chromedp.ActionFunc(func(ctx context.Context) error { - buf, _, err := page.PrintToPDF(). - WithPrintBackground(true). - WithPaperWidth(8.27). - WithPaperHeight(11.69). - Do(ctx) - if err != nil { - return err - } - pdf = buf - return nil - }), - ) - if err != nil { - return err - } + var htmlURL strings.Builder + htmlURL.WriteString("file://") - // Save PDF to file - if err := os.WriteFile(outputFile, pdf, 0644); err != nil { - return err + switch runtime.GOOS { + case "windows": + htmlURL.WriteString("/") + } + + // Convert to absolute path + absPath, err := filepath.Abs(f.Input) + if err != nil { + return err + } + + htmlURL.WriteString(filepath.ToSlash(absPath)) + + c.ctx, c.cancel = context.WithTimeout(c.ctx, 60*time.Second) + defer c.cancel() + + var pdfData []byte + err = chromedp.Run(c.ctx, + chromedp.Navigate(htmlURL.String()), + chromedp.WaitReady("body", chromedp.ByQuery), + chromedp.ActionFunc(func(ctx context.Context) error { + buf, _, err := page.PrintToPDF(). + WithPrintBackground(true). + WithPaperWidth(8.27). + WithPaperHeight(11.69). + Do(ctx) + if err != nil { + return err + } + pdfData = buf + return nil + }), + ) + if err != nil { + return err + } + + // Save PDF to file + if err := os.WriteFile(f.Output, pdfData, 0644); err != nil { + return err + } } return nil } diff --git a/html2pdf.go b/html2pdf.go index 09555cd..e88a099 100644 --- a/html2pdf.go +++ b/html2pdf.go @@ -1,8 +1,21 @@ package html2pdf -import "gitea.tecamino.com/paadi/html2pdf/converter" +import ( + "gitea.tecamino.com/paadi/html2pdf/converter" + "gitea.tecamino.com/paadi/html2pdf/models" +) +// Convert converts one .html file to .pdf func Convert(chromePath, inputFile, outputFile string) error { + input := models.File{ + Input: inputFile, + Output: outputFile, + } c := converter.NewConverter(chromePath) - return c.Convert(inputFile, outputFile) + return c.Convert(input) +} + +// NewConverterInstance start new chrome headless shell instance +func NewConverterInstance(chromePath string) *converter.Converter { + return converter.NewConverter(chromePath) } diff --git a/html2pdf_test.go b/html2pdf_test.go index 3c35033..7290244 100644 --- a/html2pdf_test.go +++ b/html2pdf_test.go @@ -1,12 +1,49 @@ package html2pdf -import "testing" +import ( + "os" + "path/filepath" + "strings" + "testing" + + "gitea.tecamino.com/paadi/html2pdf/converter" +) func TestConvert(t *testing.T) { - t.Log("start test") + t.Log("start test convert one file") err := Convert("./assets", "dst/test.html", "out.pdf") if err != nil { t.Fatal(err) } } + +func TestConvertFiles(t *testing.T) { + t.Log("start test convert files") + + rootPath := "dst" + files, err := os.ReadDir(rootPath) + if err != nil { + t.Fatal(err) + } + + var input []converter.File + for _, f := range files { + ext := filepath.Ext(f.Name()) + if ext != ".html" { + continue + } + + input = append(input, converter.File{ + Input: filepath.Join(rootPath, f.Name()), + Output: strings.Replace(f.Name(), ext, ".pdf", 1), + }) + } + + c := converter.NewConverter("./assets") + + if err := c.Convert(input...); err != nil { + t.Fatal(err) + } + t.Log("test successfull") +}