package pdfrender import ( "fmt" "os" "path/filepath" "regexp" "strings" ) // InlineResources inlines external CSS and images into the HTML for PDF rendering func InlineResources(html string, templateDir string) (string, error) { // Inline CSS cssRegex := regexp.MustCompile(`]*>`) html = cssRegex.ReplaceAllStringFunc(html, func(match string) string { matches := cssRegex.FindStringSubmatch(match) if len(matches) < 2 { return match } cssPath := matches[1] fullPath := filepath.Join(templateDir, cssPath) cssContent, err := os.ReadFile(fullPath) if err != nil { // Return original tag if CSS can't be loaded return match } return fmt.Sprintf("", string(cssContent)) }) // Inline images (except data URIs which are already inline) imgRegex := regexp.MustCompile(`]*)>`) html = imgRegex.ReplaceAllStringFunc(html, func(match string) string { matches := imgRegex.FindStringSubmatch(match) if len(matches) < 3 { return match } imgSrc := matches[1] imgAttrs := matches[2] // Skip if already a data URI or template variable if strings.HasPrefix(imgSrc, "data:") || strings.Contains(imgSrc, "{{") { return match } fullPath := filepath.Join(templateDir, imgSrc) imgData, err := os.ReadFile(fullPath) if err != nil { // Return original tag if image can't be loaded return match } // Detect mime type from extension mimeType := "image/png" ext := strings.ToLower(filepath.Ext(imgSrc)) switch ext { case ".jpg", ".jpeg": mimeType = "image/jpeg" case ".gif": mimeType = "image/gif" case ".svg": mimeType = "image/svg+xml" } dataURI := ImageToBase64DataURI(imgData, mimeType) return fmt.Sprintf(``, dataURI, imgAttrs) }) return html, nil } // LoadAndInlineTemplate loads a template, renders it, and inlines all resources func (tl *TemplateLoader) RenderTemplateWithInlinedResources(templateName string, data interface{}) (string, error) { // First render the template html, err := tl.RenderTemplate(templateName, data) if err != nil { return "", err } // Then inline all external resources return InlineResources(html, tl.templateDir) }