Files
cv-site/internal/pdf/generator.go
T

90 lines
2.0 KiB
Go
Raw Normal View History

package pdf
import (
"context"
"fmt"
"io"
"time"
"github.com/chromedp/cdproto/page"
"github.com/chromedp/chromedp"
)
// Generator handles PDF generation using headless Chrome
type Generator struct {
timeout time.Duration
}
// NewGenerator creates a new PDF generator with the specified timeout
func NewGenerator(timeout time.Duration) *Generator {
if timeout == 0 {
timeout = 30 * time.Second
}
return &Generator{
timeout: timeout,
}
}
// GenerateFromURL generates a PDF from a given URL
func (g *Generator) GenerateFromURL(ctx context.Context, url string) ([]byte, error) {
// Create context with timeout
ctx, cancel := context.WithTimeout(ctx, g.timeout)
defer cancel()
// Create chromedp context
allocCtx, allocCancel := chromedp.NewContext(ctx)
defer allocCancel()
// Buffer to store PDF
var pdfBuffer []byte
// Run chromedp tasks
err := chromedp.Run(allocCtx,
// Navigate to URL
chromedp.Navigate(url),
// Wait for page to be ready
chromedp.WaitReady("body"),
// Small delay to ensure all content is loaded
chromedp.Sleep(500*time.Millisecond),
// Generate PDF with print-optimized settings
chromedp.ActionFunc(func(ctx context.Context) error {
var err error
pdfBuffer, _, err = page.PrintToPDF().
WithPrintBackground(true).
WithPreferCSSPageSize(true).
WithMarginTop(0).
WithMarginBottom(0).
WithMarginLeft(0).
WithMarginRight(0).
WithPaperWidth(8.27). // A4 width in inches
WithPaperHeight(11.69). // A4 height in inches
Do(ctx)
return err
}),
)
if err != nil {
return nil, fmt.Errorf("chromedp execution failed: %w", err)
}
if len(pdfBuffer) == 0 {
return nil, fmt.Errorf("generated PDF is empty")
}
return pdfBuffer, nil
}
// StreamFromURL generates a PDF and writes it to the provided writer
func (g *Generator) StreamFromURL(ctx context.Context, url string, w io.Writer) error {
pdfData, err := g.GenerateFromURL(ctx, url)
if err != nil {
return err
}
_, err = w.Write(pdfData)
return err
}