مقاله فنی

جاسازی فونت‌های CID Type 2 در PDF از دلفی

PDFium Component متن را در یک صفحه PDF در سطح گلیف با AddCidType2Text می‌نویسد، داده TrueTypeی را که شما فراهم می‌کنید به‌عنوان یک فونت CID Type 2 جاسازی می‌کند. آن به هر نمونه گلیف یک CID متوالی اختصاص می‌دهد، نگاشت صریح CID-به-GID و CMap ToUnicode را تولید می‌کند، و گلیف‌های روی همان خط پایه را در یک شیء متن بومی واحد ادغام می‌کند. زیرمجموعه‌سازی اختیاری فایل را کوچک نگه می‌دارد، با یک سیاست صریح برای اینکه وقتی زیرمجموعه‌سازی شکست می‌خورد چه اتفاقی می‌افتد

نوشتن در سطح گلیف چیزی است که وقتی متن از قبل شکل گرفته به آن نیاز دارید. عربی، دواناگری و هر رسم‌الخطی با فرم‌های وابسته به بافت، دنباله‌ای از شناسه‌های گلیف تولید می‌کنند که دیگر یک‌به‌یک روی کاراکترها نگاشت نمی‌شود، بنابراین یک API که یک رشته و یک نام فونت می‌گیرد نمی‌تواند نتیجه را بیان کند. تحویل مستقیم گلیف‌ها و موقعیت‌ها تنها راهی است که می‌توانید متن پیچیده رسم‌الخط شکل‌گرفته درست را در یک PDF بگذارید

AddCidType2Text در Delphi به هر نمونهٔ گلیف شکل‌یافته CID ترتیبی می‌دهد و CIDToGIDMap و CMapِ ToUnicode را می‌نویسد و اجرا را در یک شیء متن صفحه ادغام می‌کند که تمیز استخراج می‌شود
هر نمونه گلیف CID خودش را می‌گیرد، دیکشنری فونت CIDها را به شناسه‌های گلیف و برگشت به Unicode نگاشت می‌کند، و رشته به‌عنوان یک شیء متن روی صفحه فرود می‌آید که به متن مقصود برمی‌گردد

چرا هر نمونه گلیف CID خودش را می‌گیرد

بهینه‌سازی وسوسه‌انگیز حذف تکرار است: یک CID برای هر شناسه گلیف متمایز، که هرجا آن گلیف ظاهر شود دوباره استفاده می‌شود. آن یک فونت کوچک‌تر تولید می‌کند و استخراج متن را می‌شکند، زیرا همان گلیف می‌تواند مشروعاً به محتوای یونیکد متفاوتی در جاهای متفاوت مطابقت داشته باشد

یک گلیف لیگاتور مورد روشن است. همان گلیف «ffi» می‌تواند نماینده سه کاراکتر در یک کلمه باشد و، پس از یک تصمیم شکل‌دهی متفاوت، برای چیز دیگری در جای دیگر. نگاشت ToUnicode توسط CID کلیدگذاری شده، بنابراین یک CID مشترک فقط می‌تواند یک نگاشت حمل کند، و هر متنی که آن رقابت را ببازد غیرقابل‌استخراج می‌شود

بنابراین هر نمونه گلیف CID خودش را می‌گیرد، و هر نگاشت آزاد است که چندین واحد کد UTF-16 باشد. یک گلیف بدون متن معنادار — یک عنصر تزئینی، یک گلیف فقط-موقعیت‌دهی — صریحاً به U+200B، یک فاصله بدون عرض، نگاشت می‌شود، بنابراین هر CID یک نتیجه استخراج قابل‌مشاهده دارد نه یک شکاف

uses
  PDFium;

var
  Pdf: TPdf;
  Glyphs: TPdfCidGlyphs;
  Options: TPdfCidFontOptions;
  Report: TPdfCidFontReport;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.FileName := 'label.pdf';
    Pdf.LoadDocument;
    Pdf.PageNumber := 1;

    // یک ورودی برای هر گلیف شکل‌گرفته: شناسه گلیف، متنی که نمایندگی می‌کند،
    // و پیشروی و آفست‌هایش در فضای متن
    SetLength(Glyphs, 3);
    Glyphs[0].GlyphID := 402;  Glyphs[0].UnicodeText := 'ffi';
    Glyphs[0].Advance := 18.4;
    Glyphs[1].GlyphID := 71;  Glyphs[1].UnicodeText := 'c';
    Glyphs[1].Advance := 9.8;
    Glyphs[2].GlyphID := 74;   Glyphs[2].UnicodeText := 'e';
    Glyphs[2].Advance := 9.2;

    Options := TPdfCidFontOptions.Default;   // زیرمجموعه ترجیحی
    Options.VerifyExtraction := True;

    if Pdf.AddCidType2Text(LoadFileBytes('NotoSans.ttf'), Glyphs,
         11, 72, 700, Options, Report) then
      Writeln(Format('%d glyphs, %d unique, font %d -> %d bytes, match=%s',
        [Report.GlyphCount, Report.UniqueGlyphCount,
         Report.OriginalFontBytes, Report.EmbeddedFontBytes,
         BoolToStr(Report.ExtractionMatches, True)]));
  finally
    Pdf.Free;
  end;
end;

زیرمجموعه‌سازی، و بررسی‌هایی که یک کد بازگشتی به شما نمی‌دهد

زیرمجموعه‌سازی یک فونت به گلیف‌هایی که واقعاً استفاده شده‌اند، تفاوت میان جاسازی ۳۰۰ کیلوبایت و جاسازی ۱۲ کیلوبایت است، و روی سندی با چندین فونت این تصمیم می‌گیرد که آیا فایل قابل‌ایمیل‌کردن است یا نه. مسیر زیرمجموعه‌سازی پلتفرم یک لیست گلیف را مستقیماً می‌پذیرد، که کاملاً با این API جور است زیرا فراخوان از قبل هر شناسه گلیف مورداستفاده را می‌داند

آنچه به شما نمی‌دهد اطمینان است. یک فراخوانی زیرمجموعه‌سازی می‌تواند موفقیت را گزارش دهد و خروجی‌ای غیرقابل‌استفاده برگرداند، بنابراین مؤلفه سه ویژگی را پیش از پذیرش نتیجه اعتبارسنجی می‌کند: خروجی باید کوچک‌تر از اصل باشد، باید دوباره به‌عنوان یک sfnt معتبر با یک جدول maxp قابل‌خواندن تجزیه شود، و باید گلیف‌ها را تا بالاترین شناسه اصلی درخواست‌شده نگه دارد. هر شکستی یعنی زیرمجموعه رد می‌شود

آنچه بعد اتفاق می‌افتد سیاست فراخوان است. تحت pcfemSubsetPreferred، پیش‌فرض، یک زیرمجموعه ردشده به جاسازی فونت کامل بازمی‌گردد، بنابراین صفحه درست است و صرفاً بزرگ‌تر. تحت pcfemSubsetRequired، عملیات پیش از تغییر صفحه شکست می‌خورد، که همان چیزی است که یک خط لوله با محدودیت اندازه می‌خواهد. pcfemFull کاملاً زیرمجموعه‌سازی را رد می‌کند. گزارش به شما می‌گوید کدام مسیر از طریق SubsetAttempted، SubsetApplied، UsedFullFontFallback و SubsetErrorCode طی شده

زیرمجموعه‌سازی فونت CID Type 2 در Delphi سه بررسی اعتبارسنجی اندازه و تمامیت sfnt و پوشش گلیف را پیش از پذیرش می‌گذراند و زیرمجموعهٔ ردشده از سیاست pcfem یعنی چارهٔ فونت کامل یا شکست سخت پیروی می‌کند
یک زیرمجموعه فقط پس از قبول بررسی‌های اندازه و sfnt و پوشش گلیف پذیرفته می‌شود، و زیرمجموعه ردشده سپس از سیاست فراخواننده پیروی می‌کند — بازگشت به فونت کامل یا شکست پیش از تغییر صفحه

اعتبارسنجی‌ای که نمی‌تواند یک مثبت کاذب تولید کند

با فعال بودن VerifyExtraction، مؤلفه تأیید می‌کند که آنچه نوشته می‌تواند دوباره خوانده شود. راه ساده‌لوحانه برای انجام این کار استخراج کل صفحه و جستجوی رشته موردانتظار است، و آن غلط است: صفحه‌ای که از قبل آن متن را حمل می‌کرد، حتی وقتی متن جدید نادرست نوشته شده باشد، بررسی را قبول می‌شود

در عوض صفحه متن بازسازی می‌شود و handleهای شیءای که توسط این فراخوانی درج شده‌اند، به‌طور جداگانه، به ترتیب درج، خوانده و به هم متصل می‌شوند. نتیجه با متن موردانتظار مقایسه می‌شود، و گزارش هر دو رشته را همراه با بولین در معرض دید می‌گذارد، بنابراین یک عدم‌تطابق می‌تواند تشخیص داده شود نه صرفاً کشف

آن را در طول توسعه و در هر خط لوله‌ای که قابلیت استخراج یک نیازمندی است روشن نگه دارید — بایگانی‌های قابل‌جستجو، انطباق دسترس‌پذیری، متن‌کاوی پایین‌دستی. هزینه یک بازسازی صفحه متن در هر فراخوانی است، به همین دلیل به‌طور پیش‌فرض در حلقه‌های فشرده روشن نیست

بودجه‌ها و شکست اتمیک

بایت‌های فونت، نمونه‌های گلیف و واحدهای کد یونیکد هرکدام پیش از تخصیص سقف‌دار هستند، و فرمت فونت، اندیس TTC، بازه شناسه گلیف و مقادیر هندسی پیش از نوشتن هر چیزی اعتبارسنجی می‌شوند. هندسه باید متناهی باشد، که واضح به نظر می‌رسد تا وقتی یک موتور شکل‌دهی به شما یک پیشروی NaN از یک فونت بدشکل بدهد

شکست در سطح صفحه اتمیک است. اگر بارگذاری فونت، نوشتن شیء، تولید محتوا یا اعتبارسنجی استخراج شکست بخورد، هر شیئی که توسط آن فراخوانی درج شده به ترتیب معکوس حذف می‌شود و محتوای صفحه دوباره تولید می‌شود. یک فراخوانی ناموفق صفحه را همان‌طور که بود رها می‌کند، نه با نیمی از یک اجرای متن روی آن

این کجای یک خط لوله متن جا می‌گیرد

تقسیم کار ارزش بیان صریح دارد. شکل‌دهی — تبدیل کاراکترها به گلیف‌های موقعیت‌یافته — وظیفه این API نیست؛ آن متعلق به یک موتور شکل‌دهی است، و پشتیبانی دوجهتی و رسم‌الخط پیچیده خودِ مؤلفه در مدیریت ایموجی، CJK و جفت جانشین پوشش داده شده است. این API چیزی است که پس از آن، با اجرای گلیفی که شکل‌دهنده تولید کرده، فراخوانی می‌کنید

برای متن لاتین معمولی بدون شکل‌دهی وابسته به بافت، APIهای متن رشته‌ای ساده‌تر ابزار درست هستند و کد کوچک‌تری تولید می‌کنند. وقتی خروجی شکل‌گرفته دارید، وقتی به کنترل دقیق شناسه‌های گلیف نیاز دارید، یا وقتی فونت باید از بایت‌هایی که خودتان نگه می‌دارید جاسازی شود نه با نام حل‌شود، سراغ نوشتن CID Type 2 بروید — جایگزین حل فونت مکانیزم فراهم‌کننده‌ای است که در کنترل جایگزینی فونت PDF شرح داده شده

یک یادداشت استقراری: جاسازی یک فونت به همان اندازه یک سؤال مجوز است که یک سؤال فنی. فونت‌ها در اینکه آیا جاسازی اصلاً مجاز است، فقط برای نمایش مجاز است، یا برای ویرایش مجاز است، متفاوتند. کتابخانه هر بایتی که به آن بدهید جاسازی خواهد کرد، و بررسی مجوز مسئولیت شماست، نه فرمت فایل

نوشتن متن در سطح گلیف، تدارک فونت و استخراج متن همان مدل صفحه را در Delphi، C++Builder و Lazarus به اشتراک می‌گذارند؛ API کامل در صفحه PDFium Component برای Delphi شرح داده شده است