PDF sayfa (page) boyutları bir sayfanın (page) oluşturulduğu sırada sabitlenir (fixed), bu nedenle bir resmi (image) yeniden boyutlandırdığınız (resize) gibi içeriği basitçe (simply) yerinde (in place) yeniden ölçeklendiremezsiniz. Küçültmeyi pratik (practical) hale getiren kitaplık modeli yakalama (capture) ve yeniden çizmektir (redraw): her sayfanın (page) içeriğini belgeden bir işleyiciye (handle) çıkarın (lift), orijinal (original) medya (media) boyutunda yeni (new) boş (blank) bir sayfa (page) oluşturun, ardından yakalanan içeriği daha küçük (reduced) bir sınırlayıcı kutu (bounding box) içinde geri (back) çizin (draw). Çevredeki boşluklar marj (margin) haline gelir. Örneğin bir A4 sayfasında %70 (70%) ölçekte (scale), genişliğin %15'i (15%) her iki tarafa, aynı oranda üst (top) ve alt (bottom) kısımlara düşer; bu da tam (exactly) olarak aşağıdaki (below) sınır (border) aritmetiğinin (arithmetic) ürettiği (produces) şeydir
CapturePage nasıl çalışır
CapturePage bir sayfa (page) numarası alır, o sayfanın (page) içeriğini (content) bellek içi (in-memory) bir yakalama nesnesine (capture object) yükseltir (promotes) ve sayfayı (page) belgenin sayfa (page) ağacından kaldırır (removes). Bu kaldırma işlemi kasıtlıdır (intentional) ve döngünün yinelenme indeksine (iteration index) bakılmaksızın her zaman sayfa (page) 1'i (1) seçmesinin (selects) nedeni budur: sayfa (page) 1 yakalanıp silindiğinde, sayfa (page) 2 olan (was) sayfa yeni (new) sayfa (page) 1 olur ve bu (so) böyle (on) devam eder. Sayfa seçiciyi (page selector) döngü sayacıyla (loop counter) birlikte artırırsanız (increment), her iki sayfadan (page) birini atlarsınız (skip) ve beklenen (expected) çıktının yarısını elde edersiniz (end up)
CapturePage tarafından (by) döndürülen yakalama (capture) tutamacı (handle) bir sayfa (page) referansı (reference) değildir; daha (more) çok bir içerik anlık (snapshot) görüntüsüne benzer. DrawCapturedPage öğesini çağırana (call) veya açıkça (explicitly) serbest bırakana (release) kadar geçerliliğini korur (stays valid). DrawCapturedPage bu tutamacı (handle) artı (plus) tümü punto (points) cinsinden verilen sol (left) ofset, alt (bottom) ofset, genişlik ve yükseklik (height) olarak verilen bir hedef dikdörtgeni (destination rectangle) alır. Kütüphane (library), en-boy (aspect) oranını (ratio) yalnızca dikdörtgeninizin orijinal orantılara (proportions) uyması durumunda koruyarak (preserving), yakalanan (captured) içeriği bu dikdörtgene (rectangle) tam olarak uyacak şekilde ölçeklendirir (scales). Eşit ölçekleme (uniform scaling) için dikdörtgenin, sayfada ortalanmış ve ölçek çarpanıyla (scale factor) çarpılmış (multiplied) orijinal boyut olmasını istersiniz (want)
Ortalama matematiği
%70'lik (70%) bir ölçek çarpanıyla (scale factor), her bir boyutun (dimension) kalan %30'u (30%) iki taraf (sides) arasında (between) eşit olarak paylaştırılır. Dolayısıyla (So) yatay içe doğru (horizontal inset) yerleşim pageWidth * (1.0 - 0.70) / 2'dir, bu da (which) genişliğin %15'idir (15%) ve dikey (vertical) iç yerleşim (inset), sayfa yüksekliğini (page height) kullanarak aynı formülü (formula) izler. Daha (Then) sonra (Then) DrawCapturedPage için (for) hedef dikdörtgeni (destination rectangle) (horizBorder, vertBorder) konumundan (at) başlar ve pageWidth - 2 * horizBorder boyutundan (by) pageHeight - 2 * vertBorder boyutuna yayılır (spans). Bu aritmetik, kütüphaneye (library) özgü değildir; sadece daha küçük bir dikdörtgeni daha (larger) büyük (larger) bir (one) dikdörtgenin (rectangle) içine simetrik (symmetrically) olarak yerleştirmenin (fitting) geometrisidir
Dikkat çeken bir şey: SetOrigin(1) koordinat başlangıç noktasını (coordinate origin) sol alt (bottom-left) yerine (rather than) sol üstte (top-left) konumlandırır. DrawCapturedPage öğesine aktardığınız (pass) kenarlık (border) değerleri (values), ayarladığınız orijinden itibaren (from) ölçülür (measured), bu (so) nedenle (so) yükleme ve çizim (loading and drawing) arasında (between) orijin (origin) modlarını değiştirirseniz (switch), ortalama (centering) yanlış (off) olur (off)
C# örneği
Aşağıdaki kod Pages.pdf'in (Pages.pdf) her sayfasını (page) yakala-ve-yeniden-çiz (capture-and-redraw) döngüsü (cycle) aracılığıyla işler ve sonucu (result) newpages.pdf dosyasına yazar. PDFL, projeye (project) PDFlibDLL64.dll dosyasından (from) eklenen ActiveX/COM sarmalayıcı (wrapper) nesnesidir (object)
private void ScalePages_Click(object sender, EventArgs e)
{
File.Delete("newpages.pdf");
double pageWidth, pageHeight, horizBorder, vertBorder;
double scaleFactor = 0.70;
int capturedPageId, ret;
PDFL.LoadFromFile("Pages.pdf", "");
PDFL.SetOrigin(1);
int numPages = PDFL.PageCount();
for (int i = 1; i <= numPages; i++)
{
// Always select page 1: CapturePage removes the page, so page 2
// becomes page 1 on the next iteration.
PDFL.SelectPage(1);
pageWidth = PDFL.PageWidth();
pageHeight = PDFL.PageHeight();
horizBorder = pageWidth * (1.0 - scaleFactor) / 2;
vertBorder = pageHeight * (1.0 - scaleFactor) / 2;
capturedPageId = PDFL.CapturePage(1);
PDFL.NewPage();
PDFL.SetPageDimensions(pageWidth, pageHeight);
ret = PDFL.DrawCapturedPage(
capturedPageId,
horizBorder, vertBorder,
pageWidth - 2 * horizBorder,
pageHeight - 2 * vertBorder);
}
PDFL.SaveToFile("newpages.pdf");
}
Delphi örneği
Delphi sürümü (version), COM katmanı yerine doğrudan (directly) TPDFlib kullanır, ancak (but) çağrı (call) sırası (sequence) aynıdır (identical). Pratik (practical) bir fark (difference), çıktı dosyası (output file) korumasıdır (guard): File.Delete yerine (instead) FileExists ve (plus) DeleteFile, çünkü SaveToFile, daha önce (previous) bir (a) görüntüleyicide (viewer) hala (still) açık olan bir (a) çalıştırma (run) tarafından hedef (destination) kilitlenirse (locked) başarısız (fail) olacaktır (will)
procedure TForm1.ScalePagesClick(Sender: TObject);
var
PDFLib: TPDFlib;
pageWidth, pageHeight, horizBorder, vertBorder: Double;
scaleFactor: Double;
capturedPageId, ret, numPages, i: Integer;
begin
if FileExists('newpages.pdf') then
DeleteFile('newpages.pdf');
scaleFactor := 0.70;
PDFLib := TPDFlib.Create;
try
PDFLib.LoadFromFile('Pages.pdf', '');
PDFLib.SetOrigin(1);
numPages := PDFLib.PageCount();
for i := 1 to numPages do
begin
PDFLib.SelectPage(1);
pageWidth := PDFLib.PageWidth();
pageHeight := PDFLib.PageHeight();
horizBorder := pageWidth * (1.0 - scaleFactor) / 2;
vertBorder := pageHeight * (1.0 - scaleFactor) / 2;
capturedPageId := PDFLib.CapturePage(1);
PDFLib.NewPage();
PDFLib.SetPageDimensions(pageWidth, pageHeight);
ret := PDFLib.DrawCapturedPage(
capturedPageId,
horizBorder, vertBorder,
pageWidth - 2 * horizBorder,
pageHeight - 2 * vertBorder);
end;
PDFLib.SaveToFile('newpages.pdf');
finally
PDFLib.Free;
end;
end;
Ölçek çarpanı (scale factor) aslında (actually) neyi kontrol (controls) eder (controls)
Buradaki 0.70 (0.70) değeri, işlenen içeriğin dosyanın orijinal bayt (byte) boyutunun %70'i (70%) olduğu anlamına (means) değil (not), her sayfa boyutunun (dimension) %70'ini kapladığı anlamına gelir. Bu (this) işlemden (operation) sonraki (after) dosya boyutu (file size) büyük (large) ölçüde orijinal içeriğin karmaşıklığına (complexity) bağlıdır (depends); büyük resimlere sahip bir sayfa orantılı (proportionally) olarak (proportionally) küçülmeyecektir (shrink) çünkü (because) piksel verileri (data) aynı (same) çözünürlükte (resolution) daha (smaller) küçük (smaller) bir alana yeniden (redrawn) çizilir (redrawn). Eğer (If) bayt düzeyinde (byte-level) sıkıştırma (compression) amaçlanıyorsa (goal), doğru (right) yaklaşım (approach) geometrik (geometric) ölçeklendirme (scaling) değil (not), LinearizeFile veya akış (stream) sıkıştırmasıyla yeniden (re-saving) kaydetmektir (re-saving)
%70 (70%) rakamı da kesin (hard) bir sınır (limit) değildir. 0.0 (0.0) ile 1.0 (1.0) arasındaki (between) herhangi (Any) bir değer (value) işe yarar ve 1.0'ın üzerindeki değerler (values), sayfa (page) boyutlarını da artırmadığınız (increase) sürece (unless) ortam kutusu (media box) kenarında (edge) kırpılan (clips) içeriği (content) orijinal sayfa (page) sınırının (boundary) ötesine (beyond) büyütür (enlarge). Karışık (Mixed-size) boyutlu (Mixed-size) belgeler (documents) doğal (naturally) olarak işlenir çünkü PageWidth ve PageHeight, kenarlık hesaplamasından (calculation) önce her sayfa için sorgulanır (queried), bu nedenle (so) tek (odd) sayfaların A4 ve çift (even) sayfaların A3 olduğu bir (a) belge, herhangi bir özel duruma (casing) gerek kalmadan her sayfa (page) boyutunda doğru (correctly) şekilde ortalanmış çıktı üretecektir (produce)
İşlerin nerede ters (wrong) gidebileceği (go)
Uygulamada (practice) iki başarısızlık (failure) modu (modes) ortaya çıkar (come up). Birincisi (first), önceki bir (a) çalıştırmadan (run) dolayı (from) PDF görüntüleyicisinde açık (open) bırakılan bir çıktı dosyasıdır: SaveToFile platforma bağlı (depending) olarak (depending) başarısız (fail) olacak (will) veya (or) sıfır bayt yazacaktır ve yeni (new) çıktı (output) asla inmeyecektir (lands). İşlevin (function) en üstündeki (top) dosya (file-delete) silme (file-delete) koruması (guard) geliştirme (development) için bunu (that) işler (handles), ancak bir üretim boru hattında (pipeline) geçici (temporary) bir (a) yola (path) yazmak (writing) ve (and) başarıyla yeniden adlandırmak (renaming) daha (safer) güvenlidir (safer)
İkincisi, sayfa (page) sayısındaki (count) uyumsuzluktur (mismatch). CapturePage sayfaları işlerken (processes) belgeden kaldırdığı için, döngüden önce PageCount() ile okuduğunuz sayı, yineleme yapmak (iterate) için doğru (correct) sınırdır (bound). PageCount() döngü (loop) içinde (inside) çağrılması (Calling), her geçişte (pass) azalan (decreasing) bir sayı döndürür (return) ve (and) erken (early) çıkarak (exit) son sayfaları (pages) işlenmeden (unprocessed) bırakırdı. Örneklerdeki (examples) döngü değişkeni yalnızca kalan (remaining-iterations) yineleme (remaining-iterations) sayacı (counter) olarak hizmet eder; daha önce açıklanan nedenle seçilecek sayfa her zaman (always) 1 olduğundan, asla bir sayfa (page) seçmek (select) için (for) kullanılmaz (used)
Burada (here) gösterilen (shown) CapturePage, DrawCapturedPage ve SetPageDimensions dahil (including) sayfa (page) işleme (manipulation) çağrıları (calls), Delphi, C#, VB.NET ve C++ için losLab PDF Kütüphanesinin bir parçasıdır