Egy olyan PDF, amelynek fejléce Word- vagy Excel-stílusú színátmenetes háttérrel rendelkezik, képpé renderelve korábban egy üres fehér téglalappal tért vissza ott, ahol a színkeveréknek kellene lennie. A HotPDF oldalrenderelője mostantól tiszteletben tartja a PDF sh (shading) operátorát a 2-es típusú axiális és a 3-as típusú radiális színátmeneteknél: kiértékeli az árnyalás függvényét a színátmenet tengelye mentén, és megfesti a keveréket, míg a korábbi verziók csendben elhagyták ezt az operátort, és a területet papírfehéren hagyták. A szinte minden irodai dokumentum színátmenetét lefedő két árnyalási típus támogatott; a háló (mesh) típusok nem, és ez a cikk őszintén bemutatja, hol húzódik ez a határvonal
Miért renderelődik a PDF színátmenet fehér dobozként?
A PDF színátmenet vektoros konstrukció, nem pedig egy bitkép, amelyet a renderelő közvetlenül át tudna másolni. Egy árnyalási szótár (shading dictionary, ISO 32000-1 §8.7.4.5) leírja a geometriát – egy tengelyt vagy egy körpárt a Coords tömbben –, valamint egy színfüggvényt, az sh operátor pedig lefesti ezt az árnyalást az aktuális vágási tartományban (clip region). Ugyanezt a grafikai modellt mutatja be a HotPDF is, amikor útvonalakat és kitöltéseket rajzol az oldalvászonra. A HotPDF oldalrenderelője operátorról operátorra járja be a tartalomfolyamot, és minden olyan operátort kihagy, amelyhez nincs megvalósított kódútvonala, így az oldal többi része továbbra is renderelődik. A 2.335.0 verzió előtt az sh ebben a kihagyott készletben élt: a fejléc vagy a teljes oldalas színátmenet semmivel sem járult hozzá a kimenethez, így a háttér fehérként látszódott át. A fájl soha nem volt sérült. A renderelőnek egyszerűen nem volt kezelője erre az egy operátorra, és a fehér doboz pontosan az, ahogyan egy hiányzó kezelő kinéz
Az árnyalás mögötti függvénykiértékelési lánc
Az árnyalást nem lehet megfesteni, amíg a függvénye ki nincs értékelve, így ennek a gépezetnek kellett először megérkeznie. A 2-es típusú axiális és a 3-as típusú radiális árnyalások mindegyike tartalmaz egy /Function bejegyzést, amely a színátmenet menti parametrikus pozíciót képezi le színné (ISO 32000-1 §7.10), a HotPDF függvénykiértékelője pedig feloldja a FunctionType-ot, és ennek megfelelően irányítja a végrehajtást. A 2-es típusú exponenciális interpoláció (§7.10.3) kiszámítja a C0 + t^N * (C1 - C0) értéket a Domain és Range korlátozásával; a 0-s típusú mintavételezett függvények (§7.10.2) 8, 16 vagy 32 bites minták rácsát olvassák le, és az Encode térképen keresztül kiválasztják a legközelebbit, amit részletesen tárgyal a 0-s típusú mintavételezett színkeresésekről szóló bemutatónk; a 3-as típusú összefűző (stitching) függvények (§7.10.4) kiválasztanak egy alfüggvényt a Bounds tömb alapján, és rekurzív módon lépnek be abba. A 4-es típusú PostScript kalkulátor függvények (§7.10.5) nem kerülnek kiértékelésre – kecsesen meghiúsult kiértékeléssé fokozódnak le a hibás szín helyett, igazodva a HotPDF által a renderelési útvonalon alkalmazott konzervatív irányelvhez. Ez a kiértékelő a 2.334.0 verzióban érkezett, egy kiadással magát az operátort megelőzően, mivel az árnyalásfestő csak annyira jó, mint a mögötte álló függvény
Hogyan alakítja a HotPDF a folytonos színátmenetet pixelekké?
A HotPDF a folytonos keveréket egyszínű sávok véges sorozatával közelíti meg. Az árnyalásfestő végigmegy a színátmenet tengelyén, felosztja azt legfeljebb 64 sávra – kevesebbre, ha a tengely rövid eszközpixelekben –, kiértékeli a függvényt az egyes sávok parametrikus pozíciójában, és kitölt egy, a tengelyre merőleges téglalapot egy tömör ecsettel. A kompromisszum a sávok száma és a simaság között van: több sáv szorosabban követi a keveréket, de több kitöltést igényel, és a 64 a szándékos felső határ. Mivel a szám az eszközpixelekben mért tengelyhosszal is skálázódik, a felbontás számít. Ugyanazon oldal nagyobb DPI-vel történő renderelése meghosszabbítja a tengelyt, így egy rövid színátmenet sávokat nyer, és a csíkozás lágyul, amíg el nem éri a felső határt
// The shading discretizer uses up to 64 color bands along the gradient
// axis, but never more than the axis is long in device pixels. Rendering
// the same page at a higher DPI lengthens that axis, so a short gradient
// gains bands and the banding softens until the 64-band ceiling is hit.
Thumb := Pdf.RenderLoadedPageToBitmap(PageIndex, 96); // coarser bands
Proof := Pdf.RenderLoadedPageToBitmap(PageIndex, 300); // up to 64 bands
Árnyékolt oldal renderelése bitképpé
A nyilvános belépési pont változatlan: a RenderLoadedPageToBitmap egy 0-alapú oldalindexet és egy DPI értéket vesz át, egy hívó által birtokolt 24 bites bitképet ad vissza, és hiba esetén nil értékkel tér vissza kivétel kiváltása helyett, így a színátmenet támogatása transzparens a meglévő kódjai számára. Egy oldal, amely korábban üresen renderelte a színátmenetes fejlécét, most ugyanazt a bitképet adja vissza a befestett keverékkel, és nincs szükség API változtatásra a használatához. Az egyetlen dolog, amit érdemes megjegyezni, a tulajdonjog: a hívó szabadítja fel a visszaadott bitképet. A teljes renderelési folyamatot – a tartalomfolyam értelmezését, a beágyazott glifeket és az oldal-gyorsítótárazást – a PDF oldalak bitképpé rendereléséről szóló útmutató Delphiben tárgyalja
var
Pdf: THotPDF;
Bmp: TBitmap;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('quarterly-report.pdf') > 0 then
begin
// Page 1 (zero-based) at 150 DPI. A gradient-filled header that
// used to come back blank now carries its color blend.
Bmp := Pdf.RenderLoadedPageToBitmap(0, 150);
if Assigned(Bmp) then
try
Bmp.SaveToFile('page1.bmp');
finally
Bmp.Free;
end;
end;
finally
Pdf.Free;
end;
end;
Egy egyszerű regressziós teszt adódik ugyanebből a hívásból. Renderelje le az oldalt, vegyen mintát egy pixelből ott, ahová a színátmenetes sáv tartozik, és ellenőrizze, hogy az már nem a papírfehér szín, amelyre a renderelő korábban visszaesett – egy egysoros ellenőrzés, amely elcsípi a régi, művelet nélküli viselkedéshez való csendes visszatérést
Bmp := Pdf.RenderLoadedPageToBitmap(0, 150);
if Assigned(Bmp) then
try
// True when the sh operator painted; False if the region fell back to white.
HeaderPainted := Bmp.Canvas.Pixels[Bmp.Width div 2, 8] <> clWhite;
finally
Bmp.Free;
end;
Amit a HotPDF nem rajzol ki: hálós árnyalások és vágási élek
A négy hálós árnyalási típus kívül esik a hatókörön, és ezt a dokumentum tervezésénél érdemes tudni. A szabad formájú Gouraud háromszöghálók (Type 4), a rács formájú Gouraud hálók (Type 5), a Coons folt (patch) hálók (Type 6) és a tenzortermék-folt hálók (Type 7), amelyek az ISO 32000-1 §8.7.4.5.5 - §8.7.4.5.8 bekezdésekben vannak definiálva, nem kerülnek renderelésre; az ezeket használó oldal továbbra is renderelődik, csak az a terület marad változatlanul. Két további kényes pontot érdemes nyíltan kimondani. A sávok téglalapjai az árnyalás sávját fedik le, nem pedig pontosan az aktuális vágási útvonalra (clip path) vannak vágva, így egy lekerekített vagy szabálytalan alakúra maszkolt színátmenet annak befoglaló sávjaként rajzolódik ki, amíg a pontos tartományvágás meg nem érkezik egy későbbi körben. A HotPDF azt is feltételezi, hogy a függvény kimenete RGB vagy szürkeárnyalatos, így a CMYK-ban vagy egzotikus színtérben megírt árnyalás inkább csak közelítve van, mintsem színkezelve. A legtöbb Delphi és C++Builder csapat által feldolgozott dokumentumhoz – jelentésekhez, számlákhoz, kimutatásokhoz és PDF-be exportált diavetítésekhez – az axiális és radiális árnyalások gyakorlatilag lefednek minden színátmenetet, amellyel találkozni fog, a háló-intenzív terveket pedig inkább előnézetként kell kezelni, mintsem pontos nyomatként
A HotPDF oldalrenderelője, az itt leírt sh operátor támogatás és az alatta lévő 0-s, 2-es és 3-as típusú függvénykiértékelő a Delphihez és C++Builderhez készült HotPDF Component részeként kerül forgalomba – ez egy natív VCL könyvtár külső DLL-függőségek nélkül, amely egyetlen csomagban fedi le a PDF létrehozását, szerkesztését, szövegkivonását és oldalrenderelését