Teknik Makale

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

HotPDF vektör grafiklerini, geçerli sayfada bir yol kurup ardından onun boyanmasını isteyerek çizer. Arada bitmap adımı yoktur. MoveTo ve LineTo ile çizdiğiniz bir çizgi, içerik akışında PDF yol operatörleri olarak son bulur, yani gerçek bir vektör olarak kalır: yüzde 50 yakınlaştırmada net, yüzde 1600 yakınlaştırmada net ve rasterleştirilmiş bir sürümün tutacağı yerin küçük bir kesri kadar. Şemalar, tablo çizgileri, grafik eksenleri ve form süslemeleri için istediğiniz tam olarak budur ve arkasındaki API tek oturuşta öğrenilecek kadar küçüktür

Çizim yüzeyinin tamamı THotPDF.CurrentPage üzerinde yaşar. BeginDoc ile EndDoc arasında o sayfa nesnesi üzerinde rengi ve çizgi kalınlığını ayarlar, geometriyi yerleştirir ve onu işlemek için bir boyama operatörü çağırırsınız. En çok kullanacağınız dört ilkel şunlardır: keyfi yollar için MoveTo ve LineTo, kutular için Rectangle, daireler için Circle ve iki boyama operatörü olan Stroke ile Fill

Koordinat sistemi sol alt köşeden başlar

VCL tarafından gelen herkesi tökezleten tek şey budur. Denetimleri boyadığınız TCanvas, başlangıç noktasını sol üst köşeye koyar ve Y aşağı doğru büyür. PDF bunun tersini yapar. HotPDF sayfanın sol alt köşesinden punto cinsinden (1/72 inç) ölçer ve yukarı doğru gittikçe Y artar. Y := 720 noktası, 792 punto yüksekliğindeki bir US Letter sayfasının üstüne yakın oturur, Y := 50 ise altına yakın oturur. İlk çiziminiz dikeyde aynalanmış çıkıyorsa nedeni budur: ekran grafiklerinden taşınan kod yanlış yönü varsayar ve alt kenardan taşar

Aynı kural TextOut için de geçerlidir, dolayısıyla bir kez içselleştirdiğinizde metin ve şekiller tek bir zihinsel modeli paylaşır. Bir düzeni, her öğenin üstünün değil altının nerede duracağına karar vererek planlayın; gerisi kendiliğinden gelir

Ekran canvas sol üst başlangıç noktası ile PDF sol alt başlangıç noktasının karşılaştırması: bir US Letter sayfasının üstüne yakın aynı nokta TCanvas kodunda Y = 72, HotPDF puntolarında ise Y = 720 okunur, dolayısıyla Y çevrilmeden taşınan kod aynalanmış çizer
HotPDF ölçümü punto cinsinden sol alt köşeden yapar, dolayısıyla 612 x 792 sayfanın üstüne yakın bir nokta Y = 720 taşır — TCanvas kodunun küçük ve aşağı yönlü bir Y ile adreslediği fiziksel konumun aynısı

Yollar: MoveTo, LineTo, Stroke

Konturlu bir yol; kaldırılan, yerleştirilen ve sürüklenen bir kalemdir. MoveTo kalemi kaldırır ve hiçbir iz bırakmadan başlangıç noktasını belirler. Her LineTo geçerli yolu yeni bir noktaya uzatır. Stroke çağırana kadar sayfada hiçbir şey belirmez; bu çağrı biriken yolu geçerli kontur rengi ve çizgi kalınlığıyla çizer, sonra yolu temizler, böylece sonraki MoveTo sıfırdan başlar

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

    // Çizgi kalınlığı punto cinsindendir ve siz değiştirene kadar geçerlidir.
    Pdf.CurrentPage.SetLineWidth(1.5);
    Pdf.CurrentPage.SetRGBStrokeColor(clBlack);

    // Sayfanın üstüne yakın yatay bir çizgi (Y alttan ölçülür).
    Pdf.CurrentPage.MoveTo(72, 720);
    Pdf.CurrentPage.LineTo(523, 720);
    Pdf.CurrentPage.Stroke;          // yolu işle; bundan önce hiçbir şey çizilmedi

    // Daha kalın, bağlı bir çoklu çizgi: tek yolda üç parça.
    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 ayrıntı gerçek hata ayıklama süresi kazandırır. Çizgi kalınlığı bir argüman değil, durumdur: SetLineWidth onu bir kez ayarlar ve siz yeniden değiştirene kadar sonraki her Stroke o değeri kullanır; yukarıdaki çoklu çizginin ilk çizgiden kalın olmasının nedeni budur. Ayrıca yol her Stroke sonrasında sıfırlanır, dolayısıyla unutulmuş bir Stroke, özenle yerleştirdiğiniz geometrinin hiç işlenmemesi demektir. Çıktıda bir şekil eksikse, bakılacak ilk yer boyama çağrısıdır

Koordinatlar puntodur ve puntolar kesirli olabilir. MoveTo ile LineTo, Single değerleri kabul eder, dolayısıyla 0.5 puntoluk saç teli inceliğinde bir çizgi ya da 72.25 konumu geçerli ve anlamlıdır, en yakın tam birime yuvarlanıp yok edilmez. Bu hassasiyet iki zıt yönde önem taşır. Yaklaşık 0.5 altındaki bir çizgi kalınlığı, ekranda kaybolup baskıda yeniden beliren, aygıta bağlı mümkün olan en ince çizgi olarak işlenebilir; bu yüzden görünür bir çizgi, varsayılan yerine bilinçli olarak belirlediğiniz bir kalınlık ister. Diğer uçta, tablo çizgilerini ve kılavuz çizgilerini tam punto koordinatlarına oturtmak, komşu çizgiler farklı yuvarlandığında yoğun bir kılavuzun hafifçe düzensiz görünmesini engeller. Kılavuz aralığına en baştan punto cinsinden karar verin; düzenin geri kalanı bunu devralır

Dolu şekiller ve renk

Kapalı ilkeller dış çizgi 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 rengiyle boyayan Fill ile ya da yalnızca dış çizgi için Stroke ile işlenir. Dolgu rengi ile kontur rengi ayrı durum parçalarıdır; SetRGBFillColor ve SetRGBStrokeColor ile ayarlanır ve ikisi de tek bir TColor alır. Bu, Delphi renk sabitlerini ve RGB yardımcısını doğrudan yeniden kullanabileceğiniz anlamına gelir

HotPDF yol modeli: MoveTo, LineTo, Rectangle ve Circle bellekte görünmez bir geçerli yol kurar ve yalnızca Stroke, Fill ya da FillAndStroke işlemesi, kontur rengi, dolgu rengi ve çizgi kalınlığından oluşan kalıcı grafik durumunu kullanarak onu boyar, sonra arabelleği temizler
Geometri, bir boyama operatörü onu saklanan kontur rengi, dolgu rengi ve çizgi kalınlığıyla işleyene dek geçerli yolda sessizce birikir — unutulmuş bir boyama çağrısı şekli çizilmemiş bırakır
// Rectangle(X, Y, Width, Height): X ve Y sol alt köşedir.
Pdf.CurrentPage.SetRGBFillColor(RGB(220, 60, 60));
Pdf.CurrentPage.Rectangle(72, 500, 160, 90);
Pdf.CurrentPage.Fill;

// Circle(X, Y, Radius): X ve Y merkezdir.
Pdf.CurrentPage.SetRGBFillColor(clNavy);
Pdf.CurrentPage.Circle(420, 545, 45);
Pdf.CurrentPage.Fill;

// Yalnızca dış çizgi: bir kontur rengi ve kalınlık ayarlayın, sonra Stroke.
Pdf.CurrentPage.SetLineWidth(2);
Pdf.CurrentPage.SetRGBStrokeColor(clBlack);
Pdf.CurrentPage.Rectangle(72, 400, 160, 60);
Pdf.CurrentPage.Stroke;

Rectangle üzerindeki argüman biçimine dikkat edin. Bu, iki karşıt köşe değil, konum artı boyuttur: X, Y, Width, Height. Delphi geliştiricilerinin bildiği TCanvas.Rectangle ise (Left, Top, Right, Bottom) alır, dolayısıyla kas hafızası HotPDF'e genişlik ve yükseklik beklediği yerde ikinci bir köşe verdirir ve kutu yanlış boyutta çıkar. (X, Y) çifti, sayfa başlangıç noktasıyla tutarlı biçimde sol alt köşedir. Daire içinse (X, Y) merkezdir ve üçüncü argüman punto cinsinden yarıçaptır

Özgün örneğin yanlış yaptığı bir renk tercihi

Bu örneğin eski bir sürümü, her şekilde renkleri Random($FFFFFF) ile tohumluyordu. Canlı görünür ama üretilen belgeler için yanlış içgüdüdür. Koddan ürettiğiniz bir PDF genellikle test etmek de istediğiniz bir şeydir ve rastgele dolgu renkleri çıktıyı çalıştırmadan çalıştırmaya karşılaştırılamaz kılar: bilinen iyi bir dosyaya karşı bayt bayt fark alma işlemi, gerçek bir neden olmaksızın her seferinde başarısız olur. Açık renkler seçin. Bir dizi şekil boyunca çeşitlilik istediğinizde bunu verinizden ya da sabit bir palet dizisinden sürün, böylece aynı girdi her zaman aynı dosyayı üretir. Ürün bir yayın hattından geçiyorsa belirlenirlik, yenilikten daha değerlidir

İlkelleri bir araya getirmek: bir açıklama kutusu

Her ilkel tek başına basittir; asıl kazanç, birkaçı bir raporun gerçekten ihtiyaç duyduğu bir şeye birleştiğinde ortaya çıkar. Bir şekli işaret edip açıklayan kutu olan açıklama balonu, buraya kadar anlatılan her şeyi kullanır: kenarlıklı dolu bir dikdörtgen, konturlu bir işaretçi çizgisi, işaretçiyi sabitleyen bir nokta ve kutunun içinde, şekillerin kullandığı aynı sol alt koordinatlarla yerleştirilmiş metin. FillAndStroke burada hakkını verir; dikdörtgeni iki kez kurmak yerine tek bir işlemede hem iç kısmı hem dış çizgiyi boyar

HotPDF ilkellerinden kurulan bir açıklama kutusunun anatomisi: FillAndStroke ile işlenen bir dikdörtgen, MoveTo ve LineTo ile konturlanan bir işaretçi çizgisi, dolu bir sabitleme noktası ve şekillerle aynı sol alt kılavuzu paylaşan TextOut etiket çubukları
Açıklama kutusunu dört işleme kurar — FillAndStroke paneli ve çerçeveyi birlikte boyar, işaretçi ile nokta kontur ve dolgu durumunu yeniden kullanır ve her etiket ofseti kutu köşesine (90, 600) karşı düz aritmetiktir
var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'Callout.pdf';
    Pdf.BeginDoc;

    // 1. Kutu: soluk dolgu artı görünür bir kenarlık, tek yol, tek işleme.
    //    Rectangle sol alt köşe artı boyuttur, Y alttan ölçülür
    Pdf.CurrentPage.SetRGBFillColor(RGB(255, 244, 214));   // soluk kehribar panel
    Pdf.CurrentPage.SetRGBStrokeColor(RGB(180, 130, 40));  // daha koyu çerçeve
    Pdf.CurrentPage.SetLineWidth(1);
    Pdf.CurrentPage.Rectangle(90, 600, 240, 70);
    Pdf.CurrentPage.FillAndStroke;

    // 2. İşaretçi: kutunun kenarından aşağıya, açıklanan şeye doğru
    //    uzanan tek konturlu parça
    Pdf.CurrentPage.SetLineWidth(1.5);
    Pdf.CurrentPage.MoveTo(90, 615);        // kutunun sol kenarı
    Pdf.CurrentPage.LineTo(66, 546);
    Pdf.CurrentPage.Stroke;

    // 3. Dolu bir nokta işaretçiyi hedefine sabitler
    Pdf.CurrentPage.SetRGBFillColor(RGB(180, 130, 40));
    Pdf.CurrentPage.Circle(64, 542, 3);
    Pdf.CurrentPage.Fill;

    // 4. Etiket, kutunun sol alt köşesine göre konumlandırılır.
    //    Metin ve şekiller tek koordinat sistemini paylaşır, bu yüzden
    //    ofsetler (90, 600) noktasına karşı düz aritmetiktir
    Pdf.CurrentPage.SetFont('Arial', [fsBold], 10);
    Pdf.CurrentPage.TextOut(102, 645, 0, 'Check this total');
    Pdf.CurrentPage.SetFont('Arial', [], 9);
    Pdf.CurrentPage.TextOut(102, 628, 0, 'The rounding rule changed in the');
    Pdf.CurrentPage.TextOut(102, 616, 0, 'June release; verify against v2.1');

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

Bileşik çizimin ne kadar az durum yönetimi gerektirdiğine dikkat edin. Dolgu rengi, kontur rengi ve çizgi kalınlığı, her biri onu kullanan şeklin hemen öncesinde ayarlanır; böylece çizimin her bloğu kendi kendine yeten bir birim gibi okunur ve gizli durumu peşinden sürüklemeden yeniden sıralanabilir ya da bir yardımcı işleve çıkarılabilir. Bunu, sabitleme noktasını ve dizeleri alan bir yordama sarın; kırk satır karşılığında yeniden kullanılabilir bir şema açıklaması elde edersiniz

Vektör çizimin kazandırdığı ve kazandırmadığı yerler

Geometri üretilmiş olduğunda bu yol ve şekil çağrılarına uzanın: grafik kılavuz çizgileri ve çubukları, bir fatura tablosunun cetvel çizgileri, bir şema üzerindeki açıklama kutuları, birkaç yolla ifade edilen bir logo işareti. Bunların hepsi bulanıklaşmadan ölçeklenir ve dosya boyutuna neredeyse hiçbir şey eklemez, çünkü bir dikdörtgen binlerce piksel değil birkaç sayıdır. Madalyonun öteki yüzü de dürüsttür. Elinizdeki şey aslında bir fotoğraf ya da ekran görüntüsüyse, onu bunun yerine AddImage ve ShowImage ile bir görüntü olarak çizin; bir bitmap'i vektör çağrılarıyla çizmek size hiçbir şey kazandırmaz. Yukarıdaki düz parçalar, dikdörtgenler ve daireler gerçek raporlama işinin büyük çoğunluğunu taşır ve geliştiricilerin ardından sorduğu üç incelik olan eğriler, kesik çizgi desenleri ve saydamlık aynı sayfa nesnesinde durur

Kısaca eğriler, kesik çizgiler ve saydamlık

Serbest biçimli eğriler, halihazırda sahip olduğunuz aynı yol mekanizmasını genişletir. CurveToC(X1, Y1, X2, Y2, X3, Y3), geçerli noktadan (X3, Y3) noktasına iki denetim noktasına doğru bükülen kübik bir Bezier parçası ekler; kısayol çeşitleri CurveToV ve CurveToY ise denetim noktalarından birinin bir uç noktayla çakıştığı durumları karşılar. Tek bir Stroke ya da Fill onu işlemeden önce bir yol, LineTo ve CurveToC parçalarını serbestçe karıştırabilir; yuvarlatılmış köşeler ve pürüzsüz grafik çizgileri böyle kurulur

Kesik konturlar, tıpkı çizgi kalınlığı gibi durumdur. SetDash([3, 3], 0) sonraki her konturu üç punto dolu, üç punto boş desene geçirir; dizi, dolu ve boş kesimlerin uzunluklarını punto cinsinden yazar, ikinci argüman ise döngünün nereden başlayacağını fazlar. NoDash kalemi düz çizgiye döndürür. Ayarlayın, bunu isteyen kılavuz çizgilerini konturlayın ve bir sonraki düz çizgiden önce sıfırlayın; yoksa kesik desen sessizce ardından gelen her şeye bulaşır

Saydamlık, bir renk argümanı yerine adlandırılmış bir grafik durumu üzerinden işler, çünkü PDF içinde alfa, grafik durumu sözlüğünün bir özelliğidir. Belge üzerinde RegisterExtGState ile 0 ile 1 arasında bir dolgu alfası ve bir kontur alfası vererek bir tane kaydedin, sonra döndürdüğü adı CurrentPage.SetGraphicsState ile uygulayın; o noktadan sonraki dolgular ve konturlar kayıtlı opaklıkta boyanır. Renk ayarlayıcılarından daha ağır bir törendir ve bir vurgu çubuğunun metni gizlemeden onun üzerinde durması gerektiği ilk anda buna değer

Korunmaya değer kalan alışkanlık doğrulamadır. Üretilen geometri sizin makinenizde geçip müşterininkinde kalabilir; bunun nedeni genellikle karıştırdığınız metinde font ikamesi ya da geçerli olmayan bir sayfa boyutu varsayımıdır. Bitmiş dosyayı birkaç yakınlaştırma düzeyinde açarak kenarların temiz kaldığını doğrulayın ve her şeklin amaçladığınız kenar boşluğu kutusunun içine düştüğünü denetleyin. Belirlenimci bir renk düzeniyle bu denetim, gözle bakmak yerine bir referans PDF karşısında otomatikleştirilebilir

Burada gösterilen MoveTo, LineTo, Stroke, Fill ve renk çağrıları, Delphi ve C++Builder için HotPDF Delphi Bileşeni kapsamındadır