Techninis straipsnis

PDF gradientų atvaizdavimas Delphi aplinkoje: ašiniai ir radialiniai

PDF failas, kurio antraštėje yra „Word“ arba „Excel“ stiliaus gradientinis fonas, atvaizduotas į vaizdą, anksčiau grąžindavo tuščią baltą stačiakampį ten, kur turėtų būti spalvų perėjimas. HotPDF puslapio atvaizduotojas dabar atsižvelgia į PDF sh (šešėliavimo) operatorių, skirtą 2 tipo ašiniams ir 3 tipo radialiniams gradientams: jis įvertina šešėliavimo funkciją išilgai gradiento ašies ir nupiešia spalvų perėjimą, kai ankstesnės versijos tyliai praleisdavo šį operatorių ir palikdavo sritį baltą kaip popierius. Du šešėliavimo tipai, apimantys beveik visus biuro dokumentų gradientus, yra palaikomi; tinklo tipai — ne, ir šiame straipsnyje sąžiningai nurodoma ši riba

Kodėl PDF gradientas atvaizduojamas kaip balta dėžutė?

PDF gradientas yra vektorinė konstrukcija, o ne taškinis vaizdas, kurį atvaizduotojas gali tiesiog perkelti. Šešėliavimo žodynas (ISO 32000-1 §8.7.4.5) aprašo geometriją — ašį arba apskritimų porą Coords masyve — bei spalvų funkciją, o sh operatorius nupiešia šį šešėliavimą esamoje kirpimo srityje; tai yra tas pats grafikos modelis, kurį HotPDF pateikia, kai jūs piešiate kelius ir užpildus puslapio drobėje. HotPDF puslapio atvaizduotojas pereina turinio srautą po vieną operatorių, o bet kuris operatorius, kuriam jis neturi kodo kelio, yra praleidžiamas, kad likusi puslapio dalis vis tiek būtų atvaizduojama. Iki 2.335.0 versijos sh buvo tame praleistų operatorių rinkinyje: antraštės arba viso puslapio gradientas nieko neprisidėdavo prie išvesties, todėl fonas persišviesdavo kaip baltas. Failas niekada nebuvo sugadintas. Atvaizduotojas tiesiog neturėjo to vieno operatoriaus apdorojimo programos, o balta dėžutė yra būtent tai, kaip atrodo trūkstama apdorojimo programa

Funkcijų įvertinimo grandinė už šešėliavimo

Šešėliavimas negali būti nupieštas, kol neįvertinta jo funkcija, zodžiu, šis mechanizmas turėjo būti įdiegtas pirmiausia. Tiek 2 tipo ašiniai, tiek 3 tipo radialiniai šešėliavimai turi /Function, kuri susieja parametrinę padėtį išilgai gradiento su spalva (ISO 32000-1 §7.10), o HotPDF funkcijų įvertintojas nustato FunctionType ir nukreipia į jį. 2 tipo eksponentinė interpoliacija (§7.10.3) apskaičiuoja C0 + t^N * (C1 - C0) su Domain ir Range ribojimais; 0 tipo diskretizuotos funkcijos (§7.10.2) nuskaito 8, 16 arba 32 bitų pavyzdžių tinklelį ir pasirenka artimiausią per Encode žemėlapį — atvejis, išsamiai aprašytas mūsų straipsnyje apie 0 tipo diskretizuotų spalvų paieškas; 3 tipo sujungimo funkcijos (§7.10.4) pasirenka subfunkciją pagal Bounds masyvą ir vykdo rekursiją į ją. 4 tipo „PostScript“ skaičiuoklio funkcijos (§7.10.5) nėra vertinamos — jos tiesiog virsta nesėkmingu įvertinimu, o ne klaidinga spalva, atitinkančia konservatyvią politiką, kurios HotPDF laikosi visame atvaizdavimo kelyje. Šis vertintojas pasirodė 2.334.0 versijoje, viena versija anksčiau už patį operatorių, nes šešėliavimo piešėjas yra toks geras, kokia gera yra po juo esanti funkcija

Kaip HotPDF paverčia tolygų gradientą pikseliais?

HotPDF priartina tolygų perėjimą naudodama ribotą vientisų spalvų juostų rinkinį. Šešėliavimo piešėjas pereina gradiento ašį, padalija ją į iki 64 juostų — mažiau, kai ašis yra trumpa įrenginio pikseliais —, įvertina funkciją kiekvienos juostos parametrinėje padėtyje ir užpildo stačiakampį, statmeną ašiai, vientisu teptuku. Kompromisas yra juostų skaičius prieš tolygumą: daugiau juostų tiksliau seka perėjimą, tačiau kainuoja daugiau užpildymų, o 64 yra sąmoningai nustatyta riba. Kadangi skaičius taip pat skaluojasi su ašies ilgiu įrenginio pikseliais, raiška yra svarbi. To paties puslapio atvaizdavimas su didesniu DPI pailgina ašį, todėl trumpas gradientas gauna daugiau juostų ir jo dryžiai sušvelnėja, kol pasiekiama 64 juostų riba

// 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

Šešėliuoto puslapio atvaizdavimas taškiniame vaizde

Viešas įėjimo taškas nesikeičia: RenderLoadedPageToBitmap priima nuliu pagrįstą puslapio indeksą bei DPI reikšmę, grąžina iškvietėjui priklausantį 24 bitų bitmap ir nesėkmės atveju grąžina nil, užuot kėlęs klaidą, todėl šešėliavimo palaikymas yra skaidrus jūsų jau turimam kodui. Puslapis, kurio gradientinė antraštė anksčiau būdavo atvaizduojama tuščia, dabar grąžina tą patį bitmap su nupieštu spalvų perėjimu, ir jokių API pakeitimų nereikia. Vienintelis dalykas, kurį verta atsiminti, yra nuosavybė: iškvietėjas pats atlaisvina grąžintą bitmap. Visas atvaizdavimo konvejeris — turinio srauto interpretavimas, įterptieji glifai ir puslapių talpinimas atmintyje — aprašytas straipsnyje PDF puslapių atvaizdavimo taškiniame vaizde Delphi aplinkoje vadovas

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;

Paprasta apsauga nuo regreso išplaukia iš to paties iškvietimo. Atvaizduokite puslapį, paimkite pikselio pavyzdį ten, kur turėtų būti gradiento juosta, ir įsitikinkite, kad tai nebėra popieriaus baltumas, kurį atvaizduotojas naudojo kaip atsarginį variantą — vienos eilutės patikrinimas, kuris užfiksuoja tylų sugrįžimą prie senos neveiklios elgsenos

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;

Ko HotPDF nepiešia: tinkliniai šešėliavimai ir kirpimo kraštai

Keturi tinklinio šešėliavimo tipai nepatenka į taikymo sritį, ir tai reikėtų žinoti iš anksto. Laisvos formos „Gouraud“ trikampių tinklai (4 tipas), gardelės formos „Gouraud“ tinklai (5 tipas), „Coons“ lopų tinklai (6 tipas) ir tenzorinių sandaugų lopų tinklai (7 tipas), apibrėžti ISO 32000-1 §8.7.4.5.5–§8.7.4.5.8, nėra atvaizduojami; puslapis, kuriame jie naudojami, vis tiek yra atvaizduojamas, tik ta sritis lieka tokia, kokia buvusi. Verta aiškiai įvardyti dar dvi ribas. Juostų stačiakampiai apima šešėliavimo juostą, o nėra tiksliai nukerpami pagal esamą kirpimo kelią, todėl gradientas, užmaskuotas į apvalią ar netaisyklingą formą, piešiamas kaip jį ribojanti juosta, kol vėlesniuose etapuose bus įdiegtas tikslus sričių kirpimas. Taip pat HotPDF daro prielaidą, kad funkcijos išvestis yra RGB arba pilkumo tonai, todėl šešėliavimas, sukurtas CMYK ar kitoje egzotinėje spalvų erdvėje, yra apytikslis, o ne valdomas spalvų valdymo sistema. Dokumentams, kuriuos iš tikrųjų apdoroja dauguma Delphi ir C++Builder komandų — ataskaitoms, sąskaitoms faktūroms, pareiškimams ir skaidrių rinkiniams, eksportuotiems į PDF —, ašiniai ir radialiniai perėjimai apima beveik visus gradientus, kuriuos sutiksite, o maketus su sudėtingais tinklais reikėtų traktuoti kaip peržiūrą, o ne kaip galutinį atspaudą

HotPDF puslapio atvaizduotojas, čia aprašytas sh operatoriaus palaikymas ir po juo esantis 0/2/3 tipo funkcijų įvertintojas platinami kaip HotPDF komponento, skirto Delphi ir C++Builder, dalis — vietinė VCL biblioteka be išorinių DLL priklausomybių, sujungianti PDF kūrimą, redagavimą, teksto išgavimą ir puslapių atvaizdavimą viename pakete