/
afanasevn
/
PdfEncoder
Обзор
Документация
Войти
/
afanasevn
/
PdfEncoder
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
tests/PdfEncoder.CompatSpike/Program.cs
199 строк
6 KB
IBS\NAfanasev
Add project files.
01 июл 2026, 14:54
01 июл 2026, 14:54
8414644
Код
Авторство
О чём код?
using Docnet.Core; using Docnet.Core.Models; using TesseractOCR; using TesseractOCR.Enums; using TesseractOCR.Pix; using UglyToad.PdfPig; /// <summary> /// PoC совместимости PdfPig + Docnet + TesseractOCR на .NET 10 (A-05). /// </summary> return await CompatSpike.RunAsync(args); internal static class CompatSpike { /// <summary> /// Запускает проверки native-зависимостей и возвращает код выхода. /// </summary> public static async Task<int> RunAsync(string[] args) { var repoRoot = FindRepoRoot() ?? Directory.GetCurrentDirectory(); var tessdataPath = ResolveTessdataPath(repoRoot, args); var pdfPath = Path.Combine(Path.GetTempPath(), $"pdfencoder-spike-{Guid.NewGuid():N}.pdf"); await File.WriteAllBytesAsync(pdfPath, MinimalPdfBytes); try { Console.WriteLine("[1/3] PdfPig: reading text layer..."); var pdfText = ReadPdfText(pdfPath); Console.WriteLine($" Text: \"{pdfText.Trim()}\""); Console.WriteLine("[2/3] Docnet: rendering page 1..."); var imagePath = RenderPageToPgm(pdfPath); Console.WriteLine($" Image: {imagePath}"); Console.WriteLine("[3/3] TesseractOCR: OCR (rus+eng)..."); if (tessdataPath is null) { Console.WriteLine(" SKIP: tessdata not found. Place rus.traineddata and eng.traineddata in ./tessdata"); Console.WriteLine("Compat spike: PdfPig + Docnet OK. OCR skipped."); return 0; } var ocrText = RunOcr(imagePath, tessdataPath); Console.WriteLine($" OCR: \"{ocrText.Trim()}\""); Console.WriteLine("Compat spike: all checks passed."); return 0; } catch (Exception ex) { Console.Error.WriteLine($"Compat spike failed: {ex}"); return 1; } finally { if (File.Exists(pdfPath)) { File.Delete(pdfPath); } } } private static string ReadPdfText(string pdfPath) { using var document = PdfDocument.Open(pdfPath); var page = document.GetPage(1); return string.Join(' ', page.GetWords().Select(word => word.Text)); } private static string RenderPageToPgm(string pdfPath) { var pdfBytes = File.ReadAllBytes(pdfPath); var imagePath = Path.Combine(Path.GetTempPath(), $"pdfencoder-spike-{Guid.NewGuid():N}.pgm"); using var reader = DocLib.Instance.GetDocReader(pdfBytes, new PageDimensions(1080, 1920)); using var pageReader = reader.GetPageReader(0); var width = pageReader.GetPageWidth(); var height = pageReader.GetPageHeight(); var bgra = pageReader.GetImage(); var grayscale = ConvertBgraToGrayscale(bgra); WritePgm(imagePath, width, height, grayscale); return imagePath; } private static string RunOcr( string imagePath, string tessdataPath) { using var engine = new Engine(tessdataPath, "rus+eng", EngineMode.Default); using var img = Image.LoadFromFile(imagePath); using var page = engine.Process(img); return page.Text; } private static byte[] ConvertBgraToGrayscale(byte[] bgra) { var pixels = bgra.Length / 4; var grayscale = new byte[pixels]; for (var i = 0; i < pixels; i++) { var offset = i * 4; var b = bgra[offset]; var g = bgra[offset + 1]; var r = bgra[offset + 2]; grayscale[i] = (byte)((r * 299 + g * 587 + b * 114) / 1000); } return grayscale; } private static void WritePgm( string path, int width, int height, byte[] grayscale) { using var stream = File.Create(path); using var writer = new StreamWriter(stream); writer.WriteLine("P5"); writer.WriteLine($"{width} {height}"); writer.WriteLine("255"); writer.Flush(); stream.Write(grayscale); } private static string? ResolveTessdataPath( string repoRoot, string[] args) { if (args.Length > 0 && Directory.Exists(args[0])) { return args[0]; } var candidates = new[] { Path.Combine(repoRoot, "tessdata"), Path.Combine(Directory.GetCurrentDirectory(), "tessdata") }; foreach (var candidate in candidates) { if (Directory.Exists(candidate) && File.Exists(Path.Combine(candidate, "rus.traineddata")) && File.Exists(Path.Combine(candidate, "eng.traineddata"))) { return candidate; } } return null; } private static string? FindRepoRoot() { var directory = new DirectoryInfo(Directory.GetCurrentDirectory()); while (directory is not null) { if (File.Exists(Path.Combine(directory.FullName, "PdfEncoder.slnx")) || File.Exists(Path.Combine(directory.FullName, "global.json"))) { return directory.FullName; } directory = directory.Parent; } return null; } private static readonly byte[] MinimalPdfBytes = """ %PDF-1.4 1 0 obj<< /Type /Catalog /Pages 2 0 R >>endobj 2 0 obj<< /Type /Pages /Kids [3 0 R] /Count 1 >>endobj 3 0 obj<< /Type /Page /Parent 2 0 R /MediaBox [0 0 300 144] /Contents 4 0 R /Resources<< /Font<< /F1 5 0 R >> >> >>endobj 4 0 obj<< /Length 44 >>stream BT /F1 24 Tf 50 80 Td (Hello PdfEncoder) Tj ET endstream endobj 5 0 obj<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>endobj xref 0 6 0000000000 65535 f 0000000009 00000 n 0000000058 00000 n 0000000115 00000 n 0000000270 00000 n 0000000363 00000 n trailer<< /Size 6 /Root 1 0 R >> startxref 445 %%EOF """u8.ToArray(); }