Į sugeneruotos sąskaitos antraštę įdedate 600×400 pikselių logotipą, savo 96 DPI kūrimo monitoriuje jis atrodo gerai, o po savaitės klientas su didelio DPI nešiojamuoju kompiuteriu praneša, kad spausdinant jis išeina pašto ženklo dydžio. Patys pikseliai nepasikeitė. Pasikeitė prielaida, kad pikselių skaičius reiškia fizinį dydį, o OOXML pasaulyje taip nėra. Skaičiuoklės vaizdas savo matmenis saugo EMU vienetais, ir kol nepradėsite mąstyti EMU arba į jį tiksliai persiverčiančiais realaus pasaulio vienetais, jūsų išdėstymas priklausys nuo to, kokį DPI nuspręs manyti atvaizduojanti mašina
HotXLS yra vietinis VCL skaičiuoklių komponentas, skirtas Delphi ir C++Builder, skaitantis ir rašantis XLS bei XLSX be Excel ar bet kokios COM priklausomybės. Nuo v2.91.0 XLSX vaizdo objektas nebeverčia jūsų ranka skaičiuoti vienetų aritmetikos: šalia žalių EMU jis pateikia plotį ir aukštį centimetrais, coliais ir punktais, taip pat Scale metodą, kuris keičia dydį pagal procentą ir prireikus užrakina proporcijas. Šis straipsnis paaiškina, kas iš tikrųjų yra EMU, kodėl DrawingML jį pasirinko ir kaip naudoti naują geometrijos paviršių tam, kad paveikslėlius dėliotumėte pagal fizinį dydį, o ne pagal nepatikimą pikselių skaičių
Kas yra EMU ir kodėl jį naudoja DrawingML
EMU reiškia English Metric Unit, ir tai yra pagrindinis ilgio vienetas DrawingML sluoksnyje, bendrame visai Office Open XML šeimai (ECMA-376, 1 dalis, §20). Vienas EMU apibrėžtas taip, kad tiksliai būtų 914400 EMU viename colyje ir 360000 EMU viename centimetre. Būtent šios dvi konstantos ir yra visa priežastis, kodėl vienetas egzistuoja. 914400 dalijasi iš 2, 3, 4, 5, 6, 8, 9, 10, 12 ir daugelio kitų skaičių; jis išskaidomas į 26 × 32 × 52 × 127. Kadangi 1 colis = 2,54 cm tiksliai, pasirinkus vienetą, kuris dalijasi iš 360000 ir iš švarios 914400 dalies, formatas gali išreikšti colius, centimetrus ir punktus kaip sveikuosius skaičius, be jokio apvalinimo vieneto riboje. Ten, kur slankiojo kablelio "1,27 cm" dreifuotų, EMU tiesiog saugo 457200 ir išlieka tikslus
Kitas čia svarbus vienetas yra punktas. Tipografinis punktas yra 1/72 colio, todėl viename punkte yra 12700 EMU (914400 / 72). Būtent punktais pats Excel po gaubtu mąsto apie eilučių aukštį, šriftų dydį ir paraštes, todėl vaizdo geometrijos pateikimas punktais naudingas tada, kai norite, kad paveikslėlis lygiuotųsi į teksto metriką, o ne į spausdintą liniuotę. HotXLS visas keturias priklausomybes bibliotekoje užkoduoja kaip vienetų konstantas:
const
XlsxEmuPerInch = 914400; // 1 inch
XlsxEmuPerCm = 360000; // 1 centimetre
XlsxEmuPerPoint = 12700; // 1 point (1/72 inch)
XlsxEmuPerPixel = 9525; // 1 pixel at 96 DPI (914400 / 96)
Būtent paskutinė eilutė ir yra pašto ženklo dydžio klaidos esmė. Pikselis fizinį dydį įgyja tik tada, kai fiksuojate DPI, o 9525 EMU yra vieno pikselio dydis būtent esant 96 DPI. Numatytasis Excel atvaizdavimo DPI yra 96, todėl 100 pikselių vaizdas pagal numatytuosius nustatymus nusileidžia kaip 100 × 9525 = 952500 EMU ≈ 2,54 cm, tačiau faile nėra nieko, kas garantuotų, jog vartotojas taip pat naudos 96. Autoriaukite realiais vienetais ir ši dviprasmybė dingsta: 4 cm lieka 4 cm, nesvarbu, ar ekranas turi 96, ar 220 DPI
TXLSXImage geometrijos paviršius
Įterptas paveikslėlis HotXLS sistemoje yra TXLSXImage. Jo kanoninis saugojimas yra du sveikieji laukai - WidthEMU ir HeightEMU - pririšti prie 1 pagrindu skaičiuojamų Row ir Col (viršutinio kairiojo langelio, nuo kurio paveikslėlis kabo). Realūs vienetai yra skaičiuojami vaizdai virš šių EMU laukų, o ne atskira būsena: skaitant WidthCM EMU dalijami iš 360000, o rašant reikšmė padauginama ir suapvalinama atgal. Todėl kiekvienas nustatomas matmuo yra tik kita to paties pagrindinio EMU dydžio rašyba:
WidthInch/HeightInch- EMU ÷ 914400WidthCM/HeightCM- EMU ÷ 360000WidthPt/HeightPt- EMU ÷ 12700WidthEMU/HeightEMU- sveikasis šaltinio tiesos dydis
Paveikslėlį pridedate su AddImage(ARow, ACol, AData, AFormat), perduodami žalius užkoduotus baitus ir TXLSXImageFormat reikšmę (xlsxImagePng, xlsxImageJpeg, xlsxImageGif arba xlsxImageBmp); metodas grąžina nuliniu pagrindu skaičiuojamą indeksą į darbalapio Images kolekciją. Taip pat yra AddImageFromFile(ARow, ACol, AFileName), kuris formatą nustato pagal failo plėtinį. Atkreipkite dėmesį į indeksų bazę: AddImage grąžina nuliniu pagrindu skaičiuojamą indeksą ir Images[] taip pat yra nuliniu pagrindu, o tai sąmoningai kontrastuoja su 1 pagrindu skaičiuojamu Cells[Row, Col] tinkleliu, todėl nemanykite, kad abu sutampa
var
Sheet: TXLSXWorksheet;
Img: TXLSXImage;
Idx: Integer;
begin
Sheet := Workbook.Sheets.Add('Images');
// Anchor a PNG at row 3, column 2; AddImage returns a 0-based index.
Idx := Sheet.AddImage(3, 2, LogoBytes, xlsxImagePng);
Img := Sheet.Images[Idx];
Img.WidthCM := 4.0; // 4 cm wide -> 1440000 EMU
Img.HeightCM := 3.0; // 3 cm tall -> 1080000 EMU
// Same geometry, read back in other units.
// Img.WidthPt is now 113.39 pt, Img.WidthInch is 1.5748 in.
end;
Naujai sukurtas paveikslėlis pagal nutylėjimą yra 100×100 pikselių, tai yra 952500 EMU kvadratas, maždaug 2,54 cm dėžutė esant 96 DPI. Toks numatytasis dydis egzistuoja tam, kad paveikslėlis būtų matomas net jei pamirštumėte jį išmatuoti, tačiau bet kokiam rimtam išdėstymui turėtumėte nustatyti aiškų fizinį dydį, o ne pasikliauti numatytuoju dydžiu, išvestu iš pikselių
Mastelio keitimas ir proporcijų vėliava
Kai norite keisti dydį santykinai dabartiniams matmenims, o ne iki absoliutaus tikslo - tarkime, sumažinti diagramos paveikslėlį iki 60% nuo to, kokio dydžio jis buvo importuotas - naudokite Scale:
procedure Scale(APercent: Double; AKeepAspect: Boolean = True);
APercent yra procentas, kuriame 100 reiškia be pokyčio, 150 padidina per pusę, o 50 sumažina perpus. Kai AKeepAspect paliekamas numatytuoju True, tiek plotis, tiek aukštis padauginami iš to paties koeficiento, todėl proporcijos išlieka ir 4×3 cm vaizdas po Scale(150) tampa 6×4,5 cm. Perduokite False ir keičiasi tik plotis - aukštis paliekamas tiksliai toks, koks buvo. Toks asimetriškumas yra sąmoningas: kai norite nepriklausomai tampyti vieną ašį, teisingas įrankis yra aiškūs WidthCM/HeightCM nustatytojai, o neproporcinga Scale šaka skirta siauresniam atvejui, kai koreguojamas tik plotis. Labai lengva perskaityti Scale(150, False) kaip "ištempk abi kryptis laisvai" ir nustebti, todėl tada, kai tikrai norite dviejų nepriklausomų matmenų, rinkitės nustatytojus
Img.WidthCM := 4.0;
Img.HeightCM := 3.0;
Img.Scale(150); // aspect locked: now 6.0 x 4.5 cm
Img.Scale(100); // no-op, returns immediately
Img.Scale(50, False); // width only: 3.0 cm wide, height unchanged at 4.5 cm
Dar viena maža elgsena, kurią verta žinoti: Scale(100) iš karto grįžta neliesdamas nė vieno lauko, todėl jį saugu kviesti besąlygiškai cikle, kuriame procentas gali būti 100. Kadangi geometrija saugoma kaip sveikieji EMU, kiekvienas nustatymas apvalina. Todėl pereinant per trupmeninius centimetrus gali atsirasti mažytis EMU dalies dreifas - gerokai mažesnis už tai, ką galima pamatyti, tačiau verta tai žinoti, jei testuose kada nors tikrinate griežtą lygybę. Jei reikia pikselio tikslumo kontrolės, nustatykite WidthEMU ir HeightEMU tiesiogiai ir visiškai praleiskite vienetų konvertavimą
Geometrijos nuskaitymas atgal
Paveikslėlių kolekciją galima užklausti, o tai svarbu tada, kai įkeliate jau egzistuojančią darbaknygę ir reikia apžiūrėti ar pakoreguoti tai, kas joje jau yra, o ne tai, ką ką tik pridėjote. Images.Count išvardija kiekvieną lapo paveikslėlį, Images[i] juos indeksuoja nuliniu pagrindu, o FindAt(ARow, ACol) grąžina prie konkretaus langelio prikabintą paveikslėlį - arba nil, jei jo ten nėra. Taip pat yra IndexOfCell, jei reikia ne objekto, o indekso, ir DeleteAt / DeleteInRange šalinimui
var
i: Integer;
Img: TXLSXImage;
begin
for i := 0 to Sheet.Images.Count - 1 do
begin
Img := Sheet.Images[i];
Writeln(Format('[%d] R%dC%d %.2f x %.2f cm (%d x %d EMU)',
[i, Img.Row, Img.Col, Img.WidthCM, Img.HeightCM,
Img.WidthEMU, Img.HeightEMU]));
end;
Img := Sheet.Images.FindAt(3, 2); // nil-check before use
if Img <> nil then
Img.Scale(80);
end;
Kadangi realių vienetų savybės yra gyvi vaizdai, paveikslėlis, importuotas iš kito įrankio tam tikru EMU dydžiu, iš karto praneša savo geometriją centimetrais - jums nereikia jokio papildomo konvertavimo žingsnio. Tai natūraliai dera su platesniu piešimo modeliu; jei dėliojate diagramas ir figūras kartu su rastriniais vaizdais, papildomas vadovas apie HotXLS diagrams, images, and Excel drawings in Delphi aprašo inkaravimo modelį, kuriuo šie objektai dalijasi
Metrinės puslapio nustatymų paraštės
Tas pats EMU ir realių vienetų įtempimas pasirodo vienu lygiu aukščiau - puslapyje. OOXML ir Excel spausdinimo paraštes saugo coliais, o tai nepatogu, jei jūsų ataskaitų šablonai aprašomi milimetrais, kaip didžiojoje pasaulio dalyje už JAV ribų. v2.91.0 prideda centimetrines plėveles ant colinių paraščių: MarginLeftCM, MarginRightCM, MarginTopCM, MarginBottomCM, MarginHeaderCM ir MarginFooterCM. Kiekviena iš jų yra plonas patogumo sluoksnis virš atitinkamos colių savybės, konvertuojantis pagal tikslią 1 colio = 2,54 cm proporciją
Sheet.MarginLeftCM := 2.0; // 2 cm == 0.7874 inch
Sheet.MarginRightCM := 2.0;
Sheet.MarginTopCM := 2.5;
Sheet.MarginBottomCM := 2.5;
Sheet.MarginHeaderCM := 1.0;
Sheet.MarginFooterCM := 1.0;
Colių savybės (MarginLeft ir panašios) išlieka kanoniniu saugojimu, todėl galite maišyti abu būdus - nustatyti viršutinę paraštę centimetrais ir perskaityti ją coliais arba atvirkščiai - ir į diską įrašytas failas abiem atvejais bus identiškas. Konvertavimas yra paprastas dauginimas iš 2,54, be jokio grubaus apvalinimo tinklelio, todėl 2 cm lieka 2 cm visa double tikslumo apimtimi. Tai ta pati metrinio patogumo filosofija, kaip ir vaizdų geometrijoje: po gaubtu formatas kalba imperiniais vienetais, o biblioteka leidžia autoriuoti tais vienetais, kuriais parašyta jūsų specifikacija. Jei norite išdėlioti aplinkinę ataskaitą - pavadinimus, metaduomenų blokus, sumas - žiūrėkite merged cells and report template layout in HotXLS, kur šios paraštės naudojamos kartu su sujungtomis sritimis ir spausdinimo sritimi
Pastaba apie tai, ką geometrija garantuoja ir ko negarantuoja
Geometrijos savybės valdo deklaruotą paveikslėlio dydį faile - dydį, kuriuo jį atvaizduos atitinkantis vartotojas. Jos neperkoduoja ir nepersemplina pačių vaizdo baitų; 50×50 pikselių PNG, kurį nustatote kaip 8 cm, bus išdidintas ir atrodys blokuotas, lygiai taip pat, kaip ir pačiame Excel. Dydžio nustatymas yra išdėstymo, o ne vaizdo apdorojimo operacija, todėl paveikslėliui turite paduoti pakankamą šaltinio raišką tam fiziniam dydžiui, kurį ketinate naudoti. Biblioteka taip pat neperkoduoja formatų: baitai, kuriuos perduodate į AddImage, saugomi ir išrašomi tokie, kokie yra, pagal jūsų nurodytą TXLSXImageFormat. Jei perduosite JPEG baitus, bet pažymėsite juos kaip xlsxImagePng, sukursite failą, kurio Excel neatidarys, todėl, kai tik galite, leiskite AddImageFromFile nuspręsti formatą iš plėtinio
Niekas čia nėra egzotiška, kai tik įsisąmoninate vieną po tuo slypinčią idėją: OOXML fizinis dydis yra tikroji reikšmė, o pikseliai yra tik išvestinis, nuo DPI priklausantis jos šešėlis. Autoriuokite paveikslėlius ir paraštes centimetrais, coliais arba punktais, leiskite HotXLS juos paversti tiksliais EMU, ir jūsų sąskaitos bei ataskaitos ant kiekvienos mašinos spausdinsis tuo pačiu dydžiu
Čia aprašyti vaizdų geometrijos, mastelio keitimo ir metrinių paraščių API pateikiami kartu su HotXLS Delphi spreadsheet component, kuris iš Delphi ir C++Builder skaito ir rašo XLS bei XLSX nereikalaudamas jokio įdiegto Excel