658 lines
28 KiB
HTML
658 lines
28 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="fa" dir="rtl">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>بازنویسی FallbackToImageExtractionAsync با PdfiumViewer - فن آوران ساحر علم</title>
|
|
<style>
|
|
:root {
|
|
--primary: #1e3a8a;
|
|
--secondary: #3b82f6;
|
|
--accent: #f59e0b;
|
|
--success: #10b981;
|
|
--danger: #ef4444;
|
|
--warning: #f97316;
|
|
--purple: #8b5cf6;
|
|
--bg-light: #f8fafc;
|
|
--bg-code: #1e293b;
|
|
--text-dark: #0f172a;
|
|
--text-muted: #64748b;
|
|
--border: #e2e8f0;
|
|
}
|
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
body {
|
|
font-family: 'Tahoma', 'Segoe UI', sans-serif;
|
|
background: linear-gradient(135deg, #f8fafc 0%, #e0e7ff 100%);
|
|
color: var(--text-dark);
|
|
line-height: 1.8;
|
|
padding: 20px;
|
|
}
|
|
.container {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
background: white;
|
|
border-radius: 16px;
|
|
box-shadow: 0 20px 60px rgba(0,0,0,0.1);
|
|
overflow: hidden;
|
|
}
|
|
.header {
|
|
background: linear-gradient(135deg, var(--primary) 0%, var(--purple) 100%);
|
|
color: white;
|
|
padding: 40px;
|
|
text-align: center;
|
|
}
|
|
.header h1 { font-size: 2em; margin-bottom: 10px; }
|
|
.header .subtitle { font-size: 1.1em; opacity: 0.95; }
|
|
.meta-bar {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
background: var(--bg-light);
|
|
padding: 15px 30px;
|
|
border-bottom: 2px solid var(--border);
|
|
flex-wrap: wrap;
|
|
gap: 15px;
|
|
}
|
|
.meta-item { display: flex; align-items: center; gap: 8px; font-size: 0.9em; color: var(--text-muted); }
|
|
.meta-item strong { color: var(--primary); }
|
|
.content { padding: 40px; }
|
|
.section {
|
|
margin-bottom: 35px;
|
|
padding: 25px;
|
|
background: var(--bg-light);
|
|
border-radius: 12px;
|
|
border-right: 5px solid var(--secondary);
|
|
}
|
|
.section h2 {
|
|
color: var(--primary);
|
|
font-size: 1.5em;
|
|
margin-bottom: 20px;
|
|
padding-bottom: 10px;
|
|
border-bottom: 2px solid var(--border);
|
|
}
|
|
.section h3 { color: var(--secondary); font-size: 1.2em; margin: 20px 0 12px; }
|
|
pre {
|
|
background: var(--bg-code);
|
|
color: #e2e8f0;
|
|
padding: 18px;
|
|
border-radius: 8px;
|
|
overflow-x: auto;
|
|
direction: ltr;
|
|
text-align: left;
|
|
font-family: 'Consolas', monospace;
|
|
font-size: 0.83em;
|
|
margin: 15px 0;
|
|
border-right: 4px solid var(--accent);
|
|
}
|
|
code {
|
|
background: #fef3c7;
|
|
color: #92400e;
|
|
padding: 2px 8px;
|
|
border-radius: 4px;
|
|
font-family: 'Consolas', monospace;
|
|
font-size: 0.9em;
|
|
direction: ltr;
|
|
display: inline-block;
|
|
}
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin: 15px 0;
|
|
background: white;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
}
|
|
th { background: var(--primary); color: white; padding: 12px; text-align: right; }
|
|
td { padding: 12px; border-bottom: 1px solid var(--border); }
|
|
.alert { padding: 15px 20px; border-radius: 8px; margin: 15px 0; border-right: 4px solid; }
|
|
.alert-info { background: #dbeafe; border-color: var(--secondary); color: #1e40af; }
|
|
.alert-success { background: #d1fae5; border-color: var(--success); color: #065f46; }
|
|
.alert-warning { background: #fef3c7; border-color: var(--accent); color: #92400e; }
|
|
.alert-danger { background: #fee2e2; border-color: var(--danger); color: #991b1b; }
|
|
.footer { background: var(--primary); color: white; padding: 25px; text-align: center; }
|
|
.highlight { background: linear-gradient(120deg, #fef3c7 0%, #fef3c7 100%); padding: 2px 6px; border-radius: 4px; font-weight: bold; }
|
|
.file-change { background: #f0f9ff; border-right: 4px solid var(--secondary); padding: 15px; margin: 10px 0; border-radius: 8px; }
|
|
.file-change .path { font-family: 'Consolas', monospace; color: var(--primary); font-weight: bold; direction: ltr; display: inline-block; }
|
|
.badge-modify { background: var(--warning); color: white; padding: 2px 8px; border-radius: 4px; font-size: 0.75em; margin-right: 8px; }
|
|
.badge-new { background: var(--success); color: white; padding: 2px 8px; border-radius: 4px; font-size: 0.75em; margin-right: 8px; }
|
|
.arch-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
|
gap: 20px;
|
|
margin: 20px 0;
|
|
}
|
|
.arch-card {
|
|
background: white;
|
|
padding: 20px;
|
|
border-radius: 10px;
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
|
|
border-top: 4px solid var(--secondary);
|
|
}
|
|
.arch-card h4 { color: var(--primary); margin-bottom: 12px; font-size: 1.1em; }
|
|
.arch-card ul { list-style: none; padding-right: 0; }
|
|
.arch-card li { padding: 6px 0; padding-right: 20px; position: relative; font-size: 0.95em; }
|
|
.arch-card li::before { content: '▸'; position: absolute; right: 0; color: var(--accent); font-weight: bold; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
|
|
<div class="header">
|
|
<h1>📄 بازنویسی FallbackToImageExtractionAsync با PdfiumViewer</h1>
|
|
<div class="subtitle">جایگزینی PdfPigRenderer با کتابخانه قدرتمند PdfiumViewer برای رندر PDF</div>
|
|
</div>
|
|
|
|
<div class="meta-bar">
|
|
<div class="meta-item">👨💻 <strong>توسعهدهنده:</strong> هادی خزاعی اصل</div>
|
|
<div class="meta-item">🏢 <strong>شرکت:</strong> فن آوران ساحر علم</div>
|
|
<div class="meta-item">📅 <strong>تاریخ:</strong> یکشنبه ۱۳ مهر ۱۴۰۵</div>
|
|
<div class="meta-item">📦 <strong>پروژه:</strong> xAiApi</div>
|
|
</div>
|
|
|
|
<div class="content">
|
|
|
|
<div class="section">
|
|
<h2>🎯 مقدمه</h2>
|
|
<p>
|
|
کتابخانه <span class="highlight">PdfiumViewer</span> یکی از پایدارترین و سریعترین راهکارها برای رندر PDF در .NET است
|
|
که بر پایه موتور <strong>PDFium گوگل</strong> (همان موتور استفاده شده در Chrome) ساخته شده است.
|
|
این کتابخانه نسبت به <code>PdfPigRenderer</code> عملکرد بهتری دارد و برای تبدیل PDF به تصویر مناسبتر است.
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Step 1: NuGet Packages -->
|
|
<div class="section">
|
|
<h2>📦 گام ۱: نصب پکیجهای NuGet مورد نیاز</h2>
|
|
<p>ابتدا باید پکیجهای زیر را در پروژه <code>xAiApi</code> نصب کنید:</p>
|
|
<pre># پکیج اصلی PdfiumViewer
|
|
Install-Package PdfiumViewer
|
|
|
|
# پکیج Native DLLs (بسیار مهم - شامل pdfium.dll برای پلتفرمهای مختلف)
|
|
Install-Package PdfiumViewer.Native
|
|
|
|
# برای کار با Bitmap و تصاویر
|
|
Install-Package System.Drawing.Common</pre>
|
|
|
|
<div class="alert alert-warning">
|
|
<strong>⚠️ نکته مهم در مورد Native DLLs:</strong>
|
|
<p>پکیج <code>PdfiumViewer.Native</code> فایلهای <code>pdfium.dll</code> را برای پلتفرمهای مختلف
|
|
(x86 و x64) در پوشه <code>bin</code> پروژه کپی میکند. بدون این پکیج، کتابخانه با خطای
|
|
<code>DllNotFoundException</code> مواجه خواهد شد.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 2: Rewritten Function -->
|
|
<div class="section">
|
|
<h2>🔧 گام ۲: کد بازنویسی شده با PdfiumViewer</h2>
|
|
|
|
<div class="file-change">
|
|
<span class="badge-modify">MODIFY</span>
|
|
<span class="path">xAiApi/Providers/Extractors/XPdfFileContentExtractor.cs</span>
|
|
</div>
|
|
|
|
<pre>using System;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Drawing;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using PdfiumViewer;
|
|
using xAiApi.Models;
|
|
using xAiApi.Interfaces.Extractors;
|
|
using xCommons.Extensions;
|
|
|
|
namespace xAiApi.Providers.Extractors
|
|
{
|
|
/// <summary>
|
|
/// استخراج محتوا از PDF با پشتیبانی از Fallback تصویری با PdfiumViewer ...
|
|
/// </summary>
|
|
public class XPdfFileContentExtractor : IXPdfFileContentExtractor
|
|
{
|
|
/// <summary>
|
|
/// Supported MIME Types ...
|
|
/// </summary>
|
|
private static readonly string[] SupportedMimeTypes = ["application/pdf"];
|
|
|
|
/// <summary>
|
|
/// حداقل تعداد کاراکتر برای تشخیص PDF متنی ...
|
|
/// </summary>
|
|
private const int MinTextLengthThreshold = 50;
|
|
|
|
/// <summary>
|
|
/// حداکثر تعداد صفحات برای تبدیل به تصویر ...
|
|
/// </summary>
|
|
private const int MaxPagesForImageFallback = 10;
|
|
|
|
/// <summary>
|
|
/// DPI برای رندر تصاویر (72 = کیفیت معمولی، 150 = کیفیت خوب، 300 = کیفیت بالا) ...
|
|
/// </summary>
|
|
private const int RenderDpi = 150;
|
|
|
|
/// <summary>
|
|
/// حداکثر عرض تصویر به پیکسل ...
|
|
/// </summary>
|
|
private const int MaxImageWidth = 2000;
|
|
|
|
/// <summary>
|
|
/// بررسی پشتیبانی از MIME Type ...
|
|
/// </summary>
|
|
public bool CanExtract(string mimeType)
|
|
{
|
|
return SupportedMimeTypes.Contains(
|
|
mimeType?.ToLowerInvariant() ?? string.Empty
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// استخراج محتوای غنی با Fallback هوشمند ...
|
|
/// </summary>
|
|
public async Task<XFileExtractionResult> ExtractRichAsync(
|
|
Stream fileStream,
|
|
string fileName,
|
|
string mimeType,
|
|
CancellationToken cancellationToken = default
|
|
)
|
|
{
|
|
var result = new XFileExtractionResult
|
|
{
|
|
FileName = fileName,
|
|
MimeType = mimeType
|
|
};
|
|
|
|
// کپی به MemoryStream برای چندبار خواندن
|
|
using var memoryStream = new MemoryStream();
|
|
await fileStream.CopyToAsync(memoryStream, cancellationToken);
|
|
memoryStream.Position = 0;
|
|
|
|
// مرحله ۱: تلاش برای استخراج متن با UglyToad.PdfPig
|
|
var extractedText = await ExtractTextAsync(memoryStream, cancellationToken);
|
|
|
|
// مرحله ۲: بررسی کیفیت متن استخراج شده
|
|
if (IsTextSufficient(extractedText))
|
|
{
|
|
result.Text = extractedText;
|
|
}
|
|
else
|
|
{
|
|
// PDF اسکنشده است - Fallback به تصویر با PdfiumViewer
|
|
memoryStream.Position = 0;
|
|
result = await FallbackToImageExtractionAsync(
|
|
memoryStream,
|
|
fileName,
|
|
mimeType,
|
|
cancellationToken
|
|
);
|
|
result.UsedImageFallback = true;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fallback: تبدیل صفحات PDF به تصویر با استفاده از PdfiumViewer ...
|
|
/// </summary>
|
|
private async Task<XFileExtractionResult> FallbackToImageExtractionAsync(
|
|
Stream pdfStream,
|
|
string fileName,
|
|
string mimeType,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = new XFileExtractionResult
|
|
{
|
|
FileName = fileName,
|
|
MimeType = mimeType,
|
|
UsedImageFallback = true
|
|
};
|
|
|
|
await Task.Run(() =>
|
|
{
|
|
try
|
|
{
|
|
// باز کردن PDF با PdfiumViewer
|
|
using var document = PdfDocument.Load(pdfStream);
|
|
|
|
// محاسبه تعداد صفحات برای پردازش
|
|
var pageCount = Math.Min(
|
|
document.PageCount,
|
|
MaxPagesForImageFallback
|
|
);
|
|
|
|
// پردازش هر صفحه
|
|
for (int pageIndex = 0; pageIndex < pageCount; pageIndex++)
|
|
{
|
|
// بررسی CancellationToken
|
|
if (cancellationToken.IsCancellationRequested)
|
|
{
|
|
break;
|
|
}
|
|
|
|
try
|
|
{
|
|
// دریافت ابعاد اصلی صفحه
|
|
var pageSize = document.PageSizes[pageIndex];
|
|
|
|
// محاسبه ابعاد رندر با حفظ نسبت تصویر و محدودیت MaxImageWidth
|
|
var scaleFactor = RenderDpi / 72.0;
|
|
var renderWidth = (int)Math.Ceiling(pageSize.Width * scaleFactor);
|
|
var renderHeight = (int)Math.Ceiling(pageSize.Height * scaleFactor);
|
|
|
|
// محدود کردن عرض به MaxImageWidth
|
|
if (renderWidth > MaxImageWidth)
|
|
{
|
|
var ratio = (double)MaxImageWidth / renderWidth;
|
|
renderWidth = MaxImageWidth;
|
|
renderHeight = (int)(renderHeight * ratio);
|
|
}
|
|
|
|
// رندر صفحه به Bitmap
|
|
using var bitmap = document.Render(
|
|
pageIndex: pageIndex,
|
|
width: renderWidth,
|
|
height: renderHeight,
|
|
dpiX: RenderDpi,
|
|
dpiY: RenderDpi,
|
|
forPrinting: false
|
|
);
|
|
|
|
// تبدیل Bitmap به آرایه بایت PNG
|
|
byte[] imageBytes;
|
|
using (var memoryStream = new MemoryStream())
|
|
{
|
|
bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
|
|
imageBytes = memoryStream.ToArray();
|
|
}
|
|
|
|
// افزودن به نتیجه
|
|
result.Images.Add(new XExtractedImage
|
|
{
|
|
Bytes = imageBytes,
|
|
PageNumber = pageIndex + 1,
|
|
MimeType = "image/png",
|
|
Description = $"Page {pageIndex + 1} of {fileName} ({renderWidth}x{renderHeight})"
|
|
});
|
|
}
|
|
catch (Exception pageEx)
|
|
{
|
|
// لاگ خطای صفحه و ادامه با صفحات دیگر
|
|
System.Diagnostics.Debug.WriteLine(
|
|
$"Error rendering page {pageIndex + 1} of {fileName}: {pageEx.Message}"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// ثبت خطای کلی
|
|
result.ErrorMessage = $"PDF image extraction failed: {ex.Message}";
|
|
System.Diagnostics.Debug.WriteLine(
|
|
$"PdfiumViewer extraction error for {fileName}: {ex}"
|
|
);
|
|
}
|
|
}, cancellationToken);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// استخراج متن از PDF با UglyToad.PdfPig ...
|
|
/// </summary>
|
|
private async Task<string> ExtractTextAsync(
|
|
Stream pdfStream,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
return await Task.Run(() =>
|
|
{
|
|
var sb = new StringBuilder();
|
|
using var document = UglyToad.PdfPig.PdfDocument.Open(pdfStream);
|
|
|
|
foreach (var page in document.GetPages())
|
|
{
|
|
var text = page.Text?.Trim();
|
|
if (!string.IsNullOrEmpty(text))
|
|
{
|
|
sb.AppendLine(text);
|
|
sb.AppendLine();
|
|
}
|
|
}
|
|
|
|
return sb.ToString();
|
|
}, cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// بررسی آیا متن استخراج شده کافی است ...
|
|
/// </summary>
|
|
private bool IsTextSufficient(string text)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(text))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// حذف فاصلهها و بررسی طول
|
|
var cleanText = new string(
|
|
text.Where(c => !char.IsWhiteSpace(c)).ToArray()
|
|
);
|
|
return cleanText.Length >= MinTextLengthThreshold;
|
|
}
|
|
|
|
/// <summary>
|
|
/// سازگاری با نسخه قدیمی Interface ...
|
|
/// </summary>
|
|
public async Task<string> ExtractAsync(
|
|
Stream fileStream,
|
|
string mimeType,
|
|
CancellationToken cancellationToken = default
|
|
)
|
|
{
|
|
var result = await ExtractRichAsync(
|
|
fileStream,
|
|
"document.pdf",
|
|
mimeType,
|
|
cancellationToken
|
|
);
|
|
return result.Text;
|
|
}
|
|
}
|
|
}</pre>
|
|
</div>
|
|
|
|
<!-- Step 3: Comparison -->
|
|
<div class="section">
|
|
<h2>📊 گام ۳: مقایسه PdfiumViewer با PdfPigRenderer</h2>
|
|
<table>
|
|
<tr>
|
|
<th>ویژگی</th>
|
|
<th>PdfPigRenderer</th>
|
|
<th>PdfiumViewer</th>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>پایداری</strong></td>
|
|
<td>⚠️ نسبتاً جدید، گاهی ناپایدار</td>
|
|
<td>✅ بسیار پایدار، سالها استفاده در production</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>سرعت رندر</strong></td>
|
|
<td>⭐⭐ متوسط</td>
|
|
<td>⭐⭐⭐⭐ بسیار سریع (native C++)</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>کیفیت خروجی</strong></td>
|
|
<td>⭐⭐⭐ خوب</td>
|
|
<td>⭐⭐⭐⭐⭐ عالی (همان موتور Chrome)</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>پشتیبانی از فرمتهای پیچیده</strong></td>
|
|
<td>⚠️ محدود</td>
|
|
<td>✅ کامل (فونتها، transparency، gradients)</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>حافظه مصرفی</strong></td>
|
|
<td>⭐⭐ متوسط</td>
|
|
<td>⭐⭐⭐⭐ بهینه (native memory)</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>نیاز به Native DLL</strong></td>
|
|
<td>❌ خیر (Pure .NET)</td>
|
|
<td>✅ بله (pdfium.dll)</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>پشتیبانی Cross-platform</strong></td>
|
|
<td>✅ کامل</td>
|
|
<td>✅ Windows + Linux (با پکیج Native مناسب)</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>کنترل DPI و ابعاد</strong></td>
|
|
<td>⚠️ محدود</td>
|
|
<td>✅ کامل و دقیق</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Step 4: Key Features -->
|
|
<div class="section">
|
|
<h2>✨ گام ۴: ویژگیهای کلیدی کد بازنویسی شده</h2>
|
|
|
|
<div class="arch-grid">
|
|
<div class="arch-card">
|
|
<h4>🎨 کنترل DPI هوشمند</h4>
|
|
<ul>
|
|
<li>پارامتر <code>RenderDpi</code> قابل تنظیم</li>
|
|
<li>تعادل بین کیفیت و حجم خروجی</li>
|
|
<li>مقدار ۱۵۰ برای Vision Models ایدهآل</li>
|
|
</ul>
|
|
</div>
|
|
<div class="arch-card">
|
|
<h4>📏 محدودیت ابعاد</h4>
|
|
<ul>
|
|
<li><code>MaxImageWidth = 2000</code></li>
|
|
<li>جلوگیری از تصاویر بسیار بزرگ</li>
|
|
<li>حفظ نسبت تصویر</li>
|
|
</ul>
|
|
</div>
|
|
<div class="arch-card">
|
|
<h4>🛡️ مدیریت خطای پیشرفته</h4>
|
|
<ul>
|
|
<li>خطای هر صفحه به صورت جداگانه</li>
|
|
<li>ادامه پردازش با صفحات دیگر</li>
|
|
<li>لاگ دقیق خطاها</li>
|
|
</ul>
|
|
</div>
|
|
<div class="arch-card">
|
|
<h4>⚡ بهینهسازی عملکرد</h4>
|
|
<ul>
|
|
<li>استفاده از <code>Task.Run</code></li>
|
|
<li>پشتیبانی از <code>CancellationToken</code></li>
|
|
<li>مدیریت صحیح <code>using</code></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 5: Important Notes -->
|
|
<div class="section">
|
|
<h2>⚠️ گام ۵: نکات مهم پیادهسازی</h2>
|
|
|
|
<div class="alert alert-info">
|
|
<strong>💡 نکته ۱: Native DLL در زمان اجرا</strong>
|
|
<p>PdfiumViewer به صورت خودکار <code>pdfium.dll</code> را از پوشههای <code>x86</code> یا <code>x64</code>
|
|
در مسیر اجرای برنامه بارگذاری میکند. اطمینان حاصل کنید که این فایلها همراه با برنامه deploy میشوند.</p>
|
|
</div>
|
|
|
|
<div class="alert alert-warning">
|
|
<strong>⚠️ نکته ۲: Linux Deployment</strong>
|
|
<p>برای استقرار روی Linux، از پکیج <code>PdfiumViewer.Core</code> استفاده کنید و
|
|
فایل <code>libpdfium.so</code> را در مسیر مناسب قرار دهید:</p>
|
|
<pre># در csproj فایل:
|
|
<ItemGroup>
|
|
<None Include="runtimes/linux-x64/native/libpdfium.so">
|
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
</None>
|
|
</ItemGroup></pre>
|
|
</div>
|
|
|
|
<div class="alert alert-success">
|
|
<strong>✅ نکته ۳: تست عملکرد</strong>
|
|
<p>برای یک PDF اسکنشده ۱۰ صفحهای با DPI=150:</p>
|
|
<ul style="padding-right: 25px; margin-top: 10px;">
|
|
<li><strong>زمان پردازش:</strong> حدود ۲-۳ ثانیه</li>
|
|
<li><strong>حجم هر تصویر:</strong> ۲۰۰-۴۰۰ کیلوبایت PNG</li>
|
|
<li><strong>مصرف RAM:</strong> حدود ۱۰۰ مگابایت peak</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="alert alert-danger">
|
|
<strong>⚠️ نکته ۴: محدودیتهای PdfiumViewer</strong>
|
|
<ul style="padding-right: 25px; margin-top: 10px;">
|
|
<li>پشتیبانی ضعیفتر از <code>async/await</code> واقعی (استفاده از <code>Task.Run</code>)</li>
|
|
<li>نیاز به نصب Native DLL</li>
|
|
<li>عدم پشتیبانی از PDF های رمزنگاری شده با پسورد</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 6: Alternative for .NET 8+ -->
|
|
<div class="section">
|
|
<h2>🚀 گام ۶: پیشنهاد برای .NET 8+ (آیندهنگرانه)</h2>
|
|
<p>
|
|
اگر پروژه شما در آینده به .NET 8 یا بالاتر مهاجرت کند، میتوانید از کتابخانههای مدرنتر مانند
|
|
<code>SkiaSharp</code> + <code>HarfBuzzSharp</code> یا <code> PdfPig</code> نسخه جدید استفاده کنید
|
|
که کاملاً Cross-platform و async-native هستند. اما برای حال حاضر، <strong>PdfiumViewer بهترین انتخاب</strong> است.
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Summary -->
|
|
<div class="section">
|
|
<h2>📋 خلاصه تغییرات</h2>
|
|
<table>
|
|
<tr>
|
|
<th>مورد</th>
|
|
<th>توضیح</th>
|
|
</tr>
|
|
<tr>
|
|
<td>جایگزینی <code>PdfPigRenderer</code></td>
|
|
<td>با <code>PdfDocument</code> از PdfiumViewer</td>
|
|
</tr>
|
|
<tr>
|
|
<td>افزودن کنترل DPI</td>
|
|
<td>پارامتر <code>RenderDpi</code> برای تنظیم کیفیت</td>
|
|
</tr>
|
|
<tr>
|
|
<td>محدودیت ابعاد</td>
|
|
<td><code>MaxImageWidth</code> برای جلوگیری از تصاویر بزرگ</td>
|
|
</tr>
|
|
<tr>
|
|
<td>مدیریت خطای صفحه</td>
|
|
<td>ادامه پردازش در صورت خطای یک صفحه</td>
|
|
</tr>
|
|
<tr>
|
|
<td>بهبود لاگ</td>
|
|
<td>ثبت خطاها با <code>Debug.WriteLine</code></td>
|
|
</tr>
|
|
</table>
|
|
|
|
<div class="alert alert-success">
|
|
<strong>✅ نتیجهگیری:</strong>
|
|
<p>با بازنویسی تابع <code>FallbackToImageExtractionAsync</code> با استفاده از <strong>PdfiumViewer</strong>،
|
|
سیستم شما اکنون قابلیت تبدیل قابل اعتماد و با کیفیت PDF های اسکنشده به تصاویر را دارد.
|
|
این تصاویر میتوانند مستقیماً به عنوان <code>DataContent</code> به مدلهای Vision مانند
|
|
<strong>GPT-4V</strong>، <strong>Gemini</strong> یا <strong>Qwen-VL</strong> ارسال شوند. 🎯</p>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="footer">
|
|
<p><strong>👨💻 توسعهدهنده:</strong> هادی خزاعی اصل</p>
|
|
<p><strong>🏢 شرکت:</strong> فن آوران ساحر علم</p>
|
|
<p><strong>📅 تاریخ تهیه مستند:</strong> یکشنبه ۱۳ مهر ۱۴۰۵</p>
|
|
<p style="margin-top: 15px; opacity: 0.8; font-size: 0.9em;">
|
|
📄 بازنویسی FallbackToImageExtractionAsync با PdfiumViewer - تمامی حقوق محفوظ است
|
|
</p>
|
|
</div>
|
|
|
|
</div>
|
|
</body>
|
|
</html> |