Teknik Makale

EPS İçe Aktarma: gsave, Path ve ImageMask Farkları

Bir PDF sayfasına yerleştirilen bir EPS logo, konturu kaybolmuş olarak, tek renkli bir işaret kendi negatifi olarak basılmış olarak ya da Æ áya dönüşmüş olarak çıkabilir. Her belirti, PostScript ile PDF grafik semantiğinin ayrıştığı bir yeri işaretler; dolayısıyla Delphi için PDFlibPas EPS içe aktarımı PostScript programını yorumlar ve her farkı yerli PDF işleçleri olarak yazar

Programı yorumlamak ya da olduğu gibi geçirmek

PostScript bir PDFin içinde iki türlü oturabilir ve ikisinden yalnızca biri ekranda bir şey gösterir. ISO 32000-1 §8.8.2, bir PostScript XObjecti tanımlar: /Subtype /PS akışının baytları, yalnızca çıktı aygıtı bir PostScript yazıcıyken yorumlanmadan baskı işine kopyalanır; öteki her yerde etkisi yoktur ve §8.8 genel bakışı, PostScript XObjectlarının kullanılmaması gerektiğini söyler. PDF/A onları baştan dışlar. TPDFlib.NewPostScriptXObject ile DrawPostScriptXObject o geçiş biçimini yazar; ImportEPSFromFile ile DrawPostScript ise programı bir yorumlayıcıdan geçirir ve sıradan yollar, satır içi görüntüler ile metin çıkarır. Görselliği yorumlayıcıdan geçirin ve PS XObjecti, matbaa ya da üretim yazıcısının önündeki ızgara görüntü işleyici olan, tek bir baskı odası RIPine yöneltilmiş bir parçaya saklayın. EPS yorumlamak ayrıca EMF vektör içe aktarımından başka bir iştir; orada girdi, tekrar çalınacak GDI kayıtları listesidir. Bir EPS dosyası ise bir programdır

procedure AddPrintRoomHook(PDF: TPDFlib);
var
  PSRef: Integer;
begin
  // /Subtype /PS akışı olarak birebir saklanır ve Do ile başvurulur.
  // Yalnızca bir PostScript yazıcıda icra edilir; görüntüleyiciler hiçbir şey çizmez
  PSRef := PDF.NewPostScriptXObject(
    'userdict /PrintRoomMark known { PrintRoomMark } if');
  if PSRef <> 0 then
    PDF.DrawPostScriptXObject(PSRef);
end;
PostScript icra modeli ile PDFin ayrıldığı yerler ve satır satır bir işleç çevirisinin ürettiği sonuç
PostScript davranışıPDF davranışıBirebir çevirinin sonucu
gsave / grestore, geçerli yolu ile geçerli noktayı saklar ve geri yüklerq / Q yola dokunmaz ve boyama onu bitirir (§8.5.1)Bir kontur ya da grestore sonrası devam eden bir parça kaybolur
clip, geçerli yolu sonraki boyama için tutarWyi, yolu bitiren boyama işleci — genellikle n — izlerKlipten sonraki konturun çizecek bir şeyi yoktur
ImageMatrix, kullanıcı uzayını görüntü uzayına eşlerHer görüntü birim kareyi doldurur; ilk satır üstte (§8.9.4)Aşağıdan yukarı ya da döndürülmüş görüntüler ters ya da kaymış düşer
true imagemask 1 bitleri boyarVarsayılan Decode [0 1]li bir kalıp 0 bitleri boyar (§8.9.6.2)Tek renkli bir logo negatifi olarak basılır
Roman Standard-14 fontlar varsayılan olarak StandardEncoding kullanırStandardEncoding adının özel bir anlamı yoktur (§9.6.6.1)Aksanlar, tırnaklar ve ligatürler harfleri değiştirir
%%BoundingBox ile %%HiResBoundingBox yorumları görsel alanını tanımlarYerleşim, yazanın çıkardığı matris neyse odurGörsel, öngörülen kutusundan kayar ya da ölçek dışına taşar

grestoreden sonra kontur nereye gitti?

Kontur kayboldu; çünkü PDF yolu hiç saklamadı. ISO 32000-1 §8.5.1 bunu tek cümlede koyar: "PDF (PostScriptten farklı olarak), geçerli yol grafik durumunun parçası değildir" ve bir yol boyandıktan sonra m ya da re yeniden başlayana kadar geçerli bir yol yoktur. PostScript üreticileri ters kurala yaslanır. Dolgulu bir şekli konturla çizmenin alışılmış yolu gsave fill grestore stroketır: dolgu, saklanmış bir yol kopyasını tüketir, grestore yolu geri getirir ve kontur aynı geometriyi boyar. gsavei qya, filli fye ve grestorei Qya eşleyin; kontur boş bir yolla gelir ve şekil dolu, kontur gitmiş olur. grestoreden sonra geri yüklenen yolu devam ettiren bir lineto aynı şekilde düşer; eksik bir parça olarak

Delphi için PDFlibPas EPS içe aktarımında PostScript gsave fill grestore stroke ile birebir q f Q S çevirisini karşılaştıran zaman çizgisi
birebir q f Q eşlemesi yolu dolguda bitirir; PDFlibPas bu yüzden özel bir PostScript yolu tutar ve grestore sonrası kontur geometrisini hâlâ bulur
uses
  SysUtils, PDFlibrary;

const
  // Konturlu dolgulu üçgen: dolgu gsave/grestore içinde koşar,
  // grestore sonrası kontur geri yüklenen yolu yeniden kullanır
  TriangleEPS =
    '%!PS-Adobe-3.0 EPSF-3.0'#10 +
    '%%BoundingBox: 0 0 200 120'#10 +
    'newpath 20 20 moveto 180 20 lineto 100 100 lineto closepath'#10 +
    'gsave 0.85 setgray fill grestore'#10 +
    '3 setlinewidth 0 setgray stroke'#10;

var
  PDF: TPDFlib;
begin
  PDF := TPDFlib.Create;
  try
    PDF.SetOrigin(1);   // Left ile Top sol üst köşeden ölçülür
    // 0 olan Width ile Height, 200 x 120 sınırlayıcı kutu boyutunu korur
    if PDF.DrawPostScript(72, 72, 0, 0, TriangleEPS) = 1 then
      PDF.SaveToFile('triangle.pdf')
    else
      Writeln('DrawPostScript failed, code ', PDF.LastErrorCode);
    // Beklenen: 3 birimlik siyah konturlu, açık gri bir üçgen.
    // Birebir q/f/Q/S çevirisi üçgeni doldurur ve konturu düşürür
  finally
    PDF.Free;
  end;
end.

PDFlibPas kendi PostScript yolunu tutar; PDF içerik akışının o anda taşıdığından bağımsızdır ve PDF yolunu yalnızca bir şey boyadığında ya da kıptığında yazar. Her nokta, moveto ya da lineto koştuğu sırada geçerli olan dönüşüm matrisine sabitlenir; PostScriptteki gibi, sonradan bir scale ya da concat yolda duran noktaları asla oynatmaz. currentpoint, saklanan noktayı geçerli matris üzerinden geri eşler; dolayısıyla şimdiki kullanıcı uzayında cevap verir. Bir gsave, yol zincirinin sonuna bir başvuru artı geçerli nokta, matris, font ve renk uzayı kaydeder; dolayısıyla iç içe saklamalar bütün yolları asla kopyalamaz

Kırpma, iki yol modelinin yeniden ayrıldığı yerdir ve içe aktarım orada da PostScripti izler: clip ile eoclip, PDF tarafı için W n çıkarır ama sıkça gelen kontur için mantıksal yolu yerinde bırakır; PostScriptte taze boş bir yol açan rectclip ise re W n çıkarır ve yolu temizler. Yol saklama 100.000 düğüme kısıtlanır ve tekrar çalmalar, paylaşılan işlem bütçesinden çizilir; böylece düşmanca bir dosya çıktıyı şişirmek için gsave ile strokeu döngüye sokamaz

Görüntü yerleştirme: ImageMatrix öbür yöne işaret eder

Bir EPS görüntüsü, ImageMatrixi yerleştirme sayıldığında ters düşer; çünkü o, ters yönlü eşlemeyi tanımlar. PDFte §8.9.4, görüntü sınırını kullanıcı uzayının birim karesine, üst örnek satırı üstte olacak şekilde bağlar: örtük görüntüden kullanıcıya matrisi [1/w 0 0 -1/h 0 1]dir. PostScriptin ImageMatrixi kullanıcı uzayını görüntü uzayına eşler. PDF yerleştirme matrisi bu yüzden [w 0 0 -h 0 h] ile ImageMatrixin tersinin çarpımıdır. Alışılmış yukarıdan aşağı matris [w 0 0 -h 0 h] için çarpım birimdir. Naif dönüştürücülerin gündelik kullanımda doğru görünmesinin nedeni budur. [w 0 0 h 0 0]le yazılmış bir aşağıdan yukarı tarama, birim karenin içinde dikey bir ters çevirme olan [1 0 0 -1 0 1]i verir; döndürülmüş ya da eğik matrisler özel durum istemez. Sonlu bir veri kaynağı erken bittiğinde PDFlibPas yalnızca tamamlanmış satırları boyar, özgün ImageMatrixi korur ve gerçekten gelen satırlara göre ölçekler; böylece kesilmiş bir görüntü, doğru ölçekte kendi alanının üst bandını doldurur. Kalan satırları bütün yüksekliğe germek, sağlam görünen bozuk bir resim üretirdi

Delphide PDFlibPas EPS içe aktarımı için PostScript ImageMatrix kuralından PDF yerleştirme matrisini çıkaran şema: dik ve ters sonuçlar ile kesilmiş satır el yazısıyla
yerleştirme matrisi, PDF birim kare eşlemesinin ters ImageMatrixle çarpımıdır; yukarıdan aşağı görsel dik düşer ve yalnızca aşağıdan yukarı taramalar ters döner

imagemask hangi biti boyar?

truei polarity işleneni olarak alan imagemask, 1 bitleri boyar ve PDFte bu Decode [1 0]dur. ISO 32000-1 §8.9.6.2, [0 1]yi bir görüntü maskesi için varsayılan tanımlar: 0 örneği sayfayı geçerli renkle damgalar, 1 arka plana dokunmaz; [1 0] bunu tersine çevirir. PostScript booleanı hangi örnek değerinin boyayacağını söyler. Onu PDF varsayılanını tersine çevir diye okuyun ve logo negatifi olarak basılır: işaretin oyulduğu dolu bir blok. PDFlibPas trueyu [1 0]a, falseu [0 1]e eşler, kalıbı programın kurduğu hangi renkse onunla boyansın diye /IM trueli bir satır içi görüntü olarak çıkarır ve sözlük biçiminde yalnızca o iki Decode dizisini kabul eder

Delphi için PDFlibPas EPS içe aktarımında PostScript imagemask polaritysinin PDF Decode dizilerine eşlenmesi: true 1 bitleri boyar, false negatifi basar
PostScript booleanı boyayan örnek değerini adlandırır; trueyu Decode [1 0]a eşlemek, tek renkli bir logonun negatifi olarak basılmasını önler

On iki bitli örnekler daha küçük bir uyuşmazlık saklar. PDFin 12 bitli görüntüsü yoktur; §8.9.5.1, bileşen başına 1, 2, 4, 8 ve PDF 1.5ten itibaren 16 bite izin verir. Her örneği dört bit sola kaydırmak onu hiçbir şey kaybetmeden 16 bite sokar; ama en büyük değer 65535 değil 65520 olur ve varsayılan Decodele her parlak örnek yaklaşık 0.023 yüzde fazla koyu çıkar. İçe aktarım kaydırmayı korur ve üst Decode uçunu 65535/65520 ile gerer; bu, bütün normalize edilmiş değerleri geri getirir. 12 bitli bir görüntü, çıktı sürümünü kendiliğinden PDF 1.5e yükseltir; PDF/A ya da PDF/X modunda ya da çıktı sürümü 1.5in altında kilitliyken içe aktarım, sayfa değişmeden 538 hatasıyla durur

Æ neden á olarak çıkar?

PostScriptte bir Roman font, program yeniden kodlamadıkça StandardEncoding kullanır ve PDF o tabloyu adlandıramaz: ISO 32000-1 §9.6.6.1 adına özel bir anlam vermez ve önceden tanımlı seçenekler olarak WinAnsiEncoding, MacRomanEncoding ile MacExpertEncodingi bırakır. Ek D.2 tabloları, kodlar WinAnsiye değiştirilmediğinde neler bozulduğunu gösterir: sekizlik 341 (0xE1), StandardEncodingte AE, WinAnside ise aacutedur; dolayısıyla Æ á olur. 0xAE birinde fi ligatürü, ötekinde ®dir. 0x27, StandardEncodingte quoteright, WinAnside düz bir quotesingledir; bu, tipografik kesme işaretlerini daktilo kesmelerine çevirir. Bir programın kullandığı her Standard-14 Roman font için PDFlibPas, /Encoding sözlüğü /BaseEncoding /WinAnsiEncoding ve StandardEncoding sırasında bütün 256 kodu adlandıran bir /Differences dizisi taşıyan özel bir Type 1 font kaynağı yazar; böylece hiçbir kod, görüntüleyicinin taban tabloyu nasıl doldurduğuna bağlanmaz. Genişlikler aynı encodingden gelir, bir ToUnicode haritası kopya ile aramanın Æ döndürmesini sağlar ve Symbol ile ZapfDingbats gömülü kodlarını korur. Kodunuzun içe aktarımdan önce seçtiği fonta dokunulmaz; çünkü önbellekteki bir fontu EPSe uydurmak için yeniden kodlamak, onunla zaten yerleştirilmiş metni de değiştirirdi

O kaynaklar fontları gömmeden adlandırır; bu, gömmeyi gerektiren profillerle çatışır. PDF/A, PDF/X ya da PDF/UA için kurulmuş bir belgede ya da SetEmbedAllFonts(1)den sonra EPS metni 538 hatasıyla düşer ve sayfa eski hâlinde kalır. Arşiv çıktısı için daha temiz yol, metni dış hatlara dönüştürülmüş olarak dışa aktarılmış bir EPSdir; herhangi bir modda düz yollar olarak içe girer. Mevcut bir dosyada gömülmemiş bırakılmış fontlar ise bunun yerine PDF/A için eksik fontları gömmeye ihtiyaç duyar. EPS metni, 14 standart fonta tam adlarıyla oturur; kendi font programını gömen görsellik, metni dış hatlara çevrildikten sonra temiz girer — bu, yerel bir yedek fontun her satırı oynatmasını da engeller

Sınırlayıcı kutular, DSC yorumları ve ikili EPS dosyaları

Yerleşim, görselin sınırlayıcı kutusunu geçtiğiniz dikdörtgene ölçekler; dolayısıyla kutunun doğru yerden gelmesi gerekir. PDFlibPas %%BoundingBox ile %%HiResBoundingBoxi yalnızca gerçek DSC yorum satırlarından — yani satır başlayan üst düzey yorumlardan — okur ve geçerli yüksek çözünürlüklü kutu, tam sayı olanı yener. Düz bir alt dizge araması o anahtarları birebir dizgelerin içinde, yordam gövdelerinde ve ikili görüntü verisinde de bulur. EPS dosyaları üçünü birden taşır. (atend) değerli bir başlık, sayıları trailerdaki bir yoruma erteleyerek tarayıcı oraya ulaştığında okur. Hiç kutusu olmayan bir dosya 612 ile 792ye düşer; boş ya da ters çevrilmiş bir kutu 124 hatasıyla düşer. Width ile Height, kutuyu bağımsız ölçekler: doğal boyutu korumak için ikisine de 0 geçirin ya da ikisini kutunun en boy oranında geçirin; sıfırdan farklı tek bir değer görseli tek eksende gerer

İkili veri giriş noktasına karar verir. DrawPostScript bir WideString alır; kodla kurulan PostScript için sorun yoktur. Ama ham görüntü örnekleri, currentfile üzerinden okunan Flate verisi ve DOS EPS sarmalayıcısı, Unicode metinden geçemeyen baytlar içerir. ImportEPSFromFile dosyayı ham baytlar olarak okur, C5 D0 D3 C6 önizleme başlığını tanır, PostScript bölümünün offset ile uzunluğunun dosyanın içinde kaldığını denetler ve yalnızca o bölümü icra eder; TIFF ya da WMF önizlemesini yok sayar. İki çağrı da en fazla 4 MiB kaynak alır, Options = 0 ister, 1 ya da 0 döndürür ve ya bütün çizimi ya da hiçbir şeyi ekler. Hata nedeni, okunduğunda sıfırlanan LastErrorCodetedir; bir kez yakalayın

uses
  SysUtils, PDFlibrary;

function PlaceEPS(PDF: TPDFlib; const FileName: string;
  Left, Top: Double): Boolean;
var
  Code: Integer;
begin
  // 0, 0: doğal boyut (%%HiResBoundingBox ya da %%BoundingBox)
  Result := PDF.ImportEPSFromFile(Left, Top, 0, 0, FileName) = 1;
  if Result then
    Exit;
  Code := PDF.LastErrorCode;   // okumak kodu sıfırlar, o yüzden bir kez okuyun
  case Code of
    402:
      Writeln(FileName, ': file cannot be opened');
    PDFLIB_ERROR_POSTSCRIPT_INVALID:      // 124
      Writeln(FileName, ': malformed PostScript, bad bounding box or nothing painted');
    PDFLIB_ERROR_POSTSCRIPT_UNSUPPORTED:  // 538
      Writeln(FileName, ': construct the import does not handle, or Standard-14 text in an archival profile');
    PDFLIB_ERROR_POSTSCRIPT_BUDGET:       // 539
      Writeln(FileName, ': source over 4 MiB or a work limit reached');
  else
    Writeln(FileName, ': import failed with code ', Code);
  end;
end;

var
  PDF: TPDFlib;
begin
  PDF := TPDFlib.Create;
  try
    PDF.SetOrigin(1);
    if PlaceEPS(PDF, 'logo.eps', 40, 40) then
      PDF.SaveToFile('letterhead.pdf');
  finally
    PDF.Free;
  end;
end.

538 hatası bir işleç adlandırdığında görselliği editöründen, metni dış hatlara çevrilmiş düz bir EPS olarak yeniden dışa aktarın; genellikle işleci kovalamaktan hızlıdır ve dış hatlara çevrilmiş görsellik, PDFlibPas Delphi PDF Library ile kurulmuş bir PDF/A ya da PDF/UA belgesine de Standard-14 font çatışması olmadan girer