HotPDF pretvara XPS i OpenXPS pakete u PDF unutar Delphija i C++Buildera bez upravljačkog programa za ispis, preslikavajući svaku koordinatu fiksne stranice od 96 DPI kroz jednu matricu stranice s razmjerom 0.75 i okretanjem Y-osi, objavljujući svaki VisualBrush kao dijeljeni Form XObject i pretvarajući načine popločavanja ImageBrush-a u izvorne PDF obrasce popločavanja umjesto ponovljenih iscrtavanja slike
Scenarij koji većinu Windows radionica uvuče u ovo dosadan je i neizbježan. Nešto se već ispisuje na Microsoft XPS Document Writer — izvještaj naslijeđenog ERP-a, potpisan obrazac, serija izvoda — a arhivska politika kaže PDF. XPS je sasvim dobar format za hvatanje ispisa i užasan format za predati sustavu evidencije deset godina od sada. Dakle, spool datoteka mora postati PDF stranica za stranicu, i onog trenutka kad počnete pisati taj pretvarač otkrivate da zanimljivi dio nije XML. Nego to što se XPS i PDF ne slažu oko toga gdje je ishodište, koliko vrijedi jedinica i čime smije biti četkica
Iz paketa u PDF u jednom prolazu
Ulazna točka jest registar rukovatelja dokumentima, a ne poseban XPS razred. THPDFDocumentHandlerRegistry.RegisterStandardHandlers instalira rukovatelje za XPS, EPUB i CBZ; prepoznavanje se temelji na sadržaju, pa paket koji nosi [Content_Types].xml plus barem jedan dio .fpage dobiva 95 bodova čak i kada ekstenzija datoteke laže, dok gola ekstenzija .xps ili .oxps dobiva samo 10. Taj redoslijed važan je kada primate učitavanja, jer napadač koji preimenuje EPUB u .xps ne smije upravljati cjevovodom
var
Handled: IHPDFHandledDocument;
Info: THPDFDocumentHandlerInfo;
Options: THPDFDocumentHandlerOptions;
Registry: THPDFDocumentHandlerRegistry;
Output: TFileStream;
begin
Registry := THPDFDocumentHandlerRegistry.Create;
Output := TFileStream.Create('spool.pdf', fmCreate);
try
Registry.RegisterStandardHandlers;
Options := THPDFDocumentHandlerOptions.Default;
if not Registry.OpenFromFile('spool.xps', '', Options, Handled, Info) then
raise Exception.Create('no registered handler recognised the package');
if Handled.Format = hdfXPS then
Handled.WritePDF(Output, Options, Info);
// Info.UnsupportedFeatureCount jest pošten rezultat ove pretvorbe
finally
Output.Free;
Registry.Free;
end;
end;
Sve oko pretvorbe budžetira se prije nego što se pokuša. THPDFDocumentHandlerOptions.Default ograničava arhivske unose na 10.000, proširene arhivske bajtove na 1 GiB, omjer sažimanja na 200, resurse na 4.096 i stranice na 10.000, i nosi neobavezan CancellationToken kako bi se posao na strani poslužitelja mogao zaustaviti usred paketa. Nakon toga pročitajte Info.UnsupportedFeatureCount i vrijednost različitu od nule tretirajte kao stvaran nalaz: HotPDF namjerno broji što nije mogao preslikati umjesto da nacrta približnu zamjenu i ostane tih o tome
Zašto XPS stranica treba matricu umjesto prepisanih koordinata?
Zato što prepisivanje koordinata gubi stog transformacija. XPS FixedPage specificiran je u jedinicama od 96 DPI s ishodištem gore lijevo i Y-osi koja raste prema dolje; PDF korisnički prostor ima 72 DPI s ishodištem dolje lijevo i Y-osi koja raste prema gore. Naivno rješenje jest pomnožiti svaki broj s 0.75 i oduzeti svaki Y od visine stranice pri ispisivanju. To djeluje za jedan ravan put i raspada se onog trenutka kad uđe RenderTransform, ugniježđeni Canvas ili matrica lokalna za četkicu, jer su te transformacije definirane u XPS prostoru, a vaše prepisivanje po koordinati već ga je napustilo. HotPDF zato drži projekciju kao matricu i komponira je. HPDFXPSPageMatrix vraća fiksne konstante jednom po stranici, HPDFMultiplyXPSMatrix spaja ih s nakupljenom transformacijom putanje, a rezultat se ispisuje kao jedan operator cm prije geometrije. Podaci putanje zatim se zapisuju nepromijenjenim XPS brojevima, i zato skraćena geometrijska sintaksa može dijeliti isti ograničeni parser korišten za podatke SVG putanje — samo vodeći token pravila ispune F0 ili F1 rukuje XPS adapter. Ako ste slijedili isto rasuđivanje kod uveza vektora EMF i WMF, oblik argumenta vam je poznat: formati uvoza pretvaraju se matricom, nikada aritmetikom nad koordinatama listova
function HPDFXPSPageMatrix(PageHeight: Double): THPDFXPSMatrix;
begin
Result.A := 0.75; // 96-DPI XPS jedinica u 72-DPI PDF točku
Result.B := 0;
Result.C := 0;
Result.D := -0.75; // XPS Y raste prema dolje, PDF Y raste prema gore
Result.E := 0;
Result.F := PageHeight; // Visina PDF stranice, u točkama
end;
// Jedna komponirana CTM po vizualu, ispisana prije svakog operatora putanje
Effective := HPDFMultiplyXPSMatrix(HPDFXPSPageMatrix(PageHeightPDF), PathMatrix);
Page.AppendRawContent(HPDFXPSMatrixOperator(Effective));
Kako ponovno koristiti VisualBrush bez dvostrukog iscrtavanja?
VisualBrush slika proizvoljno vizualno stablo — djecu Canvas, Path i Glyphs — u regiju, moguće ponovljeno preko nje. HotPDF taj vizual jednom kompajlira u PDF Form XObject i zatim ga postavlja, što je ista strategija resursa opisana u tekstu o uvozu SVG-a preko Form XObjecta. Dvije pojedinosti odlučuju hoće li to raditi. Prvo, vizual se mora prolaziti kao izravna XML djeca: ravno pretraživanje za elementima vrijednim popločavanja izvlači ugniježđene vizuale na najvišu razinu stranice i razara i opseg resursa i redoslijed slikanja. Drugo, sadržaj se hvata s već primijenjenom matricom stranice iz XPS-a u PDF, pa objavljivanje Form-a zahtijeva množenje inverzom te matrice, inače svako postavljanje ponovno primjenjuje razmjer 0.75 i okretanje Y-osi. Form također mora posjedovati svoje resurse: HotPDF kopira samo fontove, XObjecte, obrasce, ExtGStates i prostore boja na koje uhvaćeni sadržajni tok stvarno upućuje; kloniranje cijelog rječnika resursa stranice povuklo bi Form koji se registrira u njegov vlastiti graf resursa i izgradilo ciklus. Fontovi ostaju u izravnom rječniku na običnim stranicama i unose se u dijeljeni indirektni rječnik samo kada uhvaćeni sadržaj stvarno sadrži Tf, pa dokument bez višekratno upotrebljivih vizuala ne plaća taj stroj. Napomenite jednu granicu specifikacije vrijednu znanja prije prijave greške: ECMA-388 sekcija 13.4 zahtijeva da su i ViewboxUnits i ViewportUnits na VisualBrush Absolute, pa relativne jedinice nisu nedostajuća značajka — to je nesukladan ulaz, i HotPDF odbija izmišljati koordinatnu semantiku za njih
Popločavanje ImageBrush: četiri načina, četiri veličine ćelije
XPS načini popločavanja preslikavaju se na PDF obrasce popločavanja iz ISO 32000-1 sekcije 8.7.3 umjesto da se rašire u ponovljena postavljanja slike preko pokrivene površine, što izlaznu veličinu i vrijeme pretvorbe drži neovisnima o tome koliko stranice četkica pokriva. Preslikavanje je mehaničko jednom kad ga vidite: zrcaljenje se izražava stavljanjem zrcaljenih postavljanja unutar jedne ćelije obrasca i proširenjem ćelije da tome odgovara
Tile— jedno postavljanje, ćelija ostaje 1×1 viewportFlipX— dva postavljanja, ćelija proširena na 2×1FlipY— dva postavljanja, ćelija produžena na 1×2FlipXY— četiri postavljanja, ćelija raširena na 2×2
Svako postavljanje nosi vlastiti pravokutnik za isjecanje, jer bi preslikavanje Viewbox koje prelazi svoju pod-ćeliju zakrvavilo u susjedno zrcaljenje. /Matrix obrasca je dio koji ljude iznenadi. Obrazac popločavanja sidri se u zadani korisnički prostor svog nadređenog sadržajnog toka, a ne u grafičko stanje važeće u trenutku odabira obrasca, pa matrica mora izričito komponirati sva tri sloja — projekciju fiksne stranice, transformaciju Path i Transform lokalnu za četkicu — umjesto da se oslanja na ambijentalnu CTM. HotPDF također provjerava prije alociranja: RegisterImageTilingPattern ograničava obrazac na 1.024 postavljanja i odbija degenerirane isjece, neinvertibilne matrice i nevažeće indekse slika. Ako želite opći model s PDF strane iza ovoga, tekst o obrascima popločavanja i Pattern prostoru boja pokriva temeljne operatore
// Projekcija fiksne stranice savijena u matricu obrasca, zatim ona lokalna za četkicu
PatternMatrix := HPDFMatFromOps( 0.75 * PathMatrix.A, -0.75 * PathMatrix.B,
0.75 * PathMatrix.C, -0.75 * PathMatrix.D,
0.75 * PathMatrix.E,
PageHeight - 0.75 * PathMatrix.F);
if Brush.HasTransform then
PatternMatrix := HPDFMatMul(PatternMatrix, BrushMatrix);
PatternName := Document.RegisterImageTilingPattern(Resource.ImageIndex,
Brush.Viewport.Left, Brush.Viewport.Top,
Brush.Viewport.Left + CellWidth, Brush.Viewport.Top + CellHeight,
CellWidth, CellHeight, Placements, pttNoDistortion, PatternMatrix);
Što se dogodi kada radijalni gradijent nije krug?
XPS definira RadialGradientBrush s GradientOrigin, Center, RadiusX i RadiusY, pa je četkica elipsa. PDF sjenčanje tipa 3, u ISO 32000-1 sekciji 8.7.4.5.4, stapa dva kruga i nema načina da izravno izrazi elipsu. Prosječivanje dva radijusa u jedan broj zamamni je prečac i vidljivo je pogrešan na svakoj četkici koja nije blizu okrugle. HotPDF umjesto toga seli problem u koordinatni sustav: razmjeri Y s RadiusY / RadiusX, registrira pošteno kružno sjenčanje u tom razmjeriranom prostoru, odabere obrazac i odmah ispisuje recipročni razmjer tako da geometrija putanje zapisana dalje ostane u izvornom XPS korisničkom prostoru
ScaleY := Brush.RadiusY / Brush.RadiusX;
PatternName := Document.RegisterMultiStopRadialGradient(
Brush.StartX, Brush.StartY / ScaleY, 0,
Brush.EndX, Brush.EndY / ScaleY, Brush.RadiusX,
StopPositions, StopColours, 3);
if Abs(ScaleY - 1) > 0.000001 then
Page.AppendRawContent('1 0 0 ' + HPDFPDFNumber(ScaleY) + ' 0 0 cm'#10);
Page.SetFillPattern(PatternName); // obrazac hvata CTM upravo ovdje
if Abs(ScaleY - 1) > 0.000001 then
Page.AppendRawContent('1 0 0 ' + HPDFPDFNumber(1 / ScaleY) + ' 0 0 cm'#10);
Redoslijed u tom isječku cijela je trik, i nije stilski. PDF obrazac sjenčanja hvata trenutnu matricu transformacije u trenutku kada je odabran kao trenutna boja, pa privremeni razmjer mora biti ispisan prije SetFillPattern ili SetStrokePattern, a recipročni mora slijediti odabir ali prethoditi operatorima putanje. Pokvarite redoslijed u bilo kojem smjeru i imate gradijent koji se ispravno renderira na prvoj putanji a odmiče na svakoj sljedećoj. Srodno ograničenje vrijedi za način relativnih koordinata: RadiusX i RadiusY moraju se razriješiti naspram širine i visine putanje odvojeno, jer razmjerivanje oboje jednom duljinom bridova tiho mijenja omjer slike elipse na svakoj ne-kvadratnoj putanji
Gdje je pretvorba iskrena prema svojim granicama
Neke XPS konstrukcije pretvaraju se približno, a neke se uopće ne pretvaraju, i dizajnerski izbor kroz sve jest brojati ih umjesto lažirati. TIFF i JPEG XR dijelovi rasteriziraju se kroz WIC i ne nose obećanje o očuvanom alfa kanalu, dok se PNG s valjanim alfa kanalom dijeli na osnovnu sliku plus /SMask. Unutarnja veličina slike izvodi se kao pixel * 96 / DPI, čitajući prvo PNG pHYs ili JPEG JFIF gustoću s padom na 96 DPI, pa loše zaglavlje gustoće završi na predvidivoj veličini umjesto na proizvoljnoj. Neriješeni resursi matrica, nestandardne relativne transformacije, ColorConvertedBitmap, nepodržani načini širenja gradijenta i neispravna geometrija svi povećavaju UnsupportedFeatureCount, i neispravan ulaz propada zatvoreno umjesto da se degradira u tiho drugačiji crtež
To je koristan stav za arhivski pretvarač: pretvorba koja tiho aproksimira gora je od one koja vam kaže koje četiri elemente nije mogla predstaviti, jer samo druga daje nešto za provjeriti prije nego što se dokument zapečati u sustav evidencije. Ako procjenjujete pretvorbu XPS i OpenXPS uz ostatak cjevovoda dokumenata — kompoziciju stranica, fontove, potpisivanje, PDF/A izlaz — stranica HotPDF Delphi PDF komponente navodi potpuni skup značajki i podržane verzije Delphija i C++Buildera