Uneori livrabilul nu este un document, este o imagine a unei tabele. Un bloc de rezumat într-un e-mail de stare, un panou KPI randat într-un dashboard, o miniatură lângă un rezultat de căutare: toate vor celulele și niciuna nu vrea hârtie. TXLSCellImageExporter din HotXLS primește un dreptunghi de celule clasic sau XLSX și produce un singur PNG sau JPEG compact, fără mărime de pagină, fără margini, fără antete sau subsoluri, fără titluri de tipărire și fără rupere de pagină. Rezoluția, scara, formatul și calitatea JPEG sunt configurabile, obiectele, liniile de grilă și bordurile de celule au comutatoare independente, fundalul poate fi o culoare sau transparent, iar scrierea fișierului trece printr-o înlocuire atomică în același dosar care lasă o țintă existentă neatinsă dacă ceva eșuează
Motivul pentru care are nevoie de un exporter propriu, nu de un fanion pe calea de tipărire, este că paginarea nu este un strat opțional pe care îl puteți dezactiva. Ea este lucrul pentru care există pipeline-ul de pagini
De ce nu randați intervalul prin pipeline-ul de tipărire?
Pentru că pipeline-ul de tipărire inserează o pagină între dumneavoastră și celule. Mărimea hârtiei decide cât încape, marginile împing conținutul spre interior, antetele și subsolurile ocupă benzi pe care nu le-ați cerut, titlurile de tipărire repetă rânduri pe care le aveți deja, iar ruperea de pagină despică intervalul. Un bloc de rezumat care se întâmplă să călerească o rupere iese ca două imagini cu rândul interesant tăiat în două. Puteți compensa totul configurând o mărime de pagină personalizată care corespunde exact intervalului, și oamenii o fac, dar asta înseamnă recalcularea geometriei de hârtie de fiecare dată când intervalul se schimbă și lasă totuși banda de antet și logica de titluri de tipărire în cale
Exporterul de celule măsoară dreptunghiul, alocă un bitmap de exact acea mărime, desenează celulele în el și codează. Nu există pagină, deci nu există nimic de configurat deoparte. Pentru cazurile în care chiar vreți hârtie, calea de export PDF este unealta potrivită și este tratată în articolul despre exportul PDF al foilor de lucru
Măsurați înainte să randați
Measure returnează dimensiunile în pixeli pe care setările curente le-ar produce fără să codeze nimic. Aceasta contează din două motive. Un template HTML sau de e-mail are de obicei nevoie de dimensiunile imaginii înainte ca imaginea să existe, pentru a rezerva cutia și a evita deplasarea layoutului. Iar un serviciu care randează intervale selectate de utilizatori are nevoie de o modalitate de a respinge o cerere absurdă înainte să aloce pentru ea
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 păstrează trasările subțiri clare
Exporter.DPI := 96;
Exporter.Scale := 2.0; // rezultat cu densitate 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 și H sunt acum cunoscute; rezervați cutia de layout înainte de codare
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;
Bugete, pentru că scara înmulțește
MaxPixels și MaxBytes nu sunt decorațiune defensivă. Numărul de pixeli crește cu pătratul factorului de scară și cu pătratul raportului de rezoluție, astfel încât un interval rezonabil de 1200 pe 800 la 96 DPI devine în jur de 47 de megapixeli la 600 DPI, iar un utilizator care selectează tot intervalul folosit în locul unui bloc de rezumat adaugă încă un ordin de mărime peste asta. Fără limită, modul de eșec este o alocare pe care procesul nu o poate satisface, ceea ce doboare orice mai făcea procesul acela
Cu o limită cererea eșuează, iar apelantul poate alege: refuzați, reduceți scara sau îngustați intervalul. Aceasta este o poziție mult mai bună pentru un server de rapoarte, și este același raționament din spatele bugetelor explicite din decoderul de metafișier descris în articolul despre decoderul mărginit EMF și WMF
Înlocuire atomică și de ce dosarul contează
Save către un nume de fișier nu scrie în țintă. Scrie un fișier temporar în același dosar, codează în el și abia apoi înlocuiește ținta. Dacă codarea eșuează, dacă bugetul este depășit pe parcurs sau dacă procesul este ucis, imaginea anterioară este încă acolo și încă validă. Un dashboard care își regenerează dalele la program nu afișează deci niciodată un PNG trunchiat, care este simptomul obișnuit al unei scrieri naive care deschide destinația și începe să transmită în flux
Detaliul aceluiași dosar nu este întâmplător. O înlocuire atomică este atomică doar în interiorul unui volum, deoarece între volume sistemul de operare trebuie să copieze și apoi să șteargă, ceea ce reintroduce fereastra pe care încercați să o închideți. Orice implementare a acestui tipar care își pune fișierul temporar în directorul temp de sistem nu este atomică pe o mașină unde rezultatul trăiește pe alt disc
Evenimentele de desen desenează pe canvasul real
Atât exporterul de intervale, cât și exporterul de pagini expun evenimente de desen de început și de final, și ele primesc un context complet doar pentru citire, nu doar un handle de canvas. TXLSPagePaintContext poartă canvasul viu, limitele în pixeli, mărimea paginii în puncte, rezoluția și scara efectiv folosite, numărul paginii în document, numărul paginii în foaie, numărul total de pagini, numele foii și foaia de lucru de origine în variantele atât clasică, cât și XLSX. Este de ajuns pentru a desena un filigran care scalează corect sau un ștampil de pagină care știe unde se află în serie
procedure TReportJob.StampDraft(Sender: TObject;
const AContext: TXLSPagePaintContext);
begin
// Conștient de scară, astfel încât ștampla arată la fel la 1x și 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;
Trei comportamente merită în care să aveți încredere. Evenimentele se declanșează exact o dată per cadru randat, inclusiv fiecare cadru al unui TIFF multipagină, deci un contor incrementat în handler este de încredere. Rămân tăcute în timpul măsurării, deci un handler cu efect secundar nu rulează de două ori pentru un rezultat. Iar dacă evenimentul de început aruncă excepție, cel de final nu se declanșează și nu se scriu octeți parțiali de imagine, deci o excepție în propriul cod de desenare nu poate produce un fișier pe jumătate ștampilat
Alegerea formatului
PNG pentru orice încărcat de text. JPEG aplică o transformare pe blocuri care produce un înel vizibil în jurul trasărilor subțiri cu contrast înalt, iar acesta este exact ce sunt bordurile de celule și textul mic, iar artefactele supraviețuiesc la setări de calitate la care o fotografie arată perfect. JPEG își câștigă locul când intervalul este dominat de fotografii înglobate și mărimea fișierului contează mai mult decât fidelitatea muchiilor. Fundalurile transparente cer PNG, deoarece JPEG nu are canal alfa, deci o dală menită să stea pe o suprafață colorată a făcut alegerea pentru dumneavoastră
Dacă intervalul dumneavoastră conține celule îmbinate, verificați rezultatul contra foii: regiunile îmbinate interacționează cu lățimile coloanelor în moduri care surprind oamenii, iar regulile de layout sunt tratate în articolul despre celulele îmbinate și șabloanele de rapoarte. HotXLS citește și scrie XLS, XLSX, ODS și CSV din Delphi și C++Builder fără nicio dependență de Excel, iar întreaga suprafață a exporterului este documentată pe pagina de produs HotXLS Delphi spreadsheet component