Teknik Makale

PDFlibPas ile Free Pascal'da EMF Vektör İçe Aktarımı

PDFlibPas, enhanced metafile kayıtlarını gerçek PDF sayfa içeriğine rasterleştirmek yerine kayıt kayıt dönüştürür; içe aktarılan bir grafiği ya da CAD çizimini her yakınlaştırmada net tutan da budur. O dönüştürücü yaklaşık 6500 satırdır ve VCL hedefine göre yazılmıştı; dolayısıyla kitaplık bir Free Pascal hedefi kazandığında taşınamaz olarak sınıflandırıldı ve bir stub ile değiştirildi. O sınıflandırma yanlıştı ve yanlış olması, bir bağımlılığın çevresinde yeniden yazmaya karar vermeden önce nasıl denetleneceğine dair faydalı bir derstir

O 6500 satırın gerçek VCL yüzeyi küçük çıktı: piksel biçimi, akış kaydetme, tanıtıcı, canvas ve tarama satırları için kullanılan bir bitmap sınıfı; genişlik, yükseklik ve tanıtıcısı için kullanılan bir metafile sınıfı; ve iki sabitle renk türü. Bunların her biri, kitaplığın kendi grafik birimi tarafından zaten sağlanıyordu; o birim tam olarak non-VCL derlemenin eşdeğerlere sahip olması için vardır. Dönüştürücü hiç VCL tarafından engellenmemişti. Engellenmişti, Free Pascal Windows birimi tarafından

Kodun gerçekten bağımlı olduğu eksen boyunca böl

Dolayısıyla değişiklik bir yeniden uygulama değildi. Tek bir koşulluydu: "VCL olmadan derlendiğinde stubu derle" ifadesinden "Windows için derlenmediğinde stubu derle" ifadesine. Doğru eksen budur ve nedenini söylemek farkı açık hâle getirir. Enhanced metafile bir Windows kapsayıcıdır. Dönüştürücü, baştan sona Windows GDI kayıtları için bir ayrıştırıcıdır. Ana uygulamanın VCL kullanması, başka bir widget kümesi kullanması ya da hiç kullanmaması, o kayıtların yorumlanıp yorumlanamayacağıyla hiçbir ilgisi yoktur; hedefin Windows olması ise her şeyle ilgilidir

Doğru ekseni seçmenin sonuçları bedavaya gelir. Bu kitaplıkta Windows platform sembolünü tanımsız yapan C++Builder derlemeleri, atan stubu tutar ve tam olarak önceki gibi davranır. macOS stubu doğru biçimde tutar, çünkü orada ayrıştırılacak GDI kaydı yoktur. Delphi VCL derlemeleri dokunulmazdır. Ve non-VCL bir widget kümesiyle Windows derlemesi, kimsenin uygulaması gerekmeyen bir yan etki olarak vektör EMF içe aktarımı kazanır. Gerçek bağımlılıkla hizalanmış bir koşullu, platform işini tek satırlık bir değişikliğe çevirir; yanlış olanla hizalanmış koşullu ise onu hiçbir zaman programa girmeyecek bir yeniden yazıma çevirir

EMF içe aktarım koşullunun VCL üyeliğinden Windows platformuna yeniden eksenlenmesi; stubların başka yerde tutulması ve non-VCL Windows derlemelerine vektör içe aktarım kazandırılması
Stub koşulunu Windows platformuna yeniden eksenlemek, tüm mevcut derleme davranışlarını korur ve non-VCL Windows hedeflerine EMF vektör içe aktarımını bedavaya verir

Free Pascal boşluğu bildirimlerdi, mantık değil

Gerçekte eksik olan, Delphi Windows biriminin sağladığı ve Free Pascal biriminin sağlamadığı Win32 bildirimleriydi. Bunları koşulluları dönüştürücüye dağıtmak yerine tek bir uyumluluk biriminde toplamak, ayrıştırıcıyı okunabilir tuttu. Liste öğreticidir, çünkü iki RTL arasındaki başlık kapsamının ne kadar dengesiz olduğunu gösterir: 113 metafile kayıt türü sabiti, iki extended metin çıkışı bayrağı, üç gradyan doldurma modu sabiti, bir tanıtıcı tablosu işaretçi türü, gradyan vertex ve primitive kayıtları için takma adlar ve Free Pascal'ın hiç bildirmediği, alpha blending, saydam blitting ve renk yönetimi modunu kapsayan üç kayıt türü

Bunların hiçbiri tek tek ilginç değildir. Ama hepsinin, ayrıştırıcı derlenmeden önce doğru olması gerekir ve uyumluluk birimi doğal yuvadır, çünkü başlık belgelendirmesine karşı bir birim olarak diff alınabilir

Free Pascal Windows biriminde eksik olan ve EMF den PDF vektör dönüştürücüsü için tek bir uyumluluk biriminde toplanan Win32 bildirimleri
Kayıt sabitleri, bayraklar, takma adlar ve üç eksik kayıt türünün tamamı, başlık belgelendirmesine karşı diff alınabilen tek bir uyumluluk biriminde yaşar

Sessizce yanlış resmi çizen bildirim

O bildirimlerden ikisi yalnızca eksik değildir; mevcutturlar ve bu amaç için yanlıştırlar, üstelik hiçbir zaman bir metafile kaydına dokunmasanız bile hatırlamaya değer kısım burasıdır

Free Pascal, fırça oluşturma kaydını çalışma zamanı fırça yapısı gömülü olarak bildirir ve extended kalem kaydını çalışma zamanı kalem yapısı gömülü olarak bildirir. Bu çalışma zamanı yapılarının her ikisi de hatch üyesini işaretçi boyutunda bir tamsayı olarak bildirir, çünkü canlı bir GDI çağrısında o üye bir tanıtıcı taşıyabilir. Bir metafile ise her zaman 32 bitlik biçimi saklar, çünkü kayıt düzeni serileştirilmiş dosya biçiminin parçasıdır ve işlem bitliğine göre değişmez

32 bitlik derlemelerde ikisi örtüşür ve hiçbir şey olmaz. Win64 derlemesinde işaretçi boyutundaki üye sekiz bayttır, dosyada ise dört bayt vardır; dolayısıyla hatch üyesinden sonraki her alan yanlış ofsetten okunur. Ne bir istisna, ne bir ayrıştırma hatası ne de bir uyarı vardır. Metafile sadece yanlış çizilir: yanlış baytlardan renkler, yanlış baytlardan kalem genişlikleri ve bir yapı düzeni hatası yerine bir çizim hatası gibi görünen bir resim. Delphi, tam da bu nedenle her iki yapının açıkça 32 bitlik varyantlarını gönderir ve uyumluluk birimi onları aynı şekilde yeniden bildirir

EMF fırça kaydının bayt düzeni, Win64 derlemesinde işaretçi boyutlu hatch alanının sonraki alanları dört bayt kaydırışını sabit 32 bitlik düzene karşı gösterir
Serileştirilen kayıt her zaman 4 baytlık bir hatch saklar; dolayısıyla işaretçi boyutlu çalışma zamanı yapısı, Win64 derlemesinde sonraki her alanı sessizce yanlış okur
// Win64 derlemesinde yanlış: Hatch işaretçi boyutunda, dosya 32 bit
// saklar ve hatasız biçimde sonraki her alan dört bayt kayar
type
  TLogBrushRuntime = record
    lbStyle: UINT;
    lbColor: COLORREF;
    lbHatch: ULONG_PTR;      // 64 bitlik bir işlemde 8 bayt
  end;

// Doğru: serileştirilmiş düzen, bitlikten bağımsız sabit genişlik
type
  TLogBrush32 = record
    lbStyle: UINT;
    lbColor: COLORREF;
    lbHatch: DWORD;          // her zaman 4 bayt, metafile içindeki saklanışıyla
  end;

Genel kural: hem çalışma zamanı API argümanı hem de serileştirilmiş alan düzeni olarak görünen her yapı, iki bildirim gerektirir ve serileştirilmiş olan baştan sona sabit genişlikli türler kullanmalıdır. Bir dosya biçimindeki işaretçi boyutlu üyeler, her zaman bir 64 bitlik derleme bekleyen hatadır

İmza farkları her çağrı noktasında değil, bir sarmalayıcıya aittir

Kalan farklar sıradan imza uyuşmazlıklarıydı ve bunları emmenin yolu, her çağrı noktasında koşullu değil iletici bir sarmalayıcıdır. Dönüşüm birleştirme işlevi, Delphi'nin referans parametre aldığı yerde Free Pascal altında işaretçiler alır; dolayısıyla sarmalayıcı referansları alır ve adresleri geçirir. Ayrıca her iki kaynak argümanı da önce yerellere kopyalar, çünkü dönüştürücüde hedef matrisin aynı zamanda kaynaklardan biri olduğu çağrı noktaları vardır ve okudukça yazan bir işleve aynı adresi iki kez geçirmek, yalnızca döndürülmüş içerikte ortaya çıkan incelikli biçimde yanlış bir dönüşüm üretir

function CombineTransformCompat(var Dest: TXForm;
  const A, B: TXForm): BOOL;
var
  SrcA, SrcB: TXForm;
begin
  // Önce kopyala: çağıranlar meşru olarak Dest'i A ya da B olarak geçirir
  SrcA := A;
  SrcB := B;
{$IFDEF FPC}
  Result := Windows.CombineTransform(@Dest, @SrcA, @SrcB);
{$ELSE}
  Result := Windows.CombineTransform(Dest, SrcA, SrcB);
{$ENDIF}
end;

Dikdörtgen ve nokta türleri diğer durumdur. Free Pascal, metafile dikdörtgen ve nokta kayıtlarını genel grafik olanlarından ayrı türler olarak ele alır; dolayısıyla sekiz atama noktası, özdeş düzene sahip kayıtlar arasında açık bir tür dönüştürme gerektirdi. Her iki derleyici de dönüştürme biçimini kabul eder; dolayısıyla o noktalar hiç koşullu taşımaz, bu da biraz çirkinliğe değer

Bunun bir Free Pascal dağıtımı için değiştirdiği şey

Vektör EMF içe aktarımı, Free Pascal altında Windows üzerinde çalışır ve Delphi derlemesiyle aynı sayfa içeriğini üretir: yollar yol olarak, gradyanlar desen içeriği olarak, metin metin olarak. Windows dışında raster yolu cevap olmaya devam eder ve bu, bağlantı noktasının değil biçimin kısıtıdır. Dönüştürücünün beslediği koordinat ve kırpma durumu içerik akışı CTM ve kırpma izleyici makalesinde anlatılır; yaydığı vektör primitifleri ise vektör grafik, shaderlar ve gradyanlar konusunda ele alınır

Kendi kod tabanınızı aynı fırsat için denetliyorsanız, faydalı alıştırma işi başlatan alıştırmadır: bağımlı olduğunuzu düşündüğünüz çerçeveden gerçekte kullandığınız üyeleri listeleyin. Cevap çoğu zaman içe aktarma listesinin ima ettiğinden çok daha kısadır ve gerçek kısıt genellikle tamamen başka bir yerdedir. Cihaz bağlamı tabanlı içe aktarma yolları genel olarak baskı önizleme ve cihaz bağlamı makalesinde anlatılır; platform ve araç zinciri kapsamı ise losLab PDF Developer Library ürün sayfasında listelenir