مقاله فنی

ساختار فایل PDF: فرمت در واقع چگونه کار می‌کند

PDF یک فرمت سند به شکلی که Word یا RTF هستند، نیست. آن فرمت‌ها توالی از محتوا را ذخیره می‌کنند که یک رندرکننده (renderer) در لحظه نمایش تفسیر می‌کند، بنابراین خروجی به هر فونت و موتور چیدمانی که اتفاقاً وجود دارد بستگی دارد. PDF نتیجه آن فرآیند را ذخیره می‌کند: دستورالعمل‌های رندر دقیق، برنامه‌های فونت، جریان‌های تصویر فشرده شده، و یک گراف آبجکت که آنها را به یک توصیف مستقل از هر صفحه پیوند می‌دهد. فایل اطلاعات کافی برای بازتولید یکسان هر صفحه در هر رندرکننده سازگار را به همراه دارد، که هم هدف اصلی طراحی آن است و هم منبع بیشتر پیچیدگی‌هایی است که هنگام تلاش برای تولید، تجزیه، یا تغییر برنامه‌نویسی‌شده‌ی آن با آن مواجه می‌شوید

مدل آبجکت

هر PDF مجموعه‌ای از آبجکت‌های شماره‌گذاری شده است. یک آبجکت می‌تواند از نوع بولین (boolean)، عدد صحیح، عدد حقیقی، نام، رشته، آرایه، دیکشنری، جریان (stream) یا نال (null) باشد. تقریباً هر چیز جالبی یک دیکشنری است، که مجموعه‌ای از جفت‌های کلید-مقدار است که در آن کلیدها نام هستند و مقادیر هر نوع آبجکت دیگری هستند، از جمله ارجاعات به سایر آبجکت‌ها بر اساس شماره و تعداد نسل. جریان، دیکشنری است که به دنبال آن یک دنباله بایت قرار دارد و معمولاً فشرده شده است

دیکشنری کاتالوگ، ریشه است. به درخت‌صفحه اشاره می‌کند، که دیکشنری‌های صفحه را به جای یک لیست مسطح، در یک ساختار درخت متعادل سازماندهی می‌کند، بنابراین پیمایش به صفحه ۵۰۰۰ از یک سند ۱۰۰۰۰ صفحه‌ای نیازی به پیمایش تمام توصیف‌گرهای صفحه قبلی ندارد. هر دیکشنری صفحه به جریان‌های محتوای خود (یک یا چند توالی از عملگرهای توصیف‌صفحه)، دیکشنری منابع آن (که به نوبه خود به توصیف‌گرهای فونت، فضاهای رنگی، و XObjectهای تصویر ارجاع می‌دهد)، و مدیا باکس آن (فضای مختصاتی که صفحه در آن قرار دارد) ارجاع می‌دهد. مبدا مختصات در گوشه پایین سمت چپ است، و Y مثبت به سمت بالا می‌رود، در واحدهای ۱/۷۲ اینچ

در انتهای فایل جدول cross-reference قرار دارد که هر شماره آبجکت را به آفست بایت آن در فایل نگاشت می‌کند. این چیزی است که دسترسی تصادفی را امکان‌پذیر می‌کند: یک نمایشگر ابتدا جدول cross-reference را می‌خواند، سپس مستقیماً به دنبال هر آبجکتی که نیاز دارد می‌گردد. PDF 1.5 جریان‌های cross-reference را معرفی کرد، که جدول را در یک آبجکت جریان فشرده می‌کنند و آبجکت‌های مرتبط را در جریان‌های آبجکت بسته‌بندی می‌کنند، که به طور قابل توجهی اندازه فایل را برای اسنادی با بسیاری از آبجکت‌های کوچک کاهش می‌دهد

جریان‌های محتوا و مدل گرافیکی

محتوای بصری یک صفحه در یک یا چند جریان محتوا قرار دارد. هر جریان توالی از عملگرهای PDF است که با عملوندهای آنها پراکنده شده‌اند. عملگر متن BT یک آبجکت متنی را شروع می‌کند، Tf فونت و اندازه را از دیکشنری منابع انتخاب می‌کند، Td مکان‌نمای متن را قرار می‌دهد، Tj یا TJ یک رشته را نقاشی می‌کند، و ET آبجکت متنی را می‌بندد. گرافیک‌های برداری نیز از الگوی مشابهی پیروی می‌کنند: m نقطه شروع یک مسیر را تنظیم می‌کند، l یک بخش خط را ضمیمه می‌کند، c یک منحنی بزیه (Bezier curve) را ضمیمه می‌کند، و f یا S مسیر را پر می‌کند یا خطوط آن را می‌کشد (strokes)

حالت گرافیکی بر هر چیزی که بین عملگرها اتفاق می‌افتد حاکم است: ماتریس تبدیل فعلی، عرض خط، فضای رنگ، رنگ پر کردن، رنگ خط تیره (stroke) و مسیر برش (clipping path). عملگرهایی مانند q و Q حالت گرافیکی را روی یک پشته قرار داده (push) و برمی‌دارند (pop)، که این نحوه پیاده‌سازی تبدیل مختصات محلی و لغو موقت حالت در PDF بدون تأثیر بر زمینه اطراف آنهاست. XObjectهای فرم این را تعمیم می‌دهند: یک جریان محتوای مستقل با دیکشنری منابع خاص خود که می‌تواند در موقعیت‌ها و مقیاس‌های دلخواه با یک عملگر منفرد Do روی یک صفحه نقاشی شود

جاسازی فونت و استخراج متن

PDF می‌تواند با نام به فونت‌ها ارجاع دهد و برای جایگزینی به نمایشگر تکیه کند، اما در عمل هر سندی که قصد به اشتراک گذاری آن را دارید باید داده‌های فونت را در خود جاسازی کند. یک فونت Type 1 یا TrueType/OpenType تعبیه شده در یک PDF دارای یک دیکشنری توصیفگر فونت است که به جریان فایل فونت اشاره می‌کند. برای فونت‌های TrueType، آن جریان حاوی برنامه باینری فونت است؛ برای Type 1، داده‌های PFB است. زیرمجموعه‌سازی (Subsetting)، که کاری است که هر تولیدکننده جدی PDF انجام می‌دهد، گلیف‌هایی را که سند به آنها ارجاع نمی‌دهد حذف می‌کند و اندازه فایل‌ها را حتی برای فونت‌های بزرگ یونیکد قابل مدیریت نگه می‌دارد

استخراج متن جایی است که جاسازی فونت مشکل‌ساز می‌شود. نمایش بصری یک کاراکتر توسط یک گلیف در برنامه فونت جاسازی شده تعیین می‌شود. مقدار یونیکد آن کاراکتر توسط یک جریان ToUnicode CMap که به دیکشنری فونت پیوست شده است تعیین می‌شود. زمانی که ToUnicode CMap وجود ندارد یا اشتباه است، یک نمایشگر PDF می‌تواند متن را به صورت خوانا رندر کند اما نمی‌تواند آن را به عنوان یونیکد معنی‌دار استخراج کند، به همین دلیل است که کپی-پیست از برخی PDFها متن‌های نامفهومی (garbage) تولید می‌کند. PDF تگ‌گذاری‌شده (ISO 32000 §14.8) یک لایه دوم اضافه می‌کند: یک درخت ساختار منطقی که محتوای صفحه را به نقش‌های معنایی-سند مانند پاراگراف‌ها، سرفصل‌ها و سلول‌های جدول نگاشت می‌کند. صفحه‌خوان‌ها و موتورهای بازآرایی (reflow engines) به جای ترتیب جریان محتوای خام از درخت ساختار استفاده می‌کنند، که توضیح می‌دهد چرا یک PDF که از نظر بصری خوب چیده شده است در صورت عدم وجود یا اشتباه بودن تگ‌گذاری می‌تواند همچنان غیرقابل دسترس باشد

به‌روزرسانی‌های افزایشی و امضاهای دیجیتال

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

اول اینکه، فایل با هر چرخه ذخیره رشد می‌کند. سندی که به طور مکرر ویرایش و ذخیره می‌شود، لایه‌هایی از آبجکت‌های منسوخ را جمع‌آوری می‌کند. ابزارهایی مانند QPDF می‌توانند برای بازیابی آن فضا، یک فایل را خطی کرده یا آن را فشرده-و-بازنویسی کنند، اما پیش‌فرض انباشتگی است. دوم، امضاهای دیجیتال برای مدل یکپارچگی خود به به‌روزرسانی‌های افزایشی وابسته هستند. امضای ISO 32000 دامنه بایتی از فایل را پوشش می‌دهد، معمولاً همه چیز به جز نگهدارنده برای خود مقدار امضا. هر گونه تغییرات پس از امضا که به عنوان به‌روزرسانی‌های افزایشی اضافی ظاهر می‌شوند، برای یک خواننده اعتبارسنجی به عنوان تغییراتی که پس از امضا ایجاد شده‌اند قابل مشاهده است، که دقیقاً همان مسیر ممیزی است که شما می‌خواهید. با این حال، این همچنین به این معنی است که تغییرات خاصی مانند افزودن امضای تأیید یا پر کردن فیلدهای فرم، به صراحت توسط استاندارد بدون باطل کردن امضای اصلی مجاز است، مشروط بر اینکه تغییرات با تنظیمات مجوز سند (ISO 32000-2 §12.7.6) مطابقت داشته باشد. تغییری که خارج از این مجوزها باشد به عنوان غیرمجاز علامت‌گذاری می‌شود. درک درست این تمایز زمانی که اسنادی تولید می‌کنید که قرار است در مراحل بعدی به تأیید نهایی برسند، اهمیت دارد

سطوح انطباق و دودمان ISO 32000

PDF به عنوان یک فرمت اختصاصی Adobe در سال ۱۹۹۳ شروع شد، مدل تصویربرداری PostScript را جذب کرد و در طول پانزده نسخه ویژگی‌هایی را جمع‌آوری کرد: رمزنگاری در ۱.۱، فرم‌های تعاملی در ۱.۲، امضاهای دیجیتال و ساختار منطقی در ۱.۳، شفافیت در ۱.۴، جریان‌های آبجکت در ۱.۵، رمزنگاری AES در ۱.۶. Adobe در سال ۲۰۰۷، PDF 1.7 را به ISO ارسال کرد، و ISO 32000-1:2008 نتیجه آن بود. ISO 32000-2:2020 فرمت PDF 2.0 را پوشش می‌دهد، که چندین حوزه مشخص‌نشده را محکم‌تر کرد، استخراج کلید AES-256 را مورد بازبینی قرار داد (نسخه ۶ جایگزین نسخه ۵ شد) و پشتیبانی صریح برای فایل‌های مرتبط و رسانه غنی (rich media) اضافه کرد

زیر‌استانداردها از یک مبنا سرچشمه می‌گیرند. PDF/A (ISO 19005) ویژگی‌ها را در ازای ثبات آرشیوی معامله می‌کند: بدون رمزنگاری، بدون وابستگی محتوای خارجی، همه فونت‌ها جاسازی شده، فضاهای رنگی مستقل از دستگاه، متادیتا XMP مورد نیاز است. PDF/A-1 بر اساس PDF 1.4، و PDF/A-2 بر اساس PDF 1.7 است، PDF/A-3 فایل‌های جاسازی شده از هر فرمتی را مجاز می‌داند. PDF/X (ISO 15930) زیرمجموعه تولید چاپ است: مقاصد خروجی، کادرهای حاشیه و برش، بدون شفافیت در سطوح انطباق قدیمی‌تر. PDF/UA (ISO 14289) ساختار تگ‌گذاری‌شده، نگاشت‌های یونیکد، و متادیتای زبان را برای دسترسی‌پذیری اجباری می‌کند. اینها فرمت‌های رقیب نیستند؛ آنها مجموعه‌ای از محدودیت‌های اضافی بر روی هسته PDF هستند و یک فایل می‌تواند همزمان با بیش از یک استاندارد مطابقت داشته باشد به شرطی که محدودیت‌ها با هم تضاد نداشته باشند

برای هر کسی که کدی می‌نویسد که PDF را تولید یا پردازش می‌کند، خط مبنای عملی ISO 32000-2 با توجه دقیق به بخش‌های پوشش‌دهنده مدل cross-reference (§7.5)، حالت گرافیکی (§8.4)، عملگرهای حالت متنی (§9.3)، توصیفگرهای فونت و ToUnicode (§9.6 و §9.10)، فرم‌های تعاملی (§12.7) و امضاهای دیجیتال (§12.8) است. استاندارد طولانی است، اما بیشتر کارهای برنامه‌نویسی PDF بارها و بارها بخش باریکی از آن را لمس می‌کند. درک مدل آبجکت و مکانیزم cross-reference نقطه ورود است؛ از آنجا به بعد همه چیز تخصصی‌سازی است