مقاله فنی

فشرده‌سازی بومی تصویر دو‌سطحی JBIG2 در PDFهای دلفی

یک قرارداد اسکن شده، شامل چند صد نقطه در اینچ از جوهر سیاه روی کاغذ سفید است. ذخیره آن به صورت بیت‌مپ یک-بیت-بر-پیکسل در حال حاضر کوچک است، اما با این حال صد صفحه از این نوع، حجم یک PDF را بیش از آنچه که بتوانید ایمیل کنید، افزایش می‌دهد. فیلتر مناسب این محاسبات را تغییر می‌دهد. JBIG2 بالاترین نرخ فشرده‌سازی را دارد که استاندارد ISO 32000-1 برای تصاویر دوسطحی تعریف می‌کند، و در مورد مجموعه‌ای از متون اسکن شده به طور معمول حجم تولیدی CCITT Group 4 را به نصف کاهش می‌دهد. این فیلتری است که وقتی ورودی فکس شده، اسکن شده، یا در غیر این صورت به دو رنگ تقلیل یافته است، باید به سراغ آن بروید، و HotPDF می‌تواند آن را به طور مستقیم در یک PDF بنویسد

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

جایگاه JBIG2 در مشخصات PDF

استاندارد ISO 32000-1 گزینه JBIG2Decode را در میان فیلترهای جریان در بخش 7.4.7 فهرست می‌کند، که از PDF 1.4 به بعد در دسترس است. این فقط در یک جا اعمال می‌شود: image XObject هایی که /BitsPerComponent آنها 1 است و فضای رنگی آنها به یک کانال واحد ختم می‌شود. کل موضوع همین است. JBIG2 یک کدک دوسطحی است، بنابراین هرگز با DCT یا JPXDecode در عکس‌ها رقابت نمی‌کند. این فرمت با CCITTFaxDecode، فیلترهای فکس Group 3 و Group 4، دقیقاً در نوع صفحه‌ای با دو تن رنگ که یک اسکنر سند تولید می‌کند، رقابت می‌کند

رمزگشا، ساختار JBIG2 جاسازی شده‌ای را مصرف می‌کند که استاندارد آن را پروفایل PDF می‌نامد، جایی که هر جریان تصویر به جای یک جریان بیتی ساده، دنباله‌ای از سگمنت‌ها را در خود نگه می‌دارد. یک جریان اختیاری /JBIG2Globals، سگمنت‌های مشترک بین چندین تصویر در همان سند را حمل می‌کند، که مکانیزمی است که به محتوای تکراری اجازه می‌دهد به جای یک بار در هر صفحه، یک بار برای کل فایل ذخیره شود. کامپوننت HotPDF به طور پیش‌فرض جریان هر تصویر را ساطع می‌کند و کانال سراسری را آزاد نگه می‌دارد مگر اینکه یک بک‌اند آن را درخواست کند

معماری رمزگذار مبتنی بر بک‌اند

یک رمزگذار کامل JBIG2 نرم‌افزار بزرگی است و تهاجمی‌ترین بخش‌های آن از نظر تاریخی تحت فشار پتنت‌ها بوده و تحت لایسنس‌هایی عرضه شده‌اند که برای هر محصولی مناسب نیستند. ابزار HotPDF این تنش را با جدا کردن رابط از موتور برطرف می‌کند. یونیت HPDFJBIG2 فراخوانی‌هایی را تعریف می‌کند که بقیه کتابخانه انجام می‌دهند، و یک رمزگذار داخلی نسبتاً ساده ارائه می‌دهد تا JBIG2 بلافاصله کار کند. وقتی به نسبت‌های در سطح تولید نیاز دارید، یک موتور قوی‌تر را ثبت می‌کنید و کتابخانه کار را به آن محول می‌کند، بدون اینکه تغییری در کد فراخوانی شما ایجاد شود

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

uses
  HPDFJBIG2;

// Query what is active, then optionally install a stronger engine.
if not IsJBIG2EncoderBackendAvailable then
  // Production backend not present: HotPDF uses its built-in MMR path.
  RegisterJBIG2EncoderBackend(MyVendorJBIG2Encode);

// Later, to return to the built-in behaviour:
// ClearJBIG2Backends;

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

گزینه‌های رمزگذاری در واقع چه چیزی را مبادله می‌کنند

رمزگذاری از طریق TJBIG2EncodeOptions پیکربندی می‌شود، یک رکورد با فیلدهای Lossless، UseGlobalSegments، UseSymbolDictionary، و LossyLevel. پوشش سازگار با کامپوننت THPDFJBIG2Options فیلدهای Lossless، UseSymbolDictionary، و LossyLevel را منتشر می‌کند تا بتوان آنها را از Object Inspector تنظیم کرد، و در داخل، آن را به رکورد تبدیل می‌کند. سه هدف تنظیمات را هدایت می‌کنند

بازسازی بدون اتلاف (Lossless) هر پیکسلی را حفظ می‌کند. Lossless را روی True تنظیم کنید و LossyLevel را روی صفر بگذارید، و بیت‌مپ رمزگشایی شده بیت‌به‌بیت با ورودی یکسان است. این تنها انتخاب امن برای طراحی‌های خطی، نقشه‌های فنی، و هر صفحه‌ای است که حذف یک پیکسل می‌تواند معنی را تغییر دهد، مانند امضا یا مهر. کدگذاری دیکشنری-نماد، حذف موارد تکراری با آگاهی از متن را فعال می‌کند و گزینه‌ای است که JBIG2 را از فیلترهای فکس متمایز می‌کند. سطح اتلاف (lossy level)، عددی صحیح بین 0 تا 9، به یک بک‌اند توانمند اجازه می‌دهد تا با در نظر گرفتن علامت‌های تقریباً مشابه به عنوان یک نماد واحد، کیفیت را با اندازه مبادله کند. صفر به معنای بدون اتلاف است. رمزگذار داخلی فقط مسیر بدون اتلاف را رعایت می‌کند و هر سطح اتلاف غیر صفر را نادیده می‌گیرد، بنابراین سطوح بالاتر تنها زمانی اعمال می‌شوند که بک‌اندی که آنها را پیاده‌سازی می‌کند ثبت شده باشد

var
  Options: TJBIG2EncodeOptions;
begin
  Options := DefaultJBIG2EncodeOptions;   // Lossless True, symbol dictionary on
  Options.Lossless := True;
  Options.LossyLevel := 0;                // 0 keeps every pixel
  Options.UseSymbolDictionary := True;    // dedupe repeated glyphs
  // Pass Options to a backend, or let THPDFJBIG2Options carry them.
end;

دیکشنری‌های نماد و اینکه چرا اسکن‌های متنی برنده هستند

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

این دقیقاً همان جایی است که JBIG2 از CCITT Group 4 پیشی می‌گیرد. الگوریتم Group 4 هر خط اسکن را نسبت به خط بالای آن بدون هیچ درکی از گلیف کدگذاری می‌کند، بنابراین هزینه کامل هر حرف را هر بار که حرف ظاهر می‌شود می‌پردازد. الگوریتم JBIG2 این هزینه را یک بار می‌پردازد. هنگامی که همان دیکشنری به جریان سراسری در سطح سند ارتقا می‌یابد، صرفه‌جویی در یک اسکن چند‌صفحه‌ای ترکیب می‌شود، زیرا شکل‌هایی که صفحه به صفحه به اشتراک گذاشته می‌شوند یک بار برای کل فایل ذخیره می‌شوند. در متون متراکم این تفاوت حاشیه‌ای نیست. این دلیلی است که JBIG2 وجود دارد

ناحیه عمومی و MMR برای بقیه موارد

هر تصویر دوسطحی متن نیست. نقشه‌ها، شماتیک‌ها، نقشه‌های مهندسی، و صفحات ترکیبی دارای طراحی‌های خطی هستند که هیچ دیکشنری نمی‌تواند آن‌ها را خلاصه کند. برای آن‌ها، JBIG2 یک ناحیه عمومی (generic region) را کدگذاری می‌کند، یک مستطیل از پیکسل‌ها که مستقیماً بدون هیچ آموزش نمادی فشرده می‌شود. این استاندارد اجازه می‌دهد که یک ناحیه عمومی از MMR، روش کدگذاری modified modified READ که در حال حاضر در فکس Group 4 استفاده می‌شود، بهره ببرد، که هر ردیف پیکسل را در برابر ردیف بالایی آن مدل‌سازی می‌کند

این مسیری است که HotPDF در رمزگذار داخلی خود ارائه می‌دهد. وقتی هیچ بک‌اندی ثبت نشده است و درخواست به صورت بدون اتلاف (lossless) است، کتابخانه بیت‌مپ را به عنوان یک ناحیه عمومی MMR واحد فشرده می‌کند و آن را در ساختار سگمنت JBIG2 که پروفایل PDF به آن نیاز دارد، قرار می‌دهد. این کار به هیچ دیکشنری، هیچ مرحله آموزشی، و هیچ تصویر دومی برای ارجاع نیاز ندارد، بنابراین یک گزینه پیش‌فرض قابل اعتماد برای طراحی‌های خطی و محتوای ترکیبی دوسطحی است. این روش روی متن خالص به پای یک رمزگذار کامل دیکشنری‌نماد نمی‌رسد، اما همیشه درست، همیشه بدون اتلاف، و همیشه در دسترس است. سطح رمزگذار برای آن یک فراخوانی است

var
  Encoder: THPDFJBIG2Encoder;
  ImageData: TJBIG2ByteArray;
  Scanlines: TJBIG2ScanlineArray;  // one byte array per row, MSB-first
  W, H: Integer;
begin
  // Scanlines, W and H describe a 1-bit page; each row is (W + 7) div 8 bytes.
  Encoder := THPDFJBIG2Encoder.Create;
  try
    if Encoder.EncodeToByteArray(Scanlines, W, H, ImageData) then
      // ImageData now holds a JBIG2 stream ready for a /JBIG2Decode XObject.
      ;
  finally
    Encoder.Free;
  end;
end;

فعال کردن آن هنگام ساخت یک سند

برای استفاده‌های روزمره، شما مستقیماً کلاس رمزگذار را لمس نمی‌کنید. کامپوننت HotPDF، گزینه JBIG2 را به عنوان یک انتخاب برای فشرده‌سازی تصویر در سند قرار می‌دهد. نوع شمارشی THPDFImageCompressionType شامل icJBIG2 در کنار گزینه‌های Flate، JPEG و CCITT است، و سند دارای خاصیتی به نام JBIG2Options از نوع THPDFJBIG2Options است که تنظیمات استفاده شده در هنگام انتخاب آن فشرده‌سازی را نگه می‌دارد. هر دو را پیش از افزودن تصاویر دوسطحی که می‌خواهید به این روش فشرده شوند، پیکربندی کنید

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.ImageCompressionType := icJBIG2;     // route 1-bit images through JBIG2
    Pdf.JBIG2Options.Lossless := True;        // keep every pixel
    Pdf.JBIG2Options.UseSymbolDictionary := True;
    Pdf.JBIG2Options.LossyLevel := 0;
    // Add pages and place your scanned 1-bit images here.
  finally
    Pdf.Free;
  end;
end;

یکی از امکانات شایان ذکر، افزونه DBGridHotPDFExport است که یک TDBGrid را مستقیماً در یک PDF رندر می‌کند. خروجی آن عمدتاً خطوط و متن دوسطحی است، بنابراین سندی که برای JBIG2 پیکربندی شده باشد، این خروجی‌ها را بدون هیچ‌گونه پردازش اضافی از جانب شما فشرده نگه می‌دارد. دو موضوع مرتبط در این وبلاگ به عمق بیشتری از گردش کار پیرامون آن می‌پردازند. برای اینکه چگونه تصاویر و فونت‌ها هنگام ساخت گزارش‌ها قرار می‌گیرند، خروجی گزارش با فونت‌ها و تصاویر در دلفی را ببینید. هنگامی که یک سند فشرده باید مشخصات یک پروفایل آرشیوی را برآورده کند، قوانین در اعتبارسنجی PDF/A، PDF/X و PDF/UA در دلفی به شما می‌گویند که کدام فیلترها را یک سطح انطباق خاص می‌پذیرد. فرمت JBIG2 به عنوان بخشی از کامپوننت HotPDF برای دلفی و C++Builder، در کنار APIهای بارگذاری، ویرایش، و رمزگذاری که در جای دیگری از اینجا پوشش داده شده‌اند، ارائه می‌شود