Niekedy výstupom nie je dokument, ale obrázok tabuľky. Súhrnný blok v statusovom e-maile, vyrenderovaný panel KPI na dashboarde, miniatúra vedľa výsledku vyhľadávania: všetky chcú bunky a žiadny nepatr papier. TXLSCellImageExporter v HotXLS berie klasický či XLSX obdĺžnik buniek a produkuje jeden kompaktný PNG alebo JPEG bez veľkosti strany, bez okrajov, bez hlavičiek či pätičiek, bez tlačových titulov a bez zlomov strán. Rozlíšenie, mierka, formát a kvalita JPEG sú nastaviteľné, objekty, mriežka a okraje buniek majú nezávislé prepínače, pozadie môže byť farba alebo transparentné a zápis súboru prechádza atomickou zámenou v tom istom priečinku, ktorá ponechá existujúci cieľ nedotknutý, ak čokoľvek zlyhá
Dôvod, prečo to potrebuje vlastný exportér namiesto príznaku na tlačovej ceste, je, že stránkovanie nie je voliteľná vrstva, ktorú možno vypnúť. Je to vec, na ktorú pipeline strán existuje
Prečo nevyrenderovať rozsah cez tlačovú pipeline?
Pretože tlačová pipeline vkladá stranu medzi vás a bunky. Veľkosť papiera rozhoduje, koľko sa zmestí, okraje tlačia obsah dovnútra, hlavičky a pätičky obsadzujú pásy, o ktoré ste nežiadali, tlačové tituly opakujú riadky, ktoré už máte, a zlomy strán rozdeľujú rozsah. Súhrnný blok, ktorý náhodou prekračuje zlom, vyjde ako dva obrázky s zaujímavým riadkom prerezaným na polovicu. Všetko to môžete kompenzovať nastavením vlastnej veľkosti strany presne zodpovedajúcej rozsahu a ľudia to robia, ale to znamená prepočítavať geometriu papiera pri každej zmene rozsahu a aj tak zostáva v ceste pás hlavičky a logika tlačových titulov
Bunkový exportér zmeria obdĺžnik, alokuje bitmapu presne tej veľkosti, nakreslí do nej bunky a zakóduje. Nie je tu strana, takže niet čo konfigurovať preč. Pre prípady, keď papier chcete, je správnym nástrojom cesta exportu PDF a pokrýva ju článok o exporte pracovného hárka do PDF
Merajte skôr, než vyrenderujete
Measure vracia pixelové rozmery, ktoré by aktuálne nastavenia produkovali, bez kódovania čohokoľvek. To má význam z dvoch dôvodov. HTML či e-mailová šablóna zvyčajne potrebuje rozmery obrazu skôr, než obraz existuje, aby si mohla rezervovať box a vyhnúť sa posunu layoutu. A služba, ktorá renderuje používateľom vybrané rozsahy, potrebuje spôsob, ako odmietnuť absurdnú požiadavku skôr, než alokuje pre ňu
uses
lxHandleX, lxPagination;
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
Exporter: TXLSCellImageExporter;
Summary: TXLSXRange;
W, H, Bytes: Integer;
begin
Book := TXLSXWorkbook.Create;
try
Book.Open('quarter.xlsx');
Sheet := Book.Sheets.ByPos[0];
Summary := Sheet.Range['A1:F20'];
Exporter := TXLSCellImageExporter.Create;
try
Exporter.ImageFormat := xpifPng; // PNG udržuje tenké ťahy ostré
Exporter.DPI := 96;
Exporter.Scale := 2.0; // výstup s hustotou retina
Exporter.IncludeGridlines := False;
Exporter.IncludeCellBorders := True;
Exporter.TransparentBackground := True;
Exporter.MaxPixels := 40 * 1000 * 1000;
Exporter.MaxBytes := 8 * 1024 * 1024;
if not Exporter.Measure(Summary, W, H) then
raise Exception.Create('range exceeds the configured budget');
// W a H sú teraz známe; rezervujte layout box pred kódovaním
Bytes := Exporter.Save(Summary, 'summary.png');
if Bytes <= 0 then
raise Exception.Create('image export failed, previous file kept');
finally
Exporter.Free;
end;
finally
Book.Free;
end;
end;
Rozpočty, pretože mierka násobí
MaxPixels a MaxBytes nie sú obranná dekorácia. Počet pixelov rastie s druhou mocninou faktora mierky a s druhou mocninou pomeru rozlíšenia, takže rozsah, ktorý je rozumných 1200 krát 800 pri 96 DPI, sa stane približne 47 megapixelmi pri 600 DPI a používateľ, ktorý vyberie celý použitý rozsah namiesto súhrnného bloku, pridá ešte ďalší rád veľkosti navyše. Bez stropu je režim zlyhania alokácia, ktorú proces nedokáže uspokojiť, čo zvalí všetko ostatné, čo ten proces robil
So stropom požiadavka zlyhá a volajúci si vyberie: odmietnuť, znížiť mierku alebo zúžiť rozsah. To je oveľa lepšia pozícia pre reportový server a je to to isté uvažovanie za explicitnými rozpočtmi v dekóderi metafilov popísanom v článku o ohraničenom dekóderi EMF a WMF
Atomická zámena a prečo záleží na priečinku
Save na meno súboru nezapisuje do cieľa. Zapisuje dočasný súbor v tom istom priečinku, kóduje do neho a až potom zamení cieľ. Ak kódovanie zlyhá, ak sa rozpočet prekročí v polovici alebo ak je proces zabitý, predchádzajúci obraz je stále tam a stále platný. Dashboard, ktorý regeneruje svoje dlaždice podľa plánu, preto nikdy neukáže skrátený PNG, čo je obvyklý príznak naivity zápisu, ktorý otvorí cieľ a začne streamovať
Detail rovnakého priečinka nie je náhodný. Atomická zámena je atomická len v rámci jedného zväzku, pretože naprieč zväzkami musí operačný systém kopírovať a potom mazať, čo znovu zavádza okno, ktoré ste sa snažili zavrieť. Akákoľvek implementácia tohto vzoru, ktorá dáva svoj dočasný súbor do systémového temp adresára, nie je atomická na stroji, kde výstup býva na inom disku
Paint udalosti kreslia na skutočný canvas
Exportér rozsahu aj exportér strán vystavujú vedúce a záverečné paint udalosti a prijímajú úplný kontext len na čítanie, nie len handle canvasu. TXLSPagePaintContext nesie živý canvas, pixelové hranice, veľkosť strany v bodoch, rozlíšenie a mierku skutočne používané, číslo strany dokumentu, číslo strany v hárku, celkový počet strán, meno hárka a pôvodný pracovný hárok v klasickej aj XLSX podobe. To stačí na nakreslenie vodoznaku, ktorý sa správne škáluje, alebo pečiatky strany, ktorá vie, kde je v behu
procedure TReportJob.StampDraft(Sender: TObject;
const AContext: TXLSPagePaintContext);
begin
// S ohľadom na mierku, takže pečiatka vyzerá rovnako pri 1x a 3x
AContext.Canvas.Font.Height := Round(-48 * AContext.Scale);
AContext.Canvas.Font.Color := clSilver;
AContext.Canvas.Brush.Style := bsClear;
AContext.Canvas.TextOut(AContext.Bounds.Left + Round(24 * AContext.Scale),
AContext.Bounds.Top + Round(24 * AContext.Scale), 'DRAFT');
end;
Exporter.AfterPaint := Job.StampDraft;
Tri správania stoja za spoľahnutie. Udalosti sa spustia presne raz za vyrenderovaný rámec, vrátane každého rámca viacstranového TIFF, takže počítadlo zvyšované v handleri je dôveryhodné. Počas merania zostávajú tiché, takže handler s vedľajším efektom nebeží dvakrát na jeden výstup. A ak vedúca udalosť vyhodí výnimku, záverečná udalosť sa nespustí a nezapisujú sa žiadne čiastočné bajty obrazu, takže výnimka vo vašom vlastnom kresliacom kóde nemôže produkovať polopečiatkovaný súbor
Voľba formátu
PNG pre všetko s množstvom textu. JPEG aplikuje blokovú transformáciu, ktorá produkuje viditeľné zvony okolo tenkých vysokokontrastných ťahov, čím presne sú okraje buniek a malý text, a artefakty prežívajú pri nastaveniach kvality, kde fotografia vyzerá perfektne. JPEG si zaslúži svoje miesto, keď rozsahom dominujú vložené fotografie a veľkosť súboru je dôležitejšia než vernosť hrán. Transparentné pozadie vyžaduje PNG, keďže JPEG nemá alpha kanál, takže dlaždica určená sedieť na farebnom povrchu rozhodla za vás
Ak váš rozsah obsahuje zlúčené bunky, skontrolujte výstup voči hárku: zlúčené regióny interagujú so šírkami stĺpcov spôsobmi, ktoré ľudí prekvapujú, a pravidlá layoutu pokrýva článok o zlúčených bunkách a šablónach správ. HotXLS číta a zapisuje XLS, XLSX, ODS a CSV z Delphi a C++Builder bez závislosti na Exceli a kompletný povrch exportéra je zdokumentovaný na produktovej stránke HotXLS Delphi spreadsheet component