Un PDF al cărui antet conține un fundal în degrade în stil Word sau Excel, randat într-o imagine, returna anterior un dreptunghi alb gol în locul unde trebuia să fie amestecul de culori. Generatorul de randare al paginilor HotPDF respectă acum operatorul PDF sh (shading) pentru degradeuri axiale de tip 2 și radiale de tip 3: evaluează funcția degradeului de-a lungul axei acestuia și desenează amestecul, în timp ce versiunile anterioare ignorau operatorul în mod silențios și lăsau regiunea complet albă. Cele două tipuri de degradeuri care acoperă aproape orice document de birou sunt incluse; tipurile mesh (rețea) nu sunt incluse, iar acest articol prezintă în mod onest unde se află această linie de demarcație
De ce se randează un degrade PDF ca o casetă albă?
Un degrade PDF este o construcție vectorială, nu o imagine bitmap pe care generatorul de randare o poate transfera (blit). Un dicționar de degrade (ISO 32000-1 §8.7.4.5) descrie geometria — o axă sau o pereche de cercuri în tabloul Coords — plus o funcție de culoare, iar operatorul sh desenează acea umbră în regiunea curentă de tăiere (clip region), același model grafic pe care HotPDF îl expune când desenați căi și umpleri pe canvas-ul paginii. Generatorul de pagini HotPDF parcurge fluxul de conținut operator cu operator, iar orice operator pentru care nu are o cale de execuție este ignorat, astfel încât restul paginii să se randeze în continuare. Înainte de versiunea 2.335.0, sh făcea parte din acel set ignorat: un antet sau un degrade pe întreaga pagină nu contribuia cu nimic la rezultat, așa că fundalul apărea alb. Fișierul nu a fost niciodată corupt. Generatorul pur și simplu nu avea un handler pentru acel operator, iar o casetă albă este exact aspectul pe care îl are lipsa unui handler
Lanțul de evaluare a funcțiilor din spatele unui degrade
Un degrade nu poate fi desenat până când funcția sa nu este evaluată, așa că acel mecanism a trebuit să fie implementat primul. Degradeurile axiale de tip 2 și radiale de tip 3 conțin ambele o funcție /Function care mapează o poziție parametrică de-a lungul gradientului într-o culoare (ISO 32000-1 §7.10), iar evaluatorul de funcții al HotPDF identifică tipul FunctionType și direcționează execuția. Interpolarea exponențială de tip 2 (§7.10.3) calculează C0 + t^N * (C1 - C0) cu limitare pentru Domain și Range; funcțiile eșantionate de tip 0 (§7.10.2) citesc o grilă de eșantioane pe 8, 16 sau 32 de biți și le aleg pe cele mai apropiate prin harta Encode, caz descris în detaliu în ghidul nostru despre căutările de culori eșantionate de tip 0; funcțiile de îmbinare (stitching) de tip 3 (§7.10.4) selectează o sub-funcție prin tabloul Bounds și revin recursiv în aceasta. Funcțiile calculatorului PostScript de tip 4 (§7.10.5) nu sunt evaluate — ele eșuează în mod controlat la o evaluare nereușită, mai degrabă decât la o culoare greșită, în conformitate cu politica conservatoare pe care HotPDF o aplică pe calea de randare. Acest evaluator a fost livrat în versiunea 2.334.0, cu o versiune înainte de operatorul în sine, deoarece desenarea degradeurilor este la fel de bună ca funcția pe care se bazează
Cum transformă HotPDF un degrade continuu în pixeli?
HotPDF aproximează amestecul continuu printr-un număr finit de benzi de culoare solidă. Desenatorul de degradeuri parcurge axa degradeului, o împarte în până la 64 de benzi — mai puține când axa este scurtă în pixeli de dispozitiv —, evaluează funcția la poziția parametrică a fiecărei benzi și umple un dreptunghi perpendicular pe axă cu o pensulă solidă. Compromisul este între numărul de benzi și finețe: mai multe benzi urmăresc mai fidel amestecul, dar costă mai multe umpleri, iar 64 este limita stabilită deliberat. Deoarece numărul depinde de asemenea de lungimea axei în pixeli de dispozitiv, rezoluția contează. Randarea aceleiași pagini la un DPI mai ridicat prelungește axa, astfel încât un degrade scurt câștigă benzi și dungile sale se atenuează până când se atinge limita de 64 de benzi
// 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
Randarea unei pagini cu degrade la o imagine bitmap
Punctul public de intrare este neschimbat: RenderLoadedPageToBitmap primește un indice de pagină bazat pe zero și o valoare DPI, returnează un bitmap pe 24 de biți deținut de apelant și returnează nil în caz de eșec în loc să genereze o eroare, astfel încât suportul pentru degradeuri este transparent pentru codul pe care îl aveți deja. O pagină care randa anterior antetul în degrade ca fiind gol returnează acum același bitmap cu amestecul desenat, nefiind necesară nicio modificare a API-ului. Singurul lucru care merită reținut este proprietatea: apelantul eliberează bitmap-ul returnat. Întregul flux de randare — interpretarea fluxului de conținut, glifele încorporate și stocarea paginilor în cache — este acoperit în ghidul pentru randarea paginilor PDF la o imagine bitmap în Delphi
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;
A cheap regression guard falls out of the same call. Render the page, sample a pixel where the gradient band belongs, and confirm it is no longer the paper-white the renderer used to fall back to — a one-line check that catches a silent return to the old no-op behavior
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;
Ce nu desenează HotPDF: degradeuri mesh și margini decupate
Cele patru tipuri de degradeuri mesh (rețea) nu sunt incluse în specificații, iar documentele trebuie să fie pregătite pentru acest lucru. Rețelele de triunghiuri Gouraud în formă liberă (tip 4), rețelele Gouraud în formă de rețea (tip 5), rețelele de petice Coons (tip 6) și rețelele de petice cu produs tensorial (tip 7), definite în ISO 32000-1 §8.7.4.5.5 până la §8.7.4.5.8, nu sunt randate; o pagină care le folosește se randează în continuare, doar acea regiune fiind lăsată ca atare. Încă două detalii merită menționate clar. Dreptunghiurile de bandă acoperă banda degradeului în loc să fie decupate exact după calea curentă de decupare (clip path), astfel încât un degrade mascat într-o formă rotunjită sau neregulată se desenează ca o bandă de delimitare până când decuparea precisă a regiunilor va fi implementată într-o versiune ulterioară. HotPDF presupune de asemenea că ieșirea funcției este RGB sau grayscale (nivele de gri), deci un degrade creat în CMYK sau într-un spațiu de culoare exotic este aproximat mai degrabă decât gestionat colorimetric. Pentru documentele pe care majoritatea echipelor Delphi și C++Builder le procesează de fapt — rapoarte, facturi, extrase și prezentări exportate în PDF —, degradeurile axiale și radiale acoperă practic orice degrade întâlnit, iar schițele de design cu multe rețele mesh trebuie tratate ca o previzualizare, nu ca o dovadă exactă
Generatorul de pagini HotPDF, suportul pentru operatorul sh descris aici și evaluatorul de funcții de tip 0/2/3 pe care se bazează sunt livrate ca parte a HotPDF Component pentru Delphi și C++Builder — o bibliotecă nativă VCL fără dependențe de DLL-uri externe, ce acoperă crearea, editarea, extragerea textului și randarea paginilor într-un singur pachet