Teknik Makale

Delphi'de HotPDF Canvas Çizimi: Vektör Yolları ve Renk

HotPDF, geçerli sayfada bir yol (path) oluşturarak ve ardından bunun boyanmasını isteyerek vektör grafikleri çizer. Arada hiçbir bitmap adımı yoktur. MoveTo ve LineTo ile çizdiğiniz bir çizgi, içerik akışında PDF yol operatörleri olarak son bulur, böylece gerçek bir vektör olarak kalır: %50 yakınlaştırmada net, %1600'de net ve rasterleştirilmiş bir sürümün mal olacağı boyutun sadece bir kısmıdır. Diyagramlar, tablo çizgileri, grafik eksenleri ve form süslemeleri için tam olarak istediğiniz şey budur ve arkasındaki API tek oturuşta öğrenilebilecek kadar küçüktür

Tüm çizim yüzeyi THotPDF.CurrentPage üzerinde yaşar. BeginDoc ve EndDoc arasında o sayfa nesnesinde renk ve çizgi genişliğini ayarlar, geometriyi yerleştirir ve bunu işlemek için bir boyama operatörü çağırırsınız. En çok kullanacağınız dört temel öğe, isteğe bağlı yollar için MoveTo ve LineTo, kutular için Rectangle, diskler için Circle ve iki boyama operatörü olan Stroke ve Fill olacaktır

Koordinat sistemi sol alttadır

Bu, VCL'den gelen herkesin kafasını karıştıran tek şeydir. Kontrolleri boyadığınız TCanvas, başlangıç noktasını Y aşağı doğru büyüyerek sol üst köşeye yerleştirir. PDF ise tam tersini yapar. HotPDF, sayfanın sol alt (bottom-left) köşesinden nokta (1/72 inç) cinsinden ölçer ve Y siz yukarı doğru hareket ettikçe artar. Y := 720 konumundaki bir nokta, 792 nokta uzunluğundaki bir US Letter sayfasının en üstüne yakın oturur ve Y := 50 en alta yakın oturur. Eğer ilk çiziminiz dikey olarak aynalanmış çıkıyorsa, nedeni budur: ekran grafiklerinden aktarılan kod yanlış yönü varsayar ve alt kenardan dışarı taşar

Aynı kural TextOut için de geçerlidir, bu yüzden içselleştirdiğinizde metin ve şekiller tek bir zihinsel modeli paylaşır. Bir mizanpajı, her öğenin üstünün değil, altının nerede duracağına karar vererek planlayın, gerisi bunu takip eder

Yollar: MoveTo, LineTo, Stroke

Konturlanmış bir yol (stroked path), kaldırılmış, yerleştirilmiş ve sürüklenmiş bir kalemdir. MoveTo kalemi kaldırır ve hiçbir şeyi işaretlemeden başlangıç noktasını belirler. Her LineTo mevcut yolu yeni bir noktaya uzatır. Siz, geçerli kontur rengini ve çizgi genişliğini kullanarak biriken yolu çizen ve ardından sonraki MoveTo'nun baştan başlaması için yolu temizleyen Stroke'u çağırana kadar sayfada hiçbir şey görünmez

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'DrawPaths.pdf';
    Pdf.BeginDoc;

    // Line width is in points and applies until you change it.
    Pdf.CurrentPage.SetLineWidth(1.5);
    Pdf.CurrentPage.SetRGBStrokeColor(clBlack);

    // A horizontal rule near the top of the page (Y measured from bottom).
    Pdf.CurrentPage.MoveTo(72, 720);
    Pdf.CurrentPage.LineTo(523, 720);
    Pdf.CurrentPage.Stroke;          // commit the path; nothing drew before this

    // A thicker connected polyline: three segments in one path.
    Pdf.CurrentPage.SetLineWidth(3);
    Pdf.CurrentPage.SetRGBStrokeColor(RGB(30, 90, 200));
    Pdf.CurrentPage.MoveTo(72, 640);
    Pdf.CurrentPage.LineTo(172, 690);
    Pdf.CurrentPage.LineTo(272, 620);
    Pdf.CurrentPage.LineTo(372, 680);
    Pdf.CurrentPage.Stroke;

    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

İki detay gerçek hata ayıklama zamanından tasarruf sağlar. Çizgi genişliği bir argüman değil, bir durumdur: SetLineWidth bunu bir kez ayarlar ve siz tekrar değiştirene kadar her bir sonraki Stroke bu değeri kullanır, yukarıdaki çoklu çizginin kuraldan daha kalın olmasının nedeni budur. Ve her Stroke'tan sonra yol sıfırlanır, bu nedenle unutulmuş bir Stroke, çok dikkatli bir şekilde yerleştirdiğiniz geometrinin hiçbir zaman oluşturulmadığı anlamına gelir. Çıktıda bir şekil eksikse, bakılacak ilk yer boyama çağrısıdır

Koordinatlar noktalardır (points) ve noktalar kesirlidir. MoveTo ve LineTo, Single değerlerini kabul eder, bu nedenle 0.5 noktadaki bir ince çizgi veya 72.25'teki bir konum yasaldır ve anlamlıdır, en yakın tam birime yuvarlanmaz. Bu hassasiyet iki zıt yönde önemlidir. Yaklaşık 0.5'in altındaki bir çizgi genişliği, ekranda kaybolan ve yazdırıldığında yeniden ortaya çıkan cihaza bağlı mümkün olan en ince çizgi olarak oluşturulabilir, bu nedenle görünür bir çizgi, varsayılan yerine bilerek ayarladığınız bir genişlik ister. Diğer uçta, tablo çizgilerini ve kılavuz çizgilerini tam nokta koordinatlarına tutturmak, bitişik çizgilerin farklı yuvarlandığı durumlarda yoğun bir ızgaranın biraz düzensiz görünmesini engeller. Izgara aralığına nokta cinsinden önceden karar verin, mizanpajın geri kalanı bunu devralır

Dolgulu şekiller ve renk

Kapalı temel öğeler, dış hatları çizilmek yerine doldurulabilir. Rectangle bir konum ve bir boyut alır, Circle bir merkez ve bir yarıçap alır ve her ikisi de, iç kısmı geçerli dolgu renginde boyayan Fill ile veya yalnızca bir dış hat için Stroke ile işlenir. Dolgu rengi ve kontur rengi, her ikisi de tek bir TColor alan SetRGBFillColor ve SetRGBStrokeColor ile ayarlanan ayrı durum parçalarıdır. Bu, Delphi'nin renk sabitlerini ve RGB yardımcısını doğrudan yeniden kullanabileceğiniz anlamına gelir

// Rectangle(X, Y, Width, Height): X and Y are the lower-left corner.
Pdf.CurrentPage.SetRGBFillColor(RGB(220, 60, 60));
Pdf.CurrentPage.Rectangle(72, 500, 160, 90);
Pdf.CurrentPage.Fill;

// Circle(X, Y, Radius): X and Y are the center.
Pdf.CurrentPage.SetRGBFillColor(clNavy);
Pdf.CurrentPage.Circle(420, 545, 45);
Pdf.CurrentPage.Fill;

// Outline only: set a stroke color and a width, then Stroke.
Pdf.CurrentPage.SetLineWidth(2);
Pdf.CurrentPage.SetRGBStrokeColor(clBlack);
Pdf.CurrentPage.Rectangle(72, 400, 160, 60);
Pdf.CurrentPage.Stroke;

Rectangle üzerindeki argüman şekline dikkat edin. İki zıt köşe değil, konum-artı-boyuttur, X, Y, Genişlik, Yükseklik (Width, Height). Delphi geliştiricilerinin bildiği TCanvas.Rectangle, (Sol, Üst, Sağ, Alt) alır, bu nedenle kas hafızası HotPDF'e bir genişlik ve yükseklik beklediği yerde ikinci bir köşe verecektir ve kutu yanlış boyutta çıkacaktır. (X, Y) çifti, sayfa başlangıç noktasıyla tutarlı olan sol alt köşedir. Bir daire için (X, Y) merkezdir ve üçüncü argüman nokta cinsinden yarıçaptır

Orijinal örneğin yanlış yaptığı bir renk seçimi

Bu örneğin daha eski bir sürümü, her şekilde Random($FFFFFF) ile renklere tohum (seed) atmıştı. Canlı görünüyor ve üretilen belgeler için yanlış bir içgüdü. Koddan oluşturduğunuz bir PDF genellikle aynı zamanda test etmek isteyeceğiniz bir şeydir ve rastgele dolgu renkleri, çıktıyı çalışmadan çalışmaya karşılaştırmayı imkansız hale getirir: bilinen iyi bir dosyaya karşı bayt bayt bir karşılaştırma (diff), gerçek bir neden olmadan her seferinde başarısız olur. Açık renkler seçin. Bir dizi şekil arasında çeşitlilik istediğinizde, bunu verilerinizden veya sabit bir palet dizisinden sürün, böylece aynı girdi her zaman aynı dosyayı üretir. Artefakt bir sürüm ardışık düzeninde (release pipeline) hareket ettiğinde, determinizm yenilikten daha değerlidir

Temel öğeleri bir çağrı kutusunda birleştirme

Her temel çizim çağrısı tek başına basittir; asıl kazanım, raporun ihtiyaç duyduğu bir açıklama kutusunda ortaya çıkar. Kutunun dolgulu bir dikdörtgeni ve kenarlığı, şekle uzanan çizgisi, çizginin bağlantı noktası ve kutunun içinde aynı sol-alt koordinat sistemiyle yerleştirilmiş metni bulunur. FillAndStroke, bir yolun içini ve dış çizgisini tek çağrıda boyayarak dikdörtgeni iki kez kurma ihtiyacını ortadan kaldırır

Dolgu rengi, kontur rengi ve çizgi genişliğini her şekli kullanan çağrının hemen öncesinde ayarlayın. Böylece her çizim bloğu bağımsız okunur ve gizli grafik durumu taşımadan bir yardımcı yordam içine alınabilir

Vektör çiziminin işe yaradığı ve yaramadığı yerler

Geometri oluşturulduğunda bu yol ve şekil çağrılarına ulaşın: grafik kılavuz çizgileri ve çubukları, bir fatura tablosunun kurallı çizgileri, bir diyagramdaki açıklama kutuları, bir avuç yol olarak ifade edilen bir logo işareti. Tamamı bulanıklaşmadan ölçeklenir ve dosya boyutuna neredeyse hiçbir şey katmaz, çünkü bir dikdörtgen binlerce piksel yerine birkaç sayıdır. Madalyonun diğer yüzü de dürüsttür. Aslında sahip olduğunuz şey bir fotoğraf veya ekran görüntüsü ise, bunun yerine onu AddImage ve ShowImage ile bir resim olarak çizin; bir bitmap'i vektör çağrılarıyla izlemek size hiçbir şey kazandırmaz. Karmaşık eğriler de burada kapsam dışındadır. Yukarıdaki temel öğeler, gerçek raporlama işinin büyük çoğunluğunu taşıyan düz parçalar, dikdörtgenler ve dairelerdir; serbest biçimli Bezier eğrilerine ihtiyaç duyan herhangi bir şey API'nin ayrı bir parçasıdır

Sürdürmeye değer kalan alışkanlık doğrulamadır. Oluşturulan geometri makinenizde geçebilir ve genellikle karıştırdığınız herhangi bir metindeki yazı tipi değişimi veya geçerli olmayan bir sayfa boyutu varsayımı nedeniyle bir müşterininkinde başarısız olabilir. Kenarların temiz kaldığını onaylamak için bitmiş dosyayı birkaç yakınlaştırma düzeyinde açın ve her şeklin amaçladığınız kenar boşluğu kutusunun içine düştüğünü kontrol edin. Deterministik bir renk şemasıyla, bu kontrol gözle kontrol edilmek yerine referans bir PDF'ye karşı otomatikleştirilebilir

Burada gösterilen MoveTo, LineTo, Stroke, Fill ve renk çağrıları, Delphi ve C++Builder için HotPDF Component'in bir parçasıdır

Eğriler, kesikli çizgiler ve şeffaflık

Serbest biçimli eğriler, mevcut yol mekanizmasını genişletir. CurveToC(X1, Y1, X2, Y2, X3, Y3), geçerli noktadan (X3, Y3) konumuna iki kontrol noktasını izleyen bir kübik Bezier parçası ekler; CurveToV ve CurveToY ise kısayollardır. Tek bir Stroke veya Fill çağrısıyla boyamadan önce aynı yolda LineTo ve CurveToC parçalarını birlikte kullanabilirsiniz

Kesikli çizgiler grafik durumunun parçasıdır. SetDash([3, 3], 0) sonraki çizgileri üç punto çizili ve üç punto boş bir düzene geçirir; NoDash kalemi düz çizgiye döndürür. Kesikli ızgarayı çizdikten sonra durumu sıfırlayın, yoksa desen sonraki çizgilere de taşınır

Şeffaflık renk parametresinden değil, adlandırılmış grafik durumundan gelir. Belgeye RegisterExtGState ile 0 ile 1 arasında dolgu ve kontur alfa değerleri kaydedin, ardından adı CurrentPage.SetGraphicsState ile uygulayın