Brūkšniavimas, atvaizduojamas kaip vienas plokščias pilkas blokas, — klasikinis plytelinio rašto gedimas. HotPDF, natyvus VCL PDF komponentas Delphi ir C++Builder platformoms, dažo PatternType 1 paversdamas dabartinį taką laikinu apkarpymu ir pakartotinai paleisdamas rašto turinio srautą po vieną kartą kiekvienai matomai plytelei, o rašto pasirinkimas laikomas grafikos būsenoje ir atkuriamas su q ir Q
Simptomai pasireiškia dviem skoniais, ir jie atrodo nesusiję, kol nežinote priežasties. CAD brėžinys praranda savo pjūvio brūkšniavimą ir grįžta kaip vientisi užpildymai, nes atvaizdavimo mechanizmas raštą suvedė į vidutinę spalvą ir ją nudažė. Arba brūkšniavimas pabėga: antraštinis blokas, kuris turėtų būti paprastai baltas, perima įstrižas linijas iš detalės vaizdo, buvusio kelis takus anksčiau. Abu tai — rašto būsenos problemos, ir tik viena jų susijusi apskritai su plytelių piešimu
Kodėl plytelinis raštas persilieja į kitą taką?
Todėl, kad pasirinktas rašto pavadinimas yra grafikos būsenos dalis, ne operatoriaus, kuris jį panaudojo, savybė. ISO 32000-1 §8.6.6.2 apibrėžia Pattern spalvų erdvę kaip tokią, kurios spalvos reikšmė yra rašto pavadinimas, pateiktas scn ar SCN, ir kiekvienas kitas spalvos būsenos komponentas išsaugomas q ir atkuriamas Q. Rašto pavadinimas turi laikytis tos pačios taisyklės. HotPDF jį laiko būsenos įraše kaip FillPatternName ir StrokePatternName, kartu su užpildymo ir apvedimo spalvų erdvės šeima, todėl Q grąžina ankstesnį pasirinkimą lygiai taip pat, kaip grąžina ankstesnį CTM
Laikykite tą pavadinimą vietiniame kintamajame operatoriaus dispečeryje, ir jis išgyvens kiekvieną Q sraute. Gedimas tada iškyla kur nors netikėtoje vietoje: formos XObject, nupieštas po raštu papuoštu taku, paveldi rašto pasirinkimą, kurio jo pačios turinio srautas niekada nepadarė, o jo užpildymai išeina brūkšniuoti. Įdėtinės formos tai dar pablogina, nes kiekvienas įdėjimo lygis stumia ir traukia būseną, kurios klaidojantis kintamasis ignoruoja. Nespalvinės erdvės nustatymas su cs ar CS, arba paprasto g / rg / k išleidimas, taip pat turi išvalyti rašto pavadinimą, kitaip pasenęs pasirinkimas pergyvena spalvų erdvę, kuri jam suteikė prasmę
q
/Pattern cs % pattern colour space, ISO 32000-1 8.6.6.2
/P1 scn % coloured tiling pattern, PaintType 1
10 10 200 120 re f % this rectangle is hatched
Q
0 0 300 200 re f % must be black again, not hatched
q
/Cs2 cs % [/Pattern /DeviceCMYK] array
0 0.6 1 0 /P2 scn % uncoloured pattern plus its underlying colour
20 20 160 90 re f*
Q
Raštas dažomas per apkarpymą, niekada kaip užpildymas
Teisingas modelis — atimtinis: apribokite įrenginio apkarpymą iki dažomos figūros, tada paleiskite rašto turinį jo viduje. HotPDF niekada pirmiausia nepiešia vientiso apytikslio varianto ir jo neuždažo, nes tarpinis vientisas variantas būtų matomas per tarpus tarp plytelių ir konfliktuotų su bet kokiu skaidrumu plytelės turinyje. §8.7.3.2 aprašo plytelinį raštą kaip turinio srautą, kartojamą fiksuotais horizontaliais ir vertikaliais intervalais, o kartojimas turi prasmę tik prieš apkarpymą, jau turintį teisingą formą. Užpildymams pavertimas tiesioginis: HPDFSelectFillPathClip nustato daugiakampio užpildymo režimą į ALTERNATE operatoriams f*, B* ir b* ir į WINDING nulinio-ne variantams, sukuria GDI taką ir sujungia jį su apkarpymu naudojant SelectClipPath. Ta viena eilutė kaip tik ir daro, kad lyginis-nelyginis raštu užpildytas plotas paliktų tas pačias skyles, kaip lyginis-nelyginis vientisas užpildymas, o to kaip tik ir reikia spurgo formos brūkšniuotam plotui
Apvedimai — dalis, kurią lengva sugadinti. Apvedimo takas neturi vidaus, todėl paties tako sujungimas su apkarpymu duoda tuščią plotą, ir niekas nenudažoma. HPDFSelectStrokePathClip todėl pirmiausia iš dabartinės būsenos sukuria geometrinį plunksnakotį, naudodamas PS_GEOMETRIC su galūnės forma iš J, jungtimi iš j, briaunos riba iš M, ir PS_USERSTYLE, kai aktyvus brūkšnių masyvas, tada iškviečia WidenPath, kad paverstų apvedimo kontūrą užpildomu plotu prieš apkarpymą. Galūnės, jungties, briaunos ribos ir brūkšnio elgesys ant rašto apvedimo tako tada atitinka įprastą apvedimą pagal konstrukciją, ne pagal antrą realizaciją. Čia gyvena dvi sąžiningos ribos: linijos plotis, mažesnis nei vienas įrenginio vienetas, apribojamas iki vieno pikselio, o brūkšnių masyvas apkarpomas prie šešiolikos įrašų, kuri yra ExtCreatePen priimama viršutinė riba
Kurios plytelės iš tikrųjų matomos?
Matomas intervalas gaunamas paleidžiant transformaciją atgal. Plytelių išdėstymas vyksta rašto erdvėje, bet vienintelis dalykas, žinantis, kiek puslapio yra liečiama, — įrenginio apkarpymo dėžė, esanti įrenginio erdvėje. HotPDF sudaro BaseMatrix := CTM * PatternMatrix, ją apverčia ir atvaizduoja keturis GDI apkarpymo dėžės kampus atgal per atvirkštinę matricą. Ašiai lygiuoti tų keturių atvaizduotų kampų kraštai duoda rašto erdvės stačiakampį, kurį galima būtų padengti, o šio stačiakampio dalijimas iš XStep ir YStep pagal rašto BBox duoda uždarus indeksų intervalus. Kiekviena ląstelė tada atvaizduojama su CTM iš CTM * PatternMatrix * Translate(i * XStep, j * YStep) ir apkarpoma antrą kartą pagal savo pačios transformuotą BBox daugiakampį. Šis antras apkarpymas svarbus, kai XStep mažesnis nei ribos dėžės plotis, tai — kaip išreiškiami persidengiantys plytelių dizainai; be jo, kaimyninės ląstelės tapytų viena ant kitos už savo deklaruotos apimties ribų. Jei ląstelės apkarpymas grįžta kaip NULLREGION, ląstelė praleidžiama, nieko neanalizuojant ir nevykdant
// Map the device clip box back into pattern space through the inverse of
// CTM * PatternMatrix, then convert those bounds into tile index ranges.
BaseMatrix := HPDFMatMul(FGSStack.State.CTM, PatternMatrix);
if not HPDFMatInvert(BaseMatrix, InverseMatrix) then Exit; // singular: refuse
if GetClipBox(FDC, ClipRect) = ERROR then Exit;
// MinX..MaxY are the axis-aligned bounds of the four mapped clip corners.
I0 := Floor((MinX - BBox[2]) / StepXAbs);
I1 := Ceil ((MaxX - BBox[0]) / StepXAbs);
J0 := Floor((MinY - BBox[3]) / StepYAbs);
J1 := Ceil ((MaxY - BBox[1]) / StepYAbs);
PlannedTiles := Int64(I1 - I0 + 1) * Int64(J1 - J0 + 1);
if (PlannedTiles <= 0) or (PlannedTiles > FPatternTilesRemaining) then Exit;
Dec(FPatternTilesRemaining, Integer(PlannedTiles));
Nespalvoti raštai ir spalva, ateinanti iš išorės
PaintType 2 raštas neša formą, bet ne spalvą, o spalva atkeliauja kartu su rašto pavadinimu. §8.7.3.2 nurodo, kad nespalvotas raštas naudojamas tik su Pattern spalvų erdve, deklaruojančia pagrindinę erdvę, todėl scn pirmiausia gauna komponentų reikšmes, o rašto pavadinimą — paskiausiai. HotPDF šiuos komponentus išsprendžia per pagrindinę erdvę, saugomą rašto spalvos erdvės įraše, o tai reiškia, kad nespalvotas brūkšniavimas gali būti nuspalvintas Separation rašalu ar DeviceN deriniu, kaip ir bet koks kitas užpildymas; šio sprendimo mechanika aprašyta straipsnyje apie Separation ir DeviceN specialiųjų spalvų atvaizdavimą. Plytelės viduje du dažymo tipai smarkiai skiriasi. Prie PaintType 2 atvaizdavimo mechanizmas nustato spalvos operatoriaus slopinimo vėliavėlę plytelės trukmei, todėl bet koks g, rg, k ar scn rašto turinyje ignoruojamas, ir kiekvienas ženklas gauna iš išorės pateiktą spalvą. Prie PaintType 1 galioja priešingai: užpildymo ir apvedimo būsena atstatoma į PDF numatytąsias reikšmes, DeviceGray juoda su tapatybine spalvų erdve, o plytelė nuspalvina save. Šio atstatymo praleidimas leidžia spalvai, kuri atsitiktinai buvo aktyvi f operatoriaus metu, prasiskverbti į raštą, kuris turėjo būti savarankiškai apibūdinamas
Kodėl grafikos būsenos steko gylis turi būti atkurtas po kiekvienos plytelės?
Todėl, kad rašto turinio srautas gali būti nesubalansuotas, ir žala kaupiasi per ląsteles. Plytelė, kurios srautas turi tris q operatorius ir du Q operatorius, palieka steką vienu kadru gilesnį, nei buvo pradžioje. Atkurkite tik dabartinį būsenos įrašą tarp ląstelių, ir gylis toliau auga, todėl ląstelė numeris du šimtai vykdoma iš steko kadro, priklausančio ląstelei numeris šimtas devyniasdešimt devyni, su bet kokiu CTM ir apkarpymu, kurį tas kadras nešė. HotPDF todėl padaro būsenos įrašo ir steko gylio nuotrauką prieš plytelių ciklą ir iškviečia RestoreSnapshot kiekvienos iteracijos pradžioje, kuri sutrumpina steką iki išsaugoto ilgio ir vienu žingsniu atkuria išsaugotą būseną. Puslapio Resources žodynas ir spalvos operatoriaus slopinimo vėliavėlė atkuriami toje pačioje riboje, nes plytelė gali nurodyti savo pačios resursus ir negali jų perduoti kaimynei. GDI apkarpymo būsena gauna tą pačią priežiūrą per SaveDC / RestoreDC porą aplink kiekvieną ląstelę, todėl plytelė, įdiegianti savo pačios W n apkarpymą, negali sumažinti ploto, prieinamo kitai
Biudžetai, atsisakymai, ir kas nebus nupiešta
Plyteliniai raštai — lengviausia vieta PDF faile parašyti paslaugos atsisakymo failą, todėl ribos — griežti skaičiai, ne euristika. Rašto įdėjimas apribotas iki 4 gylio, ta pati apsauga, naudojama Form XObject rekursijai, ir tai sustabdo raštą, kuris nurodo pats į save per savo pačios resursų žodyną. Vienas tako dažymas gali vykdyti daugiausiai 16 384 plyteles iš viso, skaičiuojant įdėtinius raštus žemyn ir atstatant tik tada, kai prasideda išoriškiausio rašto dažymas. Plytelių tinklas, kurio planuojamas ląstelių skaičius viršija tai, kas liko iš to biudžeto, atmetamas iš karto, prieš paleidžiant nė vieną ląstelę
Degeneruota geometrija atmetama, ne aproksimuojama. Trūkstamas ar nulinio ploto BBox, XStep ar YStep, kurio dydis mažesnis nei 1e-6, CTM * PatternMatrix sandauga be atvirkštinės, atvaizduotos apkarpymo koordinatės virš 1e9, ar indekso dydis virš milijono — visa tai sukelia, kad rašto dažymas grįžta nieko nenupiešęs. Rezultatas — nenudažytas plotas vietoj pakibusio atvaizdavimo gijos, o tai — kompromisas, kurio norite partijos konverteryje. Našumas kyla iš vieno sprendimo: rašto srautas analizuojamas vieną kartą dažymui su HPDFTokenizeContentStream, o žetonų masyvas naudojamas pakartotinai kiekvienai matomai ląstelei, todėl plytelių skaičius padaugina vykdymo kainą, bet niekada — analizės kainą
Raštu papuošto puslapio atvaizdavimas iš Delphi
Niekas apie rašto palaikymą nekeičia iškviečiančio kodo. Įkelkite dokumentą, paprašykite puslapio, ir plytelinis darbas vyksta turinio srauto interpretatoriaus viduje, kurį jau valdo puslapio-į-bitmap atvaizdavimas. Tas pats interpretatorius maitina bitmap, metafailo ir spausdintuvo įrenginio kontekstus, todėl brūkšniuotas brėžinys, atrodantis teisingai peržiūros miniatiūroje, spausdinamas su ta pačia plytelių geometrija. PatternType 2 šešėliavimo raštai eina kitu šakos keliu, kuris dalijasi savo vertinimo keliu su paprastu sh operatoriumi, aprašytu detaliai straipsnyje apie ašinio ir spindulinio šešėliavimo atvaizdavimą
var
Pdf: THotPDF;
Bmp: TBitmap;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('assembly-drawing.pdf') > 0 then
begin
// Section hatching that previously flattened to a solid block now
// replays the tile content once per visible cell.
Bmp := Pdf.RenderLoadedPageToBitmap(0, 200);
if Assigned(Bmp) then
try
Bmp.SaveToFile('sheet1.bmp');
finally
Bmp.Free;
end;
end;
finally
Pdf.Free;
end;
end;
Kai raštu papuoštas plotas vis tiek atrodo neteisingai, patikrinkite tris gedimo klases šia tvarka. Visiškai tuščias plotas paprastai reiškia atsisakymą: patikrinkite XStep, YStep ir BBox dėl degeneruotų reikšmių, arba suskaičiuokite plyteles, kurių prireiktų tinklui, pagal 16 384 ribą. Vienoje plokščioje spalvoje nudažytas plotas reiškia, kad rašto pavadinimas taip ir nepasiekė dažymo operatoriaus, o tai nurodo į cs ir scn tvarką sraute. Raštas, pasirodantis ten, kur jam nepriklauso, reiškia būsenos atkūrimo problemą, ir vieta, į kurią reikia žiūrėti, — q / Q tvarkymas aplink formą ar taką, kuris jį paveldėjo
Plyteliniai raštai — vienas iš tų PDF funkcijų, likusių nematomų, kol failas, kuriam jų reikia, nenusileidžia į jūsų pašto dėžutę, ir tada jie tampa visu darbu. Jei kuriate brėžinių žiūrykles, inžinerinių dokumentų konverterius ar ataskaitų atvaizduotojus Delphi ar C++Builder platformose, visas komponentas ir jo atvaizdavimo API dokumentuoti puslapyje HotPDF Delphi PDF komponentas