Technical Article

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

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

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

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

استاندارد ISO 32000-1 JBIG2Decode را در میان فیلترهای استریم در بخش ۷.۴.۷ فهرست می‌کند که از PDF 1.4 به بعد در دسترس است. این تنها در یک جا اعمال می‌شود: در image XObjectها که /BitsPerComponent آن‌ها ۱ است و فضای رنگی آن‌ها به یک کانال واحد ختم می‌شود. نکته اصلی همین است. 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)، که یک عدد صحیح از 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 یک منطقه عمومی را کدگذاری می‌کند، مستطیلی از پیکسل‌ها که به طور مستقیم بدون هیچ آموزش نمادی فشرده شده‌اند. این استاندارد اجازه می‌دهد تا یک منطقه عمومی از 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های بارگذاری، ویرایش و رمزنگاری که در جاهای دیگر این وبلاگ پوشش داده شده‌اند، ارائه می‌شود