Pudotat 600×400 pikselin logon luodun laskun ylätunnisteeseen, se näyttää hyvältä 96 DPI:n kehitysnäytölläsi, ja viikkoa myöhemmin korkean DPI-tarkkuuden kannettavaa käyttävä asiakas ilmoittaa sen tulostuvan postimerkin kokoisena. Pikselit eivät muuttuneet. Muuttunut tekijä oli oletus siitä, että pikselimäärä tarkoittaa fyysistä kokoa, ja OOXML-muodossa näin ei ole. Taulukkolaskentakuva kantaa mittansa EMU-yksiköinä, ja ennen kuin ajattelet EMU-yksiköinä – tai niihin siististi kartoitettavina reaalimaailman yksiköinä – asettelusi on renderöivän koneen olettaman DPI-tarkkuuden armoilla
HotXLS on alkuperäinen VCL-taulukkolaskentakomponentti Delphille ja C++Builderille, ja versiosta v2.91.0 alkaen XLSX-kuvaobjekti säästää sinut yksikkölaskuilta: raa'an EMU-arvon ohella se tuo esiin leveyden ja korkeuden senttimetreinä, tuumina ja pisteinä (points), sekä Scale-metodin, joka muuttaa kokoa prosentteina valinnaisella kuvasuhteen lukituksella. Tämä artikkeli käsittelee sitä, mikä EMU todellisuudessa on, miksi DrawingML valitsi sen ja miten uutta geometriarajapintaa käytetään kuvien asettamiseen fyysisen koon mukaan pikselimäärän sijaan, johon et voi luottaa
Mikä on EMU ja miksi DrawingML käyttää sitä
EMU tarkoittaa sanoja English Metric Unit, ja se on peruspituusyksikkö DrawingML-piirtokerroksessa, joka jaetaan koko Office Open XML -perheen kesken (ECMA-376, Osa 1, §20). Yksi EMU on määritelty siten, että tuumassa on täsmälleen 914400 EMU-yksikköä ja senttimetrissä 360000 EMU-yksikköä. Nämä kaksi vakiota ovat koko yksikön olemassaolon syy. Luku 914400 on jaollinen luvuilla 2, 3, 4, 5, 6, 8, 9, 10, 12 ja monilla muilla; sen tekijät ovat 26 × 32 × 52 × 127. Koska 1 tuuma = 2,54 cm täsmälleen, sellaisen yksikön valitseminen, joka on jaollinen sekä luvulla 360000 että luvun 914400 puhtaalla murtoluvulla, sallii formaatin ilmentää tuumia, senttimetrejä ja pisteitä kokonaislukuina ilman pyöristyksiä yksikkörajalla. Siinä missä liukulukumuotoinen '1,27 cm' kärsisi pyöristysvirheistä, EMU tallentaa arvon 457200 ja pysyy tarkkana
Toinen tärkeä yksikkö tässä on piste (point). Typografinen piste on 1/72 tuumaa, joten yhtä pistettä kohden on täsmälleen 12700 EMU-yksikköä (914400 / 72). Pisteet ovat tapa, jolla Excel itse käsittelee rivikorkeuksia, fonttikokoja ja marginaaleja pellin alla, minkä vuoksi kuvageometrian ilmaiseminen pisteinä on hyödyllistä, kun haluat kuvan linjautuvan tekstin mittasuhteiden eikä tulostetun viivaimen mukaan. HotXLS koodaa kaikki neljä suhdetta yksikkövakioiksi kirjastossa:
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)
Tämä viimeinen rivi on se postimerkkivirheen ydin. Pikselillä on fyysinen koko vain, kun DPI-tarkkuus on kiinnitetty, ja 9525 EMU on yhden pikselin koko nimenomaan 96 DPI:n tarkkuudella. Excelin oletusrenderöinti-DPI on 96, joten 100 pikselin kuva päätyy kokoon 100 × 9525 = 952500 EMU ≈ 2,54 cm oletusasetuksilla – mutta mikään tiedostossa ei takaa, että vastaanottaja käyttää arvoa 96. Määritä koot fyysisissä yksiköissä, ja tuo epävarmuus katoaa: 4 cm on 4 cm riippumatta siitä, onko näyttö 96 vai 220 DPI
TXLSXImage-geometriarajapinta
Upotettu kuva HotXLS-komponentissa on TXLSXImage-tyyppiä. Sen kanoninen tallennustapa on kaksi kokonaislukukenttää, WidthEMU ja HeightEMU, ankkuroituna nollasta poikkeavaan 1-pohjaiseen soluun Row ja Col (solu, josta kuvan vasen yläkulma roikkuu). Reaalimaailman yksikköominaisuudet ovat laskettuja näkymiä näiden EMU-kenttien yli, eivät erillistä tilaa – WidthCM-arvon lukeminen jakaa EMU-arvon luvulla 360000, ja sen kirjoittaminen kertoo ja pyöristää takaisin. Joten jokainen asettamasi mittasuhde on vain eri tapa kirjoittaa sama taustalla oleva EMU-arvo:
WidthInch/HeightInch— EMU ÷ 914400WidthCM/HeightCM— EMU ÷ 360000WidthPt/HeightPt— EMU ÷ 12700WidthEMU/HeightEMU— kokonaislukumuotoinen totuuden lähde
Lisäät kuvan metodilla AddImage(ARow, ACol, AData, AFormat) välittämällä raa'at koodatut tavut ja TXLSXImageFormat-arvon (xlsxImagePng, xlsxImageJpeg, xlsxImageGif tai xlsxImageBmp); se palauttaa nollapohjaisen indeksin laskentataulukon Images-kokoelmaan. Saatavilla on myös AddImageFromFile(ARow, ACol, AFileName), joka päättelee muodon tiedostotarkenteesta. Huomaa indeksin kanta: AddImage palauttaa nollapohjaisen indeksin ja Images[] on nollapohjainen, mikä on tietoinen ero verrattuna 1-pohjaiseen Cells[Row, Col]-ruudukkoon, joten älä oleta niiden täsmäävän
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;
Juuri luodun kuvan oletuskoko on 100×100 pikseliä, eli 952500 EMU-yksikköä kanttiinsa, mikä vastaa noin 2,54 cm laatikkoa 96 DPI:n tarkkuudella. Tämä oletus on olemassa, jotta kuva on näkyvissä, vaikka unohtaisit määrittää sen koon, mutta todellisissa asetteluissa sinun tulisi asettaa nimenomainen fyysinen koko sen sijaan, että luottaisit pikselipohjaiseen oletukseen
Skaalaus ja kuvasuhteen lippu
Kun haluat muuttaa kokoa suhteessa nykyisiin mittoihin absoluuttisen kohteen sijaan – esimerkiksi pienentää kaaviokuvan 60 prosenttiin siitä, millä se tuotiin – käytä Scale-metodia:
procedure Scale(APercent: Double; AKeepAspect: Boolean = True);
APercent on prosenttiosuus, jossa 100 tarkoittaa muuttumatonta, 150 suurentaa puolella ja 50 puolittaa. Kun AKeepAspect on oletusarvossaan True, sekä leveys ja korkeus kerrotaan samalla tekijällä, jolloin mittasuhteet säilyvät ja 4×3 cm kuvasta tulee 6×4,5 cm kutsun Scale(150) jälkeen. Jos välität arvon False, vain leveys skaalautuu – korkeus jätetään täsmälleen siksi, mikä se oli. Tämä epäsymmetria on tarkoituksellista: kun haluat venyttää yhtä akselia itsenäisesti, oikea työkalu on nimenomaiset WidthCM/HeightCM-asetukset, ja Scale-metodin kuvasuhteesta riippumaton haara on olemassa kapeampaa leveyden säätöä varten. On helppo tulkita kutsu Scale(150, False) väärin muodossa 'venytä molempia vapaasti' ja yttyä, joten turvaudu asetuksiin silloin, kun tarkoitat todella kahta itsenäistä ulottuvuutta
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
Yksi pieni huomioitava käyttäytyminen: Scale(100) oikaisee ja palaa koskematta kumpaankaan kenttään, joten sitä on turvallista kutsua ehdottomasti silmukassa, jossa prosentti voi olla 100. Ja koska geometria tallennetaan kokonaislukumuotoisina EMU-yksikköinä, jokainen asetus pyöristää. Edestakainen muunnos murtolukuisten senttimetrien läpi voi siksi heittää EMU:n murto-osalla – reilusti alle minkään näkyvän rajan, mutta hyvä tietää, jos koskaan tarkistat tarkkaa yhtäsuuruutta testeissä. Pikselintarkkaa hallintaa varten aseta WidthEMU ja HeightEMU suoraan ja ohita yksikkömuunnos kokonaan
Geometrian lukeminen takaisin
Kuvakokoelma on kyseltävissä, mikä on tärkeää silloin, kun lataat olemassa olevan työkirjan ja sinun on tarkistettava tai säädettävä siellä jo olevia kuvia sen sijaan, mitä juuri lisäsit. Images.Count luettelee jokaisen taulukon kuvan, Images[i] indeksoi ne nollapohjaisesti, ja FindAt(ARow, ACol) palauttaa tiettyyn soluun ankkuroidun kuvan – tai arvon nil, jos sellaista ei ole. Saatavilla on myös IndexOfCell indeksin saamiseksi objektin sijaan, sekä DeleteAt / DeleteInRange poistoa varten
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;
Koska reaalimaailman yksikköominaisuudet ovat live-näkymiä, toisesta työkalusta tietyssä EMU-koossa tuotu kuva ilmoittaa geometriansa senttimetreinä välittömästi – ilman muunnosvaihetta sinun puoleltasi. Tämä sopii luontevasti laajempaan piirustusmalliin; jos sijoitat kaavioita ja muotoja rasterikuvien ohella, rinnakkaisopas HotXLS-kaavioista, kuvista ja Excel-piirustuksista Delphissä kattaa näiden objektien jakaman ankkurointimallin
Metriset sivuasettelun marginaalit
Sama EMU-vastaan-reaaliyksiköt -jännite näkyy yhtä tasoa ylempänä, eli sivulla. OOXML ja Excel tallentavat tulostusmarginaalit tuumina, mikä on hankalaa, jos raporttipohjasi on määritelty millimetreinä kuten suurimmassa osassa maailmaa Yhdysvaltojen ulkopuolella. Versio v2.91.0 lisää senttimetrikääreet tuumamarginaalien päälle: MarginLeftCM, MarginRightCM, MarginTopCM, MarginBottomCM, MarginHeaderCM ja MarginFooterCM. Jokainen on kevyt mukavuusominaisuus vastaavan tuumapropertyn päällä, muuntaen arvot tarkalla suhteella 1 tuuma = 2,54 cm
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;
Tuumapropertyt (MarginLeft ja vastaavat) säilyvät kanonisena tallennuspaikkana, joten voit sekoittaa näitä kahta – asettaa ylämarginaalin senttimetreinä ja lukea sen takaisin tuumina, tai päinvastoin – ja levylle kirjoitettava tiedosto on identtinen molemmissa tapauksissa. Muunnos on pelkkä kertolasku luvulla 2,54 ilman pyöristystä karkeaan ruudukkoon, joten 2 cm pysyy 2 senttimetrinä täydellä double-tarkkuudella. Tämä on sama metrinen mukavuusfilosofia kuin kuvageometriassa: formaatti puhuu imperiaalisia yksiköitä pellin alla, ja kirjasto antaa sinun kirjoittaa koodia missä tahansa yksikössä, jossa määrityksesi on laadittu. Ympäröivän raportin – otsikoiden, metatietolohkojen, yhteissummien – asettelua varten katso artikkeli yhdistetyistä soluista ja raporttipohjien asettelusta HotXLS-komponentissa, joka käyttää näitä marginaaleja yhdessä yhdistettyjen alueiden ja tulostusalueen kanssa
Huomautus siitä, mitä geometria takaa ja mitä se ei takaa
Geometriapropertyt hallitsevat kuvan ilmoitettua kokoa tiedostossa – eli kokoa, jolla standardinmukainen vastaanottaja sen renderöi. Ne eivät muuta itse kuvan tavujen näytemäärää (resample); 50×50 pikselin PNG-kuva, jonka kooksi asetetaan 8 cm, skaalautuu ylöspäin ja näyttää palikkaiselta, aivan kuten se tekisi Excelissä. Koon määritys on asetteluoperaatio, ei kuvankäsittelyoperaatio, joten anna kuvalle riittävästi lähderesoluutiota suunnittelemaasi fyysistä kokoa varten. Kirjasto ei myöskään uudelleenkoodaa tiedostomuotoja: tavut, jotka välität metodille AddImage, tallennetaan ja kirjoitetaan eteenpäin sellaisenaan ilmoittamasi TXLSXImageFormat-arvon mukaisesti. Jos välität JPEG-tavuja mutta merkitset ne tyypillä xlsxImagePng, tuotat tiedoston, jota Excel ei voi avata, joten anna metodin AddImageFromFile päätellä muoto tiedostopäätteestä aina kun voit
Mikään tästä ei ole ihmeellistä, kun sisäistät sen taustalla olevan ainoan ajatuksen: OOXML-formaatissa fyysinen koko on todellinen suure, ja pikselit ovat vain sen johdettu, DPI-tarkkuudesta riippuva varjo. Kirjoita kuvat ja marginaalit senttimetreinä, tuumina tai pisteinä, anna HotXLS-komponentin kartoittaa ne tarkkoihin EMU-yksiköihin, ja laskusi sekä raporttisi tulostuvat saman kokoisina jokaisella koneella, jolla ne avataan
Tässä kuvatut kuvageometrian, skaalauksen ja metristen marginaalien API:t toimitetaan HotXLS Delphi -taulukkolaskentakomponentin mukana, joka lukee ja kirjoittaa XLS- ja XLSX-tiedostoja Delphistä ja C++Builderista käsin ilman Excel-asennusta