Serija grafikona ispunjena doslovnim RGB-om ne slijedi temu radne knjige. Promijenite temu i serija zadržava staru boju. HotXLS to u binarnom XLS-u rješava ispunama serija grafikona obojenima prema temi: zapisom GelFrame, 4198 ili $1066, zapisanim odmah nakon AreaFormata unutar bloka serije i s indeksom sheme OfficeArt te tintom. Excel tada seriju iscrtava onako kako iscrtava tematsku ispunu koju je samo zapisao
Odakle dolazi broj zapisa GelFrame?
Broj zapisa GelFrame je 4198 ($1066) i nećete ga pronaći u vlastitom odjeljku specifikacije zapisa. [MS-XLS] 2.4.131 opisuje što GelFrame sadrži, ali za razliku od većine odjeljaka zapisa ne navodi vrijednost rt. ABNF podtoka grafikona također ne pomaže: daje samo produkciju GELFRAME = 1*2GelFrame *Continue, koja imenuje zapis bez numeriranja. Broj se nalazi u tablici nabrajanja brojeva zapisa, nekoliko stranica dalje od odjeljka koji dokumentira korisni teret. Tu produkciju vrijedi ponovno pogledati ako pišete čitač: dopušta jedan ili dva zapisa GelFrame, od kojih nakon svakoga opcionalno mogu slijediti Continue zapisi, pa će parser koji pretpostavlja jedan zapis po produkciji pogrešno obraditi datoteku koju nije sam zapisao. HotXLS emitira točno jedan GelFrame po tematskoj seriji, što Excel proizvodi za jednostavnu punu tematsku ispunu, a njegov dekoder zapis tretira kao samostalan korisni teret umjesto da pretpostavi fiksni broj
Unutar korisnog tereta GelFrame: dvije tablice svojstava OfficeArt
Korisni teret GelFramea dvije su tablice svojstava OfficeArta jedna iza druge: OfficeArtFOPT (nazvan OPT1), a zatim OfficeArtTertiaryFOPT (OPT2). Svaka je tablica dvobajtni broj svojstava iza kojeg slijedi toliko unosa FOPTE od šest bajtova, a svaki unos je dvobajtni opid i četverobajtni op. Bit 15 u opid je fComplex: kada je postavljen, vrijednost op duljina je u bajtovima i nakon fiksnih unosa slijedi promjenjivi rep. Dekoder koji zanemari te repove desinkronizira se i čita smeće kao opid za sve nakon prvog složenog svojstva
Tematska ispuna izražena je s tri svojstva raspoređena kroz obje tablice i još jednim koje deklarira vrstu ispune. HotXLS zapisuje četiri svojstva u 28 bajtova, bez složenih repova:
fillType$0180 u OPT1, postavljen na 1 (msofillSolid)fillColor$0181 u OPT1, spljošteni RGB koji će iscrtati stariji potrošač ili onaj koji ne razumije temefillColorExt$019E u OPT2, osnovna boja temefillColorExtMod$01A0 u OPT2, tinta ili nijansa primijenjena na osnovnu boju
Ta je podjela namjerna u formatu, a ne slučajnost implementacije: [MS-ODRAW] 2.2.2 opisuje tematsku trojku kao ravnu boju, osnovnu boju i izmjenu, pa potrošač koji razumije teme ponovno računa ispunu, dok onaj koji ih ne razumije i dalje slika nešto razumno. Susjedni opidi slijede isti obrazac i nose isto numeriranje u starim i aktualnim izdanjima [MS-ODRAW], što je praktično kada uspoređujete dvije revizije: fillOpacity $0182, fillBackColor $0183, fillShadeType $019C, fillBackColorExt $01A2 i fillBackColorExtMod $01A4
Zašto indeks sheme sjedi u crvenom bajtu?
Jer je OfficeArtCOLORREF definiran pomakom bajta, a ne brojčanom vrijednošću: crveni je na bajtu 0, zeleni na bajtu 1, plavi na bajtu 2, a zastavice na bajtu 3. Pročitajte tu strukturu kao little-endian DWORD, što je svaki op FOPTE-a, i crvena postaje bajt najmanje težine. Razrađeni primjer lineColor u [MS-ODRAW] to potvrđuje. Zato fSchemeIndex, koji je bit E zastavica, ima brojčanu vrijednost $08000000, a sam indeks sheme ide u crveni bajt, dok zeleni i plavi moraju biti nula. Accent1 je stoga vrijednost op-a $08000004, a ne $00000004 i nikako $04000000
Redoslijed indeksa teme koji specifikacija odbija definirati
Specifikacija redoslijed indeksa sheme naziva određenim hostom i ne daje tablicu, što znači da sam raspored bajtova nije dovoljan za interoperabilnost s Excelom. HotXLS koristi redoslijed teme proračunske tablice, onaj koji prolazi povratni ciklus sa stvarnim Excelovim datotekama:
- 0 = lt1, 1 = dk1, 2 = lt2, 3 = dk2
- 4 do 9 = accent1 do accent6
- 10 = hlink, 11 = folHlink
Tinta i nijansa: korisni teret MSOTINTSHADE
fillColorExtMod op vrijednost je MSOTINTSHADE i smjer i iznos kodira u jednom DWORD-u umjesto kao predznačni razlomak. Vrijednost $20000000 znači bez izmjene. Tinta posvjetljivanja je $02F4 shl 16 or amount shl 8 or $10 (MSOTINT), a tinta potamnjivanja isti je oblik s $01F4 u višoj riječi (MSOSHADE). Bajt amount ide suprotno intuiciji: $FF znači nepromijenjeno, a $00 znači puna izmjena. HotXLS to normalizira u jedan double u stilu DrawingML-a, gdje pozitivno posvjetljuje, a negativno potamnjuje, koristeći plus ili minus (255 - amount) / 255. Mapiranje je točno za vrijednosti koje Excel stvarno nudi u sučelju, zbog čega je povratni ciklus bez gubitaka, a ne približno bez gubitaka: poznato posvjetljivanje Lighter 40% iznos je 153, a (255 - 153) / 255 jest 0,4 bez pogreške zaokruživanja u bilo kojem smjeru. Nijansa s iznosom 191 vraća se kao -64/255. Evo kodera, ograničenog na dopušteni raspon:
if Tint > 0 then // MSOTINT - svjetlije
TintOp := LongWord($02F4) shl 16 or
(LongWord(Round(255 * (1 - Tint))) shl 8) or $10
else if Tint < 0 then // MSOSHADE - tamnije
TintOp := LongWord($01F4) shl 16 or
(LongWord(Round(255 * (1 + Tint))) shl 8) or $10
else
TintOp := $20000000; // MSOCOLORMODUNDEFINED
Postavljanje i čitanje tematske ispune iz Delphija
Na strani pisanja tematska ispuna dva su dodatna polja u zapisu stila po seriji. TXLSChartSeriesStyleInfo dobio je HasFillTheme, FillThemeColor i FillThemeTint, a builder emitira GelFrame samo kada su postavljeni i HasStyle i HasFillTheme. Ako postavite i izričiti FillRgb, ta vrijednost ide u OPT1 fillColor doslovno; ako ne, HotXLS sam spljoštava boju kroz ugrađenu zadanu tablicu Officeove teme s primijenjenom tintom, pa serija koja ima samo temu i dalje ima razumnu ravnu boju za potrošače koji zanemaruju OPT2. Primijetite inicijalizaciju Default(), koja je važna jer TXLSChartSeriesInfo sadrži upravljana polja, a njegova obična Boolean polja inače budu smeće sa stoga:
var
Wb: TXLSWorkbook;
Series: array [0..1] of TXLSChartSeriesInfo;
begin
Wb := TXLSWorkbook.Create;
try
Wb.Sheets.Add.Name := 'Data';
Series[0] := Default(TXLSChartSeriesInfo); // nikad ne koristi FillChar nad ovim zapisom
Series[0].Name := 'Explicit';
Series[0].Categories := 'Data!$A$1:$A$2';
Series[0].Values := 'Data!$B$1:$B$2';
Series[0].HasStyle := True;
Series[0].Style.HasFill := True;
Series[0].Style.FillRgb := $C47244; // accent1, crveni bajt je onaj najmanje težine
Series[0].Style.HasFillTheme := True;
Series[0].Style.FillThemeColor := 4; // accent1
Series[0].Style.FillThemeTint := 0.4; // Lighter 40%
Series[1] := Default(TXLSChartSeriesInfo);
Series[1].Name := 'ThemeOnly';
Series[1].Categories := 'Data!$A$1:$A$2';
Series[1].Values := 'Data!$C$1:$C$2';
Series[1].HasStyle := True;
Series[1].Style.HasFillTheme := True; // bez izričitog RGB-a: spljošteno
Series[1].Style.FillThemeColor := 8; // accent5
Wb.Sheets.AddChartSheet('Themed', xlsChartTypeColumn, '', '', '', Series);
Wb.SaveAs('themed.xls');
finally
Wb.Free;
end;
end;
Čitanje natrag ide kroz isti model grafikona koji koristi ostatak HotXLS pregleda grafikona. GetChartModel vraća vlasnički TXLSChartModel koji oslobađate, a svaki TXLSChartSeries izlaže HasFillTheme, FillThemeColor i FillThemeTint uz FillRgb dekodiran iz OPT1 fillColor, koji za tu seriju ima prednost pred bojom AreaFormata. Iste tri vrijednosti također dolaze do kanonske semantičke snimke kao SolidFillThemeSet, SolidFillThemeColor i SolidFillThemeTint, pa usporedba radne knjige vidi promjenu teme kao promjenu teme, a ne kao neobjašnjivi pomak RGB-a. Ako dolazite sa strane XLSX-a, ovo je pandan binarnog formata oblikovanju opisanom u vodiču HotXLS-a za Excelove grafikone, slike i crteže u Delphiju:
Wb := TXLSWorkbook.Create;
try
Wb.Open('themed.xls');
Model := Wb.Sheets[2]._Chart.GetChartModel;
try
Ser := Model.GetSeries(0);
if Ser.HasFillTheme then
begin
WriteLn(Ser.FillThemeColor); // 4 = accent1
WriteLn(Ser.FillThemeTint:0:3); // 0.400
WriteLn(IntToHex(Ser.FillRgb, 6)); // C47244, OPT1 fillColor
end;
finally
Model.Free;
end;
finally
Wb.Free;
end;
Što tematska ispuna u binarnom XLS-u ne jamči?
Tri poštena ograničenja. Prvo, najvažnije za svakoga tko revidira ovaj kod: nijedna ogledna datoteka u lokalnom korpusu uopće ne sadrži zapis GelFrame. Jedanaest pojava para bajtova 66 10 u primjeru uvjetnog oblikovanja sjede na granicama koje nisu zapisi, a puni ispis zapisa cijelog toka nalazi nula pogodaka. Ovdje opisani raspored bitova izveden je iz specifikacije, a zatim učvršćen na tri načina: simetrijom dekodiranja nad izlazom buildera, ručno izgrađenim testovima bajtova koji sintetički korisni teret $1066 dovode izravno u dekoder i provjerom točnog spljoštenog RGB-a. To je slabiji oblik dokaza od snimljene Excelove datoteke i vrijedi to reći umjesto sugerirati suprotno. Drugo, spljoštavanje ispune koja ima samo temu koristi ugrađenu zadanu tablicu Officeove teme, a ne dio teme pročitan iz radne knjige, jer binarni XLS nema dio teme u smislu zapakiranog XLSX-a — ako vam treba da vlastita tema radne knjige upravlja ravnom bojom, sami predajte FillRgb. Treće, dekoder prihvaća GelFrame samo unutar bloka serije; isti se zapis može pojaviti na području grafikona ili okviru osi, a njegovo prihvaćanje ondje tiho bi pripisalo pozadinsku ispunu seriji, pa se takvi zapisi zanemaruju. fillColorExt bez zastavice $08000000 također se tretira kao obična proširena boja i nikad ne postavlja HasFillTheme. Za radne knjige u kojima je grafikon napisan u svijetu XLSX-a i samo prolazi kroz sustav, put očuvanja u članku o uređivanju Excelovih grafikona bez gubitka ChartML-a sigurniji je put, a spremnik u kojem ti zapisi sjede obrađen je u članku o čitanju složenih datoteka OLE2 u Delphiju bez COM IStoragea
Tematske ispune grafikona, GelFrame koder i dekoder te puni builder podtoka grafikona BIFF8 isporučuju se u HotXLS Delphi spreadsheet component za Delphi i C++Builder, koja čita i zapisuje XLS, XLSX i ODS bez instaliranog Excela