A lap-összefűzés (page stitching) a meglévő oldalak tartalmát komponálja egy közös vászonra, ami különbözik a fájlok összefűzésétől (merging). A losLab PDF Library megvalósítja a Form XObject alapú oldal-összefűzést és a komponálható vízjel-sablonokat Delphihez: a StitchPageOverlay, a StitchPagesSideBySide és a StitchPagesVertically tetszőleges méretben, teljes vektoros hűséggel helyezi el a rögzített oldalakat, míg a TPDFlibCompositeWatermark egyetlen hívással rétegezi a szöveges és képi vízjeleket egy oldaltartományon keresztül. Ha Önnek valójában arra van szüksége, hogy több dokumentum teljes oldalait fűzze össze egyetlen fájlba, akkor ez a merge funkciócsalád, amelyet a gyors, bájtszintű PDF-összefűzésről szóló cikk tárgyal; ez a cikk a tartalom egyetlen koordináta-térben történő egyesítéséről szól
Az idevezető kérések hétköznapiak és makacsok. Egy iskola két vizsgaoldalt szeretne egyetlen fekvő lapra helyezni, hogy a felére csökkentse a papírhasználatot. Egy fordító a meglévő angol oldalt és annak fordítását szeretné egymás mellett látni egyetlen oldalon, együtt görgetve. Egy jogi csapat azt szeretné, ha minden vázlat egyszerre három réteggel lenne ellátva: a logóval a sarokban, egy átlós BIZALMAS felirattal a közepén, és egy kis lábléccel, kizárólag az 1–3. oldalakon. Mindhárom ugyanarra a mögöttes problémára vezethető vissza, nevezetesen a már kiszedett oldaltartalom máshova történő elhelyezésére más méretben, anélkül, hogy azt bitképpé rontanánk le
Miért hibásodik meg a PDF tartalomfolyamok egyszerű összefűzése?
A naiv összefűzés — a forrásoldal /Contents folyamának másolása a céloldalra — három strukturális okból is meghiúsul. Először is, a koordináták ütköznek: mindkét tartalomfolyam a saját MediaBox-ának bal alsó sarkában feltételezi a saját origóját, így a beillesztett tartalom a meglévő tartalom tetejére, rossz helyre kerül. Másodszor, az erőforrásnevek ütköznek: minden oldal a saját /Resources szótárához viszonyítva oldja fel az olyan operátorokat, mint a /F1 Tf és a /Im0 Do, és két oldal gyakran ugyanazt a nevet különböző betűtípusokhoz vagy képekhez rendeli, így az egyikük csendben a rossz erőforrással jelenik meg. Harmadszor, a nyers folyam másolása egyáltalán nem teszi lehetővé a nagyítást; a legtöbb, amit tehet, az az eltolás
Form XObject-ek mindhárom problémát egyszerre oldják meg, és a losLab PDF Library ezért építi rájuk az összefűzést. Az ISO 32000-1 §8.10 szabvány a form XObject-et önálló tartalomfolyamként definiálja, amely saját /Resources szótárral és saját koordináta-térrel rendelkezik, és amelyet az éppen aktív transzformációs mátrix alatt a nevének hívásával helyeznek el egy oldalon. A CapturePage egy teljes meglévő oldalt — a tartalmat és az erőforrásokat is beleértve — egy /Subtype /Form XObject-be csomagol, és az összefűző függvények ezután egy cm mátrix segítségével pozicionálják azt: tetszés szerint méretezik, eltolják vagy elforgatják. Mivel a forrás vektoros marad, a szöveg szöveg, az útvonalak pedig útvonalak maradnak bármilyen nagyítási szinten, ami megegyezik azzal a tulajdonsággal, amely a vektorgrafikát és az árnyékolási mintákat felbontásfüggetlenné teszi. Semmi sem lesz raszterizálva, és az izolált erőforrás-szótár azt jelenti, hogy a rögzített oldal nem ütközhet a céloldallal a /F1 név miatt
Hogyan lehet két PDF oldalt egyetlen oldalon egyesíteni?
A StitchPagesSideBySide(Page1, Page2, Gap, TargetHeight) a közvetlen válasz: rögzíti mindkét forrásoldalt, létrehoz egy új, szélesebb oldalt, és a két rögzített oldalt balra és jobbra helyezi el egy margóval közöttük, mindegyiket a TargetHeight magassághoz igazítva. A függvény az új oldalszámmal (1-alapú) tér vissza, vagy sikertelenség esetén 0-t ad, és mindkét forrásoldal rögzítésre és elrejtésre kerül a művelet részeként. A laponként két vizsgaoldalas eset egy háromsoros feladat
var
Lib: TPDFlib;
NewPage: Integer;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('exam.pdf', '');
// Az 1. és 2. oldal egy új, szélesebb oldalon, 18pt margóval,
// mindkettő 595pt kimeneti magasságra méretezve (A4 fekvő)
NewPage := Lib.StitchPagesSideBySide(1, 2, 18, 595);
if NewPage > 0 then
Lib.SaveToFile('exam-2up.pdf');
finally
Lib.Free;
end;
end;
Függőleges elrendezéshez a StitchPagesVertically(PageRanges, Gap, TargetWidth) egy teljes oldaltartományt egymásra helyez egyetlen hosszú, poszter-stílusú oldallá. A PageRanges elfogadja a szabványos tartomány-szintaxist, például az '1-3,5' formátumot. Minden forrásoldal úgy van méretezve, hogy a szélessége megegyezzen a TargetWidth értékkel, így az egyes oldalak magassági hozzájárulása a saját magasságuk szorozva a saját skálatényezőjükkel, a kimeneti oldal magassága pedig ezek összege, plusz egy-egy Gap (rés) az egyes párok között. Ez az elrendezés ideális a folyamatos görgetésű felülvizsgálati dokumentumokhoz vagy a letter méretű forrásokból összeállított hosszú bizonylatokhoz
Hogyan helyezhetünk átfedésként egy oldalt egy másikra?
A StitchPageOverlay(SourcePage, TargetPage, Left, Top, Width, Height, Opacity) egy meglévő oldalt rajzol egy másik meglévő oldalra, ahelyett, hogy újat hozna létre. A forrásoldalt form XObject-ként rögzíti, és a megadott téglalapban rajzolja rá a céloldalra, 0 és 1 közötti Opacity (átlátszatlanság) értékkel (az 1 teljesen átlátszatlan). A szélesség és a magasság szabad paraméterek, így az elhelyezés megnyúlik, ha a megadott arány eltér a forrásoldal saját méretarányától; adjon meg arányos párt, ha a forrás torzításmentes indexképét szeretné kapni. Tipikus felhasználása az a dokumentum, amelynek jóváhagyási blokkját külön oldalként tartják karban, és rányomják a borítóra
var
Lib: TPDFlib;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('report.pdf', '');
// Az 5. oldal tartalmazza a jóváhagyási blokkot; helyezze el az 1. oldalon
// egy 260 x 180-as dobozban 45%-os átlátszatlansággal. Az 5. oldal elfogy:
// rögzítésre és elrejtésre kerül, így a 6..n oldalak 5..n-1 oldalak lesznek
if Lib.StitchPageOverlay(5, 1, 300, 500, 260, 180, 0.45) = 1 then
Lib.SaveToFile('report-approved.pdf');
finally
Lib.Free;
end;
end;
Mi történik az oldalszámokkal a rögzítés után?
A CapturePage felemészti a forrásoldalt: annak tartalma átkerül az XObject-be, és a most már üres oldal elrejtésre kerül, így a forrás feletti oldalszámok azonnal eggyel lejjebb csúsznak. Ez a legfontosabb szemantikai szabály az egész összefűző API-ban. A losLab PDF Library kezeli az aritmetikát az egyes összefűző hívásokon belül: a StitchPageOverlay módosítja a célindexet, ha a cél a forrás felett helyezkedik el, a StitchPagesSideBySide pedig a magasabb sorszámú oldalt rögzíti először, így a második rögzítés indexe továbbra is érvényes marad, de a saját környező kódjának számolnia kell a hívások közötti eltolódással. Két szabály tartja helyesen a több összefűzést tartalmazó kódot: rögzítsen minden szükséges oldalméretet vagy oldalszámot az első rögzítés *előtt*, mert utána megváltoznak; valamint amikor maga rögzít több oldalt egy ciklusban, iteráljon csökkenő oldalsorrendben, hogy a későbbi oldalak elrejtése soha ne zavarja meg a még nem rögzített korábbiak indexét
Hogyan lehet többrétegű vízjelet alkalmazni egy oldaltartományra?
A PDFlibWatermark.pas fájlban található vízjel-sablonréteg objektumokká alakítja az „egyszer definiáld, sok oldalon alkalmazd” elvet. A TPDFlibWatermarkBase hordozza azt, ami minden vízjelben közös: egy kilencpontos Position-t (wpTopLeft-től wpBottomRight-ig, plusz a wpCustom-ot, amely nyers X/Y koordinátákat használ), egy Angle értéket fokban, egy 0 és 1 közötti Opacity értéket, valamint egy PageRange karakterláncot, ahol az üres érték az összes oldalt jelenti. A TPDFlibTextWatermark hozzáadja a szöveget, a betűtípus ID-t (alapértelmezés szerint Helvetica), a méretet és az RGB színt; a TPDFlibImageWatermark hozzáadja a korábban hozzáaddott kép ID-jét, valamint az elhelyezési szélességet és magasságot. A TPDFlibCompositeWatermark alvízjelek listáját tárolja, és rekurzívan alkalmazza őket, a TPDFlib.ApplyWatermark pedig az egyetlen hívással elérhető belépési pont, amely tiszteletben tartja a sablon saját oldaltartományát, és visszaadja a lebélyegzett oldalak számát. A háromrétegű jogi bélyegző így néz ki
var
Lib: TPDFlib;
Logo: TPDFlibImageWatermark;
Diagonal, Footer: TPDFlibTextWatermark;
Stack: TPDFlibCompositeWatermark;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('draft.pdf', '');
Stack := TPDFlibCompositeWatermark.Create;
try
Logo := TPDFlibImageWatermark.Create;
Logo.ImageID := Lib.AddImageFromFile('logo.png', 0);
Logo.Position := wpTopRight;
Logo.Width := 90;
Logo.Height := 32;
Stack.Add(Logo);
Diagonal := TPDFlibTextWatermark.Create;
Diagonal.Text := 'CONFIDENTIAL';
Diagonal.Position := wpCenter;
Diagonal.Angle := 45;
Diagonal.FontSize := 60;
Diagonal.Opacity := 0.15;
Stack.Add(Diagonal);
Footer := TPDFlibTextWatermark.Create;
Footer.Text := 'Internal review copy';
Footer.Position := wpBottomCenter;
Footer.FontSize := 9;
Footer.Opacity := 0.6;
Stack.Add(Footer);
Stack.PageRange := '1-3'; // a gyermekek öröklik ezt a tartományt
Lib.ApplyWatermark(Stack);
Lib.SaveToFile('draft-marked.pdf');
finally
Stack.Free; // a kompozit felszabadítja a gyermekeit
end;
finally
Lib.Free;
end;
end;
Két kompozíciós részletet érdemes részletezni. A tartományöröklés egyirányú és nem destruktív: az üres PageRange-dzsel rendelkező gyermek ideiglenesen örökli a kompozit tartományát az Apply során, míg az a gyermek, amely saját tartományt állít be, megtartja azt, így a láblécet minden oldalhoz rögzítheti, miközben az átlós bélyegző csak a vázlatrészt fedi le. A tulajdonjog pedig követi a kompozitot: a TPDFlibCompositeWatermark.Destroy felszabadítja a gyermekeit, így Ön egyszer szabadítja fel a kompozitot és semmi mást, a fenti példához hasonlóan
Ismerendő korlátok
Két valós korlát érvényes, és mindkettő a működési mechanizmusból adódik. Először is, a rögzítés csak az oldal tartalomfolyamát és erőforrásait csomagolja be. A megjegyzések (annotations), linkek, űrlapmezők és kommentek különálló objektumként élnek az oldalszótárban, nem pedig a tartalomfolyamban, így nem kerülnek át az XObject-be; az összefűzött elrendezés hordozza a látható oldaltartalmat, de a források interaktív rétegét nem. Másodszor, a kilencpontos szövegpozicionálás csak közelítés: teljes elrendezési motor nélkül a könyvtár nem tudja a karakterlánc pontos leképezett szélességét, ezért a szövegdobozt az oldalszélesség 40%-ára becsüli az olyan pozíciók feloldásakor, mint a wpCenter. Ez elég pontos egy rövid címke középre igazításához, de a hosszú karakterláncok képpont-pontos elhelyezéséhez váltson a wpCustom-ra, és számítsa ki magának a koordinátákat
A méret itt nem jelent gyakorlati korlátot, mivel a rögzítés és az összefűzés objektumhivatkozásokat manipulál ahelyett, hogy újra kódolná az oldaltartalmat; ha a források több száz megabájtosak, akkor az összefűzés előtt a nagy fájlok közvetlen hozzáféréssel történő összefűzéséről és felosztásáról szóló útmutatóban leírt módszert kell alkalmazni. Az itt bemutatott összefűző függvényer és vízjel-sablon osztályok a Delphi, C# és VB.NET rendszerekhez készült aktuális losLab PDF Library-ben találhatók, az alacsonyabb szintű CapturePage, DrawCapturedPage és DrawCapturedPageMatrix primitívek mellett, ha olyan elrendezésre van szüksége, amelyet a három kész összefűző hívás nem fed le