Teknik Makale

Delphi'de Mixed Raster Content: Taranan PDF, JPEG + CCITT

losLab PDF Library for Delphi, taranmış bir sayfayı TPDFlib.CompressPageAsMRC ile Mixed Raster Content kullanarak sıkıştırır. Metot sayfayı render eder, tam çözünürlüklü 1 bitlik bir ön plan maskesini eşikler, gerisini bir JPEG arka plana küçültür ve sayfayı iki görüntü olarak yeniden kurar: bir /DCTDecode arka plan ile geçerli dolgu renginde boyanan bir /CCITTFaxDecode stencil maskesi

Bu yöntemin varlık sebebi, her belge arşivinin bolca bulduğu sayfadır: fatura ya da sözleşmenin 300 DPI renkli taraması, tek bir büyük JPEG olarak saklanmış. Metni okunur tutan bir kaliteyle kodlarsanız dosya büyür; kaliteyi düşürürseniz harflerde haleler ve dağılmış serifler belirir, çünkü JPEG'in en kötü yaptığı iş beyaz kağıt üzerindeki keskin siyah kenardır. Mixed Raster Content ise tek kodekten iki iş yapmasını istemeyi bırakır

Tek JPEG, taranan metni neden hem bulanık hem büyük yapar?

Tek bir JPEG taranan metni kötü işler, çünkü DCT kodeği bitlerini yumuşak gradyanlara harcar ve keskin kenarları, nicemlemenin ilk attığı yüksek frekanslı katsayılarla yaklaşıklaştırır. Taramadaki metin neredeyse baştan sona keskin kenardır. O kenarları temiz tutmak, kağıt dokusuna, logoya ve kahve lekesine kadar tüm sayfada yüksek kalite ayarı dayatır; hiçbirinin buna ihtiyacı yokken

MRC fikri sayfayı, her bölgenin gerçekte ne olduğuna göre ikiye ayırır. Mürekkep, ikili düzeyli (bilevel) bir görüntüye dönüşür; CCITT gibi bir faks kodeği burada siyah ve beyaz piksel dizilerini kayıpsız ve son derece kompakt biçimde kaydeder. Geri kalan her şey — kağıt tonu, fotoğraflar, renkli arka planlar — sürekli tonlu bir görüntüye dönüşür ve çözünürlüğün çok küçük bir kesriyle saklanabilir; çünkü kimse arka planı 300 DPI ile okumaz. İkili düzeyli katman metni tam çözünürlükte net tutar; arka plan katmanı rengi düşük maliyetle tutar

Tek JPEG tarama ile PDFlibPas CompressPageAsMRC'nin Delphi içinde oluşturduğu Mixed Raster Content katman ayrımı: DCT kodeği keskin metin kenarlarını dağıtır ve tüm sayfada yüksek kaliteyi dayatır; buna karşılık mürekkep, 300 DPI'da kayıpsız bir 1 bitlik CCITT stenciline, kağıt tonu ise 75 DPI'lık bir DeviceRGB JPEG arka plana dönüşür
Mixed Raster Content tek kodekten iki iş yapmasını istemeyi bırakır: ikili düzeyli katman harfleri tam çözünürlükte net tutar, arka plan rengi maliyetin çok küçük bir kesriyle tutar; bu yüzden 50-70 arası kalite genellikle fark edilmez

CompressPageAsMRC bir sayfayı iki katmana nasıl böler?

TPDFlib.CompressPageAsMRC sayfa başına tek bir sabit işlem hattı çalıştırır. Sayfayı istenen DPI'da 24 bitlik bir bit eşlemeye render eder, her pikseli Rec. 601 ağırlıklı parlaklıkla (binde 299/587/114) Threshold değerine karşı sınıflandırır ve sonucu aynı çözünürlükte bir 1 bitlik maskeye yazar. Aynı anda aynı render'ı BGScale ile kutu ortalaması kullanarak küçültür; BGScale 4 iken her 4×4 piksel bloğu tek bir arka plan pikseline dönüşür

PDFlibPas'ta Delphi için CompressPageAsMRC veri akışı: tek bir 300 DPI 24 bitlik render, Rec. 601 parlaklığıyla eşiklenerek tam çözünürlüklü bir CCITTFaxDecode K 1 ImageMask stenciline dönüşür; BGScale 4 ile kutu ortalaması alınarak DCTDecode DeviceRGB arka plan olur ve her iki görüntü, maske üstte olacak şekilde özgün sayfa operatörlerinin yerini alır
İki katman da tek bir render'dan türetilir: DPI, eşiği geçebilecek en ince çizgiyi belirler; BGScale, fotoğraflar için 2'den düz metin için 8'e kadar arka plan ayrıntısıyla yer değiştirir ve yeniden kurulan sayfa stencil'ini geçerli dolgu renginde çizer

Sonra sayfa içeriğinin yerini yenisi alır. Özgün operatörler kaldırılır; küçültülen arka plan, /DeviceRGB içinde bir /DCTDecode görüntüsü olarak gömülür (ISO 32000-1 §7.4.8); maske, kütüphanenin CCITT kodlayıcısıyla bir /CCITTFaxDecode görüntüsü olarak kodlanır (§7.4.6) ve /ImageMask true olarak işaretlenir; ikisi de maske üstte olacak şekilde sayfa kutusunun tamamına çizilir. İmzası kısadır:

function CompressPageAsMRC(Page: Integer; DPI: Double;
  BGScale, JPEGQuality, Threshold, Options: Integer): Integer;
  • Page 1 tabanlıdır ve PageCount içinde olmalıdır
  • DPI, kaynak rasterin render çözünürlüğüdür; 50-1200
  • BGScale, arka plan küçültme katsayısıdır; 1-8
  • JPEGQuality, arka plan JPEG kalitesidir; 1-100
  • Threshold, parlaklık eşiğidir; 1-255. Bu değerin üzerindeki pikseller kağıt, daha koyu pikseller mürekkeptir
  • Options rezerve edilmiştir ve 0 olmalıdır

Taranmış bir dosya üzerinden geçen tipik bir toplu iş şuna benzer. SetFillColor çağrısını her sayfanın hemen önünde yapın; nedenini sonraki bölüm açıklıyor

uses
  SysUtils, PDFlibrary;

procedure CompressScannedFile(const SrcFile, DstFile: string);
var
  Lib: TPDFlib;
  P, Replaced: Integer;
begin
  Lib := TPDFlib.Create;
  try
    if Lib.LoadFromFile(SrcFile, '') <> 1 then
      raise Exception.CreateFmt('Cannot open %s', [SrcFile]);
    for P := 1 to Lib.PageCount do
    begin
      Lib.SetFillColor(0, 0, 0);  // stencil katmanının mürekkep rengi
      // 300 DPI maske, 75 DPI arka plan, JPEG kalitesi 60, luma 160'ta kesim
      Replaced := Lib.CompressPageAsMRC(P, 300, 4, 60, 160, 0);
      if Replaced = 0 then
        raise Exception.CreateFmt('MRC failed on page %d', [P]);
    end;
    if Lib.SaveToFile(DstFile) <> 1 then
      raise Exception.CreateFmt('Cannot save %s', [DstFile]);
  finally
    Lib.Free;
  end;
end;

Ön plan neden geçerli dolgu renginde boyanır?

Ön plan katmanı bir stencil maskesidir ve stencil maskesinin kendine ait rengi yoktur. ISO 32000-1 §8.9.6.2, /ImageMask true bayraklı bir görüntüyü 1 bitlik bir şekil olarak tanımlar: örnek değerler boyanın nereye gideceğini işaretler ve boya, grafik durumunda geçerli olan nonstroking renktir. Katmanı ucuz yapan tam olarak budur; CompressPageAsMRC'in renk parametresi almamasının nedeni de bu

TPDFlib.CompressPageAsMRC, maskesini SetFillColor ile ayarlanan renge boyar; bu yüzden çağrı sırası önemlidir. Boyacı, dolgu rengini tembel (lazy) biçimde yayar: SetFillColor rengi kaydeder ve değişmiş olarak işaretler, stencil çizimi ise rg operatörünü kendi q/Q bloğunun içinde yalnızca o değişiklik hâlâ bekliyorken yazar. Araya dolgulu bir şekil çizerseniz bekleyen değişikliği o şekil tüketir. Yukarıdaki toplu işte olduğu gibi rengi her sayfadan hemen önce ayarlamak tüm tahmin işini ortadan kaldırır. Normal seçim siyahtır; çıktının fotokopiye daha az benzemesini istediğiniz mavi mürekkepli formlarda koyu lacivert iş görür

Delphi'de PDFlibPas MRC stencil katmanı için tembel dolgu rengi yayma dizisi: SetFillColor rengi bekleyen bir değişiklik olarak kaydeder; ImageMask stencil çizimi, değişiklik hâlâ bekliyorken rg operatörünü kendi q ve Q bloğunun içine yazar; araya giren dolgulu bir şekil ise bekleyen değişikliği onun yerine tüketir
Bir stencil maskesi renge sahip değildir; her mürekkep pikseli tek bir dolgu rengi alır: kırmızı bir kaşe, mavi bir imza ve siyah metin tek renkte birleşir; SetFillColor'ın her sayfadan hemen önce çağrılmasının nedeni budur
// Mavi tükenmez kalem formu: mürekkep katmanını koyu lacivertte render et
Lib.SetFillColor(0.08, 0.12, 0.35);
Replaced := Lib.CompressPageAsMRC(PageNo, 300, 4, 55, 170, 0);

Yerleşim, kütüphanenin koordinat başlangıcını izler. CompressPageAsMRC, GetOrigin değerini okur ve her iki görüntüyü sayfa kutusunun üst kenarından çizer: başlangıç sol üstteyken (SetOrigin(1)) üst koordinat 0, varsayılan sol alt başlangıçta üst koordinat PageHeight olur. Ayarlamanız gereken bir şey yoktur; ancak bu, hattınızın hangi başlangıcı kullanıyor olduğuna bakılmaksızın katmanların neden doğru yere oturduğunu açıklar

Stencil anlambilminin bir sonucunu açıkça söylemekte yarar var: mürekkep olarak sınıflanan her piksel aynı rengi alır. Kırmızı bir kaşe, mavi bir imza ve siyah gövde metni, ön plan katmanında tek bir dolgu renginde buluşur. Özgün renklerin soluk, düşük çözünürlüklü izini altta yalnızca arka plan JPEG'i taşır

DPI, BGScale, Threshold ve JPEG kalitesi seçimi

DPI değeri metnin keskinliğini belirler; ofis taramaları için makul varsayılan 300'dür. Maske tam render çözünürlüğünde tutulur, dolayısıyla DPI, eşiği geçebilecek çizgi inceliğini belirler. Özgün tarama çözünürlüğünün üzerine çıkmak hiçbir şey kazandırmaz; renderer gömülü tarama görüntüsünü yalnızca büyütür. Öteki sınır bellektir: US Letter bir sayfa 300 DPI'da 2550×3300 piksele, yani maske ile arka plan türetilmeden önce 24 bitlik piksel verisi olarak 25,245,000 bayta render edilir; aynı sayfa 1200 DPI tavanında 10200×13200 piksel olur ve kabaca 404 MB bellek ister

BGScale, arka plan ayrıntısını boyutla takas eder. 300 DPI'da 4 katsayısı 75 DPI'lık bir arka plan verir; Letter için 638×825 piksel olur ve kağıt tonu ile düz renk alanları için fazlasıyla yeter. Okuyucunun gerçekten bakacağı fotoğraflı ya da taramalı (halftone) çizimli sayfalar 2'yi hak eder; beyaz kağıt üzerindeki düz metin 6 ya da 8 kaldırır, çünkü arka plan orada bir renk tonundan öteye geçmez

Threshold, sayfanın görünümünü değiştiren parametredir. Yükseltmek daha çok orta gri pikseli mürekkep olarak sınıflandırır; bu, ince çizgileri ve kurşun kalem izlerini kalınlaştırır ama tarayıcı gürültüsünü ve kağıt gölgesini de leke olarak içeri alır. Düşürmek daha temiz bir kağıt ve daha ince, yer yer kopuk harfler verir. Beyaz üzerinde siyah metin için 128-170 civarı makul bir başlangıç aralığıdır; iki taraf arasındaki takas, aynı parlaklık eşiğinin RenderPageToMonochromeFileEx yöntemini sürdüğü Delphi'de PDF sayfalarını 1 bitlik monokroma render etme makalesinde ele alınanın aynısıdır. O yöntemin aksine CompressPageAsMRC'in despeckle aşaması yoktur; gürültülü taramalar bu yüzden biraz daha düşük bir eşikle daha iyi sonuç verir

JPEGQuality, tek görüntülük taramada olduğundan daha az önemlidir; çünkü arka plan artık hiçbir metin kenarı taşımaz. 50-70 arası kalite, keskin bir maskenin arkasındaki 75 DPI'lık arka planda genellikle fark edilmez

Dönüş değeri size neyi söyler, neyi söylemez?

TPDFlib.CompressPageAsMRC, değiştirdiği sayfa içeriğinin bayt cinsinden boyutunu döndürür; bir şey ters gittiğinde 0 döner. Bu bir başarı göstergesidir, kazanım ölçüsü değildir. Tipik bir taranmış sayfada özgün içerik akışı birkaç düzine bayttır; tek bir görüntüyü yerleştirmeye yetecek kadar operatör. Bu yüzden sayfa megabaytlarca küçülse bile küçük bir pozitif sayı normal sonuçtur. Özgün içerik akışı boş olan bir sayfa, yeniden kurulmuş olsa da 0 raporlar

Hata davranışı atomik değildir ve tasarımı buna göre kurmanız gereken kısım tam da budur. Argüman kontrolleri, render ve JPEG kodlaması sayfaya dokunulmadan önce çalışır; bu yüzden aralık dışı bir BGScale, 101 olan bir JPEGQuality ya da bir render hatası sayfayı olduğu gibi bırakır. Özgün içerik temizlendikten sonra ise katmanlardan birini gömme ya da çizme başarısızlığı da 0 döndürür ve o noktada sayfa çoktan kısmen yeniden kurulmuş olabilir. Bellekteki belgeyi kaydetmek yerine atmaya bir 0'ı gerekçe yapın ve sonucu asla kaynak dosyanın üzerine yazmayın

Dönüşümün gerçekte ne kazandırdığını görmek için belgeyi ölçün. Öncesinde ve sonrasında SaveToString uzunluğunu karşılaştırmak en hızlı kontroldür; kategori bazında yanıt için AuditDocumentSpace ile PDF dosya boyutu denetimi, ağırlığın görüntülerden beklendiği gibi çıkıp çıkmadığını gösterir

function MRCSavings(Lib: TPDFlib): Int64;
var
  Before: Int64;
  P: Integer;
begin
  Before := Length(Lib.SaveToString);
  for P := 1 to Lib.PageCount do
  begin
    Lib.SetFillColor(0, 0, 0);
    if Lib.CompressPageAsMRC(P, 300, 4, 60, 160, 0) = 0 then
      raise Exception.CreateFmt('Page %d failed; discard this document', [P]);
  end;
  Result := Before - Length(Lib.SaveToString);
end;

Bu iki katmanlı MRC'nin ITU-T T.44'ün gerisinde kaldığı yer

CompressPageAsMRC bilinçli olarak sadeleştirilmiş bir MRC uygular. ITU-T T.44'teki tam model şerit başına üç katman kullanır: bir arka plan görüntüsü, mürekkep renklerini taşıyan bir ön plan görüntüsü ve ikisi arasında piksel piksel seçim yapan bir ikili düzeyli maske; tek sayfada birden çok maske ve ön plan çiftine yer vardır. PDF terimleriyle üçüncü katman, tek renkte boyanan bir stencil yerine açık bir maskeli (§8.9.6.3) düşük çözünürlüklü renkli bir ön plan görüntüsü olurdu. PDF Library for Delphi ön plan renk katmanını atlar; sonucu bu kadar küçük yapan da budur, renkli mürekkebin dolgu rengine dönüşmesinin nedeni de

  • Yöntem, taranmış kağıt üzerindeki siyah ya da tek renkli metne uygundur; renk kodlu belgeler, vurgulanmış metinler ve renkli kaşeler mürekkep renklerini kaybeder
  • Yeniden kurulan sayfa tamamen raster'dır: özgün sayfadaki gerçek metin, vektör çizim ya da seçilebilir karakterler piksele dönüşür. Bu yüzden bunu doğal dijital sayfalarda değil taramalarda çalıştırın; oralarda doğru araçlar yazı tipi alt kümeleme (subsetting) ve görüntü küçültmedir
  • Maske, kütüphanenin CCITT kodlayıcısını T.4 iki boyutlu modda kullanır; /K 1 ile /CCITTFaxDecode olarak yazılır. Kodlayıcının AddImageCCITTFromBitmapStream üzerinden bir Group 4 modu da vardır ama CompressPageAsMRC onu açmaz ve JBIG2 kullanmaz
  • Açıklamalar ve form alanları düzleştirilmez; yeniden kurulan içeriğin üzerinde nesne olarak kalırlar
  • Arka plan /DeviceRGB'dir, bu yüzden çıktı PDF/X-1a iş akışlarına uygun değildir; SetFillColor da PDF/X-1a modunda reddedilir
  • Zaten OCR gerektiren bir tarama, özgün pikseller tam renk derinliğiyle hâlâ varken MRC'den önce tanınmalıdır

SSS

CompressPageAsMRC metni aranır tutar mı?

Hayır. CompressPageAsMRC sayfa içeriğini iki görüntüyle değiştirir; özgün sayfadaki tüm metin operatörleri, görünmez bir OCR metin katmanı dahil, onunla birlikte kaldırılır. Sıkıştırmadan sonra sıkıştırılmış sayfada OCR çalıştırın ya da metin katmanını sıkıştırmadan sonra geri ekleyin

Bir belgenin yalnızca bazı sayfalarını sıkıştırabilir miyim?

Evet. CompressPageAsMRC çağrı başına 1 tabanlı tek bir sayfada çalışır; sayfaları siz seçersiniz ve BGScale ile Threshold'u sayfa başına bile değiştirebilirsiniz; örneğin katsayıyı fotoğraf eki olan sayfa için 2, düz metin sayfaları için 6 yapabilirsiniz

Options parametresi ne olmalı?

0 iletin. Options geçerli sürümde gelecekteki kullanım için rezerve edilmiştir ve hiçbir bit tanımlı değildir; sıfırdan farklı bir değer bugün hiçbir anlam taşımaz

CompressPageAsMRC, losLab PDF Library for Delphi v3.561.0 ile birlikte geldi; kendi bünyesinde kurulu olduğu render, JPEG, CCITT ve stencil maske yapı taşları da hattın bir varyantına ihtiyaç duyarsanız her biri genel metot olarak kullanılabilir. Kütüphane, C++Builder desteği ve tam API başvurusu PDF Library for Delphi ürün sayfasında