PDFium Component جدولها را روی یک صفحه PDF تشخیص میدهد و آنها را بهصورت یک شبکه از سلولها با span سطر و ستون، سطرهای سربرگ و یک مقدار اطمینان برمیگرداند، از طریق ExtractTables برای یک صفحه و ExtractDocumentTables برای کل یک سند. هر جدول با یک فراخوانی به CSV یا JSON تبدیل میشود، و جدولهایی که در شکست صفحه ادامه مییابند میتوانند در یک زنجیره ادامه به هم پیوند بخورند
PDF هیچ شیء جدولی ندارد. یک جدول در یک PDF مجموعهای از اجراهای متنی است که بهگونهای قرار داده شده که یک انسان آنها را بهصورت یک شبکه میخواند، گاهی با خطوطی که دورشان رسم شده و اغلب بدون آن. بازیابی شبکه یعنی بازسازی یک نیتی که فایل هرگز ثبت نکرده، به همین دلیل هر ابزار استخراج نتایج کمی متفاوت تولید میکند و به همین دلیل ابزاری که اطمینان خودش را به شما میگوید مفیدتر از ابزاری است که نمیگوید
دو حالت تشخیص برای دو نوع جدول
تشخیص خطکشیشده از خطوط رسمشده استفاده میکند. هر قطعه مسیر رنگشده از طریق ماتریس شیء صفحه به مختصات صفحه تبدیل میشود، خطوط افقی و عمودی متقاطع میشوند، و تقاطعها مؤلفههای متصل تشکیل میدهند. هر مؤلفه شبکه مرتبشده خودش از موقعیتهای X و Y میشود، که همان چیزی است که مانع میشود دو جدول جداگانه روی یک صفحه در یک شبکه بیمعنا ادغام شوند
تشخیص فاصله سفید جدولهایی را مدیریت میکند که با تراز بهجای خط رسم شدهاند. جعبههای کلمه به سطرهای بصری گروهبندی میشوند، شکافهای درون یک سطر آن را به ستونهای نامزد تقسیم میکنند، و یک جدول فقط زمانی پذیرفته میشود که دستکم MinRows سطر دستکم MinColumns نقطه لنگر تراز-چپ را درون AlignmentTolerance تکرار کنند. ضریب شکاف سطر بهطور پیشفرض ۳ است، که فاصله خط پایه تقریباً ۳۰ نقطهای معمولِ متن ۱۲ نقطهای را پوشش میدهد بدون اینکه اجازه دهد یک خط منفرد حاوی چندین اجرای متنی وانمود کند یک جدول است
uses
PDFium;
var
Pdf: TPdf;
Options: TPdfTableExtractionOptions;
Tables: TPdfTables;
I: Integer;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := 'annual-report.pdf';
Pdf.LoadDocument;
Pdf.PageNumber := 12; // مبتنی بر ۱
Options := TPdfTableExtractionOptions.Default;
Options.DetectRuledTables := True;
Options.DetectWhitespaceTables := True;
Options.MinConfidence := 0.6; // پیشفرض ۰٫۵ است
Options.HeaderRowCount := 1;
Tables := Pdf.ExtractTables(Options);
for I := 0 to High(Tables) do
Writeln(Format('table %d: %dx%d cells, confidence %.2f, mode %d',
[I, Tables[I].RowCount, Tables[I].ColumnCount,
Tables[I].Confidence, Ord(Tables[I].DetectionMode)]));
if Length(Tables) > 0 then
SaveText('page12-table0.csv', Tables[0].ToCsv);
finally
Pdf.Free;
end;
end;
سلولهای ادغامشده چگونه بازیابی میشوند؟
این بخشی است که استخراجکنندههای سادهلوحانه در آن اشتباه میکنند. یک سلول ادغامشده نمیتواند فقط از شبکه سراسری شناسایی شود، زیرا شبکه از همه خطوط روی صفحه مشتق شده و یک ناحیه ادغامشده بهسادگی فاقد خط داخلیای است که آن را جدا میکرد
قاعدهای که اینجا استفاده میشود محلی است: دو سلول پایه مجاور وقتی ادغام میشوند که هیچ خط مرزی فاصله میان آنها را پوشش ندهد. union-find آنها را میپیوندد، مؤلفههای مستطیلی حاصل به مقادیر RowSpan و ColumnSpan تبدیل میشوند، و متن به یک سلول پایه با نقطه مرکزیاش اختصاص مییابد و سپس آن سلول را تا ریشه ادغامش دنبال میکند. انجام آن به این شکل همچنین هزینه را در کلمات بهعلاوه سلولها خطی نگه میدارد، بهجای اسکن درجهدومی که از آزمایش هر کلمه در برابر هر سلول به دست میآورید
اثر عملی این است که یک جدول مالی با یک سربرگ «مجموع» ادغامشده که سه ستون را در بر میگیرد، با یک سلول با span سه بیرون میآید، نه یک سلول پرشده و دو سلول خالی مرموز
ادامه در سراسر صفحات
جدولهای طولانی در سراسر صفحات میشکنند، و رفتار با قطعه هر صفحه بهعنوان یک جدول مستقل، فراخوان را مجبور میکند آنها را به هم بدوزد. ExtractDocumentTables میتواند در عوض آنها را پیوند بزند، اما فقط تحت شرایط سختگیرانه: قطعه باید پایینترین جدول روی صفحه قبلی باشد، بعدی باید بالاترین جدول روی صفحه بعدی باشد، شماره صفحات باید مجاور باشند، و مرزهای ستون باید مطابقت داشته باشند
هر چهار شرط با هم چیزی است که مانع خطای واضح میشود، که زنجیره کردن هر جدول چهار-ستونی در یک سند در یک مگا-جدول خیالی است چون بهطور تصادفی یک شمار ستون مشترک دارند. وقتی شرایط برقرارند، جدولها یک شناسه گروه ادامه مشترک را به اشتراک میگذارند و متادیتای ادامه حمل میکنند؛ وقتی برقرار نیستند، جدولهای جداگانه به دست میآورید و میتوانید خودتان تصمیم بگیرید
استخراج در سطح سند بودجههای MaxCells و MaxTables را در سراسر صفحات به اشتراک میگذارد نه اینکه آنها را به ازای هر صفحه بازنشانی کند، و صفحه فعال را در یک بلوک finally بازمیگرداند، بنابراین یک اجرای استخراج در یک نمایشگر کاربر را با نگاه به همان صفحهای که روی آن بود رها میکند
صادرات بدون خراب کردن داده
هر دو صادرکننده درباره فرار عمدی هستند. CSV همیشه فیلدها را نقلقول میکند و نشانههای نقلقول داخلی را دوبل میکند، که از شکست کلاسیکی جلوگیری میکند که در آن یک سلول حاوی یک ویرگول بیسروصدا به دو ستون تبدیل میشود. برای سلولهای ادغامشده، محتوا فقط در نقطه لنگر بالا-چپ منتشر میشود، بنابراین یک رفتوبرگشت CSV یک سربرگ گسترده را در سراسر ستونهایی که پوشش میدهد تکرار نمیکند
JSON یونیکد را حفظ میکند بهجای فرار دادنش به ASCII، کاراکترهای کنترلی را فرار میدهد، و متادیتایی را میگنجاند که یک مصرفکننده برای قضاوت کیفیت به آن نیاز دارد: حالت تشخیص، اطمینان، مرزها، مقادیر span، پرچمهای سربرگ و اطلاعات ادامه. اگر جدولهای استخراجشده را به یک سیستم پاییندستی تغذیه میکنید، JSON را ترجیح دهید، زیرا یک سطر CSV نمیتواند به شما بگوید جدولی که از آن آمده امتیاز اطمینان ۰٫۵۱ کسب کرده:
// استخراج سراسر سند، فقط نگهداشتن جدولهای ارزشاعتماد
Tables := Pdf.ExtractDocumentTables(Options);
for I := 0 to High(Tables) do
begin
if Tables[I].Confidence < 0.75 then
begin
Log(Format('page %d table needs review (%.2f)',
[Tables[I].PageNumber, Tables[I].Confidence]));
Continue;
end;
if Tables[I].ContinuationGroup > 0 then
AppendToGroup(Tables[I].ContinuationGroup, Tables[I].ToJson)
else
EmitStandalone(Tables[I].ToJson);
end;
تنظیم دقیق، و دانستن اینکه چه زمانی متوقف شوید
سه تنظیم بیشتر از بقیه اهمیت دارند. MinConfidence دروازه کیفیت است، و ۰٫۵ عمداً اغماضکننده است؛ آن را برای دریافت خودکار بالا ببرید و برای یک رابط کاربری بازبینی که در آن یک انسان هر نتیجه را تأیید میکند پایین بیاورید. MinColumnGap تصمیم میگیرد چه چیزی در حالت فاصله سفید بهعنوان یک مرز ستون شمرده میشود، و جدولهای بهطور تنگ تنظیمشده در گزارشهای فشرده ممکن است نیاز داشته باشند آن از پیشفرض ۱۲ نقطهای کاهش یابد. MaxRowGapFactor تصمیم میگیرد چه زمانی فاصله عمودی یک جدول را پایان میدهد، که برای جدولهایی با سطرهای خالی گاهبهگاه اهمیت دارد
درباره محدودیتها صادق باشید. جدولهای خطکشیشده بهطور قابلاعتماد استخراج میشوند. جدولهای فاصله سفید بهتمیزی ترازشده بهخوبی استخراج میشوند. جدولهایی با متن چرخاندهشده، جدولهای تودرتو، یا سلولهایی که محتوایشان به چیزی شبیه یک سطر دیگر بستهبندی میشود، صرفنظر از نحوه تنظیم پارامترها به بازبینی نیاز خواهند داشت. برای آنها، مدل متن ساختاریافته مواد خام را برای ساختن یک خواننده حوزهمحور به شما میدهد، که در بلوکهای متن ساختاریافته و ترتیب خواندن شرح داده شده
یک همراهی مفید: وقتی یک سند اسکنشده اصلاً متنی ندارد، تشخیص جدول تا وقتی یک لایه متن وجود نداشته باشد، چیزی برای کار کردن ندارد. ابتدا یکی اضافه کنید، همانطور که در افزودن لایه متن قابلجستجو به PDFهای اسکنشده شرح داده شده، سپس استخراج کنید. جعبههای کلمهای که یک ارائهدهنده OCR برمیگرداند دقیقاً همان ورودیای هستند که تشخیص فاصله سفید به آن نیاز دارد
استخراج جدول، متن ساختاریافته و بازچیدمان همگی از همان مدل صفحه در Delphi، C++Builder و Lazarus میخوانند؛ API کامل در صفحه PDFium Component برای Delphi شرح داده شده است