Teknik Makale

HotPDF ile Delphi'de PDF Tiling Pattern Render Etme

Tek düz gri bir blok olarak render edilen tarama (hatching), klasik tiling-pattern hatasıdır. Delphi ve C++Builder için yerel VCL PDF bileşeni olan HotPDF, PatternType 1'i geçerli yolu geçici bir klip hâline getirip pattern içerik akışını görünür tile başına bir kez yeniden oynatarak boyar; pattern seçimi grafik durumunda tutulur ve q ile Q tarafından geri yüklenir

Belirtiler iki türde gelir ve nedenini bilene kadar alakasız görünürler. Bir CAD çizimi kesit taramasını kaybeder ve düz dolgular olarak geri döner, çünkü renderer pattern'i bir ortalama renge çözer ve onu boyar. Ya da tarama kaçar: düz beyaz olması gereken bir başlık bloğu, birkaç yol öncesindeki bir detay görünümünden çapraz çizgileri alır. İkisi de pattern-durumu problemidir ve yalnızca biri tile çizmekle ilgilidir

Bir tiling pattern neden bir sonraki yola sızar?

Çünkü seçili pattern adı, onu kullanan operatörün özelliği değil, grafik durumunun bir parçasıdır. ISO 32000-1 §8.6.6.2, bir Pattern renk uzayını, renk değerinin scn veya SCN'e sağlanan bir pattern adı olduğu bir uzay olarak tanımlar ve renk durumunun her diğer bileşeni q tarafından kaydedilir ve Q tarafından geri yüklenir. Pattern adı da aynı kurala uymalıdır. HotPDF onu, dolgu ve vuruş renk uzayı ailesinin yanında, durum kaydında FillPatternName ve StrokePatternName olarak tutar, dolayısıyla bir Q, önceki seçimi, önceki CTM'yi geri koyduğu tam şekilde geri koyar

Bunun yerine o adı operatör dağıtıcısı içinde yerel bir değişkende saklayın ve akıştaki her Q'dan hayatta kalır. Hata daha sonra beklenmeyen bir yerde ortaya çıkar: desenlendirilmiş yoldan sonra çizilen bir Form XObject, kendi içerik akışının hiç yapmadığı bir pattern seçimini miras alır ve dolguları taranmış çıkar. İç içe geçmiş formlar bunu daha kötü yapar, çünkü her iç içe geçme düzeyi başıboş değişkenin görmezden geldiği durumu iter ve çıkarır. cs veya CS ile pattern olmayan bir renk uzayı ayarlamak, veya sade bir g / rg / k vermek de pattern adını temizlemelidir, aksi halde eskimiş seçim, ona anlam veren renk uzayından daha uzun yaşar

q
  /Pattern cs              % pattern colour space, ISO 32000-1 8.6.6.2
  /P1 scn                  % coloured tiling pattern, PaintType 1
  10 10 200 120 re f       % this rectangle is hatched
Q
0 0 300 200 re f           % must be black again, not hatched

q
  /Cs2 cs                  % [/Pattern /DeviceCMYK] array
  0 0.6 1 0 /P2 scn        % uncoloured pattern plus its underlying colour
  20 20 160 90 re f*
Q

Bir pattern bir klip üzerinden boyanır, asla bir dolgu olarak değil

Doğru model çıkarımsaldır: cihaz klibini boyanan şekle sınırlayın, sonra pattern içeriğini onun içinde çalıştırın. HotPDF asla önce düz bir yaklaşım çizip üzerine boyamaz, çünkü ara düz renk, tile'lar arasındaki boşluklardan görünür olur ve tile içeriğindeki herhangi bir saydamlıkla çatışır. §8.7.3.2, bir tiling pattern'i, sabit yatay ve dikey aralıklarla çoğaltılan bir içerik akışı olarak tanımlar ve çoğaltma yalnızca zaten doğru şekle sahip bir klibe karşı anlamlıdır. Dolgular için dönüşüm doğrudandır: HPDFSelectFillPathClip, çokgen dolgu modunu f*, B* ve b* için ALTERNATE'e ve tek olmayan varyantlar için WINDING'e ayarlar, GDI yolunu inşa eder ve onu SelectClipPath ile klibe kesiştirir. Bu tek satır, çift-tek desenli bir dolgunun çift-tek düz bir dolguyla aynı delikleri bırakmasını sağlayan şeydir, ki bu tam olarak simit şeklinde taranmış bir bölgenin ihtiyacı olan şeydir

Vuruşlar yanlış yapılması kolay olan kısımdır. Vuruşlanmış bir yolun iç kısmı yoktur, dolayısıyla yolun kendisini klibe kesiştirmek boş bir bölge verir ve hiçbir şey boyanmaz. HPDFSelectStrokePathClip bu yüzden önce geçerli durumdan geometrik bir kalem inşa eder, J'den uç başlığı, j'den birleşimi, M'den miter sınırını kullanarak ve bir tire dizisi etkinken PS_USERSTYLE ile PS_GEOMETRIC kullanır, sonra klipten önce vuruşlanmış anahatı doldurulabilir bir bölgeye dönüştürmek için WidenPath'i çağırır. Bir pattern-vuruşlanmış yoldaki uç, birleşim, miter ve tire davranışı, o zaman ikinci bir uygulamayla değil inşayla normal bir vuruşa eşleşir. Burada iki dürüst sınır yaşar: bir cihaz birimi altındaki çizgi genişlikleri bir piksele sabitlenir ve tire dizisi, ExtCreatePen'in kabul ettiği tavan olan on altı girdide kesilir

Hangi tile'lar gerçekten görünür?

Görünür aralık, dönüşümü geriye doğru çalıştırmaktan gelir. Tile yerleşimi pattern uzayında gerçekleşir, ama sayfanın ne kadarına dokunulduğunu bilen tek şey, cihaz uzayında olan cihaz klip kutusudur. HotPDF, BaseMatrix := CTM * PatternMatrix'i oluşturur, onu tersine çevirir ve GDI klip kutusunun dört köşesini tersi üzerinden geri eşler. Bu dört eşlenmiş köşenin eksen hizalı sınırları, potansiyel olarak kapsanabilecek pattern-uzayı dikdörtgenini verir ve bu dikdörtgeni XStep ve YStep'e pattern BBox'una karşı bölmek, kapalı indeks aralıkları verir. Her hücre daha sonra CTM * PatternMatrix * Translate(i * XStep, j * YStep)'in bir CTM'siyle render edilir ve kendi dönüştürülmüş BBox çokgeninine ikinci kez klipe alınır. Bu ikinci klip, XStep, sınır kutusu genişliğinden küçük olduğunda önemlidir, ki üst üste binen tile tasarımları bu şekilde ifade edilir; onsuz, komşu hücreler kendi bildirilen kapsamlarının dışında birbirinin üzerine boyanırdı. Hücre-başına klip NULLREGION olarak dönerse, hücre hiçbir şey tokenize edilmeden veya çalıştırılmadan atlanır

// Map the device clip box back into pattern space through the inverse of
// CTM * PatternMatrix, then convert those bounds into tile index ranges.
BaseMatrix := HPDFMatMul(FGSStack.State.CTM, PatternMatrix);
if not HPDFMatInvert(BaseMatrix, InverseMatrix) then Exit;   // singular: refuse
if GetClipBox(FDC, ClipRect) = ERROR then Exit;

// MinX..MaxY are the axis-aligned bounds of the four mapped clip corners.
I0 := Floor((MinX - BBox[2]) / StepXAbs);
I1 := Ceil ((MaxX - BBox[0]) / StepXAbs);
J0 := Floor((MinY - BBox[3]) / StepYAbs);
J1 := Ceil ((MaxY - BBox[1]) / StepYAbs);

PlannedTiles := Int64(I1 - I0 + 1) * Int64(J1 - J0 + 1);
if (PlannedTiles <= 0) or (PlannedTiles > FPatternTilesRemaining) then Exit;
Dec(FPatternTilesRemaining, Integer(PlannedTiles));

Renksiz pattern'ler ve dışarıdan gelen renk

Bir PaintType 2 pattern şekil taşır ama renk taşımaz ve renk pattern adıyla birlikte gelir. §8.7.3.2, renksiz bir pattern'in yalnızca altta yatan bir uzay bildiren bir Pattern renk uzayıyla kullanıldığını belirtir, dolayısıyla scn önce bileşen değerlerini, son olarak pattern adını alır. HotPDF bu bileşenleri, pattern renk uzayı girdisinde saklanan altta yatan uzay üzerinden çözer, bu da renksiz bir taramanın, diğer herhangi bir dolgu gibi tam olarak bir Separation mürekkebi veya bir DeviceN kombinasyonuyla tonlanabileceği anlamına gelir; bu çözümlemenin mekaniği Separation ve DeviceN spot renklerini render etmede ele alınmıştır. Tile'ın içinde, iki boyama türü keskin bir şekilde ayrılır. PaintType 2 için renderer, tile süresince bir renk-operatörü bastırma bayrağı ayarlar, dolayısıyla pattern içeriğindeki herhangi bir g, rg, k veya scn görmezden gelinir ve her işaret dışarıdan sağlanan rengi alır. PaintType 1 için tam tersi geçerlidir: dolgu ve vuruş durumu PDF varsayılanlarına, kimlik renk uzaylı DeviceGray siyaha sıfırlanır ve tile kendini renklendirir. Bu sıfırlamayı atlamak, f operatöründe o an geçerli olan rengin, kendini betimlemesi gereken bir pattern'e sızmasına izin verir

Grafik durum yığını derinliği her tile'dan sonra neden geri yüklenmeli?

Çünkü bir pattern içerik akışının dengesiz olmasına izin verilir ve hasar hücreler boyunca birikir. Akışında üç q operatörü ve iki Q operatörü bulunan bir tile, yığını başladığından bir çerçeve daha derin bırakır. Hücreler arasında yalnızca geçerli durum kaydını geri yükleyin, derinlik büyümeye devam eder, dolayısıyla iki yüzüncü hücre, o çerçevenin taşıdığı CTM ve klip ile birlikte, yüz doksan dokuzuncu hücreye ait bir yığın çerçevesinden çalışır. HotPDF bu yüzden tile döngüsünden önce durum kaydını ve yığın derinliğini anlık görüntüler ve her yinelemenin başında RestoreSnapshot'ı çağırır, ki bu yığını kaydedilen uzunluğa geri keser ve kaydedilen durumu tek bir adımda yeniden kurar. Sayfa Resources sözlüğü ve renk-operatörü bastırma bayrağı aynı sınırda geri yüklenir, çünkü bir tile kendi kaynaklarına referans verebilir ve onları komşusuna vermemelidir. GDI klip durumu, her hücrenin etrafında bir SaveDC / RestoreDC çifti aracılığıyla aynı muameleyi görür, dolayısıyla kendi W n klibini kuran bir tile, bir sonrakine kullanılabilir bölgeyi küçültemez

Bütçeler, retler ve renderer'ın çizmeyeceği şeyler

Tiling pattern'ler, bir PDF'de hizmet reddi dosyası yazmanın en kolay yeridir, dolayısıyla sınırlar sezgisel değil sert sayılardır. Pattern iç içe geçmesi, Form XObject özyinelemesi için kullanılan aynı korumayla derinlik 4'te sınırlıdır, ki bu kendi kaynak sözlüğü üzerinden kendine referans veren bir pattern'i durdurur. Tek bir yol boyaması, iç içe geçmiş pattern'ler boyunca sayılan ve yalnızca en dıştaki pattern boyaması başladığında sıfırlanan, toplamda en fazla 16.384 tile çalıştırabilir. Planlanan hücre sayısı bu bütçeden kalanı aşan bir tile ızgarası, tek bir hücre çalışmadan doğrudan reddedilir

Dejenere geometri yaklaşık olarak değil reddedilerek ele alınır. Eksik veya sıfır alanlı bir BBox, büyüklüğü 1e-6'nın altında bir XStep veya YStep, tersi olmayan bir CTM * PatternMatrix çarpımı, 1e9'un ötesinde eşlenmiş klip koordinatları veya bir milyonun ötesinde bir indeks büyüklüğü, hepsi pattern boyamasının hiçbir şey çizmeden dönmesine neden olur. Sonuç, asılı kalmış bir render iş parçacığı yerine boyanmamış bir bölgedir, ki bu bir toplu dönüştürücüde istediğiniz değiş tokuştur. Performans tek bir karardan gelir: pattern akışı boyama başına bir kez HPDFTokenizeContentStream ile tokenize edilir ve token dizisi her görünür hücre boyunca yeniden kullanılır, dolayısıyla tile sayısı çalıştırma maliyetini çarpar ama asla sözcüksel çözümleme maliyetini çarpmaz

Delphi'den desenlendirilmiş bir sayfayı render etmek

Pattern desteği hakkında hiçbir şey çağıran kodu değiştirmez. Belgeyi yükleyin, bir sayfa isteyin ve tiling çalışması, sayfadan bitmap'e render etmenin zaten yönlendirdiği içerik-akışı yorumlayıcısının içinde gerçekleşir. Aynı yorumlayıcı bitmap, metafile ve yazıcı cihaz bağlamlarını besler, dolayısıyla bir önizleme küçük resminde doğru görünen taranmış bir çizim, aynı tile geometrisiyle yazdırılır. PatternType 2 gölgeleme pattern'leri, eksenel ve radyal gölgeleme render etme altında ayrıntılı olarak anlatılan, çıplak sh operatörüyle değerlendirme yolunu paylaşan farklı bir dala girer

var
  Pdf: THotPDF;
  Bmp: TBitmap;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('assembly-drawing.pdf') > 0 then
    begin
      // Section hatching that previously flattened to a solid block now
      // replays the tile content once per visible cell.
      Bmp := Pdf.RenderLoadedPageToBitmap(0, 200);
      if Assigned(Bmp) then
      try
        Bmp.SaveToFile('sheet1.bmp');
      finally
        Bmp.Free;
      end;
    end;
  finally
    Pdf.Free;
  end;
end;

Desenlendirilmiş bir bölge hâlâ yanlış görünüyorsa, üç hata sınıfını sırayla kontrol edin. Tamamen boş bir bölge genellikle bir reddi ifade eder: XStep, YStep ve BBox'u dejenere değerler için inceleyin, veya ızgaranın ihtiyaç duyacağı tile'ları 16.384 tavanına karşı sayın. Tek düz bir renkte boyanmış bir bölge, pattern adının hiçbir zaman boyama operatörüne ulaşmadığı anlamına gelir, ki bu akıştaki cs ve scn sıralamasına işaret eder. Ait olmadığı bir yerde ortaya çıkan bir pattern, durum geri yüklemesi anlamına gelir ve bakılacak yer, onu miras alan form veya yol etrafındaki q / Q işlemesidir

Tiling pattern'ler, onlara ihtiyaç duyan dosya gelen kutunuza düşene kadar görünmez kalan ve sonra tüm iş hâline gelen PDF özelliklerinden biridir. Delphi veya C++Builder üzerinde çizim görüntüleyicileri, mühendislik belgesi dönüştürücüleri veya rapor renderer'ları inşa ediyorsanız, tam bileşen ve render API'si HotPDF Delphi PDF bileşeni sayfasında belgelenmiştir