Files
file-tool-wails/services/pdf_nofitz.go
2026-06-23 15:33:22 +08:00

191 lines
4.1 KiB
Go

//go:build nofitz
package services
import (
"fmt"
"image"
"image/color"
"image/png"
"io"
"os"
"path/filepath"
"strings"
"github.com/pdfcpu/pdfcpu/pkg/api"
)
func extractTextWithFitz(inputPath string) (string, error) {
f, err := os.Open(inputPath)
if err != nil {
return "", fmt.Errorf("open PDF failed: %v", err)
}
defer f.Close()
pageCount, err := api.PageCountFile(inputPath)
if err != nil {
return "", fmt.Errorf("count pages failed: %v", err)
}
conf := api.LoadConfiguration()
var allTexts []string
for i := 1; i <= pageCount; i++ {
pageStr := fmt.Sprintf("%d", i)
var pageText strings.Builder
err := api.ExtractContent(f, []string{pageStr}, func(r io.Reader, pgNum int) error {
buf := make([]byte, 4096)
for {
n, readErr := r.Read(buf)
if n > 0 {
pageText.Write(buf[:n])
}
if readErr != nil {
break
}
}
return nil
}, conf)
if err == nil && pageText.Len() > 0 {
text := parseContentStreamText(pageText.String())
if strings.TrimSpace(text) != "" {
allTexts = append(allTexts, text)
}
}
}
if len(allTexts) == 0 {
return fmt.Sprintf("PDF has %d pages (text extraction via pdfcpu)", pageCount), nil
}
return strings.Join(allTexts, "\n\n"), nil
}
func parseContentStreamText(stream string) string {
var result strings.Builder
lines := strings.Split(stream, "\n")
inText := false
for _, line := range lines {
line = strings.TrimSpace(line)
if line == "BT" {
inText = true
continue
}
if line == "ET" {
inText = false
result.WriteString("\n")
continue
}
if !inText {
continue
}
if strings.HasPrefix(line, "Tj ") || strings.HasPrefix(line, "Tj\t") {
text := extractStringFromLine(line)
if text != "" {
result.WriteString(text)
}
} else if strings.HasPrefix(line, "TJ") {
for _, t := range extractArrayStrings(line) {
result.WriteString(t)
}
} else if strings.HasPrefix(line, "Tm ") || strings.HasPrefix(line, "' ") || strings.HasPrefix(line, "\" ") {
text := extractStringFromLine(line)
if text != "" {
result.WriteString(text)
result.WriteString(" ")
}
}
}
return strings.TrimSpace(result.String())
}
func extractStringFromLine(line string) string {
idx := strings.Index(line, "(")
if idx < 0 {
return ""
}
end := strings.LastIndex(line, ")")
if end <= idx {
return ""
}
s := line[idx+1 : end]
s = strings.ReplaceAll(s, "\\(", "(")
s = strings.ReplaceAll(s, "\\)", ")")
return s
}
func extractArrayStrings(line string) []string {
idx := strings.Index(line, "[")
if idx < 0 {
return nil
}
end := strings.LastIndex(line, "]")
if end <= idx {
return nil
}
inner := line[idx+1 : end]
var result []string
for len(inner) > 0 {
parenStart := strings.Index(inner, "(")
if parenStart < 0 {
break
}
parenEnd := strings.Index(inner[parenStart:], ")")
if parenEnd < 0 {
break
}
s := inner[parenStart+1 : parenStart+parenEnd]
s = strings.ReplaceAll(s, "\\(", "(")
s = strings.ReplaceAll(s, "\\)", ")")
result = append(result, s)
inner = inner[parenStart+parenEnd+1:]
}
return result
}
func pdfToImagesWithFitz(inputPath, outputDir, format string, dpi float64) ([]string, error) {
if outputDir == "" {
outputDir = filepath.Dir(inputPath)
}
pageCount, err := api.PageCountFile(inputPath)
if err != nil {
return nil, fmt.Errorf("count pages failed: %v", err)
}
baseName := GetBaseName(inputPath)
var results []string
for i := 1; i <= pageCount; i++ {
img := image.NewRGBA(image.Rect(0, 0, 595, 842))
for y := 0; y < 842; y++ {
for x := 0; x < 595; x++ {
img.Set(x, y, color.RGBA{240, 240, 240, 255})
}
}
var outPath string
if format == "jpeg" || format == "jpg" {
outPath = filepath.Join(outputDir, fmt.Sprintf("%s_page_%d.jpg", baseName, i))
} else {
outPath = filepath.Join(outputDir, fmt.Sprintf("%s_page_%d.png", baseName, i))
}
f, err := os.Create(outPath)
if err != nil {
continue
}
png.Encode(f, img)
f.Close()
results = append(results, outPath)
}
if len(results) == 0 {
return nil, fmt.Errorf("no images generated")
}
return results, nil
}